diff options
Diffstat (limited to 'drivers')
220 files changed, 45213 insertions, 3307 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 4875f0149eb4..b83389145f28 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -88,7 +88,7 @@ config ACPI_PROC_EVENT config ACPI_AC tristate "AC Adapter" - depends on X86 + depends on X86 && POWER_SUPPLY default y help This driver adds support for the AC Adapter object, which indicates @@ -97,7 +97,7 @@ config ACPI_AC config ACPI_BATTERY tristate "Battery" - depends on X86 + depends on X86 && POWER_SUPPLY default y help This driver adds support for battery information through @@ -117,6 +117,7 @@ config ACPI_BUTTON config ACPI_VIDEO tristate "Video" depends on X86 && BACKLIGHT_CLASS_DEVICE && VIDEO_OUTPUT_CONTROL + depends on INPUT help This driver implement the ACPI Extensions For Display Adapters for integrated graphics devices on motherboard, as specified in @@ -349,12 +350,11 @@ config ACPI_HOTPLUG_MEMORY $>modprobe acpi_memhotplug config ACPI_SBS - tristate "Smart Battery System (EXPERIMENTAL)" + tristate "Smart Battery System" depends on X86 - depends on EXPERIMENTAL + depends on POWER_SUPPLY help - This driver adds support for the Smart Battery System. - A "Smart Battery" is quite old and quite rare compared - to today's ACPI "Control Method" battery. + This driver adds support for the Smart Battery System, another + type of access to battery information, found on some laptops. endif # ACPI diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index d4336f1730e9..54e3ab0e5fc0 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -60,3 +60,4 @@ obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o obj-$(CONFIG_ACPI_HOTPLUG_MEMORY) += acpi_memhotplug.o obj-y += cm_sbs.o obj-$(CONFIG_ACPI_SBS) += sbs.o +obj-$(CONFIG_ACPI_SBS) += sbshc.o diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c index 26d70702b313..e03de37a750d 100644 --- a/drivers/acpi/ac.c +++ b/drivers/acpi/ac.c @@ -29,6 +29,7 @@ #include <linux/types.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> +#include <linux/power_supply.h> #include <acpi/acpi_bus.h> #include <acpi/acpi_drivers.h> @@ -72,16 +73,37 @@ static struct acpi_driver acpi_ac_driver = { }; struct acpi_ac { + struct power_supply charger; struct acpi_device * device; unsigned long state; }; +#define to_acpi_ac(x) container_of(x, struct acpi_ac, charger); + static const struct file_operations acpi_ac_fops = { .open = acpi_ac_open_fs, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; +static int get_ac_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct acpi_ac *ac = to_acpi_ac(psy); + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + val->intval = ac->state; + break; + default: + return -EINVAL; + } + return 0; +} + +static enum power_supply_property ac_props[] = { + POWER_SUPPLY_PROP_ONLINE, +}; /* -------------------------------------------------------------------------- AC Adapter Management @@ -208,6 +230,7 @@ static void acpi_ac_notify(acpi_handle handle, u32 event, void *data) acpi_bus_generate_netlink_event(device->pnp.device_class, device->dev.bus_id, event, (u32) ac->state); + kobject_uevent(&ac->charger.dev->kobj, KOBJ_CHANGE); break; default: ACPI_DEBUG_PRINT((ACPI_DB_INFO, @@ -244,7 +267,12 @@ static int acpi_ac_add(struct acpi_device *device) result = acpi_ac_add_fs(device); if (result) goto end; - + ac->charger.name = acpi_device_bid(device); + ac->charger.type = POWER_SUPPLY_TYPE_MAINS; + ac->charger.properties = ac_props; + ac->charger.num_properties = ARRAY_SIZE(ac_props); + ac->charger.get_property = get_ac_property; + power_supply_register(&ac->device->dev, &ac->charger); status = acpi_install_notify_handler(device->handle, ACPI_ALL_NOTIFY, acpi_ac_notify, ac); @@ -279,7 +307,8 @@ static int acpi_ac_remove(struct acpi_device *device, int type) status = acpi_remove_notify_handler(device->handle, ACPI_ALL_NOTIFY, acpi_ac_notify); - + if (ac->charger.dev) + power_supply_unregister(&ac->charger); acpi_ac_remove_fs(device); kfree(ac); diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 9b2c0f74f869..681e26b56b11 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -1,6 +1,8 @@ /* - * acpi_battery.c - ACPI Battery Driver ($Revision: 37 $) + * battery.c - ACPI Battery Driver (Revision: 2.0) * + * Copyright (C) 2007 Alexey Starikovskiy <astarikovskiy@suse.de> + * Copyright (C) 2004-2007 Vladimir Lebedev <vladimir.p.lebedev@intel.com> * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com> * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> * @@ -27,244 +29,288 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/types.h> +#include <linux/jiffies.h> + +#ifdef CONFIG_ACPI_PROCFS #include <linux/proc_fs.h> #include <linux/seq_file.h> #include <asm/uaccess.h> +#endif #include <acpi/acpi_bus.h> #include <acpi/acpi_drivers.h> -#define ACPI_BATTERY_VALUE_UNKNOWN 0xFFFFFFFF +#include <linux/power_supply.h> -#define ACPI_BATTERY_FORMAT_BIF "NNNNNNNNNSSSS" -#define ACPI_BATTERY_FORMAT_BST "NNNN" +#define ACPI_BATTERY_VALUE_UNKNOWN 0xFFFFFFFF #define ACPI_BATTERY_COMPONENT 0x00040000 #define ACPI_BATTERY_CLASS "battery" #define ACPI_BATTERY_DEVICE_NAME "Battery" #define ACPI_BATTERY_NOTIFY_STATUS 0x80 #define ACPI_BATTERY_NOTIFY_INFO 0x81 -#define ACPI_BATTERY_UNITS_WATTS "mW" -#define ACPI_BATTERY_UNITS_AMPS "mA" #define _COMPONENT ACPI_BATTERY_COMPONENT -#define ACPI_BATTERY_UPDATE_TIME 0 - -#define ACPI_BATTERY_NONE_UPDATE 0 -#define ACPI_BATTERY_EASY_UPDATE 1 -#define ACPI_BATTERY_INIT_UPDATE 2 - ACPI_MODULE_NAME("battery"); MODULE_AUTHOR("Paul Diefenbaugh"); +MODULE_AUTHOR("Alexey Starikovskiy <astarikovskiy@suse.de>"); MODULE_DESCRIPTION("ACPI Battery Driver"); MODULE_LICENSE("GPL"); -static unsigned int update_time = ACPI_BATTERY_UPDATE_TIME; - -/* 0 - every time, > 0 - by update_time */ -module_param(update_time, uint, 0644); +static unsigned int cache_time = 1000; +module_param(cache_time, uint, 0644); +MODULE_PARM_DESC(cache_time, "cache time in milliseconds"); +#ifdef CONFIG_ACPI_PROCFS extern struct proc_dir_entry *acpi_lock_battery_dir(void); extern void *acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir); -static int acpi_battery_add(struct acpi_device *device); -static int acpi_battery_remove(struct acpi_device *device, int type); -static int acpi_battery_resume(struct acpi_device *device); +enum acpi_battery_files { + info_tag = 0, + state_tag, + alarm_tag, + ACPI_BATTERY_NUMFILES, +}; + +#endif static const struct acpi_device_id battery_device_ids[] = { {"PNP0C0A", 0}, {"", 0}, }; -MODULE_DEVICE_TABLE(acpi, battery_device_ids); - -static struct acpi_driver acpi_battery_driver = { - .name = "battery", - .class = ACPI_BATTERY_CLASS, - .ids = battery_device_ids, - .ops = { - .add = acpi_battery_add, - .resume = acpi_battery_resume, - .remove = acpi_battery_remove, - }, -}; -struct acpi_battery_state { - acpi_integer state; - acpi_integer present_rate; - acpi_integer remaining_capacity; - acpi_integer present_voltage; -}; - -struct acpi_battery_info { - acpi_integer power_unit; - acpi_integer design_capacity; - acpi_integer last_full_capacity; - acpi_integer battery_technology; - acpi_integer design_voltage; - acpi_integer design_capacity_warning; - acpi_integer design_capacity_low; - acpi_integer battery_capacity_granularity_1; - acpi_integer battery_capacity_granularity_2; - acpi_string model_number; - acpi_string serial_number; - acpi_string battery_type; - acpi_string oem_info; -}; - -enum acpi_battery_files{ - ACPI_BATTERY_INFO = 0, - ACPI_BATTERY_STATE, - ACPI_BATTERY_ALARM, - ACPI_BATTERY_NUMFILES, -}; +MODULE_DEVICE_TABLE(acpi, battery_device_ids); -struct acpi_battery_flags { - u8 battery_present_prev; - u8 alarm_present; - u8 init_update; - u8 update[ACPI_BATTERY_NUMFILES]; - u8 power_unit; -}; struct acpi_battery { - struct mutex mutex; + struct mutex lock; + struct power_supply bat; struct acpi_device *device; - struct acpi_battery_flags flags; - struct acpi_buffer bif_data; - struct acpi_buffer bst_data; - unsigned long alarm; - unsigned long update_time[ACPI_BATTERY_NUMFILES]; + unsigned long update_time; + int current_now; + int capacity_now; + int voltage_now; + int design_capacity; + int full_charge_capacity; + int technology; + int design_voltage; + int design_capacity_warning; + int design_capacity_low; + int capacity_granularity_1; + int capacity_granularity_2; + int alarm; + char model_number[32]; + char serial_number[32]; + char type[32]; + char oem_info[32]; + int state; + int power_unit; + u8 alarm_present; }; +#define to_acpi_battery(x) container_of(x, struct acpi_battery, bat); + inline int acpi_battery_present(struct acpi_battery *battery) { return battery->device->status.battery_present; } -inline char *acpi_battery_power_units(struct acpi_battery *battery) -{ - if (battery->flags.power_unit) - return ACPI_BATTERY_UNITS_AMPS; - else - return ACPI_BATTERY_UNITS_WATTS; -} -inline acpi_handle acpi_battery_handle(struct acpi_battery *battery) +static int acpi_battery_technology(struct acpi_battery *battery) { - return battery->device->handle; + if (!strcasecmp("NiCd", battery->type)) + return POWER_SUPPLY_TECHNOLOGY_NiCd; + if (!strcasecmp("NiMH", battery->type)) + return POWER_SUPPLY_TECHNOLOGY_NiMH; + if (!strcasecmp("LION", battery->type)) + return POWER_SUPPLY_TECHNOLOGY_LION; + if (!strcasecmp("LiP", battery->type)) + return POWER_SUPPLY_TECHNOLOGY_LIPO; + return POWER_SUPPLY_TECHNOLOGY_UNKNOWN; } -/* -------------------------------------------------------------------------- - Battery Management - -------------------------------------------------------------------------- */ - -static void acpi_battery_check_result(struct acpi_battery *battery, int result) +static int acpi_battery_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) { - if (!battery) - return; + struct acpi_battery *battery = to_acpi_battery(psy); - if (result) { - battery->flags.init_update = 1; + if ((!acpi_battery_present(battery)) && + psp != POWER_SUPPLY_PROP_PRESENT) + return -ENODEV; + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + if (battery->state & 0x01) + val->intval = POWER_SUPPLY_STATUS_DISCHARGING; + else if (battery->state & 0x02) + val->intval = POWER_SUPPLY_STATUS_CHARGING; + else if (battery->state == 0) + val->intval = POWER_SUPPLY_STATUS_FULL; + break; + case POWER_SUPPLY_PROP_PRESENT: + val->intval = acpi_battery_present(battery); + break; + case POWER_SUPPLY_PROP_TECHNOLOGY: + val->intval = acpi_battery_technology(battery); + break; + case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: + val->intval = battery->design_voltage * 1000; + break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + val->intval = battery->voltage_now * 1000; + break; + case POWER_SUPPLY_PROP_CURRENT_NOW: + val->intval = battery->current_now * 1000; + break; + case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: + case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN: + val->intval = battery->design_capacity * 1000; + break; + case POWER_SUPPLY_PROP_CHARGE_FULL: + case POWER_SUPPLY_PROP_ENERGY_FULL: + val->intval = battery->full_charge_capacity * 1000; + break; + case POWER_SUPPLY_PROP_CHARGE_NOW: + case POWER_SUPPLY_PROP_ENERGY_NOW: + val->intval = battery->capacity_now * 1000; + break; + case POWER_SUPPLY_PROP_MODEL_NAME: + val->strval = battery->model_number; + break; + case POWER_SUPPLY_PROP_MANUFACTURER: + val->strval = battery->oem_info; + break; + default: + return -EINVAL; } + return 0; } -static int acpi_battery_extract_package(struct acpi_battery *battery, - union acpi_object *package, - struct acpi_buffer *format, - struct acpi_buffer *data, - char *package_name) +static enum power_supply_property charge_battery_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_TECHNOLOGY, + POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, + POWER_SUPPLY_PROP_CHARGE_FULL, + POWER_SUPPLY_PROP_CHARGE_NOW, + POWER_SUPPLY_PROP_MODEL_NAME, + POWER_SUPPLY_PROP_MANUFACTURER, +}; + +static enum power_supply_property energy_battery_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_TECHNOLOGY, + POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, + POWER_SUPPLY_PROP_ENERGY_FULL, + POWER_SUPPLY_PROP_ENERGY_NOW, + POWER_SUPPLY_PROP_MODEL_NAME, + POWER_SUPPLY_PROP_MANUFACTURER, +}; + +#ifdef CONFIG_ACPI_PROCFS +inline char *acpi_battery_units(struct acpi_battery *battery) { - acpi_status status = AE_OK; - struct acpi_buffer data_null = { 0, NULL }; + return (battery->power_unit)?"mA":"mW"; +} +#endif - status = acpi_extract_package(package, format, &data_null); - if (status != AE_BUFFER_OVERFLOW) { - ACPI_EXCEPTION((AE_INFO, status, "Extracting size %s", - package_name)); - return -ENODEV; - } +/* -------------------------------------------------------------------------- + Battery Management + -------------------------------------------------------------------------- */ +struct acpi_offsets { + size_t offset; /* offset inside struct acpi_sbs_battery */ + u8 mode; /* int or string? */ +}; - if (data_null.length != data->length) { - kfree(data->pointer); - data->pointer = kzalloc(data_null.length, GFP_KERNEL); - if (!data->pointer) { - ACPI_EXCEPTION((AE_INFO, AE_NO_MEMORY, "kzalloc()")); - return -ENOMEM; - } - data->length = data_null.length; - } +static struct acpi_offsets state_offsets[] = { + {offsetof(struct acpi_battery, state), 0}, + {offsetof(struct acpi_battery, current_now), 0}, + {offsetof(struct acpi_battery, capacity_now), 0}, + {offsetof(struct acpi_battery, voltage_now), 0}, +}; - status = acpi_extract_package(package, format, data); - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, "Extracting %s", - package_name)); - return -ENODEV; - } +static struct acpi_offsets info_offsets[] = { + {offsetof(struct acpi_battery, power_unit), 0}, + {offsetof(struct acpi_battery, design_capacity), 0}, + {offsetof(struct acpi_battery, full_charge_capacity), 0}, + {offsetof(struct acpi_battery, technology), 0}, + {offsetof(struct acpi_battery, design_voltage), 0}, + {offsetof(struct acpi_battery, design_capacity_warning), 0}, + {offsetof(struct acpi_battery, design_capacity_low), 0}, + {offsetof(struct acpi_battery, capacity_granularity_1), 0}, + {offsetof(struct acpi_battery, capacity_granularity_2), 0}, + {offsetof(struct acpi_battery, model_number), 1}, + {offsetof(struct acpi_battery, serial_number), 1}, + {offsetof(struct acpi_battery, type), 1}, + {offsetof(struct acpi_battery, oem_info), 1}, +}; +static int extract_package(struct acpi_battery *battery, + union acpi_object *package, + struct acpi_offsets *offsets, int num) +{ + int i, *x; + union acpi_object *element; + if (package->type != ACPI_TYPE_PACKAGE) + return -EFAULT; + for (i = 0; i < num; ++i) { + if (package->package.count <= i) + return -EFAULT; + element = &package->package.elements[i]; + if (offsets[i].mode) { + if (element->type != ACPI_TYPE_STRING && + element->type != ACPI_TYPE_BUFFER) + return -EFAULT; + strncpy((u8 *)battery + offsets[i].offset, + element->string.pointer, 32); + } else { + if (element->type != ACPI_TYPE_INTEGER) + return -EFAULT; + x = (int *)((u8 *)battery + offsets[i].offset); + *x = element->integer.value; + } + } return 0; } static int acpi_battery_get_status(struct acpi_battery *battery) { - int result = 0; - - result = acpi_bus_get_status(battery->device); - if (result) { + if (acpi_bus_get_status(battery->device)) { ACPI_EXCEPTION((AE_INFO, AE_ERROR, "Evaluating _STA")); return -ENODEV; } - return result; + return 0; } static int acpi_battery_get_info(struct acpi_battery *battery) { - int result = 0; + int result = -EFAULT; acpi_status status = 0; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - struct acpi_buffer format = { sizeof(ACPI_BATTERY_FORMAT_BIF), - ACPI_BATTERY_FORMAT_BIF - }; - union acpi_object *package = NULL; - struct acpi_buffer *data = NULL; - struct acpi_battery_info *bif = NULL; - - battery->update_time[ACPI_BATTERY_INFO] = get_seconds(); if (!acpi_battery_present(battery)) return 0; + mutex_lock(&battery->lock); + status = acpi_evaluate_object(battery->device->handle, "_BIF", + NULL, &buffer); + mutex_unlock(&battery->lock); - /* Evaluate _BIF */ - - status = - acpi_evaluate_object(acpi_battery_handle(battery), "_BIF", NULL, - &buffer); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BIF")); return -ENODEV; } - package = buffer.pointer; - - data = &battery->bif_data; - - /* Extract Package Data */ - - result = - acpi_battery_extract_package(battery, package, &format, data, - "_BIF"); - if (result) - goto end; - - end: - + result = extract_package(battery, buffer.pointer, + info_offsets, ARRAY_SIZE(info_offsets)); kfree(buffer.pointer); - - if (!result) { - bif = data->pointer; - battery->flags.power_unit = bif->power_unit; - } - return result; } @@ -273,342 +319,203 @@ static int acpi_battery_get_state(struct acpi_battery *battery) int result = 0; acpi_status status = 0; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - struct acpi_buffer format = { sizeof(ACPI_BATTERY_FORMAT_BST), - ACPI_BATTERY_FORMAT_BST - }; - union acpi_object *package = NULL; - struct acpi_buffer *data = NULL; - - battery->update_time[ACPI_BATTERY_STATE] = get_seconds(); if (!acpi_battery_present(battery)) return 0; - /* Evaluate _BST */ + if (battery->update_time && + time_before(jiffies, battery->update_time + + msecs_to_jiffies(cache_time))) + return 0; + + mutex_lock(&battery->lock); + status = acpi_evaluate_object(battery->device->handle, "_BST", + NULL, &buffer); + mutex_unlock(&battery->lock); - status = - acpi_evaluate_object(acpi_battery_handle(battery), "_BST", NULL, - &buffer); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BST")); return -ENODEV; } - package = buffer.pointer; - - data = &battery->bst_data; - - /* Extract Package Data */ - - result = - acpi_battery_extract_package(battery, package, &format, data, - "_BST"); - if (result) - goto end; - - end: + result = extract_package(battery, buffer.pointer, + state_offsets, ARRAY_SIZE(state_offsets)); + battery->update_time = jiffies; kfree(buffer.pointer); - return result; } -static int acpi_battery_get_alarm(struct acpi_battery *battery) -{ - battery->update_time[ACPI_BATTERY_ALARM] = get_seconds(); - - return 0; -} - -static int acpi_battery_set_alarm(struct acpi_battery *battery, - unsigned long alarm) +static int acpi_battery_set_alarm(struct acpi_battery *battery) { acpi_status status = 0; - union acpi_object arg0 = { ACPI_TYPE_INTEGER }; + union acpi_object arg0 = { .type = ACPI_TYPE_INTEGER }; struct acpi_object_list arg_list = { 1, &arg0 }; - battery->update_time[ACPI_BATTERY_ALARM] = get_seconds(); - - if (!acpi_battery_present(battery)) + if (!acpi_battery_present(battery)|| !battery->alarm_present) return -ENODEV; - if (!battery->flags.alarm_present) - return -ENODEV; - - arg0.integer.value = alarm; + arg0.integer.value = battery->alarm; - status = - acpi_evaluate_object(acpi_battery_handle(battery), "_BTP", + mutex_lock(&battery->lock); + status = acpi_evaluate_object(battery->device->handle, "_BTP", &arg_list, NULL); + mutex_unlock(&battery->lock); + if (ACPI_FAILURE(status)) return -ENODEV; - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Alarm set to %d\n", (u32) alarm)); - - battery->alarm = alarm; - + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Alarm set to %d\n", battery->alarm)); return 0; } static int acpi_battery_init_alarm(struct acpi_battery *battery) { - int result = 0; acpi_status status = AE_OK; acpi_handle handle = NULL; - struct acpi_battery_info *bif = battery->bif_data.pointer; - unsigned long alarm = battery->alarm; /* See if alarms are supported, and if so, set default */ - - status = acpi_get_handle(acpi_battery_handle(battery), "_BTP", &handle); - if (ACPI_SUCCESS(status)) { - battery->flags.alarm_present = 1; - if (!alarm && bif) { - alarm = bif->design_capacity_warning; - } - result = acpi_battery_set_alarm(battery, alarm); - if (result) - goto end; - } else { - battery->flags.alarm_present = 0; + status = acpi_get_handle(battery->device->handle, "_BTP", &handle); + if (ACPI_FAILURE(status)) { + battery->alarm_present = 0; + return 0; } - - end: - - return result; + battery->alarm_present = 1; + if (!battery->alarm) + battery->alarm = battery->design_capacity_warning; + return acpi_battery_set_alarm(battery); } -static int acpi_battery_init_update(struct acpi_battery *battery) +static int acpi_battery_update(struct acpi_battery *battery) { - int result = 0; - - result = acpi_battery_get_status(battery); - if (result) + int saved_present = acpi_battery_present(battery); + int result = acpi_battery_get_status(battery); + if (result || !acpi_battery_present(battery)) return result; - - battery->flags.battery_present_prev = acpi_battery_present(battery); - - if (acpi_battery_present(battery)) { + if (saved_present != acpi_battery_present(battery) || + !battery->update_time) { + battery->update_time = 0; result = acpi_battery_get_info(battery); if (result) return result; - result = acpi_battery_get_state(battery); - if (result) - return result; - - acpi_battery_init_alarm(battery); - } - - return result; -} - -static int acpi_battery_update(struct acpi_battery *battery, - int update, int *update_result_ptr) -{ - int result = 0; - int update_result = ACPI_BATTERY_NONE_UPDATE; - - if (!acpi_battery_present(battery)) { - update = 1; - } - - if (battery->flags.init_update) { - result = acpi_battery_init_update(battery); - if (result) - goto end; - update_result = ACPI_BATTERY_INIT_UPDATE; - } else if (update) { - result = acpi_battery_get_status(battery); - if (result) - goto end; - if ((!battery->flags.battery_present_prev & acpi_battery_present(battery)) - || (battery->flags.battery_present_prev & !acpi_battery_present(battery))) { - result = acpi_battery_init_update(battery); - if (result) - goto end; - update_result = ACPI_BATTERY_INIT_UPDATE; + if (battery->power_unit) { + battery->bat.properties = charge_battery_props; + battery->bat.num_properties = + ARRAY_SIZE(charge_battery_props); } else { - update_result = ACPI_BATTERY_EASY_UPDATE; + battery->bat.properties = energy_battery_props; + battery->bat.num_properties = + ARRAY_SIZE(energy_battery_props); } + acpi_battery_init_alarm(battery); } - - end: - - battery->flags.init_update = (result != 0); - - *update_result_ptr = update_result; - - return result; -} - -static void acpi_battery_notify_update(struct acpi_battery *battery) -{ - acpi_battery_get_status(battery); - - if (battery->flags.init_update) { - return; - } - - if ((!battery->flags.battery_present_prev & - acpi_battery_present(battery)) || - (battery->flags.battery_present_prev & - !acpi_battery_present(battery))) { - battery->flags.init_update = 1; - } else { - battery->flags.update[ACPI_BATTERY_INFO] = 1; - battery->flags.update[ACPI_BATTERY_STATE] = 1; - battery->flags.update[ACPI_BATTERY_ALARM] = 1; - } + return acpi_battery_get_state(battery); } /* -------------------------------------------------------------------------- FS Interface (/proc) -------------------------------------------------------------------------- */ +#ifdef CONFIG_ACPI_PROCFS static struct proc_dir_entry *acpi_battery_dir; static int acpi_battery_print_info(struct seq_file *seq, int result) { struct acpi_battery *battery = seq->private; - struct acpi_battery_info *bif = NULL; - char *units = "?"; if (result) goto end; - if (acpi_battery_present(battery)) - seq_printf(seq, "present: yes\n"); - else { - seq_printf(seq, "present: no\n"); - goto end; - } - - bif = battery->bif_data.pointer; - if (!bif) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, "BIF buffer is NULL")); - result = -ENODEV; + seq_printf(seq, "present: %s\n", + acpi_battery_present(battery)?"yes":"no"); + if (!acpi_battery_present(battery)) goto end; - } - - /* Battery Units */ - - units = acpi_battery_power_units(battery); - - if (bif->design_capacity == ACPI_BATTERY_VALUE_UNKNOWN) + if (battery->design_capacity == ACPI_BATTERY_VALUE_UNKNOWN) seq_printf(seq, "design capacity: unknown\n"); else seq_printf(seq, "design capacity: %d %sh\n", - (u32) bif->design_capacity, units); + battery->design_capacity, + acpi_battery_units(battery)); - if (bif->last_full_capacity == ACPI_BATTERY_VALUE_UNKNOWN) + if (battery->full_charge_capacity == ACPI_BATTERY_VALUE_UNKNOWN) seq_printf(seq, "last full capacity: unknown\n"); else seq_printf(seq, "last full capacity: %d %sh\n", - (u32) bif->last_full_capacity, units); + battery->full_charge_capacity, + acpi_battery_units(battery)); - switch ((u32) bif->battery_technology) { - case 0: - seq_printf(seq, "battery technology: non-rechargeable\n"); - break; - case 1: - seq_printf(seq, "battery technology: rechargeable\n"); - break; - default: - seq_printf(seq, "battery technology: unknown\n"); - break; - } + seq_printf(seq, "battery technology: %srechargeable\n", + (!battery->technology)?"non-":""); - if (bif->design_voltage == ACPI_BATTERY_VALUE_UNKNOWN) + if (battery->design_voltage == ACPI_BATTERY_VALUE_UNKNOWN) seq_printf(seq, "design voltage: unknown\n"); else seq_printf(seq, "design voltage: %d mV\n", - (u32) bif->design_voltage); + battery->design_voltage); seq_printf(seq, "design capacity warning: %d %sh\n", - (u32) bif->design_capacity_warning, units); + battery->design_capacity_warning, + acpi_battery_units(battery)); seq_printf(seq, "design capacity low: %d %sh\n", - (u32) bif->design_capacity_low, units); + battery->design_capacity_low, + acpi_battery_units(battery)); seq_printf(seq, "capacity granularity 1: %d %sh\n", - (u32) bif->battery_capacity_granularity_1, units); + battery->capacity_granularity_1, + acpi_battery_units(battery)); seq_printf(seq, "capacity granularity 2: %d %sh\n", - (u32) bif->battery_capacity_granularity_2, units); - seq_printf(seq, "model number: %s\n", bif->model_number); - seq_printf(seq, "serial number: %s\n", bif->serial_number); - seq_printf(seq, "battery type: %s\n", bif->battery_type); - seq_printf(seq, "OEM info: %s\n", bif->oem_info); - + battery->capacity_granularity_2, + acpi_battery_units(battery)); + seq_printf(seq, "model number: %s\n", battery->model_number); + seq_printf(seq, "serial number: %s\n", battery->serial_number); + seq_printf(seq, "battery type: %s\n", battery->type); + seq_printf(seq, "OEM info: %s\n", battery->oem_info); end: - if (result) seq_printf(seq, "ERROR: Unable to read battery info\n"); - return result; } static int acpi_battery_print_state(struct seq_file *seq, int result) { struct acpi_battery *battery = seq->private; - struct acpi_battery_state *bst = NULL; - char *units = "?"; if (result) goto end; - if (acpi_battery_present(battery)) - seq_printf(seq, "present: yes\n"); - else { - seq_printf(seq, "present: no\n"); - goto end; - } - - bst = battery->bst_data.pointer; - if (!bst) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, "BST buffer is NULL")); - result = -ENODEV; + seq_printf(seq, "present: %s\n", + acpi_battery_present(battery)?"yes":"no"); + if (!acpi_battery_present(battery)) goto end; - } - - /* Battery Units */ - - units = acpi_battery_power_units(battery); - - if (!(bst->state & 0x04)) - seq_printf(seq, "capacity state: ok\n"); - else - seq_printf(seq, "capacity state: critical\n"); - if ((bst->state & 0x01) && (bst->state & 0x02)) { + seq_printf(seq, "capacity state: %s\n", + (battery->state & 0x04)?"critical":"ok"); + if ((battery->state & 0x01) && (battery->state & 0x02)) seq_printf(seq, "charging state: charging/discharging\n"); - } else if (bst->state & 0x01) + else if (battery->state & 0x01) seq_printf(seq, "charging state: discharging\n"); - else if (bst->state & 0x02) + else if (battery->state & 0x02) seq_printf(seq, "charging state: charging\n"); - else { + else seq_printf(seq, "charging state: charged\n"); - } - if (bst->present_rate == ACPI_BATTERY_VALUE_UNKNOWN) + if (battery->current_now == ACPI_BATTERY_VALUE_UNKNOWN) seq_printf(seq, "present rate: unknown\n"); else seq_printf(seq, "present rate: %d %s\n", - (u32) bst->present_rate, units); + battery->current_now, acpi_battery_units(battery)); - if (bst->remaining_capacity == ACPI_BATTERY_VALUE_UNKNOWN) + if (battery->capacity_now == ACPI_BATTERY_VALUE_UNKNOWN) seq_printf(seq, "remaining capacity: unknown\n"); else seq_printf(seq, "remaining capacity: %d %sh\n", - (u32) bst->remaining_capacity, units); - - if (bst->present_voltage == ACPI_BATTERY_VALUE_UNKNOWN) + battery->capacity_now, acpi_battery_units(battery)); + if (battery->voltage_now == ACPI_BATTERY_VALUE_UNKNOWN) seq_printf(seq, "present voltage: unknown\n"); else seq_printf(seq, "present voltage: %d mV\n", - (u32) bst->present_voltage); - + battery->voltage_now); end: - - if (result) { + if (result) seq_printf(seq, "ERROR: Unable to read battery state\n"); - } return result; } @@ -616,7 +523,6 @@ static int acpi_battery_print_state(struct seq_file *seq, int result) static int acpi_battery_print_alarm(struct seq_file *seq, int result) { struct acpi_battery *battery = seq->private; - char *units = "?"; if (result) goto end; @@ -625,189 +531,121 @@ static int acpi_battery_print_alarm(struct seq_file *seq, int result) seq_printf(seq, "present: no\n"); goto end; } - - /* Battery Units */ - - units = acpi_battery_power_units(battery); - seq_printf(seq, "alarm: "); if (!battery->alarm) seq_printf(seq, "unsupported\n"); else - seq_printf(seq, "%lu %sh\n", battery->alarm, units); - + seq_printf(seq, "%u %sh\n", battery->alarm, + acpi_battery_units(battery)); end: - if (result) seq_printf(seq, "ERROR: Unable to read battery alarm\n"); - return result; } -static ssize_t -acpi_battery_write_alarm(struct file *file, - const char __user * buffer, - size_t count, loff_t * ppos) +static ssize_t acpi_battery_write_alarm(struct file *file, + const char __user * buffer, + size_t count, loff_t * ppos) { int result = 0; char alarm_string[12] = { '\0' }; struct seq_file *m = file->private_data; struct acpi_battery *battery = m->private; - int update_result = ACPI_BATTERY_NONE_UPDATE; if (!battery || (count > sizeof(alarm_string) - 1)) return -EINVAL; - - mutex_lock(&battery->mutex); - - result = acpi_battery_update(battery, 1, &update_result); if (result) { result = -ENODEV; goto end; } - if (!acpi_battery_present(battery)) { result = -ENODEV; goto end; } - if (copy_from_user(alarm_string, buffer, count)) { result = -EFAULT; goto end; } - alarm_string[count] = '\0'; - - result = acpi_battery_set_alarm(battery, - simple_strtoul(alarm_string, NULL, 0)); - if (result) - goto end; - + battery->alarm = simple_strtol(alarm_string, NULL, 0); + result = acpi_battery_set_alarm(battery); end: - - acpi_battery_check_result(battery, result); - if (!result) - result = count; - - mutex_unlock(&battery->mutex); - + return count; return result; } typedef int(*print_func)(struct seq_file *seq, int result); -typedef int(*get_func)(struct acpi_battery *battery); - -static struct acpi_read_mux { - print_func print; - get_func get; -} acpi_read_funcs[ACPI_BATTERY_NUMFILES] = { - {.get = acpi_battery_get_info, .print = acpi_battery_print_info}, - {.get = acpi_battery_get_state, .print = acpi_battery_print_state}, - {.get = acpi_battery_get_alarm, .print = acpi_battery_print_alarm}, + +static print_func acpi_print_funcs[ACPI_BATTERY_NUMFILES] = { + acpi_battery_print_info, + acpi_battery_print_state, + acpi_battery_print_alarm, }; static int acpi_battery_read(int fid, struct seq_file *seq) { struct acpi_battery *battery = seq->private; - int result = 0; - int update_result = ACPI_BATTERY_NONE_UPDATE; - int update = 0; - - mutex_lock(&battery->mutex); - - update = (get_seconds() - battery->update_time[fid] >= update_time); - update = (update | battery->flags.update[fid]); - - result = acpi_battery_update(battery, update, &update_result); - if (result) - goto end; - - if (update_result == ACPI_BATTERY_EASY_UPDATE) { - result = acpi_read_funcs[fid].get(battery); - if (result) - goto end; + int result = acpi_battery_update(battery); + return acpi_print_funcs[fid](seq, result); +} + +#define DECLARE_FILE_FUNCTIONS(_name) \ +static int acpi_battery_read_##_name(struct seq_file *seq, void *offset) \ +{ \ + return acpi_battery_read(_name##_tag, seq); \ +} \ +static int acpi_battery_##_name##_open_fs(struct inode *inode, struct file *file) \ +{ \ + return single_open(file, acpi_battery_read_##_name, PDE(inode)->data); \ +} + +DECLARE_FILE_FUNCTIONS(info); +DECLARE_FILE_FUNCTIONS(state); +DECLARE_FILE_FUNCTIONS(alarm); + +#undef DECLARE_FILE_FUNCTIONS + +#define FILE_DESCRIPTION_RO(_name) \ + { \ + .name = __stringify(_name), \ + .mode = S_IRUGO, \ + .ops = { \ + .open = acpi_battery_##_name##_open_fs, \ + .read = seq_read, \ + .llseek = seq_lseek, \ + .release = single_release, \ + .owner = THIS_MODULE, \ + }, \ + } + +#define FILE_DESCRIPTION_RW(_name) \ + { \ + .name = __stringify(_name), \ + .mode = S_IFREG | S_IRUGO | S_IWUSR, \ + .ops = { \ + .open = acpi_battery_##_name##_open_fs, \ + .read = seq_read, \ + .llseek = seq_lseek, \ + .write = acpi_battery_write_##_name, \ + .release = single_release, \ + .owner = THIS_MODULE, \ + }, \ } - end: - result = acpi_read_funcs[fid].print(seq, result); - acpi_battery_check_result(battery, result); - battery->flags.update[fid] = result; - mutex_unlock(&battery->mutex); - return result; -} - -static int acpi_battery_read_info(struct seq_file *seq, void *offset) -{ - return acpi_battery_read(ACPI_BATTERY_INFO, seq); -} - -static int acpi_battery_read_state(struct seq_file *seq, void *offset) -{ - return acpi_battery_read(ACPI_BATTERY_STATE, seq); -} - -static int acpi_battery_read_alarm(struct seq_file *seq, void *offset) -{ - return acpi_battery_read(ACPI_BATTERY_ALARM, seq); -} - -static int acpi_battery_info_open_fs(struct inode *inode, struct file *file) -{ - return single_open(file, acpi_battery_read_info, PDE(inode)->data); -} - -static int acpi_battery_state_open_fs(struct inode *inode, struct file *file) -{ - return single_open(file, acpi_battery_read_state, PDE(inode)->data); -} - -static int acpi_battery_alarm_open_fs(struct inode *inode, struct file *file) -{ - return single_open(file, acpi_battery_read_alarm, PDE(inode)->data); -} - static struct battery_file { struct file_operations ops; mode_t mode; char *name; } acpi_battery_file[] = { - { - .name = "info", - .mode = S_IRUGO, - .ops = { - .open = acpi_battery_info_open_fs, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, - }, - }, - { - .name = "state", - .mode = S_IRUGO, - .ops = { - .open = acpi_battery_state_open_fs, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, - }, - }, - { - .name = "alarm", - .mode = S_IFREG | S_IRUGO | S_IWUSR, - .ops = { - .open = acpi_battery_alarm_open_fs, - .read = seq_read, - .write = acpi_battery_write_alarm, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, - }, - }, + FILE_DESCRIPTION_RO(info), + FILE_DESCRIPTION_RO(state), + FILE_DESCRIPTION_RW(alarm), }; +#undef FILE_DESCRIPTION_RO +#undef FILE_DESCRIPTION_RW + static int acpi_battery_add_fs(struct acpi_device *device) { struct proc_dir_entry *entry = NULL; @@ -832,25 +670,51 @@ static int acpi_battery_add_fs(struct acpi_device *device) entry->owner = THIS_MODULE; } } - return 0; } -static int acpi_battery_remove_fs(struct acpi_device *device) +static void acpi_battery_remove_fs(struct acpi_device *device) { int i; - if (acpi_device_dir(device)) { - for (i = 0; i < ACPI_BATTERY_NUMFILES; ++i) { - remove_proc_entry(acpi_battery_file[i].name, + if (!acpi_device_dir(device)) + return; + for (i = 0; i < ACPI_BATTERY_NUMFILES; ++i) + remove_proc_entry(acpi_battery_file[i].name, acpi_device_dir(device)); - } - remove_proc_entry(acpi_device_bid(device), acpi_battery_dir); - acpi_device_dir(device) = NULL; - } - return 0; + remove_proc_entry(acpi_device_bid(device), acpi_battery_dir); + acpi_device_dir(device) = NULL; +} + +#endif + +static ssize_t acpi_battery_alarm_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev)); + return sprintf(buf, "%d\n", battery->alarm * 1000); +} + +static ssize_t acpi_battery_alarm_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long x; + struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev)); + if (sscanf(buf, "%ld\n", &x) == 1) + battery->alarm = x/1000; + if (acpi_battery_present(battery)) + acpi_battery_set_alarm(battery); + return count; } +static struct device_attribute alarm_attr = { + .attr = {.name = "alarm", .mode = 0644, .owner = THIS_MODULE}, + .show = acpi_battery_alarm_show, + .store = acpi_battery_alarm_store, +}; + /* -------------------------------------------------------------------------- Driver Interface -------------------------------------------------------------------------- */ @@ -858,33 +722,17 @@ static int acpi_battery_remove_fs(struct acpi_device *device) static void acpi_battery_notify(acpi_handle handle, u32 event, void *data) { struct acpi_battery *battery = data; - struct acpi_device *device = NULL; - + struct acpi_device *device; if (!battery) return; - device = battery->device; - - switch (event) { - case ACPI_BATTERY_NOTIFY_STATUS: - case ACPI_BATTERY_NOTIFY_INFO: - case ACPI_NOTIFY_BUS_CHECK: - case ACPI_NOTIFY_DEVICE_CHECK: - device = battery->device; - acpi_battery_notify_update(battery); - acpi_bus_generate_proc_event(device, event, + acpi_battery_update(battery); + acpi_bus_generate_proc_event(device, event, + acpi_battery_present(battery)); + acpi_bus_generate_netlink_event(device->pnp.device_class, + device->dev.bus_id, event, acpi_battery_present(battery)); - acpi_bus_generate_netlink_event(device->pnp.device_class, - device->dev.bus_id, event, - acpi_battery_present(battery)); - break; - default: - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Unsupported event [0x%x]\n", event)); - break; - } - - return; + kobject_uevent(&battery->bat.dev->kobj, KOBJ_CHANGE); } static int acpi_battery_add(struct acpi_device *device) @@ -892,33 +740,27 @@ static int acpi_battery_add(struct acpi_device *device) int result = 0; acpi_status status = 0; struct acpi_battery *battery = NULL; - if (!device) return -EINVAL; - battery = kzalloc(sizeof(struct acpi_battery), GFP_KERNEL); if (!battery) return -ENOMEM; - - mutex_init(&battery->mutex); - - mutex_lock(&battery->mutex); - battery->device = device; strcpy(acpi_device_name(device), ACPI_BATTERY_DEVICE_NAME); strcpy(acpi_device_class(device), ACPI_BATTERY_CLASS); acpi_driver_data(device) = battery; - - result = acpi_battery_get_status(battery); - if (result) - goto end; - - battery->flags.init_update = 1; - + mutex_init(&battery->lock); + acpi_battery_update(battery); +#ifdef CONFIG_ACPI_PROCFS result = acpi_battery_add_fs(device); if (result) goto end; - +#endif + battery->bat.name = acpi_device_bid(device); + battery->bat.type = POWER_SUPPLY_TYPE_BATTERY; + battery->bat.get_property = acpi_battery_get_property; + result = power_supply_register(&battery->device->dev, &battery->bat); + result = device_create_file(battery->bat.dev, &alarm_attr); status = acpi_install_notify_handler(device->handle, ACPI_ALL_NOTIFY, acpi_battery_notify, battery); @@ -927,20 +769,16 @@ static int acpi_battery_add(struct acpi_device *device) result = -ENODEV; goto end; } - printk(KERN_INFO PREFIX "%s Slot [%s] (battery %s)\n", ACPI_BATTERY_DEVICE_NAME, acpi_device_bid(device), device->status.battery_present ? "present" : "absent"); - end: - if (result) { +#ifdef CONFIG_ACPI_PROCFS acpi_battery_remove_fs(device); +#endif kfree(battery); } - - mutex_unlock(&battery->mutex); - return result; } @@ -951,27 +789,19 @@ static int acpi_battery_remove(struct acpi_device *device, int type) if (!device || !acpi_driver_data(device)) return -EINVAL; - battery = acpi_driver_data(device); - - mutex_lock(&battery->mutex); - status = acpi_remove_notify_handler(device->handle, ACPI_ALL_NOTIFY, acpi_battery_notify); - +#ifdef CONFIG_ACPI_PROCFS acpi_battery_remove_fs(device); - - kfree(battery->bif_data.pointer); - - kfree(battery->bst_data.pointer); - - mutex_unlock(&battery->mutex); - - mutex_destroy(&battery->mutex); - +#endif + if (battery->bat.dev) { + device_remove_file(battery->bat.dev, &alarm_attr); + power_supply_unregister(&battery->bat); + } + mutex_destroy(&battery->lock); kfree(battery); - return 0; } @@ -979,44 +809,48 @@ static int acpi_battery_remove(struct acpi_device *device, int type) static int acpi_battery_resume(struct acpi_device *device) { struct acpi_battery *battery; - if (!device) return -EINVAL; - - battery = device->driver_data; - - battery->flags.init_update = 1; - + battery = acpi_driver_data(device); + battery->update_time = 0; return 0; } +static struct acpi_driver acpi_battery_driver = { + .name = "battery", + .class = ACPI_BATTERY_CLASS, + .ids = battery_device_ids, + .ops = { + .add = acpi_battery_add, + .resume = acpi_battery_resume, + .remove = acpi_battery_remove, + }, +}; + static int __init acpi_battery_init(void) { - int result; - if (acpi_disabled) return -ENODEV; - +#ifdef CONFIG_ACPI_PROCFS acpi_battery_dir = acpi_lock_battery_dir(); if (!acpi_battery_dir) return -ENODEV; - - result = acpi_bus_register_driver(&acpi_battery_driver); - if (result < 0) { +#endif + if (acpi_bus_register_driver(&acpi_battery_driver) < 0) { +#ifdef CONFIG_ACPI_PROCFS acpi_unlock_battery_dir(acpi_battery_dir); +#endif return -ENODEV; } - return 0; } static void __exit acpi_battery_exit(void) { acpi_bus_unregister_driver(&acpi_battery_driver); - +#ifdef CONFIG_ACPI_PROCFS acpi_unlock_battery_dir(acpi_battery_dir); - - return; +#endif } module_init(acpi_battery_init); diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 9ba778a2b484..a54234d3aac1 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -284,15 +284,11 @@ DECLARE_WAIT_QUEUE_HEAD(acpi_bus_event_queue); extern int event_is_open; -int acpi_bus_generate_proc_event(struct acpi_device *device, u8 type, int data) +int acpi_bus_generate_proc_event4(const char *device_class, const char *bus_id, u8 type, int data) { - struct acpi_bus_event *event = NULL; + struct acpi_bus_event *event; unsigned long flags = 0; - - if (!device) - return -EINVAL; - /* drop event on the floor if no one's listening */ if (!event_is_open) return 0; @@ -301,8 +297,8 @@ int acpi_bus_generate_proc_event(struct acpi_device *device, u8 type, int data) if (!event) return -ENOMEM; - strcpy(event->device_class, device->pnp.device_class); - strcpy(event->bus_id, device->pnp.bus_id); + strcpy(event->device_class, device_class); + strcpy(event->bus_id, bus_id); event->type = type; event->data = data; @@ -313,6 +309,17 @@ int acpi_bus_generate_proc_event(struct acpi_device *device, u8 type, int data) wake_up_interruptible(&acpi_bus_event_queue); return 0; + +} + +EXPORT_SYMBOL_GPL(acpi_bus_generate_proc_event4); + +int acpi_bus_generate_proc_event(struct acpi_device *device, u8 type, int data) +{ + if (!device) + return -EINVAL; + return acpi_bus_generate_proc_event4(device->pnp.device_class, + device->pnp.bus_id, type, data); } EXPORT_SYMBOL(acpi_bus_generate_proc_event); diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 9cd7997312e0..7b4178393e34 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -426,7 +426,7 @@ int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit, handler->func = func; handler->data = data; mutex_lock(&ec->lock); - list_add_tail(&handler->node, &ec->list); + list_add(&handler->node, &ec->list); mutex_unlock(&ec->lock); return 0; } @@ -441,7 +441,6 @@ void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit) if (query_bit == handler->query_bit) { list_del(&handler->node); kfree(handler); - break; } } mutex_unlock(&ec->lock); diff --git a/drivers/acpi/event.c b/drivers/acpi/event.c index a2b9304596ce..5c95863f8fa9 100644 --- a/drivers/acpi/event.c +++ b/drivers/acpi/event.c @@ -240,7 +240,7 @@ int acpi_bus_generate_netlink_event(const char *device_class, return 0; } -EXPORT_SYMBOL(acpi_generate_netlink_event); +EXPORT_SYMBOL(acpi_bus_generate_netlink_event); static int acpi_event_genetlink_init(void) { diff --git a/drivers/acpi/hardware/hwsleep.c b/drivers/acpi/hardware/hwsleep.c index cf69c0040a39..8181afbd1d4d 100644 --- a/drivers/acpi/hardware/hwsleep.c +++ b/drivers/acpi/hardware/hwsleep.c @@ -234,15 +234,11 @@ acpi_status acpi_enter_sleep_state_prep(u8 sleep_state) "While executing method _SST")); } - /* - * 1) Disable/Clear all GPEs - */ + /* Disable/Clear all GPEs */ + status = acpi_hw_disable_all_gpes(); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - return_ACPI_STATUS(AE_OK); + return_ACPI_STATUS(status); } ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state_prep) diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index e944aaee4e06..9f11dc296cdd 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -102,6 +102,8 @@ static struct acpi_driver acpi_processor_driver = { .add = acpi_processor_add, .remove = acpi_processor_remove, .start = acpi_processor_start, + .suspend = acpi_processor_suspend, + .resume = acpi_processor_resume, }, }; @@ -724,6 +726,25 @@ static void acpi_processor_notify(acpi_handle handle, u32 event, void *data) return; } +static int acpi_cpu_soft_notify(struct notifier_block *nfb, + unsigned long action, void *hcpu) +{ + unsigned int cpu = (unsigned long)hcpu; + struct acpi_processor *pr = processors[cpu]; + + if (action == CPU_ONLINE && pr) { + acpi_processor_ppc_has_changed(pr); + acpi_processor_cst_has_changed(pr); + acpi_processor_tstate_has_changed(pr); + } + return NOTIFY_OK; +} + +static struct notifier_block acpi_cpu_notifier = +{ + .notifier_call = acpi_cpu_soft_notify, +}; + static int acpi_processor_add(struct acpi_device *device) { struct acpi_processor *pr = NULL; @@ -987,6 +1008,7 @@ void acpi_processor_install_hotplug_notify(void) ACPI_UINT32_MAX, processor_walk_namespace_cb, &action, NULL); #endif + register_hotcpu_notifier(&acpi_cpu_notifier); } static @@ -999,6 +1021,7 @@ void acpi_processor_uninstall_hotplug_notify(void) ACPI_UINT32_MAX, processor_walk_namespace_cb, &action, NULL); #endif + unregister_hotcpu_notifier(&acpi_cpu_notifier); } /* diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index d9b8af763e1e..f18261368e76 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -325,6 +325,23 @@ static void acpi_state_timer_broadcast(struct acpi_processor *pr, #endif +/* + * Suspend / resume control + */ +static int acpi_idle_suspend; + +int acpi_processor_suspend(struct acpi_device * device, pm_message_t state) +{ + acpi_idle_suspend = 1; + return 0; +} + +int acpi_processor_resume(struct acpi_device * device) +{ + acpi_idle_suspend = 0; + return 0; +} + static void acpi_processor_idle(void) { struct acpi_processor *pr = NULL; @@ -355,7 +372,7 @@ static void acpi_processor_idle(void) } cx = pr->power.state; - if (!cx) { + if (!cx || acpi_idle_suspend) { if (pm_idle_save) pm_idle_save(); else diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c index a578986e3214..90fd09c65f95 100644 --- a/drivers/acpi/sbs.c +++ b/drivers/acpi/sbs.c @@ -1,6 +1,8 @@ /* - * acpi_sbs.c - ACPI Smart Battery System Driver ($Revision: 1.16 $) + * sbs.c - ACPI Smart Battery System Driver ($Revision: 2.0 $) * + * Copyright (c) 2007 Alexey Starikovskiy <astarikovskiy@suse.de> + * Copyright (c) 2005-2007 Vladimir Lebedev <vladimir.p.lebedev@intel.com> * Copyright (c) 2005 Rich Townsend <rhdt@bartol.udel.edu> * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -26,15 +28,22 @@ #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/kernel.h> + +#ifdef CONFIG_ACPI_PROCFS #include <linux/proc_fs.h> #include <linux/seq_file.h> #include <asm/uaccess.h> +#endif + #include <linux/acpi.h> #include <linux/timer.h> #include <linux/jiffies.h> #include <linux/delay.h> -#define ACPI_SBS_COMPONENT 0x00080000 +#include <linux/power_supply.h> + +#include "sbshc.h" + #define ACPI_SBS_CLASS "sbs" #define ACPI_AC_CLASS "ac_adapter" #define ACPI_BATTERY_CLASS "battery" @@ -44,836 +53,436 @@ #define ACPI_SBS_FILE_ALARM "alarm" #define ACPI_BATTERY_DIR_NAME "BAT%i" #define ACPI_AC_DIR_NAME "AC0" -#define ACPI_SBC_SMBUS_ADDR 0x9 -#define ACPI_SBSM_SMBUS_ADDR 0xa -#define ACPI_SB_SMBUS_ADDR 0xb -#define ACPI_SBS_AC_NOTIFY_STATUS 0x80 -#define ACPI_SBS_BATTERY_NOTIFY_STATUS 0x80 -#define ACPI_SBS_BATTERY_NOTIFY_INFO 0x81 -#define _COMPONENT ACPI_SBS_COMPONENT +enum acpi_sbs_device_addr { + ACPI_SBS_CHARGER = 0x9, + ACPI_SBS_MANAGER = 0xa, + ACPI_SBS_BATTERY = 0xb, +}; -ACPI_MODULE_NAME("sbs"); +#define ACPI_SBS_NOTIFY_STATUS 0x80 +#define ACPI_SBS_NOTIFY_INFO 0x81 -MODULE_AUTHOR("Rich Townsend"); +MODULE_AUTHOR("Alexey Starikovskiy <astarikovskiy@suse.de>"); MODULE_DESCRIPTION("Smart Battery System ACPI interface driver"); MODULE_LICENSE("GPL"); -#define xmsleep(t) msleep(t) - -#define ACPI_EC_SMB_PRTCL 0x00 /* protocol, PEC */ - -#define ACPI_EC_SMB_STS 0x01 /* status */ -#define ACPI_EC_SMB_ADDR 0x02 /* address */ -#define ACPI_EC_SMB_CMD 0x03 /* command */ -#define ACPI_EC_SMB_DATA 0x04 /* 32 data registers */ -#define ACPI_EC_SMB_BCNT 0x24 /* number of data bytes */ - -#define ACPI_EC_SMB_STS_DONE 0x80 -#define ACPI_EC_SMB_STS_STATUS 0x1f - -#define ACPI_EC_SMB_PRTCL_WRITE 0x00 -#define ACPI_EC_SMB_PRTCL_READ 0x01 -#define ACPI_EC_SMB_PRTCL_WORD_DATA 0x08 -#define ACPI_EC_SMB_PRTCL_BLOCK_DATA 0x0a - -#define ACPI_EC_SMB_TRANSACTION_SLEEP 1 -#define ACPI_EC_SMB_ACCESS_SLEEP1 1 -#define ACPI_EC_SMB_ACCESS_SLEEP2 10 - -#define DEF_CAPACITY_UNIT 3 -#define MAH_CAPACITY_UNIT 1 -#define MWH_CAPACITY_UNIT 2 -#define CAPACITY_UNIT DEF_CAPACITY_UNIT - -#define REQUEST_UPDATE_MODE 1 -#define QUEUE_UPDATE_MODE 2 - -#define DATA_TYPE_COMMON 0 -#define DATA_TYPE_INFO 1 -#define DATA_TYPE_STATE 2 -#define DATA_TYPE_ALARM 3 -#define DATA_TYPE_AC_STATE 4 +static unsigned int cache_time = 1000; +module_param(cache_time, uint, 0644); +MODULE_PARM_DESC(cache_time, "cache time in milliseconds"); extern struct proc_dir_entry *acpi_lock_ac_dir(void); extern struct proc_dir_entry *acpi_lock_battery_dir(void); extern void acpi_unlock_ac_dir(struct proc_dir_entry *acpi_ac_dir); extern void acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir); -#define MAX_SBS_BAT 4 +#define MAX_SBS_BAT 4 #define ACPI_SBS_BLOCK_MAX 32 -#define ACPI_SBS_SMBUS_READ 1 -#define ACPI_SBS_SMBUS_WRITE 2 - -#define ACPI_SBS_WORD_DATA 1 -#define ACPI_SBS_BLOCK_DATA 2 - -#define UPDATE_DELAY 10 - -/* 0 - every time, > 0 - by update_time */ -static unsigned int update_time = 120; - -static unsigned int capacity_mode = CAPACITY_UNIT; - -module_param(update_time, uint, 0644); -module_param(capacity_mode, uint, 0444); - -static int acpi_sbs_add(struct acpi_device *device); -static int acpi_sbs_remove(struct acpi_device *device, int type); -static int acpi_sbs_resume(struct acpi_device *device); - static const struct acpi_device_id sbs_device_ids[] = { - {"ACPI0001", 0}, - {"ACPI0005", 0}, + {"ACPI0002", 0}, {"", 0}, }; MODULE_DEVICE_TABLE(acpi, sbs_device_ids); -static struct acpi_driver acpi_sbs_driver = { - .name = "sbs", - .class = ACPI_SBS_CLASS, - .ids = sbs_device_ids, - .ops = { - .add = acpi_sbs_add, - .remove = acpi_sbs_remove, - .resume = acpi_sbs_resume, - }, -}; - -struct acpi_ac { - int ac_present; -}; - -struct acpi_battery_info { - int capacity_mode; - s16 full_charge_capacity; - s16 design_capacity; - s16 design_voltage; - int vscale; - int ipscale; - s16 serial_number; - char manufacturer_name[ACPI_SBS_BLOCK_MAX + 3]; - char device_name[ACPI_SBS_BLOCK_MAX + 3]; - char device_chemistry[ACPI_SBS_BLOCK_MAX + 3]; -}; - -struct acpi_battery_state { - s16 voltage; - s16 amperage; - s16 remaining_capacity; - s16 battery_state; -}; - -struct acpi_battery_alarm { - s16 remaining_capacity; -}; - struct acpi_battery { - int alive; - int id; - int init_state; - int battery_present; + struct power_supply bat; struct acpi_sbs *sbs; - struct acpi_battery_info info; - struct acpi_battery_state state; - struct acpi_battery_alarm alarm; - struct proc_dir_entry *battery_entry; +#ifdef CONFIG_ACPI_PROCFS + struct proc_dir_entry *proc_entry; +#endif + unsigned long update_time; + char name[8]; + char manufacturer_name[ACPI_SBS_BLOCK_MAX]; + char device_name[ACPI_SBS_BLOCK_MAX]; + char device_chemistry[ACPI_SBS_BLOCK_MAX]; + u16 alarm_capacity; + u16 full_charge_capacity; + u16 design_capacity; + u16 design_voltage; + u16 serial_number; + u16 cycle_count; + u16 temp_now; + u16 voltage_now; + s16 current_now; + s16 current_avg; + u16 capacity_now; + u16 state_of_charge; + u16 state; + u16 mode; + u16 spec; + u8 id; + u8 present:1; }; +#define to_acpi_battery(x) container_of(x, struct acpi_battery, bat); + struct acpi_sbs { - int base; + struct power_supply charger; struct acpi_device *device; - struct mutex mutex; - int sbsm_present; - int sbsm_batteries_supported; - struct proc_dir_entry *ac_entry; - struct acpi_ac ac; + struct acpi_smb_hc *hc; + struct mutex lock; +#ifdef CONFIG_ACPI_PROCFS + struct proc_dir_entry *charger_entry; +#endif struct acpi_battery battery[MAX_SBS_BAT]; - int zombie; - struct timer_list update_timer; - int run_cnt; - int update_proc_flg; + u8 batteries_supported:4; + u8 manager_present:1; + u8 charger_present:1; }; -static int acpi_sbs_update_run(struct acpi_sbs *sbs, int id, int data_type); -static void acpi_sbs_update_time(void *data); +#define to_acpi_sbs(x) container_of(x, struct acpi_sbs, charger) -union sbs_rw_data { - u16 word; - u8 block[ACPI_SBS_BLOCK_MAX + 2]; -}; - -static int acpi_ec_sbs_access(struct acpi_sbs *sbs, u16 addr, - char read_write, u8 command, int size, - union sbs_rw_data *data); - -/* -------------------------------------------------------------------------- - SMBus Communication - -------------------------------------------------------------------------- */ - -static int acpi_ec_sbs_read(struct acpi_sbs *sbs, u8 address, u8 * data) +static inline int battery_scale(int log) { - u8 val; - int err; - - err = ec_read(sbs->base + address, &val); - if (!err) { - *data = val; - } - xmsleep(ACPI_EC_SMB_TRANSACTION_SLEEP); - return (err); -} - -static int acpi_ec_sbs_write(struct acpi_sbs *sbs, u8 address, u8 data) -{ - int err; - - err = ec_write(sbs->base + address, data); - return (err); -} - -static int -acpi_ec_sbs_access(struct acpi_sbs *sbs, u16 addr, - char read_write, u8 command, int size, - union sbs_rw_data *data) -{ - unsigned char protocol, len = 0, temp[2] = { 0, 0 }; - int i; - - if (read_write == ACPI_SBS_SMBUS_READ) { - protocol = ACPI_EC_SMB_PRTCL_READ; - } else { - protocol = ACPI_EC_SMB_PRTCL_WRITE; - } - - switch (size) { - - case ACPI_SBS_WORD_DATA: - acpi_ec_sbs_write(sbs, ACPI_EC_SMB_CMD, command); - if (read_write == ACPI_SBS_SMBUS_WRITE) { - acpi_ec_sbs_write(sbs, ACPI_EC_SMB_DATA, data->word); - acpi_ec_sbs_write(sbs, ACPI_EC_SMB_DATA + 1, - data->word >> 8); - } - protocol |= ACPI_EC_SMB_PRTCL_WORD_DATA; - break; - case ACPI_SBS_BLOCK_DATA: - acpi_ec_sbs_write(sbs, ACPI_EC_SMB_CMD, command); - if (read_write == ACPI_SBS_SMBUS_WRITE) { - len = min_t(u8, data->block[0], 32); - acpi_ec_sbs_write(sbs, ACPI_EC_SMB_BCNT, len); - for (i = 0; i < len; i++) - acpi_ec_sbs_write(sbs, ACPI_EC_SMB_DATA + i, - data->block[i + 1]); - } - protocol |= ACPI_EC_SMB_PRTCL_BLOCK_DATA; - break; - default: - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "unsupported transaction %d", size)); - return (-1); - } - - acpi_ec_sbs_write(sbs, ACPI_EC_SMB_ADDR, addr << 1); - acpi_ec_sbs_write(sbs, ACPI_EC_SMB_PRTCL, protocol); - - acpi_ec_sbs_read(sbs, ACPI_EC_SMB_STS, temp); - - if (~temp[0] & ACPI_EC_SMB_STS_DONE) { - xmsleep(ACPI_EC_SMB_ACCESS_SLEEP1); - acpi_ec_sbs_read(sbs, ACPI_EC_SMB_STS, temp); - } - if (~temp[0] & ACPI_EC_SMB_STS_DONE) { - xmsleep(ACPI_EC_SMB_ACCESS_SLEEP2); - acpi_ec_sbs_read(sbs, ACPI_EC_SMB_STS, temp); - } - if ((~temp[0] & ACPI_EC_SMB_STS_DONE) - || (temp[0] & ACPI_EC_SMB_STS_STATUS)) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "transaction %d error", size)); - return (-1); - } - - if (read_write == ACPI_SBS_SMBUS_WRITE) { - return (0); - } - - switch (size) { - - case ACPI_SBS_WORD_DATA: - acpi_ec_sbs_read(sbs, ACPI_EC_SMB_DATA, temp); - acpi_ec_sbs_read(sbs, ACPI_EC_SMB_DATA + 1, temp + 1); - data->word = (temp[1] << 8) | temp[0]; - break; - - case ACPI_SBS_BLOCK_DATA: - len = 0; - acpi_ec_sbs_read(sbs, ACPI_EC_SMB_BCNT, &len); - len = min_t(u8, len, 32); - for (i = 0; i < len; i++) - acpi_ec_sbs_read(sbs, ACPI_EC_SMB_DATA + i, - data->block + i + 1); - data->block[0] = len; - break; - default: - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "unsupported transaction %d", size)); - return (-1); - } - - return (0); + int scale = 1; + while (log--) + scale *= 10; + return scale; } -static int -acpi_sbs_read_word(struct acpi_sbs *sbs, int addr, int func, u16 * word) +static inline int acpi_battery_vscale(struct acpi_battery *battery) { - union sbs_rw_data data; - int result = 0; - - result = acpi_ec_sbs_access(sbs, addr, - ACPI_SBS_SMBUS_READ, func, - ACPI_SBS_WORD_DATA, &data); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_ec_sbs_access() failed")); - } else { - *word = data.word; - } - - return result; + return battery_scale((battery->spec & 0x0f00) >> 8); } -static int -acpi_sbs_read_str(struct acpi_sbs *sbs, int addr, int func, char *str) +static inline int acpi_battery_ipscale(struct acpi_battery *battery) { - union sbs_rw_data data; - int result = 0; - - result = acpi_ec_sbs_access(sbs, addr, - ACPI_SBS_SMBUS_READ, func, - ACPI_SBS_BLOCK_DATA, &data); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_ec_sbs_access() failed")); - } else { - strncpy(str, (const char *)data.block + 1, data.block[0]); - str[data.block[0]] = 0; - } - - return result; + return battery_scale((battery->spec & 0xf000) >> 12); } -static int -acpi_sbs_write_word(struct acpi_sbs *sbs, int addr, int func, int word) +static inline int acpi_battery_mode(struct acpi_battery *battery) { - union sbs_rw_data data; - int result = 0; - - data.word = word; - - result = acpi_ec_sbs_access(sbs, addr, - ACPI_SBS_SMBUS_WRITE, func, - ACPI_SBS_WORD_DATA, &data); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_ec_sbs_access() failed")); - } - - return result; + return (battery->mode & 0x8000); } -static int sbs_zombie(struct acpi_sbs *sbs) +static inline int acpi_battery_scale(struct acpi_battery *battery) { - return (sbs->zombie); + return (acpi_battery_mode(battery) ? 10 : 1) * + acpi_battery_ipscale(battery); } -static int sbs_mutex_lock(struct acpi_sbs *sbs) +static int sbs_get_ac_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) { - if (sbs_zombie(sbs)) { - return -ENODEV; + struct acpi_sbs *sbs = to_acpi_sbs(psy); + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + val->intval = sbs->charger_present; + break; + default: + return -EINVAL; } - mutex_lock(&sbs->mutex); return 0; } -static void sbs_mutex_unlock(struct acpi_sbs *sbs) +static int acpi_battery_technology(struct acpi_battery *battery) { - mutex_unlock(&sbs->mutex); + if (!strcasecmp("NiCd", battery->device_chemistry)) + return POWER_SUPPLY_TECHNOLOGY_NiCd; + if (!strcasecmp("NiMH", battery->device_chemistry)) + return POWER_SUPPLY_TECHNOLOGY_NiMH; + if (!strcasecmp("LION", battery->device_chemistry)) + return POWER_SUPPLY_TECHNOLOGY_LION; + if (!strcasecmp("LiP", battery->device_chemistry)) + return POWER_SUPPLY_TECHNOLOGY_LIPO; + return POWER_SUPPLY_TECHNOLOGY_UNKNOWN; } -/* -------------------------------------------------------------------------- - Smart Battery System Management - -------------------------------------------------------------------------- */ - -static int acpi_check_update_proc(struct acpi_sbs *sbs) +static int acpi_sbs_battery_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) { - acpi_status status = AE_OK; + struct acpi_battery *battery = to_acpi_battery(psy); - if (update_time == 0) { - sbs->update_proc_flg = 0; - return 0; - } - if (sbs->update_proc_flg == 0) { - status = acpi_os_execute(OSL_GPE_HANDLER, - acpi_sbs_update_time, sbs); - if (status != AE_OK) { - ACPI_EXCEPTION((AE_INFO, status, - "acpi_os_execute() failed")); - return 1; - } - sbs->update_proc_flg = 1; + if ((!battery->present) && psp != POWER_SUPPLY_PROP_PRESENT) + return -ENODEV; + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + if (battery->current_now < 0) + val->intval = POWER_SUPPLY_STATUS_DISCHARGING; + else if (battery->current_now > 0) + val->intval = POWER_SUPPLY_STATUS_CHARGING; + else + val->intval = POWER_SUPPLY_STATUS_FULL; + break; + case POWER_SUPPLY_PROP_PRESENT: + val->intval = battery->present; + break; + case POWER_SUPPLY_PROP_TECHNOLOGY: + val->intval = acpi_battery_technology(battery); + break; + case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: + val->intval = battery->design_voltage * + acpi_battery_vscale(battery) * 1000; + break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + val->intval = battery->voltage_now * + acpi_battery_vscale(battery) * 1000; + break; + case POWER_SUPPLY_PROP_CURRENT_NOW: + val->intval = abs(battery->current_now) * + acpi_battery_ipscale(battery) * 1000; + break; + case POWER_SUPPLY_PROP_CURRENT_AVG: + val->intval = abs(battery->current_avg) * + acpi_battery_ipscale(battery) * 1000; + break; + case POWER_SUPPLY_PROP_CAPACITY: + val->intval = battery->state_of_charge; + break; + case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: + case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN: + val->intval = battery->design_capacity * + acpi_battery_scale(battery) * 1000; + break; + case POWER_SUPPLY_PROP_CHARGE_FULL: + case POWER_SUPPLY_PROP_ENERGY_FULL: + val->intval = battery->full_charge_capacity * + acpi_battery_scale(battery) * 1000; + break; + case POWER_SUPPLY_PROP_CHARGE_NOW: + case POWER_SUPPLY_PROP_ENERGY_NOW: + val->intval = battery->capacity_now * + acpi_battery_scale(battery) * 1000; + break; + case POWER_SUPPLY_PROP_TEMP: + val->intval = battery->temp_now - 2730; // dK -> dC + break; + case POWER_SUPPLY_PROP_MODEL_NAME: + val->strval = battery->device_name; + break; + case POWER_SUPPLY_PROP_MANUFACTURER: + val->strval = battery->manufacturer_name; + break; + default: + return -EINVAL; } return 0; } -static int acpi_sbs_generate_event(struct acpi_device *device, - int event, int state, char *bid, char *class) -{ - char bid_saved[5]; - char class_saved[20]; - int result = 0; - - strcpy(bid_saved, acpi_device_bid(device)); - strcpy(class_saved, acpi_device_class(device)); - - strcpy(acpi_device_bid(device), bid); - strcpy(acpi_device_class(device), class); - - result = acpi_bus_generate_proc_event(device, event, state); - - strcpy(acpi_device_bid(device), bid_saved); - strcpy(acpi_device_class(device), class_saved); - - acpi_bus_generate_netlink_event(class, bid, event, state); - return result; -} - -static int acpi_battery_get_present(struct acpi_battery *battery) -{ - s16 state; - int result = 0; - int is_present = 0; - - result = acpi_sbs_read_word(battery->sbs, - ACPI_SBSM_SMBUS_ADDR, 0x01, &state); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_word() failed")); - } - if (!result) { - is_present = (state & 0x000f) & (1 << battery->id); - } - battery->battery_present = is_present; - - return result; -} +static enum power_supply_property sbs_ac_props[] = { + POWER_SUPPLY_PROP_ONLINE, +}; -static int acpi_battery_select(struct acpi_battery *battery) -{ - struct acpi_sbs *sbs = battery->sbs; - int result = 0; - s16 state; - int foo; +static enum power_supply_property sbs_charge_battery_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_TECHNOLOGY, + POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_CURRENT_AVG, + POWER_SUPPLY_PROP_CAPACITY, + POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, + POWER_SUPPLY_PROP_CHARGE_FULL, + POWER_SUPPLY_PROP_CHARGE_NOW, + POWER_SUPPLY_PROP_TEMP, + POWER_SUPPLY_PROP_MODEL_NAME, + POWER_SUPPLY_PROP_MANUFACTURER, +}; - if (sbs->sbsm_present) { +static enum power_supply_property sbs_energy_battery_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_TECHNOLOGY, + POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_CURRENT_AVG, + POWER_SUPPLY_PROP_CAPACITY, + POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, + POWER_SUPPLY_PROP_ENERGY_FULL, + POWER_SUPPLY_PROP_ENERGY_NOW, + POWER_SUPPLY_PROP_TEMP, + POWER_SUPPLY_PROP_MODEL_NAME, + POWER_SUPPLY_PROP_MANUFACTURER, +}; - /* Take special care not to knobble other nibbles of - * state (aka selector_state), since - * it causes charging to halt on SBSELs */ +/* -------------------------------------------------------------------------- + Smart Battery System Management + -------------------------------------------------------------------------- */ - result = - acpi_sbs_read_word(sbs, ACPI_SBSM_SMBUS_ADDR, 0x01, &state); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_word() failed")); - goto end; - } +struct acpi_battery_reader { + u8 command; /* command for battery */ + u8 mode; /* word or block? */ + size_t offset; /* offset inside struct acpi_sbs_battery */ +}; - foo = (state & 0x0fff) | (1 << (battery->id + 12)); - result = - acpi_sbs_write_word(sbs, ACPI_SBSM_SMBUS_ADDR, 0x01, foo); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_write_word() failed")); - goto end; - } - } +static struct acpi_battery_reader info_readers[] = { + {0x01, SMBUS_READ_WORD, offsetof(struct acpi_battery, alarm_capacity)}, + {0x03, SMBUS_READ_WORD, offsetof(struct acpi_battery, mode)}, + {0x10, SMBUS_READ_WORD, offsetof(struct acpi_battery, full_charge_capacity)}, + {0x17, SMBUS_READ_WORD, offsetof(struct acpi_battery, cycle_count)}, + {0x18, SMBUS_READ_WORD, offsetof(struct acpi_battery, design_capacity)}, + {0x19, SMBUS_READ_WORD, offsetof(struct acpi_battery, design_voltage)}, + {0x1a, SMBUS_READ_WORD, offsetof(struct acpi_battery, spec)}, + {0x1c, SMBUS_READ_WORD, offsetof(struct acpi_battery, serial_number)}, + {0x20, SMBUS_READ_BLOCK, offsetof(struct acpi_battery, manufacturer_name)}, + {0x21, SMBUS_READ_BLOCK, offsetof(struct acpi_battery, device_name)}, + {0x22, SMBUS_READ_BLOCK, offsetof(struct acpi_battery, device_chemistry)}, +}; - end: - return result; -} +static struct acpi_battery_reader state_readers[] = { + {0x08, SMBUS_READ_WORD, offsetof(struct acpi_battery, temp_now)}, + {0x09, SMBUS_READ_WORD, offsetof(struct acpi_battery, voltage_now)}, + {0x0a, SMBUS_READ_WORD, offsetof(struct acpi_battery, current_now)}, + {0x0b, SMBUS_READ_WORD, offsetof(struct acpi_battery, current_avg)}, + {0x0f, SMBUS_READ_WORD, offsetof(struct acpi_battery, capacity_now)}, + {0x0e, SMBUS_READ_WORD, offsetof(struct acpi_battery, state_of_charge)}, + {0x16, SMBUS_READ_WORD, offsetof(struct acpi_battery, state)}, +}; -static int acpi_sbsm_get_info(struct acpi_sbs *sbs) +static int acpi_manager_get_info(struct acpi_sbs *sbs) { int result = 0; - s16 battery_system_info; - - result = acpi_sbs_read_word(sbs, ACPI_SBSM_SMBUS_ADDR, 0x04, - &battery_system_info); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_word() failed")); - goto end; - } - sbs->sbsm_present = 1; - sbs->sbsm_batteries_supported = battery_system_info & 0x000f; - - end: + u16 battery_system_info; + result = acpi_smbus_read(sbs->hc, SMBUS_READ_WORD, ACPI_SBS_MANAGER, + 0x04, (u8 *)&battery_system_info); + if (!result) + sbs->batteries_supported = battery_system_info & 0x000f; return result; } static int acpi_battery_get_info(struct acpi_battery *battery) { - struct acpi_sbs *sbs = battery->sbs; - int result = 0; - s16 battery_mode; - s16 specification_info; - - result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x03, - &battery_mode); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_word() failed")); - goto end; - } - battery->info.capacity_mode = (battery_mode & 0x8000) >> 15; - - result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x10, - &battery->info.full_charge_capacity); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_word() failed")); - goto end; - } - - result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x18, - &battery->info.design_capacity); - - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_word() failed")); - goto end; - } - - result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x19, - &battery->info.design_voltage); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_word() failed")); - goto end; + int i, result = 0; + + for (i = 0; i < ARRAY_SIZE(info_readers); ++i) { + result = acpi_smbus_read(battery->sbs->hc, + info_readers[i].mode, + ACPI_SBS_BATTERY, + info_readers[i].command, + (u8 *) battery + + info_readers[i].offset); + if (result) + break; } - - result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x1a, - &specification_info); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_word() failed")); - goto end; - } - - switch ((specification_info & 0x0f00) >> 8) { - case 1: - battery->info.vscale = 10; - break; - case 2: - battery->info.vscale = 100; - break; - case 3: - battery->info.vscale = 1000; - break; - default: - battery->info.vscale = 1; - } - - switch ((specification_info & 0xf000) >> 12) { - case 1: - battery->info.ipscale = 10; - break; - case 2: - battery->info.ipscale = 100; - break; - case 3: - battery->info.ipscale = 1000; - break; - default: - battery->info.ipscale = 1; - } - - result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x1c, - &battery->info.serial_number); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_word() failed")); - goto end; - } - - result = acpi_sbs_read_str(sbs, ACPI_SB_SMBUS_ADDR, 0x20, - battery->info.manufacturer_name); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_str() failed")); - goto end; - } - - result = acpi_sbs_read_str(sbs, ACPI_SB_SMBUS_ADDR, 0x21, - battery->info.device_name); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_str() failed")); - goto end; - } - - result = acpi_sbs_read_str(sbs, ACPI_SB_SMBUS_ADDR, 0x22, - battery->info.device_chemistry); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_str() failed")); - goto end; - } - - end: return result; } static int acpi_battery_get_state(struct acpi_battery *battery) { - struct acpi_sbs *sbs = battery->sbs; - int result = 0; + int i, result = 0; - result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x09, - &battery->state.voltage); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_word() failed")); - goto end; - } - - result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x0a, - &battery->state.amperage); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_word() failed")); - goto end; - } - - result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x0f, - &battery->state.remaining_capacity); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_word() failed")); - goto end; - } - - result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x16, - &battery->state.battery_state); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_word() failed")); - goto end; + if (battery->update_time && + time_before(jiffies, battery->update_time + + msecs_to_jiffies(cache_time))) + return 0; + for (i = 0; i < ARRAY_SIZE(state_readers); ++i) { + result = acpi_smbus_read(battery->sbs->hc, + state_readers[i].mode, + ACPI_SBS_BATTERY, + state_readers[i].command, + (u8 *)battery + + state_readers[i].offset); + if (result) + goto end; } - end: + battery->update_time = jiffies; return result; } static int acpi_battery_get_alarm(struct acpi_battery *battery) { - struct acpi_sbs *sbs = battery->sbs; - int result = 0; - - result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x01, - &battery->alarm.remaining_capacity); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_word() failed")); - goto end; - } - - end: - - return result; + return acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, + ACPI_SBS_BATTERY, 0x01, + (u8 *)&battery->alarm_capacity); } -static int acpi_battery_set_alarm(struct acpi_battery *battery, - unsigned long alarm) +static int acpi_battery_set_alarm(struct acpi_battery *battery) { struct acpi_sbs *sbs = battery->sbs; - int result = 0; - s16 battery_mode; - int foo; + u16 value, sel = 1 << (battery->id + 12); - result = acpi_battery_select(battery); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_battery_select() failed")); - goto end; - } + int ret; - /* If necessary, enable the alarm */ - if (alarm > 0) { - result = - acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x03, - &battery_mode); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_word() failed")); + if (sbs->manager_present) { + ret = acpi_smbus_read(sbs->hc, SMBUS_READ_WORD, ACPI_SBS_MANAGER, + 0x01, (u8 *)&value); + if (ret) goto end; - } - - result = - acpi_sbs_write_word(sbs, ACPI_SB_SMBUS_ADDR, 0x01, - battery_mode & 0xbfff); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_write_word() failed")); + if ((value & 0xf000) != sel) { + value &= 0x0fff; + value |= sel; + ret = acpi_smbus_write(sbs->hc, SMBUS_WRITE_WORD, + ACPI_SBS_MANAGER, + 0x01, (u8 *)&value, 2); + if (ret) goto end; } } - - foo = alarm / (battery->info.capacity_mode ? 10 : 1); - result = acpi_sbs_write_word(sbs, ACPI_SB_SMBUS_ADDR, 0x01, foo); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_write_word() failed")); - goto end; - } - + ret = acpi_smbus_write(sbs->hc, SMBUS_WRITE_WORD, ACPI_SBS_BATTERY, + 0x01, (u8 *)&battery->alarm_capacity, 2); end: - - return result; + return ret; } -static int acpi_battery_set_mode(struct acpi_battery *battery) +static int acpi_ac_get_present(struct acpi_sbs *sbs) { - struct acpi_sbs *sbs = battery->sbs; - int result = 0; - s16 battery_mode; - - if (capacity_mode == DEF_CAPACITY_UNIT) { - goto end; - } - - result = acpi_sbs_read_word(sbs, - ACPI_SB_SMBUS_ADDR, 0x03, &battery_mode); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_word() failed")); - goto end; - } - - if (capacity_mode == MAH_CAPACITY_UNIT) { - battery_mode &= 0x7fff; - } else { - battery_mode |= 0x8000; - } - result = acpi_sbs_write_word(sbs, - ACPI_SB_SMBUS_ADDR, 0x03, battery_mode); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_write_word() failed")); - goto end; - } - - result = acpi_sbs_read_word(sbs, - ACPI_SB_SMBUS_ADDR, 0x03, &battery_mode); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_word() failed")); - goto end; - } + int result; + u16 status; - end: + result = acpi_smbus_read(sbs->hc, SMBUS_READ_WORD, ACPI_SBS_CHARGER, + 0x13, (u8 *) & status); + if (!result) + sbs->charger_present = (status >> 15) & 0x1; return result; } -static int acpi_battery_init(struct acpi_battery *battery) +static ssize_t acpi_battery_alarm_show(struct device *dev, + struct device_attribute *attr, + char *buf) { - int result = 0; - - result = acpi_battery_select(battery); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_battery_select() failed")); - goto end; - } - - result = acpi_battery_set_mode(battery); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_battery_set_mode() failed")); - goto end; - } - - result = acpi_battery_get_info(battery); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_battery_get_info() failed")); - goto end; - } - - result = acpi_battery_get_state(battery); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_battery_get_state() failed")); - goto end; - } - - result = acpi_battery_get_alarm(battery); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_battery_get_alarm() failed")); - goto end; - } - - end: - return result; + struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev)); + acpi_battery_get_alarm(battery); + return sprintf(buf, "%d\n", battery->alarm_capacity * + acpi_battery_scale(battery) * 1000); } -static int acpi_ac_get_present(struct acpi_sbs *sbs) +static ssize_t acpi_battery_alarm_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { - int result = 0; - s16 charger_status; - - result = acpi_sbs_read_word(sbs, ACPI_SBC_SMBUS_ADDR, 0x13, - &charger_status); - - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_word() failed")); - goto end; - } - - sbs->ac.ac_present = (charger_status & 0x8000) >> 15; - - end: - - return result; + unsigned long x; + struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev)); + if (sscanf(buf, "%ld\n", &x) == 1) + battery->alarm_capacity = x / + (1000 * acpi_battery_scale(battery)); + if (battery->present) + acpi_battery_set_alarm(battery); + return count; } +static struct device_attribute alarm_attr = { + .attr = {.name = "alarm", .mode = 0644, .owner = THIS_MODULE}, + .show = acpi_battery_alarm_show, + .store = acpi_battery_alarm_store, +}; + /* -------------------------------------------------------------------------- FS Interface (/proc/acpi) -------------------------------------------------------------------------- */ +#ifdef CONFIG_ACPI_PROCFS /* Generic Routines */ - static int -acpi_sbs_generic_add_fs(struct proc_dir_entry **dir, - struct proc_dir_entry *parent_dir, - char *dir_name, - struct file_operations *info_fops, - struct file_operations *state_fops, - struct file_operations *alarm_fops, void *data) +acpi_sbs_add_fs(struct proc_dir_entry **dir, + struct proc_dir_entry *parent_dir, + char *dir_name, + struct file_operations *info_fops, + struct file_operations *state_fops, + struct file_operations *alarm_fops, void *data) { struct proc_dir_entry *entry = NULL; if (!*dir) { *dir = proc_mkdir(dir_name, parent_dir); if (!*dir) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "proc_mkdir() failed")); return -ENODEV; } (*dir)->owner = THIS_MODULE; @@ -882,10 +491,7 @@ acpi_sbs_generic_add_fs(struct proc_dir_entry **dir, /* 'info' [R] */ if (info_fops) { entry = create_proc_entry(ACPI_SBS_FILE_INFO, S_IRUGO, *dir); - if (!entry) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "create_proc_entry() failed")); - } else { + if (entry) { entry->proc_fops = info_fops; entry->data = data; entry->owner = THIS_MODULE; @@ -895,10 +501,7 @@ acpi_sbs_generic_add_fs(struct proc_dir_entry **dir, /* 'state' [R] */ if (state_fops) { entry = create_proc_entry(ACPI_SBS_FILE_STATE, S_IRUGO, *dir); - if (!entry) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "create_proc_entry() failed")); - } else { + if (entry) { entry->proc_fops = state_fops; entry->data = data; entry->owner = THIS_MODULE; @@ -908,24 +511,19 @@ acpi_sbs_generic_add_fs(struct proc_dir_entry **dir, /* 'alarm' [R/W] */ if (alarm_fops) { entry = create_proc_entry(ACPI_SBS_FILE_ALARM, S_IRUGO, *dir); - if (!entry) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "create_proc_entry() failed")); - } else { + if (entry) { entry->proc_fops = alarm_fops; entry->data = data; entry->owner = THIS_MODULE; } } - return 0; } static void -acpi_sbs_generic_remove_fs(struct proc_dir_entry **dir, +acpi_sbs_remove_fs(struct proc_dir_entry **dir, struct proc_dir_entry *parent_dir) { - if (*dir) { remove_proc_entry(ACPI_SBS_FILE_INFO, *dir); remove_proc_entry(ACPI_SBS_FILE_STATE, *dir); @@ -933,82 +531,52 @@ acpi_sbs_generic_remove_fs(struct proc_dir_entry **dir, remove_proc_entry((*dir)->name, parent_dir); *dir = NULL; } - } /* Smart Battery Interface */ - static struct proc_dir_entry *acpi_battery_dir = NULL; +static inline char *acpi_battery_units(struct acpi_battery *battery) +{ + return acpi_battery_mode(battery) ? " mWh" : " mAh"; +} + + static int acpi_battery_read_info(struct seq_file *seq, void *offset) { struct acpi_battery *battery = seq->private; struct acpi_sbs *sbs = battery->sbs; - int cscale; int result = 0; - if (sbs_mutex_lock(sbs)) { - return -ENODEV; - } - - result = acpi_check_update_proc(sbs); - if (result) - goto end; - - if (update_time == 0) { - result = acpi_sbs_update_run(sbs, battery->id, DATA_TYPE_INFO); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_update_run() failed")); - } - } + mutex_lock(&sbs->lock); - if (battery->battery_present) { - seq_printf(seq, "present: yes\n"); - } else { - seq_printf(seq, "present: no\n"); + seq_printf(seq, "present: %s\n", + (battery->present) ? "yes" : "no"); + if (!battery->present) goto end; - } - if (battery->info.capacity_mode) { - cscale = battery->info.vscale * battery->info.ipscale; - } else { - cscale = battery->info.ipscale; - } seq_printf(seq, "design capacity: %i%s\n", - battery->info.design_capacity * cscale, - battery->info.capacity_mode ? "0 mWh" : " mAh"); - + battery->design_capacity * acpi_battery_scale(battery), + acpi_battery_units(battery)); seq_printf(seq, "last full capacity: %i%s\n", - battery->info.full_charge_capacity * cscale, - battery->info.capacity_mode ? "0 mWh" : " mAh"); - + battery->full_charge_capacity * acpi_battery_scale(battery), + acpi_battery_units(battery)); seq_printf(seq, "battery technology: rechargeable\n"); - seq_printf(seq, "design voltage: %i mV\n", - battery->info.design_voltage * battery->info.vscale); - + battery->design_voltage * acpi_battery_vscale(battery)); seq_printf(seq, "design capacity warning: unknown\n"); seq_printf(seq, "design capacity low: unknown\n"); seq_printf(seq, "capacity granularity 1: unknown\n"); seq_printf(seq, "capacity granularity 2: unknown\n"); - - seq_printf(seq, "model number: %s\n", - battery->info.device_name); - + seq_printf(seq, "model number: %s\n", battery->device_name); seq_printf(seq, "serial number: %i\n", - battery->info.serial_number); - + battery->serial_number); seq_printf(seq, "battery type: %s\n", - battery->info.device_chemistry); - + battery->device_chemistry); seq_printf(seq, "OEM info: %s\n", - battery->info.manufacturer_name); - + battery->manufacturer_name); end: - - sbs_mutex_unlock(sbs); - + mutex_unlock(&sbs->lock); return result; } @@ -1022,73 +590,29 @@ static int acpi_battery_read_state(struct seq_file *seq, void *offset) struct acpi_battery *battery = seq->private; struct acpi_sbs *sbs = battery->sbs; int result = 0; - int cscale; - int foo; - - if (sbs_mutex_lock(sbs)) { - return -ENODEV; - } - result = acpi_check_update_proc(sbs); - if (result) + mutex_lock(&sbs->lock); + seq_printf(seq, "present: %s\n", + (battery->present) ? "yes" : "no"); + if (!battery->present) goto end; - if (update_time == 0) { - result = acpi_sbs_update_run(sbs, battery->id, DATA_TYPE_STATE); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_update_run() failed")); - } - } - - if (battery->battery_present) { - seq_printf(seq, "present: yes\n"); - } else { - seq_printf(seq, "present: no\n"); - goto end; - } - - if (battery->info.capacity_mode) { - cscale = battery->info.vscale * battery->info.ipscale; - } else { - cscale = battery->info.ipscale; - } - - if (battery->state.battery_state & 0x0010) { - seq_printf(seq, "capacity state: critical\n"); - } else { - seq_printf(seq, "capacity state: ok\n"); - } - - foo = (s16) battery->state.amperage * battery->info.ipscale; - if (battery->info.capacity_mode) { - foo = foo * battery->info.design_voltage / 1000; - } - if (battery->state.amperage < 0) { - seq_printf(seq, "charging state: discharging\n"); - seq_printf(seq, "present rate: %d %s\n", - -foo, battery->info.capacity_mode ? "mW" : "mA"); - } else if (battery->state.amperage > 0) { - seq_printf(seq, "charging state: charging\n"); - seq_printf(seq, "present rate: %d %s\n", - foo, battery->info.capacity_mode ? "mW" : "mA"); - } else { - seq_printf(seq, "charging state: charged\n"); - seq_printf(seq, "present rate: 0 %s\n", - battery->info.capacity_mode ? "mW" : "mA"); - } - + acpi_battery_get_state(battery); + seq_printf(seq, "capacity state: %s\n", + (battery->state & 0x0010) ? "critical" : "ok"); + seq_printf(seq, "charging state: %s\n", + (battery->current_now < 0) ? "discharging" : + ((battery->current_now > 0) ? "charging" : "charged")); + seq_printf(seq, "present rate: %d mA\n", + abs(battery->current_now) * acpi_battery_ipscale(battery)); seq_printf(seq, "remaining capacity: %i%s\n", - battery->state.remaining_capacity * cscale, - battery->info.capacity_mode ? "0 mWh" : " mAh"); - + battery->capacity_now * acpi_battery_scale(battery), + acpi_battery_units(battery)); seq_printf(seq, "present voltage: %i mV\n", - battery->state.voltage * battery->info.vscale); + battery->voltage_now * acpi_battery_vscale(battery)); end: - - sbs_mutex_unlock(sbs); - + mutex_unlock(&sbs->lock); return result; } @@ -1102,48 +626,25 @@ static int acpi_battery_read_alarm(struct seq_file *seq, void *offset) struct acpi_battery *battery = seq->private; struct acpi_sbs *sbs = battery->sbs; int result = 0; - int cscale; - - if (sbs_mutex_lock(sbs)) { - return -ENODEV; - } - - result = acpi_check_update_proc(sbs); - if (result) - goto end; - if (update_time == 0) { - result = acpi_sbs_update_run(sbs, battery->id, DATA_TYPE_ALARM); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_update_run() failed")); - } - } + mutex_lock(&sbs->lock); - if (!battery->battery_present) { + if (!battery->present) { seq_printf(seq, "present: no\n"); goto end; } - if (battery->info.capacity_mode) { - cscale = battery->info.vscale * battery->info.ipscale; - } else { - cscale = battery->info.ipscale; - } - + acpi_battery_get_alarm(battery); seq_printf(seq, "alarm: "); - if (battery->alarm.remaining_capacity) { + if (battery->alarm_capacity) seq_printf(seq, "%i%s\n", - battery->alarm.remaining_capacity * cscale, - battery->info.capacity_mode ? "0 mWh" : " mAh"); - } else { + battery->alarm_capacity * + acpi_battery_scale(battery), + acpi_battery_units(battery)); + else seq_printf(seq, "disabled\n"); - } - end: - - sbs_mutex_unlock(sbs); - + mutex_unlock(&sbs->lock); return result; } @@ -1155,59 +656,29 @@ acpi_battery_write_alarm(struct file *file, const char __user * buffer, struct acpi_battery *battery = seq->private; struct acpi_sbs *sbs = battery->sbs; char alarm_string[12] = { '\0' }; - int result, old_alarm, new_alarm; - - if (sbs_mutex_lock(sbs)) { - return -ENODEV; - } - - result = acpi_check_update_proc(sbs); - if (result) - goto end; - - if (!battery->battery_present) { + int result = 0; + mutex_lock(&sbs->lock); + if (!battery->present) { result = -ENODEV; goto end; } - if (count > sizeof(alarm_string) - 1) { result = -EINVAL; goto end; } - if (copy_from_user(alarm_string, buffer, count)) { result = -EFAULT; goto end; } - alarm_string[count] = 0; - - old_alarm = battery->alarm.remaining_capacity; - new_alarm = simple_strtoul(alarm_string, NULL, 0); - - result = acpi_battery_set_alarm(battery, new_alarm); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_battery_set_alarm() failed")); - acpi_battery_set_alarm(battery, old_alarm); - goto end; - } - result = acpi_battery_get_alarm(battery); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_battery_get_alarm() failed")); - acpi_battery_set_alarm(battery, old_alarm); - goto end; - } - + battery->alarm_capacity = simple_strtoul(alarm_string, NULL, 0) / + acpi_battery_scale(battery); + acpi_battery_set_alarm(battery); end: - sbs_mutex_unlock(sbs); - - if (result) { + mutex_unlock(&sbs->lock); + if (result) return result; - } else { - return count; - } + return count; } static int acpi_battery_alarm_open_fs(struct inode *inode, struct file *file) @@ -1246,26 +717,15 @@ static struct proc_dir_entry *acpi_ac_dir = NULL; static int acpi_ac_read_state(struct seq_file *seq, void *offset) { - struct acpi_sbs *sbs = seq->private; - int result; - if (sbs_mutex_lock(sbs)) { - return -ENODEV; - } + struct acpi_sbs *sbs = seq->private; - if (update_time == 0) { - result = acpi_sbs_update_run(sbs, -1, DATA_TYPE_AC_STATE); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_update_run() failed")); - } - } + mutex_lock(&sbs->lock); seq_printf(seq, "state: %s\n", - sbs->ac.ac_present ? "on-line" : "off-line"); - - sbs_mutex_unlock(sbs); + sbs->charger_present ? "on-line" : "off-line"); + mutex_unlock(&sbs->lock); return 0; } @@ -1282,429 +742,203 @@ static struct file_operations acpi_ac_state_fops = { .owner = THIS_MODULE, }; +#endif + /* -------------------------------------------------------------------------- Driver Interface -------------------------------------------------------------------------- */ +static int acpi_battery_read(struct acpi_battery *battery) +{ + int result = 0, saved_present = battery->present; + u16 state; + + if (battery->sbs->manager_present) { + result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, + ACPI_SBS_MANAGER, 0x01, (u8 *)&state); + if (!result) + battery->present = state & (1 << battery->id); + state &= 0x0fff; + state |= 1 << (battery->id + 12); + acpi_smbus_write(battery->sbs->hc, SMBUS_WRITE_WORD, + ACPI_SBS_MANAGER, 0x01, (u8 *)&state, 2); + } else if (battery->id == 0) + battery->present = 1; + if (result || !battery->present) + return result; -/* Smart Battery */ + if (saved_present != battery->present) { + battery->update_time = 0; + result = acpi_battery_get_info(battery); + if (result) + return result; + } + result = acpi_battery_get_state(battery); + return result; +} +/* Smart Battery */ static int acpi_battery_add(struct acpi_sbs *sbs, int id) { - int is_present; + struct acpi_battery *battery = &sbs->battery[id]; int result; - char dir_name[32]; - struct acpi_battery *battery; - - battery = &sbs->battery[id]; - - battery->alive = 0; - battery->init_state = 0; battery->id = id; battery->sbs = sbs; + result = acpi_battery_read(battery); + if (result) + return result; - result = acpi_battery_select(battery); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_battery_select() failed")); - goto end; - } - - result = acpi_battery_get_present(battery); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_battery_get_present() failed")); - goto end; - } - - is_present = battery->battery_present; - - if (is_present) { - result = acpi_battery_init(battery); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_battery_init() failed")); - goto end; - } - battery->init_state = 1; - } - - sprintf(dir_name, ACPI_BATTERY_DIR_NAME, id); - - result = acpi_sbs_generic_add_fs(&battery->battery_entry, - acpi_battery_dir, - dir_name, - &acpi_battery_info_fops, - &acpi_battery_state_fops, - &acpi_battery_alarm_fops, battery); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_generic_add_fs() failed")); - goto end; + sprintf(battery->name, ACPI_BATTERY_DIR_NAME, id); +#ifdef CONFIG_ACPI_PROCFS + acpi_sbs_add_fs(&battery->proc_entry, acpi_battery_dir, + battery->name, &acpi_battery_info_fops, + &acpi_battery_state_fops, &acpi_battery_alarm_fops, + battery); +#endif + battery->bat.name = battery->name; + battery->bat.type = POWER_SUPPLY_TYPE_BATTERY; + if (!acpi_battery_mode(battery)) { + battery->bat.properties = sbs_charge_battery_props; + battery->bat.num_properties = + ARRAY_SIZE(sbs_charge_battery_props); + } else { + battery->bat.properties = sbs_energy_battery_props; + battery->bat.num_properties = + ARRAY_SIZE(sbs_energy_battery_props); } - battery->alive = 1; - + battery->bat.get_property = acpi_sbs_battery_get_property; + result = power_supply_register(&sbs->device->dev, &battery->bat); + device_create_file(battery->bat.dev, &alarm_attr); printk(KERN_INFO PREFIX "%s [%s]: Battery Slot [%s] (battery %s)\n", - ACPI_SBS_DEVICE_NAME, acpi_device_bid(sbs->device), dir_name, - sbs->battery->battery_present ? "present" : "absent"); - - end: + ACPI_SBS_DEVICE_NAME, acpi_device_bid(sbs->device), + battery->name, sbs->battery->present ? "present" : "absent"); return result; } static void acpi_battery_remove(struct acpi_sbs *sbs, int id) { - - if (sbs->battery[id].battery_entry) { - acpi_sbs_generic_remove_fs(&(sbs->battery[id].battery_entry), - acpi_battery_dir); - } + if (sbs->battery[id].bat.dev) + device_remove_file(sbs->battery[id].bat.dev, &alarm_attr); + power_supply_unregister(&sbs->battery[id].bat); +#ifdef CONFIG_ACPI_PROCFS + if (sbs->battery[id].proc_entry) { + acpi_sbs_remove_fs(&(sbs->battery[id].proc_entry), + acpi_battery_dir); + } +#endif } -static int acpi_ac_add(struct acpi_sbs *sbs) +static int acpi_charger_add(struct acpi_sbs *sbs) { int result; result = acpi_ac_get_present(sbs); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_ac_get_present() failed")); + if (result) goto end; - } - - result = acpi_sbs_generic_add_fs(&sbs->ac_entry, - acpi_ac_dir, - ACPI_AC_DIR_NAME, - NULL, &acpi_ac_state_fops, NULL, sbs); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_generic_add_fs() failed")); +#ifdef CONFIG_ACPI_PROCFS + result = acpi_sbs_add_fs(&sbs->charger_entry, acpi_ac_dir, + ACPI_AC_DIR_NAME, NULL, + &acpi_ac_state_fops, NULL, sbs); + if (result) goto end; - } - +#endif + sbs->charger.name = "sbs-charger"; + sbs->charger.type = POWER_SUPPLY_TYPE_MAINS; + sbs->charger.properties = sbs_ac_props; + sbs->charger.num_properties = ARRAY_SIZE(sbs_ac_props); + sbs->charger.get_property = sbs_get_ac_property; + power_supply_register(&sbs->device->dev, &sbs->charger); printk(KERN_INFO PREFIX "%s [%s]: AC Adapter [%s] (%s)\n", ACPI_SBS_DEVICE_NAME, acpi_device_bid(sbs->device), - ACPI_AC_DIR_NAME, sbs->ac.ac_present ? "on-line" : "off-line"); - + ACPI_AC_DIR_NAME, sbs->charger_present ? "on-line" : "off-line"); end: - return result; } -static void acpi_ac_remove(struct acpi_sbs *sbs) +static void acpi_charger_remove(struct acpi_sbs *sbs) { - - if (sbs->ac_entry) { - acpi_sbs_generic_remove_fs(&sbs->ac_entry, acpi_ac_dir); - } + if (sbs->charger.dev) + power_supply_unregister(&sbs->charger); +#ifdef CONFIG_ACPI_PROCFS + if (sbs->charger_entry) + acpi_sbs_remove_fs(&sbs->charger_entry, acpi_ac_dir); +#endif } -static void acpi_sbs_update_time_run(unsigned long data) +void acpi_sbs_callback(void *context) { - acpi_os_execute(OSL_GPE_HANDLER, acpi_sbs_update_time, (void *)data); -} - -static int acpi_sbs_update_run(struct acpi_sbs *sbs, int id, int data_type) -{ - struct acpi_battery *battery; - int result = 0, cnt; - int old_ac_present = -1; - int old_battery_present = -1; - int new_ac_present = -1; - int new_battery_present = -1; - int id_min = 0, id_max = MAX_SBS_BAT - 1; - char dir_name[32]; - int do_battery_init = 0, do_ac_init = 0; - int old_remaining_capacity = 0; - int update_battery = 1; - int up_tm = update_time; - - if (sbs_zombie(sbs)) { - goto end; - } - - if (id >= 0) { - id_min = id_max = id; - } - - if (data_type == DATA_TYPE_COMMON && up_tm > 0) { - cnt = up_tm / (up_tm > UPDATE_DELAY ? UPDATE_DELAY : up_tm); - if (sbs->run_cnt % cnt != 0) { - update_battery = 0; - } - } - - sbs->run_cnt++; - - old_ac_present = sbs->ac.ac_present; - - result = acpi_ac_get_present(sbs); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_ac_get_present() failed")); - } - - new_ac_present = sbs->ac.ac_present; - - do_ac_init = (old_ac_present != new_ac_present); - if (sbs->run_cnt == 1 && data_type == DATA_TYPE_COMMON) { - do_ac_init = 1; - } - - if (do_ac_init) { - result = acpi_sbs_generate_event(sbs->device, - ACPI_SBS_AC_NOTIFY_STATUS, - new_ac_present, - ACPI_AC_DIR_NAME, - ACPI_AC_CLASS); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_generate_event() failed")); - } - } - - if (data_type == DATA_TYPE_COMMON) { - if (!do_ac_init && !update_battery) { - goto end; - } - } - - if (data_type == DATA_TYPE_AC_STATE && !do_ac_init) { - goto end; - } - - for (id = id_min; id <= id_max; id++) { - battery = &sbs->battery[id]; - if (battery->alive == 0) { - continue; - } - - old_remaining_capacity = battery->state.remaining_capacity; - - old_battery_present = battery->battery_present; - - result = acpi_battery_select(battery); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_battery_select() failed")); - } - - result = acpi_battery_get_present(battery); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_battery_get_present() failed")); - } - - new_battery_present = battery->battery_present; - - do_battery_init = ((old_battery_present != new_battery_present) - && new_battery_present); - if (!new_battery_present) - goto event; - if (do_ac_init || do_battery_init) { - result = acpi_battery_init(battery); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_battery_init() " - "failed")); - } - } - if (sbs_zombie(sbs)) { - goto end; - } - - if ((data_type == DATA_TYPE_COMMON - || data_type == DATA_TYPE_INFO) - && new_battery_present) { - result = acpi_battery_get_info(battery); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_battery_get_info() failed")); - } - } - if (data_type == DATA_TYPE_INFO) { - continue; - } - if (sbs_zombie(sbs)) { - goto end; - } - - if ((data_type == DATA_TYPE_COMMON - || data_type == DATA_TYPE_STATE) - && new_battery_present) { - result = acpi_battery_get_state(battery); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_battery_get_state() failed")); - } - } - if (data_type == DATA_TYPE_STATE) { - goto event; - } - if (sbs_zombie(sbs)) { - goto end; - } - - if ((data_type == DATA_TYPE_COMMON - || data_type == DATA_TYPE_ALARM) - && new_battery_present) { - result = acpi_battery_get_alarm(battery); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_battery_get_alarm() " - "failed")); - } - } - if (data_type == DATA_TYPE_ALARM) { - continue; - } - if (sbs_zombie(sbs)) { - goto end; - } - - event: - - if (old_battery_present != new_battery_present || do_ac_init || - old_remaining_capacity != - battery->state.remaining_capacity) { - sprintf(dir_name, ACPI_BATTERY_DIR_NAME, id); - result = acpi_sbs_generate_event(sbs->device, - ACPI_SBS_BATTERY_NOTIFY_STATUS, - new_battery_present, - dir_name, - ACPI_BATTERY_CLASS); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_generate_event() " - "failed")); - } + int id; + struct acpi_sbs *sbs = context; + struct acpi_battery *bat; + u8 saved_charger_state = sbs->charger_present; + u8 saved_battery_state; + acpi_ac_get_present(sbs); + if (sbs->charger_present != saved_charger_state) { +#ifdef CONFIG_ACPI_PROC_EVENT + acpi_bus_generate_proc_event4(ACPI_AC_CLASS, ACPI_AC_DIR_NAME, + ACPI_SBS_NOTIFY_STATUS, + sbs->charger_present); +#endif + kobject_uevent(&sbs->charger.dev->kobj, KOBJ_CHANGE); + } + if (sbs->manager_present) { + for (id = 0; id < MAX_SBS_BAT; ++id) { + if (!(sbs->batteries_supported & (1 << id))) + continue; + bat = &sbs->battery[id]; + saved_battery_state = bat->present; + acpi_battery_read(bat); + if (saved_battery_state == bat->present) + continue; +#ifdef CONFIG_ACPI_PROC_EVENT + acpi_bus_generate_proc_event4(ACPI_BATTERY_CLASS, + bat->name, + ACPI_SBS_NOTIFY_STATUS, + bat->present); +#endif + kobject_uevent(&bat->bat.dev->kobj, KOBJ_CHANGE); } } - - end: - - return result; } -static void acpi_sbs_update_time(void *data) -{ - struct acpi_sbs *sbs = data; - unsigned long delay = -1; - int result; - unsigned int up_tm = update_time; - - if (sbs_mutex_lock(sbs)) - return; - - result = acpi_sbs_update_run(sbs, -1, DATA_TYPE_COMMON); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_update_run() failed")); - } - - if (sbs_zombie(sbs)) { - goto end; - } - - if (!up_tm) { - if (timer_pending(&sbs->update_timer)) - del_timer(&sbs->update_timer); - } else { - delay = (up_tm > UPDATE_DELAY ? UPDATE_DELAY : up_tm); - delay = jiffies + HZ * delay; - if (timer_pending(&sbs->update_timer)) { - mod_timer(&sbs->update_timer, delay); - } else { - sbs->update_timer.data = (unsigned long)data; - sbs->update_timer.function = acpi_sbs_update_time_run; - sbs->update_timer.expires = delay; - add_timer(&sbs->update_timer); - } - } - - end: - - sbs_mutex_unlock(sbs); -} +static int acpi_sbs_remove(struct acpi_device *device, int type); static int acpi_sbs_add(struct acpi_device *device) { - struct acpi_sbs *sbs = NULL; - int result = 0, remove_result = 0; + struct acpi_sbs *sbs; + int result = 0; int id; - acpi_status status = AE_OK; - unsigned long val; - - status = - acpi_evaluate_integer(device->handle, "_EC", NULL, &val); - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, "Error obtaining _EC")); - return -EIO; - } sbs = kzalloc(sizeof(struct acpi_sbs), GFP_KERNEL); if (!sbs) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, "kzalloc() failed")); result = -ENOMEM; goto end; } - mutex_init(&sbs->mutex); - - sbs_mutex_lock(sbs); + mutex_init(&sbs->lock); - sbs->base = 0xff & (val >> 8); + sbs->hc = acpi_driver_data(device->parent); sbs->device = device; - strcpy(acpi_device_name(device), ACPI_SBS_DEVICE_NAME); strcpy(acpi_device_class(device), ACPI_SBS_CLASS); acpi_driver_data(device) = sbs; - result = acpi_ac_add(sbs); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, "acpi_ac_add() failed")); - goto end; - } - - acpi_sbsm_get_info(sbs); - - if (!sbs->sbsm_present) { - result = acpi_battery_add(sbs, 0); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_battery_add() failed")); - goto end; - } - } else { - for (id = 0; id < MAX_SBS_BAT; id++) { - if ((sbs->sbsm_batteries_supported & (1 << id))) { - result = acpi_battery_add(sbs, id); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_battery_add() failed")); - goto end; - } - } - } - } - - init_timer(&sbs->update_timer); - result = acpi_check_update_proc(sbs); + result = acpi_charger_add(sbs); if (result) goto end; + result = acpi_manager_get_info(sbs); + if (!result) { + sbs->manager_present = 1; + for (id = 0; id < MAX_SBS_BAT; ++id) + if ((sbs->batteries_supported & (1 << id))) + acpi_battery_add(sbs, id); + } else + acpi_battery_add(sbs, 0); + acpi_smbus_register_callback(sbs->hc, acpi_sbs_callback, sbs); end: - - sbs_mutex_unlock(sbs); - - if (result) { - remove_result = acpi_sbs_remove(device, 0); - if (remove_result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_remove() failed")); - } - } - + if (result) + acpi_sbs_remove(device, 0); return result; } @@ -1713,39 +947,25 @@ static int acpi_sbs_remove(struct acpi_device *device, int type) struct acpi_sbs *sbs; int id; - if (!device) { + if (!device) return -EINVAL; - } - sbs = acpi_driver_data(device); - if (!sbs) { + if (!sbs) return -EINVAL; - } - - sbs_mutex_lock(sbs); - - sbs->zombie = 1; - del_timer_sync(&sbs->update_timer); - acpi_os_wait_events_complete(NULL); - del_timer_sync(&sbs->update_timer); - - for (id = 0; id < MAX_SBS_BAT; id++) { + mutex_lock(&sbs->lock); + acpi_smbus_unregister_callback(sbs->hc); + for (id = 0; id < MAX_SBS_BAT; ++id) acpi_battery_remove(sbs, id); - } - - acpi_ac_remove(sbs); - - sbs_mutex_unlock(sbs); - - mutex_destroy(&sbs->mutex); - + acpi_charger_remove(sbs); + mutex_unlock(&sbs->lock); + mutex_destroy(&sbs->lock); kfree(sbs); - return 0; } static void acpi_sbs_rmdirs(void) { +#ifdef CONFIG_ACPI_PROCFS if (acpi_ac_dir) { acpi_unlock_ac_dir(acpi_ac_dir); acpi_ac_dir = NULL; @@ -1754,69 +974,58 @@ static void acpi_sbs_rmdirs(void) acpi_unlock_battery_dir(acpi_battery_dir); acpi_battery_dir = NULL; } +#endif } static int acpi_sbs_resume(struct acpi_device *device) { struct acpi_sbs *sbs; - if (!device) return -EINVAL; - sbs = device->driver_data; - - sbs->run_cnt = 0; - + acpi_sbs_callback(sbs); return 0; } +static struct acpi_driver acpi_sbs_driver = { + .name = "sbs", + .class = ACPI_SBS_CLASS, + .ids = sbs_device_ids, + .ops = { + .add = acpi_sbs_add, + .remove = acpi_sbs_remove, + .resume = acpi_sbs_resume, + }, +}; + static int __init acpi_sbs_init(void) { int result = 0; if (acpi_disabled) return -ENODEV; - - if (capacity_mode != DEF_CAPACITY_UNIT - && capacity_mode != MAH_CAPACITY_UNIT - && capacity_mode != MWH_CAPACITY_UNIT) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "invalid capacity_mode = %d", capacity_mode)); - return -EINVAL; - } - +#ifdef CONFIG_ACPI_PROCFS acpi_ac_dir = acpi_lock_ac_dir(); - if (!acpi_ac_dir) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_lock_ac_dir() failed")); + if (!acpi_ac_dir) return -ENODEV; - } - acpi_battery_dir = acpi_lock_battery_dir(); if (!acpi_battery_dir) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_lock_battery_dir() failed")); acpi_sbs_rmdirs(); return -ENODEV; } - +#endif result = acpi_bus_register_driver(&acpi_sbs_driver); if (result < 0) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_bus_register_driver() failed")); acpi_sbs_rmdirs(); return -ENODEV; } - return 0; } static void __exit acpi_sbs_exit(void) { acpi_bus_unregister_driver(&acpi_sbs_driver); - acpi_sbs_rmdirs(); - return; } diff --git a/drivers/acpi/sbshc.c b/drivers/acpi/sbshc.c new file mode 100644 index 000000000000..046d7c3ed356 --- /dev/null +++ b/drivers/acpi/sbshc.c @@ -0,0 +1,309 @@ +/* + * SMBus driver for ACPI Embedded Controller (v0.1) + * + * Copyright (c) 2007 Alexey Starikovskiy + * + * 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 version 2. + */ + +#include <acpi/acpi_bus.h> +#include <acpi/acpi_drivers.h> +#include <acpi/actypes.h> +#include <linux/wait.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include "sbshc.h" + +#define ACPI_SMB_HC_CLASS "smbus_host_controller" +#define ACPI_SMB_HC_DEVICE_NAME "ACPI SMBus HC" + +struct acpi_smb_hc { + struct acpi_ec *ec; + struct mutex lock; + wait_queue_head_t wait; + u8 offset; + u8 query_bit; + smbus_alarm_callback callback; + void *context; +}; + +static int acpi_smbus_hc_add(struct acpi_device *device); +static int acpi_smbus_hc_remove(struct acpi_device *device, int type); + +static const struct acpi_device_id sbs_device_ids[] = { + {"ACPI0001", 0}, + {"ACPI0005", 0}, + {"", 0}, +}; + +MODULE_DEVICE_TABLE(acpi, sbs_device_ids); + +static struct acpi_driver acpi_smb_hc_driver = { + .name = "smbus_hc", + .class = ACPI_SMB_HC_CLASS, + .ids = sbs_device_ids, + .ops = { + .add = acpi_smbus_hc_add, + .remove = acpi_smbus_hc_remove, + }, +}; + +union acpi_smb_status { + u8 raw; + struct { + u8 status:5; + u8 reserved:1; + u8 alarm:1; + u8 done:1; + } fields; +}; + +enum acpi_smb_status_codes { + SMBUS_OK = 0, + SMBUS_UNKNOWN_FAILURE = 0x07, + SMBUS_DEVICE_ADDRESS_NACK = 0x10, + SMBUS_DEVICE_ERROR = 0x11, + SMBUS_DEVICE_COMMAND_ACCESS_DENIED = 0x12, + SMBUS_UNKNOWN_ERROR = 0x13, + SMBUS_DEVICE_ACCESS_DENIED = 0x17, + SMBUS_TIMEOUT = 0x18, + SMBUS_HOST_UNSUPPORTED_PROTOCOL = 0x19, + SMBUS_BUSY = 0x1a, + SMBUS_PEC_ERROR = 0x1f, +}; + +enum acpi_smb_offset { + ACPI_SMB_PROTOCOL = 0, /* protocol, PEC */ + ACPI_SMB_STATUS = 1, /* status */ + ACPI_SMB_ADDRESS = 2, /* address */ + ACPI_SMB_COMMAND = 3, /* command */ + ACPI_SMB_DATA = 4, /* 32 data registers */ + ACPI_SMB_BLOCK_COUNT = 0x24, /* number of data bytes */ + ACPI_SMB_ALARM_ADDRESS = 0x25, /* alarm address */ + ACPI_SMB_ALARM_DATA = 0x26, /* 2 bytes alarm data */ +}; + +static inline int smb_hc_read(struct acpi_smb_hc *hc, u8 address, u8 *data) +{ + return ec_read(hc->offset + address, data); +} + +static inline int smb_hc_write(struct acpi_smb_hc *hc, u8 address, u8 data) +{ + return ec_write(hc->offset + address, data); +} + +static inline int smb_check_done(struct acpi_smb_hc *hc) +{ + union acpi_smb_status status = {.raw = 0}; + smb_hc_read(hc, ACPI_SMB_STATUS, &status.raw); + return status.fields.done && (status.fields.status == SMBUS_OK); +} + +static int wait_transaction_complete(struct acpi_smb_hc *hc, int timeout) +{ + if (wait_event_timeout(hc->wait, smb_check_done(hc), + msecs_to_jiffies(timeout))) + return 0; + else + return -ETIME; +} + +int acpi_smbus_transaction(struct acpi_smb_hc *hc, u8 protocol, u8 address, + u8 command, u8 *data, u8 length) +{ + int ret = -EFAULT, i; + u8 temp, sz = 0; + + mutex_lock(&hc->lock); + if (smb_hc_read(hc, ACPI_SMB_PROTOCOL, &temp)) + goto end; + if (temp) { + ret = -EBUSY; + goto end; + } + smb_hc_write(hc, ACPI_SMB_COMMAND, command); + smb_hc_write(hc, ACPI_SMB_COMMAND, command); + if (!(protocol & 0x01)) { + smb_hc_write(hc, ACPI_SMB_BLOCK_COUNT, length); + for (i = 0; i < length; ++i) + smb_hc_write(hc, ACPI_SMB_DATA + i, data[i]); + } + smb_hc_write(hc, ACPI_SMB_ADDRESS, address << 1); + smb_hc_write(hc, ACPI_SMB_PROTOCOL, protocol); + /* + * Wait for completion. Save the status code, data size, + * and data into the return package (if required by the protocol). + */ + ret = wait_transaction_complete(hc, 1000); + if (ret || !(protocol & 0x01)) + goto end; + switch (protocol) { + case SMBUS_RECEIVE_BYTE: + case SMBUS_READ_BYTE: + sz = 1; + break; + case SMBUS_READ_WORD: + sz = 2; + break; + case SMBUS_READ_BLOCK: + if (smb_hc_read(hc, ACPI_SMB_BLOCK_COUNT, &sz)) { + ret = -EFAULT; + goto end; + } + sz &= 0x1f; + break; + } + for (i = 0; i < sz; ++i) + smb_hc_read(hc, ACPI_SMB_DATA + i, &data[i]); + end: + mutex_unlock(&hc->lock); + return ret; +} + +int acpi_smbus_read(struct acpi_smb_hc *hc, u8 protocol, u8 address, + u8 command, u8 *data) +{ + return acpi_smbus_transaction(hc, protocol, address, command, data, 0); +} + +EXPORT_SYMBOL_GPL(acpi_smbus_read); + +int acpi_smbus_write(struct acpi_smb_hc *hc, u8 protocol, u8 address, + u8 command, u8 *data, u8 length) +{ + return acpi_smbus_transaction(hc, protocol, address, command, data, length); +} + +EXPORT_SYMBOL_GPL(acpi_smbus_write); + +int acpi_smbus_register_callback(struct acpi_smb_hc *hc, + smbus_alarm_callback callback, void *context) +{ + mutex_lock(&hc->lock); + hc->callback = callback; + hc->context = context; + mutex_unlock(&hc->lock); + return 0; +} + +EXPORT_SYMBOL_GPL(acpi_smbus_register_callback); + +int acpi_smbus_unregister_callback(struct acpi_smb_hc *hc) +{ + mutex_lock(&hc->lock); + hc->callback = NULL; + hc->context = NULL; + mutex_unlock(&hc->lock); + return 0; +} + +EXPORT_SYMBOL_GPL(acpi_smbus_unregister_callback); + +static void acpi_smbus_callback(void *context) +{ + struct acpi_smb_hc *hc = context; + + if (hc->callback) + hc->callback(hc->context); +} + +static int smbus_alarm(void *context) +{ + struct acpi_smb_hc *hc = context; + union acpi_smb_status status; + if (smb_hc_read(hc, ACPI_SMB_STATUS, &status.raw)) + return 0; + /* Check if it is only a completion notify */ + if (status.fields.done) + wake_up(&hc->wait); + if (!status.fields.alarm) + return 0; + mutex_lock(&hc->lock); + smb_hc_write(hc, ACPI_SMB_STATUS, status.raw); + if (hc->callback) + acpi_os_execute(OSL_GPE_HANDLER, acpi_smbus_callback, hc); + mutex_unlock(&hc->lock); + return 0; +} + +typedef int (*acpi_ec_query_func) (void *data); + +extern int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit, + acpi_handle handle, acpi_ec_query_func func, + void *data); + +static int acpi_smbus_hc_add(struct acpi_device *device) +{ + int status; + unsigned long val; + struct acpi_smb_hc *hc; + + if (!device) + return -EINVAL; + + status = acpi_evaluate_integer(device->handle, "_EC", NULL, &val); + if (ACPI_FAILURE(status)) { + printk(KERN_ERR PREFIX "error obtaining _EC.\n"); + return -EIO; + } + + strcpy(acpi_device_name(device), ACPI_SMB_HC_DEVICE_NAME); + strcpy(acpi_device_class(device), ACPI_SMB_HC_CLASS); + + hc = kzalloc(sizeof(struct acpi_smb_hc), GFP_KERNEL); + if (!hc) + return -ENOMEM; + mutex_init(&hc->lock); + init_waitqueue_head(&hc->wait); + + hc->ec = acpi_driver_data(device->parent); + hc->offset = (val >> 8) & 0xff; + hc->query_bit = val & 0xff; + acpi_driver_data(device) = hc; + + acpi_ec_add_query_handler(hc->ec, hc->query_bit, NULL, smbus_alarm, hc); + printk(KERN_INFO PREFIX "SBS HC: EC = 0x%p, offset = 0x%0x, query_bit = 0x%0x\n", + hc->ec, hc->offset, hc->query_bit); + + return 0; +} + +extern void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit); + +static int acpi_smbus_hc_remove(struct acpi_device *device, int type) +{ + struct acpi_smb_hc *hc; + + if (!device) + return -EINVAL; + + hc = acpi_driver_data(device); + acpi_ec_remove_query_handler(hc->ec, hc->query_bit); + kfree(hc); + return 0; +} + +static int __init acpi_smb_hc_init(void) +{ + int result; + + result = acpi_bus_register_driver(&acpi_smb_hc_driver); + if (result < 0) + return -ENODEV; + return 0; +} + +static void __exit acpi_smb_hc_exit(void) +{ + acpi_bus_unregister_driver(&acpi_smb_hc_driver); +} + +module_init(acpi_smb_hc_init); +module_exit(acpi_smb_hc_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Alexey Starikovskiy"); +MODULE_DESCRIPTION("ACPI SMBus HC driver"); diff --git a/drivers/acpi/sbshc.h b/drivers/acpi/sbshc.h new file mode 100644 index 000000000000..3bda3491a97b --- /dev/null +++ b/drivers/acpi/sbshc.h @@ -0,0 +1,27 @@ +struct acpi_smb_hc; +enum acpi_smb_protocol { + SMBUS_WRITE_QUICK = 2, + SMBUS_READ_QUICK = 3, + SMBUS_SEND_BYTE = 4, + SMBUS_RECEIVE_BYTE = 5, + SMBUS_WRITE_BYTE = 6, + SMBUS_READ_BYTE = 7, + SMBUS_WRITE_WORD = 8, + SMBUS_READ_WORD = 9, + SMBUS_WRITE_BLOCK = 0xa, + SMBUS_READ_BLOCK = 0xb, + SMBUS_PROCESS_CALL = 0xc, + SMBUS_BLOCK_PROCESS_CALL = 0xd, +}; + +static const u8 SMBUS_PEC = 0x80; + +typedef void (*smbus_alarm_callback)(void *context); + +extern int acpi_smbus_read(struct acpi_smb_hc *hc, u8 protocol, u8 address, + u8 command, u8 * data); +extern int acpi_smbus_write(struct acpi_smb_hc *hc, u8 protocol, u8 slave_address, + u8 command, u8 * data, u8 length); +extern int acpi_smbus_register_callback(struct acpi_smb_hc *hc, + smbus_alarm_callback callback, void *context); +extern int acpi_smbus_unregister_callback(struct acpi_smb_hc *hc); diff --git a/drivers/acpi/sleep/Makefile b/drivers/acpi/sleep/Makefile index 195a4f69c0f7..f1fb888c2d29 100644 --- a/drivers/acpi/sleep/Makefile +++ b/drivers/acpi/sleep/Makefile @@ -1,5 +1,5 @@ -obj-y := poweroff.o wakeup.o -obj-$(CONFIG_ACPI_SLEEP) += main.o +obj-y := wakeup.o +obj-y += main.o obj-$(CONFIG_ACPI_SLEEP) += proc.o EXTRA_CFLAGS += $(ACPI_CFLAGS) diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c index c52ade816fb4..be616317fe53 100644 --- a/drivers/acpi/sleep/main.c +++ b/drivers/acpi/sleep/main.c @@ -15,13 +15,38 @@ #include <linux/dmi.h> #include <linux/device.h> #include <linux/suspend.h> + +#include <asm/io.h> + #include <acpi/acpi_bus.h> #include <acpi/acpi_drivers.h> #include "sleep.h" u8 sleep_states[ACPI_S_STATE_COUNT]; +#ifdef CONFIG_PM_SLEEP static u32 acpi_target_sleep_state = ACPI_STATE_S0; +#endif + +int acpi_sleep_prepare(u32 acpi_state) +{ +#ifdef CONFIG_ACPI_SLEEP + /* do we have a wakeup address for S2 and S3? */ + if (acpi_state == ACPI_STATE_S3) { + if (!acpi_wakeup_address) { + return -EFAULT; + } + acpi_set_firmware_waking_vector((acpi_physical_address) + virt_to_phys((void *) + acpi_wakeup_address)); + + } + ACPI_FLUSH_CPU_CACHE(); + acpi_enable_wakeup_device_prep(acpi_state); +#endif + acpi_enter_sleep_state_prep(acpi_state); + return 0; +} #ifdef CONFIG_SUSPEND static struct pm_ops acpi_pm_ops; @@ -230,6 +255,11 @@ static int acpi_hibernation_enter(void) static void acpi_hibernation_finish(void) { + /* + * If ACPI is not enabled by the BIOS and the boot kernel, we need to + * enable it here. + */ + acpi_enable(); acpi_leave_sleep_state(ACPI_STATE_S4); acpi_disable_wakeup_device(ACPI_STATE_S4); @@ -275,6 +305,7 @@ int acpi_suspend(u32 acpi_state) return -EINVAL; } +#ifdef CONFIG_PM_SLEEP /** * acpi_pm_device_sleep_state - return preferred power state of ACPI device * in the system sleep state given by %acpi_target_sleep_state @@ -349,6 +380,21 @@ int acpi_pm_device_sleep_state(struct device *dev, int wake, int *d_min_p) *d_min_p = d_min; return d_max; } +#endif + +static void acpi_power_off_prepare(void) +{ + /* Prepare to power off the system */ + acpi_sleep_prepare(ACPI_STATE_S5); +} + +static void acpi_power_off(void) +{ + /* acpi_sleep_prepare(ACPI_STATE_S5) should have already been called */ + printk("%s called\n", __FUNCTION__); + local_irq_disable(); + acpi_enter_sleep_state(ACPI_STATE_S5); +} int __init acpi_sleep_init(void) { @@ -363,16 +409,17 @@ int __init acpi_sleep_init(void) if (acpi_disabled) return 0; + sleep_states[ACPI_STATE_S0] = 1; + printk(KERN_INFO PREFIX "(supports S0"); + #ifdef CONFIG_SUSPEND - printk(KERN_INFO PREFIX "(supports"); - for (i = ACPI_STATE_S0; i < ACPI_STATE_S4; i++) { + for (i = ACPI_STATE_S1; i < ACPI_STATE_S4; i++) { status = acpi_get_sleep_type_data(i, &type_a, &type_b); if (ACPI_SUCCESS(status)) { sleep_states[i] = 1; printk(" S%d", i); } } - printk(")\n"); pm_set_ops(&acpi_pm_ops); #endif @@ -382,10 +429,16 @@ int __init acpi_sleep_init(void) if (ACPI_SUCCESS(status)) { hibernation_set_ops(&acpi_hibernation_ops); sleep_states[ACPI_STATE_S4] = 1; + printk(" S4"); } -#else - sleep_states[ACPI_STATE_S4] = 0; #endif - + status = acpi_get_sleep_type_data(ACPI_STATE_S5, &type_a, &type_b); + if (ACPI_SUCCESS(status)) { + sleep_states[ACPI_STATE_S5] = 1; + printk(" S5"); + pm_power_off_prepare = acpi_power_off_prepare; + pm_power_off = acpi_power_off; + } + printk(")\n"); return 0; } diff --git a/drivers/acpi/sleep/poweroff.c b/drivers/acpi/sleep/poweroff.c deleted file mode 100644 index 39e40d56b034..000000000000 --- a/drivers/acpi/sleep/poweroff.c +++ /dev/null @@ -1,75 +0,0 @@ -/* - * poweroff.c - ACPI handler for powering off the system. - * - * AKA S5, but it is independent of whether or not the kernel supports - * any other sleep support in the system. - * - * Copyright (c) 2005 Alexey Starikovskiy <alexey.y.starikovskiy@intel.com> - * - * This file is released under the GPLv2. - */ - -#include <linux/pm.h> -#include <linux/init.h> -#include <acpi/acpi_bus.h> -#include <linux/sysdev.h> -#include <asm/io.h> -#include "sleep.h" - -int acpi_sleep_prepare(u32 acpi_state) -{ -#ifdef CONFIG_ACPI_SLEEP - /* do we have a wakeup address for S2 and S3? */ - if (acpi_state == ACPI_STATE_S3) { - if (!acpi_wakeup_address) { - return -EFAULT; - } - acpi_set_firmware_waking_vector((acpi_physical_address) - virt_to_phys((void *) - acpi_wakeup_address)); - - } - ACPI_FLUSH_CPU_CACHE(); - acpi_enable_wakeup_device_prep(acpi_state); -#endif - acpi_gpe_sleep_prepare(acpi_state); - acpi_enter_sleep_state_prep(acpi_state); - return 0; -} - -#ifdef CONFIG_PM - -static void acpi_power_off_prepare(void) -{ - /* Prepare to power off the system */ - acpi_sleep_prepare(ACPI_STATE_S5); -} - -static void acpi_power_off(void) -{ - /* acpi_sleep_prepare(ACPI_STATE_S5) should have already been called */ - printk("%s called\n", __FUNCTION__); - local_irq_disable(); - /* Some SMP machines only can poweroff in boot CPU */ - acpi_enter_sleep_state(ACPI_STATE_S5); -} - -static int acpi_poweroff_init(void) -{ - if (!acpi_disabled) { - u8 type_a, type_b; - acpi_status status; - - status = - acpi_get_sleep_type_data(ACPI_STATE_S5, &type_a, &type_b); - if (ACPI_SUCCESS(status)) { - pm_power_off_prepare = acpi_power_off_prepare; - pm_power_off = acpi_power_off; - } - } - return 0; -} - -late_initcall(acpi_poweroff_init); - -#endif /* CONFIG_PM */ diff --git a/drivers/acpi/sleep/proc.c b/drivers/acpi/sleep/proc.c index 66b62b0d3609..3839efd5eaea 100644 --- a/drivers/acpi/sleep/proc.c +++ b/drivers/acpi/sleep/proc.c @@ -23,7 +23,7 @@ */ ACPI_MODULE_NAME("sleep") -#ifdef CONFIG_ACPI_PROCFS_SLEEP +#ifdef CONFIG_ACPI_PROCFS static int acpi_system_sleep_seq_show(struct seq_file *seq, void *offset) { int i; @@ -76,7 +76,7 @@ acpi_system_write_sleep(struct file *file, Done: return error ? error : count; } -#endif /* CONFIG_ACPI_PROCFS_SLEEP */ +#endif /* CONFIG_ACPI_PROCFS */ #if defined(CONFIG_RTC_DRV_CMOS) || defined(CONFIG_RTC_DRV_CMOS_MODULE) || !defined(CONFIG_X86) /* use /sys/class/rtc/rtcX/wakealarm instead; it's not ACPI-specific */ @@ -471,7 +471,7 @@ static const struct file_operations acpi_system_wakeup_device_fops = { .release = single_release, }; -#ifdef CONFIG_ACPI_PROCFS_SLEEP +#ifdef CONFIG_ACPI_PROCFS static const struct file_operations acpi_system_sleep_fops = { .open = acpi_system_sleep_open_fs, .read = seq_read, @@ -479,7 +479,7 @@ static const struct file_operations acpi_system_sleep_fops = { .llseek = seq_lseek, .release = single_release, }; -#endif /* CONFIG_ACPI_PROCFS_SLEEP */ +#endif /* CONFIG_ACPI_PROCFS */ #ifdef HAVE_ACPI_LEGACY_ALARM static const struct file_operations acpi_system_alarm_fops = { @@ -506,7 +506,7 @@ static int __init acpi_sleep_proc_init(void) if (acpi_disabled) return 0; -#ifdef CONFIG_ACPI_PROCFS_SLEEP +#ifdef CONFIG_ACPI_PROCFS /* 'sleep' [R/W] */ entry = create_proc_entry("sleep", S_IFREG | S_IRUGO | S_IWUSR, diff --git a/drivers/acpi/sleep/sleep.h b/drivers/acpi/sleep/sleep.h index ff1f8504f497..a2ea125ae2d0 100644 --- a/drivers/acpi/sleep/sleep.h +++ b/drivers/acpi/sleep/sleep.h @@ -5,6 +5,5 @@ extern int acpi_suspend (u32 state); extern void acpi_enable_wakeup_device_prep(u8 sleep_state); extern void acpi_enable_wakeup_device(u8 sleep_state); extern void acpi_disable_wakeup_device(u8 sleep_state); -extern void acpi_gpe_sleep_prepare(u32 sleep_state); extern int acpi_sleep_prepare(u32 acpi_state); diff --git a/drivers/acpi/sleep/wakeup.c b/drivers/acpi/sleep/wakeup.c index 97c27ddb144d..ed8e41becf0c 100644 --- a/drivers/acpi/sleep/wakeup.c +++ b/drivers/acpi/sleep/wakeup.c @@ -64,36 +64,29 @@ void acpi_enable_wakeup_device(u8 sleep_state) ACPI_FUNCTION_TRACE("acpi_enable_wakeup_device"); spin_lock(&acpi_device_lock); list_for_each_safe(node, next, &acpi_wakeup_device_list) { - struct acpi_device *dev = container_of(node, - struct acpi_device, - wakeup_list); - + struct acpi_device *dev = + container_of(node, struct acpi_device, wakeup_list); + if (!dev->wakeup.flags.valid) + continue; /* If users want to disable run-wake GPE, * we only disable it for wake and leave it for runtime */ - if (dev->wakeup.flags.run_wake && !dev->wakeup.state.enabled) { - spin_unlock(&acpi_device_lock); - acpi_set_gpe_type(dev->wakeup.gpe_device, - dev->wakeup.gpe_number, - ACPI_GPE_TYPE_RUNTIME); - /* Re-enable it, since set_gpe_type will disable it */ - acpi_enable_gpe(dev->wakeup.gpe_device, - dev->wakeup.gpe_number, ACPI_ISR); - spin_lock(&acpi_device_lock); + if (!dev->wakeup.state.enabled || + sleep_state > (u32) dev->wakeup.sleep_state) { + if (dev->wakeup.flags.run_wake) { + spin_unlock(&acpi_device_lock); + /* set_gpe_type will disable GPE, leave it like that */ + acpi_set_gpe_type(dev->wakeup.gpe_device, + dev->wakeup.gpe_number, + ACPI_GPE_TYPE_RUNTIME); + spin_lock(&acpi_device_lock); + } continue; } - - if (!dev->wakeup.flags.valid || - !dev->wakeup.state.enabled || - (sleep_state > (u32) dev->wakeup.sleep_state)) - continue; - spin_unlock(&acpi_device_lock); - /* run-wake GPE has been enabled */ if (!dev->wakeup.flags.run_wake) acpi_enable_gpe(dev->wakeup.gpe_device, dev->wakeup.gpe_number, ACPI_ISR); - dev->wakeup.state.active = 1; spin_lock(&acpi_device_lock); } spin_unlock(&acpi_device_lock); @@ -112,26 +105,25 @@ void acpi_disable_wakeup_device(u8 sleep_state) spin_lock(&acpi_device_lock); list_for_each_safe(node, next, &acpi_wakeup_device_list) { - struct acpi_device *dev = container_of(node, - struct acpi_device, - wakeup_list); + struct acpi_device *dev = + container_of(node, struct acpi_device, wakeup_list); - if (dev->wakeup.flags.run_wake && !dev->wakeup.state.enabled) { - spin_unlock(&acpi_device_lock); - acpi_set_gpe_type(dev->wakeup.gpe_device, - dev->wakeup.gpe_number, - ACPI_GPE_TYPE_WAKE_RUN); - /* Re-enable it, since set_gpe_type will disable it */ - acpi_enable_gpe(dev->wakeup.gpe_device, - dev->wakeup.gpe_number, ACPI_NOT_ISR); - spin_lock(&acpi_device_lock); + if (!dev->wakeup.flags.valid) continue; - } - - if (!dev->wakeup.flags.valid || - !dev->wakeup.state.active || - (sleep_state > (u32) dev->wakeup.sleep_state)) + if (!dev->wakeup.state.enabled || + sleep_state > (u32) dev->wakeup.sleep_state) { + if (dev->wakeup.flags.run_wake) { + spin_unlock(&acpi_device_lock); + acpi_set_gpe_type(dev->wakeup.gpe_device, + dev->wakeup.gpe_number, + ACPI_GPE_TYPE_WAKE_RUN); + /* Re-enable it, since set_gpe_type will disable it */ + acpi_enable_gpe(dev->wakeup.gpe_device, + dev->wakeup.gpe_number, ACPI_NOT_ISR); + spin_lock(&acpi_device_lock); + } continue; + } spin_unlock(&acpi_device_lock); acpi_disable_wakeup_device_power(dev); @@ -142,7 +134,6 @@ void acpi_disable_wakeup_device(u8 sleep_state) acpi_clear_gpe(dev->wakeup.gpe_device, dev->wakeup.gpe_number, ACPI_NOT_ISR); } - dev->wakeup.state.active = 0; spin_lock(&acpi_device_lock); } spin_unlock(&acpi_device_lock); @@ -160,48 +151,20 @@ static int __init acpi_wakeup_device_init(void) struct acpi_device *dev = container_of(node, struct acpi_device, wakeup_list); - /* In case user doesn't load button driver */ - if (dev->wakeup.flags.run_wake && !dev->wakeup.state.enabled) { - spin_unlock(&acpi_device_lock); - acpi_set_gpe_type(dev->wakeup.gpe_device, - dev->wakeup.gpe_number, - ACPI_GPE_TYPE_WAKE_RUN); - acpi_enable_gpe(dev->wakeup.gpe_device, - dev->wakeup.gpe_number, ACPI_NOT_ISR); - dev->wakeup.state.enabled = 1; - spin_lock(&acpi_device_lock); - } + if (!dev->wakeup.flags.run_wake || dev->wakeup.state.enabled) + continue; + spin_unlock(&acpi_device_lock); + acpi_set_gpe_type(dev->wakeup.gpe_device, + dev->wakeup.gpe_number, + ACPI_GPE_TYPE_WAKE_RUN); + acpi_enable_gpe(dev->wakeup.gpe_device, + dev->wakeup.gpe_number, ACPI_NOT_ISR); + dev->wakeup.state.enabled = 1; + spin_lock(&acpi_device_lock); } spin_unlock(&acpi_device_lock); - return 0; } late_initcall(acpi_wakeup_device_init); - -/* - * Disable all wakeup GPEs before entering requested sleep state. - * @sleep_state: ACPI state - * Since acpi_enter_sleep_state() will disable all - * RUNTIME GPEs, we simply mark all GPES that - * are not enabled for wakeup from requested state as RUNTIME. - */ -void acpi_gpe_sleep_prepare(u32 sleep_state) -{ - struct list_head *node, *next; - - list_for_each_safe(node, next, &acpi_wakeup_device_list) { - struct acpi_device *dev = container_of(node, - struct acpi_device, - wakeup_list); - - /* The GPE can wakeup system from this state, don't touch it */ - if ((u32) dev->wakeup.sleep_state >= sleep_state) - continue; - /* acpi_set_gpe_type will automatically disable GPE */ - acpi_set_gpe_type(dev->wakeup.gpe_device, - dev->wakeup.gpe_number, - ACPI_GPE_TYPE_RUNTIME); - } -} diff --git a/drivers/acpi/tables/tbutils.c b/drivers/acpi/tables/tbutils.c index 8cc9492ffbf2..5f1d85f2ffe4 100644 --- a/drivers/acpi/tables/tbutils.c +++ b/drivers/acpi/tables/tbutils.c @@ -400,7 +400,7 @@ acpi_tb_parse_root_table(acpi_physical_address rsdp_address, u8 flags) u32 table_count; struct acpi_table_header *table; acpi_physical_address address; - acpi_physical_address rsdt_address; + acpi_physical_address uninitialized_var(rsdt_address); u32 length; u8 *table_entry; acpi_status status; diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index bc6d5866ef98..69ec73b0239d 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -195,6 +195,7 @@ struct acpi_thermal { struct acpi_thermal_trips trips; struct acpi_handle_list devices; struct timer_list timer; + struct mutex lock; }; static const struct file_operations acpi_thermal_state_fops = { @@ -711,6 +712,7 @@ static void acpi_thermal_check(void *data) int result = 0; struct acpi_thermal *tz = data; unsigned long sleep_time = 0; + unsigned long timeout_jiffies = 0; int i = 0; struct acpi_thermal_state state; @@ -720,11 +722,15 @@ static void acpi_thermal_check(void *data) return; } + /* Check if someone else is already running */ + if (!mutex_trylock(&tz->lock)) + return; + state = tz->state; result = acpi_thermal_get_temperature(tz); if (result) - return; + goto unlock; memset(&tz->state, 0, sizeof(tz->state)); @@ -787,10 +793,13 @@ static void acpi_thermal_check(void *data) * a thermal event occurs). Note that _TSP and _TZD values are * given in 1/10th seconds (we must covert to milliseconds). */ - if (tz->state.passive) + if (tz->state.passive) { sleep_time = tz->trips.passive.tsp * 100; - else if (tz->polling_frequency > 0) + timeout_jiffies = jiffies + (HZ * sleep_time) / 1000; + } else if (tz->polling_frequency > 0) { sleep_time = tz->polling_frequency * 100; + timeout_jiffies = round_jiffies(jiffies + (HZ * sleep_time) / 1000); + } ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s: temperature[%lu] sleep[%lu]\n", tz->name, tz->temperature, sleep_time)); @@ -804,17 +813,16 @@ static void acpi_thermal_check(void *data) del_timer(&(tz->timer)); } else { if (timer_pending(&(tz->timer))) - mod_timer(&(tz->timer), - jiffies + (HZ * sleep_time) / 1000); + mod_timer(&(tz->timer), timeout_jiffies); else { tz->timer.data = (unsigned long)tz; tz->timer.function = acpi_thermal_run; - tz->timer.expires = jiffies + (HZ * sleep_time) / 1000; + tz->timer.expires = timeout_jiffies; add_timer(&(tz->timer)); } } - - return; + unlock: + mutex_unlock(&tz->lock); } /* -------------------------------------------------------------------------- @@ -1251,7 +1259,7 @@ static int acpi_thermal_add(struct acpi_device *device) strcpy(acpi_device_name(device), ACPI_THERMAL_DEVICE_NAME); strcpy(acpi_device_class(device), ACPI_THERMAL_CLASS); acpi_driver_data(device) = tz; - + mutex_init(&tz->lock); result = acpi_thermal_get_info(tz); if (result) goto end; @@ -1321,7 +1329,7 @@ static int acpi_thermal_remove(struct acpi_device *device, int type) } acpi_thermal_remove_fs(device); - + mutex_destroy(&tz->lock); kfree(tz); return 0; } diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 3c9bb85a6a93..f31e3c8749e0 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -409,15 +409,17 @@ acpi_video_device_lcd_query_levels(struct acpi_video_device *device, static int acpi_video_device_lcd_set_level(struct acpi_video_device *device, int level) { - int status; + int status = AE_OK; union acpi_object arg0 = { ACPI_TYPE_INTEGER }; struct acpi_object_list args = { 1, &arg0 }; arg0.integer.value = level; - status = acpi_evaluate_object(device->dev->handle, "_BCM", &args, NULL); - printk(KERN_DEBUG "set_level status: %x\n", status); + if (device->cap._BCM) + status = acpi_evaluate_object(device->dev->handle, "_BCM", + &args, NULL); + device->brightness->curr = level; return status; } @@ -425,11 +427,11 @@ static int acpi_video_device_lcd_get_level_current(struct acpi_video_device *device, unsigned long *level) { - int status; - - status = acpi_evaluate_integer(device->dev->handle, "_BQC", NULL, level); - - return status; + if (device->cap._BQC) + return acpi_evaluate_integer(device->dev->handle, "_BQC", NULL, + level); + *level = device->brightness->curr; + return AE_OK; } static int @@ -1634,9 +1636,20 @@ static int acpi_video_get_next_level(struct acpi_video_device *device, u32 level_current, u32 event) { - int min, max, min_above, max_below, i, l; + int min, max, min_above, max_below, i, l, delta = 255; max = max_below = 0; min = min_above = 255; + /* Find closest level to level_current */ + for (i = 0; i < device->brightness->count; i++) { + l = device->brightness->levels[i]; + if (abs(l - level_current) < abs(delta)) { + delta = l - level_current; + if (!delta) + break; + } + } + /* Ajust level_current to closest available level */ + level_current += delta; for (i = 0; i < device->brightness->count; i++) { l = device->brightness->levels[i]; if (l < min) @@ -1754,7 +1767,7 @@ static int acpi_video_bus_put_devices(struct acpi_video_bus *video) static int acpi_video_bus_start_devices(struct acpi_video_bus *video) { - return acpi_video_bus_DOS(video, 1, 0); + return acpi_video_bus_DOS(video, 0, 0); } static int acpi_video_bus_stop_devices(struct acpi_video_bus *video) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 06f212ff2b4f..c16820325d7b 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -418,10 +418,12 @@ static const struct pci_device_id ahci_pci_tbl[] = { /* ATI */ { PCI_VDEVICE(ATI, 0x4380), board_ahci_sb600 }, /* ATI SB600 */ - { PCI_VDEVICE(ATI, 0x4390), board_ahci_sb600 }, /* ATI SB700 IDE */ - { PCI_VDEVICE(ATI, 0x4391), board_ahci_sb600 }, /* ATI SB700 AHCI */ - { PCI_VDEVICE(ATI, 0x4392), board_ahci_sb600 }, /* ATI SB700 nraid5 */ - { PCI_VDEVICE(ATI, 0x4393), board_ahci_sb600 }, /* ATI SB700 raid5 */ + { PCI_VDEVICE(ATI, 0x4390), board_ahci_sb600 }, /* ATI SB700/800 */ + { PCI_VDEVICE(ATI, 0x4391), board_ahci_sb600 }, /* ATI SB700/800 */ + { PCI_VDEVICE(ATI, 0x4392), board_ahci_sb600 }, /* ATI SB700/800 */ + { PCI_VDEVICE(ATI, 0x4393), board_ahci_sb600 }, /* ATI SB700/800 */ + { PCI_VDEVICE(ATI, 0x4394), board_ahci_sb600 }, /* ATI SB700/800 */ + { PCI_VDEVICE(ATI, 0x4395), board_ahci_sb600 }, /* ATI SB700/800 */ /* VIA */ { PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251 }, /* VIA VT8251 */ diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index e40c94f5f59d..6996eb5b7506 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -921,6 +921,13 @@ static int piix_broken_suspend(void) { static struct dmi_system_id sysids[] = { { + .ident = "TECRA M3", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), + DMI_MATCH(DMI_PRODUCT_NAME, "TECRA M3"), + }, + }, + { .ident = "TECRA M5", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), @@ -955,7 +962,8 @@ static int piix_broken_suspend(void) DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE M500"), }, }, - { } + + { } /* terminate list */ }; static const char *oemstrs[] = { "Tecra M3,", @@ -1187,6 +1195,8 @@ static void piix_iocfg_bit18_quirk(struct pci_dev *pdev) DMI_MATCH(DMI_PRODUCT_NAME, "M570U"), }, }, + + { } /* terminate list */ }; u32 iocfg; diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index a3ee087223de..772be09b4689 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -3778,6 +3778,9 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { { "Maxtor 6L250S0", "BANC1G10", ATA_HORKAGE_NONCQ }, { "Maxtor 6B200M0", "BANC1BM0", ATA_HORKAGE_NONCQ }, { "Maxtor 6B200M0", "BANC1B10", ATA_HORKAGE_NONCQ }, + { "Maxtor 7B250S0", "BANC1B70", ATA_HORKAGE_NONCQ, }, + { "Maxtor 7B300S0", "BANC1B70", ATA_HORKAGE_NONCQ }, + { "Maxtor 7V300F0", "VA111630", ATA_HORKAGE_NONCQ }, { "HITACHI HDS7250SASUN500G 0621KTAWSD", "K2AOAJ0AHITACHI", ATA_HORKAGE_NONCQ }, /* NCQ hard hangs device under heavier load, needs hard power cycle */ @@ -3794,6 +3797,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { { "WDC WD740ADFD-00NLR1", NULL, ATA_HORKAGE_NONCQ, }, { "FUJITSU MHV2080BH", "00840028", ATA_HORKAGE_NONCQ, }, { "ST9160821AS", "3.CLF", ATA_HORKAGE_NONCQ, }, + { "ST3160812AS", "3.AD", ATA_HORKAGE_NONCQ, }, { "SAMSUNG HD401LJ", "ZZ100-15", ATA_HORKAGE_NONCQ, }, /* devices which puke on READ_NATIVE_MAX */ @@ -6035,6 +6039,7 @@ void ata_dev_init(struct ata_device *dev) */ spin_lock_irqsave(ap->lock, flags); dev->flags &= ~ATA_DFLAG_INIT_MASK; + dev->horkage = 0; spin_unlock_irqrestore(ap->lock, flags); memset((void *)dev + ATA_DEVICE_CLEAR_OFFSET, 0, diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index 1cce2198baaf..8023167bbbeb 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -297,7 +297,7 @@ void ata_bmdma_start (struct ata_queued_cmd *qc) dmactl = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD); iowrite8(dmactl | ATA_DMA_START, ap->ioaddr.bmdma_addr + ATA_DMA_CMD); - /* Strictly, one may wish to issue a readb() here, to + /* Strictly, one may wish to issue an ioread8() here, to * flush the mmio write. However, control also passes * to the hardware at this point, and it will interrupt * us when we are to resume control. So, in effect, @@ -307,6 +307,9 @@ void ata_bmdma_start (struct ata_queued_cmd *qc) * is expected, so I think it is best to not add a readb() * without first all the MMIO ATA cards/mobos. * Or maybe I'm just being paranoid. + * + * FIXME: The posting of this write means I/O starts are + * unneccessarily delayed for MMIO */ } diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c index 94e5edc12ac9..71bdc3b3189c 100644 --- a/drivers/ata/pata_ali.c +++ b/drivers/ata/pata_ali.c @@ -48,6 +48,13 @@ static struct dmi_system_id cable_dmi_table[] = { DMI_MATCH(DMI_BOARD_VERSION, "OmniBook N32N-736"), }, }, + { + .ident = "Toshiba Satelite S1800-814", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), + DMI_MATCH(DMI_PRODUCT_NAME, "S1800-814"), + }, + }, { } }; diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c index ed637ae33ece..5d8b91e70ecd 100644 --- a/drivers/ata/pata_it821x.c +++ b/drivers/ata/pata_it821x.c @@ -533,6 +533,10 @@ static int it821x_check_atapi_dma(struct ata_queued_cmd *qc) struct ata_port *ap = qc->ap; struct it821x_dev *itdev = ap->private_data; + /* Only use dma for transfers to/from the media. */ + if (qc->nbytes < 2048) + return -EOPNOTSUPP; + /* No ATAPI DMA in smart mode */ if (itdev->smart) return -EOPNOTSUPP; diff --git a/drivers/ata/pata_ixp4xx_cf.c b/drivers/ata/pata_ixp4xx_cf.c index 4ca7fd6118d5..5dea3584c6c2 100644 --- a/drivers/ata/pata_ixp4xx_cf.c +++ b/drivers/ata/pata_ixp4xx_cf.c @@ -189,6 +189,9 @@ static __devinit int ixp4xx_pata_probe(struct platform_device *pdev) data->cs0 = devm_ioremap(&pdev->dev, cs0->start, 0x1000); data->cs1 = devm_ioremap(&pdev->dev, cs1->start, 0x1000); + if (!data->cs0 || !data->cs1) + return -ENOMEM; + irq = platform_get_irq(pdev, 0); if (irq) set_irq_type(irq, IRQT_RISING); diff --git a/drivers/ata/pata_marvell.c b/drivers/ata/pata_marvell.c index ae206f35f747..b45506f1ef73 100644 --- a/drivers/ata/pata_marvell.c +++ b/drivers/ata/pata_marvell.c @@ -44,10 +44,10 @@ static int marvell_pre_reset(struct ata_port *ap, unsigned long deadline) return -ENOMEM; printk("BAR5:"); for(i = 0; i <= 0x0F; i++) - printk("%02X:%02X ", i, readb(barp + i)); + printk("%02X:%02X ", i, ioread8(barp + i)); printk("\n"); - devices = readl(barp + 0x0C); + devices = ioread32(barp + 0x0C); pci_iounmap(pdev, barp); if ((pdev->device == 0x6145) && (ap->port_no == 0) && diff --git a/drivers/ata/pata_sis.c b/drivers/ata/pata_sis.c index 2bd7645f1a88..cce2834b2b60 100644 --- a/drivers/ata/pata_sis.c +++ b/drivers/ata/pata_sis.c @@ -375,8 +375,9 @@ static void sis_66_set_dmamode (struct ata_port *ap, struct ata_device *adev) int drive_pci = sis_old_port_base(adev); u16 timing; + /* MWDMA 0-2 and UDMA 0-5 */ const u16 mwdma_bits[] = { 0x008, 0x302, 0x301 }; - const u16 udma_bits[] = { 0xF000, 0xD000, 0xB000, 0xA000, 0x9000}; + const u16 udma_bits[] = { 0xF000, 0xD000, 0xB000, 0xA000, 0x9000, 0x8000 }; pci_read_config_word(pdev, drive_pci, &timing); diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c index ea18e33f50ef..636c4f1a0b24 100644 --- a/drivers/ata/pata_via.c +++ b/drivers/ata/pata_via.c @@ -97,6 +97,7 @@ static const struct via_isa_bridge { u8 rev_max; u16 flags; } via_isa_bridges[] = { + { "vx800", PCI_DEVICE_ID_VIA_VX800, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST }, { "vt8237s", PCI_DEVICE_ID_VIA_8237S, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST }, { "vt8251", PCI_DEVICE_ID_VIA_8251, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST }, { "cx700", PCI_DEVICE_ID_VIA_CX700, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST }, @@ -243,7 +244,6 @@ static void via_do_set_mode(struct ata_port *ap, struct ata_device *adev, int mo int ut; int offset = 3 - (2*ap->port_no) - adev->devno; - /* Calculate the timing values we require */ ata_timing_compute(adev, mode, &t, T, UT); @@ -290,9 +290,17 @@ static void via_do_set_mode(struct ata_port *ap, struct ata_device *adev, int mo ut = t.udma ? (0xe0 | (FIT(t.udma, 2, 9) - 2)) : 0x07; break; } + /* Set UDMA unless device is not UDMA capable */ - if (udma_type) - pci_write_config_byte(pdev, 0x50 + offset, ut); + if (udma_type) { + u8 cable80_status; + + /* Get 80-wire cable detection bit */ + pci_read_config_byte(pdev, 0x50 + offset, &cable80_status); + cable80_status &= 0x10; + + pci_write_config_byte(pdev, 0x50 + offset, ut | cable80_status); + } } static void via_set_piomode(struct ata_port *ap, struct ata_device *adev) diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index 11bf6c7ac122..cb7dec97fee6 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -313,7 +313,10 @@ enum { #define IS_GEN_IIE(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_IIE) enum { - MV_DMA_BOUNDARY = 0xffffffffU, + /* DMA boundary 0xffff is required by the s/g splitting + * we need on /length/ in mv_fill-sg(). + */ + MV_DMA_BOUNDARY = 0xffffU, /* mask of register bits containing lower 32 bits * of EDMA request queue DMA address @@ -448,7 +451,7 @@ static struct scsi_host_template mv5_sht = { .queuecommand = ata_scsi_queuecmd, .can_queue = ATA_DEF_QUEUE, .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = MV_MAX_SG_CT, + .sg_tablesize = MV_MAX_SG_CT / 2, .cmd_per_lun = ATA_SHT_CMD_PER_LUN, .emulated = ATA_SHT_EMULATED, .use_clustering = 1, @@ -466,7 +469,7 @@ static struct scsi_host_template mv6_sht = { .queuecommand = ata_scsi_queuecmd, .can_queue = ATA_DEF_QUEUE, .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = MV_MAX_SG_CT, + .sg_tablesize = MV_MAX_SG_CT / 2, .cmd_per_lun = ATA_SHT_CMD_PER_LUN, .emulated = ATA_SHT_EMULATED, .use_clustering = 1, @@ -1139,15 +1142,27 @@ static unsigned int mv_fill_sg(struct ata_queued_cmd *qc) dma_addr_t addr = sg_dma_address(sg); u32 sg_len = sg_dma_len(sg); - mv_sg->addr = cpu_to_le32(addr & 0xffffffff); - mv_sg->addr_hi = cpu_to_le32((addr >> 16) >> 16); - mv_sg->flags_size = cpu_to_le32(sg_len & 0xffff); + while (sg_len) { + u32 offset = addr & 0xffff; + u32 len = sg_len; + + if ((offset + sg_len > 0x10000)) + len = 0x10000 - offset; + + mv_sg->addr = cpu_to_le32(addr & 0xffffffff); + mv_sg->addr_hi = cpu_to_le32((addr >> 16) >> 16); + mv_sg->flags_size = cpu_to_le32(len); - if (ata_sg_is_last(sg, qc)) - mv_sg->flags_size |= cpu_to_le32(EPRD_FLAG_END_OF_TBL); + sg_len -= len; + addr += len; + + if (!sg_len && ata_sg_is_last(sg, qc)) + mv_sg->flags_size |= cpu_to_le32(EPRD_FLAG_END_OF_TBL); + + mv_sg++; + n_sg++; + } - mv_sg++; - n_sg++; } return n_sg; diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index ef83e6b1e314..233e88693395 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -888,6 +888,16 @@ static inline void sil24_host_intr(struct ata_port *ap) u32 slot_stat, qc_active; int rc; + /* If PCIX_IRQ_WOC, there's an inherent race window between + * clearing IRQ pending status and reading PORT_SLOT_STAT + * which may cause spurious interrupts afterwards. This is + * unavoidable and much better than losing interrupts which + * happens if IRQ pending is cleared after reading + * PORT_SLOT_STAT. + */ + if (ap->flags & SIL24_FLAG_PCIX_IRQ_WOC) + writel(PORT_IRQ_COMPLETE, port + PORT_IRQ_STAT); + slot_stat = readl(port + PORT_SLOT_STAT); if (unlikely(slot_stat & HOST_SSTAT_ATTN)) { @@ -895,9 +905,6 @@ static inline void sil24_host_intr(struct ata_port *ap) return; } - if (ap->flags & SIL24_FLAG_PCIX_IRQ_WOC) - writel(PORT_IRQ_COMPLETE, port + PORT_IRQ_STAT); - qc_active = slot_stat & ~HOST_SSTAT_ATTN; rc = ata_qc_complete_multiple(ap, qc_active, sil24_finish_qc); if (rc > 0) @@ -910,7 +917,8 @@ static inline void sil24_host_intr(struct ata_port *ap) return; } - if (ata_ratelimit()) + /* spurious interrupts are expected if PCIX_IRQ_WOC */ + if (!(ap->flags & SIL24_FLAG_PCIX_IRQ_WOC) && ata_ratelimit()) ata_port_printk(ap, KERN_INFO, "spurious interrupt " "(slot_stat 0x%x active_tag %d sactive 0x%x)\n", slot_stat, ap->active_tag, ap->sactive); diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c index a4e631766eee..57fd30de8f0d 100644 --- a/drivers/ata/sata_via.c +++ b/drivers/ata/sata_via.c @@ -371,7 +371,7 @@ static void vt6421_set_dma_mode(struct ata_port *ap, struct ata_device *adev) { struct pci_dev *pdev = to_pci_dev(ap->host->dev); static const u8 udma_bits[] = { 0xEE, 0xE8, 0xE6, 0xE4, 0xE2, 0xE1, 0xE0, 0xE0 }; - pci_write_config_byte(pdev, PATA_UDMA_TIMING, udma_bits[adev->pio_mode - XFER_UDMA_0]); + pci_write_config_byte(pdev, PATA_UDMA_TIMING, udma_bits[adev->dma_mode - XFER_UDMA_0]); } static const unsigned int svia_bar_sizes[] = { diff --git a/drivers/base/core.c b/drivers/base/core.c index e6738bcbe5a9..ec86d6fc2360 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -284,6 +284,7 @@ static ssize_t show_uevent(struct device *dev, struct device_attribute *attr, /* let the kset specific function add its keys */ pos = data; + memset(envp, 0, sizeof(envp)); retval = kset->uevent_ops->uevent(kset, &dev->kobj, envp, ARRAY_SIZE(envp), pos, PAGE_SIZE); @@ -585,9 +586,13 @@ void device_initialize(struct device *dev) static struct kobject * get_device_parent(struct device *dev, struct device *parent) { - /* Set the parent to the class, not the parent device */ - /* this keeps sysfs from having a symlink to make old udevs happy */ - if (dev->class) + /* + * Set the parent to the class, not the parent device + * for topmost devices in class hierarchy. + * This keeps sysfs from having a symlink to make old + * udevs happy + */ + if (dev->class && (!parent || parent->class != dev->class)) return &dev->class->subsys.kobj; else if (parent) return &parent->kobj; @@ -679,14 +684,26 @@ static int device_add_class_symlinks(struct device *dev) goto out_subsys; } if (dev->parent) { - error = sysfs_create_link(&dev->kobj, &dev->parent->kobj, - "device"); - if (error) - goto out_busid; #ifdef CONFIG_SYSFS_DEPRECATED { - char * class_name = make_class_name(dev->class->name, - &dev->kobj); + struct device *parent = dev->parent; + char *class_name; + + /* + * In old sysfs stacked class devices had 'device' + * link pointing to real device instead of parent + */ + while (parent->class && !parent->bus && parent->parent) + parent = parent->parent; + + error = sysfs_create_link(&dev->kobj, + &parent->kobj, + "device"); + if (error) + goto out_busid; + + class_name = make_class_name(dev->class->name, + &dev->kobj); if (class_name) error = sysfs_create_link(&dev->parent->kobj, &dev->kobj, class_name); @@ -694,6 +711,11 @@ static int device_add_class_symlinks(struct device *dev) if (error) goto out_device; } +#else + error = sysfs_create_link(&dev->kobj, &dev->parent->kobj, + "device"); + if (error) + goto out_busid; #endif } return 0; diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c index 92bf868ca056..84d6aa500e26 100644 --- a/drivers/block/DAC960.c +++ b/drivers/block/DAC960.c @@ -17,8 +17,8 @@ */ -#define DAC960_DriverVersion "2.5.48" -#define DAC960_DriverDate "14 May 2006" +#define DAC960_DriverVersion "2.5.49" +#define DAC960_DriverDate "21 Aug 2007" #include <linux/module.h> @@ -31,6 +31,7 @@ #include <linux/genhd.h> #include <linux/hdreg.h> #include <linux/blkpg.h> +#include <linux/dma-mapping.h> #include <linux/interrupt.h> #include <linux/ioport.h> #include <linux/mm.h> @@ -1165,9 +1166,9 @@ static bool DAC960_V1_EnableMemoryMailboxInterface(DAC960_Controller_T int i; - if (pci_set_dma_mask(Controller->PCIDevice, DAC690_V1_PciDmaMask)) + if (pci_set_dma_mask(Controller->PCIDevice, DMA_32BIT_MASK)) return DAC960_Failure(Controller, "DMA mask out of range"); - Controller->BounceBufferLimit = DAC690_V1_PciDmaMask; + Controller->BounceBufferLimit = DMA_32BIT_MASK; if ((hw_type == DAC960_PD_Controller) || (hw_type == DAC960_P_Controller)) { CommandMailboxesSize = 0; @@ -1368,9 +1369,12 @@ static bool DAC960_V2_EnableMemoryMailboxInterface(DAC960_Controller_T dma_addr_t CommandMailboxDMA; DAC960_V2_CommandStatus_T CommandStatus; - if (pci_set_dma_mask(Controller->PCIDevice, DAC690_V2_PciDmaMask)) - return DAC960_Failure(Controller, "DMA mask out of range"); - Controller->BounceBufferLimit = DAC690_V2_PciDmaMask; + if (!pci_set_dma_mask(Controller->PCIDevice, DMA_64BIT_MASK)) + Controller->BounceBufferLimit = DMA_64BIT_MASK; + else if (!pci_set_dma_mask(Controller->PCIDevice, DMA_32BIT_MASK)) + Controller->BounceBufferLimit = DMA_32BIT_MASK; + else + return DAC960_Failure(Controller, "DMA mask out of range"); /* This is a temporary dma mapping, used only in the scope of this function */ CommandMailbox = pci_alloc_consistent(PCI_Device, diff --git a/drivers/block/DAC960.h b/drivers/block/DAC960.h index f5e2436c39aa..85fa9bb63759 100644 --- a/drivers/block/DAC960.h +++ b/drivers/block/DAC960.h @@ -61,13 +61,6 @@ #define DAC960_V2_MaxPhysicalDevices 272 /* - Define the pci dma mask supported by DAC960 V1 and V2 Firmware Controlers - */ - -#define DAC690_V1_PciDmaMask 0xffffffff -#define DAC690_V2_PciDmaMask 0xffffffffffffffffULL - -/* Define a 32/64 bit I/O Address data type. */ diff --git a/drivers/bluetooth/hci_usb.c b/drivers/bluetooth/hci_usb.c index 59b054810ed0..98a9cdeaffb6 100644 --- a/drivers/bluetooth/hci_usb.c +++ b/drivers/bluetooth/hci_usb.c @@ -691,15 +691,18 @@ static void hci_usb_rx_complete(struct urb *urb) urb->iso_frame_desc[i].offset, urb->iso_frame_desc[i].actual_length); - if (!urb->iso_frame_desc[i].status) + if (!urb->iso_frame_desc[i].status) { + husb->hdev->stat.byte_rx += urb->iso_frame_desc[i].actual_length; hci_recv_fragment(husb->hdev, _urb->type, urb->transfer_buffer + urb->iso_frame_desc[i].offset, urb->iso_frame_desc[i].actual_length); + } } #else ; #endif } else { + husb->hdev->stat.byte_rx += count; err = hci_recv_fragment(husb->hdev, _urb->type, urb->transfer_buffer, count); if (err < 0) { BT_ERR("%s corrupted packet: type %d count %d", diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index 67ee3d4b2878..79245714f0a7 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -1032,6 +1032,10 @@ int cdrom_open(struct cdrom_device_info *cdi, struct inode *ip, struct file *fp) check_disk_change(ip->i_bdev); return 0; err_release: + if (CDROM_CAN(CDC_LOCK) && cdi->options & CDO_LOCK) { + cdi->ops->lock_door(cdi, 0); + cdinfo(CD_OPEN, "door unlocked.\n"); + } cdi->ops->release(cdi); err: cdi->use_count--; diff --git a/drivers/char/Makefile b/drivers/char/Makefile index d68ddbe70f73..c78ff26647ee 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -129,7 +129,7 @@ $(obj)/defkeymap.o: $(obj)/defkeymap.c ifdef GENERATE_KEYMAP -$(obj)/defkeymap.c $(obj)/%.c: $(src)/%.map +$(obj)/defkeymap.c: $(obj)/%.c: $(src)/%.map loadkeys --mktable $< > $@.tmp sed -e 's/^static *//' $@.tmp > $@ rm $@.tmp diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h index 35ab1a9f8e8b..8955e7ff759a 100644 --- a/drivers/char/agp/agp.h +++ b/drivers/char/agp/agp.h @@ -176,7 +176,7 @@ struct agp_bridge_data { #define I830_GMCH_MEM_MASK 0x1 #define I830_GMCH_MEM_64M 0x1 #define I830_GMCH_MEM_128M 0 -#define I830_GMCH_GMS_MASK 0xF0 +#define I830_GMCH_GMS_MASK 0x70 #define I830_GMCH_GMS_DISABLED 0x00 #define I830_GMCH_GMS_LOCAL 0x10 #define I830_GMCH_GMS_STOLEN_512 0x20 @@ -190,6 +190,7 @@ struct agp_bridge_data { #define INTEL_I830_ERRSTS 0x92 /* Intel 855GM/852GM registers */ +#define I855_GMCH_GMS_MASK 0xF0 #define I855_GMCH_GMS_STOLEN_0M 0x0 #define I855_GMCH_GMS_STOLEN_1M (0x1 << 4) #define I855_GMCH_GMS_STOLEN_4M (0x2 << 4) diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index 2c9ca2c64628..141ca176c397 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -506,7 +506,7 @@ static void intel_i830_init_gtt_entries(void) break; } } else { - switch (gmch_ctrl & I830_GMCH_GMS_MASK) { + switch (gmch_ctrl & I855_GMCH_GMS_MASK) { case I855_GMCH_GMS_STOLEN_1M: gtt_entries = MB(1) - KB(size); break; @@ -914,6 +914,7 @@ static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge) struct aper_size_info_fixed *size; int num_entries; u32 temp, temp2; + int gtt_map_size = 256 * 1024; size = agp_bridge->current_size; page_order = size->page_order; @@ -923,7 +924,9 @@ static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge) pci_read_config_dword(intel_private.pcidev, I915_MMADDR, &temp); pci_read_config_dword(intel_private.pcidev, I915_PTEADDR,&temp2); - intel_private.gtt = ioremap(temp2, 256 * 1024); + if (IS_G33) + gtt_map_size = 1024 * 1024; /* 1M on G33 */ + intel_private.gtt = ioremap(temp2, gtt_map_size); if (!intel_private.gtt) return -ENOMEM; diff --git a/drivers/char/drm/i915_drv.h b/drivers/char/drm/i915_drv.h index 737088bd0780..28b98733beb8 100644 --- a/drivers/char/drm/i915_drv.h +++ b/drivers/char/drm/i915_drv.h @@ -210,6 +210,12 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); #define I915REG_INT_MASK_R 0x020a8 #define I915REG_INT_ENABLE_R 0x020a0 +#define I915REG_PIPEASTAT 0x70024 +#define I915REG_PIPEBSTAT 0x71024 + +#define I915_VBLANK_INTERRUPT_ENABLE (1UL<<17) +#define I915_VBLANK_CLEAR (1UL<<1) + #define SRX_INDEX 0x3c4 #define SRX_DATA 0x3c5 #define SR01 1 diff --git a/drivers/char/drm/i915_irq.c b/drivers/char/drm/i915_irq.c index 4b4b2ce89863..bb8e9e9c8201 100644 --- a/drivers/char/drm/i915_irq.c +++ b/drivers/char/drm/i915_irq.c @@ -214,6 +214,10 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) struct drm_device *dev = (struct drm_device *) arg; drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; u16 temp; + u32 pipea_stats, pipeb_stats; + + pipea_stats = I915_READ(I915REG_PIPEASTAT); + pipeb_stats = I915_READ(I915REG_PIPEBSTAT); temp = I915_READ16(I915REG_INT_IDENTITY_R); @@ -225,6 +229,8 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) return IRQ_NONE; I915_WRITE16(I915REG_INT_IDENTITY_R, temp); + (void) I915_READ16(I915REG_INT_IDENTITY_R); + DRM_READMEMORYBARRIER(); dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); @@ -252,6 +258,12 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) if (dev_priv->swaps_pending > 0) drm_locked_tasklet(dev, i915_vblank_tasklet); + I915_WRITE(I915REG_PIPEASTAT, + pipea_stats|I915_VBLANK_INTERRUPT_ENABLE| + I915_VBLANK_CLEAR); + I915_WRITE(I915REG_PIPEBSTAT, + pipeb_stats|I915_VBLANK_INTERRUPT_ENABLE| + I915_VBLANK_CLEAR); } return IRQ_HANDLED; diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c index 7ecffc9c738f..4c16778e3f84 100644 --- a/drivers/char/hpet.c +++ b/drivers/char/hpet.c @@ -62,6 +62,8 @@ static u32 hpet_nhpet, hpet_max_freq = HPET_USER_FREQ; +/* This clocksource driver currently only works on ia64 */ +#ifdef CONFIG_IA64 static void __iomem *hpet_mctr; static cycle_t read_hpet(void) @@ -79,6 +81,7 @@ static struct clocksource clocksource_hpet = { .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; static struct clocksource *hpet_clocksource; +#endif /* A lock for concurrent access by app and isr hpet activity. */ static DEFINE_SPINLOCK(hpet_lock); @@ -943,14 +946,14 @@ static acpi_status hpet_resources(struct acpi_resource *res, void *data) printk(KERN_DEBUG "%s: 0x%lx is busy\n", __FUNCTION__, hdp->hd_phys_address); iounmap(hdp->hd_address); - return -EBUSY; + return AE_ALREADY_EXISTS; } } else if (res->type == ACPI_RESOURCE_TYPE_FIXED_MEMORY32) { struct acpi_resource_fixed_memory32 *fixmem32; fixmem32 = &res->data.fixed_memory32; if (!fixmem32) - return -EINVAL; + return AE_NO_MEMORY; hdp->hd_phys_address = fixmem32->address; hdp->hd_address = ioremap(fixmem32->address, @@ -960,7 +963,7 @@ static acpi_status hpet_resources(struct acpi_resource *res, void *data) printk(KERN_DEBUG "%s: 0x%lx is busy\n", __FUNCTION__, hdp->hd_phys_address); iounmap(hdp->hd_address); - return -EBUSY; + return AE_ALREADY_EXISTS; } } else if (res->type == ACPI_RESOURCE_TYPE_EXTENDED_IRQ) { struct acpi_resource_extended_irq *irqp; diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 9b07f7851061..dd441ff4af56 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -2215,7 +2215,8 @@ static int ipmi_pci_resume(struct pci_dev *pdev) static struct pci_device_id ipmi_pci_devices[] = { { PCI_DEVICE(PCI_HP_VENDOR_ID, PCI_MMC_DEVICE_ID) }, - { PCI_DEVICE_CLASS(PCI_ERMC_CLASSCODE, PCI_ERMC_CLASSCODE_MASK) } + { PCI_DEVICE_CLASS(PCI_ERMC_CLASSCODE, PCI_ERMC_CLASSCODE_MASK) }, + { 0, } }; MODULE_DEVICE_TABLE(pci, ipmi_pci_devices); diff --git a/drivers/char/mspec.c b/drivers/char/mspec.c index c08a4152ee8f..04ac155d3a07 100644 --- a/drivers/char/mspec.c +++ b/drivers/char/mspec.c @@ -67,7 +67,7 @@ /* * Page types allocated by the device. */ -enum { +enum mspec_page_type { MSPEC_FETCHOP = 1, MSPEC_CACHED, MSPEC_UNCACHED @@ -83,15 +83,25 @@ static int is_sn2; * One of these structures is allocated when an mspec region is mmaped. The * structure is pointed to by the vma->vm_private_data field in the vma struct. * This structure is used to record the addresses of the mspec pages. + * This structure is shared by all vma's that are split off from the + * original vma when split_vma()'s are done. + * + * The refcnt is incremented atomically because mm->mmap_sem does not + * protect in fork case where multiple tasks share the vma_data. */ struct vma_data { atomic_t refcnt; /* Number of vmas sharing the data. */ - spinlock_t lock; /* Serialize access to the vma. */ + spinlock_t lock; /* Serialize access to this structure. */ int count; /* Number of pages allocated. */ - int type; /* Type of pages allocated. */ + enum mspec_page_type type; /* Type of pages allocated. */ + int flags; /* See VMD_xxx below. */ + unsigned long vm_start; /* Original (unsplit) base. */ + unsigned long vm_end; /* Original (unsplit) end. */ unsigned long maddr[0]; /* Array of MSPEC addresses. */ }; +#define VMD_VMALLOCED 0x1 /* vmalloc'd rather than kmalloc'd */ + /* used on shub2 to clear FOP cache in the HUB */ static unsigned long scratch_page[MAX_NUMNODES]; #define SH2_AMO_CACHE_ENTRIES 4 @@ -129,8 +139,8 @@ mspec_zero_block(unsigned long addr, int len) * mspec_open * * Called when a device mapping is created by a means other than mmap - * (via fork, etc.). Increments the reference count on the underlying - * mspec data so it is not freed prematurely. + * (via fork, munmap, etc.). Increments the reference count on the + * underlying mspec data so it is not freed prematurely. */ static void mspec_open(struct vm_area_struct *vma) @@ -145,43 +155,43 @@ mspec_open(struct vm_area_struct *vma) * mspec_close * * Called when unmapping a device mapping. Frees all mspec pages - * belonging to the vma. + * belonging to all the vma's sharing this vma_data structure. */ static void mspec_close(struct vm_area_struct *vma) { struct vma_data *vdata; - int i, pages, result, vdata_size; + int index, last_index; + unsigned long my_page; vdata = vma->vm_private_data; + if (!atomic_dec_and_test(&vdata->refcnt)) return; - pages = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; - vdata_size = sizeof(struct vma_data) + pages * sizeof(long); - for (i = 0; i < pages; i++) { - if (vdata->maddr[i] == 0) + last_index = (vdata->vm_end - vdata->vm_start) >> PAGE_SHIFT; + for (index = 0; index < last_index; index++) { + if (vdata->maddr[index] == 0) continue; /* * Clear the page before sticking it back * into the pool. */ - result = mspec_zero_block(vdata->maddr[i], PAGE_SIZE); - if (!result) - uncached_free_page(vdata->maddr[i]); + my_page = vdata->maddr[index]; + vdata->maddr[index] = 0; + if (!mspec_zero_block(my_page, PAGE_SIZE)) + uncached_free_page(my_page); else printk(KERN_WARNING "mspec_close(): " - "failed to zero page %i\n", - result); + "failed to zero page %ld\n", my_page); } - if (vdata_size <= PAGE_SIZE) - kfree(vdata); - else + if (vdata->flags & VMD_VMALLOCED) vfree(vdata); + else + kfree(vdata); } - /* * mspec_nopfn * @@ -195,7 +205,8 @@ mspec_nopfn(struct vm_area_struct *vma, unsigned long address) int index; struct vma_data *vdata = vma->vm_private_data; - index = (address - vma->vm_start) >> PAGE_SHIFT; + BUG_ON(address < vdata->vm_start || address >= vdata->vm_end); + index = (address - vdata->vm_start) >> PAGE_SHIFT; maddr = (volatile unsigned long) vdata->maddr[index]; if (maddr == 0) { maddr = uncached_alloc_page(numa_node_id()); @@ -237,10 +248,11 @@ static struct vm_operations_struct mspec_vm_ops = { * underlying pages. */ static int -mspec_mmap(struct file *file, struct vm_area_struct *vma, int type) +mspec_mmap(struct file *file, struct vm_area_struct *vma, + enum mspec_page_type type) { struct vma_data *vdata; - int pages, vdata_size; + int pages, vdata_size, flags = 0; if (vma->vm_pgoff != 0) return -EINVAL; @@ -255,12 +267,17 @@ mspec_mmap(struct file *file, struct vm_area_struct *vma, int type) vdata_size = sizeof(struct vma_data) + pages * sizeof(long); if (vdata_size <= PAGE_SIZE) vdata = kmalloc(vdata_size, GFP_KERNEL); - else + else { vdata = vmalloc(vdata_size); + flags = VMD_VMALLOCED; + } if (!vdata) return -ENOMEM; memset(vdata, 0, vdata_size); + vdata->vm_start = vma->vm_start; + vdata->vm_end = vma->vm_end; + vdata->flags = flags; vdata->type = type; spin_lock_init(&vdata->lock); vdata->refcnt = ATOMIC_INIT(1); diff --git a/drivers/char/random.c b/drivers/char/random.c index 397c714cf2ba..af274e5a25ee 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -1550,11 +1550,13 @@ __u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr, * As close as possible to RFC 793, which * suggests using a 250 kHz clock. * Further reading shows this assumes 2 Mb/s networks. - * For 10 Gb/s Ethernet, a 1 GHz clock is appropriate. - * That's funny, Linux has one built in! Use it! - * (Networks are faster now - should this be increased?) + * For 10 Mb/s Ethernet, a 1 MHz clock is appropriate. + * For 10 Gb/s Ethernet, a 1 GHz clock should be ok, but + * we also need to limit the resolution so that the u32 seq + * overlaps less than one time per MSL (2 minutes). + * Choosing a clock of 64 ns period is OK. (period of 274 s) */ - seq += ktime_get_real().tv64; + seq += ktime_get_real().tv64 >> 6; #if 0 printk("init_seq(%lx, %lx, %d, %d) = %d\n", saddr, daddr, sport, dport, seq); diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c index 3423e9ee6481..3ee73cf64bd2 100644 --- a/drivers/char/tty_ioctl.c +++ b/drivers/char/tty_ioctl.c @@ -795,6 +795,7 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file, if (L_ICANON(tty)) retval = inq_canon(tty); return put_user(retval, (unsigned int __user *) arg); +#ifndef TCGETS2 case TIOCGLCKTRMIOS: if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios_locked)) return -EFAULT; @@ -806,6 +807,19 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file, if (user_termios_to_kernel_termios(real_tty->termios_locked, (struct termios __user *) arg)) return -EFAULT; return 0; +#else + case TIOCGLCKTRMIOS: + if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios_locked)) + return -EFAULT; + return 0; + + case TIOCSLCKTRMIOS: + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (user_termios_to_kernel_termios_1(real_tty->termios_locked, (struct termios __user *) arg)) + return -EFAULT; + return 0; +#endif case TIOCPKT: { diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c index c6f6f4209739..7a61a2a9aafe 100644 --- a/drivers/char/vt_ioctl.c +++ b/drivers/char/vt_ioctl.c @@ -770,6 +770,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, /* * Switching-from response */ + acquire_console_sem(); if (vc->vt_newvt >= 0) { if (arg == 0) /* @@ -784,7 +785,6 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, * complete the switch. */ int newvt; - acquire_console_sem(); newvt = vc->vt_newvt; vc->vt_newvt = -1; i = vc_allocate(newvt); @@ -798,7 +798,6 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, * other console switches.. */ complete_change_console(vc_cons[newvt].d); - release_console_sem(); } } @@ -810,9 +809,12 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, /* * If it's just an ACK, ignore it */ - if (arg != VT_ACKACQ) + if (arg != VT_ACKACQ) { + release_console_sem(); return -EINVAL; + } } + release_console_sem(); return 0; @@ -1030,7 +1032,7 @@ static DECLARE_WAIT_QUEUE_HEAD(vt_activate_queue); /* * Sleeps until a vt is activated, or the task is interrupted. Returns - * 0 if activation, -EINTR if interrupted. + * 0 if activation, -EINTR if interrupted by a signal handler. */ int vt_waitactive(int vt) { @@ -1055,7 +1057,7 @@ int vt_waitactive(int vt) break; } release_console_sem(); - retval = -EINTR; + retval = -ERESTARTNOHAND; if (signal_pending(current)) break; schedule(); @@ -1208,15 +1210,18 @@ void change_console(struct vc_data *new_vc) /* * Send the signal as privileged - kill_pid() will * tell us if the process has gone or something else - * is awry + * is awry. + * + * We need to set vt_newvt *before* sending the signal or we + * have a race. */ + vc->vt_newvt = new_vc->vc_num; if (kill_pid(vc->vt_pid, vc->vt_mode.relsig, 1) == 0) { /* * It worked. Mark the vt to switch to and * return. The process needs to send us a * VT_RELDISP ioctl to complete the switch. */ - vc->vt_newvt = new_vc->vc_num; return; } diff --git a/drivers/edac/e752x_edac.c b/drivers/edac/e752x_edac.c index 3bba224cb55d..6eb434749cd5 100644 --- a/drivers/edac/e752x_edac.c +++ b/drivers/edac/e752x_edac.c @@ -967,7 +967,7 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx) if (!force_function_unhide && !(stat8 & (1 << 5))) { printk(KERN_INFO "Contact your BIOS vendor to see if the " "E752x error registers can be safely un-hidden\n"); - return -ENOMEM; + return -ENODEV; } stat8 |= (1 << 5); pci_write_config_byte(pdev, E752X_DEVPRES1, stat8); diff --git a/drivers/edac/edac_core.h b/drivers/edac/edac_core.h index 4e6bad15c4ba..e80af67664cc 100644 --- a/drivers/edac/edac_core.h +++ b/drivers/edac/edac_core.h @@ -75,7 +75,7 @@ extern int edac_debug_level; #define edac_debug_printk(level, fmt, arg...) \ do { \ if (level <= edac_debug_level) \ - edac_printk(KERN_EMERG, EDAC_DEBUG, fmt, ##arg); \ + edac_printk(KERN_DEBUG, EDAC_DEBUG, fmt, ##arg); \ } while(0) #define debugf0( ... ) edac_debug_printk(0, __VA_ARGS__ ) diff --git a/drivers/firewire/Kconfig b/drivers/firewire/Kconfig index d011a76f8e7a..fe9e768cfbc4 100644 --- a/drivers/firewire/Kconfig +++ b/drivers/firewire/Kconfig @@ -11,7 +11,8 @@ config FIREWIRE This is the "Juju" FireWire stack, a new alternative implementation designed for robustness and simplicity. You can build either this stack, or the classic stack (the ieee1394 driver, ohci1394 etc.) - or both. + or both. Please read http://wiki.linux1394.org/JujuMigration before + you enable the new stack. To compile this driver as a module, say M here: the module will be called firewire-core. It functionally replaces ieee1394, raw1394, diff --git a/drivers/firewire/fw-ohci.c b/drivers/firewire/fw-ohci.c index 7e427b4c74b5..e14c1ca7813e 100644 --- a/drivers/firewire/fw-ohci.c +++ b/drivers/firewire/fw-ohci.c @@ -1945,10 +1945,8 @@ static int pci_suspend(struct pci_dev *pdev, pm_message_t state) return err; } err = pci_set_power_state(pdev, pci_choose_state(pdev, state)); - if (err) { - fw_error("pci_set_power_state failed\n"); - return err; - } + if (err) + fw_error("pci_set_power_state failed with %d\n", err); return 0; } diff --git a/drivers/hwmon/lm78.c b/drivers/hwmon/lm78.c index 565c4e679b8d..6eea3476b90c 100644 --- a/drivers/hwmon/lm78.c +++ b/drivers/hwmon/lm78.c @@ -882,7 +882,7 @@ static int __init lm78_isa_device_add(unsigned short address) { struct resource res = { .start = address, - .end = address + LM78_EXTENT, + .end = address + LM78_EXTENT - 1, .name = "lm78", .flags = IORESOURCE_IO, }; diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c index c95909cc1d21..dcc941a5aaff 100644 --- a/drivers/hwmon/w83781d.c +++ b/drivers/hwmon/w83781d.c @@ -1746,7 +1746,7 @@ w83781d_isa_device_add(unsigned short address) { struct resource res = { .start = address, - .end = address + W83781D_EXTENT, + .end = address + W83781D_EXTENT - 1, .name = "w83781d", .flags = IORESOURCE_IO, }; diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c index 8a5f5825bb72..7f0a0a62cf60 100644 --- a/drivers/i2c/algos/i2c-algo-bit.c +++ b/drivers/i2c/algos/i2c-algo-bit.c @@ -357,13 +357,29 @@ static int sendbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) return wrcount; } +static int acknak(struct i2c_adapter *i2c_adap, int is_ack) +{ + struct i2c_algo_bit_data *adap = i2c_adap->algo_data; + + /* assert: sda is high */ + if (is_ack) /* send ack */ + setsda(adap, 0); + udelay((adap->udelay + 1) / 2); + if (sclhi(adap) < 0) { /* timeout */ + dev_err(&i2c_adap->dev, "readbytes: ack/nak timeout\n"); + return -ETIMEDOUT; + } + scllo(adap); + return 0; +} + static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) { int inval; int rdcount=0; /* counts bytes read */ - struct i2c_algo_bit_data *adap = i2c_adap->algo_data; unsigned char *temp = msg->buf; int count = msg->len; + const unsigned flags = msg->flags; while (count > 0) { inval = i2c_inb(i2c_adap); @@ -377,28 +393,12 @@ static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) temp++; count--; - if (msg->flags & I2C_M_NO_RD_ACK) { - bit_dbg(2, &i2c_adap->dev, "i2c_inb: 0x%02x\n", - inval); - continue; - } - - /* assert: sda is high */ - if (count) /* send ack */ - setsda(adap, 0); - udelay((adap->udelay + 1) / 2); - bit_dbg(2, &i2c_adap->dev, "i2c_inb: 0x%02x %s\n", inval, - count ? "A" : "NA"); - if (sclhi(adap)<0) { /* timeout */ - dev_err(&i2c_adap->dev, "readbytes: timeout at ack\n"); - return -ETIMEDOUT; - }; - scllo(adap); - /* Some SMBus transactions require that we receive the transaction length as the first read byte. */ - if (rdcount == 1 && (msg->flags & I2C_M_RECV_LEN)) { + if (rdcount == 1 && (flags & I2C_M_RECV_LEN)) { if (inval <= 0 || inval > I2C_SMBUS_BLOCK_MAX) { + if (!(flags & I2C_M_NO_RD_ACK)) + acknak(i2c_adap, 0); dev_err(&i2c_adap->dev, "readbytes: invalid " "block length (%d)\n", inval); return -EREMOTEIO; @@ -409,6 +409,18 @@ static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) count += inval; msg->len += inval; } + + bit_dbg(2, &i2c_adap->dev, "readbytes: 0x%02x %s\n", + inval, + (flags & I2C_M_NO_RD_ACK) + ? "(no ack/nak)" + : (count ? "A" : "NA")); + + if (!(flags & I2C_M_NO_RD_ACK)) { + inval = acknak(i2c_adap, count); + if (inval < 0) + return inval; + } } return rdcount; } diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c index 025f19423faf..44e1cd21bb01 100644 --- a/drivers/i2c/busses/i2c-gpio.c +++ b/drivers/i2c/busses/i2c-gpio.c @@ -147,7 +147,7 @@ static int __init i2c_gpio_probe(struct platform_device *pdev) * The reason to do so is to avoid sysfs names that only make * sense when there are multiple adapters. */ - adap->nr = pdev->id >= 0 ? pdev->id : 0; + adap->nr = (pdev->id != -1) ? pdev->id : 0; ret = i2c_bit_add_numbered_bus(adap); if (ret) goto err_add_bus; diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index 9d6b790d4321..bb5466b27b59 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -926,7 +926,7 @@ static int i2c_pxa_probe(struct platform_device *dev) * The reason to do so is to avoid sysfs names that only make * sense when there are multiple adapters. */ - i2c->adap.nr = dev->id >= 0 ? dev->id : 0; + i2c->adap.nr = dev->id != -1 ? dev->id : 0; ret = i2c_add_numbered_adapter(&i2c->adap); if (ret < 0) { diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig index 7adb61bad6ad..4200251ff635 100644 --- a/drivers/ide/Kconfig +++ b/drivers/ide/Kconfig @@ -781,7 +781,7 @@ endif config BLK_DEV_IDE_PMAC bool "Builtin PowerMac IDE support" - depends on PPC_PMAC && IDE=y + depends on PPC_PMAC && IDE=y && BLK_DEV_IDE=y help This driver provides support for the built-in IDE controller on most of the recent Apple Power Macintoshes and PowerBooks. @@ -946,7 +946,7 @@ config BLK_DEV_Q40IDE config BLK_DEV_MPC8xx_IDE bool "MPC8xx IDE support" - depends on 8xx && IDE=y && BLK_DEV_IDE=y + depends on 8xx && IDE=y && BLK_DEV_IDE=y && !PPC_MERGE select IDE_GENERIC help This option provides support for IDE on Motorola MPC8xx Systems. diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c index eba1adbc1b6a..4754769eda97 100644 --- a/drivers/ide/ide-disk.c +++ b/drivers/ide/ide-disk.c @@ -487,6 +487,7 @@ static inline int idedisk_supports_lba48(const struct hd_driveid *id) */ static const struct drive_list_entry hpa_list[] = { { "ST340823A", NULL }, + { "ST320413A", NULL }, { NULL, NULL } }; diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c index f4cd2700cae5..646a54e233d3 100644 --- a/drivers/ide/ide-iops.c +++ b/drivers/ide/ide-iops.c @@ -615,8 +615,7 @@ u8 eighty_ninty_three (ide_drive_t *drive) if (hwif->cbl != ATA_CBL_PATA80 && !ivb) goto no_80w; - /* Check for SATA but only if we are ATA5 or higher */ - if (id->hw_config == 0 && (id->major_rev_num & 0x7FE0)) + if (ide_dev_is_sata(id)) return 1; /* diff --git a/drivers/ide/pci/alim15x3.c b/drivers/ide/pci/alim15x3.c index 025689de50e9..11ecb618007c 100644 --- a/drivers/ide/pci/alim15x3.c +++ b/drivers/ide/pci/alim15x3.c @@ -596,6 +596,13 @@ static struct dmi_system_id cable_dmi_table[] = { DMI_MATCH(DMI_BOARD_VERSION, "OmniBook N32N-736"), }, }, + { + .ident = "Toshiba Satellite S1800-814", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), + DMI_MATCH(DMI_PRODUCT_NAME, "S1800-814"), + }, + }, { } }; diff --git a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c index 2cd74c345a6c..39f1c89f7c86 100644 --- a/drivers/ide/pci/hpt366.c +++ b/drivers/ide/pci/hpt366.c @@ -1,5 +1,5 @@ /* - * linux/drivers/ide/pci/hpt366.c Version 1.10 Jun 29, 2007 + * linux/drivers/ide/pci/hpt366.c Version 1.12 Aug 19, 2007 * * Copyright (C) 1999-2003 Andre Hedrick <andre@linux-ide.org> * Portions Copyright (C) 2001 Sun Microsystems, Inc. @@ -68,7 +68,8 @@ * HPT37x chip family; save space by introducing the separate transfer mode * table in which the mode lookup is done * - use f_CNT value saved by the HighPoint BIOS as reading it directly gives - * the wrong PCI frequency since DPLL has already been calibrated by BIOS + * the wrong PCI frequency since DPLL has already been calibrated by BIOS; + * read it only from the function 0 of HPT374 chips * - fix the hotswap code: it caused RESET- to glitch when tristating the bus, * and for HPT36x the obsolete HDIO_TRISTATE_HWIF handler was called instead * - pass to init_chipset() handlers a copy of the IDE PCI device structure as @@ -113,6 +114,7 @@ * unify HPT36x/37x timing setup code and the speedproc handlers by joining * the register setting lists into the table indexed by the clock selected * - set the correct hwif->ultra_mask for each individual chip + * - add UltraDMA mode filtering for the HPT37[24] based SATA cards * Sergei Shtylyov, <sshtylyov@ru.mvista.com> or <source@mvista.com> */ @@ -517,42 +519,44 @@ static int check_in_drive_list(ide_drive_t *drive, const char **list) } /* - * Note for the future; the SATA hpt37x we must set - * either PIO or UDMA modes 0,4,5 + * The Marvell bridge chips used on the HighPoint SATA cards do not seem + * to support the UltraDMA modes 1, 2, and 3 as well as any MWDMA modes... */ static u8 hpt3xx_udma_filter(ide_drive_t *drive) { - struct hpt_info *info = pci_get_drvdata(HWIF(drive)->pci_dev); - u8 mask; + ide_hwif_t *hwif = HWIF(drive); + struct hpt_info *info = pci_get_drvdata(hwif->pci_dev); + u8 mask = hwif->ultra_mask; switch (info->chip_type) { - case HPT370A: - if (!HPT370_ALLOW_ATA100_5 || - check_in_drive_list(drive, bad_ata100_5)) - return 0x1f; - else - return 0x3f; - case HPT370: - if (!HPT370_ALLOW_ATA100_5 || - check_in_drive_list(drive, bad_ata100_5)) - mask = 0x1f; - else - mask = 0x3f; - break; case HPT36x: if (!HPT366_ALLOW_ATA66_4 || check_in_drive_list(drive, bad_ata66_4)) - mask = 0x0f; - else - mask = 0x1f; + mask = ATA_UDMA3; if (!HPT366_ALLOW_ATA66_3 || check_in_drive_list(drive, bad_ata66_3)) - mask = 0x07; + mask = ATA_UDMA2; + break; + case HPT370: + if (!HPT370_ALLOW_ATA100_5 || + check_in_drive_list(drive, bad_ata100_5)) + mask = ATA_UDMA4; break; + case HPT370A: + if (!HPT370_ALLOW_ATA100_5 || + check_in_drive_list(drive, bad_ata100_5)) + return ATA_UDMA4; + case HPT372 : + case HPT372A: + case HPT372N: + case HPT374 : + if (ide_dev_is_sata(drive->id)) + mask &= ~0x0e; + /* Fall thru */ default: - return 0x7f; + return mask; } return check_in_drive_list(drive, bad_ata33) ? 0x00 : mask; @@ -981,6 +985,7 @@ static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const cha struct hpt_info *info = kmalloc(sizeof(struct hpt_info), GFP_KERNEL); unsigned long io_base = pci_resource_start(dev, 4); u8 pci_clk, dpll_clk = 0; /* PCI and DPLL clock in MHz */ + u8 chip_type; enum ata_clock clock; if (info == NULL) { @@ -992,7 +997,8 @@ static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const cha * Copy everything from a static "template" structure * to just allocated per-chip hpt_info structure. */ - *info = *(struct hpt_info *)pci_get_drvdata(dev); + memcpy(info, pci_get_drvdata(dev), sizeof(struct hpt_info)); + chip_type = info->chip_type; pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4)); pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78); @@ -1002,7 +1008,7 @@ static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const cha /* * First, try to estimate the PCI clock frequency... */ - if (info->chip_type >= HPT370) { + if (chip_type >= HPT370) { u8 scr1 = 0; u16 f_cnt = 0; u32 temp = 0; @@ -1016,7 +1022,7 @@ static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const cha * HighPoint does this for HPT372A. * NOTE: This register is only writeable via I/O space. */ - if (info->chip_type == HPT372A) + if (chip_type == HPT372A) outb(0x0e, io_base + 0x9c); /* @@ -1034,13 +1040,28 @@ static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const cha * First try reading the register in which the HighPoint BIOS * saves f_CNT value before reprogramming the DPLL from its * default setting (which differs for the various chips). - * NOTE: This register is only accessible via I/O space. * - * In case the signature check fails, we'll have to resort to - * reading the f_CNT register itself in hopes that nobody has - * touched the DPLL yet... + * NOTE: This register is only accessible via I/O space; + * HPT374 BIOS only saves it for the function 0, so we have to + * always read it from there -- no need to check the result of + * pci_get_slot() for the function 0 as the whole device has + * been already "pinned" (via function 1) in init_setup_hpt374() + */ + if (chip_type == HPT374 && (PCI_FUNC(dev->devfn) & 1)) { + struct pci_dev *dev1 = pci_get_slot(dev->bus, + dev->devfn - 1); + unsigned long io_base = pci_resource_start(dev1, 4); + + temp = inl(io_base + 0x90); + pci_dev_put(dev1); + } else + temp = inl(io_base + 0x90); + + /* + * In case the signature check fails, we'll have to + * resort to reading the f_CNT register itself in hopes + * that nobody has touched the DPLL yet... */ - temp = inl(io_base + 0x90); if ((temp & 0xFFFFF000) != 0xABCDE000) { int i; @@ -1120,7 +1141,7 @@ static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const cha * We also don't like using the DPLL because this causes glitches * on PRST-/SRST- when the state engine gets reset... */ - if (info->chip_type >= HPT374 || info->settings[clock] == NULL) { + if (chip_type >= HPT374 || info->settings[clock] == NULL) { u16 f_low, delta = pci_clk < 50 ? 2 : 4; int adjust; @@ -1190,7 +1211,7 @@ static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const cha /* Point to this chip's own instance of the hpt_info structure. */ pci_set_drvdata(dev, info); - if (info->chip_type >= HPT370) { + if (chip_type >= HPT370) { u8 mcr1, mcr4; /* @@ -1209,7 +1230,7 @@ static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const cha * the MISC. register to stretch the UltraDMA Tss timing. * NOTE: This register is only writeable via I/O space. */ - if (info->chip_type == HPT371N && clock == ATA_CLOCK_66MHZ) + if (chip_type == HPT371N && clock == ATA_CLOCK_66MHZ) outb(inb(io_base + 0x9c) | 0x04, io_base + 0x9c); @@ -1218,25 +1239,24 @@ static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const cha static void __devinit init_hwif_hpt366(ide_hwif_t *hwif) { - struct pci_dev *dev = hwif->pci_dev; - struct hpt_info *info = pci_get_drvdata(dev); - int serialize = HPT_SERIALIZE_IO; - u8 scr1 = 0, ata66 = hwif->channel ? 0x01 : 0x02; - u8 chip_type = info->chip_type; - u8 new_mcr, old_mcr = 0; + struct pci_dev *dev = hwif->pci_dev; + struct hpt_info *info = pci_get_drvdata(dev); + int serialize = HPT_SERIALIZE_IO; + u8 scr1 = 0, ata66 = hwif->channel ? 0x01 : 0x02; + u8 chip_type = info->chip_type; + u8 new_mcr, old_mcr = 0; /* Cache the channel's MISC. control registers' offset */ - hwif->select_data = hwif->channel ? 0x54 : 0x50; + hwif->select_data = hwif->channel ? 0x54 : 0x50; - hwif->tuneproc = &hpt3xx_tune_drive; - hwif->speedproc = &hpt3xx_tune_chipset; - hwif->quirkproc = &hpt3xx_quirkproc; - hwif->intrproc = &hpt3xx_intrproc; - hwif->maskproc = &hpt3xx_maskproc; - hwif->busproc = &hpt3xx_busproc; + hwif->tuneproc = &hpt3xx_tune_drive; + hwif->speedproc = &hpt3xx_tune_chipset; + hwif->quirkproc = &hpt3xx_quirkproc; + hwif->intrproc = &hpt3xx_intrproc; + hwif->maskproc = &hpt3xx_maskproc; + hwif->busproc = &hpt3xx_busproc; - if (chip_type <= HPT370A) - hwif->udma_filter = &hpt3xx_udma_filter; + hwif->udma_filter = &hpt3xx_udma_filter; /* * HPT3xxN chips have some complications: @@ -1486,19 +1506,19 @@ static int __devinit init_setup_hpt366(struct pci_dev *dev, ide_pci_device_t *d) d->host_flags |= IDE_HFLAG_SINGLE; d->enablebits[0].mask = d->enablebits[0].val = 0x10; - d->udma_mask = HPT366_ALLOW_ATA66_3 ? - (HPT366_ALLOW_ATA66_4 ? 0x1f : 0x0f) : 0x07; + d->udma_mask = HPT366_ALLOW_ATA66_3 ? (HPT366_ALLOW_ATA66_4 ? + ATA_UDMA4 : ATA_UDMA3) : ATA_UDMA2; break; case 3: case 4: - d->udma_mask = HPT370_ALLOW_ATA100_5 ? 0x3f : 0x1f; + d->udma_mask = HPT370_ALLOW_ATA100_5 ? ATA_UDMA5 : ATA_UDMA4; break; default: rev = 6; /* fall thru */ case 5: case 6: - d->udma_mask = HPT372_ALLOW_ATA133_6 ? 0x7f : 0x3f; + d->udma_mask = HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5; break; } @@ -1559,7 +1579,7 @@ static ide_pci_device_t hpt366_chipsets[] __devinitdata = { .init_dma = init_dma_hpt366, .autodma = AUTODMA, .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}}, - .udma_mask = HPT372_ALLOW_ATA133_6 ? 0x7f : 0x3f, + .udma_mask = HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5, .bootable = OFF_BOARD, .extra = 240, .pio_mask = ATA_PIO4, @@ -1571,7 +1591,7 @@ static ide_pci_device_t hpt366_chipsets[] __devinitdata = { .init_dma = init_dma_hpt366, .autodma = AUTODMA, .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}}, - .udma_mask = HPT302_ALLOW_ATA133_6 ? 0x7f : 0x3f, + .udma_mask = HPT302_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5, .bootable = OFF_BOARD, .extra = 240, .pio_mask = ATA_PIO4, @@ -1583,7 +1603,7 @@ static ide_pci_device_t hpt366_chipsets[] __devinitdata = { .init_dma = init_dma_hpt366, .autodma = AUTODMA, .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}}, - .udma_mask = HPT371_ALLOW_ATA133_6 ? 0x7f : 0x3f, + .udma_mask = HPT371_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5, .bootable = OFF_BOARD, .extra = 240, .pio_mask = ATA_PIO4, @@ -1595,7 +1615,7 @@ static ide_pci_device_t hpt366_chipsets[] __devinitdata = { .init_dma = init_dma_hpt366, .autodma = AUTODMA, .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}}, - .udma_mask = 0x3f, + .udma_mask = ATA_UDMA5, .bootable = OFF_BOARD, .extra = 240, .pio_mask = ATA_PIO4, @@ -1607,7 +1627,7 @@ static ide_pci_device_t hpt366_chipsets[] __devinitdata = { .init_dma = init_dma_hpt366, .autodma = AUTODMA, .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}}, - .udma_mask = HPT372_ALLOW_ATA133_6 ? 0x7f : 0x3f, + .udma_mask = HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5, .bootable = OFF_BOARD, .extra = 240, .pio_mask = ATA_PIO4, diff --git a/drivers/ide/pci/pdc202xx_new.c b/drivers/ide/pci/pdc202xx_new.c index f6db2f37efad..7b0e479c355c 100644 --- a/drivers/ide/pci/pdc202xx_new.c +++ b/drivers/ide/pci/pdc202xx_new.c @@ -9,7 +9,7 @@ * Split from: * linux/drivers/ide/pdc202xx.c Version 0.35 Mar. 30, 2002 * Copyright (C) 1998-2002 Andre Hedrick <andre@linux-ide.org> - * Copyright (C) 2005-2006 MontaVista Software, Inc. + * Copyright (C) 2005-2007 MontaVista Software, Inc. * Portions Copyright (C) 1999 Promise Technology, Inc. * Author: Frank Tiernan (frankt@promise.com) * Released under terms of General Public License @@ -341,7 +341,7 @@ static long __devinit detect_pll_input_clock(unsigned long dma_base) */ usec_elapsed = (end_time.tv_sec - start_time.tv_sec) * 1000000 + (end_time.tv_usec - start_time.tv_usec); - pll_input = ((start_count - end_count) & 0x3ffffff) / 10 * + pll_input = ((start_count - end_count) & 0x3fffffff) / 10 * (10000000 / usec_elapsed); DBG("start[%ld] end[%ld]\n", start_count, end_count); @@ -535,7 +535,7 @@ static int __devinit init_setup_pdc20270(struct pci_dev *dev, (dev->bus->self->device == PCI_DEVICE_ID_DEC_21150)) { if (PCI_SLOT(dev->devfn) & 2) return -ENODEV; - d->extra = 0; + while ((findev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, findev)) != NULL) { if ((findev->vendor == dev->vendor) && (findev->device == dev->device) && @@ -544,7 +544,8 @@ static int __devinit init_setup_pdc20270(struct pci_dev *dev, findev->irq = dev->irq; } ret = ide_setup_pci_devices(dev, findev, d); - pci_dev_put(findev); + if (ret < 0) + pci_dev_put(findev); return ret; } } diff --git a/drivers/ide/pci/via82cxxx.c b/drivers/ide/pci/via82cxxx.c index 581316f9581d..a7be7795e6af 100644 --- a/drivers/ide/pci/via82cxxx.c +++ b/drivers/ide/pci/via82cxxx.c @@ -1,6 +1,6 @@ /* * - * Version 3.46 + * Version 3.47 * * VIA IDE driver for Linux. Supported southbridges: * @@ -74,6 +74,7 @@ static struct via_isa_bridge { u8 udma_mask; u8 flags; } via_isa_bridges[] = { + { "vx800", PCI_DEVICE_ID_VIA_VX800, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST }, { "cx700", PCI_DEVICE_ID_VIA_CX700, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST }, { "vt8237s", PCI_DEVICE_ID_VIA_8237S, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST }, { "vt6410", PCI_DEVICE_ID_VIA_6410, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST }, @@ -429,19 +430,26 @@ static struct dmi_system_id cable_dmi_table[] = { { } }; -static int via_cable_override(void) +static int via_cable_override(struct pci_dev *pdev) { /* Systems by DMI */ if (dmi_check_system(cable_dmi_table)) return 1; + + /* Arima W730-K8/Targa Visionary 811/... */ + if (pdev->subsystem_vendor == 0x161F && + pdev->subsystem_device == 0x2032) + return 1; + return 0; } static u8 __devinit via82cxxx_cable_detect(ide_hwif_t *hwif) { - struct via82cxxx_dev *vdev = pci_get_drvdata(hwif->pci_dev); + struct pci_dev *pdev = hwif->pci_dev; + struct via82cxxx_dev *vdev = pci_get_drvdata(pdev); - if (via_cable_override()) + if (via_cable_override(pdev)) return ATA_CBL_PATA40_SHORT; if ((vdev->via_80w >> hwif->channel) & 1) diff --git a/drivers/ide/ppc/mpc8xx.c b/drivers/ide/ppc/mpc8xx.c index 8859fe2f5ac2..dab79afa9b22 100644 --- a/drivers/ide/ppc/mpc8xx.c +++ b/drivers/ide/ppc/mpc8xx.c @@ -32,7 +32,6 @@ #include <asm/mpc8xx.h> #include <asm/mmu.h> #include <asm/processor.h> -#include <asm/residual.h> #include <asm/io.h> #include <asm/pgtable.h> #include <asm/ide.h> diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c index 4b13cd9a027d..2fb047b898aa 100644 --- a/drivers/ide/ppc/pmac.c +++ b/drivers/ide/ppc/pmac.c @@ -1546,6 +1546,7 @@ static struct pci_device_id pmac_ide_pci_match[] = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_IPID2_ATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {}, }; static struct pci_driver pmac_ide_pci_driver = { @@ -1802,9 +1803,7 @@ pmac_ide_dma_check(ide_drive_t *drive) { struct hd_driveid *id = drive->id; ide_hwif_t *hwif = HWIF(drive); - pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)hwif->hwif_data; int enable = 1; - int map; drive->using_dma = 0; if (drive->media == ide_floppy) diff --git a/drivers/ide/setup-pci.c b/drivers/ide/setup-pci.c index 30e596c0f120..1129f8c30840 100644 --- a/drivers/ide/setup-pci.c +++ b/drivers/ide/setup-pci.c @@ -816,19 +816,15 @@ static int __init ide_scan_pcidev(struct pci_dev *dev) struct list_head *l; struct pci_driver *d; - list_for_each(l, &ide_pci_drivers) - { + list_for_each(l, &ide_pci_drivers) { d = list_entry(l, struct pci_driver, node); - if(d->id_table) - { - const struct pci_device_id *id = pci_match_id(d->id_table, dev); - if(id != NULL) - { - if(d->probe(dev, id) >= 0) - { - dev->driver = d; - return 1; - } + if (d->id_table) { + const struct pci_device_id *id = pci_match_id(d->id_table, + dev); + if (id != NULL && d->probe(dev, id) >= 0) { + dev->driver = d; + pci_dev_get(dev); + return 1; } } } @@ -851,15 +847,13 @@ void __init ide_scan_pcibus (int scan_direction) struct list_head *l, *n; pre_init = 0; - if (!scan_direction) { - while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { + if (!scan_direction) + while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) ide_scan_pcidev(dev); - } - } else { - while ((dev = pci_get_device_reverse(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { + else + while ((dev = pci_get_device_reverse(PCI_ANY_ID, PCI_ANY_ID, dev)) + != NULL) ide_scan_pcidev(dev); - } - } /* * Hand the drivers over to the PCI layer now we @@ -869,12 +863,9 @@ void __init ide_scan_pcibus (int scan_direction) list_for_each_safe(l, n, &ide_pci_drivers) { list_del(l); d = list_entry(l, struct pci_driver, node); - if (__pci_register_driver(d, d->driver.owner, - d->driver.mod_name)) { - printk(KERN_ERR "%s: failed to register driver " - "for %s\n", __FUNCTION__, - d->driver.mod_name); - } + if (__pci_register_driver(d, d->driver.owner, d->driver.mod_name)) + printk(KERN_ERR "%s: failed to register driver for %s\n", + __FUNCTION__, d->driver.mod_name); } } #endif diff --git a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c index ee45259573c8..98fd985a32ff 100644 --- a/drivers/ieee1394/ieee1394_core.c +++ b/drivers/ieee1394/ieee1394_core.c @@ -1273,7 +1273,7 @@ static void __exit ieee1394_cleanup(void) unregister_chrdev_region(IEEE1394_CORE_DEV, 256); } -fs_initcall(ieee1394_init); /* same as ohci1394 */ +module_init(ieee1394_init); module_exit(ieee1394_cleanup); /* Exported symbols */ diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c index 5667c8102efc..372c5c16eb31 100644 --- a/drivers/ieee1394/ohci1394.c +++ b/drivers/ieee1394/ohci1394.c @@ -3537,7 +3537,5 @@ static int __init ohci1394_init(void) return pci_register_driver(&ohci1394_pci_driver); } -/* Register before most other device drivers. - * Useful for remote debugging via physical DMA, e.g. using firescope. */ -fs_initcall(ohci1394_init); +module_init(ohci1394_init); module_exit(ohci1394_cleanup); diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c index ba0428d872aa..85c51bdc36f1 100644 --- a/drivers/infiniband/hw/mlx4/qp.c +++ b/drivers/infiniband/hw/mlx4/qp.c @@ -1211,12 +1211,42 @@ static void set_datagram_seg(struct mlx4_wqe_datagram_seg *dseg, dseg->qkey = cpu_to_be32(wr->wr.ud.remote_qkey); } -static void set_data_seg(struct mlx4_wqe_data_seg *dseg, - struct ib_sge *sg) +static void set_mlx_icrc_seg(void *dseg) +{ + u32 *t = dseg; + struct mlx4_wqe_inline_seg *iseg = dseg; + + t[1] = 0; + + /* + * Need a barrier here before writing the byte_count field to + * make sure that all the data is visible before the + * byte_count field is set. Otherwise, if the segment begins + * a new cacheline, the HCA prefetcher could grab the 64-byte + * chunk and get a valid (!= * 0xffffffff) byte count but + * stale data, and end up sending the wrong data. + */ + wmb(); + + iseg->byte_count = cpu_to_be32((1 << 31) | 4); +} + +static void set_data_seg(struct mlx4_wqe_data_seg *dseg, struct ib_sge *sg) { - dseg->byte_count = cpu_to_be32(sg->length); dseg->lkey = cpu_to_be32(sg->lkey); dseg->addr = cpu_to_be64(sg->addr); + + /* + * Need a barrier here before writing the byte_count field to + * make sure that all the data is visible before the + * byte_count field is set. Otherwise, if the segment begins + * a new cacheline, the HCA prefetcher could grab the 64-byte + * chunk and get a valid (!= * 0xffffffff) byte count but + * stale data, and end up sending the wrong data. + */ + wmb(); + + dseg->byte_count = cpu_to_be32(sg->length); } int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, @@ -1225,6 +1255,7 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, struct mlx4_ib_qp *qp = to_mqp(ibqp); void *wqe; struct mlx4_wqe_ctrl_seg *ctrl; + struct mlx4_wqe_data_seg *dseg; unsigned long flags; int nreq; int err = 0; @@ -1324,22 +1355,27 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, break; } - for (i = 0; i < wr->num_sge; ++i) { - set_data_seg(wqe, wr->sg_list + i); + /* + * Write data segments in reverse order, so as to + * overwrite cacheline stamp last within each + * cacheline. This avoids issues with WQE + * prefetching. + */ - wqe += sizeof (struct mlx4_wqe_data_seg); - size += sizeof (struct mlx4_wqe_data_seg) / 16; - } + dseg = wqe; + dseg += wr->num_sge - 1; + size += wr->num_sge * (sizeof (struct mlx4_wqe_data_seg) / 16); /* Add one more inline data segment for ICRC for MLX sends */ - if (qp->ibqp.qp_type == IB_QPT_SMI || qp->ibqp.qp_type == IB_QPT_GSI) { - ((struct mlx4_wqe_inline_seg *) wqe)->byte_count = - cpu_to_be32((1 << 31) | 4); - ((u32 *) wqe)[1] = 0; - wqe += sizeof (struct mlx4_wqe_data_seg); + if (unlikely(qp->ibqp.qp_type == IB_QPT_SMI || + qp->ibqp.qp_type == IB_QPT_GSI)) { + set_mlx_icrc_seg(dseg + 1); size += sizeof (struct mlx4_wqe_data_seg) / 16; } + for (i = wr->num_sge - 1; i >= 0; --i, --dseg) + set_data_seg(dseg, wr->sg_list + i); + ctrl->fence_size = (wr->send_flags & IB_SEND_FENCE ? MLX4_WQE_CTRL_FENCE : 0) | size; diff --git a/drivers/input/joystick/Kconfig b/drivers/input/joystick/Kconfig index e2abe18e575d..7c662ee594a3 100644 --- a/drivers/input/joystick/Kconfig +++ b/drivers/input/joystick/Kconfig @@ -277,7 +277,7 @@ config JOYSTICK_XPAD_FF config JOYSTICK_XPAD_LEDS bool "LED Support for Xbox360 controller 'BigX' LED" - depends on LEDS_CLASS && JOYSTICK_XPAD + depends on JOYSTICK_XPAD && (LEDS_CLASS=y || LEDS_CLASS=JOYSTICK_XPAD) ---help--- This option enables support for the LED which surrounds the Big X on XBox 360 controller. diff --git a/drivers/input/mouse/appletouch.c b/drivers/input/mouse/appletouch.c index 2bea1b2c631c..a1804bfdbb8c 100644 --- a/drivers/input/mouse/appletouch.c +++ b/drivers/input/mouse/appletouch.c @@ -328,6 +328,7 @@ static void atp_complete(struct urb* urb) { int x, y, x_z, y_z, x_f, y_f; int retval, i, j; + int key; struct atp *dev = urb->context; switch (urb->status) { @@ -468,6 +469,7 @@ static void atp_complete(struct urb* urb) ATP_XFACT, &x_z, &x_f); y = atp_calculate_abs(dev->xy_acc + ATP_XSENSORS, ATP_YSENSORS, ATP_YFACT, &y_z, &y_f); + key = dev->data[dev->datalen - 1] & 1; if (x && y) { if (dev->x_old != -1) { @@ -505,7 +507,7 @@ static void atp_complete(struct urb* urb) the first touch unless reinitialised. Do so if it's been idle for a while in order to avoid waking the kernel up several hundred times a second */ - if (atp_is_geyser_3(dev)) { + if (!key && atp_is_geyser_3(dev)) { dev->idlecount++; if (dev->idlecount == 10) { dev->valid = 0; @@ -514,7 +516,7 @@ static void atp_complete(struct urb* urb) } } - input_report_key(dev->input, BTN_LEFT, dev->data[dev->datalen - 1] & 1); + input_report_key(dev->input, BTN_LEFT, key); input_sync(dev->input); exit: diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index 702a526cf45b..f8fe42148093 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -211,6 +211,16 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = { }, }, { + /* + * Like DV4017EA does not raise AUXERR for errors on MUX ports. + */ + .ident = "HP Pavilion DV4270ca", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "Pavilion dv4000 (EH476UA#ABL)"), + }, + }, + { .ident = "Toshiba P10", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index 06b05dd22485..c2eea2767e10 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -1040,7 +1040,7 @@ static void __devinit i8042_register_ports(void) } } -static void __devinit i8042_unregister_ports(void) +static void __devexit i8042_unregister_ports(void) { int i; diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c index b407028ffc59..741f6c6f1e50 100644 --- a/drivers/input/touchscreen/usbtouchscreen.c +++ b/drivers/input/touchscreen/usbtouchscreen.c @@ -767,7 +767,7 @@ static int usbtouch_probe(struct usb_interface *intf, le16_to_cpu(udev->descriptor.idProduct)); usb_make_path(udev, usbtouch->phys, sizeof(usbtouch->phys)); - strlcpy(usbtouch->phys, "/input0", sizeof(usbtouch->phys)); + strlcat(usbtouch->phys, "/input0", sizeof(usbtouch->phys)); input_dev->name = usbtouch->name; input_dev->phys = usbtouch->phys; diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c index ec5f4046412f..4910bca52640 100644 --- a/drivers/isdn/i4l/isdn_common.c +++ b/drivers/isdn/i4l/isdn_common.c @@ -1135,7 +1135,7 @@ isdn_read(struct file *file, char __user *buf, size_t count, loff_t * off) if (count > dev->drv[drvidx]->stavail) count = dev->drv[drvidx]->stavail; len = dev->drv[drvidx]->interface->readstat(buf, count, - drvidx, isdn_minor2chan(minor)); + drvidx, isdn_minor2chan(minor - ISDN_MINOR_CTRL)); if (len < 0) { retval = len; goto out; @@ -1207,7 +1207,8 @@ isdn_write(struct file *file, const char __user *buf, size_t count, loff_t * off */ if (dev->drv[drvidx]->interface->writecmd) retval = dev->drv[drvidx]->interface-> - writecmd(buf, count, drvidx, isdn_minor2chan(minor)); + writecmd(buf, count, drvidx, + isdn_minor2chan(minor - ISDN_MINOR_CTRL)); else retval = count; goto out; diff --git a/drivers/kvm/Kconfig b/drivers/kvm/Kconfig index 7b64fd4aa2f3..0a419a0de603 100644 --- a/drivers/kvm/Kconfig +++ b/drivers/kvm/Kconfig @@ -6,7 +6,8 @@ menuconfig VIRTUALIZATION depends on X86 default y ---help--- - Say Y here to get to see options for virtualization guest drivers. + Say Y here to get to see options for using your Linux host to run other + operating systems inside virtual machines (guests). This option alone does not add any kernel code. If you say N, all options in this submenu will be skipped and disabled. diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h index 3ac9cbce3369..336be86c6f5a 100644 --- a/drivers/kvm/kvm.h +++ b/drivers/kvm/kvm.h @@ -619,7 +619,7 @@ unsigned long segment_base(u16 selector); void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa, const u8 *old, const u8 *new, int bytes); int kvm_mmu_unprotect_page_virt(struct kvm_vcpu *vcpu, gva_t gva); -void kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu); +void __kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu); int kvm_mmu_load(struct kvm_vcpu *vcpu); void kvm_mmu_unload(struct kvm_vcpu *vcpu); @@ -628,11 +628,15 @@ int kvm_hypercall(struct kvm_vcpu *vcpu, struct kvm_run *run); static inline int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t gva, u32 error_code) { - if (unlikely(vcpu->kvm->n_free_mmu_pages < KVM_MIN_FREE_MMU_PAGES)) - kvm_mmu_free_some_pages(vcpu); return vcpu->mmu.page_fault(vcpu, gva, error_code); } +static inline void kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu) +{ + if (unlikely(vcpu->kvm->n_free_mmu_pages < KVM_MIN_FREE_MMU_PAGES)) + __kvm_mmu_free_some_pages(vcpu); +} + static inline int kvm_mmu_reload(struct kvm_vcpu *vcpu) { if (likely(vcpu->mmu.root_hpa != INVALID_PAGE)) diff --git a/drivers/kvm/mmu.c b/drivers/kvm/mmu.c index 1a87ba9d5156..23965aa5ee78 100644 --- a/drivers/kvm/mmu.c +++ b/drivers/kvm/mmu.c @@ -273,12 +273,14 @@ static int mmu_topup_memory_caches(struct kvm_vcpu *vcpu) int r; r = __mmu_topup_memory_caches(vcpu, GFP_NOWAIT); + kvm_mmu_free_some_pages(vcpu); if (r < 0) { spin_unlock(&vcpu->kvm->lock); kvm_arch_ops->vcpu_put(vcpu); r = __mmu_topup_memory_caches(vcpu, GFP_KERNEL); kvm_arch_ops->vcpu_load(vcpu); spin_lock(&vcpu->kvm->lock); + kvm_mmu_free_some_pages(vcpu); } return r; } @@ -1208,7 +1210,7 @@ int kvm_mmu_unprotect_page_virt(struct kvm_vcpu *vcpu, gva_t gva) return kvm_mmu_unprotect_page(vcpu, gpa >> PAGE_SHIFT); } -void kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu) +void __kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu) { while (vcpu->kvm->n_free_mmu_pages < KVM_REFILL_PAGES) { struct kvm_mmu_page *page; @@ -1218,7 +1220,6 @@ void kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu) kvm_mmu_zap_page(vcpu->kvm, page); } } -EXPORT_SYMBOL_GPL(kvm_mmu_free_some_pages); static void free_mmu_pages(struct kvm_vcpu *vcpu) { diff --git a/drivers/lguest/lguest.c b/drivers/lguest/lguest.c index 6e135ac0834f..ee1c6d05c3d3 100644 --- a/drivers/lguest/lguest.c +++ b/drivers/lguest/lguest.c @@ -964,11 +964,12 @@ __init void lguest_init(void *boot) { /* Copy boot parameters first: the Launcher put the physical location * in %esi, and head.S converted that to a virtual address and handed - * it to us. */ - memcpy(&boot_params, boot, PARAM_SIZE); + * it to us. We use "__memcpy" because "memcpy" sometimes tries to do + * tricky things to go faster, and we're not ready for that. */ + __memcpy(&boot_params, boot, PARAM_SIZE); /* The boot parameters also tell us where the command-line is: save * that, too. */ - memcpy(boot_command_line, __va(boot_params.hdr.cmd_line_ptr), + __memcpy(boot_command_line, __va(boot_params.hdr.cmd_line_ptr), COMMAND_LINE_SIZE); /* We're under lguest, paravirt is enabled, and we're running at diff --git a/drivers/lguest/lguest_asm.S b/drivers/lguest/lguest_asm.S index f182c6a36209..1ddcd5cd20f6 100644 --- a/drivers/lguest/lguest_asm.S +++ b/drivers/lguest/lguest_asm.S @@ -22,8 +22,9 @@ jmp lguest_init /*G:055 We create a macro which puts the assembler code between lgstart_ and - * lgend_ markers. These templates end up in the .init.text section, so they - * are discarded after boot. */ + * lgend_ markers. These templates are put in the .text section: they can't be + * discarded after boot as we may need to patch modules, too. */ +.text #define LGUEST_PATCH(name, insns...) \ lgstart_##name: insns; lgend_##name:; \ .globl lgstart_##name; .globl lgend_##name @@ -34,7 +35,6 @@ LGUEST_PATCH(popf, movl %eax, lguest_data+LGUEST_DATA_irq_enabled) LGUEST_PATCH(pushf, movl lguest_data+LGUEST_DATA_irq_enabled, %eax) /*:*/ -.text /* These demark the EIP range where host should never deliver interrupts. */ .global lguest_noirq_start .global lguest_noirq_end diff --git a/drivers/md/dm-bio-list.h b/drivers/md/dm-bio-list.h index 16ee3b018b3a..3f7b827649e3 100644 --- a/drivers/md/dm-bio-list.h +++ b/drivers/md/dm-bio-list.h @@ -9,6 +9,8 @@ #include <linux/bio.h> +#ifdef CONFIG_BLOCK + struct bio_list { struct bio *head; struct bio *tail; @@ -106,4 +108,5 @@ static inline struct bio *bio_list_get(struct bio_list *bl) return bio; } +#endif /* CONFIG_BLOCK */ #endif diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 2aff4be35dc4..f96dea975fa5 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -514,7 +514,7 @@ static void ops_complete_biofill(void *stripe_head_ref) struct stripe_head *sh = stripe_head_ref; struct bio *return_bi = NULL; raid5_conf_t *conf = sh->raid_conf; - int i, more_to_read = 0; + int i; pr_debug("%s: stripe %llu\n", __FUNCTION__, (unsigned long long)sh->sector); @@ -522,16 +522,14 @@ static void ops_complete_biofill(void *stripe_head_ref) /* clear completed biofills */ for (i = sh->disks; i--; ) { struct r5dev *dev = &sh->dev[i]; - /* check if this stripe has new incoming reads */ - if (dev->toread) - more_to_read++; /* acknowledge completion of a biofill operation */ - /* and check if we need to reply to a read request - */ - if (test_bit(R5_Wantfill, &dev->flags) && !dev->toread) { + /* and check if we need to reply to a read request, + * new R5_Wantfill requests are held off until + * !test_bit(STRIPE_OP_BIOFILL, &sh->ops.pending) + */ + if (test_and_clear_bit(R5_Wantfill, &dev->flags)) { struct bio *rbi, *rbi2; - clear_bit(R5_Wantfill, &dev->flags); /* The access to dev->read is outside of the * spin_lock_irq(&conf->device_lock), but is protected @@ -558,8 +556,7 @@ static void ops_complete_biofill(void *stripe_head_ref) return_io(return_bi); - if (more_to_read) - set_bit(STRIPE_HANDLE, &sh->state); + set_bit(STRIPE_HANDLE, &sh->state); release_stripe(sh); } @@ -2541,7 +2538,7 @@ static void handle_stripe_expansion(raid5_conf_t *conf, struct stripe_head *sh, struct dma_async_tx_descriptor *tx = NULL; clear_bit(STRIPE_EXPAND_SOURCE, &sh->state); for (i = 0; i < sh->disks; i++) - if (i != sh->pd_idx && (r6s && i != r6s->qd_idx)) { + if (i != sh->pd_idx && (!r6s || i != r6s->qd_idx)) { int dd_idx, pd_idx, j; struct stripe_head *sh2; @@ -2574,7 +2571,8 @@ static void handle_stripe_expansion(raid5_conf_t *conf, struct stripe_head *sh, set_bit(R5_UPTODATE, &sh2->dev[dd_idx].flags); for (j = 0; j < conf->raid_disks; j++) if (j != sh2->pd_idx && - (r6s && j != r6s->qd_idx) && + (!r6s || j != raid6_next_disk(sh2->pd_idx, + sh2->disks)) && !test_bit(R5_Expanded, &sh2->dev[j].flags)) break; if (j == conf->raid_disks) { @@ -2583,12 +2581,12 @@ static void handle_stripe_expansion(raid5_conf_t *conf, struct stripe_head *sh, } release_stripe(sh2); - /* done submitting copies, wait for them to complete */ - if (i + 1 >= sh->disks) { - async_tx_ack(tx); - dma_wait_for_async_tx(tx); - } } + /* done submitting copies, wait for them to complete */ + if (tx) { + async_tx_ack(tx); + dma_wait_for_async_tx(tx); + } } /* @@ -2855,7 +2853,7 @@ static void handle_stripe5(struct stripe_head *sh) sh->disks = conf->raid_disks; sh->pd_idx = stripe_to_pdidx(sh->sector, conf, conf->raid_disks); - s.locked += handle_write_operations5(sh, 0, 1); + s.locked += handle_write_operations5(sh, 1, 1); } else if (s.expanded && !test_bit(STRIPE_OP_POSTXOR, &sh->ops.pending)) { clear_bit(STRIPE_EXPAND_READY, &sh->state); diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c index 317a2a3f9cc1..da7a6b591a67 100644 --- a/drivers/media/video/cx88/cx88-mpeg.c +++ b/drivers/media/video/cx88/cx88-mpeg.c @@ -580,7 +580,7 @@ struct cx8802_dev * cx8802_get_device(struct inode *inode) list_for_each(list,&cx8802_devlist) { h = list_entry(list, struct cx8802_dev, devlist); - if (h->mpeg_dev->minor == minor) + if (h->mpeg_dev && h->mpeg_dev->minor == minor) return h; } diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c index 5dd519caf81d..66ea3cbc369c 100644 --- a/drivers/media/video/ivtv/ivtv-fileops.c +++ b/drivers/media/video/ivtv/ivtv-fileops.c @@ -190,7 +190,9 @@ static void ivtv_update_pgm_info(struct ivtv *itv) int idx = (itv->pgm_info_write_idx + i) % itv->pgm_info_num; struct v4l2_enc_idx_entry *e = itv->pgm_info + idx; u32 addr = itv->pgm_info_offset + 4 + idx * 24; - const int mapping[] = { V4L2_ENC_IDX_FRAME_P, V4L2_ENC_IDX_FRAME_I, V4L2_ENC_IDX_FRAME_B, 0 }; + const int mapping[8] = { -1, V4L2_ENC_IDX_FRAME_I, V4L2_ENC_IDX_FRAME_P, -1, + V4L2_ENC_IDX_FRAME_B, -1, -1, -1 }; + // 1=I, 2=P, 4=B e->offset = read_enc(addr + 4) + ((u64)read_enc(addr + 8) << 32); if (e->offset > itv->mpg_data_received) { @@ -199,7 +201,7 @@ static void ivtv_update_pgm_info(struct ivtv *itv) e->offset += itv->vbi_data_inserted; e->length = read_enc(addr); e->pts = read_enc(addr + 16) + ((u64)(read_enc(addr + 20) & 1) << 32); - e->flags = mapping[read_enc(addr + 12) & 3]; + e->flags = mapping[read_enc(addr + 12) & 7]; i++; } itv->pgm_info_write_idx = (itv->pgm_info_write_idx + i) % itv->pgm_info_num; @@ -752,9 +754,11 @@ static void ivtv_stop_decoding(struct ivtv_open_id *id, int flags, u64 pts) ivtv_yuv_close(itv); } if (s->type == IVTV_DEC_STREAM_TYPE_YUV && itv->output_mode == OUT_YUV) - itv->output_mode = OUT_NONE; + itv->output_mode = OUT_NONE; + else if (s->type == IVTV_DEC_STREAM_TYPE_YUV && itv->output_mode == OUT_UDMA_YUV) + itv->output_mode = OUT_NONE; else if (s->type == IVTV_DEC_STREAM_TYPE_MPG && itv->output_mode == OUT_MPG) - itv->output_mode = OUT_NONE; + itv->output_mode = OUT_NONE; itv->speed = 0; clear_bit(IVTV_F_I_DEC_PAUSED, &itv->i_flags); diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index 5977a79619c2..dfe0aedc60fd 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -1099,14 +1099,21 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void case VIDIOC_G_ENC_INDEX: { struct v4l2_enc_idx *idx = arg; + struct v4l2_enc_idx_entry *e = idx->entry; + int entries; int i; - idx->entries = (itv->pgm_info_write_idx + IVTV_MAX_PGM_INDEX - itv->pgm_info_read_idx) % + entries = (itv->pgm_info_write_idx + IVTV_MAX_PGM_INDEX - itv->pgm_info_read_idx) % IVTV_MAX_PGM_INDEX; - if (idx->entries > V4L2_ENC_IDX_ENTRIES) - idx->entries = V4L2_ENC_IDX_ENTRIES; - for (i = 0; i < idx->entries; i++) { - idx->entry[i] = itv->pgm_info[(itv->pgm_info_read_idx + i) % IVTV_MAX_PGM_INDEX]; + if (entries > V4L2_ENC_IDX_ENTRIES) + entries = V4L2_ENC_IDX_ENTRIES; + idx->entries = 0; + for (i = 0; i < entries; i++) { + *e = itv->pgm_info[(itv->pgm_info_read_idx + i) % IVTV_MAX_PGM_INDEX]; + if ((e->flags & V4L2_ENC_IDX_FRAME_MASK) <= V4L2_ENC_IDX_FRAME_B) { + idx->entries++; + e++; + } } itv->pgm_info_read_idx = (itv->pgm_info_read_idx + idx->entries) % IVTV_MAX_PGM_INDEX; break; diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c index 3d81966d8c42..931b274bffca 100644 --- a/drivers/media/video/pwc/pwc-if.c +++ b/drivers/media/video/pwc/pwc-if.c @@ -1243,7 +1243,7 @@ static int pwc_video_close(struct inode *inode, struct file *file) PWC_ERROR("Failed to power down camera (%d)\n", i); } pdev->vopen--; - PWC_DEBUG_OPEN("<< video_close() vopen=%d\n", i); + PWC_DEBUG_OPEN("<< video_close() vopen=%d\n", pdev->vopen); } else { pwc_cleanup(pdev); /* Free memory (don't set pdev to 0 just yet) */ diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 8ec83bd70094..25ec16810818 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -1537,18 +1537,18 @@ struct saa7134_board saa7134_boards[] = { },{ .name = name_comp1, .vmux = 0, - .amux = LINE2, - .gpio = 0x00, + .amux = LINE1, + .gpio = 0x02, },{ .name = name_comp2, .vmux = 3, - .amux = LINE2, - .gpio = 0x00, + .amux = LINE1, + .gpio = 0x02, },{ .name = name_svideo, .vmux = 8, - .amux = LINE2, - .gpio = 0x00, + .amux = LINE1, + .gpio = 0x02, }}, .radio = { .name = name_radio, diff --git a/drivers/media/video/saa7191.c b/drivers/media/video/saa7191.c index 8615a6081a5d..b4018cce3285 100644 --- a/drivers/media/video/saa7191.c +++ b/drivers/media/video/saa7191.c @@ -130,7 +130,7 @@ static int saa7191_write_reg(struct i2c_client *client, u8 reg, /* the first byte of data must be the first subaddress number (register) */ static int saa7191_write_block(struct i2c_client *client, - u8 length, u8 *data) + u8 length, const u8 *data) { int i; int ret; @@ -592,7 +592,7 @@ static int saa7191_attach(struct i2c_adapter *adap, int addr, int kind) if (err) goto out_free_decoder; - err = saa7191_write_block(client, sizeof(initseq), (u8 *)initseq); + err = saa7191_write_block(client, sizeof(initseq), initseq); if (err) { printk(KERN_ERR "SAA7191 initialization failed\n"); goto out_detach_client; diff --git a/drivers/media/video/usbvision/usbvision-cards.c b/drivers/media/video/usbvision/usbvision-cards.c index 380564cd3317..f09eb102731b 100644 --- a/drivers/media/video/usbvision/usbvision-cards.c +++ b/drivers/media/video/usbvision/usbvision-cards.c @@ -1081,6 +1081,7 @@ struct usb_device_id usbvision_table [] = { { USB_DEVICE(0x2304, 0x0301), .driver_info=PINNA_LINX_VD_IN_CAB_PAL }, { USB_DEVICE(0x2304, 0x0419), .driver_info=PINNA_PCTV_BUNGEE_PAL_FM }, { USB_DEVICE(0x2400, 0x4200), .driver_info=HPG_WINTV }, + { }, /* terminate list */ }; MODULE_DEVICE_TABLE (usb, usbvision_table); diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c index e3371f972240..0cb006f2943d 100644 --- a/drivers/media/video/usbvision/usbvision-video.c +++ b/drivers/media/video/usbvision/usbvision-video.c @@ -1387,7 +1387,6 @@ static const struct file_operations usbvision_fops = { .ioctl = video_ioctl2, .llseek = no_llseek, /* .poll = video_poll, */ - .mmap = usbvision_v4l2_mmap, .compat_ioctl = v4l_compat_ioctl32, }; static struct video_device usbvision_video_template = { @@ -1413,7 +1412,7 @@ static struct video_device usbvision_video_template = { .vidioc_s_input = vidioc_s_input, .vidioc_queryctrl = vidioc_queryctrl, .vidioc_g_audio = vidioc_g_audio, - .vidioc_g_audio = vidioc_s_audio, + .vidioc_s_audio = vidioc_s_audio, .vidioc_g_ctrl = vidioc_g_ctrl, .vidioc_s_ctrl = vidioc_s_ctrl, .vidioc_streamon = vidioc_streamon, @@ -1459,7 +1458,7 @@ static struct video_device usbvision_radio_template= .vidioc_s_input = vidioc_s_input, .vidioc_queryctrl = vidioc_queryctrl, .vidioc_g_audio = vidioc_g_audio, - .vidioc_g_audio = vidioc_s_audio, + .vidioc_s_audio = vidioc_s_audio, .vidioc_g_ctrl = vidioc_g_ctrl, .vidioc_s_ctrl = vidioc_s_ctrl, .vidioc_g_tuner = vidioc_g_tuner, diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index a26655881e6a..e0a1ff927a5b 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -111,6 +111,21 @@ config ASUS_LAPTOP If you have an ACPI-compatible ASUS laptop, say Y or M here. +config FUJITSU_LAPTOP + tristate "Fujitsu Laptop Extras" + depends on X86 + depends on ACPI + depends on BACKLIGHT_CLASS_DEVICE + ---help--- + This is a driver for laptops built by Fujitsu: + + * P2xxx/P5xxx/S6xxx/S7xxx series Lifebooks + * Possibly other Fujitsu laptop models + + It adds support for LCD brightness control. + + If you have a Fujitsu laptop, say Y or M here. + config MSI_LAPTOP tristate "MSI Laptop Extras" depends on X86 @@ -134,6 +149,7 @@ config SONY_LAPTOP tristate "Sony Laptop Extras" depends on X86 && ACPI select BACKLIGHT_CLASS_DEVICE + depends on INPUT ---help--- This mini-driver drives the SNC and SPIC devices present in the ACPI BIOS of the Sony Vaio laptops. @@ -156,6 +172,7 @@ config THINKPAD_ACPI select BACKLIGHT_CLASS_DEVICE select HWMON select NVRAM + depends on INPUT ---help--- This is a driver for the IBM and Lenovo ThinkPad laptops. It adds support for Fn-Fx key combinations, Bluetooth control, video @@ -202,25 +219,5 @@ config THINKPAD_ACPI_BAY If you are not sure, say Y here. -config THINKPAD_ACPI_INPUT_ENABLED - bool "Enable input layer support by default" - depends on THINKPAD_ACPI - default n - ---help--- - This option enables thinkpad-acpi hot key handling over the input - layer at driver load time. When it is unset, the driver does not - enable hot key handling by default, and also starts up with a mostly - empty keymap. - - This option should be enabled if you have a new enough HAL or other - userspace support that properly handles the thinkpad-acpi event - device. It auto-tunes the hot key support to those reported by the - firmware and enables it automatically. - - If unsure, say N here to retain the old behaviour of ibm-acpi, and - thinkpad-acpi up to kernel 2.6.21: userspace will have to enable and - set up the thinkpad-acpi hot key handling using the sysfs interace - after loading the driver. - endif # MISC_DEVICES diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index b5ce0e3dba86..be90d483d2f9 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -14,4 +14,5 @@ obj-$(CONFIG_PHANTOM) += phantom.o obj-$(CONFIG_SGI_IOC4) += ioc4.o obj-$(CONFIG_SONY_LAPTOP) += sony-laptop.o obj-$(CONFIG_THINKPAD_ACPI) += thinkpad_acpi.o +obj-$(CONFIG_FUJITSU_LAPTOP) += fujitsu-laptop.o obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o diff --git a/drivers/misc/fujitsu-laptop.c b/drivers/misc/fujitsu-laptop.c new file mode 100644 index 000000000000..d366a6cc1fd9 --- /dev/null +++ b/drivers/misc/fujitsu-laptop.c @@ -0,0 +1,358 @@ +/*-*-linux-c-*-*/ + +/* + Copyright (C) 2007 Jonathan Woithe <jwoithe@physics.adelaide.edu.au> + Based on earlier work: + Copyright (C) 2003 Shane Spencer <shane@bogomip.com> + Adrian Yee <brewt-fujitsu@brewt.org> + + Templated from msi-laptop.c which is copyright by its respective authors. + + 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., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. + */ + +/* + * fujitsu-laptop.c - Fujitsu laptop support, providing access to additional + * features made available on a range of Fujitsu laptops including the + * P2xxx/P5xxx/S6xxx/S7xxx series. + * + * This driver exports a few files in /sys/devices/platform/fujitsu-laptop/; + * others may be added at a later date. + * + * lcd_level - Screen brightness: contains a single integer in the + * range 0..7. (rw) + * + * In addition to these platform device attributes the driver + * registers itself in the Linux backlight control subsystem and is + * available to userspace under /sys/class/backlight/fujitsu-laptop/. + * + * This driver has been tested on a Fujitsu Lifebook S7020. It should + * work on most P-series and S-series Lifebooks, but YMMV. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/acpi.h> +#include <linux/dmi.h> +#include <linux/backlight.h> +#include <linux/platform_device.h> +#include <linux/autoconf.h> + +#define FUJITSU_DRIVER_VERSION "0.3" + +#define FUJITSU_LCD_N_LEVELS 8 + +#define ACPI_FUJITSU_CLASS "fujitsu" +#define ACPI_FUJITSU_HID "FUJ02B1" +#define ACPI_FUJITSU_DRIVER_NAME "Fujitsu laptop FUJ02B1 ACPI extras driver" +#define ACPI_FUJITSU_DEVICE_NAME "Fujitsu FUJ02B1" + +struct fujitsu_t { + acpi_handle acpi_handle; + struct backlight_device *bl_device; + struct platform_device *pf_device; + + unsigned long fuj02b1_state; + unsigned int brightness_changed; + unsigned int brightness_level; +}; + +static struct fujitsu_t *fujitsu; + +/* Hardware access */ + +static int set_lcd_level(int level) +{ + acpi_status status = AE_OK; + union acpi_object arg0 = { ACPI_TYPE_INTEGER }; + struct acpi_object_list arg_list = { 1, &arg0 }; + acpi_handle handle = NULL; + + if (level < 0 || level >= FUJITSU_LCD_N_LEVELS) + return -EINVAL; + + if (!fujitsu) + return -EINVAL; + + status = acpi_get_handle(fujitsu->acpi_handle, "SBLL", &handle); + if (ACPI_FAILURE(status)) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "SBLL not present\n")); + return -ENODEV; + } + + arg0.integer.value = level; + + status = acpi_evaluate_object(handle, NULL, &arg_list, NULL); + if (ACPI_FAILURE(status)) + return -ENODEV; + + return 0; +} + +static int get_lcd_level(void) +{ + unsigned long state = 0; + acpi_status status = AE_OK; + + // Get the Brightness + status = + acpi_evaluate_integer(fujitsu->acpi_handle, "GBLL", NULL, &state); + if (status < 0) + return status; + + fujitsu->fuj02b1_state = state; + fujitsu->brightness_level = state & 0x0fffffff; + + if (state & 0x80000000) + fujitsu->brightness_changed = 1; + else + fujitsu->brightness_changed = 0; + + if (status < 0) + return status; + + return fujitsu->brightness_level; +} + +/* Backlight device stuff */ + +static int bl_get_brightness(struct backlight_device *b) +{ + return get_lcd_level(); +} + +static int bl_update_status(struct backlight_device *b) +{ + return set_lcd_level(b->props.brightness); +} + +static struct backlight_ops fujitsubl_ops = { + .get_brightness = bl_get_brightness, + .update_status = bl_update_status, +}; + +/* Platform device */ + +static ssize_t show_lcd_level(struct device *dev, + struct device_attribute *attr, char *buf) +{ + + int ret; + + ret = get_lcd_level(); + if (ret < 0) + return ret; + + return sprintf(buf, "%i\n", ret); +} + +static ssize_t store_lcd_level(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + + int level, ret; + + if (sscanf(buf, "%i", &level) != 1 + || (level < 0 || level >= FUJITSU_LCD_N_LEVELS)) + return -EINVAL; + + ret = set_lcd_level(level); + if (ret < 0) + return ret; + + return count; +} + +static DEVICE_ATTR(lcd_level, 0644, show_lcd_level, store_lcd_level); + +static struct attribute *fujitsupf_attributes[] = { + &dev_attr_lcd_level.attr, + NULL +}; + +static struct attribute_group fujitsupf_attribute_group = { + .attrs = fujitsupf_attributes +}; + +static struct platform_driver fujitsupf_driver = { + .driver = { + .name = "fujitsu-laptop", + .owner = THIS_MODULE, + } +}; + +/* ACPI device */ + +int acpi_fujitsu_add(struct acpi_device *device) +{ + int result = 0; + int state = 0; + + ACPI_FUNCTION_TRACE("acpi_fujitsu_add"); + + if (!device) + return -EINVAL; + + fujitsu->acpi_handle = device->handle; + sprintf(acpi_device_name(device), "%s", ACPI_FUJITSU_DEVICE_NAME); + sprintf(acpi_device_class(device), "%s", ACPI_FUJITSU_CLASS); + acpi_driver_data(device) = fujitsu; + + result = acpi_bus_get_power(fujitsu->acpi_handle, &state); + if (result) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Error reading power state\n")); + goto end; + } + + printk(KERN_INFO PREFIX "%s [%s] (%s)\n", + acpi_device_name(device), acpi_device_bid(device), + !device->power.state ? "on" : "off"); + + end: + + return result; +} + +int acpi_fujitsu_remove(struct acpi_device *device, int type) +{ + ACPI_FUNCTION_TRACE("acpi_fujitsu_remove"); + + if (!device || !acpi_driver_data(device)) + return -EINVAL; + fujitsu->acpi_handle = 0; + + return 0; +} + +static const struct acpi_device_id fujitsu_device_ids[] = { + {ACPI_FUJITSU_HID, 0}, + {"", 0}, +}; + +static struct acpi_driver acpi_fujitsu_driver = { + .name = ACPI_FUJITSU_DRIVER_NAME, + .class = ACPI_FUJITSU_CLASS, + .ids = fujitsu_device_ids, + .ops = { + .add = acpi_fujitsu_add, + .remove = acpi_fujitsu_remove, + }, +}; + +/* Initialization */ + +static int __init fujitsu_init(void) +{ + int ret, result; + + if (acpi_disabled) + return -ENODEV; + + fujitsu = kmalloc(sizeof(struct fujitsu_t), GFP_KERNEL); + if (!fujitsu) + return -ENOMEM; + memset(fujitsu, 0, sizeof(struct fujitsu_t)); + + result = acpi_bus_register_driver(&acpi_fujitsu_driver); + if (result < 0) { + ret = -ENODEV; + goto fail_acpi; + } + + /* Register backlight stuff */ + + fujitsu->bl_device = + backlight_device_register("fujitsu-laptop", NULL, NULL, + &fujitsubl_ops); + if (IS_ERR(fujitsu->bl_device)) + return PTR_ERR(fujitsu->bl_device); + + fujitsu->bl_device->props.max_brightness = FUJITSU_LCD_N_LEVELS - 1; + ret = platform_driver_register(&fujitsupf_driver); + if (ret) + goto fail_backlight; + + /* Register platform stuff */ + + fujitsu->pf_device = platform_device_alloc("fujitsu-laptop", -1); + if (!fujitsu->pf_device) { + ret = -ENOMEM; + goto fail_platform_driver; + } + + ret = platform_device_add(fujitsu->pf_device); + if (ret) + goto fail_platform_device1; + + ret = + sysfs_create_group(&fujitsu->pf_device->dev.kobj, + &fujitsupf_attribute_group); + if (ret) + goto fail_platform_device2; + + printk(KERN_INFO "fujitsu-laptop: driver " FUJITSU_DRIVER_VERSION + " successfully loaded.\n"); + + return 0; + + fail_platform_device2: + + platform_device_del(fujitsu->pf_device); + + fail_platform_device1: + + platform_device_put(fujitsu->pf_device); + + fail_platform_driver: + + platform_driver_unregister(&fujitsupf_driver); + + fail_backlight: + + backlight_device_unregister(fujitsu->bl_device); + + fail_acpi: + + kfree(fujitsu); + + return ret; +} + +static void __exit fujitsu_cleanup(void) +{ + sysfs_remove_group(&fujitsu->pf_device->dev.kobj, + &fujitsupf_attribute_group); + platform_device_unregister(fujitsu->pf_device); + platform_driver_unregister(&fujitsupf_driver); + backlight_device_unregister(fujitsu->bl_device); + + acpi_bus_unregister_driver(&acpi_fujitsu_driver); + + kfree(fujitsu); + + printk(KERN_INFO "fujitsu-laptop: driver unloaded.\n"); +} + +module_init(fujitsu_init); +module_exit(fujitsu_cleanup); + +MODULE_AUTHOR("Jonathan Woithe"); +MODULE_DESCRIPTION("Fujitsu laptop extras support"); +MODULE_VERSION(FUJITSU_DRIVER_VERSION); +MODULE_LICENSE("GPL"); diff --git a/drivers/misc/msi-laptop.c b/drivers/misc/msi-laptop.c index 932a415197b3..349be934db7c 100644 --- a/drivers/misc/msi-laptop.c +++ b/drivers/misc/msi-laptop.c @@ -353,7 +353,7 @@ static int __init msi_init(void) if (IS_ERR(msibl_device)) return PTR_ERR(msibl_device); - msibl_device->props.max_brightness = MSI_LCD_LEVEL_MAX-1, + msibl_device->props.max_brightness = MSI_LCD_LEVEL_MAX-1; ret = platform_driver_register(&msipf_driver); if (ret) diff --git a/drivers/misc/sony-laptop.c b/drivers/misc/sony-laptop.c index d38ddce592c0..f248080828f2 100644 --- a/drivers/misc/sony-laptop.c +++ b/drivers/misc/sony-laptop.c @@ -1173,7 +1173,8 @@ static struct acpi_driver sony_nc_driver = { #define SONYPI_TYPE3_OFFSET 0x12 struct sony_pic_ioport { - struct acpi_resource_io io; + struct acpi_resource_io io1; + struct acpi_resource_io io2; struct list_head list; }; @@ -1443,11 +1444,11 @@ static u8 sony_pic_call1(u8 dev) { u8 v1, v2; - wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2, + wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG); - outb(dev, spic_dev.cur_ioport->io.minimum + 4); - v1 = inb_p(spic_dev.cur_ioport->io.minimum + 4); - v2 = inb_p(spic_dev.cur_ioport->io.minimum); + outb(dev, spic_dev.cur_ioport->io1.minimum + 4); + v1 = inb_p(spic_dev.cur_ioport->io1.minimum + 4); + v2 = inb_p(spic_dev.cur_ioport->io1.minimum); dprintk("sony_pic_call1: 0x%.4x\n", (v2 << 8) | v1); return v2; } @@ -1456,13 +1457,13 @@ static u8 sony_pic_call2(u8 dev, u8 fn) { u8 v1; - wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2, + wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG); - outb(dev, spic_dev.cur_ioport->io.minimum + 4); - wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2, + outb(dev, spic_dev.cur_ioport->io1.minimum + 4); + wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG); - outb(fn, spic_dev.cur_ioport->io.minimum); - v1 = inb_p(spic_dev.cur_ioport->io.minimum); + outb(fn, spic_dev.cur_ioport->io1.minimum); + v1 = inb_p(spic_dev.cur_ioport->io1.minimum); dprintk("sony_pic_call2: 0x%.4x\n", v1); return v1; } @@ -1471,13 +1472,13 @@ static u8 sony_pic_call3(u8 dev, u8 fn, u8 v) { u8 v1; - wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2, ITERATIONS_LONG); - outb(dev, spic_dev.cur_ioport->io.minimum + 4); - wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2, ITERATIONS_LONG); - outb(fn, spic_dev.cur_ioport->io.minimum); - wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2, ITERATIONS_LONG); - outb(v, spic_dev.cur_ioport->io.minimum); - v1 = inb_p(spic_dev.cur_ioport->io.minimum); + wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG); + outb(dev, spic_dev.cur_ioport->io1.minimum + 4); + wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG); + outb(fn, spic_dev.cur_ioport->io1.minimum); + wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG); + outb(v, spic_dev.cur_ioport->io1.minimum); + v1 = inb_p(spic_dev.cur_ioport->io1.minimum); dprintk("sony_pic_call3: 0x%.4x\n", v1); return v1; } @@ -2074,7 +2075,18 @@ sony_pic_read_possible_resource(struct acpi_resource *resource, void *context) switch (resource->type) { case ACPI_RESOURCE_TYPE_START_DEPENDENT: + { + /* start IO enumeration */ + struct sony_pic_ioport *ioport = kzalloc(sizeof(*ioport), GFP_KERNEL); + if (!ioport) + return AE_ERROR; + + list_add(&ioport->list, &dev->ioports); + return AE_OK; + } + case ACPI_RESOURCE_TYPE_END_DEPENDENT: + /* end IO enumeration */ return AE_OK; case ACPI_RESOURCE_TYPE_IRQ: @@ -2101,7 +2113,7 @@ sony_pic_read_possible_resource(struct acpi_resource *resource, void *context) if (!interrupt) return AE_ERROR; - list_add_tail(&interrupt->list, &dev->interrupts); + list_add(&interrupt->list, &dev->interrupts); interrupt->irq.triggering = p->triggering; interrupt->irq.polarity = p->polarity; interrupt->irq.sharable = p->sharable; @@ -2113,18 +2125,27 @@ sony_pic_read_possible_resource(struct acpi_resource *resource, void *context) case ACPI_RESOURCE_TYPE_IO: { struct acpi_resource_io *io = &resource->data.io; - struct sony_pic_ioport *ioport = NULL; + struct sony_pic_ioport *ioport = + list_first_entry(&dev->ioports, struct sony_pic_ioport, list); if (!io) { dprintk("Blank IO resource\n"); return AE_OK; } - ioport = kzalloc(sizeof(*ioport), GFP_KERNEL); - if (!ioport) + if (!ioport->io1.minimum) { + memcpy(&ioport->io1, io, sizeof(*io)); + dprintk("IO1 at 0x%.4x (0x%.2x)\n", ioport->io1.minimum, + ioport->io1.address_length); + } + else if (!ioport->io2.minimum) { + memcpy(&ioport->io2, io, sizeof(*io)); + dprintk("IO2 at 0x%.4x (0x%.2x)\n", ioport->io2.minimum, + ioport->io2.address_length); + } + else { + printk(KERN_ERR DRV_PFX "Unknown SPIC Type, more than 2 IO Ports\n"); return AE_ERROR; - - list_add_tail(&ioport->list, &dev->ioports); - memcpy(&ioport->io, io, sizeof(*io)); + } return AE_OK; } default: @@ -2199,10 +2220,22 @@ static int sony_pic_enable(struct acpi_device *device, { acpi_status status; int result = 0; + /* Type 1 resource layout is: + * IO + * IO + * IRQNoFlags + * End + * + * Type 2 and 3 resource layout is: + * IO + * IRQNoFlags + * End + */ struct { - struct acpi_resource io_res; - struct acpi_resource irq_res; - struct acpi_resource end; + struct acpi_resource res1; + struct acpi_resource res2; + struct acpi_resource res3; + struct acpi_resource res4; } *resource; struct acpi_buffer buffer = { 0, NULL }; @@ -2217,21 +2250,49 @@ static int sony_pic_enable(struct acpi_device *device, buffer.length = sizeof(*resource) + 1; buffer.pointer = resource; - /* setup io resource */ - resource->io_res.type = ACPI_RESOURCE_TYPE_IO; - resource->io_res.length = sizeof(struct acpi_resource); - memcpy(&resource->io_res.data.io, &ioport->io, - sizeof(struct acpi_resource_io)); + /* setup Type 1 resources */ + if (spic_dev.model == SONYPI_DEVICE_TYPE1) { - /* setup irq resource */ - resource->irq_res.type = ACPI_RESOURCE_TYPE_IRQ; - resource->irq_res.length = sizeof(struct acpi_resource); - memcpy(&resource->irq_res.data.irq, &irq->irq, - sizeof(struct acpi_resource_irq)); - /* we requested a shared irq */ - resource->irq_res.data.irq.sharable = ACPI_SHARED; + /* setup io resources */ + resource->res1.type = ACPI_RESOURCE_TYPE_IO; + resource->res1.length = sizeof(struct acpi_resource); + memcpy(&resource->res1.data.io, &ioport->io1, + sizeof(struct acpi_resource_io)); - resource->end.type = ACPI_RESOURCE_TYPE_END_TAG; + resource->res2.type = ACPI_RESOURCE_TYPE_IO; + resource->res2.length = sizeof(struct acpi_resource); + memcpy(&resource->res2.data.io, &ioport->io2, + sizeof(struct acpi_resource_io)); + + /* setup irq resource */ + resource->res3.type = ACPI_RESOURCE_TYPE_IRQ; + resource->res3.length = sizeof(struct acpi_resource); + memcpy(&resource->res3.data.irq, &irq->irq, + sizeof(struct acpi_resource_irq)); + /* we requested a shared irq */ + resource->res3.data.irq.sharable = ACPI_SHARED; + + resource->res4.type = ACPI_RESOURCE_TYPE_END_TAG; + + } + /* setup Type 2/3 resources */ + else { + /* setup io resource */ + resource->res1.type = ACPI_RESOURCE_TYPE_IO; + resource->res1.length = sizeof(struct acpi_resource); + memcpy(&resource->res1.data.io, &ioport->io1, + sizeof(struct acpi_resource_io)); + + /* setup irq resource */ + resource->res2.type = ACPI_RESOURCE_TYPE_IRQ; + resource->res2.length = sizeof(struct acpi_resource); + memcpy(&resource->res2.data.irq, &irq->irq, + sizeof(struct acpi_resource_irq)); + /* we requested a shared irq */ + resource->res2.data.irq.sharable = ACPI_SHARED; + + resource->res3.type = ACPI_RESOURCE_TYPE_END_TAG; + } /* Attempt to set the resource */ dprintk("Evaluating _SRS\n"); @@ -2239,7 +2300,7 @@ static int sony_pic_enable(struct acpi_device *device, /* check for total failure */ if (ACPI_FAILURE(status)) { - printk(KERN_ERR DRV_PFX "Error evaluating _SRS"); + printk(KERN_ERR DRV_PFX "Error evaluating _SRS\n"); result = -ENODEV; goto end; } @@ -2268,11 +2329,14 @@ static irqreturn_t sony_pic_irq(int irq, void *dev_id) struct sony_pic_dev *dev = (struct sony_pic_dev *) dev_id; - ev = inb_p(dev->cur_ioport->io.minimum); - data_mask = inb_p(dev->cur_ioport->io.minimum + dev->evport_offset); + ev = inb_p(dev->cur_ioport->io1.minimum); + if (dev->cur_ioport->io2.minimum) + data_mask = inb_p(dev->cur_ioport->io2.minimum); + else + data_mask = inb_p(dev->cur_ioport->io1.minimum + dev->evport_offset); dprintk("event ([%.2x] [%.2x]) at port 0x%.4x(+0x%.2x)\n", - ev, data_mask, dev->cur_ioport->io.minimum, dev->evport_offset); + ev, data_mask, dev->cur_ioport->io1.minimum, dev->evport_offset); if (ev == 0x00 || ev == 0xff) return IRQ_HANDLED; @@ -2323,8 +2387,11 @@ static int sony_pic_remove(struct acpi_device *device, int type) } free_irq(spic_dev.cur_irq->irq.interrupts[0], &spic_dev); - release_region(spic_dev.cur_ioport->io.minimum, - spic_dev.cur_ioport->io.address_length); + release_region(spic_dev.cur_ioport->io1.minimum, + spic_dev.cur_ioport->io1.address_length); + if (spic_dev.cur_ioport->io2.minimum) + release_region(spic_dev.cur_ioport->io2.minimum, + spic_dev.cur_ioport->io2.address_length); sonypi_compat_exit(); @@ -2397,14 +2464,36 @@ static int sony_pic_add(struct acpi_device *device) goto err_remove_input; /* request io port */ - list_for_each_entry(io, &spic_dev.ioports, list) { - if (request_region(io->io.minimum, io->io.address_length, + list_for_each_entry_reverse(io, &spic_dev.ioports, list) { + if (request_region(io->io1.minimum, io->io1.address_length, "Sony Programable I/O Device")) { - dprintk("I/O port: 0x%.4x (0x%.4x) + 0x%.2x\n", - io->io.minimum, io->io.maximum, - io->io.address_length); - spic_dev.cur_ioport = io; - break; + dprintk("I/O port1: 0x%.4x (0x%.4x) + 0x%.2x\n", + io->io1.minimum, io->io1.maximum, + io->io1.address_length); + /* Type 1 have 2 ioports */ + if (io->io2.minimum) { + if (request_region(io->io2.minimum, + io->io2.address_length, + "Sony Programable I/O Device")) { + dprintk("I/O port2: 0x%.4x (0x%.4x) + 0x%.2x\n", + io->io2.minimum, io->io2.maximum, + io->io2.address_length); + spic_dev.cur_ioport = io; + break; + } + else { + dprintk("Unable to get I/O port2: " + "0x%.4x (0x%.4x) + 0x%.2x\n", + io->io2.minimum, io->io2.maximum, + io->io2.address_length); + release_region(io->io1.minimum, + io->io1.address_length); + } + } + else { + spic_dev.cur_ioport = io; + break; + } } } if (!spic_dev.cur_ioport) { @@ -2414,7 +2503,7 @@ static int sony_pic_add(struct acpi_device *device) } /* request IRQ */ - list_for_each_entry(irq, &spic_dev.interrupts, list) { + list_for_each_entry_reverse(irq, &spic_dev.interrupts, list) { if (!request_irq(irq->irq.interrupts[0], sony_pic_irq, IRQF_SHARED, "sony-laptop", &spic_dev)) { dprintk("IRQ: %d - triggering: %d - " @@ -2462,8 +2551,11 @@ err_free_irq: free_irq(spic_dev.cur_irq->irq.interrupts[0], &spic_dev); err_release_region: - release_region(spic_dev.cur_ioport->io.minimum, - spic_dev.cur_ioport->io.address_length); + release_region(spic_dev.cur_ioport->io1.minimum, + spic_dev.cur_ioport->io1.address_length); + if (spic_dev.cur_ioport->io2.minimum) + release_region(spic_dev.cur_ioport->io2.minimum, + spic_dev.cur_ioport->io2.address_length); err_remove_compat: sonypi_compat_exit(); diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index bb8956d0c104..37891a8c030a 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -21,8 +21,8 @@ * 02110-1301, USA. */ -#define IBM_VERSION "0.15" -#define TPACPI_SYSFS_VERSION 0x010000 +#define IBM_VERSION "0.16" +#define TPACPI_SYSFS_VERSION 0x020000 /* * Changelog: @@ -117,6 +117,12 @@ IBM_BIOS_MODULE_ALIAS("K[U,X-Z]"); #define __unused __attribute__ ((unused)) +static enum { + TPACPI_LIFE_INIT = 0, + TPACPI_LIFE_RUNNING, + TPACPI_LIFE_EXITING, +} tpacpi_lifecycle; + /**************************************************************************** **************************************************************************** * @@ -342,6 +348,9 @@ static void dispatch_acpi_notify(acpi_handle handle, u32 event, void *data) { struct ibm_struct *ibm = data; + if (tpacpi_lifecycle != TPACPI_LIFE_RUNNING) + return; + if (!ibm || !ibm->acpi || !ibm->acpi->notify) return; @@ -517,8 +526,10 @@ static char *next_cmd(char **cmds) ****************************************************************************/ static struct platform_device *tpacpi_pdev; +static struct platform_device *tpacpi_sensors_pdev; static struct class_device *tpacpi_hwmon; static struct input_dev *tpacpi_inputdev; +static struct mutex tpacpi_inputdev_send_mutex; static int tpacpi_resume_handler(struct platform_device *pdev) @@ -543,6 +554,12 @@ static struct platform_driver tpacpi_pdriver = { .resume = tpacpi_resume_handler, }; +static struct platform_driver tpacpi_hwmon_pdriver = { + .driver = { + .name = IBM_HWMON_DRVR_NAME, + .owner = THIS_MODULE, + }, +}; /************************************************************************* * thinkpad-acpi driver attributes @@ -692,6 +709,8 @@ static int parse_strtoul(const char *buf, { char *endp; + while (*buf && isspace(*buf)) + buf++; *value = simple_strtoul(buf, &endp, 0); while (*endp && isspace(*endp)) endp++; @@ -906,9 +925,26 @@ static ssize_t hotkey_radio_sw_show(struct device *dev, static struct device_attribute dev_attr_hotkey_radio_sw = __ATTR(hotkey_radio_sw, S_IRUGO, hotkey_radio_sw_show, NULL); +/* sysfs hotkey report_mode -------------------------------------------- */ +static ssize_t hotkey_report_mode_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", + (hotkey_report_mode != 0) ? hotkey_report_mode : 1); +} + +static struct device_attribute dev_attr_hotkey_report_mode = + __ATTR(hotkey_report_mode, S_IRUGO, hotkey_report_mode_show, NULL); + /* --------------------------------------------------------------------- */ -static struct attribute *hotkey_mask_attributes[] = { +static struct attribute *hotkey_attributes[] __initdata = { + &dev_attr_hotkey_enable.attr, + &dev_attr_hotkey_report_mode.attr, +}; + +static struct attribute *hotkey_mask_attributes[] __initdata = { &dev_attr_hotkey_mask.attr, &dev_attr_hotkey_bios_enabled.attr, &dev_attr_hotkey_bios_mask.attr, @@ -972,6 +1008,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) int res, i; int status; + int hkeyv; vdbg_printk(TPACPI_DBG_INIT, "initializing hotkey subdriver\n"); @@ -987,27 +1024,45 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) str_supported(tp_features.hotkey)); if (tp_features.hotkey) { - hotkey_dev_attributes = create_attr_set(7, NULL); + hotkey_dev_attributes = create_attr_set(8, NULL); if (!hotkey_dev_attributes) return -ENOMEM; - res = add_to_attr_set(hotkey_dev_attributes, - &dev_attr_hotkey_enable.attr); + res = add_many_to_attr_set(hotkey_dev_attributes, + hotkey_attributes, + ARRAY_SIZE(hotkey_attributes)); if (res) return res; /* mask not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p, - A30, R30, R31, T20-22, X20-21, X22-24 */ - tp_features.hotkey_mask = - acpi_evalf(hkey_handle, NULL, "DHKN", "qv"); + A30, R30, R31, T20-22, X20-21, X22-24. Detected by checking + for HKEY interface version 0x100 */ + if (acpi_evalf(hkey_handle, &hkeyv, "MHKV", "qd")) { + if ((hkeyv >> 8) != 1) { + printk(IBM_ERR "unknown version of the " + "HKEY interface: 0x%x\n", hkeyv); + printk(IBM_ERR "please report this to %s\n", + IBM_MAIL); + } else { + /* + * MHKV 0x100 in A31, R40, R40e, + * T4x, X31, and later + * */ + tp_features.hotkey_mask = 1; + } + } vdbg_printk(TPACPI_DBG_INIT, "hotkey masks are %s\n", str_supported(tp_features.hotkey_mask)); if (tp_features.hotkey_mask) { - /* MHKA available in A31, R40, R40e, T4x, X31, and later */ if (!acpi_evalf(hkey_handle, &hotkey_all_mask, - "MHKA", "qd")) + "MHKA", "qd")) { + printk(IBM_ERR + "missing MHKA handler, " + "please report this to %s\n", + IBM_MAIL); hotkey_all_mask = 0x080cU; /* FN+F12, FN+F4, FN+F3 */ + } } res = hotkey_get(&hotkey_orig_status, &hotkey_orig_mask); @@ -1055,11 +1110,6 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) TPACPI_HOTKEY_MAP_SIZE); } -#ifndef CONFIG_THINKPAD_ACPI_INPUT_ENABLED - for (i = 0; i < 12; i++) - hotkey_keycode_map[i] = KEY_UNKNOWN; -#endif /* ! CONFIG_THINKPAD_ACPI_INPUT_ENABLED */ - set_bit(EV_KEY, tpacpi_inputdev->evbit); set_bit(EV_MSC, tpacpi_inputdev->evbit); set_bit(MSC_SCAN, tpacpi_inputdev->mscbit); @@ -1081,14 +1131,17 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) set_bit(SW_RADIO, tpacpi_inputdev->swbit); } -#ifdef CONFIG_THINKPAD_ACPI_INPUT_ENABLED dbg_printk(TPACPI_DBG_INIT, "enabling hot key handling\n"); res = hotkey_set(1, (hotkey_all_mask & ~hotkey_reserved_mask) | hotkey_orig_mask); if (res) return res; -#endif /* CONFIG_THINKPAD_ACPI_INPUT_ENABLED */ + + dbg_printk(TPACPI_DBG_INIT, + "legacy hot key reporting over procfs %s\n", + (hotkey_report_mode < 2) ? + "enabled" : "disabled"); } return (tp_features.hotkey)? 0 : 1; @@ -1115,6 +1168,8 @@ static void tpacpi_input_send_key(unsigned int scancode, unsigned int keycode) { if (keycode != KEY_RESERVED) { + mutex_lock(&tpacpi_inputdev_send_mutex); + input_report_key(tpacpi_inputdev, keycode, 1); if (keycode == KEY_UNKNOWN) input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN, @@ -1126,6 +1181,8 @@ static void tpacpi_input_send_key(unsigned int scancode, input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN, scancode); input_sync(tpacpi_inputdev); + + mutex_unlock(&tpacpi_inputdev_send_mutex); } } @@ -1133,67 +1190,102 @@ static void tpacpi_input_send_radiosw(void) { int wlsw; - if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw)) + mutex_lock(&tpacpi_inputdev_send_mutex); + + if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw)) { input_report_switch(tpacpi_inputdev, SW_RADIO, !!wlsw); + input_sync(tpacpi_inputdev); + } + + mutex_unlock(&tpacpi_inputdev_send_mutex); } static void hotkey_notify(struct ibm_struct *ibm, u32 event) { u32 hkey; unsigned int keycode, scancode; - int sendacpi = 1; - - if (event == 0x80 && acpi_evalf(hkey_handle, &hkey, "MHKP", "d")) { - if (tpacpi_inputdev->users > 0) { - switch (hkey >> 12) { - case 1: - /* 0x1000-0x1FFF: key presses */ - scancode = hkey & 0xfff; - if (scancode > 0 && scancode < 0x21) { - scancode--; - keycode = hotkey_keycode_map[scancode]; - tpacpi_input_send_key(scancode, keycode); - sendacpi = (keycode == KEY_RESERVED - || keycode == KEY_UNKNOWN); - } else { - printk(IBM_ERR - "hotkey 0x%04x out of range for keyboard map\n", - hkey); - } - break; - case 5: - /* 0x5000-0x5FFF: LID */ - /* we don't handle it through this path, just - * eat up known LID events */ - if (hkey != 0x5001 && hkey != 0x5002) { - printk(IBM_ERR - "unknown LID-related hotkey event: 0x%04x\n", - hkey); - } + int send_acpi_ev; + int ignore_acpi_ev; + + if (event != 0x80) { + printk(IBM_ERR "unknown HKEY notification event %d\n", event); + /* forward it to userspace, maybe it knows how to handle it */ + acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class, + ibm->acpi->device->dev.bus_id, + event, 0); + return; + } + + while (1) { + if (!acpi_evalf(hkey_handle, &hkey, "MHKP", "d")) { + printk(IBM_ERR "failed to retrieve HKEY event\n"); + return; + } + + if (hkey == 0) { + /* queue empty */ + return; + } + + send_acpi_ev = 0; + ignore_acpi_ev = 0; + + switch (hkey >> 12) { + case 1: + /* 0x1000-0x1FFF: key presses */ + scancode = hkey & 0xfff; + if (scancode > 0 && scancode < 0x21) { + scancode--; + keycode = hotkey_keycode_map[scancode]; + tpacpi_input_send_key(scancode, keycode); + } else { + printk(IBM_ERR + "hotkey 0x%04x out of range for keyboard map\n", + hkey); + send_acpi_ev = 1; + } + break; + case 5: + /* 0x5000-0x5FFF: LID */ + /* we don't handle it through this path, just + * eat up known LID events */ + if (hkey != 0x5001 && hkey != 0x5002) { + printk(IBM_ERR + "unknown LID-related HKEY event: 0x%04x\n", + hkey); + send_acpi_ev = 1; + } else { + ignore_acpi_ev = 1; + } + break; + case 7: + /* 0x7000-0x7FFF: misc */ + if (tp_features.hotkey_wlsw && hkey == 0x7000) { + tpacpi_input_send_radiosw(); break; - case 7: - /* 0x7000-0x7FFF: misc */ - if (tp_features.hotkey_wlsw && hkey == 0x7000) { - tpacpi_input_send_radiosw(); - sendacpi = 0; - break; - } - /* fallthrough to default */ - default: - /* case 2: dock-related */ - /* 0x2305 - T43 waking up due to bay lever eject while aslept */ - /* case 3: ultra-bay related. maybe bay in dock? */ - /* 0x3003 - T43 after wake up by bay lever eject (0x2305) */ - printk(IBM_NOTICE "unhandled hotkey event 0x%04x\n", hkey); } + /* fallthrough to default */ + default: + /* case 2: dock-related */ + /* 0x2305 - T43 waking up due to bay lever eject while aslept */ + /* case 3: ultra-bay related. maybe bay in dock? */ + /* 0x3003 - T43 after wake up by bay lever eject (0x2305) */ + printk(IBM_NOTICE "unhandled HKEY event 0x%04x\n", hkey); + send_acpi_ev = 1; } - if (sendacpi) + /* Legacy events */ + if (!ignore_acpi_ev && (send_acpi_ev || hotkey_report_mode < 2)) { acpi_bus_generate_proc_event(ibm->acpi->device, event, hkey); - } else { - printk(IBM_ERR "unknown hotkey notification event %d\n", event); - acpi_bus_generate_proc_event(ibm->acpi->device, event, 0); + } + + /* netlink events */ + if (!ignore_acpi_ev && send_acpi_ev) { + acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class, + ibm->acpi->device->dev.bus_id, + event, hkey); + } } } @@ -2789,7 +2881,7 @@ static int __init thermal_init(struct ibm_init_struct *iibm) switch(thermal_read_mode) { case TPACPI_THERMAL_TPEC_16: - res = sysfs_create_group(&tpacpi_pdev->dev.kobj, + res = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj, &thermal_temp_input16_group); if (res) return res; @@ -2797,7 +2889,7 @@ static int __init thermal_init(struct ibm_init_struct *iibm) case TPACPI_THERMAL_TPEC_8: case TPACPI_THERMAL_ACPI_TMP07: case TPACPI_THERMAL_ACPI_UPDT: - res = sysfs_create_group(&tpacpi_pdev->dev.kobj, + res = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj, &thermal_temp_input8_group); if (res) return res; @@ -2814,13 +2906,13 @@ static void thermal_exit(void) { switch(thermal_read_mode) { case TPACPI_THERMAL_TPEC_16: - sysfs_remove_group(&tpacpi_pdev->dev.kobj, + sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj, &thermal_temp_input16_group); break; case TPACPI_THERMAL_TPEC_8: case TPACPI_THERMAL_ACPI_TMP07: case TPACPI_THERMAL_ACPI_UPDT: - sysfs_remove_group(&tpacpi_pdev->dev.kobj, + sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj, &thermal_temp_input16_group); break; case TPACPI_THERMAL_NONE: @@ -3603,7 +3695,7 @@ static struct device_attribute dev_attr_fan_fan1_input = __ATTR(fan1_input, S_IRUGO, fan_fan1_input_show, NULL); -/* sysfs fan fan_watchdog (driver) ------------------------------------- */ +/* sysfs fan fan_watchdog (hwmon driver) ------------------------------- */ static ssize_t fan_fan_watchdog_show(struct device_driver *drv, char *buf) { @@ -3745,10 +3837,10 @@ static int __init fan_init(struct ibm_init_struct *iibm) if (fan_status_access_mode != TPACPI_FAN_NONE || fan_control_access_mode != TPACPI_FAN_WR_NONE) { - rc = sysfs_create_group(&tpacpi_pdev->dev.kobj, + rc = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj, &fan_attr_group); if (!(rc < 0)) - rc = driver_create_file(&tpacpi_pdriver.driver, + rc = driver_create_file(&tpacpi_hwmon_pdriver.driver, &driver_attr_fan_watchdog); if (rc < 0) return rc; @@ -3831,8 +3923,8 @@ static void fan_exit(void) vdbg_printk(TPACPI_DBG_EXIT, "cancelling any pending fan watchdog tasks\n"); /* FIXME: can we really do this unconditionally? */ - sysfs_remove_group(&tpacpi_pdev->dev.kobj, &fan_attr_group); - driver_remove_file(&tpacpi_pdriver.driver, &driver_attr_fan_watchdog); + sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj, &fan_attr_group); + driver_remove_file(&tpacpi_hwmon_pdriver.driver, &driver_attr_fan_watchdog); cancel_delayed_work(&fan_watchdog_task); flush_scheduled_work(); @@ -3865,6 +3957,9 @@ static void fan_watchdog_fire(struct work_struct *ignored) { int rc; + if (tpacpi_lifecycle != TPACPI_LIFE_RUNNING) + return; + printk(IBM_NOTICE "fan watchdog: enabling fan\n"); rc = fan_set_enable(); if (rc < 0) { @@ -3885,7 +3980,8 @@ static void fan_watchdog_reset(void) if (fan_watchdog_active) cancel_delayed_work(&fan_watchdog_task); - if (fan_watchdog_maxinterval > 0) { + if (fan_watchdog_maxinterval > 0 && + tpacpi_lifecycle != TPACPI_LIFE_EXITING) { fan_watchdog_active = 1; if (!schedule_delayed_work(&fan_watchdog_task, msecs_to_jiffies(fan_watchdog_maxinterval @@ -4279,6 +4375,19 @@ static struct ibm_struct fan_driver_data = { **************************************************************************** ****************************************************************************/ +/* sysfs name ---------------------------------------------------------- */ +static ssize_t thinkpad_acpi_pdev_name_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%s\n", IBM_NAME); +} + +static struct device_attribute dev_attr_thinkpad_acpi_pdev_name = + __ATTR(name, S_IRUGO, thinkpad_acpi_pdev_name_show, NULL); + +/* --------------------------------------------------------------------- */ + /* /proc support */ static struct proc_dir_entry *proc_dir; @@ -4623,6 +4732,9 @@ module_param_named(fan_control, fan_control_allowed, bool, 0); static int brightness_mode; module_param_named(brightness_mode, brightness_mode, int, 0); +static unsigned int hotkey_report_mode; +module_param(hotkey_report_mode, uint, 0); + #define IBM_PARAM(feature) \ module_param_call(feature, set_ibm_param, NULL, NULL, 0) @@ -4648,6 +4760,12 @@ static int __init thinkpad_acpi_module_init(void) { int ret, i; + tpacpi_lifecycle = TPACPI_LIFE_INIT; + + /* Parameter checking */ + if (hotkey_report_mode > 2) + return -EINVAL; + /* Driver-level probe */ get_thinkpad_model_data(&thinkpad_id); @@ -4672,19 +4790,31 @@ static int __init thinkpad_acpi_module_init(void) ret = platform_driver_register(&tpacpi_pdriver); if (ret) { - printk(IBM_ERR "unable to register platform driver\n"); + printk(IBM_ERR "unable to register main platform driver\n"); thinkpad_acpi_module_exit(); return ret; } tp_features.platform_drv_registered = 1; + ret = platform_driver_register(&tpacpi_hwmon_pdriver); + if (ret) { + printk(IBM_ERR "unable to register hwmon platform driver\n"); + thinkpad_acpi_module_exit(); + return ret; + } + tp_features.sensors_pdrv_registered = 1; + ret = tpacpi_create_driver_attributes(&tpacpi_pdriver.driver); + if (!ret) { + tp_features.platform_drv_attrs_registered = 1; + ret = tpacpi_create_driver_attributes(&tpacpi_hwmon_pdriver.driver); + } if (ret) { printk(IBM_ERR "unable to create sysfs driver attributes\n"); thinkpad_acpi_module_exit(); return ret; } - tp_features.platform_drv_attrs_registered = 1; + tp_features.sensors_pdrv_attrs_registered = 1; /* Device initialization */ @@ -4697,7 +4827,26 @@ static int __init thinkpad_acpi_module_init(void) thinkpad_acpi_module_exit(); return ret; } - tpacpi_hwmon = hwmon_device_register(&tpacpi_pdev->dev); + tpacpi_sensors_pdev = platform_device_register_simple( + IBM_HWMON_DRVR_NAME, + -1, NULL, 0); + if (IS_ERR(tpacpi_sensors_pdev)) { + ret = PTR_ERR(tpacpi_sensors_pdev); + tpacpi_sensors_pdev = NULL; + printk(IBM_ERR "unable to register hwmon platform device\n"); + thinkpad_acpi_module_exit(); + return ret; + } + ret = device_create_file(&tpacpi_sensors_pdev->dev, + &dev_attr_thinkpad_acpi_pdev_name); + if (ret) { + printk(IBM_ERR + "unable to create sysfs hwmon device attributes\n"); + thinkpad_acpi_module_exit(); + return ret; + } + tp_features.sensors_pdev_attrs_registered = 1; + tpacpi_hwmon = hwmon_device_register(&tpacpi_sensors_pdev->dev); if (IS_ERR(tpacpi_hwmon)) { ret = PTR_ERR(tpacpi_hwmon); tpacpi_hwmon = NULL; @@ -4705,6 +4854,7 @@ static int __init thinkpad_acpi_module_init(void) thinkpad_acpi_module_exit(); return ret; } + mutex_init(&tpacpi_inputdev_send_mutex); tpacpi_inputdev = input_allocate_device(); if (!tpacpi_inputdev) { printk(IBM_ERR "unable to allocate input device\n"); @@ -4739,6 +4889,7 @@ static int __init thinkpad_acpi_module_init(void) tp_features.input_device_registered = 1; } + tpacpi_lifecycle = TPACPI_LIFE_RUNNING; return 0; } @@ -4746,6 +4897,8 @@ static void thinkpad_acpi_module_exit(void) { struct ibm_struct *ibm, *itmp; + tpacpi_lifecycle = TPACPI_LIFE_EXITING; + list_for_each_entry_safe_reverse(ibm, itmp, &tpacpi_all_drivers, all_drivers) { @@ -4764,12 +4917,22 @@ static void thinkpad_acpi_module_exit(void) if (tpacpi_hwmon) hwmon_device_unregister(tpacpi_hwmon); + if (tp_features.sensors_pdev_attrs_registered) + device_remove_file(&tpacpi_sensors_pdev->dev, + &dev_attr_thinkpad_acpi_pdev_name); + if (tpacpi_sensors_pdev) + platform_device_unregister(tpacpi_sensors_pdev); if (tpacpi_pdev) platform_device_unregister(tpacpi_pdev); + if (tp_features.sensors_pdrv_attrs_registered) + tpacpi_remove_driver_attributes(&tpacpi_hwmon_pdriver.driver); if (tp_features.platform_drv_attrs_registered) tpacpi_remove_driver_attributes(&tpacpi_pdriver.driver); + if (tp_features.sensors_pdrv_registered) + platform_driver_unregister(&tpacpi_hwmon_pdriver); + if (tp_features.platform_drv_registered) platform_driver_unregister(&tpacpi_pdriver); diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h index eee8809a50d9..c5fdd688cc99 100644 --- a/drivers/misc/thinkpad_acpi.h +++ b/drivers/misc/thinkpad_acpi.h @@ -58,13 +58,14 @@ #define IBM_NAME "thinkpad" #define IBM_DESC "ThinkPad ACPI Extras" -#define IBM_FILE "thinkpad_acpi" +#define IBM_FILE IBM_NAME "_acpi" #define IBM_URL "http://ibm-acpi.sf.net/" #define IBM_MAIL "ibm-acpi-devel@lists.sourceforge.net" #define IBM_PROC_DIR "ibm" #define IBM_ACPI_EVENT_PREFIX "ibm" #define IBM_DRVR_NAME IBM_FILE +#define IBM_HWMON_DRVR_NAME IBM_NAME "_hwmon" #define IBM_LOG IBM_FILE ": " #define IBM_ERR KERN_ERR IBM_LOG @@ -171,6 +172,7 @@ static int parse_strtoul(const char *buf, unsigned long max, /* Device model */ static struct platform_device *tpacpi_pdev; +static struct platform_device *tpacpi_sensors_pdev; static struct class_device *tpacpi_hwmon; static struct platform_driver tpacpi_pdriver; static struct input_dev *tpacpi_inputdev; @@ -181,6 +183,7 @@ static void tpacpi_remove_driver_attributes(struct device_driver *drv); static int experimental; static u32 dbg_level; static int force_load; +static unsigned int hotkey_report_mode; static int thinkpad_acpi_module_init(void); static void thinkpad_acpi_module_exit(void); @@ -232,22 +235,25 @@ struct ibm_init_struct { static struct { #ifdef CONFIG_THINKPAD_ACPI_BAY - u16 bay_status:1; - u16 bay_eject:1; - u16 bay_status2:1; - u16 bay_eject2:1; + u32 bay_status:1; + u32 bay_eject:1; + u32 bay_status2:1; + u32 bay_eject2:1; #endif - u16 bluetooth:1; - u16 hotkey:1; - u16 hotkey_mask:1; - u16 hotkey_wlsw:1; - u16 light:1; - u16 light_status:1; - u16 wan:1; - u16 fan_ctrl_status_undef:1; - u16 input_device_registered:1; - u16 platform_drv_registered:1; - u16 platform_drv_attrs_registered:1; + u32 bluetooth:1; + u32 hotkey:1; + u32 hotkey_mask:1; + u32 hotkey_wlsw:1; + u32 light:1; + u32 light_status:1; + u32 wan:1; + u32 fan_ctrl_status_undef:1; + u32 input_device_registered:1; + u32 platform_drv_registered:1; + u32 platform_drv_attrs_registered:1; + u32 sensors_pdrv_registered:1; + u32 sensors_pdrv_attrs_registered:1; + u32 sensors_pdev_attrs_registered:1; } tp_features; struct thinkpad_id_data { diff --git a/drivers/mmc/host/at91_mci.c b/drivers/mmc/host/at91_mci.c index bfebd2fa7ada..955ea60583b5 100644 --- a/drivers/mmc/host/at91_mci.c +++ b/drivers/mmc/host/at91_mci.c @@ -941,7 +941,7 @@ static int __exit at91_mci_remove(struct platform_device *pdev) host = mmc_priv(mmc); - if (host->present != -1) { + if (host->board->det_pin) { device_init_wakeup(&pdev->dev, 0); free_irq(host->board->det_pin, host); cancel_delayed_work(&host->mmc->detect); @@ -972,7 +972,7 @@ static int at91_mci_suspend(struct platform_device *pdev, pm_message_t state) struct at91mci_host *host = mmc_priv(mmc); int ret = 0; - if (device_may_wakeup(&pdev->dev)) + if (host->board->det_pin && device_may_wakeup(&pdev->dev)) enable_irq_wake(host->board->det_pin); if (mmc) @@ -987,7 +987,7 @@ static int at91_mci_resume(struct platform_device *pdev) struct at91mci_host *host = mmc_priv(mmc); int ret = 0; - if (device_may_wakeup(&pdev->dev)) + if (host->board->det_pin && device_may_wakeup(&pdev->dev)) disable_irq_wake(host->board->det_pin); if (mmc) diff --git a/drivers/mtd/mtdsuper.c b/drivers/mtd/mtdsuper.c index aca331971201..9b430f20b640 100644 --- a/drivers/mtd/mtdsuper.c +++ b/drivers/mtd/mtdsuper.c @@ -70,6 +70,8 @@ static int get_sb_mtd_aux(struct file_system_type *fs_type, int flags, DEBUG(1, "MTDSB: New superblock for device %d (\"%s\")\n", mtd->index, mtd->name); + sb->s_flags = flags; + ret = fill_super(sb, data, flags & MS_SILENT ? 1 : 0); if (ret < 0) { up_write(&sb->s_umount); diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c index cff969d05d4a..6f32a35eb106 100644 --- a/drivers/mtd/nand/cafe_nand.c +++ b/drivers/mtd/nand/cafe_nand.c @@ -816,7 +816,8 @@ static void __devexit cafe_nand_remove(struct pci_dev *pdev) } static struct pci_device_id cafe_nand_tbl[] = { - { 0x11ab, 0x4100, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MEMORY_FLASH << 8, 0xFFFF0 } + { 0x11ab, 0x4100, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MEMORY_FLASH << 8, 0xFFFF0 }, + { 0, } }; MODULE_DEVICE_TABLE(pci, cafe_nand_tbl); diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 5b9e17bf1749..c5519250efd9 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2177,7 +2177,7 @@ config SKGE with better performance and more complete ethtool support. It does not support the link failover and network management - features available in the hardware. + features that "portable" vendor supplied sk98lin driver does. This driver supports adapters based on the original Yukon chipset: Marvell 88E8001, Belkin F5D5005, CNet GigaCard, DLink DGE-530T, @@ -2215,6 +2215,93 @@ config SKY2_DEBUG If unsure, say N. +config SK98LIN + tristate "Marvell Yukon Chipset / SysKonnect SK-98xx Support (DEPRECATED)" + depends on PCI + ---help--- + Say Y here if you have a Marvell Yukon or SysKonnect SK-98xx/SK-95xx + compliant Gigabit Ethernet Adapter. + + This driver supports the original Yukon chipset. This driver is + deprecated and will be removed from the kernel in the near future, + it has been replaced by the skge driver. skge is cleaner and + seems to work better. + + This driver does not support the newer Yukon2 chipset. A separate + driver, sky2, is provided to support Yukon2-based adapters. + + The following adapters are supported by this driver: + - 3Com 3C940 Gigabit LOM Ethernet Adapter + - 3Com 3C941 Gigabit LOM Ethernet Adapter + - Allied Telesyn AT-2970LX Gigabit Ethernet Adapter + - Allied Telesyn AT-2970LX/2SC Gigabit Ethernet Adapter + - Allied Telesyn AT-2970SX Gigabit Ethernet Adapter + - Allied Telesyn AT-2970SX/2SC Gigabit Ethernet Adapter + - Allied Telesyn AT-2970TX Gigabit Ethernet Adapter + - Allied Telesyn AT-2970TX/2TX Gigabit Ethernet Adapter + - Allied Telesyn AT-2971SX Gigabit Ethernet Adapter + - Allied Telesyn AT-2971T Gigabit Ethernet Adapter + - Belkin Gigabit Desktop Card 10/100/1000Base-T Adapter, Copper RJ-45 + - EG1032 v2 Instant Gigabit Network Adapter + - EG1064 v2 Instant Gigabit Network Adapter + - Marvell 88E8001 Gigabit LOM Ethernet Adapter (Abit) + - Marvell 88E8001 Gigabit LOM Ethernet Adapter (Albatron) + - Marvell 88E8001 Gigabit LOM Ethernet Adapter (Asus) + - Marvell 88E8001 Gigabit LOM Ethernet Adapter (ECS) + - Marvell 88E8001 Gigabit LOM Ethernet Adapter (Epox) + - Marvell 88E8001 Gigabit LOM Ethernet Adapter (Foxconn) + - Marvell 88E8001 Gigabit LOM Ethernet Adapter (Gigabyte) + - Marvell 88E8001 Gigabit LOM Ethernet Adapter (Iwill) + - Marvell 88E8050 Gigabit LOM Ethernet Adapter (Intel) + - Marvell RDK-8001 Adapter + - Marvell RDK-8002 Adapter + - Marvell RDK-8003 Adapter + - Marvell RDK-8004 Adapter + - Marvell RDK-8006 Adapter + - Marvell RDK-8007 Adapter + - Marvell RDK-8008 Adapter + - Marvell RDK-8009 Adapter + - Marvell RDK-8010 Adapter + - Marvell RDK-8011 Adapter + - Marvell RDK-8012 Adapter + - Marvell RDK-8052 Adapter + - Marvell Yukon Gigabit Ethernet 10/100/1000Base-T Adapter (32 bit) + - Marvell Yukon Gigabit Ethernet 10/100/1000Base-T Adapter (64 bit) + - N-Way PCI-Bus Giga-Card 1000/100/10Mbps(L) + - SK-9521 10/100/1000Base-T Adapter + - SK-9521 V2.0 10/100/1000Base-T Adapter + - SK-9821 Gigabit Ethernet Server Adapter (SK-NET GE-T) + - SK-9821 V2.0 Gigabit Ethernet 10/100/1000Base-T Adapter + - SK-9822 Gigabit Ethernet Server Adapter (SK-NET GE-T dual link) + - SK-9841 Gigabit Ethernet Server Adapter (SK-NET GE-LX) + - SK-9841 V2.0 Gigabit Ethernet 1000Base-LX Adapter + - SK-9842 Gigabit Ethernet Server Adapter (SK-NET GE-LX dual link) + - SK-9843 Gigabit Ethernet Server Adapter (SK-NET GE-SX) + - SK-9843 V2.0 Gigabit Ethernet 1000Base-SX Adapter + - SK-9844 Gigabit Ethernet Server Adapter (SK-NET GE-SX dual link) + - SK-9851 V2.0 Gigabit Ethernet 1000Base-SX Adapter + - SK-9861 Gigabit Ethernet Server Adapter (SK-NET GE-SX Volition) + - SK-9861 V2.0 Gigabit Ethernet 1000Base-SX Adapter + - SK-9862 Gigabit Ethernet Server Adapter (SK-NET GE-SX Volition dual link) + - SK-9871 Gigabit Ethernet Server Adapter (SK-NET GE-ZX) + - SK-9871 V2.0 Gigabit Ethernet 1000Base-ZX Adapter + - SK-9872 Gigabit Ethernet Server Adapter (SK-NET GE-ZX dual link) + - SMC EZ Card 1000 (SMC9452TXV.2) + + The adapters support Jumbo Frames. + The dual link adapters support link-failover and dual port features. + Both Marvell Yukon and SysKonnect SK-98xx/SK-95xx adapters support + the scatter-gather functionality with sendfile(). Please refer to + <file:Documentation/networking/sk98lin.txt> for more information about + optional driver parameters. + Questions concerning this driver may be addressed to: + <linux@syskonnect.de> + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/kbuild/modules.txt>. The module will + be called sk98lin. This is recommended. + config VIA_VELOCITY tristate "VIA Velocity support" depends on PCI diff --git a/drivers/net/Makefile b/drivers/net/Makefile index e684212fd8e2..9c928a845841 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -66,6 +66,7 @@ ps3_gelic-objs += ps3_gelic_net.o obj-$(CONFIG_TC35815) += tc35815.o obj-$(CONFIG_SKGE) += skge.o obj-$(CONFIG_SKY2) += sky2.o +obj-$(CONFIG_SK98LIN) += sk98lin/ obj-$(CONFIG_SKFP) += skfp/ obj-$(CONFIG_VIA_RHINE) += via-rhine.o obj-$(CONFIG_VIA_VELOCITY) += via-velocity.o diff --git a/drivers/net/atl1/atl1_main.c b/drivers/net/atl1/atl1_main.c index 3c1984ecf36c..f23e13c8f9a6 100644 --- a/drivers/net/atl1/atl1_main.c +++ b/drivers/net/atl1/atl1_main.c @@ -2203,21 +2203,20 @@ static int __devinit atl1_probe(struct pci_dev *pdev, struct net_device *netdev; struct atl1_adapter *adapter; static int cards_found = 0; - bool pci_using_64 = true; int err; err = pci_enable_device(pdev); if (err) return err; - err = pci_set_dma_mask(pdev, DMA_64BIT_MASK); + /* + * 64-bit DMA currently has data corruption problems, so let's just + * use 32-bit DMA for now. This is a big hack that is probably wrong. + */ + err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); if (err) { - err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); - if (err) { - dev_err(&pdev->dev, "no usable DMA configuration\n"); - goto err_dma; - } - pci_using_64 = false; + dev_err(&pdev->dev, "no usable DMA configuration\n"); + goto err_dma; } /* Mark all PCI regions associated with PCI device * pdev as being reserved by owner atl1_driver_name @@ -2282,7 +2281,6 @@ static int __devinit atl1_probe(struct pci_dev *pdev, netdev->ethtool_ops = &atl1_ethtool_ops; adapter->bd_number = cards_found; - adapter->pci_using_64 = pci_using_64; /* setup the private structure */ err = atl1_sw_init(adapter); @@ -2299,9 +2297,6 @@ static int __devinit atl1_probe(struct pci_dev *pdev, */ /* netdev->features |= NETIF_F_TSO; */ - if (pci_using_64) - netdev->features |= NETIF_F_HIGHDMA; - netdev->features |= NETIF_F_LLTX; /* diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 854d80c330ec..66eed22cbd21 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -54,8 +54,8 @@ #define DRV_MODULE_NAME "bnx2" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "1.6.4" -#define DRV_MODULE_RELDATE "August 3, 2007" +#define DRV_MODULE_VERSION "1.6.5" +#define DRV_MODULE_RELDATE "September 20, 2007" #define RUN_AT(x) (jiffies + (x)) @@ -6727,7 +6727,8 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) } else if (CHIP_NUM(bp) == CHIP_NUM_5706 || CHIP_NUM(bp) == CHIP_NUM_5708) bp->phy_flags |= PHY_CRC_FIX_FLAG; - else if (CHIP_ID(bp) == CHIP_ID_5709_A0) + else if (CHIP_ID(bp) == CHIP_ID_5709_A0 || + CHIP_ID(bp) == CHIP_ID_5709_A1) bp->phy_flags |= PHY_DIS_EARLY_DAC_FLAG; if ((CHIP_ID(bp) == CHIP_ID_5708_A0) || diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index 4c3785c9d4b8..9ecc3adcf6c1 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -1726,6 +1726,7 @@ static int e1000_wol_exclusion(struct e1000_adapter *adapter, struct ethtool_wol case E1000_DEV_ID_82571EB_QUAD_COPPER: case E1000_DEV_ID_82571EB_QUAD_FIBER: case E1000_DEV_ID_82571EB_QUAD_COPPER_LOWPROFILE: + case E1000_DEV_ID_82571PT_QUAD_COPPER: case E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3: /* quad port adapters only support WoL on port A */ if (!adapter->quad_port_a) { diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c index ba120f7fb0be..8604adbe351c 100644 --- a/drivers/net/e1000/e1000_hw.c +++ b/drivers/net/e1000/e1000_hw.c @@ -387,6 +387,7 @@ e1000_set_mac_type(struct e1000_hw *hw) case E1000_DEV_ID_82571EB_SERDES_DUAL: case E1000_DEV_ID_82571EB_SERDES_QUAD: case E1000_DEV_ID_82571EB_QUAD_COPPER: + case E1000_DEV_ID_82571PT_QUAD_COPPER: case E1000_DEV_ID_82571EB_QUAD_FIBER: case E1000_DEV_ID_82571EB_QUAD_COPPER_LOWPROFILE: hw->mac_type = e1000_82571; diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h index fe8714655c90..07f0ea73676e 100644 --- a/drivers/net/e1000/e1000_hw.h +++ b/drivers/net/e1000/e1000_hw.h @@ -475,6 +475,7 @@ int32_t e1000_check_phy_reset_block(struct e1000_hw *hw); #define E1000_DEV_ID_82571EB_FIBER 0x105F #define E1000_DEV_ID_82571EB_SERDES 0x1060 #define E1000_DEV_ID_82571EB_QUAD_COPPER 0x10A4 +#define E1000_DEV_ID_82571PT_QUAD_COPPER 0x10D5 #define E1000_DEV_ID_82571EB_QUAD_FIBER 0x10A5 #define E1000_DEV_ID_82571EB_QUAD_COPPER_LOWPROFILE 0x10BC #define E1000_DEV_ID_82571EB_SERDES_DUAL 0x10D9 diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 4a225950fb43..e7c8951f47fa 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -108,6 +108,7 @@ static struct pci_device_id e1000_pci_tbl[] = { INTEL_E1000_ETHERNET_DEVICE(0x10BC), INTEL_E1000_ETHERNET_DEVICE(0x10C4), INTEL_E1000_ETHERNET_DEVICE(0x10C5), + INTEL_E1000_ETHERNET_DEVICE(0x10D5), INTEL_E1000_ETHERNET_DEVICE(0x10D9), INTEL_E1000_ETHERNET_DEVICE(0x10DA), /* required last entry */ @@ -1101,6 +1102,7 @@ e1000_probe(struct pci_dev *pdev, case E1000_DEV_ID_82571EB_QUAD_COPPER: case E1000_DEV_ID_82571EB_QUAD_FIBER: case E1000_DEV_ID_82571EB_QUAD_COPPER_LOWPROFILE: + case E1000_DEV_ID_82571PT_QUAD_COPPER: /* if quad port adapter, disable WoL on all but port A */ if (global_quad_port_a != 0) adapter->eeprom_wol = 0; diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h index d67f97bfa3a4..8d58be56f4e3 100644 --- a/drivers/net/ehea/ehea.h +++ b/drivers/net/ehea/ehea.h @@ -39,7 +39,7 @@ #include <asm/io.h> #define DRV_NAME "ehea" -#define DRV_VERSION "EHEA_0073" +#define DRV_VERSION "EHEA_0074" /* eHEA capability flags */ #define DLPAR_PORT_ADD_REM 1 @@ -402,6 +402,8 @@ struct ehea_mc_list { #define EHEA_PORT_UP 1 #define EHEA_PORT_DOWN 0 +#define EHEA_PHY_LINK_UP 1 +#define EHEA_PHY_LINK_DOWN 0 #define EHEA_MAX_PORT_RES 16 struct ehea_port { struct ehea_adapter *adapter; /* adapter that owns this port */ @@ -427,6 +429,7 @@ struct ehea_port { u32 msg_enable; u32 sig_comp_iv; u32 state; + u8 phy_link; u8 full_duplex; u8 autoneg; u8 num_def_qps; diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index db5747490a07..717b12984d10 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -53,17 +53,21 @@ static int rq3_entries = EHEA_DEF_ENTRIES_RQ3; static int sq_entries = EHEA_DEF_ENTRIES_SQ; static int use_mcs = 0; static int num_tx_qps = EHEA_NUM_TX_QP; +static int prop_carrier_state = 0; module_param(msg_level, int, 0); module_param(rq1_entries, int, 0); module_param(rq2_entries, int, 0); module_param(rq3_entries, int, 0); module_param(sq_entries, int, 0); +module_param(prop_carrier_state, int, 0); module_param(use_mcs, int, 0); module_param(num_tx_qps, int, 0); MODULE_PARM_DESC(num_tx_qps, "Number of TX-QPS"); MODULE_PARM_DESC(msg_level, "msg_level"); +MODULE_PARM_DESC(prop_carrier_state, "Propagate carrier state of physical " + "port to stack. 1:yes, 0:no. Default = 0 "); MODULE_PARM_DESC(rq3_entries, "Number of entries for Receive Queue 3 " "[2^x - 1], x = [6..14]. Default = " __MODULE_STRING(EHEA_DEF_ENTRIES_RQ3) ")"); @@ -467,7 +471,7 @@ static struct ehea_cqe *ehea_proc_rwqes(struct net_device *dev, else netif_receive_skb(skb); - dev->last_rx = jiffies; + port->netdev->last_rx = jiffies; } else { pr->p_stats.poll_receive_errors++; port_reset = ehea_treat_poll_error(pr, rq, cqe, @@ -814,7 +818,9 @@ int ehea_set_portspeed(struct ehea_port *port, u32 port_speed) ehea_error("Failed setting port speed"); } } - netif_carrier_on(port->netdev); + if (!prop_carrier_state || (port->phy_link == EHEA_PHY_LINK_UP)) + netif_carrier_on(port->netdev); + kfree(cb4); out: return ret; @@ -869,13 +875,19 @@ static void ehea_parse_eqe(struct ehea_adapter *adapter, u64 eqe) } if (EHEA_BMASK_GET(NEQE_EXTSWITCH_PORT_UP, eqe)) { + port->phy_link = EHEA_PHY_LINK_UP; if (netif_msg_link(port)) ehea_info("%s: Physical port up", port->netdev->name); + if (prop_carrier_state) + netif_carrier_on(port->netdev); } else { + port->phy_link = EHEA_PHY_LINK_DOWN; if (netif_msg_link(port)) ehea_info("%s: Physical port down", port->netdev->name); + if (prop_carrier_state) + netif_carrier_off(port->netdev); } if (EHEA_BMASK_GET(NEQE_EXTSWITCH_PRIMARY, eqe)) diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 1799eee88db7..315335671f0f 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -534,7 +534,7 @@ static irqreturn_t mv643xx_eth_int_handler(int irq, void *dev_id) } /* PHY status changed */ - if (eth_int_cause_ext & ETH_INT_CAUSE_PHY) { + if (eth_int_cause_ext & (ETH_INT_CAUSE_PHY | ETH_INT_CAUSE_STATE)) { struct ethtool_cmd cmd; if (mii_link_ok(&mp->mii)) { @@ -1222,7 +1222,7 @@ static int mv643xx_eth_start_xmit(struct sk_buff *skb, struct net_device *dev) spin_lock_irqsave(&mp->lock, flags); eth_tx_submit_descs_for_skb(mp, skb); - stats->tx_bytes = skb->len; + stats->tx_bytes += skb->len; stats->tx_packets++; dev->trans_start = jiffies; @@ -1357,7 +1357,6 @@ static int mv643xx_eth_probe(struct platform_device *pdev) #endif dev->watchdog_timeo = 2 * HZ; - dev->tx_queue_len = mp->tx_ring_size; dev->base_addr = 0; dev->change_mtu = mv643xx_eth_change_mtu; dev->do_ioctl = mv643xx_eth_do_ioctl; @@ -2768,8 +2767,6 @@ static const struct ethtool_ops mv643xx_ethtool_ops = { .get_stats_count = mv643xx_get_stats_count, .get_ethtool_stats = mv643xx_get_ethtool_stats, .get_strings = mv643xx_get_strings, - .get_stats_count = mv643xx_get_stats_count, - .get_ethtool_stats = mv643xx_get_ethtool_stats, .nway_reset = mv643xx_eth_nway_restart, }; diff --git a/drivers/net/mv643xx_eth.h b/drivers/net/mv643xx_eth.h index 82f8c0cbfb64..565b96696aca 100644 --- a/drivers/net/mv643xx_eth.h +++ b/drivers/net/mv643xx_eth.h @@ -64,7 +64,9 @@ #define ETH_INT_CAUSE_TX_ERROR (ETH_TX_QUEUES_ENABLED << 8) #define ETH_INT_CAUSE_TX (ETH_INT_CAUSE_TX_DONE | ETH_INT_CAUSE_TX_ERROR) #define ETH_INT_CAUSE_PHY 0x00010000 -#define ETH_INT_UNMASK_ALL_EXT (ETH_INT_CAUSE_TX | ETH_INT_CAUSE_PHY) +#define ETH_INT_CAUSE_STATE 0x00100000 +#define ETH_INT_UNMASK_ALL_EXT (ETH_INT_CAUSE_TX | ETH_INT_CAUSE_PHY | \ + ETH_INT_CAUSE_STATE) #define ETH_INT_MASK_ALL 0x00000000 #define ETH_INT_MASK_ALL_EXT 0x00000000 diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index 1c42266bf889..556962f9612d 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -3094,9 +3094,12 @@ static void myri10ge_remove(struct pci_dev *pdev) } #define PCI_DEVICE_ID_MYRICOM_MYRI10GE_Z8E 0x0008 +#define PCI_DEVICE_ID_MYRICOM_MYRI10GE_Z8E_9 0x0009 static struct pci_device_id myri10ge_pci_tbl[] = { {PCI_DEVICE(PCI_VENDOR_ID_MYRICOM, PCI_DEVICE_ID_MYRICOM_MYRI10GE_Z8E)}, + {PCI_DEVICE + (PCI_VENDOR_ID_MYRICOM, PCI_DEVICE_ID_MYRICOM_MYRI10GE_Z8E_9)}, {0}, }; diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index e323efd4ed18..cb230f44d6fc 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -409,6 +409,7 @@ int phy_mii_ioctl(struct phy_device *phydev, return 0; } +EXPORT_SYMBOL(phy_mii_ioctl); /** * phy_start_aneg - start auto-negotiation for this PHY device @@ -755,7 +756,7 @@ out_unlock: */ void phy_start(struct phy_device *phydev) { - spin_lock(&phydev->lock); + spin_lock_bh(&phydev->lock); switch (phydev->state) { case PHY_STARTING: @@ -769,7 +770,7 @@ void phy_start(struct phy_device *phydev) default: break; } - spin_unlock(&phydev->lock); + spin_unlock_bh(&phydev->lock); } EXPORT_SYMBOL(phy_stop); EXPORT_SYMBOL(phy_start); diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index e275df8c55bc..49328e050505 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -644,7 +644,7 @@ static int phy_probe(struct device *dev) if (!(phydrv->flags & PHY_HAS_INTERRUPT)) phydev->irq = PHY_POLL; - spin_lock(&phydev->lock); + spin_lock_bh(&phydev->lock); /* Start out supporting everything. Eventually, * a controller will attach, and may modify one @@ -658,7 +658,7 @@ static int phy_probe(struct device *dev) if (phydev->drv->probe) err = phydev->drv->probe(phydev); - spin_unlock(&phydev->lock); + spin_unlock_bh(&phydev->lock); return err; diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index 9293c82ef2af..4b49d0e8c7eb 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c @@ -899,17 +899,9 @@ ppp_start_xmit(struct sk_buff *skb, struct net_device *dev) /* Put the 2-byte PPP protocol number on the front, making sure there is room for the address and control fields. */ - if (skb_headroom(skb) < PPP_HDRLEN) { - struct sk_buff *ns; - - ns = alloc_skb(skb->len + dev->hard_header_len, GFP_ATOMIC); - if (ns == 0) - goto outf; - skb_reserve(ns, dev->hard_header_len); - skb_copy_bits(skb, 0, skb_put(ns, skb->len), skb->len); - kfree_skb(skb); - skb = ns; - } + if (skb_cow_head(skb, PPP_HDRLEN)) + goto outf; + pp = skb_push(skb, 2); proto = npindex_to_proto[npi]; pp[0] = proto >> 8; @@ -1533,7 +1525,7 @@ ppp_input_error(struct ppp_channel *chan, int code) static void ppp_receive_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch) { - if (skb->len >= 2) { + if (pskb_may_pull(skb, 2)) { #ifdef CONFIG_PPP_MULTILINK /* XXX do channel-level decompression here */ if (PPP_PROTO(skb) == PPP_MP) @@ -1585,7 +1577,7 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb) if (ppp->vj == 0 || (ppp->flags & SC_REJ_COMP_TCP)) goto err; - if (skb_tailroom(skb) < 124) { + if (skb_tailroom(skb) < 124 || skb_cloned(skb)) { /* copy to a new sk_buff with more tailroom */ ns = dev_alloc_skb(skb->len + 128); if (ns == 0) { @@ -1656,23 +1648,29 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb) /* check if the packet passes the pass and active filters */ /* the filter instructions are constructed assuming a four-byte PPP header on each packet */ - *skb_push(skb, 2) = 0; - if (ppp->pass_filter - && sk_run_filter(skb, ppp->pass_filter, - ppp->pass_len) == 0) { - if (ppp->debug & 1) - printk(KERN_DEBUG "PPP: inbound frame not passed\n"); - kfree_skb(skb); - return; - } - if (!(ppp->active_filter - && sk_run_filter(skb, ppp->active_filter, - ppp->active_len) == 0)) - ppp->last_recv = jiffies; - skb_pull(skb, 2); -#else - ppp->last_recv = jiffies; + if (ppp->pass_filter || ppp->active_filter) { + if (skb_cloned(skb) && + pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) + goto err; + + *skb_push(skb, 2) = 0; + if (ppp->pass_filter + && sk_run_filter(skb, ppp->pass_filter, + ppp->pass_len) == 0) { + if (ppp->debug & 1) + printk(KERN_DEBUG "PPP: inbound frame " + "not passed\n"); + kfree_skb(skb); + return; + } + if (!(ppp->active_filter + && sk_run_filter(skb, ppp->active_filter, + ppp->active_len) == 0)) + ppp->last_recv = jiffies; + __skb_pull(skb, 2); + } else #endif /* CONFIG_PPP_FILTER */ + ppp->last_recv = jiffies; if ((ppp->dev->flags & IFF_UP) == 0 || ppp->npmode[npi] != NPMODE_PASS) { @@ -1770,7 +1768,7 @@ ppp_receive_mp_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch) struct channel *ch; int mphdrlen = (ppp->flags & SC_MP_SHORTSEQ)? MPHDRLEN_SSN: MPHDRLEN; - if (!pskb_may_pull(skb, mphdrlen) || ppp->mrru == 0) + if (!pskb_may_pull(skb, mphdrlen + 1) || ppp->mrru == 0) goto err; /* no good, throw it away */ /* Decode sequence number and begin/end bits */ diff --git a/drivers/net/ppp_mppe.c b/drivers/net/ppp_mppe.c index f79cf87a2bff..c0b6d19d1457 100644 --- a/drivers/net/ppp_mppe.c +++ b/drivers/net/ppp_mppe.c @@ -136,7 +136,7 @@ struct ppp_mppe_state { * Key Derivation, from RFC 3078, RFC 3079. * Equivalent to Get_Key() for MS-CHAP as described in RFC 3079. */ -static void get_new_key_from_sha(struct ppp_mppe_state * state, unsigned char *InterimKey) +static void get_new_key_from_sha(struct ppp_mppe_state * state) { struct hash_desc desc; struct scatterlist sg[4]; @@ -153,8 +153,6 @@ static void get_new_key_from_sha(struct ppp_mppe_state * state, unsigned char *I desc.flags = 0; crypto_hash_digest(&desc, sg, nbytes, state->sha1_digest); - - memcpy(InterimKey, state->sha1_digest, state->keylen); } /* @@ -163,21 +161,21 @@ static void get_new_key_from_sha(struct ppp_mppe_state * state, unsigned char *I */ static void mppe_rekey(struct ppp_mppe_state * state, int initial_key) { - unsigned char InterimKey[MPPE_MAX_KEY_LEN]; struct scatterlist sg_in[1], sg_out[1]; struct blkcipher_desc desc = { .tfm = state->arc4 }; - get_new_key_from_sha(state, InterimKey); + get_new_key_from_sha(state); if (!initial_key) { - crypto_blkcipher_setkey(state->arc4, InterimKey, state->keylen); - setup_sg(sg_in, InterimKey, state->keylen); + crypto_blkcipher_setkey(state->arc4, state->sha1_digest, + state->keylen); + setup_sg(sg_in, state->sha1_digest, state->keylen); setup_sg(sg_out, state->session_key, state->keylen); if (crypto_blkcipher_encrypt(&desc, sg_out, sg_in, state->keylen) != 0) { printk(KERN_WARNING "mppe_rekey: cipher_encrypt failed\n"); } } else { - memcpy(state->session_key, InterimKey, state->keylen); + memcpy(state->session_key, state->sha1_digest, state->keylen); } if (state->keylen == 8) { /* See RFC 3078 */ diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c index 68631a5721ac..9b30cd600a64 100644 --- a/drivers/net/pppoe.c +++ b/drivers/net/pppoe.c @@ -385,12 +385,12 @@ static int pppoe_rcv(struct sk_buff *skb, struct pppoe_hdr *ph; struct pppox_sock *po; - if (!pskb_may_pull(skb, sizeof(struct pppoe_hdr))) - goto drop; - if (!(skb = skb_share_check(skb, GFP_ATOMIC))) goto out; + if (!pskb_may_pull(skb, sizeof(struct pppoe_hdr))) + goto drop; + ph = pppoe_hdr(skb); po = get_item((unsigned long) ph->sid, eth_hdr(skb)->h_source, dev->ifindex); @@ -848,71 +848,44 @@ static int __pppoe_xmit(struct sock *sk, struct sk_buff *skb) { struct pppox_sock *po = pppox_sk(sk); struct net_device *dev = po->pppoe_dev; - struct pppoe_hdr hdr; struct pppoe_hdr *ph; - int headroom = skb_headroom(skb); int data_len = skb->len; - struct sk_buff *skb2; if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED)) goto abort; - hdr.ver = 1; - hdr.type = 1; - hdr.code = 0; - hdr.sid = po->num; - hdr.length = htons(skb->len); - if (!dev) goto abort; - /* Copy the skb if there is no space for the header. */ - if (headroom < (sizeof(struct pppoe_hdr) + dev->hard_header_len)) { - skb2 = dev_alloc_skb(32+skb->len + - sizeof(struct pppoe_hdr) + - dev->hard_header_len); - - if (skb2 == NULL) - goto abort; - - skb_reserve(skb2, dev->hard_header_len + sizeof(struct pppoe_hdr)); - skb_copy_from_linear_data(skb, skb_put(skb2, skb->len), - skb->len); - } else { - /* Make a clone so as to not disturb the original skb, - * give dev_queue_xmit something it can free. - */ - skb2 = skb_clone(skb, GFP_ATOMIC); - - if (skb2 == NULL) - goto abort; - } + /* Copy the data if there is no space for the header or if it's + * read-only. + */ + if (skb_cow_head(skb, sizeof(*ph) + dev->hard_header_len)) + goto abort; - ph = (struct pppoe_hdr *) skb_push(skb2, sizeof(struct pppoe_hdr)); - memcpy(ph, &hdr, sizeof(struct pppoe_hdr)); - skb2->protocol = __constant_htons(ETH_P_PPP_SES); + __skb_push(skb, sizeof(*ph)); + skb_reset_network_header(skb); - skb_reset_network_header(skb2); + ph = pppoe_hdr(skb); + ph->ver = 1; + ph->type = 1; + ph->code = 0; + ph->sid = po->num; + ph->length = htons(data_len); - skb2->dev = dev; + skb->protocol = __constant_htons(ETH_P_PPP_SES); + skb->dev = dev; - dev->hard_header(skb2, dev, ETH_P_PPP_SES, + dev->hard_header(skb, dev, ETH_P_PPP_SES, po->pppoe_pa.remote, NULL, data_len); - /* We're transmitting skb2, and assuming that dev_queue_xmit - * will free it. The generic ppp layer however, is expecting - * that we give back 'skb' (not 'skb2') in case of failure, - * but free it in case of success. - */ - - if (dev_queue_xmit(skb2) < 0) - goto abort; + dev_queue_xmit(skb); - kfree_skb(skb); return 1; abort: - return 0; + kfree_skb(skb); + return 1; } diff --git a/drivers/net/pppol2tp.c b/drivers/net/pppol2tp.c index 266e8b38fe10..abe91cb595f4 100644 --- a/drivers/net/pppol2tp.c +++ b/drivers/net/pppol2tp.c @@ -491,44 +491,46 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb) u16 hdrflags; u16 tunnel_id, session_id; int length; - struct udphdr *uh; + int offset; tunnel = pppol2tp_sock_to_tunnel(sock); if (tunnel == NULL) goto error; + /* UDP always verifies the packet length. */ + __skb_pull(skb, sizeof(struct udphdr)); + /* Short packet? */ - if (skb->len < sizeof(struct udphdr)) { + if (!pskb_may_pull(skb, 12)) { PRINTK(tunnel->debug, PPPOL2TP_MSG_DATA, KERN_INFO, "%s: recv short packet (len=%d)\n", tunnel->name, skb->len); goto error; } /* Point to L2TP header */ - ptr = skb->data + sizeof(struct udphdr); + ptr = skb->data; /* Get L2TP header flags */ hdrflags = ntohs(*(__be16*)ptr); /* Trace packet contents, if enabled */ if (tunnel->debug & PPPOL2TP_MSG_DATA) { + length = min(16u, skb->len); + if (!pskb_may_pull(skb, length)) + goto error; + printk(KERN_DEBUG "%s: recv: ", tunnel->name); - for (length = 0; length < 16; length++) - printk(" %02X", ptr[length]); + offset = 0; + do { + printk(" %02X", ptr[offset]); + } while (++offset < length); + printk("\n"); } /* Get length of L2TP packet */ - uh = (struct udphdr *) skb_transport_header(skb); - length = ntohs(uh->len) - sizeof(struct udphdr); - - /* Too short? */ - if (length < 12) { - PRINTK(tunnel->debug, PPPOL2TP_MSG_DATA, KERN_INFO, - "%s: recv short L2TP packet (len=%d)\n", tunnel->name, length); - goto error; - } + length = skb->len; /* If type is control packet, it is handled by userspace. */ if (hdrflags & L2TP_HDRFLAG_T) { @@ -606,7 +608,6 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb) "%s: recv data has no seq numbers when required. " "Discarding\n", session->name); session->stats.rx_seq_discards++; - session->stats.rx_errors++; goto discard; } @@ -625,7 +626,6 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb) "%s: recv data has no seq numbers when required. " "Discarding\n", session->name); session->stats.rx_seq_discards++; - session->stats.rx_errors++; goto discard; } @@ -634,10 +634,14 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb) } /* If offset bit set, skip it. */ - if (hdrflags & L2TP_HDRFLAG_O) - ptr += 2 + ntohs(*(__be16 *) ptr); + if (hdrflags & L2TP_HDRFLAG_O) { + offset = ntohs(*(__be16 *)ptr); + skb->transport_header += 2 + offset; + if (!pskb_may_pull(skb, skb_transport_offset(skb) + 2)) + goto discard; + } - skb_pull(skb, ptr - skb->data); + __skb_pull(skb, skb_transport_offset(skb)); /* Skip PPP header, if present. In testing, Microsoft L2TP clients * don't send the PPP header (PPP header compression enabled), but @@ -673,7 +677,6 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb) */ if (PPPOL2TP_SKB_CB(skb)->ns != session->nr) { session->stats.rx_seq_discards++; - session->stats.rx_errors++; PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_DEBUG, "%s: oos pkt %hu len %d discarded, " "waiting for %hu, reorder_q_len=%d\n", @@ -698,6 +701,7 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb) return 0; discard: + session->stats.rx_errors++; kfree_skb(skb); sock_put(session->sock); @@ -958,7 +962,6 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb) int data_len = skb->len; struct inet_sock *inet; __wsum csum = 0; - struct sk_buff *skb2 = NULL; struct udphdr *uh; unsigned int len; @@ -989,41 +992,30 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb) */ headroom = NET_SKB_PAD + sizeof(struct iphdr) + sizeof(struct udphdr) + hdr_len + sizeof(ppph); - if (skb_headroom(skb) < headroom) { - skb2 = skb_realloc_headroom(skb, headroom); - if (skb2 == NULL) - goto abort; - } else - skb2 = skb; - - /* Check that the socket has room */ - if (atomic_read(&sk_tun->sk_wmem_alloc) < sk_tun->sk_sndbuf) - skb_set_owner_w(skb2, sk_tun); - else - goto discard; + if (skb_cow_head(skb, headroom)) + goto abort; /* Setup PPP header */ - skb_push(skb2, sizeof(ppph)); - skb2->data[0] = ppph[0]; - skb2->data[1] = ppph[1]; + __skb_push(skb, sizeof(ppph)); + skb->data[0] = ppph[0]; + skb->data[1] = ppph[1]; /* Setup L2TP header */ - skb_push(skb2, hdr_len); - pppol2tp_build_l2tp_header(session, skb2->data); + pppol2tp_build_l2tp_header(session, __skb_push(skb, hdr_len)); /* Setup UDP header */ inet = inet_sk(sk_tun); - skb_push(skb2, sizeof(struct udphdr)); - skb_reset_transport_header(skb2); - uh = (struct udphdr *) skb2->data; + __skb_push(skb, sizeof(*uh)); + skb_reset_transport_header(skb); + uh = udp_hdr(skb); uh->source = inet->sport; uh->dest = inet->dport; uh->len = htons(sizeof(struct udphdr) + hdr_len + sizeof(ppph) + data_len); uh->check = 0; - /* Calculate UDP checksum if configured to do so */ + /* *BROKEN* Calculate UDP checksum if configured to do so */ if (sk_tun->sk_no_check != UDP_CSUM_NOXMIT) - csum = udp_csum_outgoing(sk_tun, skb2); + csum = udp_csum_outgoing(sk_tun, skb); /* Debug */ if (session->send_seq) @@ -1036,7 +1028,7 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb) if (session->debug & PPPOL2TP_MSG_DATA) { int i; - unsigned char *datap = skb2->data; + unsigned char *datap = skb->data; printk(KERN_DEBUG "%s: xmit:", session->name); for (i = 0; i < data_len; i++) { @@ -1049,18 +1041,18 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb) printk("\n"); } - memset(&(IPCB(skb2)->opt), 0, sizeof(IPCB(skb2)->opt)); - IPCB(skb2)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED | - IPSKB_REROUTED); - nf_reset(skb2); + memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); + IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED | + IPSKB_REROUTED); + nf_reset(skb); /* Get routing info from the tunnel socket */ - dst_release(skb2->dst); - skb2->dst = sk_dst_get(sk_tun); + dst_release(skb->dst); + skb->dst = sk_dst_get(sk_tun); /* Queue the packet to IP for output */ - len = skb2->len; - rc = ip_queue_xmit(skb2, 1); + len = skb->len; + rc = ip_queue_xmit(skb, 1); /* Update stats */ if (rc >= 0) { @@ -1073,17 +1065,12 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb) session->stats.tx_errors++; } - /* Free the original skb */ - kfree_skb(skb); - return 1; -discard: - /* Free the new skb. Caller will free original skb. */ - if (skb2 != skb) - kfree_skb(skb2); abort: - return 0; + /* Free the original skb */ + kfree_skb(skb); + return 1; } /***************************************************************************** @@ -1326,12 +1313,14 @@ static struct sock *pppol2tp_prepare_tunnel_socket(int fd, u16 tunnel_id, goto err; } + sk = sock->sk; + /* Quick sanity checks */ - err = -ESOCKTNOSUPPORT; - if (sock->type != SOCK_DGRAM) { + err = -EPROTONOSUPPORT; + if (sk->sk_protocol != IPPROTO_UDP) { PRINTK(-1, PPPOL2TP_MSG_CONTROL, KERN_ERR, - "tunl %hu: fd %d wrong type, got %d, expected %d\n", - tunnel_id, fd, sock->type, SOCK_DGRAM); + "tunl %hu: fd %d wrong protocol, got %d, expected %d\n", + tunnel_id, fd, sk->sk_protocol, IPPROTO_UDP); goto err; } err = -EAFNOSUPPORT; @@ -1343,7 +1332,6 @@ static struct sock *pppol2tp_prepare_tunnel_socket(int fd, u16 tunnel_id, } err = -ENOTCONN; - sk = sock->sk; /* Check if this socket has already been prepped */ tunnel = (struct pppol2tp_tunnel *)sk->sk_user_data; diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c index 69da95b5ad0c..ea151315050c 100755 --- a/drivers/net/qla3xxx.c +++ b/drivers/net/qla3xxx.c @@ -2248,6 +2248,13 @@ static int ql_tx_rx_clean(struct ql3_adapter *qdev, qdev->rsp_consumer_index) && (work_done < work_to_do)) { net_rsp = qdev->rsp_current; + rmb(); + /* + * Fix 4032 chipe undocumented "feature" where bit-8 is set if the + * inbound completion is for a VLAN. + */ + if (qdev->device_id == QL3032_DEVICE_ID) + net_rsp->opcode &= 0x7f; switch (net_rsp->opcode) { case OPCODE_OB_MAC_IOCB_FN0: diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index b85ab4a8f2a3..c76dd29c8e9a 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -1228,7 +1228,10 @@ static void rtl8169_hw_phy_config(struct net_device *dev) return; } - /* phy config for RTL8169s mac_version C chip */ + if ((tp->mac_version != RTL_GIGA_MAC_VER_02) && + (tp->mac_version != RTL_GIGA_MAC_VER_03)) + return; + mdio_write(ioaddr, 31, 0x0001); //w 31 2 0 1 mdio_write(ioaddr, 21, 0x1000); //w 21 15 0 1000 mdio_write(ioaddr, 24, 0x65c7); //w 24 15 0 65c7 @@ -1915,7 +1918,11 @@ static void rtl_hw_start_8169(struct net_device *dev) rtl_set_rx_max_size(ioaddr); - rtl_set_rx_tx_config_registers(tp); + if ((tp->mac_version == RTL_GIGA_MAC_VER_01) || + (tp->mac_version == RTL_GIGA_MAC_VER_02) || + (tp->mac_version == RTL_GIGA_MAC_VER_03) || + (tp->mac_version == RTL_GIGA_MAC_VER_04)) + rtl_set_rx_tx_config_registers(tp); tp->cp_cmd |= rtl_rw_cpluscmd(ioaddr) | PCIMulRW; @@ -1938,6 +1945,14 @@ static void rtl_hw_start_8169(struct net_device *dev) rtl_set_rx_tx_desc_registers(tp, ioaddr); + if ((tp->mac_version != RTL_GIGA_MAC_VER_01) && + (tp->mac_version != RTL_GIGA_MAC_VER_02) && + (tp->mac_version != RTL_GIGA_MAC_VER_03) && + (tp->mac_version != RTL_GIGA_MAC_VER_04)) { + RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb); + rtl_set_rx_tx_config_registers(tp); + } + RTL_W8(Cfg9346, Cfg9346_Lock); /* Initially a 10 us delay. Turned it into a PCI commit. - FR */ @@ -1952,8 +1967,6 @@ static void rtl_hw_start_8169(struct net_device *dev) /* Enable all known interrupts by setting the interrupt mask. */ RTL_W16(IntrMask, tp->intr_event); - - RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb); } static void rtl_hw_start_8168(struct net_device *dev) @@ -2567,6 +2580,15 @@ static void rtl8169_tx_interrupt(struct net_device *dev, (TX_BUFFS_AVAIL(tp) >= MAX_SKB_FRAGS)) { netif_wake_queue(dev); } + /* + * 8168 hack: TxPoll requests are lost when the Tx packets are + * too close. Let's kick an extra TxPoll request when a burst + * of start_xmit activity is detected (if it is not detected, + * it is slow enough). -- FR + */ + smp_rmb(); + if (tp->cur_tx != dirty_tx) + RTL_W8(TxPoll, NPQ); } } diff --git a/drivers/net/sk98lin/Makefile b/drivers/net/sk98lin/Makefile new file mode 100644 index 000000000000..afd900d5d730 --- /dev/null +++ b/drivers/net/sk98lin/Makefile @@ -0,0 +1,87 @@ +# +# Makefile for the SysKonnect SK-98xx device driver. +# + + +# +# Standalone driver params +# SKPARAM += -DSK_KERNEL_24 +# SKPARAM += -DSK_KERNEL_24_26 +# SKPARAM += -DSK_KERNEL_26 +# SKPARAM += -DSK_KERNEL_22_24 + +obj-$(CONFIG_SK98LIN) += sk98lin.o +sk98lin-objs := \ + skge.o \ + skethtool.o \ + skdim.o \ + skaddr.o \ + skgehwt.o \ + skgeinit.o \ + skgepnmi.o \ + skgesirq.o \ + ski2c.o \ + sklm80.o \ + skqueue.o \ + skrlmt.o \ + sktimer.o \ + skvpd.o \ + skxmac2.o + +# DBGDEF = \ +# -DDEBUG + +ifdef DEBUG +DBGDEF += \ +-DSK_DEBUG_CHKMOD=0x00000000L \ +-DSK_DEBUG_CHKCAT=0x00000000L +endif + + +# **** possible debug modules for SK_DEBUG_CHKMOD ***************** +# SK_DBGMOD_MERR 0x00000001L /* general module error indication */ +# SK_DBGMOD_HWM 0x00000002L /* Hardware init module */ +# SK_DBGMOD_RLMT 0x00000004L /* RLMT module */ +# SK_DBGMOD_VPD 0x00000008L /* VPD module */ +# SK_DBGMOD_I2C 0x00000010L /* I2C module */ +# SK_DBGMOD_PNMI 0x00000020L /* PNMI module */ +# SK_DBGMOD_CSUM 0x00000040L /* CSUM module */ +# SK_DBGMOD_ADDR 0x00000080L /* ADDR module */ +# SK_DBGMOD_DRV 0x00010000L /* DRV module */ + +# **** possible debug categories for SK_DEBUG_CHKCAT ************** +# *** common modules *** +# SK_DBGCAT_INIT 0x00000001L module/driver initialization +# SK_DBGCAT_CTRL 0x00000002L controlling: add/rmv MCA/MAC and other controls (IOCTL) +# SK_DBGCAT_ERR 0x00000004L error handling paths +# SK_DBGCAT_TX 0x00000008L transmit path +# SK_DBGCAT_RX 0x00000010L receive path +# SK_DBGCAT_IRQ 0x00000020L general IRQ handling +# SK_DBGCAT_QUEUE 0x00000040L any queue management +# SK_DBGCAT_DUMP 0x00000080L large data output e.g. hex dump +# SK_DBGCAT_FATAL 0x00000100L large data output e.g. hex dump + +# *** driver (file skge.c) *** +# SK_DBGCAT_DRV_ENTRY 0x00010000 entry points +# SK_DBGCAT_DRV_??? 0x00020000 not used +# SK_DBGCAT_DRV_MCA 0x00040000 multicast +# SK_DBGCAT_DRV_TX_PROGRESS 0x00080000 tx path +# SK_DBGCAT_DRV_RX_PROGRESS 0x00100000 rx path +# SK_DBGCAT_DRV_PROGRESS 0x00200000 general runtime +# SK_DBGCAT_DRV_??? 0x00400000 not used +# SK_DBGCAT_DRV_PROM 0x00800000 promiscuous mode +# SK_DBGCAT_DRV_TX_FRAME 0x01000000 display tx frames +# SK_DBGCAT_DRV_ERROR 0x02000000 error conditions +# SK_DBGCAT_DRV_INT_SRC 0x04000000 interrupts sources +# SK_DBGCAT_DRV_EVENT 0x08000000 driver events + +EXTRA_CFLAGS += -Idrivers/net/sk98lin -DSK_DIAG_SUPPORT -DGENESIS -DYUKON $(DBGDEF) $(SKPARAM) + +clean: + rm -f core *.o *.a *.s + + + + + + diff --git a/drivers/net/sk98lin/h/lm80.h b/drivers/net/sk98lin/h/lm80.h new file mode 100644 index 000000000000..4e2dbbf78000 --- /dev/null +++ b/drivers/net/sk98lin/h/lm80.h @@ -0,0 +1,179 @@ +/****************************************************************************** + * + * Name: lm80.h + * Project: Gigabit Ethernet Adapters, Common Modules + * Version: $Revision: 1.6 $ + * Date: $Date: 2003/05/13 17:26:52 $ + * Purpose: Contains all defines for the LM80 Chip + * (National Semiconductor). + * + ******************************************************************************/ + +/****************************************************************************** + * + * (C)Copyright 1998-2002 SysKonnect. + * (C)Copyright 2002-2003 Marvell. + * + * 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. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +#ifndef __INC_LM80_H +#define __INC_LM80_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* defines ********************************************************************/ + +/* + * LM80 register definition + * + * All registers are 8 bit wide + */ +#define LM80_CFG 0x00 /* Configuration Register */ +#define LM80_ISRC_1 0x01 /* Interrupt Status Register 1 */ +#define LM80_ISRC_2 0x02 /* Interrupt Status Register 2 */ +#define LM80_IMSK_1 0x03 /* Interrupt Mask Register 1 */ +#define LM80_IMSK_2 0x04 /* Interrupt Mask Register 2 */ +#define LM80_FAN_CTRL 0x05 /* Fan Devisor/RST#/OS# Register */ +#define LM80_TEMP_CTRL 0x06 /* OS# Config, Temp Res. Reg */ + /* 0x07 - 0x1f reserved */ + /* current values */ +#define LM80_VT0_IN 0x20 /* current Voltage 0 value */ +#define LM80_VT1_IN 0x21 /* current Voltage 1 value */ +#define LM80_VT2_IN 0x22 /* current Voltage 2 value */ +#define LM80_VT3_IN 0x23 /* current Voltage 3 value */ +#define LM80_VT4_IN 0x24 /* current Voltage 4 value */ +#define LM80_VT5_IN 0x25 /* current Voltage 5 value */ +#define LM80_VT6_IN 0x26 /* current Voltage 6 value */ +#define LM80_TEMP_IN 0x27 /* current Temperature value */ +#define LM80_FAN1_IN 0x28 /* current Fan 1 count */ +#define LM80_FAN2_IN 0x29 /* current Fan 2 count */ + /* limit values */ +#define LM80_VT0_HIGH_LIM 0x2a /* high limit val for Voltage 0 */ +#define LM80_VT0_LOW_LIM 0x2b /* low limit val for Voltage 0 */ +#define LM80_VT1_HIGH_LIM 0x2c /* high limit val for Voltage 1 */ +#define LM80_VT1_LOW_LIM 0x2d /* low limit val for Voltage 1 */ +#define LM80_VT2_HIGH_LIM 0x2e /* high limit val for Voltage 2 */ +#define LM80_VT2_LOW_LIM 0x2f /* low limit val for Voltage 2 */ +#define LM80_VT3_HIGH_LIM 0x30 /* high limit val for Voltage 3 */ +#define LM80_VT3_LOW_LIM 0x31 /* low limit val for Voltage 3 */ +#define LM80_VT4_HIGH_LIM 0x32 /* high limit val for Voltage 4 */ +#define LM80_VT4_LOW_LIM 0x33 /* low limit val for Voltage 4 */ +#define LM80_VT5_HIGH_LIM 0x34 /* high limit val for Voltage 5 */ +#define LM80_VT5_LOW_LIM 0x35 /* low limit val for Voltage 5 */ +#define LM80_VT6_HIGH_LIM 0x36 /* high limit val for Voltage 6 */ +#define LM80_VT6_LOW_LIM 0x37 /* low limit val for Voltage 6 */ +#define LM80_THOT_LIM_UP 0x38 /* hot temperature limit (high) */ +#define LM80_THOT_LIM_LO 0x39 /* hot temperature limit (low) */ +#define LM80_TOS_LIM_UP 0x3a /* OS temperature limit (high) */ +#define LM80_TOS_LIM_LO 0x3b /* OS temperature limit (low) */ +#define LM80_FAN1_COUNT_LIM 0x3c /* Fan 1 count limit (high) */ +#define LM80_FAN2_COUNT_LIM 0x3d /* Fan 2 count limit (low) */ + /* 0x3e - 0x3f reserved */ + +/* + * LM80 bit definitions + */ + +/* LM80_CFG Configuration Register */ +#define LM80_CFG_START (1<<0) /* start monitoring operation */ +#define LM80_CFG_INT_ENA (1<<1) /* enables the INT# Interrupt output */ +#define LM80_CFG_INT_POL (1<<2) /* INT# pol: 0 act low, 1 act high */ +#define LM80_CFG_INT_CLR (1<<3) /* disables INT#/RST_OUT#/OS# outputs */ +#define LM80_CFG_RESET (1<<4) /* signals a reset */ +#define LM80_CFG_CHASS_CLR (1<<5) /* clears Chassis Intrusion (CI) pin */ +#define LM80_CFG_GPO (1<<6) /* drives the GPO# pin */ +#define LM80_CFG_INIT (1<<7) /* restore power on defaults */ + +/* LM80_ISRC_1 Interrupt Status Register 1 */ +/* LM80_IMSK_1 Interrupt Mask Register 1 */ +#define LM80_IS_VT0 (1<<0) /* limit exceeded for Voltage 0 */ +#define LM80_IS_VT1 (1<<1) /* limit exceeded for Voltage 1 */ +#define LM80_IS_VT2 (1<<2) /* limit exceeded for Voltage 2 */ +#define LM80_IS_VT3 (1<<3) /* limit exceeded for Voltage 3 */ +#define LM80_IS_VT4 (1<<4) /* limit exceeded for Voltage 4 */ +#define LM80_IS_VT5 (1<<5) /* limit exceeded for Voltage 5 */ +#define LM80_IS_VT6 (1<<6) /* limit exceeded for Voltage 6 */ +#define LM80_IS_INT_IN (1<<7) /* state of INT_IN# */ + +/* LM80_ISRC_2 Interrupt Status Register 2 */ +/* LM80_IMSK_2 Interrupt Mask Register 2 */ +#define LM80_IS_TEMP (1<<0) /* HOT temperature limit exceeded */ +#define LM80_IS_BTI (1<<1) /* state of BTI# pin */ +#define LM80_IS_FAN1 (1<<2) /* count limit exceeded for Fan 1 */ +#define LM80_IS_FAN2 (1<<3) /* count limit exceeded for Fan 2 */ +#define LM80_IS_CI (1<<4) /* Chassis Intrusion occured */ +#define LM80_IS_OS (1<<5) /* OS temperature limit exceeded */ + /* bit 6 and 7 are reserved in LM80_ISRC_2 */ +#define LM80_IS_HT_IRQ_MD (1<<6) /* Hot temperature interrupt mode */ +#define LM80_IS_OT_IRQ_MD (1<<7) /* OS temperature interrupt mode */ + +/* LM80_FAN_CTRL Fan Devisor/RST#/OS# Register */ +#define LM80_FAN1_MD_SEL (1<<0) /* Fan 1 mode select */ +#define LM80_FAN2_MD_SEL (1<<1) /* Fan 2 mode select */ +#define LM80_FAN1_PRM_CTL (3<<2) /* Fan 1 speed control */ +#define LM80_FAN2_PRM_CTL (3<<4) /* Fan 2 speed control */ +#define LM80_FAN_OS_ENA (1<<6) /* enable OS mode on RST_OUT#/OS# pins*/ +#define LM80_FAN_RST_ENA (1<<7) /* sets RST_OUT#/OS# pins in RST mode */ + +/* LM80_TEMP_CTRL OS# Config, Temp Res. Reg */ +#define LM80_TEMP_OS_STAT (1<<0) /* mirrors the state of RST_OUT#/OS# */ +#define LM80_TEMP_OS_POL (1<<1) /* select OS# polarity */ +#define LM80_TEMP_OS_MODE (1<<2) /* selects Interrupt mode */ +#define LM80_TEMP_RES (1<<3) /* selects 9 or 11 bit temp resulution*/ +#define LM80_TEMP_LSB (0xf<<4)/* 4 LSBs of 11 bit temp data */ +#define LM80_TEMP_LSB_9 (1<<7) /* LSB of 9 bit temperature data */ + + /* 0x07 - 0x1f reserved */ +/* LM80_VT0_IN current Voltage 0 value */ +/* LM80_VT1_IN current Voltage 1 value */ +/* LM80_VT2_IN current Voltage 2 value */ +/* LM80_VT3_IN current Voltage 3 value */ +/* LM80_VT4_IN current Voltage 4 value */ +/* LM80_VT5_IN current Voltage 5 value */ +/* LM80_VT6_IN current Voltage 6 value */ +/* LM80_TEMP_IN current temperature value */ +/* LM80_FAN1_IN current Fan 1 count */ +/* LM80_FAN2_IN current Fan 2 count */ +/* LM80_VT0_HIGH_LIM high limit val for Voltage 0 */ +/* LM80_VT0_LOW_LIM low limit val for Voltage 0 */ +/* LM80_VT1_HIGH_LIM high limit val for Voltage 1 */ +/* LM80_VT1_LOW_LIM low limit val for Voltage 1 */ +/* LM80_VT2_HIGH_LIM high limit val for Voltage 2 */ +/* LM80_VT2_LOW_LIM low limit val for Voltage 2 */ +/* LM80_VT3_HIGH_LIM high limit val for Voltage 3 */ +/* LM80_VT3_LOW_LIM low limit val for Voltage 3 */ +/* LM80_VT4_HIGH_LIM high limit val for Voltage 4 */ +/* LM80_VT4_LOW_LIM low limit val for Voltage 4 */ +/* LM80_VT5_HIGH_LIM high limit val for Voltage 5 */ +/* LM80_VT5_LOW_LIM low limit val for Voltage 5 */ +/* LM80_VT6_HIGH_LIM high limit val for Voltage 6 */ +/* LM80_VT6_LOW_LIM low limit val for Voltage 6 */ +/* LM80_THOT_LIM_UP hot temperature limit (high) */ +/* LM80_THOT_LIM_LO hot temperature limit (low) */ +/* LM80_TOS_LIM_UP OS temperature limit (high) */ +/* LM80_TOS_LIM_LO OS temperature limit (low) */ +/* LM80_FAN1_COUNT_LIM Fan 1 count limit (high) */ +/* LM80_FAN2_COUNT_LIM Fan 2 count limit (low) */ + /* 0x3e - 0x3f reserved */ + +#define LM80_ADDR 0x28 /* LM80 default addr */ + +/* typedefs *******************************************************************/ + + +/* function prototypes ********************************************************/ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __INC_LM80_H */ diff --git a/drivers/net/sk98lin/h/skaddr.h b/drivers/net/sk98lin/h/skaddr.h new file mode 100644 index 000000000000..423ad063d09b --- /dev/null +++ b/drivers/net/sk98lin/h/skaddr.h @@ -0,0 +1,285 @@ +/****************************************************************************** + * + * Name: skaddr.h + * Project: Gigabit Ethernet Adapters, ADDR-Modul + * Version: $Revision: 1.29 $ + * Date: $Date: 2003/05/13 16:57:24 $ + * Purpose: Header file for Address Management (MC, UC, Prom). + * + ******************************************************************************/ + +/****************************************************************************** + * + * (C)Copyright 1998-2002 SysKonnect GmbH. + * (C)Copyright 2002-2003 Marvell. + * + * 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. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/****************************************************************************** + * + * Description: + * + * This module is intended to manage multicast addresses and promiscuous mode + * on GEnesis adapters. + * + * Include File Hierarchy: + * + * "skdrv1st.h" + * ... + * "sktypes.h" + * "skqueue.h" + * "skaddr.h" + * ... + * "skdrv2nd.h" + * + ******************************************************************************/ + +#ifndef __INC_SKADDR_H +#define __INC_SKADDR_H + +#ifdef __cplusplus +extern "C" { +#endif /* cplusplus */ + +/* defines ********************************************************************/ + +#define SK_MAC_ADDR_LEN 6 /* Length of MAC address. */ +#define SK_MAX_ADDRS 14 /* #Addrs for exact match. */ + +/* ----- Common return values ----- */ + +#define SK_ADDR_SUCCESS 0 /* Function returned successfully. */ +#define SK_ADDR_ILLEGAL_PORT 100 /* Port number too high. */ +#define SK_ADDR_TOO_EARLY 101 /* Function called too early. */ + +/* ----- Clear/Add flag bits ----- */ + +#define SK_ADDR_PERMANENT 1 /* RLMT Address */ + +/* ----- Additional Clear flag bits ----- */ + +#define SK_MC_SW_ONLY 2 /* Do not update HW when clearing. */ + +/* ----- Override flag bits ----- */ + +#define SK_ADDR_LOGICAL_ADDRESS 0 +#define SK_ADDR_VIRTUAL_ADDRESS (SK_ADDR_LOGICAL_ADDRESS) /* old */ +#define SK_ADDR_PHYSICAL_ADDRESS 1 +#define SK_ADDR_CLEAR_LOGICAL 2 +#define SK_ADDR_SET_LOGICAL 4 + +/* ----- Override return values ----- */ + +#define SK_ADDR_OVERRIDE_SUCCESS (SK_ADDR_SUCCESS) +#define SK_ADDR_DUPLICATE_ADDRESS 1 +#define SK_ADDR_MULTICAST_ADDRESS 2 + +/* ----- Partitioning of excact match table ----- */ + +#define SK_ADDR_EXACT_MATCHES 16 /* #Exact match entries. */ + +#define SK_ADDR_FIRST_MATCH_RLMT 1 +#define SK_ADDR_LAST_MATCH_RLMT 2 +#define SK_ADDR_FIRST_MATCH_DRV 3 +#define SK_ADDR_LAST_MATCH_DRV (SK_ADDR_EXACT_MATCHES - 1) + +/* ----- SkAddrMcAdd/SkAddrMcUpdate return values ----- */ + +#define SK_MC_FILTERING_EXACT 0 /* Exact filtering. */ +#define SK_MC_FILTERING_INEXACT 1 /* Inexact filtering. */ + +/* ----- Additional SkAddrMcAdd return values ----- */ + +#define SK_MC_ILLEGAL_ADDRESS 2 /* Illegal address. */ +#define SK_MC_ILLEGAL_PORT 3 /* Illegal port (not the active one). */ +#define SK_MC_RLMT_OVERFLOW 4 /* Too many RLMT mc addresses. */ + +/* Promiscuous mode bits ----- */ + +#define SK_PROM_MODE_NONE 0 /* Normal receive. */ +#define SK_PROM_MODE_LLC 1 /* Receive all LLC frames. */ +#define SK_PROM_MODE_ALL_MC 2 /* Receive all multicast frames. */ +/* #define SK_PROM_MODE_NON_LLC 4 */ /* Receive all non-LLC frames. */ + +/* Macros */ + +#ifdef OLD_STUFF +#ifndef SK_ADDR_EQUAL +/* + * "&" instead of "&&" allows better optimization on IA-64. + * The replacement is safe here, as all bytes exist. + */ +#ifndef SK_ADDR_DWORD_COMPARE +#define SK_ADDR_EQUAL(A1,A2) ( \ + (((SK_U8 *)(A1))[5] == ((SK_U8 *)(A2))[5]) & \ + (((SK_U8 *)(A1))[4] == ((SK_U8 *)(A2))[4]) & \ + (((SK_U8 *)(A1))[3] == ((SK_U8 *)(A2))[3]) & \ + (((SK_U8 *)(A1))[2] == ((SK_U8 *)(A2))[2]) & \ + (((SK_U8 *)(A1))[1] == ((SK_U8 *)(A2))[1]) & \ + (((SK_U8 *)(A1))[0] == ((SK_U8 *)(A2))[0])) +#else /* SK_ADDR_DWORD_COMPARE */ +#define SK_ADDR_EQUAL(A1,A2) ( \ + (*(SK_U32 *)&(((SK_U8 *)(A1))[2]) == *(SK_U32 *)&(((SK_U8 *)(A2))[2])) & \ + (*(SK_U32 *)&(((SK_U8 *)(A1))[0]) == *(SK_U32 *)&(((SK_U8 *)(A2))[0]))) +#endif /* SK_ADDR_DWORD_COMPARE */ +#endif /* SK_ADDR_EQUAL */ +#endif /* 0 */ + +#ifndef SK_ADDR_EQUAL +#ifndef SK_ADDR_DWORD_COMPARE +#define SK_ADDR_EQUAL(A1,A2) ( \ + (((SK_U8 SK_FAR *)(A1))[5] == ((SK_U8 SK_FAR *)(A2))[5]) & \ + (((SK_U8 SK_FAR *)(A1))[4] == ((SK_U8 SK_FAR *)(A2))[4]) & \ + (((SK_U8 SK_FAR *)(A1))[3] == ((SK_U8 SK_FAR *)(A2))[3]) & \ + (((SK_U8 SK_FAR *)(A1))[2] == ((SK_U8 SK_FAR *)(A2))[2]) & \ + (((SK_U8 SK_FAR *)(A1))[1] == ((SK_U8 SK_FAR *)(A2))[1]) & \ + (((SK_U8 SK_FAR *)(A1))[0] == ((SK_U8 SK_FAR *)(A2))[0])) +#else /* SK_ADDR_DWORD_COMPARE */ +#define SK_ADDR_EQUAL(A1,A2) ( \ + (*(SK_U16 SK_FAR *)&(((SK_U8 SK_FAR *)(A1))[4]) == \ + *(SK_U16 SK_FAR *)&(((SK_U8 SK_FAR *)(A2))[4])) && \ + (*(SK_U32 SK_FAR *)&(((SK_U8 SK_FAR *)(A1))[0]) == \ + *(SK_U32 SK_FAR *)&(((SK_U8 SK_FAR *)(A2))[0]))) +#endif /* SK_ADDR_DWORD_COMPARE */ +#endif /* SK_ADDR_EQUAL */ + +/* typedefs *******************************************************************/ + +typedef struct s_MacAddr { + SK_U8 a[SK_MAC_ADDR_LEN]; +} SK_MAC_ADDR; + + +/* SK_FILTER is used to ensure alignment of the filter. */ +typedef union s_InexactFilter { + SK_U8 Bytes[8]; + SK_U64 Val; /* Dummy entry for alignment only. */ +} SK_FILTER64; + + +typedef struct s_AddrNet SK_ADDR_NET; + + +typedef struct s_AddrPort { + +/* ----- Public part (read-only) ----- */ + + SK_MAC_ADDR CurrentMacAddress; /* Current physical MAC Address. */ + SK_MAC_ADDR PermanentMacAddress; /* Permanent physical MAC Address. */ + int PromMode; /* Promiscuous Mode. */ + +/* ----- Private part ----- */ + + SK_MAC_ADDR PreviousMacAddress; /* Prev. phys. MAC Address. */ + SK_BOOL CurrentMacAddressSet; /* CurrentMacAddress is set. */ + SK_U8 Align01; + + SK_U32 FirstExactMatchRlmt; + SK_U32 NextExactMatchRlmt; + SK_U32 FirstExactMatchDrv; + SK_U32 NextExactMatchDrv; + SK_MAC_ADDR Exact[SK_ADDR_EXACT_MATCHES]; + SK_FILTER64 InexactFilter; /* For 64-bit hash register. */ + SK_FILTER64 InexactRlmtFilter; /* For 64-bit hash register. */ + SK_FILTER64 InexactDrvFilter; /* For 64-bit hash register. */ +} SK_ADDR_PORT; + + +struct s_AddrNet { +/* ----- Public part (read-only) ----- */ + + SK_MAC_ADDR CurrentMacAddress; /* Logical MAC Address. */ + SK_MAC_ADDR PermanentMacAddress; /* Logical MAC Address. */ + +/* ----- Private part ----- */ + + SK_U32 ActivePort; /* View of module ADDR. */ + SK_BOOL CurrentMacAddressSet; /* CurrentMacAddress is set. */ + SK_U8 Align01; + SK_U16 Align02; +}; + + +typedef struct s_Addr { + +/* ----- Public part (read-only) ----- */ + + SK_ADDR_NET Net[SK_MAX_NETS]; + SK_ADDR_PORT Port[SK_MAX_MACS]; + +/* ----- Private part ----- */ +} SK_ADDR; + +/* function prototypes ********************************************************/ + +#ifndef SK_KR_PROTO + +/* Functions provided by SkAddr */ + +/* ANSI/C++ compliant function prototypes */ + +extern int SkAddrInit( + SK_AC *pAC, + SK_IOC IoC, + int Level); + +extern int SkAddrMcClear( + SK_AC *pAC, + SK_IOC IoC, + SK_U32 PortNumber, + int Flags); + +extern int SkAddrMcAdd( + SK_AC *pAC, + SK_IOC IoC, + SK_U32 PortNumber, + SK_MAC_ADDR *pMc, + int Flags); + +extern int SkAddrMcUpdate( + SK_AC *pAC, + SK_IOC IoC, + SK_U32 PortNumber); + +extern int SkAddrOverride( + SK_AC *pAC, + SK_IOC IoC, + SK_U32 PortNumber, + SK_MAC_ADDR SK_FAR *pNewAddr, + int Flags); + +extern int SkAddrPromiscuousChange( + SK_AC *pAC, + SK_IOC IoC, + SK_U32 PortNumber, + int NewPromMode); + +#ifndef SK_SLIM +extern int SkAddrSwap( + SK_AC *pAC, + SK_IOC IoC, + SK_U32 FromPortNumber, + SK_U32 ToPortNumber); +#endif + +#else /* defined(SK_KR_PROTO)) */ + +/* Non-ANSI/C++ compliant function prototypes */ + +#error KR-style prototypes are not yet provided. + +#endif /* defined(SK_KR_PROTO)) */ + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __INC_SKADDR_H */ diff --git a/drivers/net/sk98lin/h/skcsum.h b/drivers/net/sk98lin/h/skcsum.h new file mode 100644 index 000000000000..6e256bd9a28c --- /dev/null +++ b/drivers/net/sk98lin/h/skcsum.h @@ -0,0 +1,213 @@ +/****************************************************************************** + * + * Name: skcsum.h + * Project: GEnesis - SysKonnect SK-NET Gigabit Ethernet (SK-98xx) + * Version: $Revision: 1.10 $ + * Date: $Date: 2003/08/20 13:59:57 $ + * Purpose: Store/verify Internet checksum in send/receive packets. + * + ******************************************************************************/ + +/****************************************************************************** + * + * (C)Copyright 1998-2001 SysKonnect GmbH. + * + * 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. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/****************************************************************************** + * + * Description: + * + * Public header file for the "GEnesis" common module "CSUM". + * + * "GEnesis" is an abbreviation of "Gigabit Ethernet Network System in Silicon" + * and is the code name of this SysKonnect project. + * + * Compilation Options: + * + * SK_USE_CSUM - Define if CSUM is to be used. Otherwise, CSUM will be an + * empty module. + * + * SKCS_OVERWRITE_PROTO - Define to overwrite the default protocol id + * definitions. In this case, all SKCS_PROTO_xxx definitions must be made + * external. + * + * SKCS_OVERWRITE_STATUS - Define to overwrite the default return status + * definitions. In this case, all SKCS_STATUS_xxx definitions must be made + * external. + * + * Include File Hierarchy: + * + * "h/skcsum.h" + * "h/sktypes.h" + * "h/skqueue.h" + * + ******************************************************************************/ + +#ifndef __INC_SKCSUM_H +#define __INC_SKCSUM_H + +#include "h/sktypes.h" +#include "h/skqueue.h" + +/* defines ********************************************************************/ + +/* + * Define the default bit flags for 'SKCS_PACKET_INFO.ProtocolFlags' if no user + * overwrite. + */ +#ifndef SKCS_OVERWRITE_PROTO /* User overwrite? */ +#define SKCS_PROTO_IP 0x1 /* IP (Internet Protocol version 4) */ +#define SKCS_PROTO_TCP 0x2 /* TCP (Transmission Control Protocol) */ +#define SKCS_PROTO_UDP 0x4 /* UDP (User Datagram Protocol) */ + +/* Indices for protocol statistics. */ +#define SKCS_PROTO_STATS_IP 0 +#define SKCS_PROTO_STATS_UDP 1 +#define SKCS_PROTO_STATS_TCP 2 +#define SKCS_NUM_PROTOCOLS 3 /* Number of supported protocols. */ +#endif /* !SKCS_OVERWRITE_PROTO */ + +/* + * Define the default SKCS_STATUS type and values if no user overwrite. + * + * SKCS_STATUS_UNKNOWN_IP_VERSION - Not an IP v4 frame. + * SKCS_STATUS_IP_CSUM_ERROR - IP checksum error. + * SKCS_STATUS_IP_CSUM_ERROR_TCP - IP checksum error in TCP frame. + * SKCS_STATUS_IP_CSUM_ERROR_UDP - IP checksum error in UDP frame + * SKCS_STATUS_IP_FRAGMENT - IP fragment (IP checksum ok). + * SKCS_STATUS_IP_CSUM_OK - IP checksum ok (not a TCP or UDP frame). + * SKCS_STATUS_TCP_CSUM_ERROR - TCP checksum error (IP checksum ok). + * SKCS_STATUS_UDP_CSUM_ERROR - UDP checksum error (IP checksum ok). + * SKCS_STATUS_TCP_CSUM_OK - IP and TCP checksum ok. + * SKCS_STATUS_UDP_CSUM_OK - IP and UDP checksum ok. + * SKCS_STATUS_IP_CSUM_OK_NO_UDP - IP checksum OK and no UDP checksum. + */ +#ifndef SKCS_OVERWRITE_STATUS /* User overwrite? */ +#define SKCS_STATUS int /* Define status type. */ + +#define SKCS_STATUS_UNKNOWN_IP_VERSION 1 +#define SKCS_STATUS_IP_CSUM_ERROR 2 +#define SKCS_STATUS_IP_FRAGMENT 3 +#define SKCS_STATUS_IP_CSUM_OK 4 +#define SKCS_STATUS_TCP_CSUM_ERROR 5 +#define SKCS_STATUS_UDP_CSUM_ERROR 6 +#define SKCS_STATUS_TCP_CSUM_OK 7 +#define SKCS_STATUS_UDP_CSUM_OK 8 +/* needed for Microsoft */ +#define SKCS_STATUS_IP_CSUM_ERROR_UDP 9 +#define SKCS_STATUS_IP_CSUM_ERROR_TCP 10 +/* UDP checksum may be omitted */ +#define SKCS_STATUS_IP_CSUM_OK_NO_UDP 11 +#endif /* !SKCS_OVERWRITE_STATUS */ + +/* Clear protocol statistics event. */ +#define SK_CSUM_EVENT_CLEAR_PROTO_STATS 1 + +/* + * Add two values in one's complement. + * + * Note: One of the two input values may be "longer" than 16-bit, but then the + * resulting sum may be 17 bits long. In this case, add zero to the result using + * SKCS_OC_ADD() again. + * + * Result = Value1 + Value2 + */ +#define SKCS_OC_ADD(Result, Value1, Value2) { \ + unsigned long Sum; \ + \ + Sum = (unsigned long) (Value1) + (unsigned long) (Value2); \ + /* Add-in any carry. */ \ + (Result) = (Sum & 0xffff) + (Sum >> 16); \ +} + +/* + * Subtract two values in one's complement. + * + * Result = Value1 - Value2 + */ +#define SKCS_OC_SUB(Result, Value1, Value2) \ + SKCS_OC_ADD((Result), (Value1), ~(Value2) & 0xffff) + +/* typedefs *******************************************************************/ + +/* + * SKCS_PROTO_STATS - The CSUM protocol statistics structure. + * + * There is one instance of this structure for each protocol supported. + */ +typedef struct s_CsProtocolStatistics { + SK_U64 RxOkCts; /* Receive checksum ok. */ + SK_U64 RxUnableCts; /* Unable to verify receive checksum. */ + SK_U64 RxErrCts; /* Receive checksum error. */ + SK_U64 TxOkCts; /* Transmit checksum ok. */ + SK_U64 TxUnableCts; /* Unable to calculate checksum in hw. */ +} SKCS_PROTO_STATS; + +/* + * s_Csum - The CSUM module context structure. + */ +typedef struct s_Csum { + /* Enabled receive SK_PROTO_XXX bit flags. */ + unsigned ReceiveFlags[SK_MAX_NETS]; +#ifdef TX_CSUM + unsigned TransmitFlags[SK_MAX_NETS]; +#endif /* TX_CSUM */ + + /* The protocol statistics structure; one per supported protocol. */ + SKCS_PROTO_STATS ProtoStats[SK_MAX_NETS][SKCS_NUM_PROTOCOLS]; +} SK_CSUM; + +/* + * SKCS_PACKET_INFO - The packet information structure. + */ +typedef struct s_CsPacketInfo { + /* Bit field specifiying the desired/found protocols. */ + unsigned ProtocolFlags; + + /* Length of complete IP header, including any option fields. */ + unsigned IpHeaderLength; + + /* IP header checksum. */ + unsigned IpHeaderChecksum; + + /* TCP/UDP pseudo header checksum. */ + unsigned PseudoHeaderChecksum; +} SKCS_PACKET_INFO; + +/* function prototypes ********************************************************/ + +#ifndef SK_CS_CALCULATE_CHECKSUM +extern unsigned SkCsCalculateChecksum( + void *pData, + unsigned Length); +#endif /* SK_CS_CALCULATE_CHECKSUM */ + +extern int SkCsEvent( + SK_AC *pAc, + SK_IOC Ioc, + SK_U32 Event, + SK_EVPARA Param); + +extern SKCS_STATUS SkCsGetReceiveInfo( + SK_AC *pAc, + void *pIpHeader, + unsigned Checksum1, + unsigned Checksum2, + int NetNumber); + +extern void SkCsSetReceiveFlags( + SK_AC *pAc, + unsigned ReceiveFlags, + unsigned *pChecksum1Offset, + unsigned *pChecksum2Offset, + int NetNumber); + +#endif /* __INC_SKCSUM_H */ diff --git a/drivers/net/sk98lin/h/skdebug.h b/drivers/net/sk98lin/h/skdebug.h new file mode 100644 index 000000000000..3cba171d74b2 --- /dev/null +++ b/drivers/net/sk98lin/h/skdebug.h @@ -0,0 +1,74 @@ +/****************************************************************************** + * + * Name: skdebug.h + * Project: Gigabit Ethernet Adapters, Common Modules + * Version: $Revision: 1.14 $ + * Date: $Date: 2003/05/13 17:26:00 $ + * Purpose: SK specific DEBUG support + * + ******************************************************************************/ + +/****************************************************************************** + * + * (C)Copyright 1998-2002 SysKonnect. + * (C)Copyright 2002-2003 Marvell. + * + * 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. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +#ifndef __INC_SKDEBUG_H +#define __INC_SKDEBUG_H + +#ifdef DEBUG +#ifndef SK_DBG_MSG +#define SK_DBG_MSG(pAC,comp,cat,arg) \ + if ( ((comp) & SK_DBG_CHKMOD(pAC)) && \ + ((cat) & SK_DBG_CHKCAT(pAC)) ) { \ + SK_DBG_PRINTF arg ; \ + } +#endif +#else +#define SK_DBG_MSG(pAC,comp,lev,arg) +#endif + +/* PLS NOTE: + * ========= + * Due to any restrictions of kernel printf routines do not use other + * format identifiers as: %x %d %c %s . + * Never use any combined format identifiers such as: %lx %ld in your + * printf - argument (arg) because some OS specific kernel printfs may + * only support some basic identifiers. + */ + +/* Debug modules */ + +#define SK_DBGMOD_MERR 0x00000001L /* general module error indication */ +#define SK_DBGMOD_HWM 0x00000002L /* Hardware init module */ +#define SK_DBGMOD_RLMT 0x00000004L /* RLMT module */ +#define SK_DBGMOD_VPD 0x00000008L /* VPD module */ +#define SK_DBGMOD_I2C 0x00000010L /* I2C module */ +#define SK_DBGMOD_PNMI 0x00000020L /* PNMI module */ +#define SK_DBGMOD_CSUM 0x00000040L /* CSUM module */ +#define SK_DBGMOD_ADDR 0x00000080L /* ADDR module */ +#define SK_DBGMOD_PECP 0x00000100L /* PECP module */ +#define SK_DBGMOD_POWM 0x00000200L /* Power Management module */ + +/* Debug events */ + +#define SK_DBGCAT_INIT 0x00000001L /* module/driver initialization */ +#define SK_DBGCAT_CTRL 0x00000002L /* controlling devices */ +#define SK_DBGCAT_ERR 0x00000004L /* error handling paths */ +#define SK_DBGCAT_TX 0x00000008L /* transmit path */ +#define SK_DBGCAT_RX 0x00000010L /* receive path */ +#define SK_DBGCAT_IRQ 0x00000020L /* general IRQ handling */ +#define SK_DBGCAT_QUEUE 0x00000040L /* any queue management */ +#define SK_DBGCAT_DUMP 0x00000080L /* large data output e.g. hex dump */ +#define SK_DBGCAT_FATAL 0x00000100L /* fatal error */ + +#endif /* __INC_SKDEBUG_H */ diff --git a/drivers/net/sk98lin/h/skdrv1st.h b/drivers/net/sk98lin/h/skdrv1st.h new file mode 100644 index 000000000000..91b8d4f45904 --- /dev/null +++ b/drivers/net/sk98lin/h/skdrv1st.h @@ -0,0 +1,188 @@ +/****************************************************************************** + * + * Name: skdrv1st.h + * Project: GEnesis, PCI Gigabit Ethernet Adapter + * Version: $Revision: 1.4 $ + * Date: $Date: 2003/11/12 14:28:14 $ + * Purpose: First header file for driver and all other modules + * + ******************************************************************************/ + +/****************************************************************************** + * + * (C)Copyright 1998-2002 SysKonnect GmbH. + * (C)Copyright 2002-2003 Marvell. + * + * 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. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/****************************************************************************** + * + * Description: + * + * This is the first include file of the driver, which includes all + * neccessary system header files and some of the GEnesis header files. + * It also defines some basic items. + * + * Include File Hierarchy: + * + * see skge.c + * + ******************************************************************************/ + +#ifndef __INC_SKDRV1ST_H +#define __INC_SKDRV1ST_H + +typedef struct s_AC SK_AC; + +/* Set card versions */ +#define SK_FAR + +/* override some default functions with optimized linux functions */ + +#define SK_PNMI_STORE_U16(p,v) memcpy((char*)(p),(char*)&(v),2) +#define SK_PNMI_STORE_U32(p,v) memcpy((char*)(p),(char*)&(v),4) +#define SK_PNMI_STORE_U64(p,v) memcpy((char*)(p),(char*)&(v),8) +#define SK_PNMI_READ_U16(p,v) memcpy((char*)&(v),(char*)(p),2) +#define SK_PNMI_READ_U32(p,v) memcpy((char*)&(v),(char*)(p),4) +#define SK_PNMI_READ_U64(p,v) memcpy((char*)&(v),(char*)(p),8) + +#define SK_ADDR_EQUAL(a1,a2) (!memcmp(a1,a2,6)) + +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/errno.h> +#include <linux/ioport.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/pci.h> +#include <linux/bitops.h> +#include <asm/byteorder.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> + +#include <linux/init.h> +#include <asm/uaccess.h> +#include <net/checksum.h> + +#define SK_CS_CALCULATE_CHECKSUM +#ifndef CONFIG_X86_64 +#define SkCsCalculateChecksum(p,l) ((~ip_compute_csum(p, l)) & 0xffff) +#else +#define SkCsCalculateChecksum(p,l) ((~ip_fast_csum(p, l)) & 0xffff) +#endif + +#include "h/sktypes.h" +#include "h/skerror.h" +#include "h/skdebug.h" +#include "h/lm80.h" +#include "h/xmac_ii.h" + +#ifdef __LITTLE_ENDIAN +#define SK_LITTLE_ENDIAN +#else +#define SK_BIG_ENDIAN +#endif + +#define SK_NET_DEVICE net_device + + +/* we use gethrtime(), return unit: nanoseconds */ +#define SK_TICKS_PER_SEC 100 + +#define SK_MEM_MAPPED_IO + +// #define SK_RLMT_SLOW_LOOKAHEAD + +#define SK_MAX_MACS 2 +#define SK_MAX_NETS 2 + +#define SK_IOC char __iomem * + +typedef struct s_DrvRlmtMbuf SK_MBUF; + +#define SK_CONST64 INT64_C +#define SK_CONSTU64 UINT64_C + +#define SK_MEMCPY(dest,src,size) memcpy(dest,src,size) +#define SK_MEMCMP(s1,s2,size) memcmp(s1,s2,size) +#define SK_MEMSET(dest,val,size) memset(dest,val,size) +#define SK_STRLEN(pStr) strlen((char*)(pStr)) +#define SK_STRNCPY(pDest,pSrc,size) strncpy((char*)(pDest),(char*)(pSrc),size) +#define SK_STRCMP(pStr1,pStr2) strcmp((char*)(pStr1),(char*)(pStr2)) + +/* macros to access the adapter */ +#define SK_OUT8(b,a,v) writeb((v), ((b)+(a))) +#define SK_OUT16(b,a,v) writew((v), ((b)+(a))) +#define SK_OUT32(b,a,v) writel((v), ((b)+(a))) +#define SK_IN8(b,a,pv) (*(pv) = readb((b)+(a))) +#define SK_IN16(b,a,pv) (*(pv) = readw((b)+(a))) +#define SK_IN32(b,a,pv) (*(pv) = readl((b)+(a))) + +#define int8_t char +#define int16_t short +#define int32_t long +#define int64_t long long +#define uint8_t u_char +#define uint16_t u_short +#define uint32_t u_long +#define uint64_t unsigned long long +#define t_scalar_t int +#define t_uscalar_t unsigned int +#define uintptr_t unsigned long + +#define __CONCAT__(A,B) A##B + +#define INT32_C(a) __CONCAT__(a,L) +#define INT64_C(a) __CONCAT__(a,LL) +#define UINT32_C(a) __CONCAT__(a,UL) +#define UINT64_C(a) __CONCAT__(a,ULL) + +#ifdef DEBUG +#define SK_DBG_PRINTF printk +#ifndef SK_DEBUG_CHKMOD +#define SK_DEBUG_CHKMOD 0 +#endif +#ifndef SK_DEBUG_CHKCAT +#define SK_DEBUG_CHKCAT 0 +#endif +/* those come from the makefile */ +#define SK_DBG_CHKMOD(pAC) (SK_DEBUG_CHKMOD) +#define SK_DBG_CHKCAT(pAC) (SK_DEBUG_CHKCAT) + +extern void SkDbgPrintf(const char *format,...); + +#define SK_DBGMOD_DRV 0x00010000 + +/**** possible driver debug categories ********************************/ +#define SK_DBGCAT_DRV_ENTRY 0x00010000 +#define SK_DBGCAT_DRV_SAP 0x00020000 +#define SK_DBGCAT_DRV_MCA 0x00040000 +#define SK_DBGCAT_DRV_TX_PROGRESS 0x00080000 +#define SK_DBGCAT_DRV_RX_PROGRESS 0x00100000 +#define SK_DBGCAT_DRV_PROGRESS 0x00200000 +#define SK_DBGCAT_DRV_MSG 0x00400000 +#define SK_DBGCAT_DRV_PROM 0x00800000 +#define SK_DBGCAT_DRV_TX_FRAME 0x01000000 +#define SK_DBGCAT_DRV_ERROR 0x02000000 +#define SK_DBGCAT_DRV_INT_SRC 0x04000000 +#define SK_DBGCAT_DRV_EVENT 0x08000000 + +#endif + +#define SK_ERR_LOG SkErrorLog + +extern void SkErrorLog(SK_AC*, int, int, char*); + +#endif + diff --git a/drivers/net/sk98lin/h/skdrv2nd.h b/drivers/net/sk98lin/h/skdrv2nd.h new file mode 100644 index 000000000000..3fa67171e832 --- /dev/null +++ b/drivers/net/sk98lin/h/skdrv2nd.h @@ -0,0 +1,447 @@ +/****************************************************************************** + * + * Name: skdrv2nd.h + * Project: GEnesis, PCI Gigabit Ethernet Adapter + * Version: $Revision: 1.10 $ + * Date: $Date: 2003/12/11 16:04:45 $ + * Purpose: Second header file for driver and all other modules + * + ******************************************************************************/ + +/****************************************************************************** + * + * (C)Copyright 1998-2002 SysKonnect GmbH. + * (C)Copyright 2002-2003 Marvell. + * + * 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. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/****************************************************************************** + * + * Description: + * + * This is the second include file of the driver, which includes all other + * neccessary files and defines all structures and constants used by the + * driver and the common modules. + * + * Include File Hierarchy: + * + * see skge.c + * + ******************************************************************************/ + +#ifndef __INC_SKDRV2ND_H +#define __INC_SKDRV2ND_H + +#include "h/skqueue.h" +#include "h/skgehwt.h" +#include "h/sktimer.h" +#include "h/ski2c.h" +#include "h/skgepnmi.h" +#include "h/skvpd.h" +#include "h/skgehw.h" +#include "h/skgeinit.h" +#include "h/skaddr.h" +#include "h/skgesirq.h" +#include "h/skcsum.h" +#include "h/skrlmt.h" +#include "h/skgedrv.h" + + +extern SK_MBUF *SkDrvAllocRlmtMbuf(SK_AC*, SK_IOC, unsigned); +extern void SkDrvFreeRlmtMbuf(SK_AC*, SK_IOC, SK_MBUF*); +extern SK_U64 SkOsGetTime(SK_AC*); +extern int SkPciReadCfgDWord(SK_AC*, int, SK_U32*); +extern int SkPciReadCfgWord(SK_AC*, int, SK_U16*); +extern int SkPciReadCfgByte(SK_AC*, int, SK_U8*); +extern int SkPciWriteCfgWord(SK_AC*, int, SK_U16); +extern int SkPciWriteCfgByte(SK_AC*, int, SK_U8); +extern int SkDrvEvent(SK_AC*, SK_IOC IoC, SK_U32, SK_EVPARA); + +#ifdef SK_DIAG_SUPPORT +extern int SkDrvEnterDiagMode(SK_AC *pAc); +extern int SkDrvLeaveDiagMode(SK_AC *pAc); +#endif + +struct s_DrvRlmtMbuf { + SK_MBUF *pNext; /* Pointer to next RLMT Mbuf. */ + SK_U8 *pData; /* Data buffer (virtually contig.). */ + unsigned Size; /* Data buffer size. */ + unsigned Length; /* Length of packet (<= Size). */ + SK_U32 PortIdx; /* Receiving/transmitting port. */ +#ifdef SK_RLMT_MBUF_PRIVATE + SK_RLMT_MBUF Rlmt; /* Private part for RLMT. */ +#endif /* SK_RLMT_MBUF_PRIVATE */ + struct sk_buff *pOs; /* Pointer to message block */ +}; + + +/* + * Time macros + */ +#if SK_TICKS_PER_SEC == 100 +#define SK_PNMI_HUNDREDS_SEC(t) (t) +#else +#define SK_PNMI_HUNDREDS_SEC(t) ((((unsigned long)t) * 100) / \ + (SK_TICKS_PER_SEC)) +#endif + +/* + * New SkOsGetTime + */ +#define SkOsGetTimeCurrent(pAC, pUsec) {\ + struct timeval t;\ + do_gettimeofday(&t);\ + *pUsec = ((((t.tv_sec) * 1000000L)+t.tv_usec)/10000);\ +} + + +/* + * ioctl definitions + */ +#define SK_IOCTL_BASE (SIOCDEVPRIVATE) +#define SK_IOCTL_GETMIB (SK_IOCTL_BASE + 0) +#define SK_IOCTL_SETMIB (SK_IOCTL_BASE + 1) +#define SK_IOCTL_PRESETMIB (SK_IOCTL_BASE + 2) +#define SK_IOCTL_GEN (SK_IOCTL_BASE + 3) +#define SK_IOCTL_DIAG (SK_IOCTL_BASE + 4) + +typedef struct s_IOCTL SK_GE_IOCTL; + +struct s_IOCTL { + char __user * pData; + unsigned int Len; +}; + + +/* + * define sizes of descriptor rings in bytes + */ + +#define TX_RING_SIZE (8*1024) +#define RX_RING_SIZE (24*1024) + +/* + * Buffer size for ethernet packets + */ +#define ETH_BUF_SIZE 1540 +#define ETH_MAX_MTU 1514 +#define ETH_MIN_MTU 60 +#define ETH_MULTICAST_BIT 0x01 +#define SK_JUMBO_MTU 9000 + +/* + * transmit priority selects the queue: LOW=asynchron, HIGH=synchron + */ +#define TX_PRIO_LOW 0 +#define TX_PRIO_HIGH 1 + +/* + * alignment of rx/tx descriptors + */ +#define DESCR_ALIGN 64 + +/* + * definitions for pnmi. TODO + */ +#define SK_DRIVER_RESET(pAC, IoC) 0 +#define SK_DRIVER_SENDEVENT(pAC, IoC) 0 +#define SK_DRIVER_SELFTEST(pAC, IoC) 0 +/* For get mtu you must add an own function */ +#define SK_DRIVER_GET_MTU(pAc,IoC,i) 0 +#define SK_DRIVER_SET_MTU(pAc,IoC,i,v) 0 +#define SK_DRIVER_PRESET_MTU(pAc,IoC,i,v) 0 + +/* +** Interim definition of SK_DRV_TIMER placed in this file until +** common modules have been finalized +*/ +#define SK_DRV_TIMER 11 +#define SK_DRV_MODERATION_TIMER 1 +#define SK_DRV_MODERATION_TIMER_LENGTH 1000000 /* 1 second */ +#define SK_DRV_RX_CLEANUP_TIMER 2 +#define SK_DRV_RX_CLEANUP_TIMER_LENGTH 1000000 /* 100 millisecs */ + +/* +** Definitions regarding transmitting frames +** any calculating any checksum. +*/ +#define C_LEN_ETHERMAC_HEADER_DEST_ADDR 6 +#define C_LEN_ETHERMAC_HEADER_SRC_ADDR 6 +#define C_LEN_ETHERMAC_HEADER_LENTYPE 2 +#define C_LEN_ETHERMAC_HEADER ( (C_LEN_ETHERMAC_HEADER_DEST_ADDR) + \ + (C_LEN_ETHERMAC_HEADER_SRC_ADDR) + \ + (C_LEN_ETHERMAC_HEADER_LENTYPE) ) + +#define C_LEN_ETHERMTU_MINSIZE 46 +#define C_LEN_ETHERMTU_MAXSIZE_STD 1500 +#define C_LEN_ETHERMTU_MAXSIZE_JUMBO 9000 + +#define C_LEN_ETHERNET_MINSIZE ( (C_LEN_ETHERMAC_HEADER) + \ + (C_LEN_ETHERMTU_MINSIZE) ) + +#define C_OFFSET_IPHEADER C_LEN_ETHERMAC_HEADER +#define C_OFFSET_IPHEADER_IPPROTO 9 +#define C_OFFSET_TCPHEADER_TCPCS 16 +#define C_OFFSET_UDPHEADER_UDPCS 6 + +#define C_OFFSET_IPPROTO ( (C_LEN_ETHERMAC_HEADER) + \ + (C_OFFSET_IPHEADER_IPPROTO) ) + +#define C_PROTO_ID_UDP 17 /* refer to RFC 790 or Stevens' */ +#define C_PROTO_ID_TCP 6 /* TCP/IP illustrated for details */ + +/* TX and RX descriptors *****************************************************/ + +typedef struct s_RxD RXD; /* the receive descriptor */ + +struct s_RxD { + volatile SK_U32 RBControl; /* Receive Buffer Control */ + SK_U32 VNextRxd; /* Next receive descriptor,low dword */ + SK_U32 VDataLow; /* Receive buffer Addr, low dword */ + SK_U32 VDataHigh; /* Receive buffer Addr, high dword */ + SK_U32 FrameStat; /* Receive Frame Status word */ + SK_U32 TimeStamp; /* Time stamp from XMAC */ + SK_U32 TcpSums; /* TCP Sum 2 / TCP Sum 1 */ + SK_U32 TcpSumStarts; /* TCP Sum Start 2 / TCP Sum Start 1 */ + RXD *pNextRxd; /* Pointer to next Rxd */ + struct sk_buff *pMBuf; /* Pointer to Linux' socket buffer */ +}; + +typedef struct s_TxD TXD; /* the transmit descriptor */ + +struct s_TxD { + volatile SK_U32 TBControl; /* Transmit Buffer Control */ + SK_U32 VNextTxd; /* Next transmit descriptor,low dword */ + SK_U32 VDataLow; /* Transmit Buffer Addr, low dword */ + SK_U32 VDataHigh; /* Transmit Buffer Addr, high dword */ + SK_U32 FrameStat; /* Transmit Frame Status Word */ + SK_U32 TcpSumOfs; /* Reserved / TCP Sum Offset */ + SK_U16 TcpSumSt; /* TCP Sum Start */ + SK_U16 TcpSumWr; /* TCP Sum Write */ + SK_U32 TcpReserved; /* not used */ + TXD *pNextTxd; /* Pointer to next Txd */ + struct sk_buff *pMBuf; /* Pointer to Linux' socket buffer */ +}; + +/* Used interrupt bits in the interrupts source register *********************/ + +#define DRIVER_IRQS ((IS_IRQ_SW) | \ + (IS_R1_F) |(IS_R2_F) | \ + (IS_XS1_F) |(IS_XA1_F) | \ + (IS_XS2_F) |(IS_XA2_F)) + +#define SPECIAL_IRQS ((IS_HW_ERR) |(IS_I2C_READY) | \ + (IS_EXT_REG) |(IS_TIMINT) | \ + (IS_PA_TO_RX1) |(IS_PA_TO_RX2) | \ + (IS_PA_TO_TX1) |(IS_PA_TO_TX2) | \ + (IS_MAC1) |(IS_LNK_SYNC_M1)| \ + (IS_MAC2) |(IS_LNK_SYNC_M2)| \ + (IS_R1_C) |(IS_R2_C) | \ + (IS_XS1_C) |(IS_XA1_C) | \ + (IS_XS2_C) |(IS_XA2_C)) + +#define IRQ_MASK ((IS_IRQ_SW) | \ + (IS_R1_B) |(IS_R1_F) |(IS_R2_B) |(IS_R2_F) | \ + (IS_XS1_B) |(IS_XS1_F) |(IS_XA1_B)|(IS_XA1_F)| \ + (IS_XS2_B) |(IS_XS2_F) |(IS_XA2_B)|(IS_XA2_F)| \ + (IS_HW_ERR) |(IS_I2C_READY)| \ + (IS_EXT_REG) |(IS_TIMINT) | \ + (IS_PA_TO_RX1) |(IS_PA_TO_RX2)| \ + (IS_PA_TO_TX1) |(IS_PA_TO_TX2)| \ + (IS_MAC1) |(IS_MAC2) | \ + (IS_R1_C) |(IS_R2_C) | \ + (IS_XS1_C) |(IS_XA1_C) | \ + (IS_XS2_C) |(IS_XA2_C)) + +#define IRQ_HWE_MASK (IS_ERR_MSK) /* enable all HW irqs */ + +typedef struct s_DevNet DEV_NET; + +struct s_DevNet { + int PortNr; + int NetNr; + SK_AC *pAC; +}; + +typedef struct s_TxPort TX_PORT; + +struct s_TxPort { + /* the transmit descriptor rings */ + caddr_t pTxDescrRing; /* descriptor area memory */ + SK_U64 VTxDescrRing; /* descr. area bus virt. addr. */ + TXD *pTxdRingHead; /* Head of Tx rings */ + TXD *pTxdRingTail; /* Tail of Tx rings */ + TXD *pTxdRingPrev; /* descriptor sent previously */ + int TxdRingFree; /* # of free entrys */ + spinlock_t TxDesRingLock; /* serialize descriptor accesses */ + SK_IOC HwAddr; /* bmu registers address */ + int PortIndex; /* index number of port (0 or 1) */ +}; + +typedef struct s_RxPort RX_PORT; + +struct s_RxPort { + /* the receive descriptor rings */ + caddr_t pRxDescrRing; /* descriptor area memory */ + SK_U64 VRxDescrRing; /* descr. area bus virt. addr. */ + RXD *pRxdRingHead; /* Head of Rx rings */ + RXD *pRxdRingTail; /* Tail of Rx rings */ + RXD *pRxdRingPrev; /* descriptor given to BMU previously */ + int RxdRingFree; /* # of free entrys */ + int RxCsum; /* use receive checksum hardware */ + spinlock_t RxDesRingLock; /* serialize descriptor accesses */ + int RxFillLimit; /* limit for buffers in ring */ + SK_IOC HwAddr; /* bmu registers address */ + int PortIndex; /* index number of port (0 or 1) */ +}; + +/* Definitions needed for interrupt moderation *******************************/ + +#define IRQ_EOF_AS_TX ((IS_XA1_F) | (IS_XA2_F)) +#define IRQ_EOF_SY_TX ((IS_XS1_F) | (IS_XS2_F)) +#define IRQ_MASK_TX_ONLY ((IRQ_EOF_AS_TX)| (IRQ_EOF_SY_TX)) +#define IRQ_MASK_RX_ONLY ((IS_R1_F) | (IS_R2_F)) +#define IRQ_MASK_SP_ONLY (SPECIAL_IRQS) +#define IRQ_MASK_TX_RX ((IRQ_MASK_TX_ONLY)| (IRQ_MASK_RX_ONLY)) +#define IRQ_MASK_SP_RX ((SPECIAL_IRQS) | (IRQ_MASK_RX_ONLY)) +#define IRQ_MASK_SP_TX ((SPECIAL_IRQS) | (IRQ_MASK_TX_ONLY)) +#define IRQ_MASK_RX_TX_SP ((SPECIAL_IRQS) | (IRQ_MASK_TX_RX)) + +#define C_INT_MOD_NONE 1 +#define C_INT_MOD_STATIC 2 +#define C_INT_MOD_DYNAMIC 4 + +#define C_CLK_FREQ_GENESIS 53215000 /* shorter: 53.125 MHz */ +#define C_CLK_FREQ_YUKON 78215000 /* shorter: 78.125 MHz */ + +#define C_INTS_PER_SEC_DEFAULT 2000 +#define C_INT_MOD_ENABLE_PERCENTAGE 50 /* if higher 50% enable */ +#define C_INT_MOD_DISABLE_PERCENTAGE 50 /* if lower 50% disable */ +#define C_INT_MOD_IPS_LOWER_RANGE 30 +#define C_INT_MOD_IPS_UPPER_RANGE 40000 + + +typedef struct s_DynIrqModInfo DIM_INFO; +struct s_DynIrqModInfo { + unsigned long PrevTimeVal; + unsigned int PrevSysLoad; + unsigned int PrevUsedTime; + unsigned int PrevTotalTime; + int PrevUsedDescrRatio; + int NbrProcessedDescr; + SK_U64 PrevPort0RxIntrCts; + SK_U64 PrevPort1RxIntrCts; + SK_U64 PrevPort0TxIntrCts; + SK_U64 PrevPort1TxIntrCts; + SK_BOOL ModJustEnabled; /* Moderation just enabled yes/no */ + + int MaxModIntsPerSec; /* Moderation Threshold */ + int MaxModIntsPerSecUpperLimit; /* Upper limit for DIM */ + int MaxModIntsPerSecLowerLimit; /* Lower limit for DIM */ + + long MaskIrqModeration; /* ModIrqType (eg. 'TxRx') */ + SK_BOOL DisplayStats; /* Stats yes/no */ + SK_BOOL AutoSizing; /* Resize DIM-timer on/off */ + int IntModTypeSelect; /* EnableIntMod (eg. 'dynamic') */ + + SK_TIMER ModTimer; /* just some timer */ +}; + +typedef struct s_PerStrm PER_STRM; + +#define SK_ALLOC_IRQ 0x00000001 + +#ifdef SK_DIAG_SUPPORT +#define DIAG_ACTIVE 1 +#define DIAG_NOTACTIVE 0 +#endif + +/**************************************************************************** + * Per board structure / Adapter Context structure: + * Allocated within attach(9e) and freed within detach(9e). + * Contains all 'per device' necessary handles, flags, locks etc.: + */ +struct s_AC { + SK_GEINIT GIni; /* GE init struct */ + SK_PNMI Pnmi; /* PNMI data struct */ + SK_VPD vpd; /* vpd data struct */ + SK_QUEUE Event; /* Event queue */ + SK_HWT Hwt; /* Hardware Timer control struct */ + SK_TIMCTRL Tim; /* Software Timer control struct */ + SK_I2C I2c; /* I2C relevant data structure */ + SK_ADDR Addr; /* for Address module */ + SK_CSUM Csum; /* for checksum module */ + SK_RLMT Rlmt; /* for rlmt module */ + spinlock_t SlowPathLock; /* Normal IRQ lock */ + struct timer_list BlinkTimer; /* for LED blinking */ + int LedsOn; + SK_PNMI_STRUCT_DATA PnmiStruct; /* structure to get all Pnmi-Data */ + int RlmtMode; /* link check mode to set */ + int RlmtNets; /* Number of nets */ + + SK_IOC IoBase; /* register set of adapter */ + int BoardLevel; /* level of active hw init (0-2) */ + + SK_U32 AllocFlag; /* flag allocation of resources */ + struct pci_dev *PciDev; /* for access to pci config space */ + struct SK_NET_DEVICE *dev[2]; /* pointer to device struct */ + + int RxBufSize; /* length of receive buffers */ + struct net_device_stats stats; /* linux 'netstat -i' statistics */ + int Index; /* internal board index number */ + + /* adapter RAM sizes for queues of active port */ + int RxQueueSize; /* memory used for receive queue */ + int TxSQueueSize; /* memory used for sync. tx queue */ + int TxAQueueSize; /* memory used for async. tx queue */ + + int PromiscCount; /* promiscuous mode counter */ + int AllMultiCount; /* allmulticast mode counter */ + int MulticCount; /* number of different MC */ + /* addresses for this board */ + /* (may be more than HW can)*/ + + int HWRevision; /* Hardware revision */ + int ActivePort; /* the active XMAC port */ + int MaxPorts; /* number of activated ports */ + int TxDescrPerRing; /* # of descriptors per tx ring */ + int RxDescrPerRing; /* # of descriptors per rx ring */ + + caddr_t pDescrMem; /* Pointer to the descriptor area */ + dma_addr_t pDescrMemDMA; /* PCI DMA address of area */ + + /* the port structures with descriptor rings */ + TX_PORT TxPort[SK_MAX_MACS][2]; + RX_PORT RxPort[SK_MAX_MACS]; + + SK_BOOL CheckQueue; /* check event queue soon */ + SK_TIMER DrvCleanupTimer;/* to check for pending descriptors */ + DIM_INFO DynIrqModInfo; /* all data related to DIM */ + + /* Only for tests */ + int PortDown; + int ChipsetType; /* Chipset family type + * 0 == Genesis family support + * 1 == Yukon family support + */ +#ifdef SK_DIAG_SUPPORT + SK_U32 DiagModeActive; /* is diag active? */ + SK_BOOL DiagFlowCtrl; /* for control purposes */ + SK_PNMI_STRUCT_DATA PnmiBackup; /* backup structure for all Pnmi-Data */ + SK_BOOL WasIfUp[SK_MAX_MACS]; /* for OpenClose while + * DIAG is busy with NIC + */ +#endif + +}; + + +#endif /* __INC_SKDRV2ND_H */ + diff --git a/drivers/net/sk98lin/h/skerror.h b/drivers/net/sk98lin/h/skerror.h new file mode 100644 index 000000000000..da062f766238 --- /dev/null +++ b/drivers/net/sk98lin/h/skerror.h @@ -0,0 +1,55 @@ +/****************************************************************************** + * + * Name: skerror.h + * Project: Gigabit Ethernet Adapters, Common Modules + * Version: $Revision: 1.7 $ + * Date: $Date: 2003/05/13 17:25:13 $ + * Purpose: SK specific Error log support + * + ******************************************************************************/ + +/****************************************************************************** + * + * (C)Copyright 1998-2002 SysKonnect. + * (C)Copyright 2002-2003 Marvell. + * + * 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. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +#ifndef _INC_SKERROR_H_ +#define _INC_SKERROR_H_ + +/* + * Define Error Classes + */ +#define SK_ERRCL_OTHER (0) /* Other error */ +#define SK_ERRCL_CONFIG (1L<<0) /* Configuration error */ +#define SK_ERRCL_INIT (1L<<1) /* Initialization error */ +#define SK_ERRCL_NORES (1L<<2) /* Out of Resources error */ +#define SK_ERRCL_SW (1L<<3) /* Internal Software error */ +#define SK_ERRCL_HW (1L<<4) /* Hardware Failure */ +#define SK_ERRCL_COMM (1L<<5) /* Communication error */ + + +/* + * Define Error Code Bases + */ +#define SK_ERRBASE_RLMT 100 /* Base Error number for RLMT */ +#define SK_ERRBASE_HWINIT 200 /* Base Error number for HWInit */ +#define SK_ERRBASE_VPD 300 /* Base Error number for VPD */ +#define SK_ERRBASE_PNMI 400 /* Base Error number for PNMI */ +#define SK_ERRBASE_CSUM 500 /* Base Error number for Checksum */ +#define SK_ERRBASE_SIRQ 600 /* Base Error number for Special IRQ */ +#define SK_ERRBASE_I2C 700 /* Base Error number for I2C module */ +#define SK_ERRBASE_QUEUE 800 /* Base Error number for Scheduler */ +#define SK_ERRBASE_ADDR 900 /* Base Error number for Address module */ +#define SK_ERRBASE_PECP 1000 /* Base Error number for PECP */ +#define SK_ERRBASE_DRV 1100 /* Base Error number for Driver */ + +#endif /* _INC_SKERROR_H_ */ diff --git a/drivers/net/sk98lin/h/skgedrv.h b/drivers/net/sk98lin/h/skgedrv.h new file mode 100644 index 000000000000..44fd4c3de818 --- /dev/null +++ b/drivers/net/sk98lin/h/skgedrv.h @@ -0,0 +1,51 @@ +/****************************************************************************** + * + * Name: skgedrv.h + * Project: Gigabit Ethernet Adapters, Common Modules + * Version: $Revision: 1.10 $ + * Date: $Date: 2003/07/04 12:25:01 $ + * Purpose: Interface with the driver + * + ******************************************************************************/ + +/****************************************************************************** + * + * (C)Copyright 1998-2002 SysKonnect. + * (C)Copyright 2002-2003 Marvell. + * + * 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. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +#ifndef __INC_SKGEDRV_H_ +#define __INC_SKGEDRV_H_ + +/* defines ********************************************************************/ + +/* + * Define the driver events. + * Usually the events are defined by the destination module. + * In case of the driver we put the definition of the events here. + */ +#define SK_DRV_PORT_RESET 1 /* The port needs to be reset */ +#define SK_DRV_NET_UP 2 /* The net is operational */ +#define SK_DRV_NET_DOWN 3 /* The net is down */ +#define SK_DRV_SWITCH_SOFT 4 /* Ports switch with both links connected */ +#define SK_DRV_SWITCH_HARD 5 /* Port switch due to link failure */ +#define SK_DRV_RLMT_SEND 6 /* Send a RLMT packet */ +#define SK_DRV_ADAP_FAIL 7 /* The whole adapter fails */ +#define SK_DRV_PORT_FAIL 8 /* One port fails */ +#define SK_DRV_SWITCH_INTERN 9 /* Port switch by the driver itself */ +#define SK_DRV_POWER_DOWN 10 /* Power down mode */ +#define SK_DRV_TIMER 11 /* Timer for free use */ +#ifdef SK_NO_RLMT +#define SK_DRV_LINK_UP 12 /* Link Up event for driver */ +#define SK_DRV_LINK_DOWN 13 /* Link Down event for driver */ +#endif +#define SK_DRV_DOWNSHIFT_DET 14 /* Downshift 4-Pair / 2-Pair (YUKON only) */ +#endif /* __INC_SKGEDRV_H_ */ diff --git a/drivers/net/sk98lin/h/skgehw.h b/drivers/net/sk98lin/h/skgehw.h new file mode 100644 index 000000000000..f6282b7956db --- /dev/null +++ b/drivers/net/sk98lin/h/skgehw.h @@ -0,0 +1,2126 @@ +/****************************************************************************** + * + * Name: skgehw.h + * Project: Gigabit Ethernet Adapters, Common Modules + * Version: $Revision: 1.56 $ + * Date: $Date: 2003/09/23 09:01:00 $ + * Purpose: Defines and Macros for the Gigabit Ethernet Adapter Product Family + * + ******************************************************************************/ + +/****************************************************************************** + * + * (C)Copyright 1998-2002 SysKonnect. + * (C)Copyright 2002-2003 Marvell. + * + * 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. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +#ifndef __INC_SKGEHW_H +#define __INC_SKGEHW_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* defines ********************************************************************/ + +#define BIT_31 (1UL << 31) +#define BIT_30 (1L << 30) +#define BIT_29 (1L << 29) +#define BIT_28 (1L << 28) +#define BIT_27 (1L << 27) +#define BIT_26 (1L << 26) +#define BIT_25 (1L << 25) +#define BIT_24 (1L << 24) +#define BIT_23 (1L << 23) +#define BIT_22 (1L << 22) +#define BIT_21 (1L << 21) +#define BIT_20 (1L << 20) +#define BIT_19 (1L << 19) +#define BIT_18 (1L << 18) +#define BIT_17 (1L << 17) +#define BIT_16 (1L << 16) +#define BIT_15 (1L << 15) +#define BIT_14 (1L << 14) +#define BIT_13 (1L << 13) +#define BIT_12 (1L << 12) +#define BIT_11 (1L << 11) +#define BIT_10 (1L << 10) +#define BIT_9 (1L << 9) +#define BIT_8 (1L << 8) +#define BIT_7 (1L << 7) +#define BIT_6 (1L << 6) +#define BIT_5 (1L << 5) +#define BIT_4 (1L << 4) +#define BIT_3 (1L << 3) +#define BIT_2 (1L << 2) +#define BIT_1 (1L << 1) +#define BIT_0 1L + +#define BIT_15S (1U << 15) +#define BIT_14S (1 << 14) +#define BIT_13S (1 << 13) +#define BIT_12S (1 << 12) +#define BIT_11S (1 << 11) +#define BIT_10S (1 << 10) +#define BIT_9S (1 << 9) +#define BIT_8S (1 << 8) +#define BIT_7S (1 << 7) +#define BIT_6S (1 << 6) +#define BIT_5S (1 << 5) +#define BIT_4S (1 << 4) +#define BIT_3S (1 << 3) +#define BIT_2S (1 << 2) +#define BIT_1S (1 << 1) +#define BIT_0S 1 + +#define SHIFT31(x) ((x) << 31) +#define SHIFT30(x) ((x) << 30) +#define SHIFT29(x) ((x) << 29) +#define SHIFT28(x) ((x) << 28) +#define SHIFT27(x) ((x) << 27) +#define SHIFT26(x) ((x) << 26) +#define SHIFT25(x) ((x) << 25) +#define SHIFT24(x) ((x) << 24) +#define SHIFT23(x) ((x) << 23) +#define SHIFT22(x) ((x) << 22) +#define SHIFT21(x) ((x) << 21) +#define SHIFT20(x) ((x) << 20) +#define SHIFT19(x) ((x) << 19) +#define SHIFT18(x) ((x) << 18) +#define SHIFT17(x) ((x) << 17) +#define SHIFT16(x) ((x) << 16) +#define SHIFT15(x) ((x) << 15) +#define SHIFT14(x) ((x) << 14) +#define SHIFT13(x) ((x) << 13) +#define SHIFT12(x) ((x) << 12) +#define SHIFT11(x) ((x) << 11) +#define SHIFT10(x) ((x) << 10) +#define SHIFT9(x) ((x) << 9) +#define SHIFT8(x) ((x) << 8) +#define SHIFT7(x) ((x) << 7) +#define SHIFT6(x) ((x) << 6) +#define SHIFT5(x) ((x) << 5) +#define SHIFT4(x) ((x) << 4) +#define SHIFT3(x) ((x) << 3) +#define SHIFT2(x) ((x) << 2) +#define SHIFT1(x) ((x) << 1) +#define SHIFT0(x) ((x) << 0) + +/* + * Configuration Space header + * Since this module is used for different OS', those may be + * duplicate on some of them (e.g. Linux). But to keep the + * common source, we have to live with this... + */ +#define PCI_VENDOR_ID 0x00 /* 16 bit Vendor ID */ +#define PCI_DEVICE_ID 0x02 /* 16 bit Device ID */ +#define PCI_COMMAND 0x04 /* 16 bit Command */ +#define PCI_STATUS 0x06 /* 16 bit Status */ +#define PCI_REV_ID 0x08 /* 8 bit Revision ID */ +#define PCI_CLASS_CODE 0x09 /* 24 bit Class Code */ +#define PCI_CACHE_LSZ 0x0c /* 8 bit Cache Line Size */ +#define PCI_LAT_TIM 0x0d /* 8 bit Latency Timer */ +#define PCI_HEADER_T 0x0e /* 8 bit Header Type */ +#define PCI_BIST 0x0f /* 8 bit Built-in selftest */ +#define PCI_BASE_1ST 0x10 /* 32 bit 1st Base address */ +#define PCI_BASE_2ND 0x14 /* 32 bit 2nd Base address */ + /* Byte 0x18..0x2b: reserved */ +#define PCI_SUB_VID 0x2c /* 16 bit Subsystem Vendor ID */ +#define PCI_SUB_ID 0x2e /* 16 bit Subsystem ID */ +#define PCI_BASE_ROM 0x30 /* 32 bit Expansion ROM Base Address */ +#define PCI_CAP_PTR 0x34 /* 8 bit Capabilities Ptr */ + /* Byte 0x35..0x3b: reserved */ +#define PCI_IRQ_LINE 0x3c /* 8 bit Interrupt Line */ +#define PCI_IRQ_PIN 0x3d /* 8 bit Interrupt Pin */ +#define PCI_MIN_GNT 0x3e /* 8 bit Min_Gnt */ +#define PCI_MAX_LAT 0x3f /* 8 bit Max_Lat */ + /* Device Dependent Region */ +#define PCI_OUR_REG_1 0x40 /* 32 bit Our Register 1 */ +#define PCI_OUR_REG_2 0x44 /* 32 bit Our Register 2 */ + /* Power Management Region */ +#define PCI_PM_CAP_ID 0x48 /* 8 bit Power Management Cap. ID */ +#define PCI_PM_NITEM 0x49 /* 8 bit Next Item Ptr */ +#define PCI_PM_CAP_REG 0x4a /* 16 bit Power Management Capabilities */ +#define PCI_PM_CTL_STS 0x4c /* 16 bit Power Manag. Control/Status */ + /* Byte 0x4e: reserved */ +#define PCI_PM_DAT_REG 0x4f /* 8 bit Power Manag. Data Register */ + /* VPD Region */ +#define PCI_VPD_CAP_ID 0x50 /* 8 bit VPD Cap. ID */ +#define PCI_VPD_NITEM 0x51 /* 8 bit Next Item Ptr */ +#define PCI_VPD_ADR_REG 0x52 /* 16 bit VPD Address Register */ +#define PCI_VPD_DAT_REG 0x54 /* 32 bit VPD Data Register */ + /* Byte 0x58..0x59: reserved */ +#define PCI_SER_LD_CTRL 0x5a /* 16 bit SEEPROM Loader Ctrl (YUKON only) */ + /* Byte 0x5c..0xff: reserved */ + +/* + * I2C Address (PCI Config) + * + * Note: The temperature and voltage sensors are relocated on a different + * I2C bus. + */ +#define I2C_ADDR_VPD 0xa0 /* I2C address for the VPD EEPROM */ + +/* + * Define Bits and Values of the registers + */ +/* PCI_COMMAND 16 bit Command */ + /* Bit 15..11: reserved */ +#define PCI_INT_DIS BIT_10S /* Interrupt INTx# disable (PCI 2.3) */ +#define PCI_FBTEN BIT_9S /* Fast Back-To-Back enable */ +#define PCI_SERREN BIT_8S /* SERR enable */ +#define PCI_ADSTEP BIT_7S /* Address Stepping */ +#define PCI_PERREN BIT_6S /* Parity Report Response enable */ +#define PCI_VGA_SNOOP BIT_5S /* VGA palette snoop */ +#define PCI_MWIEN BIT_4S /* Memory write an inv cycl ena */ +#define PCI_SCYCEN BIT_3S /* Special Cycle enable */ +#define PCI_BMEN BIT_2S /* Bus Master enable */ +#define PCI_MEMEN BIT_1S /* Memory Space Access enable */ +#define PCI_IOEN BIT_0S /* I/O Space Access enable */ + +#define PCI_COMMAND_VAL (PCI_FBTEN | PCI_SERREN | PCI_PERREN | PCI_MWIEN |\ + PCI_BMEN | PCI_MEMEN | PCI_IOEN) + +/* PCI_STATUS 16 bit Status */ +#define PCI_PERR BIT_15S /* Parity Error */ +#define PCI_SERR BIT_14S /* Signaled SERR */ +#define PCI_RMABORT BIT_13S /* Received Master Abort */ +#define PCI_RTABORT BIT_12S /* Received Target Abort */ + /* Bit 11: reserved */ +#define PCI_DEVSEL (3<<9) /* Bit 10.. 9: DEVSEL Timing */ +#define PCI_DEV_FAST (0<<9) /* fast */ +#define PCI_DEV_MEDIUM (1<<9) /* medium */ +#define PCI_DEV_SLOW (2<<9) /* slow */ +#define PCI_DATAPERR BIT_8S /* DATA Parity error detected */ +#define PCI_FB2BCAP BIT_7S /* Fast Back-to-Back Capability */ +#define PCI_UDF BIT_6S /* User Defined Features */ +#define PCI_66MHZCAP BIT_5S /* 66 MHz PCI bus clock capable */ +#define PCI_NEWCAP BIT_4S /* New cap. list implemented */ +#define PCI_INT_STAT BIT_3S /* Interrupt INTx# Status (PCI 2.3) */ + /* Bit 2.. 0: reserved */ + +#define PCI_ERRBITS (PCI_PERR | PCI_SERR | PCI_RMABORT | PCI_RTABORT |\ + PCI_DATAPERR) + +/* PCI_CLASS_CODE 24 bit Class Code */ +/* Byte 2: Base Class (02) */ +/* Byte 1: SubClass (00) */ +/* Byte 0: Programming Interface (00) */ + +/* PCI_CACHE_LSZ 8 bit Cache Line Size */ +/* Possible values: 0,2,4,8,16,32,64,128 */ + +/* PCI_HEADER_T 8 bit Header Type */ +#define PCI_HD_MF_DEV BIT_7S /* 0= single, 1= multi-func dev */ +#define PCI_HD_TYPE 0x7f /* Bit 6..0: Header Layout 0= normal */ + +/* PCI_BIST 8 bit Built-in selftest */ +/* Built-in Self test not supported (optional) */ + +/* PCI_BASE_1ST 32 bit 1st Base address */ +#define PCI_MEMSIZE 0x4000L /* use 16 kB Memory Base */ +#define PCI_MEMBASE_MSK 0xffffc000L /* Bit 31..14: Memory Base Address */ +#define PCI_MEMSIZE_MSK 0x00003ff0L /* Bit 13.. 4: Memory Size Req. */ +#define PCI_PREFEN BIT_3 /* Prefetchable */ +#define PCI_MEM_TYP (3L<<2) /* Bit 2.. 1: Memory Type */ +#define PCI_MEM32BIT (0L<<1) /* Base addr anywhere in 32 Bit range */ +#define PCI_MEM1M (1L<<1) /* Base addr below 1 MegaByte */ +#define PCI_MEM64BIT (2L<<1) /* Base addr anywhere in 64 Bit range */ +#define PCI_MEMSPACE BIT_0 /* Memory Space Indicator */ + +/* PCI_BASE_2ND 32 bit 2nd Base address */ +#define PCI_IOBASE 0xffffff00L /* Bit 31.. 8: I/O Base address */ +#define PCI_IOSIZE 0x000000fcL /* Bit 7.. 2: I/O Size Requirements */ + /* Bit 1: reserved */ +#define PCI_IOSPACE BIT_0 /* I/O Space Indicator */ + +/* PCI_BASE_ROM 32 bit Expansion ROM Base Address */ +#define PCI_ROMBASE_MSK 0xfffe0000L /* Bit 31..17: ROM Base address */ +#define PCI_ROMBASE_SIZ (0x1cL<<14) /* Bit 16..14: Treat as Base or Size */ +#define PCI_ROMSIZE (0x38L<<11) /* Bit 13..11: ROM Size Requirements */ + /* Bit 10.. 1: reserved */ +#define PCI_ROMEN BIT_0 /* Address Decode enable */ + +/* Device Dependent Region */ +/* PCI_OUR_REG_1 32 bit Our Register 1 */ + /* Bit 31..29: reserved */ +#define PCI_PHY_COMA BIT_28 /* Set PHY to Coma Mode (YUKON only) */ +#define PCI_TEST_CAL BIT_27 /* Test PCI buffer calib. (YUKON only) */ +#define PCI_EN_CAL BIT_26 /* Enable PCI buffer calib. (YUKON only) */ +#define PCI_VIO BIT_25 /* PCI I/O Voltage, 0 = 3.3V, 1 = 5V */ +#define PCI_DIS_BOOT BIT_24 /* Disable BOOT via ROM */ +#define PCI_EN_IO BIT_23 /* Mapping to I/O space */ +#define PCI_EN_FPROM BIT_22 /* Enable FLASH mapping to memory */ + /* 1 = Map Flash to memory */ + /* 0 = Disable addr. dec */ +#define PCI_PAGESIZE (3L<<20) /* Bit 21..20: FLASH Page Size */ +#define PCI_PAGE_16 (0L<<20) /* 16 k pages */ +#define PCI_PAGE_32K (1L<<20) /* 32 k pages */ +#define PCI_PAGE_64K (2L<<20) /* 64 k pages */ +#define PCI_PAGE_128K (3L<<20) /* 128 k pages */ + /* Bit 19: reserved */ +#define PCI_PAGEREG (7L<<16) /* Bit 18..16: Page Register */ +#define PCI_NOTAR BIT_15 /* No turnaround cycle */ +#define PCI_FORCE_BE BIT_14 /* Assert all BEs on MR */ +#define PCI_DIS_MRL BIT_13 /* Disable Mem Read Line */ +#define PCI_DIS_MRM BIT_12 /* Disable Mem Read Multiple */ +#define PCI_DIS_MWI BIT_11 /* Disable Mem Write & Invalidate */ +#define PCI_DISC_CLS BIT_10 /* Disc: cacheLsz bound */ +#define PCI_BURST_DIS BIT_9 /* Burst Disable */ +#define PCI_DIS_PCI_CLK BIT_8 /* Disable PCI clock driving */ +#define PCI_SKEW_DAS (0xfL<<4) /* Bit 7.. 4: Skew Ctrl, DAS Ext */ +#define PCI_SKEW_BASE 0xfL /* Bit 3.. 0: Skew Ctrl, Base */ + + +/* PCI_OUR_REG_2 32 bit Our Register 2 */ +#define PCI_VPD_WR_THR (0xffL<<24) /* Bit 31..24: VPD Write Threshold */ +#define PCI_DEV_SEL (0x7fL<<17) /* Bit 23..17: EEPROM Device Select */ +#define PCI_VPD_ROM_SZ (7L<<14) /* Bit 16..14: VPD ROM Size */ + /* Bit 13..12: reserved */ +#define PCI_PATCH_DIR (0xfL<<8) /* Bit 11.. 8: Ext Patches dir 3..0 */ +#define PCI_PATCH_DIR_3 BIT_11 +#define PCI_PATCH_DIR_2 BIT_10 +#define PCI_PATCH_DIR_1 BIT_9 +#define PCI_PATCH_DIR_0 BIT_8 +#define PCI_EXT_PATCHS (0xfL<<4) /* Bit 7.. 4: Extended Patches 3..0 */ +#define PCI_EXT_PATCH_3 BIT_7 +#define PCI_EXT_PATCH_2 BIT_6 +#define PCI_EXT_PATCH_1 BIT_5 +#define PCI_EXT_PATCH_0 BIT_4 +#define PCI_EN_DUMMY_RD BIT_3 /* Enable Dummy Read */ +#define PCI_REV_DESC BIT_2 /* Reverse Desc. Bytes */ + /* Bit 1: reserved */ +#define PCI_USEDATA64 BIT_0 /* Use 64Bit Data bus ext */ + + +/* Power Management Region */ +/* PCI_PM_CAP_REG 16 bit Power Management Capabilities */ +#define PCI_PME_SUP_MSK (0x1f<<11) /* Bit 15..11: PM Event Support Mask */ +#define PCI_PME_D3C_SUP BIT_15S /* PME from D3cold Support (if Vaux) */ +#define PCI_PME_D3H_SUP BIT_14S /* PME from D3hot Support */ +#define PCI_PME_D2_SUP BIT_13S /* PME from D2 Support */ +#define PCI_PME_D1_SUP BIT_12S /* PME from D1 Support */ +#define PCI_PME_D0_SUP BIT_11S /* PME from D0 Support */ +#define PCI_PM_D2_SUP BIT_10S /* D2 Support in 33 MHz mode */ +#define PCI_PM_D1_SUP BIT_9S /* D1 Support */ + /* Bit 8.. 6: reserved */ +#define PCI_PM_DSI BIT_5S /* Device Specific Initialization */ +#define PCI_PM_APS BIT_4S /* Auxialiary Power Source */ +#define PCI_PME_CLOCK BIT_3S /* PM Event Clock */ +#define PCI_PM_VER_MSK 7 /* Bit 2.. 0: PM PCI Spec. version */ + +/* PCI_PM_CTL_STS 16 bit Power Management Control/Status */ +#define PCI_PME_STATUS BIT_15S /* PME Status (YUKON only) */ +#define PCI_PM_DAT_SCL (3<<13) /* Bit 14..13: Data Reg. scaling factor */ +#define PCI_PM_DAT_SEL (0xf<<9) /* Bit 12.. 9: PM data selector field */ +#define PCI_PME_EN BIT_8S /* Enable PME# generation (YUKON only) */ + /* Bit 7.. 2: reserved */ +#define PCI_PM_STATE_MSK 3 /* Bit 1.. 0: Power Management State */ + +#define PCI_PM_STATE_D0 0 /* D0: Operational (default) */ +#define PCI_PM_STATE_D1 1 /* D1: (YUKON only) */ +#define PCI_PM_STATE_D2 2 /* D2: (YUKON only) */ +#define PCI_PM_STATE_D3 3 /* D3: HOT, Power Down and Reset */ + +/* VPD Region */ +/* PCI_VPD_ADR_REG 16 bit VPD Address Register */ +#define PCI_VPD_FLAG BIT_15S /* starts VPD rd/wr cycle */ +#define PCI_VPD_ADR_MSK 0x7fffL /* Bit 14.. 0: VPD address mask */ + +/* Control Register File (Address Map) */ + +/* + * Bank 0 + */ +#define B0_RAP 0x0000 /* 8 bit Register Address Port */ + /* 0x0001 - 0x0003: reserved */ +#define B0_CTST 0x0004 /* 16 bit Control/Status register */ +#define B0_LED 0x0006 /* 8 Bit LED register */ +#define B0_POWER_CTRL 0x0007 /* 8 Bit Power Control reg (YUKON only) */ +#define B0_ISRC 0x0008 /* 32 bit Interrupt Source Register */ +#define B0_IMSK 0x000c /* 32 bit Interrupt Mask Register */ +#define B0_HWE_ISRC 0x0010 /* 32 bit HW Error Interrupt Src Reg */ +#define B0_HWE_IMSK 0x0014 /* 32 bit HW Error Interrupt Mask Reg */ +#define B0_SP_ISRC 0x0018 /* 32 bit Special Interrupt Source Reg */ + /* 0x001c: reserved */ + +/* B0 XMAC 1 registers (GENESIS only) */ +#define B0_XM1_IMSK 0x0020 /* 16 bit r/w XMAC 1 Interrupt Mask Register*/ + /* 0x0022 - 0x0027: reserved */ +#define B0_XM1_ISRC 0x0028 /* 16 bit ro XMAC 1 Interrupt Status Reg */ + /* 0x002a - 0x002f: reserved */ +#define B0_XM1_PHY_ADDR 0x0030 /* 16 bit r/w XMAC 1 PHY Address Register */ + /* 0x0032 - 0x0033: reserved */ +#define B0_XM1_PHY_DATA 0x0034 /* 16 bit r/w XMAC 1 PHY Data Register */ + /* 0x0036 - 0x003f: reserved */ + +/* B0 XMAC 2 registers (GENESIS only) */ +#define B0_XM2_IMSK 0x0040 /* 16 bit r/w XMAC 2 Interrupt Mask Register*/ + /* 0x0042 - 0x0047: reserved */ +#define B0_XM2_ISRC 0x0048 /* 16 bit ro XMAC 2 Interrupt Status Reg */ + /* 0x004a - 0x004f: reserved */ +#define B0_XM2_PHY_ADDR 0x0050 /* 16 bit r/w XMAC 2 PHY Address Register */ + /* 0x0052 - 0x0053: reserved */ +#define B0_XM2_PHY_DATA 0x0054 /* 16 bit r/w XMAC 2 PHY Data Register */ + /* 0x0056 - 0x005f: reserved */ + +/* BMU Control Status Registers */ +#define B0_R1_CSR 0x0060 /* 32 bit BMU Ctrl/Stat Rx Queue 1 */ +#define B0_R2_CSR 0x0064 /* 32 bit BMU Ctrl/Stat Rx Queue 2 */ +#define B0_XS1_CSR 0x0068 /* 32 bit BMU Ctrl/Stat Sync Tx Queue 1 */ +#define B0_XA1_CSR 0x006c /* 32 bit BMU Ctrl/Stat Async Tx Queue 1*/ +#define B0_XS2_CSR 0x0070 /* 32 bit BMU Ctrl/Stat Sync Tx Queue 2 */ +#define B0_XA2_CSR 0x0074 /* 32 bit BMU Ctrl/Stat Async Tx Queue 2*/ + /* 0x0078 - 0x007f: reserved */ + +/* + * Bank 1 + * - completely empty (this is the RAP Block window) + * Note: if RAP = 1 this page is reserved + */ + +/* + * Bank 2 + */ +/* NA reg = 48 bit Network Address Register, 3x16 or 8x8 bit readable */ +#define B2_MAC_1 0x0100 /* NA reg MAC Address 1 */ + /* 0x0106 - 0x0107: reserved */ +#define B2_MAC_2 0x0108 /* NA reg MAC Address 2 */ + /* 0x010e - 0x010f: reserved */ +#define B2_MAC_3 0x0110 /* NA reg MAC Address 3 */ + /* 0x0116 - 0x0117: reserved */ +#define B2_CONN_TYP 0x0118 /* 8 bit Connector type */ +#define B2_PMD_TYP 0x0119 /* 8 bit PMD type */ +#define B2_MAC_CFG 0x011a /* 8 bit MAC Configuration / Chip Revision */ +#define B2_CHIP_ID 0x011b /* 8 bit Chip Identification Number */ + /* Eprom registers are currently of no use */ +#define B2_E_0 0x011c /* 8 bit EPROM Byte 0 (ext. SRAM size */ +#define B2_E_1 0x011d /* 8 bit EPROM Byte 1 (PHY type) */ +#define B2_E_2 0x011e /* 8 bit EPROM Byte 2 */ +#define B2_E_3 0x011f /* 8 bit EPROM Byte 3 */ +#define B2_FAR 0x0120 /* 32 bit Flash-Prom Addr Reg/Cnt */ +#define B2_FDP 0x0124 /* 8 bit Flash-Prom Data Port */ + /* 0x0125 - 0x0127: reserved */ +#define B2_LD_CTRL 0x0128 /* 8 bit EPROM loader control register */ +#define B2_LD_TEST 0x0129 /* 8 bit EPROM loader test register */ + /* 0x012a - 0x012f: reserved */ +#define B2_TI_INI 0x0130 /* 32 bit Timer Init Value */ +#define B2_TI_VAL 0x0134 /* 32 bit Timer Value */ +#define B2_TI_CTRL 0x0138 /* 8 bit Timer Control */ +#define B2_TI_TEST 0x0139 /* 8 Bit Timer Test */ + /* 0x013a - 0x013f: reserved */ +#define B2_IRQM_INI 0x0140 /* 32 bit IRQ Moderation Timer Init Reg.*/ +#define B2_IRQM_VAL 0x0144 /* 32 bit IRQ Moderation Timer Value */ +#define B2_IRQM_CTRL 0x0148 /* 8 bit IRQ Moderation Timer Control */ +#define B2_IRQM_TEST 0x0149 /* 8 bit IRQ Moderation Timer Test */ +#define B2_IRQM_MSK 0x014c /* 32 bit IRQ Moderation Mask */ +#define B2_IRQM_HWE_MSK 0x0150 /* 32 bit IRQ Moderation HW Error Mask */ + /* 0x0154 - 0x0157: reserved */ +#define B2_TST_CTRL1 0x0158 /* 8 bit Test Control Register 1 */ +#define B2_TST_CTRL2 0x0159 /* 8 bit Test Control Register 2 */ + /* 0x015a - 0x015b: reserved */ +#define B2_GP_IO 0x015c /* 32 bit General Purpose I/O Register */ +#define B2_I2C_CTRL 0x0160 /* 32 bit I2C HW Control Register */ +#define B2_I2C_DATA 0x0164 /* 32 bit I2C HW Data Register */ +#define B2_I2C_IRQ 0x0168 /* 32 bit I2C HW IRQ Register */ +#define B2_I2C_SW 0x016c /* 32 bit I2C SW Port Register */ + +/* Blink Source Counter (GENESIS only) */ +#define B2_BSC_INI 0x0170 /* 32 bit Blink Source Counter Init Val */ +#define B2_BSC_VAL 0x0174 /* 32 bit Blink Source Counter Value */ +#define B2_BSC_CTRL 0x0178 /* 8 bit Blink Source Counter Control */ +#define B2_BSC_STAT 0x0179 /* 8 bit Blink Source Counter Status */ +#define B2_BSC_TST 0x017a /* 16 bit Blink Source Counter Test Reg */ + /* 0x017c - 0x017f: reserved */ + +/* + * Bank 3 + */ +/* RAM Random Registers */ +#define B3_RAM_ADDR 0x0180 /* 32 bit RAM Address, to read or write */ +#define B3_RAM_DATA_LO 0x0184 /* 32 bit RAM Data Word (low dWord) */ +#define B3_RAM_DATA_HI 0x0188 /* 32 bit RAM Data Word (high dWord) */ + /* 0x018c - 0x018f: reserved */ + +/* RAM Interface Registers */ +/* + * The HW-Spec. calls this registers Timeout Value 0..11. But this names are + * not usable in SW. Please notice these are NOT real timeouts, these are + * the number of qWords transferred continuously. + */ +#define B3_RI_WTO_R1 0x0190 /* 8 bit WR Timeout Queue R1 (TO0) */ +#define B3_RI_WTO_XA1 0x0191 /* 8 bit WR Timeout Queue XA1 (TO1) */ +#define B3_RI_WTO_XS1 0x0192 /* 8 bit WR Timeout Queue XS1 (TO2) */ +#define B3_RI_RTO_R1 0x0193 /* 8 bit RD Timeout Queue R1 (TO3) */ +#define B3_RI_RTO_XA1 0x0194 /* 8 bit RD Timeout Queue XA1 (TO4) */ +#define B3_RI_RTO_XS1 0x0195 /* 8 bit RD Timeout Queue XS1 (TO5) */ +#define B3_RI_WTO_R2 0x0196 /* 8 bit WR Timeout Queue R2 (TO6) */ +#define B3_RI_WTO_XA2 0x0197 /* 8 bit WR Timeout Queue XA2 (TO7) */ +#define B3_RI_WTO_XS2 0x0198 /* 8 bit WR Timeout Queue XS2 (TO8) */ +#define B3_RI_RTO_R2 0x0199 /* 8 bit RD Timeout Queue R2 (TO9) */ +#define B3_RI_RTO_XA2 0x019a /* 8 bit RD Timeout Queue XA2 (TO10)*/ +#define B3_RI_RTO_XS2 0x019b /* 8 bit RD Timeout Queue XS2 (TO11)*/ +#define B3_RI_TO_VAL 0x019c /* 8 bit Current Timeout Count Val */ + /* 0x019d - 0x019f: reserved */ +#define B3_RI_CTRL 0x01a0 /* 16 bit RAM Interface Control Register */ +#define B3_RI_TEST 0x01a2 /* 8 bit RAM Interface Test Register */ + /* 0x01a3 - 0x01af: reserved */ + +/* MAC Arbiter Registers (GENESIS only) */ +/* these are the no. of qWord transferred continuously and NOT real timeouts */ +#define B3_MA_TOINI_RX1 0x01b0 /* 8 bit Timeout Init Val Rx Path MAC 1 */ +#define B3_MA_TOINI_RX2 0x01b1 /* 8 bit Timeout Init Val Rx Path MAC 2 */ +#define B3_MA_TOINI_TX1 0x01b2 /* 8 bit Timeout Init Val Tx Path MAC 1 */ +#define B3_MA_TOINI_TX2 0x01b3 /* 8 bit Timeout Init Val Tx Path MAC 2 */ +#define B3_MA_TOVAL_RX1 0x01b4 /* 8 bit Timeout Value Rx Path MAC 1 */ +#define B3_MA_TOVAL_RX2 0x01b5 /* 8 bit Timeout Value Rx Path MAC 1 */ +#define B3_MA_TOVAL_TX1 0x01b6 /* 8 bit Timeout Value Tx Path MAC 2 */ +#define B3_MA_TOVAL_TX2 0x01b7 /* 8 bit Timeout Value Tx Path MAC 2 */ +#define B3_MA_TO_CTRL 0x01b8 /* 16 bit MAC Arbiter Timeout Ctrl Reg */ +#define B3_MA_TO_TEST 0x01ba /* 16 bit MAC Arbiter Timeout Test Reg */ + /* 0x01bc - 0x01bf: reserved */ +#define B3_MA_RCINI_RX1 0x01c0 /* 8 bit Recovery Init Val Rx Path MAC 1 */ +#define B3_MA_RCINI_RX2 0x01c1 /* 8 bit Recovery Init Val Rx Path MAC 2 */ +#define B3_MA_RCINI_TX1 0x01c2 /* 8 bit Recovery Init Val Tx Path MAC 1 */ +#define B3_MA_RCINI_TX2 0x01c3 /* 8 bit Recovery Init Val Tx Path MAC 2 */ +#define B3_MA_RCVAL_RX1 0x01c4 /* 8 bit Recovery Value Rx Path MAC 1 */ +#define B3_MA_RCVAL_RX2 0x01c5 /* 8 bit Recovery Value Rx Path MAC 1 */ +#define B3_MA_RCVAL_TX1 0x01c6 /* 8 bit Recovery Value Tx Path MAC 2 */ +#define B3_MA_RCVAL_TX2 0x01c7 /* 8 bit Recovery Value Tx Path MAC 2 */ +#define B3_MA_RC_CTRL 0x01c8 /* 16 bit MAC Arbiter Recovery Ctrl Reg */ +#define B3_MA_RC_TEST 0x01ca /* 16 bit MAC Arbiter Recovery Test Reg */ + /* 0x01cc - 0x01cf: reserved */ + +/* Packet Arbiter Registers (GENESIS only) */ +/* these are real timeouts */ +#define B3_PA_TOINI_RX1 0x01d0 /* 16 bit Timeout Init Val Rx Path MAC 1 */ + /* 0x01d2 - 0x01d3: reserved */ +#define B3_PA_TOINI_RX2 0x01d4 /* 16 bit Timeout Init Val Rx Path MAC 2 */ + /* 0x01d6 - 0x01d7: reserved */ +#define B3_PA_TOINI_TX1 0x01d8 /* 16 bit Timeout Init Val Tx Path MAC 1 */ + /* 0x01da - 0x01db: reserved */ +#define B3_PA_TOINI_TX2 0x01dc /* 16 bit Timeout Init Val Tx Path MAC 2 */ + /* 0x01de - 0x01df: reserved */ +#define B3_PA_TOVAL_RX1 0x01e0 /* 16 bit Timeout Val Rx Path MAC 1 */ + /* 0x01e2 - 0x01e3: reserved */ +#define B3_PA_TOVAL_RX2 0x01e4 /* 16 bit Timeout Val Rx Path MAC 2 */ + /* 0x01e6 - 0x01e7: reserved */ +#define B3_PA_TOVAL_TX1 0x01e8 /* 16 bit Timeout Val Tx Path MAC 1 */ + /* 0x01ea - 0x01eb: reserved */ +#define B3_PA_TOVAL_TX2 0x01ec /* 16 bit Timeout Val Tx Path MAC 2 */ + /* 0x01ee - 0x01ef: reserved */ +#define B3_PA_CTRL 0x01f0 /* 16 bit Packet Arbiter Ctrl Register */ +#define B3_PA_TEST 0x01f2 /* 16 bit Packet Arbiter Test Register */ + /* 0x01f4 - 0x01ff: reserved */ + +/* + * Bank 4 - 5 + */ +/* Transmit Arbiter Registers MAC 1 and 2, use MR_ADDR() to access */ +#define TXA_ITI_INI 0x0200 /* 32 bit Tx Arb Interval Timer Init Val*/ +#define TXA_ITI_VAL 0x0204 /* 32 bit Tx Arb Interval Timer Value */ +#define TXA_LIM_INI 0x0208 /* 32 bit Tx Arb Limit Counter Init Val */ +#define TXA_LIM_VAL 0x020c /* 32 bit Tx Arb Limit Counter Value */ +#define TXA_CTRL 0x0210 /* 8 bit Tx Arbiter Control Register */ +#define TXA_TEST 0x0211 /* 8 bit Tx Arbiter Test Register */ +#define TXA_STAT 0x0212 /* 8 bit Tx Arbiter Status Register */ + /* 0x0213 - 0x027f: reserved */ + /* 0x0280 - 0x0292: MAC 2 */ + /* 0x0213 - 0x027f: reserved */ + +/* + * Bank 6 + */ +/* External registers (GENESIS only) */ +#define B6_EXT_REG 0x0300 + +/* + * Bank 7 + */ +/* This is a copy of the Configuration register file (lower half) */ +#define B7_CFG_SPC 0x0380 + +/* + * Bank 8 - 15 + */ +/* Receive and Transmit Queue Registers, use Q_ADDR() to access */ +#define B8_Q_REGS 0x0400 + +/* Queue Register Offsets, use Q_ADDR() to access */ +#define Q_D 0x00 /* 8*32 bit Current Descriptor */ +#define Q_DA_L 0x20 /* 32 bit Current Descriptor Address Low dWord */ +#define Q_DA_H 0x24 /* 32 bit Current Descriptor Address High dWord */ +#define Q_AC_L 0x28 /* 32 bit Current Address Counter Low dWord */ +#define Q_AC_H 0x2c /* 32 bit Current Address Counter High dWord */ +#define Q_BC 0x30 /* 32 bit Current Byte Counter */ +#define Q_CSR 0x34 /* 32 bit BMU Control/Status Register */ +#define Q_F 0x38 /* 32 bit Flag Register */ +#define Q_T1 0x3c /* 32 bit Test Register 1 */ +#define Q_T1_TR 0x3c /* 8 bit Test Register 1 Transfer SM */ +#define Q_T1_WR 0x3d /* 8 bit Test Register 1 Write Descriptor SM */ +#define Q_T1_RD 0x3e /* 8 bit Test Register 1 Read Descriptor SM */ +#define Q_T1_SV 0x3f /* 8 bit Test Register 1 Supervisor SM */ +#define Q_T2 0x40 /* 32 bit Test Register 2 */ +#define Q_T3 0x44 /* 32 bit Test Register 3 */ + /* 0x48 - 0x7f: reserved */ + +/* + * Bank 16 - 23 + */ +/* RAM Buffer Registers */ +#define B16_RAM_REGS 0x0800 + +/* RAM Buffer Register Offsets, use RB_ADDR() to access */ +#define RB_START 0x00 /* 32 bit RAM Buffer Start Address */ +#define RB_END 0x04 /* 32 bit RAM Buffer End Address */ +#define RB_WP 0x08 /* 32 bit RAM Buffer Write Pointer */ +#define RB_RP 0x0c /* 32 bit RAM Buffer Read Pointer */ +#define RB_RX_UTPP 0x10 /* 32 bit Rx Upper Threshold, Pause Pack */ +#define RB_RX_LTPP 0x14 /* 32 bit Rx Lower Threshold, Pause Pack */ +#define RB_RX_UTHP 0x18 /* 32 bit Rx Upper Threshold, High Prio */ +#define RB_RX_LTHP 0x1c /* 32 bit Rx Lower Threshold, High Prio */ + /* 0x10 - 0x1f: reserved at Tx RAM Buffer Registers */ +#define RB_PC 0x20 /* 32 bit RAM Buffer Packet Counter */ +#define RB_LEV 0x24 /* 32 bit RAM Buffer Level Register */ +#define RB_CTRL 0x28 /* 8 bit RAM Buffer Control Register */ +#define RB_TST1 0x29 /* 8 bit RAM Buffer Test Register 1 */ +#define RB_TST2 0x2A /* 8 bit RAM Buffer Test Register 2 */ + /* 0x2c - 0x7f: reserved */ + +/* + * Bank 24 + */ +/* + * Receive MAC FIFO, Receive LED, and Link_Sync regs (GENESIS only) + * use MR_ADDR() to access + */ +#define RX_MFF_EA 0x0c00 /* 32 bit Receive MAC FIFO End Address */ +#define RX_MFF_WP 0x0c04 /* 32 bit Receive MAC FIFO Write Pointer */ + /* 0x0c08 - 0x0c0b: reserved */ +#define RX_MFF_RP 0x0c0c /* 32 bit Receive MAC FIFO Read Pointer */ +#define RX_MFF_PC 0x0c10 /* 32 bit Receive MAC FIFO Packet Cnt */ +#define RX_MFF_LEV 0x0c14 /* 32 bit Receive MAC FIFO Level */ +#define RX_MFF_CTRL1 0x0c18 /* 16 bit Receive MAC FIFO Control Reg 1*/ +#define RX_MFF_STAT_TO 0x0c1a /* 8 bit Receive MAC Status Timeout */ +#define RX_MFF_TIST_TO 0x0c1b /* 8 bit Receive MAC Time Stamp Timeout */ +#define RX_MFF_CTRL2 0x0c1c /* 8 bit Receive MAC FIFO Control Reg 2*/ +#define RX_MFF_TST1 0x0c1d /* 8 bit Receive MAC FIFO Test Reg 1 */ +#define RX_MFF_TST2 0x0c1e /* 8 bit Receive MAC FIFO Test Reg 2 */ + /* 0x0c1f: reserved */ +#define RX_LED_INI 0x0c20 /* 32 bit Receive LED Cnt Init Value */ +#define RX_LED_VAL 0x0c24 /* 32 bit Receive LED Cnt Current Value */ +#define RX_LED_CTRL 0x0c28 /* 8 bit Receive LED Cnt Control Reg */ +#define RX_LED_TST 0x0c29 /* 8 bit Receive LED Cnt Test Register */ + /* 0x0c2a - 0x0c2f: reserved */ +#define LNK_SYNC_INI 0x0c30 /* 32 bit Link Sync Cnt Init Value */ +#define LNK_SYNC_VAL 0x0c34 /* 32 bit Link Sync Cnt Current Value */ +#define LNK_SYNC_CTRL 0x0c38 /* 8 bit Link Sync Cnt Control Register */ +#define LNK_SYNC_TST 0x0c39 /* 8 bit Link Sync Cnt Test Register */ + /* 0x0c3a - 0x0c3b: reserved */ +#define LNK_LED_REG 0x0c3c /* 8 bit Link LED Register */ + /* 0x0c3d - 0x0c3f: reserved */ + +/* Receive GMAC FIFO (YUKON only), use MR_ADDR() to access */ +#define RX_GMF_EA 0x0c40 /* 32 bit Rx GMAC FIFO End Address */ +#define RX_GMF_AF_THR 0x0c44 /* 32 bit Rx GMAC FIFO Almost Full Thresh. */ +#define RX_GMF_CTRL_T 0x0c48 /* 32 bit Rx GMAC FIFO Control/Test */ +#define RX_GMF_FL_MSK 0x0c4c /* 32 bit Rx GMAC FIFO Flush Mask */ +#define RX_GMF_FL_THR 0x0c50 /* 32 bit Rx GMAC FIFO Flush Threshold */ + /* 0x0c54 - 0x0c5f: reserved */ +#define RX_GMF_WP 0x0c60 /* 32 bit Rx GMAC FIFO Write Pointer */ + /* 0x0c64 - 0x0c67: reserved */ +#define RX_GMF_WLEV 0x0c68 /* 32 bit Rx GMAC FIFO Write Level */ + /* 0x0c6c - 0x0c6f: reserved */ +#define RX_GMF_RP 0x0c70 /* 32 bit Rx GMAC FIFO Read Pointer */ + /* 0x0c74 - 0x0c77: reserved */ +#define RX_GMF_RLEV 0x0c78 /* 32 bit Rx GMAC FIFO Read Level */ + /* 0x0c7c - 0x0c7f: reserved */ + +/* + * Bank 25 + */ + /* 0x0c80 - 0x0cbf: MAC 2 */ + /* 0x0cc0 - 0x0cff: reserved */ + +/* + * Bank 26 + */ +/* + * Transmit MAC FIFO and Transmit LED Registers (GENESIS only), + * use MR_ADDR() to access + */ +#define TX_MFF_EA 0x0d00 /* 32 bit Transmit MAC FIFO End Address */ +#define TX_MFF_WP 0x0d04 /* 32 bit Transmit MAC FIFO WR Pointer */ +#define TX_MFF_WSP 0x0d08 /* 32 bit Transmit MAC FIFO WR Shadow Ptr */ +#define TX_MFF_RP 0x0d0c /* 32 bit Transmit MAC FIFO RD Pointer */ +#define TX_MFF_PC 0x0d10 /* 32 bit Transmit MAC FIFO Packet Cnt */ +#define TX_MFF_LEV 0x0d14 /* 32 bit Transmit MAC FIFO Level */ +#define TX_MFF_CTRL1 0x0d18 /* 16 bit Transmit MAC FIFO Ctrl Reg 1 */ +#define TX_MFF_WAF 0x0d1a /* 8 bit Transmit MAC Wait after flush */ + /* 0x0c1b: reserved */ +#define TX_MFF_CTRL2 0x0d1c /* 8 bit Transmit MAC FIFO Ctrl Reg 2 */ +#define TX_MFF_TST1 0x0d1d /* 8 bit Transmit MAC FIFO Test Reg 1 */ +#define TX_MFF_TST2 0x0d1e /* 8 bit Transmit MAC FIFO Test Reg 2 */ + /* 0x0d1f: reserved */ +#define TX_LED_INI 0x0d20 /* 32 bit Transmit LED Cnt Init Value */ +#define TX_LED_VAL 0x0d24 /* 32 bit Transmit LED Cnt Current Val */ +#define TX_LED_CTRL 0x0d28 /* 8 bit Transmit LED Cnt Control Reg */ +#define TX_LED_TST 0x0d29 /* 8 bit Transmit LED Cnt Test Reg */ + /* 0x0d2a - 0x0d3f: reserved */ + +/* Transmit GMAC FIFO (YUKON only), use MR_ADDR() to access */ +#define TX_GMF_EA 0x0d40 /* 32 bit Tx GMAC FIFO End Address */ +#define TX_GMF_AE_THR 0x0d44 /* 32 bit Tx GMAC FIFO Almost Empty Thresh.*/ +#define TX_GMF_CTRL_T 0x0d48 /* 32 bit Tx GMAC FIFO Control/Test */ + /* 0x0d4c - 0x0d5f: reserved */ +#define TX_GMF_WP 0x0d60 /* 32 bit Tx GMAC FIFO Write Pointer */ +#define TX_GMF_WSP 0x0d64 /* 32 bit Tx GMAC FIFO Write Shadow Ptr. */ +#define TX_GMF_WLEV 0x0d68 /* 32 bit Tx GMAC FIFO Write Level */ + /* 0x0d6c - 0x0d6f: reserved */ +#define TX_GMF_RP 0x0d70 /* 32 bit Tx GMAC FIFO Read Pointer */ +#define TX_GMF_RSTP 0x0d74 /* 32 bit Tx GMAC FIFO Restart Pointer */ +#define TX_GMF_RLEV 0x0d78 /* 32 bit Tx GMAC FIFO Read Level */ + /* 0x0d7c - 0x0d7f: reserved */ + +/* + * Bank 27 + */ + /* 0x0d80 - 0x0dbf: MAC 2 */ + /* 0x0daa - 0x0dff: reserved */ + +/* + * Bank 28 + */ +/* Descriptor Poll Timer Registers */ +#define B28_DPT_INI 0x0e00 /* 24 bit Descriptor Poll Timer Init Val */ +#define B28_DPT_VAL 0x0e04 /* 24 bit Descriptor Poll Timer Curr Val */ +#define B28_DPT_CTRL 0x0e08 /* 8 bit Descriptor Poll Timer Ctrl Reg */ + /* 0x0e09: reserved */ +#define B28_DPT_TST 0x0e0a /* 8 bit Descriptor Poll Timer Test Reg */ + /* 0x0e0b: reserved */ + +/* Time Stamp Timer Registers (YUKON only) */ + /* 0x0e10: reserved */ +#define GMAC_TI_ST_VAL 0x0e14 /* 32 bit Time Stamp Timer Curr Val */ +#define GMAC_TI_ST_CTRL 0x0e18 /* 8 bit Time Stamp Timer Ctrl Reg */ + /* 0x0e19: reserved */ +#define GMAC_TI_ST_TST 0x0e1a /* 8 bit Time Stamp Timer Test Reg */ + /* 0x0e1b - 0x0e7f: reserved */ + +/* + * Bank 29 + */ + /* 0x0e80 - 0x0efc: reserved */ + +/* + * Bank 30 + */ +/* GMAC and GPHY Control Registers (YUKON only) */ +#define GMAC_CTRL 0x0f00 /* 32 bit GMAC Control Reg */ +#define GPHY_CTRL 0x0f04 /* 32 bit GPHY Control Reg */ +#define GMAC_IRQ_SRC 0x0f08 /* 8 bit GMAC Interrupt Source Reg */ + /* 0x0f09 - 0x0f0b: reserved */ +#define GMAC_IRQ_MSK 0x0f0c /* 8 bit GMAC Interrupt Mask Reg */ + /* 0x0f0d - 0x0f0f: reserved */ +#define GMAC_LINK_CTRL 0x0f10 /* 16 bit Link Control Reg */ + /* 0x0f14 - 0x0f1f: reserved */ + +/* Wake-up Frame Pattern Match Control Registers (YUKON only) */ + +#define WOL_REG_OFFS 0x20 /* HW-Bug: Address is + 0x20 against spec. */ + +#define WOL_CTRL_STAT 0x0f20 /* 16 bit WOL Control/Status Reg */ +#define WOL_MATCH_CTL 0x0f22 /* 8 bit WOL Match Control Reg */ +#define WOL_MATCH_RES 0x0f23 /* 8 bit WOL Match Result Reg */ +#define WOL_MAC_ADDR_LO 0x0f24 /* 32 bit WOL MAC Address Low */ +#define WOL_MAC_ADDR_HI 0x0f28 /* 16 bit WOL MAC Address High */ +#define WOL_PATT_RPTR 0x0f2c /* 8 bit WOL Pattern Read Ptr */ + +/* use this macro to access above registers */ +#define WOL_REG(Reg) ((Reg) + (pAC->GIni.GIWolOffs)) + + +/* WOL Pattern Length Registers (YUKON only) */ + +#define WOL_PATT_LEN_LO 0x0f30 /* 32 bit WOL Pattern Length 3..0 */ +#define WOL_PATT_LEN_HI 0x0f34 /* 24 bit WOL Pattern Length 6..4 */ + +/* WOL Pattern Counter Registers (YUKON only) */ + +#define WOL_PATT_CNT_0 0x0f38 /* 32 bit WOL Pattern Counter 3..0 */ +#define WOL_PATT_CNT_4 0x0f3c /* 24 bit WOL Pattern Counter 6..4 */ + /* 0x0f40 - 0x0f7f: reserved */ + +/* + * Bank 31 + */ +/* 0x0f80 - 0x0fff: reserved */ + +/* + * Bank 32 - 33 + */ +#define WOL_PATT_RAM_1 0x1000 /* WOL Pattern RAM Link 1 */ + +/* + * Bank 0x22 - 0x3f + */ +/* 0x1100 - 0x1fff: reserved */ + +/* + * Bank 0x40 - 0x4f + */ +#define BASE_XMAC_1 0x2000 /* XMAC 1 registers */ + +/* + * Bank 0x50 - 0x5f + */ + +#define BASE_GMAC_1 0x2800 /* GMAC 1 registers */ + +/* + * Bank 0x60 - 0x6f + */ +#define BASE_XMAC_2 0x3000 /* XMAC 2 registers */ + +/* + * Bank 0x70 - 0x7f + */ +#define BASE_GMAC_2 0x3800 /* GMAC 2 registers */ + +/* + * Control Register Bit Definitions: + */ +/* B0_RAP 8 bit Register Address Port */ + /* Bit 7: reserved */ +#define RAP_RAP 0x3f /* Bit 6..0: 0 = block 0,..,6f = block 6f */ + +/* B0_CTST 16 bit Control/Status register */ + /* Bit 15..14: reserved */ +#define CS_CLK_RUN_HOT BIT_13S /* CLK_RUN hot m. (YUKON-Lite only) */ +#define CS_CLK_RUN_RST BIT_12S /* CLK_RUN reset (YUKON-Lite only) */ +#define CS_CLK_RUN_ENA BIT_11S /* CLK_RUN enable (YUKON-Lite only) */ +#define CS_VAUX_AVAIL BIT_10S /* VAUX available (YUKON only) */ +#define CS_BUS_CLOCK BIT_9S /* Bus Clock 0/1 = 33/66 MHz */ +#define CS_BUS_SLOT_SZ BIT_8S /* Slot Size 0/1 = 32/64 bit slot */ +#define CS_ST_SW_IRQ BIT_7S /* Set IRQ SW Request */ +#define CS_CL_SW_IRQ BIT_6S /* Clear IRQ SW Request */ +#define CS_STOP_DONE BIT_5S /* Stop Master is finished */ +#define CS_STOP_MAST BIT_4S /* Command Bit to stop the master */ +#define CS_MRST_CLR BIT_3S /* Clear Master reset */ +#define CS_MRST_SET BIT_2S /* Set Master reset */ +#define CS_RST_CLR BIT_1S /* Clear Software reset */ +#define CS_RST_SET BIT_0S /* Set Software reset */ + +/* B0_LED 8 Bit LED register */ + /* Bit 7.. 2: reserved */ +#define LED_STAT_ON BIT_1S /* Status LED on */ +#define LED_STAT_OFF BIT_0S /* Status LED off */ + +/* B0_POWER_CTRL 8 Bit Power Control reg (YUKON only) */ +#define PC_VAUX_ENA BIT_7 /* Switch VAUX Enable */ +#define PC_VAUX_DIS BIT_6 /* Switch VAUX Disable */ +#define PC_VCC_ENA BIT_5 /* Switch VCC Enable */ +#define PC_VCC_DIS BIT_4 /* Switch VCC Disable */ +#define PC_VAUX_ON BIT_3 /* Switch VAUX On */ +#define PC_VAUX_OFF BIT_2 /* Switch VAUX Off */ +#define PC_VCC_ON BIT_1 /* Switch VCC On */ +#define PC_VCC_OFF BIT_0 /* Switch VCC Off */ + +/* B0_ISRC 32 bit Interrupt Source Register */ +/* B0_IMSK 32 bit Interrupt Mask Register */ +/* B0_SP_ISRC 32 bit Special Interrupt Source Reg */ +/* B2_IRQM_MSK 32 bit IRQ Moderation Mask */ +#define IS_ALL_MSK 0xbfffffffUL /* All Interrupt bits */ +#define IS_HW_ERR BIT_31 /* Interrupt HW Error */ + /* Bit 30: reserved */ +#define IS_PA_TO_RX1 BIT_29 /* Packet Arb Timeout Rx1 */ +#define IS_PA_TO_RX2 BIT_28 /* Packet Arb Timeout Rx2 */ +#define IS_PA_TO_TX1 BIT_27 /* Packet Arb Timeout Tx1 */ +#define IS_PA_TO_TX2 BIT_26 /* Packet Arb Timeout Tx2 */ +#define IS_I2C_READY BIT_25 /* IRQ on end of I2C Tx */ +#define IS_IRQ_SW BIT_24 /* SW forced IRQ */ +#define IS_EXT_REG BIT_23 /* IRQ from LM80 or PHY (GENESIS only) */ + /* IRQ from PHY (YUKON only) */ +#define IS_TIMINT BIT_22 /* IRQ from Timer */ +#define IS_MAC1 BIT_21 /* IRQ from MAC 1 */ +#define IS_LNK_SYNC_M1 BIT_20 /* Link Sync Cnt wrap MAC 1 */ +#define IS_MAC2 BIT_19 /* IRQ from MAC 2 */ +#define IS_LNK_SYNC_M2 BIT_18 /* Link Sync Cnt wrap MAC 2 */ +/* Receive Queue 1 */ +#define IS_R1_B BIT_17 /* Q_R1 End of Buffer */ +#define IS_R1_F BIT_16 /* Q_R1 End of Frame */ +#define IS_R1_C BIT_15 /* Q_R1 Encoding Error */ +/* Receive Queue 2 */ +#define IS_R2_B BIT_14 /* Q_R2 End of Buffer */ +#define IS_R2_F BIT_13 /* Q_R2 End of Frame */ +#define IS_R2_C BIT_12 /* Q_R2 Encoding Error */ +/* Synchronous Transmit Queue 1 */ +#define IS_XS1_B BIT_11 /* Q_XS1 End of Buffer */ +#define IS_XS1_F BIT_10 /* Q_XS1 End of Frame */ +#define IS_XS1_C BIT_9 /* Q_XS1 Encoding Error */ +/* Asynchronous Transmit Queue 1 */ +#define IS_XA1_B BIT_8 /* Q_XA1 End of Buffer */ +#define IS_XA1_F BIT_7 /* Q_XA1 End of Frame */ +#define IS_XA1_C BIT_6 /* Q_XA1 Encoding Error */ +/* Synchronous Transmit Queue 2 */ +#define IS_XS2_B BIT_5 /* Q_XS2 End of Buffer */ +#define IS_XS2_F BIT_4 /* Q_XS2 End of Frame */ +#define IS_XS2_C BIT_3 /* Q_XS2 Encoding Error */ +/* Asynchronous Transmit Queue 2 */ +#define IS_XA2_B BIT_2 /* Q_XA2 End of Buffer */ +#define IS_XA2_F BIT_1 /* Q_XA2 End of Frame */ +#define IS_XA2_C BIT_0 /* Q_XA2 Encoding Error */ + + +/* B0_HWE_ISRC 32 bit HW Error Interrupt Src Reg */ +/* B0_HWE_IMSK 32 bit HW Error Interrupt Mask Reg */ +/* B2_IRQM_HWE_MSK 32 bit IRQ Moderation HW Error Mask */ +#define IS_ERR_MSK 0x00000fffL /* All Error bits */ + /* Bit 31..14: reserved */ +#define IS_IRQ_TIST_OV BIT_13 /* Time Stamp Timer Overflow (YUKON only) */ +#define IS_IRQ_SENSOR BIT_12 /* IRQ from Sensor (YUKON only) */ +#define IS_IRQ_MST_ERR BIT_11 /* IRQ master error detected */ +#define IS_IRQ_STAT BIT_10 /* IRQ status exception */ +#define IS_NO_STAT_M1 BIT_9 /* No Rx Status from MAC 1 */ +#define IS_NO_STAT_M2 BIT_8 /* No Rx Status from MAC 2 */ +#define IS_NO_TIST_M1 BIT_7 /* No Time Stamp from MAC 1 */ +#define IS_NO_TIST_M2 BIT_6 /* No Time Stamp from MAC 2 */ +#define IS_RAM_RD_PAR BIT_5 /* RAM Read Parity Error */ +#define IS_RAM_WR_PAR BIT_4 /* RAM Write Parity Error */ +#define IS_M1_PAR_ERR BIT_3 /* MAC 1 Parity Error */ +#define IS_M2_PAR_ERR BIT_2 /* MAC 2 Parity Error */ +#define IS_R1_PAR_ERR BIT_1 /* Queue R1 Parity Error */ +#define IS_R2_PAR_ERR BIT_0 /* Queue R2 Parity Error */ + +/* B2_CONN_TYP 8 bit Connector type */ +/* B2_PMD_TYP 8 bit PMD type */ +/* Values of connector and PMD type comply to SysKonnect internal std */ + +/* B2_MAC_CFG 8 bit MAC Configuration / Chip Revision */ +#define CFG_CHIP_R_MSK (0xf<<4) /* Bit 7.. 4: Chip Revision */ + /* Bit 3.. 2: reserved */ +#define CFG_DIS_M2_CLK BIT_1S /* Disable Clock for 2nd MAC */ +#define CFG_SNG_MAC BIT_0S /* MAC Config: 0=2 MACs / 1=1 MAC*/ + +/* B2_CHIP_ID 8 bit Chip Identification Number */ +#define CHIP_ID_GENESIS 0x0a /* Chip ID for GENESIS */ +#define CHIP_ID_YUKON 0xb0 /* Chip ID for YUKON */ +#define CHIP_ID_YUKON_LITE 0xb1 /* Chip ID for YUKON-Lite (Rev. A1-A3) */ +#define CHIP_ID_YUKON_LP 0xb2 /* Chip ID for YUKON-LP */ + +#define CHIP_REV_YU_LITE_A1 3 /* Chip Rev. for YUKON-Lite A1,A2 */ +#define CHIP_REV_YU_LITE_A3 7 /* Chip Rev. for YUKON-Lite A3 */ + +/* B2_FAR 32 bit Flash-Prom Addr Reg/Cnt */ +#define FAR_ADDR 0x1ffffL /* Bit 16.. 0: FPROM Address mask */ + +/* B2_LD_CTRL 8 bit EPROM loader control register */ +/* Bits are currently reserved */ + +/* B2_LD_TEST 8 bit EPROM loader test register */ + /* Bit 7.. 4: reserved */ +#define LD_T_ON BIT_3S /* Loader Test mode on */ +#define LD_T_OFF BIT_2S /* Loader Test mode off */ +#define LD_T_STEP BIT_1S /* Decrement FPROM addr. Counter */ +#define LD_START BIT_0S /* Start loading FPROM */ + +/* + * Timer Section + */ +/* B2_TI_CTRL 8 bit Timer control */ +/* B2_IRQM_CTRL 8 bit IRQ Moderation Timer Control */ + /* Bit 7.. 3: reserved */ +#define TIM_START BIT_2S /* Start Timer */ +#define TIM_STOP BIT_1S /* Stop Timer */ +#define TIM_CLR_IRQ BIT_0S /* Clear Timer IRQ (!IRQM) */ + +/* B2_TI_TEST 8 Bit Timer Test */ +/* B2_IRQM_TEST 8 bit IRQ Moderation Timer Test */ +/* B28_DPT_TST 8 bit Descriptor Poll Timer Test Reg */ + /* Bit 7.. 3: reserved */ +#define TIM_T_ON BIT_2S /* Test mode on */ +#define TIM_T_OFF BIT_1S /* Test mode off */ +#define TIM_T_STEP BIT_0S /* Test step */ + +/* B28_DPT_INI 32 bit Descriptor Poll Timer Init Val */ +/* B28_DPT_VAL 32 bit Descriptor Poll Timer Curr Val */ + /* Bit 31..24: reserved */ +#define DPT_MSK 0x00ffffffL /* Bit 23.. 0: Desc Poll Timer Bits */ + +/* B28_DPT_CTRL 8 bit Descriptor Poll Timer Ctrl Reg */ + /* Bit 7.. 2: reserved */ +#define DPT_START BIT_1S /* Start Descriptor Poll Timer */ +#define DPT_STOP BIT_0S /* Stop Descriptor Poll Timer */ + +/* B2_E_3 8 bit lower 4 bits used for HW self test result */ +#define B2_E3_RES_MASK 0x0f + +/* B2_TST_CTRL1 8 bit Test Control Register 1 */ +#define TST_FRC_DPERR_MR BIT_7S /* force DATAPERR on MST RD */ +#define TST_FRC_DPERR_MW BIT_6S /* force DATAPERR on MST WR */ +#define TST_FRC_DPERR_TR BIT_5S /* force DATAPERR on TRG RD */ +#define TST_FRC_DPERR_TW BIT_4S /* force DATAPERR on TRG WR */ +#define TST_FRC_APERR_M BIT_3S /* force ADDRPERR on MST */ +#define TST_FRC_APERR_T BIT_2S /* force ADDRPERR on TRG */ +#define TST_CFG_WRITE_ON BIT_1S /* Enable Config Reg WR */ +#define TST_CFG_WRITE_OFF BIT_0S /* Disable Config Reg WR */ + +/* B2_TST_CTRL2 8 bit Test Control Register 2 */ + /* Bit 7.. 4: reserved */ + /* force the following error on the next master read/write */ +#define TST_FRC_DPERR_MR64 BIT_3S /* DataPERR RD 64 */ +#define TST_FRC_DPERR_MW64 BIT_2S /* DataPERR WR 64 */ +#define TST_FRC_APERR_1M64 BIT_1S /* AddrPERR on 1. phase */ +#define TST_FRC_APERR_2M64 BIT_0S /* AddrPERR on 2. phase */ + +/* B2_GP_IO 32 bit General Purpose I/O Register */ + /* Bit 31..26: reserved */ +#define GP_DIR_9 BIT_25 /* IO_9 direct, 0=In/1=Out */ +#define GP_DIR_8 BIT_24 /* IO_8 direct, 0=In/1=Out */ +#define GP_DIR_7 BIT_23 /* IO_7 direct, 0=In/1=Out */ +#define GP_DIR_6 BIT_22 /* IO_6 direct, 0=In/1=Out */ +#define GP_DIR_5 BIT_21 /* IO_5 direct, 0=In/1=Out */ +#define GP_DIR_4 BIT_20 /* IO_4 direct, 0=In/1=Out */ +#define GP_DIR_3 BIT_19 /* IO_3 direct, 0=In/1=Out */ +#define GP_DIR_2 BIT_18 /* IO_2 direct, 0=In/1=Out */ +#define GP_DIR_1 BIT_17 /* IO_1 direct, 0=In/1=Out */ +#define GP_DIR_0 BIT_16 /* IO_0 direct, 0=In/1=Out */ + /* Bit 15..10: reserved */ +#define GP_IO_9 BIT_9 /* IO_9 pin */ +#define GP_IO_8 BIT_8 /* IO_8 pin */ +#define GP_IO_7 BIT_7 /* IO_7 pin */ +#define GP_IO_6 BIT_6 /* IO_6 pin */ +#define GP_IO_5 BIT_5 /* IO_5 pin */ +#define GP_IO_4 BIT_4 /* IO_4 pin */ +#define GP_IO_3 BIT_3 /* IO_3 pin */ +#define GP_IO_2 BIT_2 /* IO_2 pin */ +#define GP_IO_1 BIT_1 /* IO_1 pin */ +#define GP_IO_0 BIT_0 /* IO_0 pin */ + +/* B2_I2C_CTRL 32 bit I2C HW Control Register */ +#define I2C_FLAG BIT_31 /* Start read/write if WR */ +#define I2C_ADDR (0x7fffL<<16) /* Bit 30..16: Addr to be RD/WR */ +#define I2C_DEV_SEL (0x7fL<<9) /* Bit 15.. 9: I2C Device Select */ + /* Bit 8.. 5: reserved */ +#define I2C_BURST_LEN BIT_4 /* Burst Len, 1/4 bytes */ +#define I2C_DEV_SIZE (7<<1) /* Bit 3.. 1: I2C Device Size */ +#define I2C_025K_DEV (0<<1) /* 0: 256 Bytes or smal. */ +#define I2C_05K_DEV (1<<1) /* 1: 512 Bytes */ +#define I2C_1K_DEV (2<<1) /* 2: 1024 Bytes */ +#define I2C_2K_DEV (3<<1) /* 3: 2048 Bytes */ +#define I2C_4K_DEV (4<<1) /* 4: 4096 Bytes */ +#define I2C_8K_DEV (5<<1) /* 5: 8192 Bytes */ +#define I2C_16K_DEV (6<<1) /* 6: 16384 Bytes */ +#define I2C_32K_DEV (7<<1) /* 7: 32768 Bytes */ +#define I2C_STOP BIT_0 /* Interrupt I2C transfer */ + +/* B2_I2C_IRQ 32 bit I2C HW IRQ Register */ + /* Bit 31.. 1 reserved */ +#define I2C_CLR_IRQ BIT_0 /* Clear I2C IRQ */ + +/* B2_I2C_SW 32 bit (8 bit access) I2C HW SW Port Register */ + /* Bit 7.. 3: reserved */ +#define I2C_DATA_DIR BIT_2S /* direction of I2C_DATA */ +#define I2C_DATA BIT_1S /* I2C Data Port */ +#define I2C_CLK BIT_0S /* I2C Clock Port */ + +/* + * I2C Address + */ +#define I2C_SENS_ADDR LM80_ADDR /* I2C Sensor Address, (Volt and Temp)*/ + + +/* B2_BSC_CTRL 8 bit Blink Source Counter Control */ + /* Bit 7.. 2: reserved */ +#define BSC_START BIT_1S /* Start Blink Source Counter */ +#define BSC_STOP BIT_0S /* Stop Blink Source Counter */ + +/* B2_BSC_STAT 8 bit Blink Source Counter Status */ + /* Bit 7.. 1: reserved */ +#define BSC_SRC BIT_0S /* Blink Source, 0=Off / 1=On */ + +/* B2_BSC_TST 16 bit Blink Source Counter Test Reg */ +#define BSC_T_ON BIT_2S /* Test mode on */ +#define BSC_T_OFF BIT_1S /* Test mode off */ +#define BSC_T_STEP BIT_0S /* Test step */ + + +/* B3_RAM_ADDR 32 bit RAM Address, to read or write */ + /* Bit 31..19: reserved */ +#define RAM_ADR_RAN 0x0007ffffL /* Bit 18.. 0: RAM Address Range */ + +/* RAM Interface Registers */ +/* B3_RI_CTRL 16 bit RAM Iface Control Register */ + /* Bit 15..10: reserved */ +#define RI_CLR_RD_PERR BIT_9S /* Clear IRQ RAM Read Parity Err */ +#define RI_CLR_WR_PERR BIT_8S /* Clear IRQ RAM Write Parity Err*/ + /* Bit 7.. 2: reserved */ +#define RI_RST_CLR BIT_1S /* Clear RAM Interface Reset */ +#define RI_RST_SET BIT_0S /* Set RAM Interface Reset */ + +/* B3_RI_TEST 8 bit RAM Iface Test Register */ + /* Bit 15.. 4: reserved */ +#define RI_T_EV BIT_3S /* Timeout Event occured */ +#define RI_T_ON BIT_2S /* Timeout Timer Test On */ +#define RI_T_OFF BIT_1S /* Timeout Timer Test Off */ +#define RI_T_STEP BIT_0S /* Timeout Timer Step */ + +/* MAC Arbiter Registers */ +/* B3_MA_TO_CTRL 16 bit MAC Arbiter Timeout Ctrl Reg */ + /* Bit 15.. 4: reserved */ +#define MA_FOE_ON BIT_3S /* XMAC Fast Output Enable ON */ +#define MA_FOE_OFF BIT_2S /* XMAC Fast Output Enable OFF */ +#define MA_RST_CLR BIT_1S /* Clear MAC Arbiter Reset */ +#define MA_RST_SET BIT_0S /* Set MAC Arbiter Reset */ + +/* B3_MA_RC_CTRL 16 bit MAC Arbiter Recovery Ctrl Reg */ + /* Bit 15.. 8: reserved */ +#define MA_ENA_REC_TX2 BIT_7S /* Enable Recovery Timer TX2 */ +#define MA_DIS_REC_TX2 BIT_6S /* Disable Recovery Timer TX2 */ +#define MA_ENA_REC_TX1 BIT_5S /* Enable Recovery Timer TX1 */ +#define MA_DIS_REC_TX1 BIT_4S /* Disable Recovery Timer TX1 */ +#define MA_ENA_REC_RX2 BIT_3S /* Enable Recovery Timer RX2 */ +#define MA_DIS_REC_RX2 BIT_2S /* Disable Recovery Timer RX2 */ +#define MA_ENA_REC_RX1 BIT_1S /* Enable Recovery Timer RX1 */ +#define MA_DIS_REC_RX1 BIT_0S /* Disable Recovery Timer RX1 */ + +/* Packet Arbiter Registers */ +/* B3_PA_CTRL 16 bit Packet Arbiter Ctrl Register */ + /* Bit 15..14: reserved */ +#define PA_CLR_TO_TX2 BIT_13S /* Clear IRQ Packet Timeout TX2 */ +#define PA_CLR_TO_TX1 BIT_12S /* Clear IRQ Packet Timeout TX1 */ +#define PA_CLR_TO_RX2 BIT_11S /* Clear IRQ Packet Timeout RX2 */ +#define PA_CLR_TO_RX1 BIT_10S /* Clear IRQ Packet Timeout RX1 */ +#define PA_ENA_TO_TX2 BIT_9S /* Enable Timeout Timer TX2 */ +#define PA_DIS_TO_TX2 BIT_8S /* Disable Timeout Timer TX2 */ +#define PA_ENA_TO_TX1 BIT_7S /* Enable Timeout Timer TX1 */ +#define PA_DIS_TO_TX1 BIT_6S /* Disable Timeout Timer TX1 */ +#define PA_ENA_TO_RX2 BIT_5S /* Enable Timeout Timer RX2 */ +#define PA_DIS_TO_RX2 BIT_4S /* Disable Timeout Timer RX2 */ +#define PA_ENA_TO_RX1 BIT_3S /* Enable Timeout Timer RX1 */ +#define PA_DIS_TO_RX1 BIT_2S /* Disable Timeout Timer RX1 */ +#define PA_RST_CLR BIT_1S /* Clear MAC Arbiter Reset */ +#define PA_RST_SET BIT_0S /* Set MAC Arbiter Reset */ + +#define PA_ENA_TO_ALL (PA_ENA_TO_RX1 | PA_ENA_TO_RX2 |\ + PA_ENA_TO_TX1 | PA_ENA_TO_TX2) + +/* Rx/Tx Path related Arbiter Test Registers */ +/* B3_MA_TO_TEST 16 bit MAC Arbiter Timeout Test Reg */ +/* B3_MA_RC_TEST 16 bit MAC Arbiter Recovery Test Reg */ +/* B3_PA_TEST 16 bit Packet Arbiter Test Register */ +/* Bit 15, 11, 7, and 3 are reserved in B3_PA_TEST */ +#define TX2_T_EV BIT_15S /* TX2 Timeout/Recv Event occured */ +#define TX2_T_ON BIT_14S /* TX2 Timeout/Recv Timer Test On */ +#define TX2_T_OFF BIT_13S /* TX2 Timeout/Recv Timer Tst Off */ +#define TX2_T_STEP BIT_12S /* TX2 Timeout/Recv Timer Step */ +#define TX1_T_EV BIT_11S /* TX1 Timeout/Recv Event occured */ +#define TX1_T_ON BIT_10S /* TX1 Timeout/Recv Timer Test On */ +#define TX1_T_OFF BIT_9S /* TX1 Timeout/Recv Timer Tst Off */ +#define TX1_T_STEP BIT_8S /* TX1 Timeout/Recv Timer Step */ +#define RX2_T_EV BIT_7S /* RX2 Timeout/Recv Event occured */ +#define RX2_T_ON BIT_6S /* RX2 Timeout/Recv Timer Test On */ +#define RX2_T_OFF BIT_5S /* RX2 Timeout/Recv Timer Tst Off */ +#define RX2_T_STEP BIT_4S /* RX2 Timeout/Recv Timer Step */ +#define RX1_T_EV BIT_3S /* RX1 Timeout/Recv Event occured */ +#define RX1_T_ON BIT_2S /* RX1 Timeout/Recv Timer Test On */ +#define RX1_T_OFF BIT_1S /* RX1 Timeout/Recv Timer Tst Off */ +#define RX1_T_STEP BIT_0S /* RX1 Timeout/Recv Timer Step */ + + +/* Transmit Arbiter Registers MAC 1 and 2, use MR_ADDR() to access */ +/* TXA_ITI_INI 32 bit Tx Arb Interval Timer Init Val */ +/* TXA_ITI_VAL 32 bit Tx Arb Interval Timer Value */ +/* TXA_LIM_INI 32 bit Tx Arb Limit Counter Init Val */ +/* TXA_LIM_VAL 32 bit Tx Arb Limit Counter Value */ + /* Bit 31..24: reserved */ +#define TXA_MAX_VAL 0x00ffffffUL/* Bit 23.. 0: Max TXA Timer/Cnt Val */ + +/* TXA_CTRL 8 bit Tx Arbiter Control Register */ +#define TXA_ENA_FSYNC BIT_7S /* Enable force of sync Tx queue */ +#define TXA_DIS_FSYNC BIT_6S /* Disable force of sync Tx queue */ +#define TXA_ENA_ALLOC BIT_5S /* Enable alloc of free bandwidth */ +#define TXA_DIS_ALLOC BIT_4S /* Disable alloc of free bandwidth */ +#define TXA_START_RC BIT_3S /* Start sync Rate Control */ +#define TXA_STOP_RC BIT_2S /* Stop sync Rate Control */ +#define TXA_ENA_ARB BIT_1S /* Enable Tx Arbiter */ +#define TXA_DIS_ARB BIT_0S /* Disable Tx Arbiter */ + +/* TXA_TEST 8 bit Tx Arbiter Test Register */ + /* Bit 7.. 6: reserved */ +#define TXA_INT_T_ON BIT_5S /* Tx Arb Interval Timer Test On */ +#define TXA_INT_T_OFF BIT_4S /* Tx Arb Interval Timer Test Off */ +#define TXA_INT_T_STEP BIT_3S /* Tx Arb Interval Timer Step */ +#define TXA_LIM_T_ON BIT_2S /* Tx Arb Limit Timer Test On */ +#define TXA_LIM_T_OFF BIT_1S /* Tx Arb Limit Timer Test Off */ +#define TXA_LIM_T_STEP BIT_0S /* Tx Arb Limit Timer Step */ + +/* TXA_STAT 8 bit Tx Arbiter Status Register */ + /* Bit 7.. 1: reserved */ +#define TXA_PRIO_XS BIT_0S /* sync queue has prio to send */ + +/* Q_BC 32 bit Current Byte Counter */ + /* Bit 31..16: reserved */ +#define BC_MAX 0xffff /* Bit 15.. 0: Byte counter */ + +/* BMU Control Status Registers */ +/* B0_R1_CSR 32 bit BMU Ctrl/Stat Rx Queue 1 */ +/* B0_R2_CSR 32 bit BMU Ctrl/Stat Rx Queue 2 */ +/* B0_XA1_CSR 32 bit BMU Ctrl/Stat Sync Tx Queue 1 */ +/* B0_XS1_CSR 32 bit BMU Ctrl/Stat Async Tx Queue 1 */ +/* B0_XA2_CSR 32 bit BMU Ctrl/Stat Sync Tx Queue 2 */ +/* B0_XS2_CSR 32 bit BMU Ctrl/Stat Async Tx Queue 2 */ +/* Q_CSR 32 bit BMU Control/Status Register */ + /* Bit 31..25: reserved */ +#define CSR_SV_IDLE BIT_24 /* BMU SM Idle */ + /* Bit 23..22: reserved */ +#define CSR_DESC_CLR BIT_21 /* Clear Reset for Descr */ +#define CSR_DESC_SET BIT_20 /* Set Reset for Descr */ +#define CSR_FIFO_CLR BIT_19 /* Clear Reset for FIFO */ +#define CSR_FIFO_SET BIT_18 /* Set Reset for FIFO */ +#define CSR_HPI_RUN BIT_17 /* Release HPI SM */ +#define CSR_HPI_RST BIT_16 /* Reset HPI SM to Idle */ +#define CSR_SV_RUN BIT_15 /* Release Supervisor SM */ +#define CSR_SV_RST BIT_14 /* Reset Supervisor SM */ +#define CSR_DREAD_RUN BIT_13 /* Release Descr Read SM */ +#define CSR_DREAD_RST BIT_12 /* Reset Descr Read SM */ +#define CSR_DWRITE_RUN BIT_11 /* Release Descr Write SM */ +#define CSR_DWRITE_RST BIT_10 /* Reset Descr Write SM */ +#define CSR_TRANS_RUN BIT_9 /* Release Transfer SM */ +#define CSR_TRANS_RST BIT_8 /* Reset Transfer SM */ +#define CSR_ENA_POL BIT_7 /* Enable Descr Polling */ +#define CSR_DIS_POL BIT_6 /* Disable Descr Polling */ +#define CSR_STOP BIT_5 /* Stop Rx/Tx Queue */ +#define CSR_START BIT_4 /* Start Rx/Tx Queue */ +#define CSR_IRQ_CL_P BIT_3 /* (Rx) Clear Parity IRQ */ +#define CSR_IRQ_CL_B BIT_2 /* Clear EOB IRQ */ +#define CSR_IRQ_CL_F BIT_1 /* Clear EOF IRQ */ +#define CSR_IRQ_CL_C BIT_0 /* Clear ERR IRQ */ + +#define CSR_SET_RESET (CSR_DESC_SET | CSR_FIFO_SET | CSR_HPI_RST |\ + CSR_SV_RST | CSR_DREAD_RST | CSR_DWRITE_RST |\ + CSR_TRANS_RST) +#define CSR_CLR_RESET (CSR_DESC_CLR | CSR_FIFO_CLR | CSR_HPI_RUN |\ + CSR_SV_RUN | CSR_DREAD_RUN | CSR_DWRITE_RUN |\ + CSR_TRANS_RUN) + +/* Q_F 32 bit Flag Register */ + /* Bit 31..28: reserved */ +#define F_ALM_FULL BIT_27 /* Rx FIFO: almost full */ +#define F_EMPTY BIT_27 /* Tx FIFO: empty flag */ +#define F_FIFO_EOF BIT_26 /* Tag (EOF Flag) bit in FIFO */ +#define F_WM_REACHED BIT_25 /* Watermark reached */ + /* reserved */ +#define F_FIFO_LEVEL (0x1fL<<16) /* Bit 23..16: # of Qwords in FIFO */ + /* Bit 15..11: reserved */ +#define F_WATER_MARK 0x0007ffL /* Bit 10.. 0: Watermark */ + +/* Q_T1 32 bit Test Register 1 */ +/* Holds four State Machine control Bytes */ +#define SM_CTRL_SV_MSK (0xffL<<24) /* Bit 31..24: Control Supervisor SM */ +#define SM_CTRL_RD_MSK (0xffL<<16) /* Bit 23..16: Control Read Desc SM */ +#define SM_CTRL_WR_MSK (0xffL<<8) /* Bit 15.. 8: Control Write Desc SM */ +#define SM_CTRL_TR_MSK 0xffL /* Bit 7.. 0: Control Transfer SM */ + +/* Q_T1_TR 8 bit Test Register 1 Transfer SM */ +/* Q_T1_WR 8 bit Test Register 1 Write Descriptor SM */ +/* Q_T1_RD 8 bit Test Register 1 Read Descriptor SM */ +/* Q_T1_SV 8 bit Test Register 1 Supervisor SM */ + +/* The control status byte of each machine looks like ... */ +#define SM_STATE 0xf0 /* Bit 7.. 4: State which shall be loaded */ +#define SM_LOAD BIT_3S /* Load the SM with SM_STATE */ +#define SM_TEST_ON BIT_2S /* Switch on SM Test Mode */ +#define SM_TEST_OFF BIT_1S /* Go off the Test Mode */ +#define SM_STEP BIT_0S /* Step the State Machine */ +/* The encoding of the states is not supported by the Diagnostics Tool */ + +/* Q_T2 32 bit Test Register 2 */ + /* Bit 31.. 8: reserved */ +#define T2_AC_T_ON BIT_7 /* Address Counter Test Mode on */ +#define T2_AC_T_OFF BIT_6 /* Address Counter Test Mode off */ +#define T2_BC_T_ON BIT_5 /* Byte Counter Test Mode on */ +#define T2_BC_T_OFF BIT_4 /* Byte Counter Test Mode off */ +#define T2_STEP04 BIT_3 /* Inc AC/Dec BC by 4 */ +#define T2_STEP03 BIT_2 /* Inc AC/Dec BC by 3 */ +#define T2_STEP02 BIT_1 /* Inc AC/Dec BC by 2 */ +#define T2_STEP01 BIT_0 /* Inc AC/Dec BC by 1 */ + +/* Q_T3 32 bit Test Register 3 */ + /* Bit 31.. 7: reserved */ +#define T3_MUX_MSK (7<<4) /* Bit 6.. 4: Mux Position */ + /* Bit 3: reserved */ +#define T3_VRAM_MSK 7 /* Bit 2.. 0: Virtual RAM Buffer Address */ + +/* RAM Buffer Register Offsets, use RB_ADDR(Queue, Offs) to access */ +/* RB_START 32 bit RAM Buffer Start Address */ +/* RB_END 32 bit RAM Buffer End Address */ +/* RB_WP 32 bit RAM Buffer Write Pointer */ +/* RB_RP 32 bit RAM Buffer Read Pointer */ +/* RB_RX_UTPP 32 bit Rx Upper Threshold, Pause Pack */ +/* RB_RX_LTPP 32 bit Rx Lower Threshold, Pause Pack */ +/* RB_RX_UTHP 32 bit Rx Upper Threshold, High Prio */ +/* RB_RX_LTHP 32 bit Rx Lower Threshold, High Prio */ +/* RB_PC 32 bit RAM Buffer Packet Counter */ +/* RB_LEV 32 bit RAM Buffer Level Register */ + /* Bit 31..19: reserved */ +#define RB_MSK 0x0007ffff /* Bit 18.. 0: RAM Buffer Pointer Bits */ + +/* RB_TST2 8 bit RAM Buffer Test Register 2 */ + /* Bit 7.. 4: reserved */ +#define RB_PC_DEC BIT_3S /* Packet Counter Decrem */ +#define RB_PC_T_ON BIT_2S /* Packet Counter Test On */ +#define RB_PC_T_OFF BIT_1S /* Packet Counter Tst Off */ +#define RB_PC_INC BIT_0S /* Packet Counter Increm */ + +/* RB_TST1 8 bit RAM Buffer Test Register 1 */ + /* Bit 7: reserved */ +#define RB_WP_T_ON BIT_6S /* Write Pointer Test On */ +#define RB_WP_T_OFF BIT_5S /* Write Pointer Test Off */ +#define RB_WP_INC BIT_4S /* Write Pointer Increm */ + /* Bit 3: reserved */ +#define RB_RP_T_ON BIT_2S /* Read Pointer Test On */ +#define RB_RP_T_OFF BIT_1S /* Read Pointer Test Off */ +#define RB_RP_DEC BIT_0S /* Read Pointer Decrement */ + +/* RB_CTRL 8 bit RAM Buffer Control Register */ + /* Bit 7.. 6: reserved */ +#define RB_ENA_STFWD BIT_5S /* Enable Store & Forward */ +#define RB_DIS_STFWD BIT_4S /* Disable Store & Forward */ +#define RB_ENA_OP_MD BIT_3S /* Enable Operation Mode */ +#define RB_DIS_OP_MD BIT_2S /* Disable Operation Mode */ +#define RB_RST_CLR BIT_1S /* Clear RAM Buf STM Reset */ +#define RB_RST_SET BIT_0S /* Set RAM Buf STM Reset */ + + +/* Receive and Transmit MAC FIFO Registers (GENESIS only) */ + +/* RX_MFF_EA 32 bit Receive MAC FIFO End Address */ +/* RX_MFF_WP 32 bit Receive MAC FIFO Write Pointer */ +/* RX_MFF_RP 32 bit Receive MAC FIFO Read Pointer */ +/* RX_MFF_PC 32 bit Receive MAC FIFO Packet Counter */ +/* RX_MFF_LEV 32 bit Receive MAC FIFO Level */ +/* TX_MFF_EA 32 bit Transmit MAC FIFO End Address */ +/* TX_MFF_WP 32 bit Transmit MAC FIFO Write Pointer */ +/* TX_MFF_WSP 32 bit Transmit MAC FIFO WR Shadow Pointer */ +/* TX_MFF_RP 32 bit Transmit MAC FIFO Read Pointer */ +/* TX_MFF_PC 32 bit Transmit MAC FIFO Packet Cnt */ +/* TX_MFF_LEV 32 bit Transmit MAC FIFO Level */ + /* Bit 31.. 6: reserved */ +#define MFF_MSK 0x007fL /* Bit 5.. 0: MAC FIFO Address/Ptr Bits */ + +/* RX_MFF_CTRL1 16 bit Receive MAC FIFO Control Reg 1 */ + /* Bit 15..14: reserved */ +#define MFF_ENA_RDY_PAT BIT_13S /* Enable Ready Patch */ +#define MFF_DIS_RDY_PAT BIT_12S /* Disable Ready Patch */ +#define MFF_ENA_TIM_PAT BIT_11S /* Enable Timing Patch */ +#define MFF_DIS_TIM_PAT BIT_10S /* Disable Timing Patch */ +#define MFF_ENA_ALM_FUL BIT_9S /* Enable AlmostFull Sign */ +#define MFF_DIS_ALM_FUL BIT_8S /* Disable AlmostFull Sign */ +#define MFF_ENA_PAUSE BIT_7S /* Enable Pause Signaling */ +#define MFF_DIS_PAUSE BIT_6S /* Disable Pause Signaling */ +#define MFF_ENA_FLUSH BIT_5S /* Enable Frame Flushing */ +#define MFF_DIS_FLUSH BIT_4S /* Disable Frame Flushing */ +#define MFF_ENA_TIST BIT_3S /* Enable Time Stamp Gener */ +#define MFF_DIS_TIST BIT_2S /* Disable Time Stamp Gener */ +#define MFF_CLR_INTIST BIT_1S /* Clear IRQ No Time Stamp */ +#define MFF_CLR_INSTAT BIT_0S /* Clear IRQ No Status */ + +#define MFF_RX_CTRL_DEF MFF_ENA_TIM_PAT + +/* TX_MFF_CTRL1 16 bit Transmit MAC FIFO Control Reg 1 */ +#define MFF_CLR_PERR BIT_15S /* Clear Parity Error IRQ */ + /* Bit 14: reserved */ +#define MFF_ENA_PKT_REC BIT_13S /* Enable Packet Recovery */ +#define MFF_DIS_PKT_REC BIT_12S /* Disable Packet Recovery */ +/* MFF_ENA_TIM_PAT (see RX_MFF_CTRL1) Bit 11: Enable Timing Patch */ +/* MFF_DIS_TIM_PAT (see RX_MFF_CTRL1) Bit 10: Disable Timing Patch */ +/* MFF_ENA_ALM_FUL (see RX_MFF_CTRL1) Bit 9: Enable Almost Full Sign */ +/* MFF_DIS_ALM_FUL (see RX_MFF_CTRL1) Bit 8: Disable Almost Full Sign */ +#define MFF_ENA_W4E BIT_7S /* Enable Wait for Empty */ +#define MFF_DIS_W4E BIT_6S /* Disable Wait for Empty */ +/* MFF_ENA_FLUSH (see RX_MFF_CTRL1) Bit 5: Enable Frame Flushing */ +/* MFF_DIS_FLUSH (see RX_MFF_CTRL1) Bit 4: Disable Frame Flushing */ +#define MFF_ENA_LOOPB BIT_3S /* Enable Loopback */ +#define MFF_DIS_LOOPB BIT_2S /* Disable Loopback */ +#define MFF_CLR_MAC_RST BIT_1S /* Clear XMAC Reset */ +#define MFF_SET_MAC_RST BIT_0S /* Set XMAC Reset */ + +#define MFF_TX_CTRL_DEF (MFF_ENA_PKT_REC | MFF_ENA_TIM_PAT | MFF_ENA_FLUSH) + +/* RX_MFF_TST2 8 bit Receive MAC FIFO Test Register 2 */ +/* TX_MFF_TST2 8 bit Transmit MAC FIFO Test Register 2 */ + /* Bit 7: reserved */ +#define MFF_WSP_T_ON BIT_6S /* Tx: Write Shadow Ptr TestOn */ +#define MFF_WSP_T_OFF BIT_5S /* Tx: Write Shadow Ptr TstOff */ +#define MFF_WSP_INC BIT_4S /* Tx: Write Shadow Ptr Increment */ +#define MFF_PC_DEC BIT_3S /* Packet Counter Decrement */ +#define MFF_PC_T_ON BIT_2S /* Packet Counter Test On */ +#define MFF_PC_T_OFF BIT_1S /* Packet Counter Test Off */ +#define MFF_PC_INC BIT_0S /* Packet Counter Increment */ + +/* RX_MFF_TST1 8 bit Receive MAC FIFO Test Register 1 */ +/* TX_MFF_TST1 8 bit Transmit MAC FIFO Test Register 1 */ + /* Bit 7: reserved */ +#define MFF_WP_T_ON BIT_6S /* Write Pointer Test On */ +#define MFF_WP_T_OFF BIT_5S /* Write Pointer Test Off */ +#define MFF_WP_INC BIT_4S /* Write Pointer Increm */ + /* Bit 3: reserved */ +#define MFF_RP_T_ON BIT_2S /* Read Pointer Test On */ +#define MFF_RP_T_OFF BIT_1S /* Read Pointer Test Off */ +#define MFF_RP_DEC BIT_0S /* Read Pointer Decrement */ + +/* RX_MFF_CTRL2 8 bit Receive MAC FIFO Control Reg 2 */ +/* TX_MFF_CTRL2 8 bit Transmit MAC FIFO Control Reg 2 */ + /* Bit 7..4: reserved */ +#define MFF_ENA_OP_MD BIT_3S /* Enable Operation Mode */ +#define MFF_DIS_OP_MD BIT_2S /* Disable Operation Mode */ +#define MFF_RST_CLR BIT_1S /* Clear MAC FIFO Reset */ +#define MFF_RST_SET BIT_0S /* Set MAC FIFO Reset */ + + +/* Link LED Counter Registers (GENESIS only) */ + +/* RX_LED_CTRL 8 bit Receive LED Cnt Control Reg */ +/* TX_LED_CTRL 8 bit Transmit LED Cnt Control Reg */ +/* LNK_SYNC_CTRL 8 bit Link Sync Cnt Control Register */ + /* Bit 7.. 3: reserved */ +#define LED_START BIT_2S /* Start Timer */ +#define LED_STOP BIT_1S /* Stop Timer */ +#define LED_STATE BIT_0S /* Rx/Tx: LED State, 1=LED on */ +#define LED_CLR_IRQ BIT_0S /* Lnk: Clear Link IRQ */ + +/* RX_LED_TST 8 bit Receive LED Cnt Test Register */ +/* TX_LED_TST 8 bit Transmit LED Cnt Test Register */ +/* LNK_SYNC_TST 8 bit Link Sync Cnt Test Register */ + /* Bit 7.. 3: reserved */ +#define LED_T_ON BIT_2S /* LED Counter Test mode On */ +#define LED_T_OFF BIT_1S /* LED Counter Test mode Off */ +#define LED_T_STEP BIT_0S /* LED Counter Step */ + +/* LNK_LED_REG 8 bit Link LED Register */ + /* Bit 7.. 6: reserved */ +#define LED_BLK_ON BIT_5S /* Link LED Blinking On */ +#define LED_BLK_OFF BIT_4S /* Link LED Blinking Off */ +#define LED_SYNC_ON BIT_3S /* Use Sync Wire to switch LED */ +#define LED_SYNC_OFF BIT_2S /* Disable Sync Wire Input */ +#define LED_ON BIT_1S /* switch LED on */ +#define LED_OFF BIT_0S /* switch LED off */ + +/* Receive and Transmit GMAC FIFO Registers (YUKON only) */ + +/* RX_GMF_EA 32 bit Rx GMAC FIFO End Address */ +/* RX_GMF_AF_THR 32 bit Rx GMAC FIFO Almost Full Thresh. */ +/* RX_GMF_WP 32 bit Rx GMAC FIFO Write Pointer */ +/* RX_GMF_WLEV 32 bit Rx GMAC FIFO Write Level */ +/* RX_GMF_RP 32 bit Rx GMAC FIFO Read Pointer */ +/* RX_GMF_RLEV 32 bit Rx GMAC FIFO Read Level */ +/* TX_GMF_EA 32 bit Tx GMAC FIFO End Address */ +/* TX_GMF_AE_THR 32 bit Tx GMAC FIFO Almost Empty Thresh.*/ +/* TX_GMF_WP 32 bit Tx GMAC FIFO Write Pointer */ +/* TX_GMF_WSP 32 bit Tx GMAC FIFO Write Shadow Ptr. */ +/* TX_GMF_WLEV 32 bit Tx GMAC FIFO Write Level */ +/* TX_GMF_RP 32 bit Tx GMAC FIFO Read Pointer */ +/* TX_GMF_RSTP 32 bit Tx GMAC FIFO Restart Pointer */ +/* TX_GMF_RLEV 32 bit Tx GMAC FIFO Read Level */ + +/* RX_GMF_CTRL_T 32 bit Rx GMAC FIFO Control/Test */ + /* Bits 31..15: reserved */ +#define GMF_WP_TST_ON BIT_14 /* Write Pointer Test On */ +#define GMF_WP_TST_OFF BIT_13 /* Write Pointer Test Off */ +#define GMF_WP_STEP BIT_12 /* Write Pointer Step/Increment */ + /* Bit 11: reserved */ +#define GMF_RP_TST_ON BIT_10 /* Read Pointer Test On */ +#define GMF_RP_TST_OFF BIT_9 /* Read Pointer Test Off */ +#define GMF_RP_STEP BIT_8 /* Read Pointer Step/Increment */ +#define GMF_RX_F_FL_ON BIT_7 /* Rx FIFO Flush Mode On */ +#define GMF_RX_F_FL_OFF BIT_6 /* Rx FIFO Flush Mode Off */ +#define GMF_CLI_RX_FO BIT_5 /* Clear IRQ Rx FIFO Overrun */ +#define GMF_CLI_RX_FC BIT_4 /* Clear IRQ Rx Frame Complete */ +#define GMF_OPER_ON BIT_3 /* Operational Mode On */ +#define GMF_OPER_OFF BIT_2 /* Operational Mode Off */ +#define GMF_RST_CLR BIT_1 /* Clear GMAC FIFO Reset */ +#define GMF_RST_SET BIT_0 /* Set GMAC FIFO Reset */ + +/* TX_GMF_CTRL_T 32 bit Tx GMAC FIFO Control/Test */ + /* Bits 31..19: reserved */ +#define GMF_WSP_TST_ON BIT_18 /* Write Shadow Pointer Test On */ +#define GMF_WSP_TST_OFF BIT_17 /* Write Shadow Pointer Test Off */ +#define GMF_WSP_STEP BIT_16 /* Write Shadow Pointer Step/Increment */ + /* Bits 15..7: same as for RX_GMF_CTRL_T */ +#define GMF_CLI_TX_FU BIT_6 /* Clear IRQ Tx FIFO Underrun */ +#define GMF_CLI_TX_FC BIT_5 /* Clear IRQ Tx Frame Complete */ +#define GMF_CLI_TX_PE BIT_4 /* Clear IRQ Tx Parity Error */ + /* Bits 3..0: same as for RX_GMF_CTRL_T */ + +#define GMF_RX_CTRL_DEF (GMF_OPER_ON | GMF_RX_F_FL_ON) +#define GMF_TX_CTRL_DEF GMF_OPER_ON + +#define RX_GMF_FL_THR_DEF 0x0a /* Rx GMAC FIFO Flush Threshold default */ + +/* GMAC_TI_ST_CTRL 8 bit Time Stamp Timer Ctrl Reg (YUKON only) */ + /* Bit 7.. 3: reserved */ +#define GMT_ST_START BIT_2S /* Start Time Stamp Timer */ +#define GMT_ST_STOP BIT_1S /* Stop Time Stamp Timer */ +#define GMT_ST_CLR_IRQ BIT_0S /* Clear Time Stamp Timer IRQ */ + +/* GMAC_CTRL 32 bit GMAC Control Reg (YUKON only) */ + /* Bits 31.. 8: reserved */ +#define GMC_H_BURST_ON BIT_7 /* Half Duplex Burst Mode On */ +#define GMC_H_BURST_OFF BIT_6 /* Half Duplex Burst Mode Off */ +#define GMC_F_LOOPB_ON BIT_5 /* FIFO Loopback On */ +#define GMC_F_LOOPB_OFF BIT_4 /* FIFO Loopback Off */ +#define GMC_PAUSE_ON BIT_3 /* Pause On */ +#define GMC_PAUSE_OFF BIT_2 /* Pause Off */ +#define GMC_RST_CLR BIT_1 /* Clear GMAC Reset */ +#define GMC_RST_SET BIT_0 /* Set GMAC Reset */ + +/* GPHY_CTRL 32 bit GPHY Control Reg (YUKON only) */ + /* Bits 31..29: reserved */ +#define GPC_SEL_BDT BIT_28 /* Select Bi-Dir. Transfer for MDC/MDIO */ +#define GPC_INT_POL_HI BIT_27 /* IRQ Polarity is Active HIGH */ +#define GPC_75_OHM BIT_26 /* Use 75 Ohm Termination instead of 50 */ +#define GPC_DIS_FC BIT_25 /* Disable Automatic Fiber/Copper Detection */ +#define GPC_DIS_SLEEP BIT_24 /* Disable Energy Detect */ +#define GPC_HWCFG_M_3 BIT_23 /* HWCFG_MODE[3] */ +#define GPC_HWCFG_M_2 BIT_22 /* HWCFG_MODE[2] */ +#define GPC_HWCFG_M_1 BIT_21 /* HWCFG_MODE[1] */ +#define GPC_HWCFG_M_0 BIT_20 /* HWCFG_MODE[0] */ +#define GPC_ANEG_0 BIT_19 /* ANEG[0] */ +#define GPC_ENA_XC BIT_18 /* Enable MDI crossover */ +#define GPC_DIS_125 BIT_17 /* Disable 125 MHz clock */ +#define GPC_ANEG_3 BIT_16 /* ANEG[3] */ +#define GPC_ANEG_2 BIT_15 /* ANEG[2] */ +#define GPC_ANEG_1 BIT_14 /* ANEG[1] */ +#define GPC_ENA_PAUSE BIT_13 /* Enable Pause (SYM_OR_REM) */ +#define GPC_PHYADDR_4 BIT_12 /* Bit 4 of Phy Addr */ +#define GPC_PHYADDR_3 BIT_11 /* Bit 3 of Phy Addr */ +#define GPC_PHYADDR_2 BIT_10 /* Bit 2 of Phy Addr */ +#define GPC_PHYADDR_1 BIT_9 /* Bit 1 of Phy Addr */ +#define GPC_PHYADDR_0 BIT_8 /* Bit 0 of Phy Addr */ + /* Bits 7..2: reserved */ +#define GPC_RST_CLR BIT_1 /* Clear GPHY Reset */ +#define GPC_RST_SET BIT_0 /* Set GPHY Reset */ + +#define GPC_HWCFG_GMII_COP (GPC_HWCFG_M_3 | GPC_HWCFG_M_2 | \ + GPC_HWCFG_M_1 | GPC_HWCFG_M_0) + +#define GPC_HWCFG_GMII_FIB ( GPC_HWCFG_M_2 | \ + GPC_HWCFG_M_1 | GPC_HWCFG_M_0) + +#define GPC_ANEG_ADV_ALL_M (GPC_ANEG_3 | GPC_ANEG_2 | \ + GPC_ANEG_1 | GPC_ANEG_0) + +/* forced speed and duplex mode (don't mix with other ANEG bits) */ +#define GPC_FRC10MBIT_HALF 0 +#define GPC_FRC10MBIT_FULL GPC_ANEG_0 +#define GPC_FRC100MBIT_HALF GPC_ANEG_1 +#define GPC_FRC100MBIT_FULL (GPC_ANEG_0 | GPC_ANEG_1) + +/* auto-negotiation with limited advertised speeds */ +/* mix only with master/slave settings (for copper) */ +#define GPC_ADV_1000_HALF GPC_ANEG_2 +#define GPC_ADV_1000_FULL GPC_ANEG_3 +#define GPC_ADV_ALL (GPC_ANEG_2 | GPC_ANEG_3) + +/* master/slave settings */ +/* only for copper with 1000 Mbps */ +#define GPC_FORCE_MASTER 0 +#define GPC_FORCE_SLAVE GPC_ANEG_0 +#define GPC_PREF_MASTER GPC_ANEG_1 +#define GPC_PREF_SLAVE (GPC_ANEG_1 | GPC_ANEG_0) + +/* GMAC_IRQ_SRC 8 bit GMAC Interrupt Source Reg (YUKON only) */ +/* GMAC_IRQ_MSK 8 bit GMAC Interrupt Mask Reg (YUKON only) */ +#define GM_IS_TX_CO_OV BIT_5 /* Transmit Counter Overflow IRQ */ +#define GM_IS_RX_CO_OV BIT_4 /* Receive Counter Overflow IRQ */ +#define GM_IS_TX_FF_UR BIT_3 /* Transmit FIFO Underrun */ +#define GM_IS_TX_COMPL BIT_2 /* Frame Transmission Complete */ +#define GM_IS_RX_FF_OR BIT_1 /* Receive FIFO Overrun */ +#define GM_IS_RX_COMPL BIT_0 /* Frame Reception Complete */ + +#define GMAC_DEF_MSK (GM_IS_TX_CO_OV | GM_IS_RX_CO_OV | \ + GM_IS_TX_FF_UR) + +/* GMAC_LINK_CTRL 16 bit GMAC Link Control Reg (YUKON only) */ + /* Bits 15.. 2: reserved */ +#define GMLC_RST_CLR BIT_1S /* Clear GMAC Link Reset */ +#define GMLC_RST_SET BIT_0S /* Set GMAC Link Reset */ + + +/* WOL_CTRL_STAT 16 bit WOL Control/Status Reg */ +#define WOL_CTL_LINK_CHG_OCC BIT_15S +#define WOL_CTL_MAGIC_PKT_OCC BIT_14S +#define WOL_CTL_PATTERN_OCC BIT_13S + +#define WOL_CTL_CLEAR_RESULT BIT_12S + +#define WOL_CTL_ENA_PME_ON_LINK_CHG BIT_11S +#define WOL_CTL_DIS_PME_ON_LINK_CHG BIT_10S +#define WOL_CTL_ENA_PME_ON_MAGIC_PKT BIT_9S +#define WOL_CTL_DIS_PME_ON_MAGIC_PKT BIT_8S +#define WOL_CTL_ENA_PME_ON_PATTERN BIT_7S +#define WOL_CTL_DIS_PME_ON_PATTERN BIT_6S + +#define WOL_CTL_ENA_LINK_CHG_UNIT BIT_5S +#define WOL_CTL_DIS_LINK_CHG_UNIT BIT_4S +#define WOL_CTL_ENA_MAGIC_PKT_UNIT BIT_3S +#define WOL_CTL_DIS_MAGIC_PKT_UNIT BIT_2S +#define WOL_CTL_ENA_PATTERN_UNIT BIT_1S +#define WOL_CTL_DIS_PATTERN_UNIT BIT_0S + +#define WOL_CTL_DEFAULT \ + (WOL_CTL_DIS_PME_ON_LINK_CHG | \ + WOL_CTL_DIS_PME_ON_PATTERN | \ + WOL_CTL_DIS_PME_ON_MAGIC_PKT | \ + WOL_CTL_DIS_LINK_CHG_UNIT | \ + WOL_CTL_DIS_PATTERN_UNIT | \ + WOL_CTL_DIS_MAGIC_PKT_UNIT) + +/* WOL_MATCH_CTL 8 bit WOL Match Control Reg */ +#define WOL_CTL_PATT_ENA(x) (BIT_0 << (x)) + +#define SK_NUM_WOL_PATTERN 7 +#define SK_PATTERN_PER_WORD 4 +#define SK_BITMASK_PATTERN 7 +#define SK_POW_PATTERN_LENGTH 128 + +#define WOL_LENGTH_MSK 0x7f +#define WOL_LENGTH_SHIFT 8 + + +/* Receive and Transmit Descriptors ******************************************/ + +/* Transmit Descriptor struct */ +typedef struct s_HwTxd { + SK_U32 volatile TxCtrl; /* Transmit Buffer Control Field */ + SK_U32 TxNext; /* Physical Address Pointer to the next TxD */ + SK_U32 TxAdrLo; /* Physical Tx Buffer Address lower dword */ + SK_U32 TxAdrHi; /* Physical Tx Buffer Address upper dword */ + SK_U32 TxStat; /* Transmit Frame Status Word */ +#ifndef SK_USE_REV_DESC + SK_U16 TxTcpOffs; /* TCP Checksum Calculation Start Value */ + SK_U16 TxRes1; /* 16 bit reserved field */ + SK_U16 TxTcpWp; /* TCP Checksum Write Position */ + SK_U16 TxTcpSp; /* TCP Checksum Calculation Start Position */ +#else /* SK_USE_REV_DESC */ + SK_U16 TxRes1; /* 16 bit reserved field */ + SK_U16 TxTcpOffs; /* TCP Checksum Calculation Start Value */ + SK_U16 TxTcpSp; /* TCP Checksum Calculation Start Position */ + SK_U16 TxTcpWp; /* TCP Checksum Write Position */ +#endif /* SK_USE_REV_DESC */ + SK_U32 TxRes2; /* 32 bit reserved field */ +} SK_HWTXD; + +/* Receive Descriptor struct */ +typedef struct s_HwRxd { + SK_U32 volatile RxCtrl; /* Receive Buffer Control Field */ + SK_U32 RxNext; /* Physical Address Pointer to the next RxD */ + SK_U32 RxAdrLo; /* Physical Rx Buffer Address lower dword */ + SK_U32 RxAdrHi; /* Physical Rx Buffer Address upper dword */ + SK_U32 RxStat; /* Receive Frame Status Word */ + SK_U32 RxTiSt; /* Receive Time Stamp (from XMAC on GENESIS) */ +#ifndef SK_USE_REV_DESC + SK_U16 RxTcpSum1; /* TCP Checksum 1 */ + SK_U16 RxTcpSum2; /* TCP Checksum 2 */ + SK_U16 RxTcpSp1; /* TCP Checksum Calculation Start Position 1 */ + SK_U16 RxTcpSp2; /* TCP Checksum Calculation Start Position 2 */ +#else /* SK_USE_REV_DESC */ + SK_U16 RxTcpSum2; /* TCP Checksum 2 */ + SK_U16 RxTcpSum1; /* TCP Checksum 1 */ + SK_U16 RxTcpSp2; /* TCP Checksum Calculation Start Position 2 */ + SK_U16 RxTcpSp1; /* TCP Checksum Calculation Start Position 1 */ +#endif /* SK_USE_REV_DESC */ +} SK_HWRXD; + +/* + * Drivers which use the reverse descriptor feature (PCI_OUR_REG_2) + * should set the define SK_USE_REV_DESC. + * Structures are 'normaly' not endianess dependent. But in + * this case the SK_U16 fields are bound to bit positions inside the + * descriptor. RxTcpSum1 e.g. must start at bit 0 within the 6.th DWord. + * The bit positions inside a DWord are of course endianess dependent and + * swaps if the DWord is swapped by the hardware. + */ + + +/* Descriptor Bit Definition */ +/* TxCtrl Transmit Buffer Control Field */ +/* RxCtrl Receive Buffer Control Field */ +#define BMU_OWN BIT_31 /* OWN bit: 0=host/1=BMU */ +#define BMU_STF BIT_30 /* Start of Frame */ +#define BMU_EOF BIT_29 /* End of Frame */ +#define BMU_IRQ_EOB BIT_28 /* Req "End of Buffer" IRQ */ +#define BMU_IRQ_EOF BIT_27 /* Req "End of Frame" IRQ */ +/* TxCtrl specific bits */ +#define BMU_STFWD BIT_26 /* (Tx) Store & Forward Frame */ +#define BMU_NO_FCS BIT_25 /* (Tx) Disable MAC FCS (CRC) generation */ +#define BMU_SW BIT_24 /* (Tx) 1 bit res. for SW use */ +/* RxCtrl specific bits */ +#define BMU_DEV_0 BIT_26 /* (Rx) Transfer data to Dev0 */ +#define BMU_STAT_VAL BIT_25 /* (Rx) Rx Status Valid */ +#define BMU_TIST_VAL BIT_24 /* (Rx) Rx TimeStamp Valid */ + /* Bit 23..16: BMU Check Opcodes */ +#define BMU_CHECK (0x55L<<16) /* Default BMU check */ +#define BMU_TCP_CHECK (0x56L<<16) /* Descr with TCP ext */ +#define BMU_UDP_CHECK (0x57L<<16) /* Descr with UDP ext (YUKON only) */ +#define BMU_BBC 0xffffL /* Bit 15.. 0: Buffer Byte Counter */ + +/* TxStat Transmit Frame Status Word */ +/* RxStat Receive Frame Status Word */ +/* + *Note: TxStat is reserved for ASIC loopback mode only + * + * The Bits of the Status words are defined in xmac_ii.h + * (see XMR_FS bits) + */ + +/* macros ********************************************************************/ + +/* Receive and Transmit Queues */ +#define Q_R1 0x0000 /* Receive Queue 1 */ +#define Q_R2 0x0080 /* Receive Queue 2 */ +#define Q_XS1 0x0200 /* Synchronous Transmit Queue 1 */ +#define Q_XA1 0x0280 /* Asynchronous Transmit Queue 1 */ +#define Q_XS2 0x0300 /* Synchronous Transmit Queue 2 */ +#define Q_XA2 0x0380 /* Asynchronous Transmit Queue 2 */ + +/* + * Macro Q_ADDR() + * + * Use this macro to access the Receive and Transmit Queue Registers. + * + * para: + * Queue Queue to access. + * Values: Q_R1, Q_R2, Q_XS1, Q_XA1, Q_XS2, and Q_XA2 + * Offs Queue register offset. + * Values: Q_D, Q_DA_L ... Q_T2, Q_T3 + * + * usage SK_IN32(pAC, Q_ADDR(Q_R2, Q_BC), pVal) + */ +#define Q_ADDR(Queue, Offs) (B8_Q_REGS + (Queue) + (Offs)) + +/* + * Macro RB_ADDR() + * + * Use this macro to access the RAM Buffer Registers. + * + * para: + * Queue Queue to access. + * Values: Q_R1, Q_R2, Q_XS1, Q_XA1, Q_XS2, and Q_XA2 + * Offs Queue register offset. + * Values: RB_START, RB_END ... RB_LEV, RB_CTRL + * + * usage SK_IN32(pAC, RB_ADDR(Q_R2, RB_RP), pVal) + */ +#define RB_ADDR(Queue, Offs) (B16_RAM_REGS + (Queue) + (Offs)) + + +/* MAC Related Registers */ +#define MAC_1 0 /* belongs to the port near the slot */ +#define MAC_2 1 /* belongs to the port far away from the slot */ + +/* + * Macro MR_ADDR() + * + * Use this macro to access a MAC Related Registers inside the ASIC. + * + * para: + * Mac MAC to access. + * Values: MAC_1, MAC_2 + * Offs MAC register offset. + * Values: RX_MFF_EA, RX_MFF_WP ... LNK_LED_REG, + * TX_MFF_EA, TX_MFF_WP ... TX_LED_TST + * + * usage SK_IN32(pAC, MR_ADDR(MAC_1, TX_MFF_EA), pVal) + */ +#define MR_ADDR(Mac, Offs) (((Mac) << 7) + (Offs)) + +#ifdef SK_LITTLE_ENDIAN +#define XM_WORD_LO 0 +#define XM_WORD_HI 1 +#else /* !SK_LITTLE_ENDIAN */ +#define XM_WORD_LO 1 +#define XM_WORD_HI 0 +#endif /* !SK_LITTLE_ENDIAN */ + + +/* + * macros to access the XMAC (GENESIS only) + * + * XM_IN16(), to read a 16 bit register (e.g. XM_MMU_CMD) + * XM_OUT16(), to write a 16 bit register (e.g. XM_MMU_CMD) + * XM_IN32(), to read a 32 bit register (e.g. XM_TX_EV_CNT) + * XM_OUT32(), to write a 32 bit register (e.g. XM_TX_EV_CNT) + * XM_INADDR(), to read a network address register (e.g. XM_SRC_CHK) + * XM_OUTADDR(), to write a network address register (e.g. XM_SRC_CHK) + * XM_INHASH(), to read the XM_HSM_CHK register + * XM_OUTHASH() to write the XM_HSM_CHK register + * + * para: + * Mac XMAC to access values: MAC_1 or MAC_2 + * IoC I/O context needed for SK I/O macros + * Reg XMAC Register to read or write + * (p)Val Value or pointer to the value which should be read or written + * + * usage: XM_OUT16(IoC, MAC_1, XM_MMU_CMD, Value); + */ + +#define XMA(Mac, Reg) \ + ((BASE_XMAC_1 + (Mac) * (BASE_XMAC_2 - BASE_XMAC_1)) | ((Reg) << 1)) + +#define XM_IN16(IoC, Mac, Reg, pVal) \ + SK_IN16((IoC), XMA((Mac), (Reg)), (pVal)) + +#define XM_OUT16(IoC, Mac, Reg, Val) \ + SK_OUT16((IoC), XMA((Mac), (Reg)), (Val)) + +#define XM_IN32(IoC, Mac, Reg, pVal) { \ + SK_IN16((IoC), XMA((Mac), (Reg)), \ + (SK_U16 SK_FAR*)&((SK_U16 SK_FAR*)(pVal))[XM_WORD_LO]); \ + SK_IN16((IoC), XMA((Mac), (Reg+2)), \ + (SK_U16 SK_FAR*)&((SK_U16 SK_FAR*)(pVal))[XM_WORD_HI]); \ +} + +#define XM_OUT32(IoC, Mac, Reg, Val) { \ + SK_OUT16((IoC), XMA((Mac), (Reg)), (SK_U16)((Val) & 0xffffL)); \ + SK_OUT16((IoC), XMA((Mac), (Reg+2)), (SK_U16)(((Val) >> 16) & 0xffffL));\ +} + +/* Remember: we are always writing to / reading from LITTLE ENDIAN memory */ + +#define XM_INADDR(IoC, Mac, Reg, pVal) { \ + SK_U16 Word; \ + SK_U8 *pByte; \ + pByte = (SK_U8 *)&((SK_U8 *)(pVal))[0]; \ + SK_IN16((IoC), XMA((Mac), (Reg)), &Word); \ + pByte[0] = (SK_U8)(Word & 0x00ff); \ + pByte[1] = (SK_U8)((Word >> 8) & 0x00ff); \ + SK_IN16((IoC), XMA((Mac), (Reg+2)), &Word); \ + pByte[2] = (SK_U8)(Word & 0x00ff); \ + pByte[3] = (SK_U8)((Word >> 8) & 0x00ff); \ + SK_IN16((IoC), XMA((Mac), (Reg+4)), &Word); \ + pByte[4] = (SK_U8)(Word & 0x00ff); \ + pByte[5] = (SK_U8)((Word >> 8) & 0x00ff); \ +} + +#define XM_OUTADDR(IoC, Mac, Reg, pVal) { \ + SK_U8 SK_FAR *pByte; \ + pByte = (SK_U8 SK_FAR *)&((SK_U8 SK_FAR *)(pVal))[0]; \ + SK_OUT16((IoC), XMA((Mac), (Reg)), (SK_U16) \ + (((SK_U16)(pByte[0]) & 0x00ff) | \ + (((SK_U16)(pByte[1]) << 8) & 0xff00))); \ + SK_OUT16((IoC), XMA((Mac), (Reg+2)), (SK_U16) \ + (((SK_U16)(pByte[2]) & 0x00ff) | \ + (((SK_U16)(pByte[3]) << 8) & 0xff00))); \ + SK_OUT16((IoC), XMA((Mac), (Reg+4)), (SK_U16) \ + (((SK_U16)(pByte[4]) & 0x00ff) | \ + (((SK_U16)(pByte[5]) << 8) & 0xff00))); \ +} + +#define XM_INHASH(IoC, Mac, Reg, pVal) { \ + SK_U16 Word; \ + SK_U8 SK_FAR *pByte; \ + pByte = (SK_U8 SK_FAR *)&((SK_U8 SK_FAR *)(pVal))[0]; \ + SK_IN16((IoC), XMA((Mac), (Reg)), &Word); \ + pByte[0] = (SK_U8)(Word & 0x00ff); \ + pByte[1] = (SK_U8)((Word >> 8) & 0x00ff); \ + SK_IN16((IoC), XMA((Mac), (Reg+2)), &Word); \ + pByte[2] = (SK_U8)(Word & 0x00ff); \ + pByte[3] = (SK_U8)((Word >> 8) & 0x00ff); \ + SK_IN16((IoC), XMA((Mac), (Reg+4)), &Word); \ + pByte[4] = (SK_U8)(Word & 0x00ff); \ + pByte[5] = (SK_U8)((Word >> 8) & 0x00ff); \ + SK_IN16((IoC), XMA((Mac), (Reg+6)), &Word); \ + pByte[6] = (SK_U8)(Word & 0x00ff); \ + pByte[7] = (SK_U8)((Word >> 8) & 0x00ff); \ +} + +#define XM_OUTHASH(IoC, Mac, Reg, pVal) { \ + SK_U8 SK_FAR *pByte; \ + pByte = (SK_U8 SK_FAR *)&((SK_U8 SK_FAR *)(pVal))[0]; \ + SK_OUT16((IoC), XMA((Mac), (Reg)), (SK_U16) \ + (((SK_U16)(pByte[0]) & 0x00ff)| \ + (((SK_U16)(pByte[1]) << 8) & 0xff00))); \ + SK_OUT16((IoC), XMA((Mac), (Reg+2)), (SK_U16) \ + (((SK_U16)(pByte[2]) & 0x00ff)| \ + (((SK_U16)(pByte[3]) << 8) & 0xff00))); \ + SK_OUT16((IoC), XMA((Mac), (Reg+4)), (SK_U16) \ + (((SK_U16)(pByte[4]) & 0x00ff)| \ + (((SK_U16)(pByte[5]) << 8) & 0xff00))); \ + SK_OUT16((IoC), XMA((Mac), (Reg+6)), (SK_U16) \ + (((SK_U16)(pByte[6]) & 0x00ff)| \ + (((SK_U16)(pByte[7]) << 8) & 0xff00))); \ +} + +/* + * macros to access the GMAC (YUKON only) + * + * GM_IN16(), to read a 16 bit register (e.g. GM_GP_STAT) + * GM_OUT16(), to write a 16 bit register (e.g. GM_GP_CTRL) + * GM_IN32(), to read a 32 bit register (e.g. GM_) + * GM_OUT32(), to write a 32 bit register (e.g. GM_) + * GM_INADDR(), to read a network address register (e.g. GM_SRC_ADDR_1L) + * GM_OUTADDR(), to write a network address register (e.g. GM_SRC_ADDR_2L) + * GM_INHASH(), to read the GM_MC_ADDR_H1 register + * GM_OUTHASH() to write the GM_MC_ADDR_H1 register + * + * para: + * Mac GMAC to access values: MAC_1 or MAC_2 + * IoC I/O context needed for SK I/O macros + * Reg GMAC Register to read or write + * (p)Val Value or pointer to the value which should be read or written + * + * usage: GM_OUT16(IoC, MAC_1, GM_GP_CTRL, Value); + */ + +#define GMA(Mac, Reg) \ + ((BASE_GMAC_1 + (Mac) * (BASE_GMAC_2 - BASE_GMAC_1)) | (Reg)) + +#define GM_IN16(IoC, Mac, Reg, pVal) \ + SK_IN16((IoC), GMA((Mac), (Reg)), (pVal)) + +#define GM_OUT16(IoC, Mac, Reg, Val) \ + SK_OUT16((IoC), GMA((Mac), (Reg)), (Val)) + +#define GM_IN32(IoC, Mac, Reg, pVal) { \ + SK_IN16((IoC), GMA((Mac), (Reg)), \ + (SK_U16 SK_FAR*)&((SK_U16 SK_FAR*)(pVal))[XM_WORD_LO]); \ + SK_IN16((IoC), GMA((Mac), (Reg+4)), \ + (SK_U16 SK_FAR*)&((SK_U16 SK_FAR*)(pVal))[XM_WORD_HI]); \ +} + +#define GM_OUT32(IoC, Mac, Reg, Val) { \ + SK_OUT16((IoC), GMA((Mac), (Reg)), (SK_U16)((Val) & 0xffffL)); \ + SK_OUT16((IoC), GMA((Mac), (Reg+4)), (SK_U16)(((Val) >> 16) & 0xffffL));\ +} + +#define GM_INADDR(IoC, Mac, Reg, pVal) { \ + SK_U16 Word; \ + SK_U8 *pByte; \ + pByte = (SK_U8 *)&((SK_U8 *)(pVal))[0]; \ + SK_IN16((IoC), GMA((Mac), (Reg)), &Word); \ + pByte[0] = (SK_U8)(Word & 0x00ff); \ + pByte[1] = (SK_U8)((Word >> 8) & 0x00ff); \ + SK_IN16((IoC), GMA((Mac), (Reg+4)), &Word); \ + pByte[2] = (SK_U8)(Word & 0x00ff); \ + pByte[3] = (SK_U8)((Word >> 8) & 0x00ff); \ + SK_IN16((IoC), GMA((Mac), (Reg+8)), &Word); \ + pByte[4] = (SK_U8)(Word & 0x00ff); \ + pByte[5] = (SK_U8)((Word >> 8) & 0x00ff); \ +} + +#define GM_OUTADDR(IoC, Mac, Reg, pVal) { \ + SK_U8 SK_FAR *pByte; \ + pByte = (SK_U8 SK_FAR *)&((SK_U8 SK_FAR *)(pVal))[0]; \ + SK_OUT16((IoC), GMA((Mac), (Reg)), (SK_U16) \ + (((SK_U16)(pByte[0]) & 0x00ff) | \ + (((SK_U16)(pByte[1]) << 8) & 0xff00))); \ + SK_OUT16((IoC), GMA((Mac), (Reg+4)), (SK_U16) \ + (((SK_U16)(pByte[2]) & 0x00ff) | \ + (((SK_U16)(pByte[3]) << 8) & 0xff00))); \ + SK_OUT16((IoC), GMA((Mac), (Reg+8)), (SK_U16) \ + (((SK_U16)(pByte[4]) & 0x00ff) | \ + (((SK_U16)(pByte[5]) << 8) & 0xff00))); \ +} + +#define GM_INHASH(IoC, Mac, Reg, pVal) { \ + SK_U16 Word; \ + SK_U8 *pByte; \ + pByte = (SK_U8 *)&((SK_U8 *)(pVal))[0]; \ + SK_IN16((IoC), GMA((Mac), (Reg)), &Word); \ + pByte[0] = (SK_U8)(Word & 0x00ff); \ + pByte[1] = (SK_U8)((Word >> 8) & 0x00ff); \ + SK_IN16((IoC), GMA((Mac), (Reg+4)), &Word); \ + pByte[2] = (SK_U8)(Word & 0x00ff); \ + pByte[3] = (SK_U8)((Word >> 8) & 0x00ff); \ + SK_IN16((IoC), GMA((Mac), (Reg+8)), &Word); \ + pByte[4] = (SK_U8)(Word & 0x00ff); \ + pByte[5] = (SK_U8)((Word >> 8) & 0x00ff); \ + SK_IN16((IoC), GMA((Mac), (Reg+12)), &Word); \ + pByte[6] = (SK_U8)(Word & 0x00ff); \ + pByte[7] = (SK_U8)((Word >> 8) & 0x00ff); \ +} + +#define GM_OUTHASH(IoC, Mac, Reg, pVal) { \ + SK_U8 *pByte; \ + pByte = (SK_U8 *)&((SK_U8 *)(pVal))[0]; \ + SK_OUT16((IoC), GMA((Mac), (Reg)), (SK_U16) \ + (((SK_U16)(pByte[0]) & 0x00ff)| \ + (((SK_U16)(pByte[1]) << 8) & 0xff00))); \ + SK_OUT16((IoC), GMA((Mac), (Reg+4)), (SK_U16) \ + (((SK_U16)(pByte[2]) & 0x00ff)| \ + (((SK_U16)(pByte[3]) << 8) & 0xff00))); \ + SK_OUT16((IoC), GMA((Mac), (Reg+8)), (SK_U16) \ + (((SK_U16)(pByte[4]) & 0x00ff)| \ + (((SK_U16)(pByte[5]) << 8) & 0xff00))); \ + SK_OUT16((IoC), GMA((Mac), (Reg+12)), (SK_U16) \ + (((SK_U16)(pByte[6]) & 0x00ff)| \ + (((SK_U16)(pByte[7]) << 8) & 0xff00))); \ +} + +/* + * Different MAC Types + */ +#define SK_MAC_XMAC 0 /* Xaqti XMAC II */ +#define SK_MAC_GMAC 1 /* Marvell GMAC */ + +/* + * Different PHY Types + */ +#define SK_PHY_XMAC 0 /* integrated in XMAC II */ +#define SK_PHY_BCOM 1 /* Broadcom BCM5400 */ +#define SK_PHY_LONE 2 /* Level One LXT1000 */ +#define SK_PHY_NAT 3 /* National DP83891 */ +#define SK_PHY_MARV_COPPER 4 /* Marvell 88E1011S */ +#define SK_PHY_MARV_FIBER 5 /* Marvell 88E1011S working on fiber */ + +/* + * PHY addresses (bits 12..8 of PHY address reg) + */ +#define PHY_ADDR_XMAC (0<<8) +#define PHY_ADDR_BCOM (1<<8) +#define PHY_ADDR_LONE (3<<8) +#define PHY_ADDR_NAT (0<<8) + +/* GPHY address (bits 15..11 of SMI control reg) */ +#define PHY_ADDR_MARV 0 + +/* + * macros to access the PHY + * + * PHY_READ() read a 16 bit value from the PHY + * PHY_WRITE() write a 16 bit value to the PHY + * + * para: + * IoC I/O context needed for SK I/O macros + * pPort Pointer to port struct for PhyAddr + * Mac XMAC to access values: MAC_1 or MAC_2 + * PhyReg PHY Register to read or write + * (p)Val Value or pointer to the value which should be read or + * written. + * + * usage: PHY_READ(IoC, pPort, MAC_1, PHY_CTRL, Value); + * Warning: a PHY_READ on an uninitialized PHY (PHY still in reset) never + * comes back. This is checked in DEBUG mode. + */ +#ifndef DEBUG +#define PHY_READ(IoC, pPort, Mac, PhyReg, pVal) { \ + SK_U16 Mmu; \ + \ + XM_OUT16((IoC), (Mac), XM_PHY_ADDR, (PhyReg) | (pPort)->PhyAddr); \ + XM_IN16((IoC), (Mac), XM_PHY_DATA, (pVal)); \ + if ((pPort)->PhyType != SK_PHY_XMAC) { \ + do { \ + XM_IN16((IoC), (Mac), XM_MMU_CMD, &Mmu); \ + } while ((Mmu & XM_MMU_PHY_RDY) == 0); \ + XM_IN16((IoC), (Mac), XM_PHY_DATA, (pVal)); \ + } \ +} +#else +#define PHY_READ(IoC, pPort, Mac, PhyReg, pVal) { \ + SK_U16 Mmu; \ + int __i = 0; \ + \ + XM_OUT16((IoC), (Mac), XM_PHY_ADDR, (PhyReg) | (pPort)->PhyAddr); \ + XM_IN16((IoC), (Mac), XM_PHY_DATA, (pVal)); \ + if ((pPort)->PhyType != SK_PHY_XMAC) { \ + do { \ + XM_IN16((IoC), (Mac), XM_MMU_CMD, &Mmu); \ + __i++; \ + if (__i > 100000) { \ + SK_DBG_PRINTF("*****************************\n"); \ + SK_DBG_PRINTF("PHY_READ on uninitialized PHY\n"); \ + SK_DBG_PRINTF("*****************************\n"); \ + break; \ + } \ + } while ((Mmu & XM_MMU_PHY_RDY) == 0); \ + XM_IN16((IoC), (Mac), XM_PHY_DATA, (pVal)); \ + } \ +} +#endif /* DEBUG */ + +#define PHY_WRITE(IoC, pPort, Mac, PhyReg, Val) { \ + SK_U16 Mmu; \ + \ + if ((pPort)->PhyType != SK_PHY_XMAC) { \ + do { \ + XM_IN16((IoC), (Mac), XM_MMU_CMD, &Mmu); \ + } while ((Mmu & XM_MMU_PHY_BUSY) != 0); \ + } \ + XM_OUT16((IoC), (Mac), XM_PHY_ADDR, (PhyReg) | (pPort)->PhyAddr); \ + XM_OUT16((IoC), (Mac), XM_PHY_DATA, (Val)); \ + if ((pPort)->PhyType != SK_PHY_XMAC) { \ + do { \ + XM_IN16((IoC), (Mac), XM_MMU_CMD, &Mmu); \ + } while ((Mmu & XM_MMU_PHY_BUSY) != 0); \ + } \ +} + +/* + * Macro PCI_C() + * + * Use this macro to access PCI config register from the I/O space. + * + * para: + * Addr PCI configuration register to access. + * Values: PCI_VENDOR_ID ... PCI_VPD_ADR_REG, + * + * usage SK_IN16(pAC, PCI_C(PCI_VENDOR_ID), pVal); + */ +#define PCI_C(Addr) (B7_CFG_SPC + (Addr)) /* PCI Config Space */ + +/* + * Macro SK_HW_ADDR(Base, Addr) + * + * Calculates the effective HW address + * + * para: + * Base I/O or memory base address + * Addr Address offset + * + * usage: May be used in SK_INxx and SK_OUTxx macros + * #define SK_IN8(pAC, Addr, pVal) ...\ + * *pVal = (SK_U8)inp(SK_HW_ADDR(pAC->Hw.Iop, Addr))) + */ +#ifdef SK_MEM_MAPPED_IO +#define SK_HW_ADDR(Base, Addr) ((Base) + (Addr)) +#else /* SK_MEM_MAPPED_IO */ +#define SK_HW_ADDR(Base, Addr) \ + ((Base) + (((Addr) & 0x7f) | (((Addr) >> 7 > 0) ? 0x80 : 0))) +#endif /* SK_MEM_MAPPED_IO */ + +#define SZ_LONG (sizeof(SK_U32)) + +/* + * Macro SK_HWAC_LINK_LED() + * + * Use this macro to set the link LED mode. + * para: + * pAC Pointer to adapter context struct + * IoC I/O context needed for SK I/O macros + * Port Port number + * Mode Mode to set for this LED + */ +#define SK_HWAC_LINK_LED(pAC, IoC, Port, Mode) \ + SK_OUT8(IoC, MR_ADDR(Port, LNK_LED_REG), Mode); + + +/* typedefs *******************************************************************/ + + +/* function prototypes ********************************************************/ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __INC_SKGEHW_H */ diff --git a/drivers/net/sk98lin/h/skgehwt.h b/drivers/net/sk98lin/h/skgehwt.h new file mode 100644 index 000000000000..e6b0016a695c --- /dev/null +++ b/drivers/net/sk98lin/h/skgehwt.h @@ -0,0 +1,48 @@ +/****************************************************************************** + * + * Name: skhwt.h + * Project: Gigabit Ethernet Adapters, Event Scheduler Module + * Version: $Revision: 1.7 $ + * Date: $Date: 2003/09/16 12:55:08 $ + * Purpose: Defines for the hardware timer functions + * + ******************************************************************************/ + +/****************************************************************************** + * + * (C)Copyright 1998-2002 SysKonnect GmbH. + * (C)Copyright 2002-2003 Marvell. + * + * 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. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/* + * SKGEHWT.H contains all defines and types for the timer functions + */ + +#ifndef _SKGEHWT_H_ +#define _SKGEHWT_H_ + +/* + * SK Hardware Timer + * - needed wherever the HWT module is used + * - use in Adapters context name pAC->Hwt + */ +typedef struct s_Hwt { + SK_U32 TStart; /* HWT start */ + SK_U32 TStop; /* HWT stop */ + int TActive; /* HWT: flag : active/inactive */ +} SK_HWT; + +extern void SkHwtInit(SK_AC *pAC, SK_IOC Ioc); +extern void SkHwtStart(SK_AC *pAC, SK_IOC Ioc, SK_U32 Time); +extern void SkHwtStop(SK_AC *pAC, SK_IOC Ioc); +extern SK_U32 SkHwtRead(SK_AC *pAC, SK_IOC Ioc); +extern void SkHwtIsr(SK_AC *pAC, SK_IOC Ioc); +#endif /* _SKGEHWT_H_ */ diff --git a/drivers/net/sk98lin/h/skgei2c.h b/drivers/net/sk98lin/h/skgei2c.h new file mode 100644 index 000000000000..d9b6f6d8dfe2 --- /dev/null +++ b/drivers/net/sk98lin/h/skgei2c.h @@ -0,0 +1,210 @@ +/****************************************************************************** + * + * Name: skgei2c.h + * Project: Gigabit Ethernet Adapters, TWSI-Module + * Version: $Revision: 1.25 $ + * Date: $Date: 2003/10/20 09:06:05 $ + * Purpose: Special defines for TWSI + * + ******************************************************************************/ + +/****************************************************************************** + * + * (C)Copyright 1998-2002 SysKonnect. + * (C)Copyright 2002-2003 Marvell. + * + * 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. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/* + * SKGEI2C.H contains all SK-98xx specific defines for the TWSI handling + */ + +#ifndef _INC_SKGEI2C_H_ +#define _INC_SKGEI2C_H_ + +/* + * Macros to access the B2_I2C_CTRL + */ +#define SK_I2C_CTL(IoC, flag, dev, dev_size, reg, burst) \ + SK_OUT32(IoC, B2_I2C_CTRL,\ + (flag ? 0x80000000UL : 0x0L) | \ + (((SK_U32)reg << 16) & I2C_ADDR) | \ + (((SK_U32)dev << 9) & I2C_DEV_SEL) | \ + (dev_size & I2C_DEV_SIZE) | \ + ((burst << 4) & I2C_BURST_LEN)) + +#define SK_I2C_STOP(IoC) { \ + SK_U32 I2cCtrl; \ + SK_IN32(IoC, B2_I2C_CTRL, &I2cCtrl); \ + SK_OUT32(IoC, B2_I2C_CTRL, I2cCtrl | I2C_STOP); \ +} + +#define SK_I2C_GET_CTL(IoC, pI2cCtrl) SK_IN32(IoC, B2_I2C_CTRL, pI2cCtrl) + +/* + * Macros to access the TWSI SW Registers + */ +#define SK_I2C_SET_BIT(IoC, SetBits) { \ + SK_U8 OrgBits; \ + SK_IN8(IoC, B2_I2C_SW, &OrgBits); \ + SK_OUT8(IoC, B2_I2C_SW, OrgBits | (SK_U8)(SetBits)); \ +} + +#define SK_I2C_CLR_BIT(IoC, ClrBits) { \ + SK_U8 OrgBits; \ + SK_IN8(IoC, B2_I2C_SW, &OrgBits); \ + SK_OUT8(IoC, B2_I2C_SW, OrgBits & ~((SK_U8)(ClrBits))); \ +} + +#define SK_I2C_GET_SW(IoC, pI2cSw) SK_IN8(IoC, B2_I2C_SW, pI2cSw) + +/* + * define the possible sensor states + */ +#define SK_SEN_IDLE 0 /* Idle: sensor not read */ +#define SK_SEN_VALUE 1 /* Value Read cycle */ +#define SK_SEN_VALEXT 2 /* Extended Value Read cycle */ + +/* + * Conversion factor to convert read Voltage sensor to milli Volt + * Conversion factor to convert read Temperature sensor to 10th degree Celsius + */ +#define SK_LM80_VT_LSB 22 /* 22mV LSB resolution */ +#define SK_LM80_TEMP_LSB 10 /* 1 degree LSB resolution */ +#define SK_LM80_TEMPEXT_LSB 5 /* 0.5 degree LSB resolution for ext. val. */ + +/* + * formula: counter = (22500*60)/(rpm * divisor * pulses/2) + * assuming: 6500rpm, 4 pulses, divisor 1 + */ +#define SK_LM80_FAN_FAKTOR ((22500L*60)/(1*2)) + +/* + * Define sensor management data + * Maximum is reached on Genesis copper dual port and Yukon-64 + * Board specific maximum is in pAC->I2c.MaxSens + */ +#define SK_MAX_SENSORS 8 /* maximal no. of installed sensors */ +#define SK_MIN_SENSORS 5 /* minimal no. of installed sensors */ + +/* + * To watch the state machine (SM) use the timer in two ways + * instead of one as hitherto + */ +#define SK_TIMER_WATCH_SM 0 /* Watch the SM to finish in a spec. time */ +#define SK_TIMER_NEW_GAUGING 1 /* Start a new gauging when timer expires */ + +/* + * Defines for the individual thresholds + */ + +/* Temperature sensor */ +#define SK_SEN_TEMP_HIGH_ERR 800 /* Temperature High Err Threshold */ +#define SK_SEN_TEMP_HIGH_WARN 700 /* Temperature High Warn Threshold */ +#define SK_SEN_TEMP_LOW_WARN 100 /* Temperature Low Warn Threshold */ +#define SK_SEN_TEMP_LOW_ERR 0 /* Temperature Low Err Threshold */ + +/* VCC which should be 5 V */ +#define SK_SEN_PCI_5V_HIGH_ERR 5588 /* Voltage PCI High Err Threshold */ +#define SK_SEN_PCI_5V_HIGH_WARN 5346 /* Voltage PCI High Warn Threshold */ +#define SK_SEN_PCI_5V_LOW_WARN 4664 /* Voltage PCI Low Warn Threshold */ +#define SK_SEN_PCI_5V_LOW_ERR 4422 /* Voltage PCI Low Err Threshold */ + +/* + * VIO may be 5 V or 3.3 V. Initialization takes two parts: + * 1. Initialize lowest lower limit and highest higher limit. + * 2. After the first value is read correct the upper or the lower limit to + * the appropriate C constant. + * + * Warning limits are +-5% of the exepected voltage. + * Error limits are +-10% of the expected voltage. + */ + +/* Bug fix AF: 16.Aug.2001: Correct the init base of LM80 sensor */ + +#define SK_SEN_PCI_IO_5V_HIGH_ERR 5566 /* + 10% V PCI-IO High Err Threshold */ +#define SK_SEN_PCI_IO_5V_HIGH_WARN 5324 /* + 5% V PCI-IO High Warn Threshold */ + /* 5000 mVolt */ +#define SK_SEN_PCI_IO_5V_LOW_WARN 4686 /* - 5% V PCI-IO Low Warn Threshold */ +#define SK_SEN_PCI_IO_5V_LOW_ERR 4444 /* - 10% V PCI-IO Low Err Threshold */ + +#define SK_SEN_PCI_IO_RANGE_LIMITER 4000 /* 4000 mV range delimiter */ + +/* correction values for the second pass */ +#define SK_SEN_PCI_IO_3V3_HIGH_ERR 3850 /* + 15% V PCI-IO High Err Threshold */ +#define SK_SEN_PCI_IO_3V3_HIGH_WARN 3674 /* + 10% V PCI-IO High Warn Threshold */ + /* 3300 mVolt */ +#define SK_SEN_PCI_IO_3V3_LOW_WARN 2926 /* - 10% V PCI-IO Low Warn Threshold */ +#define SK_SEN_PCI_IO_3V3_LOW_ERR 2772 /* - 15% V PCI-IO Low Err Threshold */ + +/* + * VDD voltage + */ +#define SK_SEN_VDD_HIGH_ERR 3630 /* Voltage ASIC High Err Threshold */ +#define SK_SEN_VDD_HIGH_WARN 3476 /* Voltage ASIC High Warn Threshold */ +#define SK_SEN_VDD_LOW_WARN 3146 /* Voltage ASIC Low Warn Threshold */ +#define SK_SEN_VDD_LOW_ERR 2970 /* Voltage ASIC Low Err Threshold */ + +/* + * PHY PLL 3V3 voltage + */ +#define SK_SEN_PLL_3V3_HIGH_ERR 3630 /* Voltage PMA High Err Threshold */ +#define SK_SEN_PLL_3V3_HIGH_WARN 3476 /* Voltage PMA High Warn Threshold */ +#define SK_SEN_PLL_3V3_LOW_WARN 3146 /* Voltage PMA Low Warn Threshold */ +#define SK_SEN_PLL_3V3_LOW_ERR 2970 /* Voltage PMA Low Err Threshold */ + +/* + * VAUX (YUKON only) + */ +#define SK_SEN_VAUX_3V3_HIGH_ERR 3630 /* Voltage VAUX High Err Threshold */ +#define SK_SEN_VAUX_3V3_HIGH_WARN 3476 /* Voltage VAUX High Warn Threshold */ +#define SK_SEN_VAUX_3V3_LOW_WARN 3146 /* Voltage VAUX Low Warn Threshold */ +#define SK_SEN_VAUX_3V3_LOW_ERR 2970 /* Voltage VAUX Low Err Threshold */ +#define SK_SEN_VAUX_0V_WARN_ERR 0 /* if VAUX not present */ +#define SK_SEN_VAUX_RANGE_LIMITER 1000 /* 1000 mV range delimiter */ + +/* + * PHY 2V5 voltage + */ +#define SK_SEN_PHY_2V5_HIGH_ERR 2750 /* Voltage PHY High Err Threshold */ +#define SK_SEN_PHY_2V5_HIGH_WARN 2640 /* Voltage PHY High Warn Threshold */ +#define SK_SEN_PHY_2V5_LOW_WARN 2376 /* Voltage PHY Low Warn Threshold */ +#define SK_SEN_PHY_2V5_LOW_ERR 2222 /* Voltage PHY Low Err Threshold */ + +/* + * ASIC Core 1V5 voltage (YUKON only) + */ +#define SK_SEN_CORE_1V5_HIGH_ERR 1650 /* Voltage ASIC Core High Err Threshold */ +#define SK_SEN_CORE_1V5_HIGH_WARN 1575 /* Voltage ASIC Core High Warn Threshold */ +#define SK_SEN_CORE_1V5_LOW_WARN 1425 /* Voltage ASIC Core Low Warn Threshold */ +#define SK_SEN_CORE_1V5_LOW_ERR 1350 /* Voltage ASIC Core Low Err Threshold */ + +/* + * FAN 1 speed + */ +/* assuming: 6500rpm +-15%, 4 pulses, + * warning at: 80 % + * error at: 70 % + * no upper limit + */ +#define SK_SEN_FAN_HIGH_ERR 20000 /* FAN Speed High Err Threshold */ +#define SK_SEN_FAN_HIGH_WARN 20000 /* FAN Speed High Warn Threshold */ +#define SK_SEN_FAN_LOW_WARN 5200 /* FAN Speed Low Warn Threshold */ +#define SK_SEN_FAN_LOW_ERR 4550 /* FAN Speed Low Err Threshold */ + +/* + * Some Voltages need dynamic thresholds + */ +#define SK_SEN_DYN_INIT_NONE 0 /* No dynamic init of thresholds */ +#define SK_SEN_DYN_INIT_PCI_IO 10 /* Init PCI-IO with new thresholds */ +#define SK_SEN_DYN_INIT_VAUX 11 /* Init VAUX with new thresholds */ + +extern int SkLm80ReadSensor(SK_AC *pAC, SK_IOC IoC, SK_SENSOR *pSen); +#endif /* n_INC_SKGEI2C_H */ diff --git a/drivers/net/sk98lin/h/skgeinit.h b/drivers/net/sk98lin/h/skgeinit.h new file mode 100644 index 000000000000..143e635ec24d --- /dev/null +++ b/drivers/net/sk98lin/h/skgeinit.h @@ -0,0 +1,797 @@ +/****************************************************************************** + * + * Name: skgeinit.h + * Project: Gigabit Ethernet Adapters, Common Modules + * Version: $Revision: 1.83 $ + * Date: $Date: 2003/09/16 14:07:37 $ + * Purpose: Structures and prototypes for the GE Init Module + * + ******************************************************************************/ + +/****************************************************************************** + * + * (C)Copyright 1998-2002 SysKonnect. + * (C)Copyright 2002-2003 Marvell. + * + * 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. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +#ifndef __INC_SKGEINIT_H_ +#define __INC_SKGEINIT_H_ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* defines ********************************************************************/ + +#define SK_TEST_VAL 0x11335577UL + +/* modifying Link LED behaviour (used with SkGeLinkLED()) */ +#define SK_LNK_OFF LED_OFF +#define SK_LNK_ON (LED_ON | LED_BLK_OFF | LED_SYNC_OFF) +#define SK_LNK_BLINK (LED_ON | LED_BLK_ON | LED_SYNC_ON) +#define SK_LNK_PERM (LED_ON | LED_BLK_OFF | LED_SYNC_ON) +#define SK_LNK_TST (LED_ON | LED_BLK_ON | LED_SYNC_OFF) + +/* parameter 'Mode' when calling SK_HWAC_LINK_LED() */ +#define SK_LED_OFF LED_OFF +#define SK_LED_ACTIVE (LED_ON | LED_BLK_OFF | LED_SYNC_OFF) +#define SK_LED_STANDBY (LED_ON | LED_BLK_ON | LED_SYNC_OFF) + +/* addressing LED Registers in SkGeXmitLED() */ +#define XMIT_LED_INI 0 +#define XMIT_LED_CNT (RX_LED_VAL - RX_LED_INI) +#define XMIT_LED_CTRL (RX_LED_CTRL- RX_LED_INI) +#define XMIT_LED_TST (RX_LED_TST - RX_LED_INI) + +/* parameter 'Mode' when calling SkGeXmitLED() */ +#define SK_LED_DIS 0 +#define SK_LED_ENA 1 +#define SK_LED_TST 2 + +/* Counter and Timer constants, for a host clock of 62.5 MHz */ +#define SK_XMIT_DUR 0x002faf08UL /* 50 ms */ +#define SK_BLK_DUR 0x01dcd650UL /* 500 ms */ + +#define SK_DPOLL_DEF 0x00ee6b28UL /* 250 ms at 62.5 MHz */ + +#define SK_DPOLL_MAX 0x00ffffffUL /* 268 ms at 62.5 MHz */ + /* 215 ms at 78.12 MHz */ + +#define SK_FACT_62 100 /* is given in percent */ +#define SK_FACT_53 85 /* on GENESIS: 53.12 MHz */ +#define SK_FACT_78 125 /* on YUKON: 78.12 MHz */ + +/* Timeout values */ +#define SK_MAC_TO_53 72 /* MAC arbiter timeout */ +#define SK_PKT_TO_53 0x2000 /* Packet arbiter timeout */ +#define SK_PKT_TO_MAX 0xffff /* Maximum value */ +#define SK_RI_TO_53 36 /* RAM interface timeout */ + +#define SK_PHY_ACC_TO 600000 /* PHY access timeout */ + +/* RAM Buffer High Pause Threshold values */ +#define SK_RB_ULPP ( 8 * 1024) /* Upper Level in kB/8 */ +#define SK_RB_LLPP_S (10 * 1024) /* Lower Level for small Queues */ +#define SK_RB_LLPP_B (16 * 1024) /* Lower Level for big Queues */ + +#ifndef SK_BMU_RX_WM +#define SK_BMU_RX_WM 0x600 /* BMU Rx Watermark */ +#endif +#ifndef SK_BMU_TX_WM +#define SK_BMU_TX_WM 0x600 /* BMU Tx Watermark */ +#endif + +/* XMAC II Rx High Watermark */ +#define SK_XM_RX_HI_WM 0x05aa /* 1450 */ + +/* XMAC II Tx Threshold */ +#define SK_XM_THR_REDL 0x01fb /* .. for redundant link usage */ +#define SK_XM_THR_SL 0x01fb /* .. for single link adapters */ +#define SK_XM_THR_MULL 0x01fb /* .. for multiple link usage */ +#define SK_XM_THR_JUMBO 0x03fc /* .. for jumbo frame usage */ + +/* values for GIPortUsage */ +#define SK_RED_LINK 1 /* redundant link usage */ +#define SK_MUL_LINK 2 /* multiple link usage */ +#define SK_JUMBO_LINK 3 /* driver uses jumbo frames */ + +/* Minimum RAM Buffer Rx Queue Size */ +#define SK_MIN_RXQ_SIZE 16 /* 16 kB */ + +/* Minimum RAM Buffer Tx Queue Size */ +#define SK_MIN_TXQ_SIZE 16 /* 16 kB */ + +/* Queue Size units */ +#define QZ_UNITS 0x7 +#define QZ_STEP 8 + +/* Percentage of queue size from whole memory */ +/* 80 % for receive */ +#define RAM_QUOTA_RX 80L +/* 0% for sync transfer */ +#define RAM_QUOTA_SYNC 0L +/* the rest (20%) is taken for async transfer */ + +/* Get the rounded queue size in Bytes in 8k steps */ +#define ROUND_QUEUE_SIZE(SizeInBytes) \ + ((((unsigned long) (SizeInBytes) + (QZ_STEP*1024L)-1) / 1024) & \ + ~(QZ_STEP-1)) + +/* Get the rounded queue size in KBytes in 8k steps */ +#define ROUND_QUEUE_SIZE_KB(Kilobytes) \ + ROUND_QUEUE_SIZE((Kilobytes) * 1024L) + +/* Types of RAM Buffer Queues */ +#define SK_RX_SRAM_Q 1 /* small receive queue */ +#define SK_RX_BRAM_Q 2 /* big receive queue */ +#define SK_TX_RAM_Q 3 /* small or big transmit queue */ + +/* parameter 'Dir' when calling SkGeStopPort() */ +#define SK_STOP_TX 1 /* Stops the transmit path, resets the XMAC */ +#define SK_STOP_RX 2 /* Stops the receive path */ +#define SK_STOP_ALL 3 /* Stops Rx and Tx path, resets the XMAC */ + +/* parameter 'RstMode' when calling SkGeStopPort() */ +#define SK_SOFT_RST 1 /* perform a software reset */ +#define SK_HARD_RST 2 /* perform a hardware reset */ + +/* Init Levels */ +#define SK_INIT_DATA 0 /* Init level 0: init data structures */ +#define SK_INIT_IO 1 /* Init level 1: init with IOs */ +#define SK_INIT_RUN 2 /* Init level 2: init for run time */ + +/* Link Mode Parameter */ +#define SK_LMODE_HALF 1 /* Half Duplex Mode */ +#define SK_LMODE_FULL 2 /* Full Duplex Mode */ +#define SK_LMODE_AUTOHALF 3 /* AutoHalf Duplex Mode */ +#define SK_LMODE_AUTOFULL 4 /* AutoFull Duplex Mode */ +#define SK_LMODE_AUTOBOTH 5 /* AutoBoth Duplex Mode */ +#define SK_LMODE_AUTOSENSE 6 /* configured mode auto sensing */ +#define SK_LMODE_INDETERMINATED 7 /* indeterminated */ + +/* Auto-negotiation timeout in 100ms granularity */ +#define SK_AND_MAX_TO 6 /* Wait 600 msec before link comes up */ + +/* Auto-negotiation error codes */ +#define SK_AND_OK 0 /* no error */ +#define SK_AND_OTHER 1 /* other error than below */ +#define SK_AND_DUP_CAP 2 /* Duplex capabilities error */ + + +/* Link Speed Capabilities */ +#define SK_LSPEED_CAP_AUTO (1<<0) /* Automatic resolution */ +#define SK_LSPEED_CAP_10MBPS (1<<1) /* 10 Mbps */ +#define SK_LSPEED_CAP_100MBPS (1<<2) /* 100 Mbps */ +#define SK_LSPEED_CAP_1000MBPS (1<<3) /* 1000 Mbps */ +#define SK_LSPEED_CAP_INDETERMINATED (1<<4) /* indeterminated */ + +/* Link Speed Parameter */ +#define SK_LSPEED_AUTO 1 /* Automatic resolution */ +#define SK_LSPEED_10MBPS 2 /* 10 Mbps */ +#define SK_LSPEED_100MBPS 3 /* 100 Mbps */ +#define SK_LSPEED_1000MBPS 4 /* 1000 Mbps */ +#define SK_LSPEED_INDETERMINATED 5 /* indeterminated */ + +/* Link Speed Current State */ +#define SK_LSPEED_STAT_UNKNOWN 1 +#define SK_LSPEED_STAT_10MBPS 2 +#define SK_LSPEED_STAT_100MBPS 3 +#define SK_LSPEED_STAT_1000MBPS 4 +#define SK_LSPEED_STAT_INDETERMINATED 5 + + +/* Link Capability Parameter */ +#define SK_LMODE_CAP_HALF (1<<0) /* Half Duplex Mode */ +#define SK_LMODE_CAP_FULL (1<<1) /* Full Duplex Mode */ +#define SK_LMODE_CAP_AUTOHALF (1<<2) /* AutoHalf Duplex Mode */ +#define SK_LMODE_CAP_AUTOFULL (1<<3) /* AutoFull Duplex Mode */ +#define SK_LMODE_CAP_INDETERMINATED (1<<4) /* indeterminated */ + +/* Link Mode Current State */ +#define SK_LMODE_STAT_UNKNOWN 1 /* Unknown Duplex Mode */ +#define SK_LMODE_STAT_HALF 2 /* Half Duplex Mode */ +#define SK_LMODE_STAT_FULL 3 /* Full Duplex Mode */ +#define SK_LMODE_STAT_AUTOHALF 4 /* Half Duplex Mode obtained by Auto-Neg */ +#define SK_LMODE_STAT_AUTOFULL 5 /* Full Duplex Mode obtained by Auto-Neg */ +#define SK_LMODE_STAT_INDETERMINATED 6 /* indeterminated */ + +/* Flow Control Mode Parameter (and capabilities) */ +#define SK_FLOW_MODE_NONE 1 /* No Flow-Control */ +#define SK_FLOW_MODE_LOC_SEND 2 /* Local station sends PAUSE */ +#define SK_FLOW_MODE_SYMMETRIC 3 /* Both stations may send PAUSE */ +#define SK_FLOW_MODE_SYM_OR_REM 4 /* Both stations may send PAUSE or + * just the remote station may send PAUSE + */ +#define SK_FLOW_MODE_INDETERMINATED 5 /* indeterminated */ + +/* Flow Control Status Parameter */ +#define SK_FLOW_STAT_NONE 1 /* No Flow Control */ +#define SK_FLOW_STAT_REM_SEND 2 /* Remote Station sends PAUSE */ +#define SK_FLOW_STAT_LOC_SEND 3 /* Local station sends PAUSE */ +#define SK_FLOW_STAT_SYMMETRIC 4 /* Both station may send PAUSE */ +#define SK_FLOW_STAT_INDETERMINATED 5 /* indeterminated */ + +/* Master/Slave Mode Capabilities */ +#define SK_MS_CAP_AUTO (1<<0) /* Automatic resolution */ +#define SK_MS_CAP_MASTER (1<<1) /* This station is master */ +#define SK_MS_CAP_SLAVE (1<<2) /* This station is slave */ +#define SK_MS_CAP_INDETERMINATED (1<<3) /* indeterminated */ + +/* Set Master/Slave Mode Parameter (and capabilities) */ +#define SK_MS_MODE_AUTO 1 /* Automatic resolution */ +#define SK_MS_MODE_MASTER 2 /* This station is master */ +#define SK_MS_MODE_SLAVE 3 /* This station is slave */ +#define SK_MS_MODE_INDETERMINATED 4 /* indeterminated */ + +/* Master/Slave Status Parameter */ +#define SK_MS_STAT_UNSET 1 /* The M/S status is not set */ +#define SK_MS_STAT_MASTER 2 /* This station is master */ +#define SK_MS_STAT_SLAVE 3 /* This station is slave */ +#define SK_MS_STAT_FAULT 4 /* M/S resolution failed */ +#define SK_MS_STAT_INDETERMINATED 5 /* indeterminated */ + +/* parameter 'Mode' when calling SkXmSetRxCmd() */ +#define SK_STRIP_FCS_ON (1<<0) /* Enable FCS stripping of Rx frames */ +#define SK_STRIP_FCS_OFF (1<<1) /* Disable FCS stripping of Rx frames */ +#define SK_STRIP_PAD_ON (1<<2) /* Enable pad byte stripping of Rx fr */ +#define SK_STRIP_PAD_OFF (1<<3) /* Disable pad byte stripping of Rx fr */ +#define SK_LENERR_OK_ON (1<<4) /* Don't chk fr for in range len error */ +#define SK_LENERR_OK_OFF (1<<5) /* Check frames for in range len error */ +#define SK_BIG_PK_OK_ON (1<<6) /* Don't set Rx Error bit for big frames */ +#define SK_BIG_PK_OK_OFF (1<<7) /* Set Rx Error bit for big frames */ +#define SK_SELF_RX_ON (1<<8) /* Enable Rx of own packets */ +#define SK_SELF_RX_OFF (1<<9) /* Disable Rx of own packets */ + +/* parameter 'Para' when calling SkMacSetRxTxEn() */ +#define SK_MAC_LOOPB_ON (1<<0) /* Enable MAC Loopback Mode */ +#define SK_MAC_LOOPB_OFF (1<<1) /* Disable MAC Loopback Mode */ +#define SK_PHY_LOOPB_ON (1<<2) /* Enable PHY Loopback Mode */ +#define SK_PHY_LOOPB_OFF (1<<3) /* Disable PHY Loopback Mode */ +#define SK_PHY_FULLD_ON (1<<4) /* Enable GMII Full Duplex */ +#define SK_PHY_FULLD_OFF (1<<5) /* Disable GMII Full Duplex */ + +/* States of PState */ +#define SK_PRT_RESET 0 /* the port is reset */ +#define SK_PRT_STOP 1 /* the port is stopped (similar to SW reset) */ +#define SK_PRT_INIT 2 /* the port is initialized */ +#define SK_PRT_RUN 3 /* the port has an active link */ + +/* PHY power down modes */ +#define PHY_PM_OPERATIONAL_MODE 0 /* PHY operational mode */ +#define PHY_PM_DEEP_SLEEP 1 /* coma mode --> minimal power */ +#define PHY_PM_IEEE_POWER_DOWN 2 /* IEEE 22.2.4.1.5 compl. power down */ +#define PHY_PM_ENERGY_DETECT 3 /* energy detect */ +#define PHY_PM_ENERGY_DETECT_PLUS 4 /* energy detect plus */ + +/* Default receive frame limit for Workaround of XMAC Errata */ +#define SK_DEF_RX_WA_LIM SK_CONSTU64(100) + +/* values for GILedBlinkCtrl (LED Blink Control) */ +#define SK_ACT_LED_BLINK (1<<0) /* Active LED blinking */ +#define SK_DUP_LED_NORMAL (1<<1) /* Duplex LED normal */ +#define SK_LED_LINK100_ON (1<<2) /* Link 100M LED on */ + +/* Link Partner Status */ +#define SK_LIPA_UNKNOWN 0 /* Link partner is in unknown state */ +#define SK_LIPA_MANUAL 1 /* Link partner is in detected manual state */ +#define SK_LIPA_AUTO 2 /* Link partner is in auto-negotiation state */ + +/* Maximum Restarts before restart is ignored (3Com WA) */ +#define SK_MAX_LRESTART 3 /* Max. 3 times the link is restarted */ + +/* Max. Auto-neg. timeouts before link detection in sense mode is reset */ +#define SK_MAX_ANEG_TO 10 /* Max. 10 times the sense mode is reset */ + +/* structures *****************************************************************/ + +/* + * MAC specific functions + */ +typedef struct s_GeMacFunc { + int (*pFnMacUpdateStats)(SK_AC *pAC, SK_IOC IoC, unsigned int Port); + int (*pFnMacStatistic)(SK_AC *pAC, SK_IOC IoC, unsigned int Port, + SK_U16 StatAddr, SK_U32 SK_FAR *pVal); + int (*pFnMacResetCounter)(SK_AC *pAC, SK_IOC IoC, unsigned int Port); + int (*pFnMacOverflow)(SK_AC *pAC, SK_IOC IoC, unsigned int Port, + SK_U16 IStatus, SK_U64 SK_FAR *pVal); +} SK_GEMACFUNC; + +/* + * Port Structure + */ +typedef struct s_GePort { +#ifndef SK_DIAG + SK_TIMER PWaTimer; /* Workaround Timer */ + SK_TIMER HalfDupChkTimer; +#endif /* SK_DIAG */ + SK_U32 PPrevShorts; /* Previous Short Counter checking */ + SK_U32 PPrevFcs; /* Previous FCS Error Counter checking */ + SK_U64 PPrevRx; /* Previous RxOk Counter checking */ + SK_U64 PRxLim; /* Previous RxOk Counter checking */ + SK_U64 LastOctets; /* For half duplex hang check */ + int PLinkResCt; /* Link Restart Counter */ + int PAutoNegTimeOut;/* Auto-negotiation timeout current value */ + int PAutoNegTOCt; /* Auto-negotiation Timeout Counter */ + int PRxQSize; /* Port Rx Queue Size in kB */ + int PXSQSize; /* Port Synchronous Transmit Queue Size in kB */ + int PXAQSize; /* Port Asynchronous Transmit Queue Size in kB */ + SK_U32 PRxQRamStart; /* Receive Queue RAM Buffer Start Address */ + SK_U32 PRxQRamEnd; /* Receive Queue RAM Buffer End Address */ + SK_U32 PXsQRamStart; /* Sync Tx Queue RAM Buffer Start Address */ + SK_U32 PXsQRamEnd; /* Sync Tx Queue RAM Buffer End Address */ + SK_U32 PXaQRamStart; /* Async Tx Queue RAM Buffer Start Address */ + SK_U32 PXaQRamEnd; /* Async Tx Queue RAM Buffer End Address */ + SK_U32 PRxOverCnt; /* Receive Overflow Counter */ + int PRxQOff; /* Rx Queue Address Offset */ + int PXsQOff; /* Synchronous Tx Queue Address Offset */ + int PXaQOff; /* Asynchronous Tx Queue Address Offset */ + int PhyType; /* PHY used on this port */ + int PState; /* Port status (reset, stop, init, run) */ + SK_U16 PhyId1; /* PHY Id1 on this port */ + SK_U16 PhyAddr; /* MDIO/MDC PHY address */ + SK_U16 PIsave; /* Saved Interrupt status word */ + SK_U16 PSsave; /* Saved PHY status word */ + SK_U16 PGmANegAdv; /* Saved GPhy AutoNegAdvertisment register */ + SK_BOOL PHWLinkUp; /* The hardware Link is up (wiring) */ + SK_BOOL PLinkBroken; /* Is Link broken ? */ + SK_BOOL PCheckPar; /* Do we check for parity errors ? */ + SK_BOOL HalfDupTimerActive; + SK_U8 PLinkCap; /* Link Capabilities */ + SK_U8 PLinkModeConf; /* Link Mode configured */ + SK_U8 PLinkMode; /* Link Mode currently used */ + SK_U8 PLinkModeStatus;/* Link Mode Status */ + SK_U8 PLinkSpeedCap; /* Link Speed Capabilities(10/100/1000 Mbps) */ + SK_U8 PLinkSpeed; /* configured Link Speed (10/100/1000 Mbps) */ + SK_U8 PLinkSpeedUsed; /* current Link Speed (10/100/1000 Mbps) */ + SK_U8 PFlowCtrlCap; /* Flow Control Capabilities */ + SK_U8 PFlowCtrlMode; /* Flow Control Mode */ + SK_U8 PFlowCtrlStatus;/* Flow Control Status */ + SK_U8 PMSCap; /* Master/Slave Capabilities */ + SK_U8 PMSMode; /* Master/Slave Mode */ + SK_U8 PMSStatus; /* Master/Slave Status */ + SK_BOOL PAutoNegFail; /* Auto-negotiation fail flag */ + SK_U8 PLipaAutoNeg; /* Auto-negotiation possible with Link Partner */ + SK_U8 PCableLen; /* Cable Length */ + SK_U8 PMdiPairLen[4]; /* MDI[0..3] Pair Length */ + SK_U8 PMdiPairSts[4]; /* MDI[0..3] Pair Diagnostic Status */ + SK_U8 PPhyPowerState; /* PHY current power state */ + int PMacColThres; /* MAC Collision Threshold */ + int PMacJamLen; /* MAC Jam length */ + int PMacJamIpgVal; /* MAC Jam IPG */ + int PMacJamIpgData; /* MAC IPG Jam to Data */ + int PMacIpgData; /* MAC Data IPG */ + SK_BOOL PMacLimit4; /* reset collision counter and backoff algorithm */ +} SK_GEPORT; + +/* + * Gigabit Ethernet Initialization Struct + * (has to be included in the adapter context) + */ +typedef struct s_GeInit { + int GIChipId; /* Chip Identification Number */ + int GIChipRev; /* Chip Revision Number */ + SK_U8 GIPciHwRev; /* PCI HW Revision Number */ + SK_BOOL GIGenesis; /* Genesis adapter ? */ + SK_BOOL GIYukon; /* YUKON-A1/Bx chip */ + SK_BOOL GIYukonLite; /* YUKON-Lite chip */ + SK_BOOL GICopperType; /* Copper Type adapter ? */ + SK_BOOL GIPciSlot64; /* 64-bit PCI Slot */ + SK_BOOL GIPciClock66; /* 66 MHz PCI Clock */ + SK_BOOL GIVauxAvail; /* VAUX available (YUKON) */ + SK_BOOL GIYukon32Bit; /* 32-Bit YUKON adapter */ + SK_U16 GILedBlinkCtrl; /* LED Blink Control */ + int GIMacsFound; /* Number of MACs found on this adapter */ + int GIMacType; /* MAC Type used on this adapter */ + int GIHstClkFact; /* Host Clock Factor (62.5 / HstClk * 100) */ + int GIPortUsage; /* Driver Port Usage */ + int GILevel; /* Initialization Level completed */ + int GIRamSize; /* The RAM size of the adapter in kB */ + int GIWolOffs; /* WOL Register Offset (HW-Bug in Rev. A) */ + SK_U32 GIRamOffs; /* RAM Address Offset for addr calculation */ + SK_U32 GIPollTimerVal; /* Descr. Poll Timer Init Val (HstClk ticks) */ + SK_U32 GIValIrqMask; /* Value for Interrupt Mask */ + SK_U32 GITimeStampCnt; /* Time Stamp High Counter (YUKON only) */ + SK_GEPORT GP[SK_MAX_MACS];/* Port Dependent Information */ + SK_GEMACFUNC GIFunc; /* MAC depedent functions */ +} SK_GEINIT; + +/* + * Error numbers and messages for skxmac2.c and skgeinit.c + */ +#define SKERR_HWI_E001 (SK_ERRBASE_HWINIT) +#define SKERR_HWI_E001MSG "SkXmClrExactAddr() has got illegal parameters" +#define SKERR_HWI_E002 (SKERR_HWI_E001+1) +#define SKERR_HWI_E002MSG "SkGeInit(): Level 1 call missing" +#define SKERR_HWI_E003 (SKERR_HWI_E002+1) +#define SKERR_HWI_E003MSG "SkGeInit() called with illegal init Level" +#define SKERR_HWI_E004 (SKERR_HWI_E003+1) +#define SKERR_HWI_E004MSG "SkGeInitPort(): Queue Size illegal configured" +#define SKERR_HWI_E005 (SKERR_HWI_E004+1) +#define SKERR_HWI_E005MSG "SkGeInitPort(): cannot init running ports" +#define SKERR_HWI_E006 (SKERR_HWI_E005+1) +#define SKERR_HWI_E006MSG "SkGeMacInit(): PState does not match HW state" +#define SKERR_HWI_E007 (SKERR_HWI_E006+1) +#define SKERR_HWI_E007MSG "SkXmInitDupMd() called with invalid Dup Mode" +#define SKERR_HWI_E008 (SKERR_HWI_E007+1) +#define SKERR_HWI_E008MSG "SkXmSetRxCmd() called with invalid Mode" +#define SKERR_HWI_E009 (SKERR_HWI_E008+1) +#define SKERR_HWI_E009MSG "SkGeCfgSync() called although PXSQSize zero" +#define SKERR_HWI_E010 (SKERR_HWI_E009+1) +#define SKERR_HWI_E010MSG "SkGeCfgSync() called with invalid parameters" +#define SKERR_HWI_E011 (SKERR_HWI_E010+1) +#define SKERR_HWI_E011MSG "SkGeInitPort(): Receive Queue Size too small" +#define SKERR_HWI_E012 (SKERR_HWI_E011+1) +#define SKERR_HWI_E012MSG "SkGeInitPort(): invalid Queue Size specified" +#define SKERR_HWI_E013 (SKERR_HWI_E012+1) +#define SKERR_HWI_E013MSG "SkGeInitPort(): cfg changed for running queue" +#define SKERR_HWI_E014 (SKERR_HWI_E013+1) +#define SKERR_HWI_E014MSG "SkGeInitPort(): unknown GIPortUsage specified" +#define SKERR_HWI_E015 (SKERR_HWI_E014+1) +#define SKERR_HWI_E015MSG "Illegal Link mode parameter" +#define SKERR_HWI_E016 (SKERR_HWI_E015+1) +#define SKERR_HWI_E016MSG "Illegal Flow control mode parameter" +#define SKERR_HWI_E017 (SKERR_HWI_E016+1) +#define SKERR_HWI_E017MSG "Illegal value specified for GIPollTimerVal" +#define SKERR_HWI_E018 (SKERR_HWI_E017+1) +#define SKERR_HWI_E018MSG "FATAL: SkGeStopPort() does not terminate (Tx)" +#define SKERR_HWI_E019 (SKERR_HWI_E018+1) +#define SKERR_HWI_E019MSG "Illegal Speed parameter" +#define SKERR_HWI_E020 (SKERR_HWI_E019+1) +#define SKERR_HWI_E020MSG "Illegal Master/Slave parameter" +#define SKERR_HWI_E021 (SKERR_HWI_E020+1) +#define SKERR_HWI_E021MSG "MacUpdateStats(): cannot update statistic counter" +#define SKERR_HWI_E022 (SKERR_HWI_E021+1) +#define SKERR_HWI_E022MSG "MacStatistic(): illegal statistic base address" +#define SKERR_HWI_E023 (SKERR_HWI_E022+1) +#define SKERR_HWI_E023MSG "SkGeInitPort(): Transmit Queue Size too small" +#define SKERR_HWI_E024 (SKERR_HWI_E023+1) +#define SKERR_HWI_E024MSG "FATAL: SkGeStopPort() does not terminate (Rx)" +#define SKERR_HWI_E025 (SKERR_HWI_E024+1) +#define SKERR_HWI_E025MSG "" + +/* function prototypes ********************************************************/ + +#ifndef SK_KR_PROTO + +/* + * public functions in skgeinit.c + */ +extern void SkGePollTxD( + SK_AC *pAC, + SK_IOC IoC, + int Port, + SK_BOOL PollTxD); + +extern void SkGeYellowLED( + SK_AC *pAC, + SK_IOC IoC, + int State); + +extern int SkGeCfgSync( + SK_AC *pAC, + SK_IOC IoC, + int Port, + SK_U32 IntTime, + SK_U32 LimCount, + int SyncMode); + +extern void SkGeLoadLnkSyncCnt( + SK_AC *pAC, + SK_IOC IoC, + int Port, + SK_U32 CntVal); + +extern void SkGeStopPort( + SK_AC *pAC, + SK_IOC IoC, + int Port, + int Dir, + int RstMode); + +extern int SkGeInit( + SK_AC *pAC, + SK_IOC IoC, + int Level); + +extern void SkGeDeInit( + SK_AC *pAC, + SK_IOC IoC); + +extern int SkGeInitPort( + SK_AC *pAC, + SK_IOC IoC, + int Port); + +extern void SkGeXmitLED( + SK_AC *pAC, + SK_IOC IoC, + int Led, + int Mode); + +extern int SkGeInitAssignRamToQueues( + SK_AC *pAC, + int ActivePort, + SK_BOOL DualNet); + +/* + * public functions in skxmac2.c + */ +extern void SkMacRxTxDisable( + SK_AC *pAC, + SK_IOC IoC, + int Port); + +extern void SkMacSoftRst( + SK_AC *pAC, + SK_IOC IoC, + int Port); + +extern void SkMacHardRst( + SK_AC *pAC, + SK_IOC IoC, + int Port); + +extern void SkXmInitMac( + SK_AC *pAC, + SK_IOC IoC, + int Port); + +extern void SkGmInitMac( + SK_AC *pAC, + SK_IOC IoC, + int Port); + +extern void SkMacInitPhy( + SK_AC *pAC, + SK_IOC IoC, + int Port, + SK_BOOL DoLoop); + +extern void SkMacIrqDisable( + SK_AC *pAC, + SK_IOC IoC, + int Port); + +extern void SkMacFlushTxFifo( + SK_AC *pAC, + SK_IOC IoC, + int Port); + +extern void SkMacIrq( + SK_AC *pAC, + SK_IOC IoC, + int Port); + +extern int SkMacAutoNegDone( + SK_AC *pAC, + SK_IOC IoC, + int Port); + +extern void SkMacAutoNegLipaPhy( + SK_AC *pAC, + SK_IOC IoC, + int Port, + SK_U16 IStatus); + +extern int SkMacRxTxEnable( + SK_AC *pAC, + SK_IOC IoC, + int Port); + +extern void SkMacPromiscMode( + SK_AC *pAC, + SK_IOC IoC, + int Port, + SK_BOOL Enable); + +extern void SkMacHashing( + SK_AC *pAC, + SK_IOC IoC, + int Port, + SK_BOOL Enable); + +extern void SkXmPhyRead( + SK_AC *pAC, + SK_IOC IoC, + int Port, + int Addr, + SK_U16 SK_FAR *pVal); + +extern void SkXmPhyWrite( + SK_AC *pAC, + SK_IOC IoC, + int Port, + int Addr, + SK_U16 Val); + +extern void SkGmPhyRead( + SK_AC *pAC, + SK_IOC IoC, + int Port, + int Addr, + SK_U16 SK_FAR *pVal); + +extern void SkGmPhyWrite( + SK_AC *pAC, + SK_IOC IoC, + int Port, + int Addr, + SK_U16 Val); + +extern void SkXmClrExactAddr( + SK_AC *pAC, + SK_IOC IoC, + int Port, + int StartNum, + int StopNum); + +extern void SkXmAutoNegLipaXmac( + SK_AC *pAC, + SK_IOC IoC, + int Port, + SK_U16 IStatus); + +extern int SkXmUpdateStats( + SK_AC *pAC, + SK_IOC IoC, + unsigned int Port); + +extern int SkGmUpdateStats( + SK_AC *pAC, + SK_IOC IoC, + unsigned int Port); + +extern int SkXmMacStatistic( + SK_AC *pAC, + SK_IOC IoC, + unsigned int Port, + SK_U16 StatAddr, + SK_U32 SK_FAR *pVal); + +extern int SkGmMacStatistic( + SK_AC *pAC, + SK_IOC IoC, + unsigned int Port, + SK_U16 StatAddr, + SK_U32 SK_FAR *pVal); + +extern int SkXmResetCounter( + SK_AC *pAC, + SK_IOC IoC, + unsigned int Port); + +extern int SkGmResetCounter( + SK_AC *pAC, + SK_IOC IoC, + unsigned int Port); + +extern int SkXmOverflowStatus( + SK_AC *pAC, + SK_IOC IoC, + unsigned int Port, + SK_U16 IStatus, + SK_U64 SK_FAR *pStatus); + +extern int SkGmOverflowStatus( + SK_AC *pAC, + SK_IOC IoC, + unsigned int Port, + SK_U16 MacStatus, + SK_U64 SK_FAR *pStatus); + +extern int SkGmCableDiagStatus( + SK_AC *pAC, + SK_IOC IoC, + int Port, + SK_BOOL StartTest); + +#ifdef SK_DIAG +extern void SkGePhyRead( + SK_AC *pAC, + SK_IOC IoC, + int Port, + int Addr, + SK_U16 *pVal); + +extern void SkGePhyWrite( + SK_AC *pAC, + SK_IOC IoC, + int Port, + int Addr, + SK_U16 Val); + +extern void SkMacSetRxCmd( + SK_AC *pAC, + SK_IOC IoC, + int Port, + int Mode); +extern void SkMacCrcGener( + SK_AC *pAC, + SK_IOC IoC, + int Port, + SK_BOOL Enable); +extern void SkMacTimeStamp( + SK_AC *pAC, + SK_IOC IoC, + int Port, + SK_BOOL Enable); +extern void SkXmSendCont( + SK_AC *pAC, + SK_IOC IoC, + int Port, + SK_BOOL Enable); +#endif /* SK_DIAG */ + +#else /* SK_KR_PROTO */ + +/* + * public functions in skgeinit.c + */ +extern void SkGePollTxD(); +extern void SkGeYellowLED(); +extern int SkGeCfgSync(); +extern void SkGeLoadLnkSyncCnt(); +extern void SkGeStopPort(); +extern int SkGeInit(); +extern void SkGeDeInit(); +extern int SkGeInitPort(); +extern void SkGeXmitLED(); +extern int SkGeInitAssignRamToQueues(); + +/* + * public functions in skxmac2.c + */ +extern void SkMacRxTxDisable(); +extern void SkMacSoftRst(); +extern void SkMacHardRst(); +extern void SkMacInitPhy(); +extern int SkMacRxTxEnable(); +extern void SkMacPromiscMode(); +extern void SkMacHashing(); +extern void SkMacIrqDisable(); +extern void SkMacFlushTxFifo(); +extern void SkMacIrq(); +extern int SkMacAutoNegDone(); +extern void SkMacAutoNegLipaPhy(); +extern void SkXmInitMac(); +extern void SkXmPhyRead(); +extern void SkXmPhyWrite(); +extern void SkGmInitMac(); +extern void SkGmPhyRead(); +extern void SkGmPhyWrite(); +extern void SkXmClrExactAddr(); +extern void SkXmAutoNegLipaXmac(); +extern int SkXmUpdateStats(); +extern int SkGmUpdateStats(); +extern int SkXmMacStatistic(); +extern int SkGmMacStatistic(); +extern int SkXmResetCounter(); +extern int SkGmResetCounter(); +extern int SkXmOverflowStatus(); +extern int SkGmOverflowStatus(); +extern int SkGmCableDiagStatus(); + +#ifdef SK_DIAG +extern void SkGePhyRead(); +extern void SkGePhyWrite(); +extern void SkMacSetRxCmd(); +extern void SkMacCrcGener(); +extern void SkMacTimeStamp(); +extern void SkXmSendCont(); +#endif /* SK_DIAG */ + +#endif /* SK_KR_PROTO */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __INC_SKGEINIT_H_ */ diff --git a/drivers/net/sk98lin/h/skgepnm2.h b/drivers/net/sk98lin/h/skgepnm2.h new file mode 100644 index 000000000000..ddd304f1a48b --- /dev/null +++ b/drivers/net/sk98lin/h/skgepnm2.h @@ -0,0 +1,334 @@ +/***************************************************************************** + * + * Name: skgepnm2.h + * Project: GEnesis, PCI Gigabit Ethernet Adapter + * Version: $Revision: 1.36 $ + * Date: $Date: 2003/05/23 12:45:13 $ + * Purpose: Defines for Private Network Management Interface + * + ****************************************************************************/ + +/****************************************************************************** + * + * (C)Copyright 1998-2002 SysKonnect GmbH. + * (C)Copyright 2002-2003 Marvell. + * + * 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. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +#ifndef _SKGEPNM2_H_ +#define _SKGEPNM2_H_ + +/* + * General definitions + */ +#define SK_PNMI_CHIPSET_XMAC 1 /* XMAC11800FP */ +#define SK_PNMI_CHIPSET_YUKON 2 /* YUKON */ + +#define SK_PNMI_BUS_PCI 1 /* PCI bus*/ + +/* + * Actions + */ +#define SK_PNMI_ACT_IDLE 1 +#define SK_PNMI_ACT_RESET 2 +#define SK_PNMI_ACT_SELFTEST 3 +#define SK_PNMI_ACT_RESETCNT 4 + +/* + * VPD releated defines + */ + +#define SK_PNMI_VPD_RW 1 +#define SK_PNMI_VPD_RO 2 + +#define SK_PNMI_VPD_OK 0 +#define SK_PNMI_VPD_NOTFOUND 1 +#define SK_PNMI_VPD_CUT 2 +#define SK_PNMI_VPD_TIMEOUT 3 +#define SK_PNMI_VPD_FULL 4 +#define SK_PNMI_VPD_NOWRITE 5 +#define SK_PNMI_VPD_FATAL 6 + +#define SK_PNMI_VPD_IGNORE 0 +#define SK_PNMI_VPD_CREATE 1 +#define SK_PNMI_VPD_DELETE 2 + + +/* + * RLMT related defines + */ +#define SK_PNMI_DEF_RLMT_CHG_THRES 240 /* 4 changes per minute */ + + +/* + * VCT internal status values + */ +#define SK_PNMI_VCT_PENDING 32 +#define SK_PNMI_VCT_TEST_DONE 64 +#define SK_PNMI_VCT_LINK 128 + +/* + * Internal table definitions + */ +#define SK_PNMI_GET 0 +#define SK_PNMI_PRESET 1 +#define SK_PNMI_SET 2 + +#define SK_PNMI_RO 0 +#define SK_PNMI_RW 1 +#define SK_PNMI_WO 2 + +typedef struct s_OidTabEntry { + SK_U32 Id; + SK_U32 InstanceNo; + unsigned int StructSize; + unsigned int Offset; + int Access; + int (* Func)(SK_AC *pAc, SK_IOC pIo, int action, + SK_U32 Id, char* pBuf, unsigned int* pLen, + SK_U32 Instance, unsigned int TableIndex, + SK_U32 NetNumber); + SK_U16 Param; +} SK_PNMI_TAB_ENTRY; + + +/* + * Trap lengths + */ +#define SK_PNMI_TRAP_SIMPLE_LEN 17 +#define SK_PNMI_TRAP_SENSOR_LEN_BASE 46 +#define SK_PNMI_TRAP_RLMT_CHANGE_LEN 23 +#define SK_PNMI_TRAP_RLMT_PORT_LEN 23 + +/* + * Number of MAC types supported + */ +#define SK_PNMI_MAC_TYPES (SK_MAC_GMAC + 1) + +/* + * MAC statistic data list (overall set for MAC types used) + */ +enum SK_MACSTATS { + SK_PNMI_HTX = 0, + SK_PNMI_HTX_OCTET, + SK_PNMI_HTX_OCTETHIGH = SK_PNMI_HTX_OCTET, + SK_PNMI_HTX_OCTETLOW, + SK_PNMI_HTX_BROADCAST, + SK_PNMI_HTX_MULTICAST, + SK_PNMI_HTX_UNICAST, + SK_PNMI_HTX_BURST, + SK_PNMI_HTX_PMACC, + SK_PNMI_HTX_MACC, + SK_PNMI_HTX_COL, + SK_PNMI_HTX_SINGLE_COL, + SK_PNMI_HTX_MULTI_COL, + SK_PNMI_HTX_EXCESS_COL, + SK_PNMI_HTX_LATE_COL, + SK_PNMI_HTX_DEFFERAL, + SK_PNMI_HTX_EXCESS_DEF, + SK_PNMI_HTX_UNDERRUN, + SK_PNMI_HTX_CARRIER, + SK_PNMI_HTX_UTILUNDER, + SK_PNMI_HTX_UTILOVER, + SK_PNMI_HTX_64, + SK_PNMI_HTX_127, + SK_PNMI_HTX_255, + SK_PNMI_HTX_511, + SK_PNMI_HTX_1023, + SK_PNMI_HTX_MAX, + SK_PNMI_HTX_LONGFRAMES, + SK_PNMI_HTX_SYNC, + SK_PNMI_HTX_SYNC_OCTET, + SK_PNMI_HTX_RESERVED, + + SK_PNMI_HRX, + SK_PNMI_HRX_OCTET, + SK_PNMI_HRX_OCTETHIGH = SK_PNMI_HRX_OCTET, + SK_PNMI_HRX_OCTETLOW, + SK_PNMI_HRX_BADOCTET, + SK_PNMI_HRX_BADOCTETHIGH = SK_PNMI_HRX_BADOCTET, + SK_PNMI_HRX_BADOCTETLOW, + SK_PNMI_HRX_BROADCAST, + SK_PNMI_HRX_MULTICAST, + SK_PNMI_HRX_UNICAST, + SK_PNMI_HRX_PMACC, + SK_PNMI_HRX_MACC, + SK_PNMI_HRX_PMACC_ERR, + SK_PNMI_HRX_MACC_UNKWN, + SK_PNMI_HRX_BURST, + SK_PNMI_HRX_MISSED, + SK_PNMI_HRX_FRAMING, + SK_PNMI_HRX_UNDERSIZE, + SK_PNMI_HRX_OVERFLOW, + SK_PNMI_HRX_JABBER, + SK_PNMI_HRX_CARRIER, + SK_PNMI_HRX_IRLENGTH, + SK_PNMI_HRX_SYMBOL, + SK_PNMI_HRX_SHORTS, + SK_PNMI_HRX_RUNT, + SK_PNMI_HRX_TOO_LONG, + SK_PNMI_HRX_FCS, + SK_PNMI_HRX_CEXT, + SK_PNMI_HRX_UTILUNDER, + SK_PNMI_HRX_UTILOVER, + SK_PNMI_HRX_64, + SK_PNMI_HRX_127, + SK_PNMI_HRX_255, + SK_PNMI_HRX_511, + SK_PNMI_HRX_1023, + SK_PNMI_HRX_MAX, + SK_PNMI_HRX_LONGFRAMES, + + SK_PNMI_HRX_RESERVED, + + SK_PNMI_MAX_IDX /* NOTE: Ensure SK_PNMI_CNT_NO is set to this value */ +}; + +/* + * MAC specific data + */ +typedef struct s_PnmiStatAddr { + SK_U16 Reg; /* MAC register containing the value */ + SK_BOOL GetOffset; /* TRUE: Offset managed by PNMI (call GetStatVal())*/ +} SK_PNMI_STATADDR; + + +/* + * SK_PNMI_STRUCT_DATA copy offset evaluation macros + */ +#define SK_PNMI_OFF(e) ((SK_U32)(SK_UPTR)&(((SK_PNMI_STRUCT_DATA *)0)->e)) +#define SK_PNMI_MAI_OFF(e) ((SK_U32)(SK_UPTR)&(((SK_PNMI_STRUCT_DATA *)0)->e)) +#define SK_PNMI_VPD_OFF(e) ((SK_U32)(SK_UPTR)&(((SK_PNMI_VPD *)0)->e)) +#define SK_PNMI_SEN_OFF(e) ((SK_U32)(SK_UPTR)&(((SK_PNMI_SENSOR *)0)->e)) +#define SK_PNMI_CHK_OFF(e) ((SK_U32)(SK_UPTR)&(((SK_PNMI_CHECKSUM *)0)->e)) +#define SK_PNMI_STA_OFF(e) ((SK_U32)(SK_UPTR)&(((SK_PNMI_STAT *)0)->e)) +#define SK_PNMI_CNF_OFF(e) ((SK_U32)(SK_UPTR)&(((SK_PNMI_CONF *)0)->e)) +#define SK_PNMI_RLM_OFF(e) ((SK_U32)(SK_UPTR)&(((SK_PNMI_RLMT *)0)->e)) +#define SK_PNMI_MON_OFF(e) ((SK_U32)(SK_UPTR)&(((SK_PNMI_RLMT_MONITOR *)0)->e)) +#define SK_PNMI_TRP_OFF(e) ((SK_U32)(SK_UPTR)&(((SK_PNMI_TRAP *)0)->e)) + +#define SK_PNMI_SET_STAT(b,s,o) {SK_U32 Val32; char *pVal; \ + Val32 = (s); \ + pVal = (char *)(b) + ((SK_U32)(SK_UPTR) \ + &(((SK_PNMI_STRUCT_DATA *)0)-> \ + ReturnStatus.ErrorStatus)); \ + SK_PNMI_STORE_U32(pVal, Val32); \ + Val32 = (o); \ + pVal = (char *)(b) + ((SK_U32)(SK_UPTR) \ + &(((SK_PNMI_STRUCT_DATA *)0)-> \ + ReturnStatus.ErrorOffset)); \ + SK_PNMI_STORE_U32(pVal, Val32);} + +/* + * Time macros + */ +#ifndef SK_PNMI_HUNDREDS_SEC +#if SK_TICKS_PER_SEC == 100 +#define SK_PNMI_HUNDREDS_SEC(t) (t) +#else +#define SK_PNMI_HUNDREDS_SEC(t) (((t) * 100) / (SK_TICKS_PER_SEC)) +#endif /* !SK_TICKS_PER_SEC */ +#endif /* !SK_PNMI_HUNDREDS_SEC */ + +/* + * Macros to work around alignment problems + */ +#ifndef SK_PNMI_STORE_U16 +#define SK_PNMI_STORE_U16(p,v) {*(char *)(p) = *((char *)&(v)); \ + *((char *)(p) + 1) = \ + *(((char *)&(v)) + 1);} +#endif + +#ifndef SK_PNMI_STORE_U32 +#define SK_PNMI_STORE_U32(p,v) {*(char *)(p) = *((char *)&(v)); \ + *((char *)(p) + 1) = \ + *(((char *)&(v)) + 1); \ + *((char *)(p) + 2) = \ + *(((char *)&(v)) + 2); \ + *((char *)(p) + 3) = \ + *(((char *)&(v)) + 3);} +#endif + +#ifndef SK_PNMI_STORE_U64 +#define SK_PNMI_STORE_U64(p,v) {*(char *)(p) = *((char *)&(v)); \ + *((char *)(p) + 1) = \ + *(((char *)&(v)) + 1); \ + *((char *)(p) + 2) = \ + *(((char *)&(v)) + 2); \ + *((char *)(p) + 3) = \ + *(((char *)&(v)) + 3); \ + *((char *)(p) + 4) = \ + *(((char *)&(v)) + 4); \ + *((char *)(p) + 5) = \ + *(((char *)&(v)) + 5); \ + *((char *)(p) + 6) = \ + *(((char *)&(v)) + 6); \ + *((char *)(p) + 7) = \ + *(((char *)&(v)) + 7);} +#endif + +#ifndef SK_PNMI_READ_U16 +#define SK_PNMI_READ_U16(p,v) {*((char *)&(v)) = *(char *)(p); \ + *(((char *)&(v)) + 1) = \ + *((char *)(p) + 1);} +#endif + +#ifndef SK_PNMI_READ_U32 +#define SK_PNMI_READ_U32(p,v) {*((char *)&(v)) = *(char *)(p); \ + *(((char *)&(v)) + 1) = \ + *((char *)(p) + 1); \ + *(((char *)&(v)) + 2) = \ + *((char *)(p) + 2); \ + *(((char *)&(v)) + 3) = \ + *((char *)(p) + 3);} +#endif + +#ifndef SK_PNMI_READ_U64 +#define SK_PNMI_READ_U64(p,v) {*((char *)&(v)) = *(char *)(p); \ + *(((char *)&(v)) + 1) = \ + *((char *)(p) + 1); \ + *(((char *)&(v)) + 2) = \ + *((char *)(p) + 2); \ + *(((char *)&(v)) + 3) = \ + *((char *)(p) + 3); \ + *(((char *)&(v)) + 4) = \ + *((char *)(p) + 4); \ + *(((char *)&(v)) + 5) = \ + *((char *)(p) + 5); \ + *(((char *)&(v)) + 6) = \ + *((char *)(p) + 6); \ + *(((char *)&(v)) + 7) = \ + *((char *)(p) + 7);} +#endif + +/* + * Macros for Debug + */ +#ifdef DEBUG + +#define SK_PNMI_CHECKFLAGS(vSt) {if (pAC->Pnmi.MacUpdatedFlag > 0 || \ + pAC->Pnmi.RlmtUpdatedFlag > 0 || \ + pAC->Pnmi.SirqUpdatedFlag > 0) { \ + SK_DBG_MSG(pAC, \ + SK_DBGMOD_PNMI, \ + SK_DBGCAT_CTRL, \ + ("PNMI: ERR: %s MacUFlag=%d, RlmtUFlag=%d, SirqUFlag=%d\n", \ + vSt, \ + pAC->Pnmi.MacUpdatedFlag, \ + pAC->Pnmi.RlmtUpdatedFlag, \ + pAC->Pnmi.SirqUpdatedFlag))}} + +#else /* !DEBUG */ + +#define SK_PNMI_CHECKFLAGS(vSt) /* Nothing */ + +#endif /* !DEBUG */ + +#endif /* _SKGEPNM2_H_ */ diff --git a/drivers/net/sk98lin/h/skgepnmi.h b/drivers/net/sk98lin/h/skgepnmi.h new file mode 100644 index 000000000000..1ed214ccb253 --- /dev/null +++ b/drivers/net/sk98lin/h/skgepnmi.h @@ -0,0 +1,962 @@ +/***************************************************************************** + * + * Name: skgepnmi.h + * Project: GEnesis, PCI Gigabit Ethernet Adapter + * Version: $Revision: 1.62 $ + * Date: $Date: 2003/08/15 12:31:52 $ + * Purpose: Defines for Private Network Management Interface + * + ****************************************************************************/ + +/****************************************************************************** + * + * (C)Copyright 1998-2002 SysKonnect GmbH. + * (C)Copyright 2002-2003 Marvell. + * + * 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. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +#ifndef _SKGEPNMI_H_ +#define _SKGEPNMI_H_ + +/* + * Include dependencies + */ +#include "h/sktypes.h" +#include "h/skerror.h" +#include "h/sktimer.h" +#include "h/ski2c.h" +#include "h/skaddr.h" +#include "h/skrlmt.h" +#include "h/skvpd.h" + +/* + * Management Database Version + */ +#define SK_PNMI_MDB_VERSION 0x00030001 /* 3.1 */ + + +/* + * Event definitions + */ +#define SK_PNMI_EVT_SIRQ_OVERFLOW 1 /* Counter overflow */ +#define SK_PNMI_EVT_SEN_WAR_LOW 2 /* Lower war thres exceeded */ +#define SK_PNMI_EVT_SEN_WAR_UPP 3 /* Upper war thres exceeded */ +#define SK_PNMI_EVT_SEN_ERR_LOW 4 /* Lower err thres exceeded */ +#define SK_PNMI_EVT_SEN_ERR_UPP 5 /* Upper err thres exceeded */ +#define SK_PNMI_EVT_CHG_EST_TIMER 6 /* Timer event for RLMT Chg */ +#define SK_PNMI_EVT_UTILIZATION_TIMER 7 /* Timer event for Utiliza. */ +#define SK_PNMI_EVT_CLEAR_COUNTER 8 /* Clear statistic counters */ +#define SK_PNMI_EVT_XMAC_RESET 9 /* XMAC will be reset */ + +#define SK_PNMI_EVT_RLMT_PORT_UP 10 /* Port came logically up */ +#define SK_PNMI_EVT_RLMT_PORT_DOWN 11 /* Port went logically down */ +#define SK_PNMI_EVT_RLMT_SEGMENTATION 13 /* Two SP root bridges found */ +#define SK_PNMI_EVT_RLMT_ACTIVE_DOWN 14 /* Port went logically down */ +#define SK_PNMI_EVT_RLMT_ACTIVE_UP 15 /* Port came logically up */ +#define SK_PNMI_EVT_RLMT_SET_NETS 16 /* 1. Parameter is number of nets + 1 = single net; 2 = dual net */ +#define SK_PNMI_EVT_VCT_RESET 17 /* VCT port reset timer event started with SET. */ + + +/* + * Return values + */ +#define SK_PNMI_ERR_OK 0 +#define SK_PNMI_ERR_GENERAL 1 +#define SK_PNMI_ERR_TOO_SHORT 2 +#define SK_PNMI_ERR_BAD_VALUE 3 +#define SK_PNMI_ERR_READ_ONLY 4 +#define SK_PNMI_ERR_UNKNOWN_OID 5 +#define SK_PNMI_ERR_UNKNOWN_INST 6 +#define SK_PNMI_ERR_UNKNOWN_NET 7 +#define SK_PNMI_ERR_NOT_SUPPORTED 10 + + +/* + * Return values of driver reset function SK_DRIVER_RESET() and + * driver event function SK_DRIVER_EVENT() + */ +#define SK_PNMI_ERR_OK 0 +#define SK_PNMI_ERR_FAIL 1 + + +/* + * Return values of driver test function SK_DRIVER_SELFTEST() + */ +#define SK_PNMI_TST_UNKNOWN (1 << 0) +#define SK_PNMI_TST_TRANCEIVER (1 << 1) +#define SK_PNMI_TST_ASIC (1 << 2) +#define SK_PNMI_TST_SENSOR (1 << 3) +#define SK_PNMI_TST_POWERMGMT (1 << 4) +#define SK_PNMI_TST_PCI (1 << 5) +#define SK_PNMI_TST_MAC (1 << 6) + + +/* + * RLMT specific definitions + */ +#define SK_PNMI_RLMT_STATUS_STANDBY 1 +#define SK_PNMI_RLMT_STATUS_ACTIVE 2 +#define SK_PNMI_RLMT_STATUS_ERROR 3 + +#define SK_PNMI_RLMT_LSTAT_PHY_DOWN 1 +#define SK_PNMI_RLMT_LSTAT_AUTONEG 2 +#define SK_PNMI_RLMT_LSTAT_LOG_DOWN 3 +#define SK_PNMI_RLMT_LSTAT_LOG_UP 4 +#define SK_PNMI_RLMT_LSTAT_INDETERMINATED 5 + +#define SK_PNMI_RLMT_MODE_CHK_LINK (SK_RLMT_CHECK_LINK) +#define SK_PNMI_RLMT_MODE_CHK_RX (SK_RLMT_CHECK_LOC_LINK) +#define SK_PNMI_RLMT_MODE_CHK_SPT (SK_RLMT_CHECK_SEG) +/* #define SK_PNMI_RLMT_MODE_CHK_EX */ + +/* + * OID definition + */ +#ifndef _NDIS_ /* Check, whether NDIS already included OIDs */ + +#define OID_GEN_XMIT_OK 0x00020101 +#define OID_GEN_RCV_OK 0x00020102 +#define OID_GEN_XMIT_ERROR 0x00020103 +#define OID_GEN_RCV_ERROR 0x00020104 +#define OID_GEN_RCV_NO_BUFFER 0x00020105 + +/* #define OID_GEN_DIRECTED_BYTES_XMIT 0x00020201 */ +#define OID_GEN_DIRECTED_FRAMES_XMIT 0x00020202 +/* #define OID_GEN_MULTICAST_BYTES_XMIT 0x00020203 */ +#define OID_GEN_MULTICAST_FRAMES_XMIT 0x00020204 +/* #define OID_GEN_BROADCAST_BYTES_XMIT 0x00020205 */ +#define OID_GEN_BROADCAST_FRAMES_XMIT 0x00020206 +/* #define OID_GEN_DIRECTED_BYTES_RCV 0x00020207 */ +#define OID_GEN_DIRECTED_FRAMES_RCV 0x00020208 +/* #define OID_GEN_MULTICAST_BYTES_RCV 0x00020209 */ +#define OID_GEN_MULTICAST_FRAMES_RCV 0x0002020A +/* #define OID_GEN_BROADCAST_BYTES_RCV 0x0002020B */ +#define OID_GEN_BROADCAST_FRAMES_RCV 0x0002020C +#define OID_GEN_RCV_CRC_ERROR 0x0002020D +#define OID_GEN_TRANSMIT_QUEUE_LENGTH 0x0002020E + +#define OID_802_3_PERMANENT_ADDRESS 0x01010101 +#define OID_802_3_CURRENT_ADDRESS 0x01010102 +/* #define OID_802_3_MULTICAST_LIST 0x01010103 */ +/* #define OID_802_3_MAXIMUM_LIST_SIZE 0x01010104 */ +/* #define OID_802_3_MAC_OPTIONS 0x01010105 */ + +#define OID_802_3_RCV_ERROR_ALIGNMENT 0x01020101 +#define OID_802_3_XMIT_ONE_COLLISION 0x01020102 +#define OID_802_3_XMIT_MORE_COLLISIONS 0x01020103 +#define OID_802_3_XMIT_DEFERRED 0x01020201 +#define OID_802_3_XMIT_MAX_COLLISIONS 0x01020202 +#define OID_802_3_RCV_OVERRUN 0x01020203 +#define OID_802_3_XMIT_UNDERRUN 0x01020204 +#define OID_802_3_XMIT_TIMES_CRS_LOST 0x01020206 +#define OID_802_3_XMIT_LATE_COLLISIONS 0x01020207 + +/* + * PnP and PM OIDs + */ +#ifdef SK_POWER_MGMT +#define OID_PNP_CAPABILITIES 0xFD010100 +#define OID_PNP_SET_POWER 0xFD010101 +#define OID_PNP_QUERY_POWER 0xFD010102 +#define OID_PNP_ADD_WAKE_UP_PATTERN 0xFD010103 +#define OID_PNP_REMOVE_WAKE_UP_PATTERN 0xFD010104 +#define OID_PNP_ENABLE_WAKE_UP 0xFD010106 +#endif /* SK_POWER_MGMT */ + +#endif /* _NDIS_ */ + +#define OID_SKGE_MDB_VERSION 0xFF010100 +#define OID_SKGE_SUPPORTED_LIST 0xFF010101 +#define OID_SKGE_VPD_FREE_BYTES 0xFF010102 +#define OID_SKGE_VPD_ENTRIES_LIST 0xFF010103 +#define OID_SKGE_VPD_ENTRIES_NUMBER 0xFF010104 +#define OID_SKGE_VPD_KEY 0xFF010105 +#define OID_SKGE_VPD_VALUE 0xFF010106 +#define OID_SKGE_VPD_ACCESS 0xFF010107 +#define OID_SKGE_VPD_ACTION 0xFF010108 + +#define OID_SKGE_PORT_NUMBER 0xFF010110 +#define OID_SKGE_DEVICE_TYPE 0xFF010111 +#define OID_SKGE_DRIVER_DESCR 0xFF010112 +#define OID_SKGE_DRIVER_VERSION 0xFF010113 +#define OID_SKGE_HW_DESCR 0xFF010114 +#define OID_SKGE_HW_VERSION 0xFF010115 +#define OID_SKGE_CHIPSET 0xFF010116 +#define OID_SKGE_ACTION 0xFF010117 +#define OID_SKGE_RESULT 0xFF010118 +#define OID_SKGE_BUS_TYPE 0xFF010119 +#define OID_SKGE_BUS_SPEED 0xFF01011A +#define OID_SKGE_BUS_WIDTH 0xFF01011B +/* 0xFF01011C unused */ +#define OID_SKGE_DIAG_ACTION 0xFF01011D +#define OID_SKGE_DIAG_RESULT 0xFF01011E +#define OID_SKGE_MTU 0xFF01011F +#define OID_SKGE_PHYS_CUR_ADDR 0xFF010120 +#define OID_SKGE_PHYS_FAC_ADDR 0xFF010121 +#define OID_SKGE_PMD 0xFF010122 +#define OID_SKGE_CONNECTOR 0xFF010123 +#define OID_SKGE_LINK_CAP 0xFF010124 +#define OID_SKGE_LINK_MODE 0xFF010125 +#define OID_SKGE_LINK_MODE_STATUS 0xFF010126 +#define OID_SKGE_LINK_STATUS 0xFF010127 +#define OID_SKGE_FLOWCTRL_CAP 0xFF010128 +#define OID_SKGE_FLOWCTRL_MODE 0xFF010129 +#define OID_SKGE_FLOWCTRL_STATUS 0xFF01012A +#define OID_SKGE_PHY_OPERATION_CAP 0xFF01012B +#define OID_SKGE_PHY_OPERATION_MODE 0xFF01012C +#define OID_SKGE_PHY_OPERATION_STATUS 0xFF01012D +#define OID_SKGE_MULTICAST_LIST 0xFF01012E +#define OID_SKGE_CURRENT_PACKET_FILTER 0xFF01012F + +#define OID_SKGE_TRAP 0xFF010130 +#define OID_SKGE_TRAP_NUMBER 0xFF010131 + +#define OID_SKGE_RLMT_MODE 0xFF010140 +#define OID_SKGE_RLMT_PORT_NUMBER 0xFF010141 +#define OID_SKGE_RLMT_PORT_ACTIVE 0xFF010142 +#define OID_SKGE_RLMT_PORT_PREFERRED 0xFF010143 +#define OID_SKGE_INTERMEDIATE_SUPPORT 0xFF010160 + +#define OID_SKGE_SPEED_CAP 0xFF010170 +#define OID_SKGE_SPEED_MODE 0xFF010171 +#define OID_SKGE_SPEED_STATUS 0xFF010172 + +#define OID_SKGE_BOARDLEVEL 0xFF010180 + +#define OID_SKGE_SENSOR_NUMBER 0xFF020100 +#define OID_SKGE_SENSOR_INDEX 0xFF020101 +#define OID_SKGE_SENSOR_DESCR 0xFF020102 +#define OID_SKGE_SENSOR_TYPE 0xFF020103 +#define OID_SKGE_SENSOR_VALUE 0xFF020104 +#define OID_SKGE_SENSOR_WAR_THRES_LOW 0xFF020105 +#define OID_SKGE_SENSOR_WAR_THRES_UPP 0xFF020106 +#define OID_SKGE_SENSOR_ERR_THRES_LOW 0xFF020107 +#define OID_SKGE_SENSOR_ERR_THRES_UPP 0xFF020108 +#define OID_SKGE_SENSOR_STATUS 0xFF020109 +#define OID_SKGE_SENSOR_WAR_CTS 0xFF02010A +#define OID_SKGE_SENSOR_ERR_CTS 0xFF02010B +#define OID_SKGE_SENSOR_WAR_TIME 0xFF02010C +#define OID_SKGE_SENSOR_ERR_TIME 0xFF02010D + +#define OID_SKGE_CHKSM_NUMBER 0xFF020110 +#define OID_SKGE_CHKSM_RX_OK_CTS 0xFF020111 +#define OID_SKGE_CHKSM_RX_UNABLE_CTS 0xFF020112 +#define OID_SKGE_CHKSM_RX_ERR_CTS 0xFF020113 +#define OID_SKGE_CHKSM_TX_OK_CTS 0xFF020114 +#define OID_SKGE_CHKSM_TX_UNABLE_CTS 0xFF020115 + +#define OID_SKGE_STAT_TX 0xFF020120 +#define OID_SKGE_STAT_TX_OCTETS 0xFF020121 +#define OID_SKGE_STAT_TX_BROADCAST 0xFF020122 +#define OID_SKGE_STAT_TX_MULTICAST 0xFF020123 +#define OID_SKGE_STAT_TX_UNICAST 0xFF020124 +#define OID_SKGE_STAT_TX_LONGFRAMES 0xFF020125 +#define OID_SKGE_STAT_TX_BURST 0xFF020126 +#define OID_SKGE_STAT_TX_PFLOWC 0xFF020127 +#define OID_SKGE_STAT_TX_FLOWC 0xFF020128 +#define OID_SKGE_STAT_TX_SINGLE_COL 0xFF020129 +#define OID_SKGE_STAT_TX_MULTI_COL 0xFF02012A +#define OID_SKGE_STAT_TX_EXCESS_COL 0xFF02012B +#define OID_SKGE_STAT_TX_LATE_COL 0xFF02012C +#define OID_SKGE_STAT_TX_DEFFERAL 0xFF02012D +#define OID_SKGE_STAT_TX_EXCESS_DEF 0xFF02012E +#define OID_SKGE_STAT_TX_UNDERRUN 0xFF02012F +#define OID_SKGE_STAT_TX_CARRIER 0xFF020130 +/* #define OID_SKGE_STAT_TX_UTIL 0xFF020131 */ +#define OID_SKGE_STAT_TX_64 0xFF020132 +#define OID_SKGE_STAT_TX_127 0xFF020133 +#define OID_SKGE_STAT_TX_255 0xFF020134 +#define OID_SKGE_STAT_TX_511 0xFF020135 +#define OID_SKGE_STAT_TX_1023 0xFF020136 +#define OID_SKGE_STAT_TX_MAX 0xFF020137 +#define OID_SKGE_STAT_TX_SYNC 0xFF020138 +#define OID_SKGE_STAT_TX_SYNC_OCTETS 0xFF020139 +#define OID_SKGE_STAT_RX 0xFF02013A +#define OID_SKGE_STAT_RX_OCTETS 0xFF02013B +#define OID_SKGE_STAT_RX_BROADCAST 0xFF02013C +#define OID_SKGE_STAT_RX_MULTICAST 0xFF02013D +#define OID_SKGE_STAT_RX_UNICAST 0xFF02013E +#define OID_SKGE_STAT_RX_PFLOWC 0xFF02013F +#define OID_SKGE_STAT_RX_FLOWC 0xFF020140 +#define OID_SKGE_STAT_RX_PFLOWC_ERR 0xFF020141 +#define OID_SKGE_STAT_RX_FLOWC_UNKWN 0xFF020142 +#define OID_SKGE_STAT_RX_BURST 0xFF020143 +#define OID_SKGE_STAT_RX_MISSED 0xFF020144 +#define OID_SKGE_STAT_RX_FRAMING 0xFF020145 +#define OID_SKGE_STAT_RX_OVERFLOW 0xFF020146 +#define OID_SKGE_STAT_RX_JABBER 0xFF020147 +#define OID_SKGE_STAT_RX_CARRIER 0xFF020148 +#define OID_SKGE_STAT_RX_IR_LENGTH 0xFF020149 +#define OID_SKGE_STAT_RX_SYMBOL 0xFF02014A +#define OID_SKGE_STAT_RX_SHORTS 0xFF02014B +#define OID_SKGE_STAT_RX_RUNT 0xFF02014C +#define OID_SKGE_STAT_RX_CEXT 0xFF02014D +#define OID_SKGE_STAT_RX_TOO_LONG 0xFF02014E +#define OID_SKGE_STAT_RX_FCS 0xFF02014F +/* #define OID_SKGE_STAT_RX_UTIL 0xFF020150 */ +#define OID_SKGE_STAT_RX_64 0xFF020151 +#define OID_SKGE_STAT_RX_127 0xFF020152 +#define OID_SKGE_STAT_RX_255 0xFF020153 +#define OID_SKGE_STAT_RX_511 0xFF020154 +#define OID_SKGE_STAT_RX_1023 0xFF020155 +#define OID_SKGE_STAT_RX_MAX 0xFF020156 +#define OID_SKGE_STAT_RX_LONGFRAMES 0xFF020157 + +#define OID_SKGE_RLMT_CHANGE_CTS 0xFF020160 +#define OID_SKGE_RLMT_CHANGE_TIME 0xFF020161 +#define OID_SKGE_RLMT_CHANGE_ESTIM 0xFF020162 +#define OID_SKGE_RLMT_CHANGE_THRES 0xFF020163 + +#define OID_SKGE_RLMT_PORT_INDEX 0xFF020164 +#define OID_SKGE_RLMT_STATUS 0xFF020165 +#define OID_SKGE_RLMT_TX_HELLO_CTS 0xFF020166 +#define OID_SKGE_RLMT_RX_HELLO_CTS 0xFF020167 +#define OID_SKGE_RLMT_TX_SP_REQ_CTS 0xFF020168 +#define OID_SKGE_RLMT_RX_SP_CTS 0xFF020169 + +#define OID_SKGE_RLMT_MONITOR_NUMBER 0xFF010150 +#define OID_SKGE_RLMT_MONITOR_INDEX 0xFF010151 +#define OID_SKGE_RLMT_MONITOR_ADDR 0xFF010152 +#define OID_SKGE_RLMT_MONITOR_ERRS 0xFF010153 +#define OID_SKGE_RLMT_MONITOR_TIMESTAMP 0xFF010154 +#define OID_SKGE_RLMT_MONITOR_ADMIN 0xFF010155 + +#define OID_SKGE_TX_SW_QUEUE_LEN 0xFF020170 +#define OID_SKGE_TX_SW_QUEUE_MAX 0xFF020171 +#define OID_SKGE_TX_RETRY 0xFF020172 +#define OID_SKGE_RX_INTR_CTS 0xFF020173 +#define OID_SKGE_TX_INTR_CTS 0xFF020174 +#define OID_SKGE_RX_NO_BUF_CTS 0xFF020175 +#define OID_SKGE_TX_NO_BUF_CTS 0xFF020176 +#define OID_SKGE_TX_USED_DESCR_NO 0xFF020177 +#define OID_SKGE_RX_DELIVERED_CTS 0xFF020178 +#define OID_SKGE_RX_OCTETS_DELIV_CTS 0xFF020179 +#define OID_SKGE_RX_HW_ERROR_CTS 0xFF02017A +#define OID_SKGE_TX_HW_ERROR_CTS 0xFF02017B +#define OID_SKGE_IN_ERRORS_CTS 0xFF02017C +#define OID_SKGE_OUT_ERROR_CTS 0xFF02017D +#define OID_SKGE_ERR_RECOVERY_CTS 0xFF02017E +#define OID_SKGE_SYSUPTIME 0xFF02017F + +#define OID_SKGE_ALL_DATA 0xFF020190 + +/* Defines for VCT. */ +#define OID_SKGE_VCT_GET 0xFF020200 +#define OID_SKGE_VCT_SET 0xFF020201 +#define OID_SKGE_VCT_STATUS 0xFF020202 + +#ifdef SK_DIAG_SUPPORT +/* Defines for driver DIAG mode. */ +#define OID_SKGE_DIAG_MODE 0xFF020204 +#endif /* SK_DIAG_SUPPORT */ + +/* New OIDs */ +#define OID_SKGE_DRIVER_RELDATE 0xFF020210 +#define OID_SKGE_DRIVER_FILENAME 0xFF020211 +#define OID_SKGE_CHIPID 0xFF020212 +#define OID_SKGE_RAMSIZE 0xFF020213 +#define OID_SKGE_VAUXAVAIL 0xFF020214 +#define OID_SKGE_PHY_TYPE 0xFF020215 +#define OID_SKGE_PHY_LP_MODE 0xFF020216 + +/* VCT struct to store a backup copy of VCT data after a port reset. */ +typedef struct s_PnmiVct { + SK_U8 VctStatus; + SK_U8 PCableLen; + SK_U32 PMdiPairLen[4]; + SK_U8 PMdiPairSts[4]; +} SK_PNMI_VCT; + + +/* VCT status values (to be given to CPA via OID_SKGE_VCT_STATUS). */ +#define SK_PNMI_VCT_NONE 0 +#define SK_PNMI_VCT_OLD_VCT_DATA 1 +#define SK_PNMI_VCT_NEW_VCT_DATA 2 +#define SK_PNMI_VCT_OLD_DSP_DATA 4 +#define SK_PNMI_VCT_NEW_DSP_DATA 8 +#define SK_PNMI_VCT_RUNNING 16 + + +/* VCT cable test status. */ +#define SK_PNMI_VCT_NORMAL_CABLE 0 +#define SK_PNMI_VCT_SHORT_CABLE 1 +#define SK_PNMI_VCT_OPEN_CABLE 2 +#define SK_PNMI_VCT_TEST_FAIL 3 +#define SK_PNMI_VCT_IMPEDANCE_MISMATCH 4 + +#define OID_SKGE_TRAP_SEN_WAR_LOW 500 +#define OID_SKGE_TRAP_SEN_WAR_UPP 501 +#define OID_SKGE_TRAP_SEN_ERR_LOW 502 +#define OID_SKGE_TRAP_SEN_ERR_UPP 503 +#define OID_SKGE_TRAP_RLMT_CHANGE_THRES 520 +#define OID_SKGE_TRAP_RLMT_CHANGE_PORT 521 +#define OID_SKGE_TRAP_RLMT_PORT_DOWN 522 +#define OID_SKGE_TRAP_RLMT_PORT_UP 523 +#define OID_SKGE_TRAP_RLMT_SEGMENTATION 524 + +#ifdef SK_DIAG_SUPPORT +/* Defines for driver DIAG mode. */ +#define SK_DIAG_ATTACHED 2 +#define SK_DIAG_RUNNING 1 +#define SK_DIAG_IDLE 0 +#endif /* SK_DIAG_SUPPORT */ + +/* + * Generic PNMI IOCTL subcommand definitions. + */ +#define SK_GET_SINGLE_VAR 1 +#define SK_SET_SINGLE_VAR 2 +#define SK_PRESET_SINGLE_VAR 3 +#define SK_GET_FULL_MIB 4 +#define SK_SET_FULL_MIB 5 +#define SK_PRESET_FULL_MIB 6 + + +/* + * Define error numbers and messages for syslog + */ +#define SK_PNMI_ERR001 (SK_ERRBASE_PNMI + 1) +#define SK_PNMI_ERR001MSG "SkPnmiGetStruct: Unknown OID" +#define SK_PNMI_ERR002 (SK_ERRBASE_PNMI + 2) +#define SK_PNMI_ERR002MSG "SkPnmiGetStruct: Cannot read VPD keys" +#define SK_PNMI_ERR003 (SK_ERRBASE_PNMI + 3) +#define SK_PNMI_ERR003MSG "OidStruct: Called with wrong OID" +#define SK_PNMI_ERR004 (SK_ERRBASE_PNMI + 4) +#define SK_PNMI_ERR004MSG "OidStruct: Called with wrong action" +#define SK_PNMI_ERR005 (SK_ERRBASE_PNMI + 5) +#define SK_PNMI_ERR005MSG "Perform: Cannot reset driver" +#define SK_PNMI_ERR006 (SK_ERRBASE_PNMI + 6) +#define SK_PNMI_ERR006MSG "Perform: Unknown OID action command" +#define SK_PNMI_ERR007 (SK_ERRBASE_PNMI + 7) +#define SK_PNMI_ERR007MSG "General: Driver description not initialized" +#define SK_PNMI_ERR008 (SK_ERRBASE_PNMI + 8) +#define SK_PNMI_ERR008MSG "Addr: Tried to get unknown OID" +#define SK_PNMI_ERR009 (SK_ERRBASE_PNMI + 9) +#define SK_PNMI_ERR009MSG "Addr: Unknown OID" +#define SK_PNMI_ERR010 (SK_ERRBASE_PNMI + 10) +#define SK_PNMI_ERR010MSG "CsumStat: Unknown OID" +#define SK_PNMI_ERR011 (SK_ERRBASE_PNMI + 11) +#define SK_PNMI_ERR011MSG "SensorStat: Sensor descr string too long" +#define SK_PNMI_ERR012 (SK_ERRBASE_PNMI + 12) +#define SK_PNMI_ERR012MSG "SensorStat: Unknown OID" +#define SK_PNMI_ERR013 (SK_ERRBASE_PNMI + 13) +#define SK_PNMI_ERR013MSG "" +#define SK_PNMI_ERR014 (SK_ERRBASE_PNMI + 14) +#define SK_PNMI_ERR014MSG "Vpd: Cannot read VPD keys" +#define SK_PNMI_ERR015 (SK_ERRBASE_PNMI + 15) +#define SK_PNMI_ERR015MSG "Vpd: Internal array for VPD keys to small" +#define SK_PNMI_ERR016 (SK_ERRBASE_PNMI + 16) +#define SK_PNMI_ERR016MSG "Vpd: Key string too long" +#define SK_PNMI_ERR017 (SK_ERRBASE_PNMI + 17) +#define SK_PNMI_ERR017MSG "Vpd: Invalid VPD status pointer" +#define SK_PNMI_ERR018 (SK_ERRBASE_PNMI + 18) +#define SK_PNMI_ERR018MSG "Vpd: VPD data not valid" +#define SK_PNMI_ERR019 (SK_ERRBASE_PNMI + 19) +#define SK_PNMI_ERR019MSG "Vpd: VPD entries list string too long" +#define SK_PNMI_ERR021 (SK_ERRBASE_PNMI + 21) +#define SK_PNMI_ERR021MSG "Vpd: VPD data string too long" +#define SK_PNMI_ERR022 (SK_ERRBASE_PNMI + 22) +#define SK_PNMI_ERR022MSG "Vpd: VPD data string too long should be errored before" +#define SK_PNMI_ERR023 (SK_ERRBASE_PNMI + 23) +#define SK_PNMI_ERR023MSG "Vpd: Unknown OID in get action" +#define SK_PNMI_ERR024 (SK_ERRBASE_PNMI + 24) +#define SK_PNMI_ERR024MSG "Vpd: Unknown OID in preset/set action" +#define SK_PNMI_ERR025 (SK_ERRBASE_PNMI + 25) +#define SK_PNMI_ERR025MSG "Vpd: Cannot write VPD after modify entry" +#define SK_PNMI_ERR026 (SK_ERRBASE_PNMI + 26) +#define SK_PNMI_ERR026MSG "Vpd: Cannot update VPD" +#define SK_PNMI_ERR027 (SK_ERRBASE_PNMI + 27) +#define SK_PNMI_ERR027MSG "Vpd: Cannot delete VPD entry" +#define SK_PNMI_ERR028 (SK_ERRBASE_PNMI + 28) +#define SK_PNMI_ERR028MSG "Vpd: Cannot update VPD after delete entry" +#define SK_PNMI_ERR029 (SK_ERRBASE_PNMI + 29) +#define SK_PNMI_ERR029MSG "General: Driver description string too long" +#define SK_PNMI_ERR030 (SK_ERRBASE_PNMI + 30) +#define SK_PNMI_ERR030MSG "General: Driver version not initialized" +#define SK_PNMI_ERR031 (SK_ERRBASE_PNMI + 31) +#define SK_PNMI_ERR031MSG "General: Driver version string too long" +#define SK_PNMI_ERR032 (SK_ERRBASE_PNMI + 32) +#define SK_PNMI_ERR032MSG "General: Cannot read VPD Name for HW descr" +#define SK_PNMI_ERR033 (SK_ERRBASE_PNMI + 33) +#define SK_PNMI_ERR033MSG "General: HW description string too long" +#define SK_PNMI_ERR034 (SK_ERRBASE_PNMI + 34) +#define SK_PNMI_ERR034MSG "General: Unknown OID" +#define SK_PNMI_ERR035 (SK_ERRBASE_PNMI + 35) +#define SK_PNMI_ERR035MSG "Rlmt: Unknown OID" +#define SK_PNMI_ERR036 (SK_ERRBASE_PNMI + 36) +#define SK_PNMI_ERR036MSG "" +#define SK_PNMI_ERR037 (SK_ERRBASE_PNMI + 37) +#define SK_PNMI_ERR037MSG "Rlmt: SK_RLMT_MODE_CHANGE event return not 0" +#define SK_PNMI_ERR038 (SK_ERRBASE_PNMI + 38) +#define SK_PNMI_ERR038MSG "Rlmt: SK_RLMT_PREFPORT_CHANGE event return not 0" +#define SK_PNMI_ERR039 (SK_ERRBASE_PNMI + 39) +#define SK_PNMI_ERR039MSG "RlmtStat: Unknown OID" +#define SK_PNMI_ERR040 (SK_ERRBASE_PNMI + 40) +#define SK_PNMI_ERR040MSG "PowerManagement: Unknown OID" +#define SK_PNMI_ERR041 (SK_ERRBASE_PNMI + 41) +#define SK_PNMI_ERR041MSG "MacPrivateConf: Unknown OID" +#define SK_PNMI_ERR042 (SK_ERRBASE_PNMI + 42) +#define SK_PNMI_ERR042MSG "MacPrivateConf: SK_HWEV_SET_ROLE returned not 0" +#define SK_PNMI_ERR043 (SK_ERRBASE_PNMI + 43) +#define SK_PNMI_ERR043MSG "MacPrivateConf: SK_HWEV_SET_LMODE returned not 0" +#define SK_PNMI_ERR044 (SK_ERRBASE_PNMI + 44) +#define SK_PNMI_ERR044MSG "MacPrivateConf: SK_HWEV_SET_FLOWMODE returned not 0" +#define SK_PNMI_ERR045 (SK_ERRBASE_PNMI + 45) +#define SK_PNMI_ERR045MSG "MacPrivateConf: SK_HWEV_SET_SPEED returned not 0" +#define SK_PNMI_ERR046 (SK_ERRBASE_PNMI + 46) +#define SK_PNMI_ERR046MSG "Monitor: Unknown OID" +#define SK_PNMI_ERR047 (SK_ERRBASE_PNMI + 47) +#define SK_PNMI_ERR047MSG "SirqUpdate: Event function returns not 0" +#define SK_PNMI_ERR048 (SK_ERRBASE_PNMI + 48) +#define SK_PNMI_ERR048MSG "RlmtUpdate: Event function returns not 0" +#define SK_PNMI_ERR049 (SK_ERRBASE_PNMI + 49) +#define SK_PNMI_ERR049MSG "SkPnmiInit: Invalid size of 'CounterOffset' struct!!" +#define SK_PNMI_ERR050 (SK_ERRBASE_PNMI + 50) +#define SK_PNMI_ERR050MSG "SkPnmiInit: Invalid size of 'StatAddr' table!!" +#define SK_PNMI_ERR051 (SK_ERRBASE_PNMI + 51) +#define SK_PNMI_ERR051MSG "SkPnmiEvent: Port switch suspicious" +#define SK_PNMI_ERR052 (SK_ERRBASE_PNMI + 52) +#define SK_PNMI_ERR052MSG "" +#define SK_PNMI_ERR053 (SK_ERRBASE_PNMI + 53) +#define SK_PNMI_ERR053MSG "General: Driver release date not initialized" +#define SK_PNMI_ERR054 (SK_ERRBASE_PNMI + 54) +#define SK_PNMI_ERR054MSG "General: Driver release date string too long" +#define SK_PNMI_ERR055 (SK_ERRBASE_PNMI + 55) +#define SK_PNMI_ERR055MSG "General: Driver file name not initialized" +#define SK_PNMI_ERR056 (SK_ERRBASE_PNMI + 56) +#define SK_PNMI_ERR056MSG "General: Driver file name string too long" + +/* + * Management counter macros called by the driver + */ +#define SK_PNMI_SET_DRIVER_DESCR(pAC,v) ((pAC)->Pnmi.pDriverDescription = \ + (char *)(v)) + +#define SK_PNMI_SET_DRIVER_VER(pAC,v) ((pAC)->Pnmi.pDriverVersion = \ + (char *)(v)) + +#define SK_PNMI_SET_DRIVER_RELDATE(pAC,v) ((pAC)->Pnmi.pDriverReleaseDate = \ + (char *)(v)) + +#define SK_PNMI_SET_DRIVER_FILENAME(pAC,v) ((pAC)->Pnmi.pDriverFileName = \ + (char *)(v)) + +#define SK_PNMI_CNT_TX_QUEUE_LEN(pAC,v,p) \ + { \ + (pAC)->Pnmi.Port[p].TxSwQueueLen = (SK_U64)(v); \ + if ((pAC)->Pnmi.Port[p].TxSwQueueLen > (pAC)->Pnmi.Port[p].TxSwQueueMax) { \ + (pAC)->Pnmi.Port[p].TxSwQueueMax = (pAC)->Pnmi.Port[p].TxSwQueueLen; \ + } \ + } +#define SK_PNMI_CNT_TX_RETRY(pAC,p) (((pAC)->Pnmi.Port[p].TxRetryCts)++) +#define SK_PNMI_CNT_RX_INTR(pAC,p) (((pAC)->Pnmi.Port[p].RxIntrCts)++) +#define SK_PNMI_CNT_TX_INTR(pAC,p) (((pAC)->Pnmi.Port[p].TxIntrCts)++) +#define SK_PNMI_CNT_NO_RX_BUF(pAC,p) (((pAC)->Pnmi.Port[p].RxNoBufCts)++) +#define SK_PNMI_CNT_NO_TX_BUF(pAC,p) (((pAC)->Pnmi.Port[p].TxNoBufCts)++) +#define SK_PNMI_CNT_USED_TX_DESCR(pAC,v,p) \ + ((pAC)->Pnmi.Port[p].TxUsedDescrNo=(SK_U64)(v)); +#define SK_PNMI_CNT_RX_OCTETS_DELIVERED(pAC,v,p) \ + { \ + ((pAC)->Pnmi.Port[p].RxDeliveredCts)++; \ + (pAC)->Pnmi.Port[p].RxOctetsDeliveredCts += (SK_U64)(v); \ + } +#define SK_PNMI_CNT_ERR_RECOVERY(pAC,p) (((pAC)->Pnmi.Port[p].ErrRecoveryCts)++); + +#define SK_PNMI_CNT_SYNC_OCTETS(pAC,p,v) \ + { \ + if ((p) < SK_MAX_MACS) { \ + ((pAC)->Pnmi.Port[p].StatSyncCts)++; \ + (pAC)->Pnmi.Port[p].StatSyncOctetsCts += (SK_U64)(v); \ + } \ + } + +#define SK_PNMI_CNT_RX_LONGFRAMES(pAC,p) \ + { \ + if ((p) < SK_MAX_MACS) { \ + ((pAC)->Pnmi.Port[p].StatRxLongFrameCts++); \ + } \ + } + +#define SK_PNMI_CNT_RX_FRAMETOOLONG(pAC,p) \ + { \ + if ((p) < SK_MAX_MACS) { \ + ((pAC)->Pnmi.Port[p].StatRxFrameTooLongCts++); \ + } \ + } + +#define SK_PNMI_CNT_RX_PMACC_ERR(pAC,p) \ + { \ + if ((p) < SK_MAX_MACS) { \ + ((pAC)->Pnmi.Port[p].StatRxPMaccErr++); \ + } \ + } + +/* + * Conversion Macros + */ +#define SK_PNMI_PORT_INST2LOG(i) ((unsigned int)(i) - 1) +#define SK_PNMI_PORT_LOG2INST(l) ((unsigned int)(l) + 1) +#define SK_PNMI_PORT_PHYS2LOG(p) ((unsigned int)(p) + 1) +#define SK_PNMI_PORT_LOG2PHYS(pAC,l) ((unsigned int)(l) - 1) +#define SK_PNMI_PORT_PHYS2INST(pAC,p) \ + (pAC->Pnmi.DualNetActiveFlag ? 2 : ((unsigned int)(p) + 2)) +#define SK_PNMI_PORT_INST2PHYS(pAC,i) ((unsigned int)(i) - 2) + +/* + * Structure definition for SkPnmiGetStruct and SkPnmiSetStruct + */ +#define SK_PNMI_VPD_KEY_SIZE 5 +#define SK_PNMI_VPD_BUFSIZE (VPD_SIZE) +#define SK_PNMI_VPD_ENTRIES (VPD_SIZE / 4) +#define SK_PNMI_VPD_DATALEN 128 /* Number of data bytes */ + +#define SK_PNMI_MULTICAST_LISTLEN 64 +#define SK_PNMI_SENSOR_ENTRIES (SK_MAX_SENSORS) +#define SK_PNMI_CHECKSUM_ENTRIES 3 +#define SK_PNMI_MAC_ENTRIES (SK_MAX_MACS + 1) +#define SK_PNMI_MONITOR_ENTRIES 20 +#define SK_PNMI_TRAP_ENTRIES 10 +#define SK_PNMI_TRAPLEN 128 +#define SK_PNMI_STRINGLEN1 80 +#define SK_PNMI_STRINGLEN2 25 +#define SK_PNMI_TRAP_QUEUE_LEN 512 + +typedef struct s_PnmiVpd { + char VpdKey[SK_PNMI_VPD_KEY_SIZE]; + char VpdValue[SK_PNMI_VPD_DATALEN]; + SK_U8 VpdAccess; + SK_U8 VpdAction; +} SK_PNMI_VPD; + +typedef struct s_PnmiSensor { + SK_U8 SensorIndex; + char SensorDescr[SK_PNMI_STRINGLEN2]; + SK_U8 SensorType; + SK_U32 SensorValue; + SK_U32 SensorWarningThresholdLow; + SK_U32 SensorWarningThresholdHigh; + SK_U32 SensorErrorThresholdLow; + SK_U32 SensorErrorThresholdHigh; + SK_U8 SensorStatus; + SK_U64 SensorWarningCts; + SK_U64 SensorErrorCts; + SK_U64 SensorWarningTimestamp; + SK_U64 SensorErrorTimestamp; +} SK_PNMI_SENSOR; + +typedef struct s_PnmiChecksum { + SK_U64 ChecksumRxOkCts; + SK_U64 ChecksumRxUnableCts; + SK_U64 ChecksumRxErrCts; + SK_U64 ChecksumTxOkCts; + SK_U64 ChecksumTxUnableCts; +} SK_PNMI_CHECKSUM; + +typedef struct s_PnmiStat { + SK_U64 StatTxOkCts; + SK_U64 StatTxOctetsOkCts; + SK_U64 StatTxBroadcastOkCts; + SK_U64 StatTxMulticastOkCts; + SK_U64 StatTxUnicastOkCts; + SK_U64 StatTxLongFramesCts; + SK_U64 StatTxBurstCts; + SK_U64 StatTxPauseMacCtrlCts; + SK_U64 StatTxMacCtrlCts; + SK_U64 StatTxSingleCollisionCts; + SK_U64 StatTxMultipleCollisionCts; + SK_U64 StatTxExcessiveCollisionCts; + SK_U64 StatTxLateCollisionCts; + SK_U64 StatTxDeferralCts; + SK_U64 StatTxExcessiveDeferralCts; + SK_U64 StatTxFifoUnderrunCts; + SK_U64 StatTxCarrierCts; + SK_U64 Dummy1; /* StatTxUtilization */ + SK_U64 StatTx64Cts; + SK_U64 StatTx127Cts; + SK_U64 StatTx255Cts; + SK_U64 StatTx511Cts; + SK_U64 StatTx1023Cts; + SK_U64 StatTxMaxCts; + SK_U64 StatTxSyncCts; + SK_U64 StatTxSyncOctetsCts; + SK_U64 StatRxOkCts; + SK_U64 StatRxOctetsOkCts; + SK_U64 StatRxBroadcastOkCts; + SK_U64 StatRxMulticastOkCts; + SK_U64 StatRxUnicastOkCts; + SK_U64 StatRxLongFramesCts; + SK_U64 StatRxPauseMacCtrlCts; + SK_U64 StatRxMacCtrlCts; + SK_U64 StatRxPauseMacCtrlErrorCts; + SK_U64 StatRxMacCtrlUnknownCts; + SK_U64 StatRxBurstCts; + SK_U64 StatRxMissedCts; + SK_U64 StatRxFramingCts; + SK_U64 StatRxFifoOverflowCts; + SK_U64 StatRxJabberCts; + SK_U64 StatRxCarrierCts; + SK_U64 StatRxIRLengthCts; + SK_U64 StatRxSymbolCts; + SK_U64 StatRxShortsCts; + SK_U64 StatRxRuntCts; + SK_U64 StatRxCextCts; + SK_U64 StatRxTooLongCts; + SK_U64 StatRxFcsCts; + SK_U64 Dummy2; /* StatRxUtilization */ + SK_U64 StatRx64Cts; + SK_U64 StatRx127Cts; + SK_U64 StatRx255Cts; + SK_U64 StatRx511Cts; + SK_U64 StatRx1023Cts; + SK_U64 StatRxMaxCts; +} SK_PNMI_STAT; + +typedef struct s_PnmiConf { + char ConfMacCurrentAddr[6]; + char ConfMacFactoryAddr[6]; + SK_U8 ConfPMD; + SK_U8 ConfConnector; + SK_U32 ConfPhyType; + SK_U32 ConfPhyMode; + SK_U8 ConfLinkCapability; + SK_U8 ConfLinkMode; + SK_U8 ConfLinkModeStatus; + SK_U8 ConfLinkStatus; + SK_U8 ConfFlowCtrlCapability; + SK_U8 ConfFlowCtrlMode; + SK_U8 ConfFlowCtrlStatus; + SK_U8 ConfPhyOperationCapability; + SK_U8 ConfPhyOperationMode; + SK_U8 ConfPhyOperationStatus; + SK_U8 ConfSpeedCapability; + SK_U8 ConfSpeedMode; + SK_U8 ConfSpeedStatus; +} SK_PNMI_CONF; + +typedef struct s_PnmiRlmt { + SK_U32 RlmtIndex; + SK_U32 RlmtStatus; + SK_U64 RlmtTxHelloCts; + SK_U64 RlmtRxHelloCts; + SK_U64 RlmtTxSpHelloReqCts; + SK_U64 RlmtRxSpHelloCts; +} SK_PNMI_RLMT; + +typedef struct s_PnmiRlmtMonitor { + SK_U32 RlmtMonitorIndex; + char RlmtMonitorAddr[6]; + SK_U64 RlmtMonitorErrorCts; + SK_U64 RlmtMonitorTimestamp; + SK_U8 RlmtMonitorAdmin; +} SK_PNMI_RLMT_MONITOR; + +typedef struct s_PnmiRequestStatus { + SK_U32 ErrorStatus; + SK_U32 ErrorOffset; +} SK_PNMI_REQUEST_STATUS; + +typedef struct s_PnmiStrucData { + SK_U32 MgmtDBVersion; + SK_PNMI_REQUEST_STATUS ReturnStatus; + SK_U32 VpdFreeBytes; + char VpdEntriesList[SK_PNMI_VPD_ENTRIES * SK_PNMI_VPD_KEY_SIZE]; + SK_U32 VpdEntriesNumber; + SK_PNMI_VPD Vpd[SK_PNMI_VPD_ENTRIES]; + SK_U32 PortNumber; + SK_U32 DeviceType; + char DriverDescr[SK_PNMI_STRINGLEN1]; + char DriverVersion[SK_PNMI_STRINGLEN2]; + char DriverReleaseDate[SK_PNMI_STRINGLEN1]; + char DriverFileName[SK_PNMI_STRINGLEN1]; + char HwDescr[SK_PNMI_STRINGLEN1]; + char HwVersion[SK_PNMI_STRINGLEN2]; + SK_U16 Chipset; + SK_U32 ChipId; + SK_U8 VauxAvail; + SK_U32 RamSize; + SK_U32 MtuSize; + SK_U32 Action; + SK_U32 TestResult; + SK_U8 BusType; + SK_U8 BusSpeed; + SK_U8 BusWidth; + SK_U8 SensorNumber; + SK_PNMI_SENSOR Sensor[SK_PNMI_SENSOR_ENTRIES]; + SK_U8 ChecksumNumber; + SK_PNMI_CHECKSUM Checksum[SK_PNMI_CHECKSUM_ENTRIES]; + SK_PNMI_STAT Stat[SK_PNMI_MAC_ENTRIES]; + SK_PNMI_CONF Conf[SK_PNMI_MAC_ENTRIES]; + SK_U8 RlmtMode; + SK_U32 RlmtPortNumber; + SK_U8 RlmtPortActive; + SK_U8 RlmtPortPreferred; + SK_U64 RlmtChangeCts; + SK_U64 RlmtChangeTime; + SK_U64 RlmtChangeEstimate; + SK_U64 RlmtChangeThreshold; + SK_PNMI_RLMT Rlmt[SK_MAX_MACS]; + SK_U32 RlmtMonitorNumber; + SK_PNMI_RLMT_MONITOR RlmtMonitor[SK_PNMI_MONITOR_ENTRIES]; + SK_U32 TrapNumber; + SK_U8 Trap[SK_PNMI_TRAP_QUEUE_LEN]; + SK_U64 TxSwQueueLen; + SK_U64 TxSwQueueMax; + SK_U64 TxRetryCts; + SK_U64 RxIntrCts; + SK_U64 TxIntrCts; + SK_U64 RxNoBufCts; + SK_U64 TxNoBufCts; + SK_U64 TxUsedDescrNo; + SK_U64 RxDeliveredCts; + SK_U64 RxOctetsDeliveredCts; + SK_U64 RxHwErrorsCts; + SK_U64 TxHwErrorsCts; + SK_U64 InErrorsCts; + SK_U64 OutErrorsCts; + SK_U64 ErrRecoveryCts; + SK_U64 SysUpTime; +} SK_PNMI_STRUCT_DATA; + +#define SK_PNMI_STRUCT_SIZE (sizeof(SK_PNMI_STRUCT_DATA)) +#define SK_PNMI_MIN_STRUCT_SIZE ((unsigned int)(SK_UPTR)\ + &(((SK_PNMI_STRUCT_DATA *)0)->VpdFreeBytes)) + /* + * ReturnStatus field + * must be located + * before VpdFreeBytes + */ + +/* + * Various definitions + */ +#define SK_PNMI_MAX_PROTOS 3 + +#define SK_PNMI_CNT_NO 66 /* Must have the value of the enum + * SK_PNMI_MAX_IDX. Define SK_PNMI_CHECK + * for check while init phase 1 + */ + +/* + * Estimate data structure + */ +typedef struct s_PnmiEstimate { + unsigned int EstValueIndex; + SK_U64 EstValue[7]; + SK_U64 Estimate; + SK_TIMER EstTimer; +} SK_PNMI_ESTIMATE; + + +/* + * VCT timer data structure + */ +typedef struct s_VctTimer { + SK_TIMER VctTimer; +} SK_PNMI_VCT_TIMER; + + +/* + * PNMI specific adapter context structure + */ +typedef struct s_PnmiPort { + SK_U64 StatSyncCts; + SK_U64 StatSyncOctetsCts; + SK_U64 StatRxLongFrameCts; + SK_U64 StatRxFrameTooLongCts; + SK_U64 StatRxPMaccErr; + SK_U64 TxSwQueueLen; + SK_U64 TxSwQueueMax; + SK_U64 TxRetryCts; + SK_U64 RxIntrCts; + SK_U64 TxIntrCts; + SK_U64 RxNoBufCts; + SK_U64 TxNoBufCts; + SK_U64 TxUsedDescrNo; + SK_U64 RxDeliveredCts; + SK_U64 RxOctetsDeliveredCts; + SK_U64 RxHwErrorsCts; + SK_U64 TxHwErrorsCts; + SK_U64 InErrorsCts; + SK_U64 OutErrorsCts; + SK_U64 ErrRecoveryCts; + SK_U64 RxShortZeroMark; + SK_U64 CounterOffset[SK_PNMI_CNT_NO]; + SK_U32 CounterHigh[SK_PNMI_CNT_NO]; + SK_BOOL ActiveFlag; + SK_U8 Align[3]; +} SK_PNMI_PORT; + + +typedef struct s_PnmiData { + SK_PNMI_PORT Port [SK_MAX_MACS]; + SK_PNMI_PORT BufPort [SK_MAX_MACS]; /* 2002-09-13 pweber */ + SK_U64 VirtualCounterOffset[SK_PNMI_CNT_NO]; + SK_U32 TestResult; + char HwVersion[10]; + SK_U16 Align01; + + char *pDriverDescription; + char *pDriverVersion; + char *pDriverReleaseDate; + char *pDriverFileName; + + int MacUpdatedFlag; + int RlmtUpdatedFlag; + int SirqUpdatedFlag; + + SK_U64 RlmtChangeCts; + SK_U64 RlmtChangeTime; + SK_PNMI_ESTIMATE RlmtChangeEstimate; + SK_U64 RlmtChangeThreshold; + + SK_U64 StartUpTime; + SK_U32 DeviceType; + char PciBusSpeed; + char PciBusWidth; + char Chipset; + char PMD; + char Connector; + SK_BOOL DualNetActiveFlag; + SK_U16 Align02; + + char TrapBuf[SK_PNMI_TRAP_QUEUE_LEN]; + unsigned int TrapBufFree; + unsigned int TrapQueueBeg; + unsigned int TrapQueueEnd; + unsigned int TrapBufPad; + unsigned int TrapUnique; + SK_U8 VctStatus[SK_MAX_MACS]; + SK_PNMI_VCT VctBackup[SK_MAX_MACS]; + SK_PNMI_VCT_TIMER VctTimeout[SK_MAX_MACS]; +#ifdef SK_DIAG_SUPPORT + SK_U32 DiagAttached; +#endif /* SK_DIAG_SUPPORT */ +} SK_PNMI; + + +/* + * Function prototypes + */ +extern int SkPnmiInit(SK_AC *pAC, SK_IOC IoC, int Level); +extern int SkPnmiSetVar(SK_AC *pAC, SK_IOC IoC, SK_U32 Id, void* pBuf, + unsigned int *pLen, SK_U32 Instance, SK_U32 NetIndex); +extern int SkPnmiGetStruct(SK_AC *pAC, SK_IOC IoC, void* pBuf, + unsigned int *pLen, SK_U32 NetIndex); +extern int SkPnmiPreSetStruct(SK_AC *pAC, SK_IOC IoC, void* pBuf, + unsigned int *pLen, SK_U32 NetIndex); +extern int SkPnmiSetStruct(SK_AC *pAC, SK_IOC IoC, void* pBuf, + unsigned int *pLen, SK_U32 NetIndex); +extern int SkPnmiEvent(SK_AC *pAC, SK_IOC IoC, SK_U32 Event, + SK_EVPARA Param); +extern int SkPnmiGenIoctl(SK_AC *pAC, SK_IOC IoC, void * pBuf, + unsigned int * pLen, SK_U32 NetIndex); + +#endif diff --git a/drivers/net/sk98lin/h/skgesirq.h b/drivers/net/sk98lin/h/skgesirq.h new file mode 100644 index 000000000000..3eec6274e413 --- /dev/null +++ b/drivers/net/sk98lin/h/skgesirq.h @@ -0,0 +1,110 @@ +/****************************************************************************** + * + * Name: skgesirq.h + * Project: Gigabit Ethernet Adapters, Common Modules + * Version: $Revision: 1.30 $ + * Date: $Date: 2003/07/04 12:34:13 $ + * Purpose: SK specific Gigabit Ethernet special IRQ functions + * + ******************************************************************************/ + +/****************************************************************************** + * + * (C)Copyright 1998-2002 SysKonnect. + * (C)Copyright 2002-2003 Marvell. + * + * 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. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +#ifndef _INC_SKGESIRQ_H_ +#define _INC_SKGESIRQ_H_ + +/* Define return codes of SkGePortCheckUp and CheckShort */ +#define SK_HW_PS_NONE 0 /* No action needed */ +#define SK_HW_PS_RESTART 1 /* Restart needed */ +#define SK_HW_PS_LINK 2 /* Link Up actions needed */ + +/* + * Define the Event the special IRQ/INI module can handle + */ +#define SK_HWEV_WATIM 1 /* Timeout for WA Errata #2 XMAC */ +#define SK_HWEV_PORT_START 2 /* Port Start Event by RLMT */ +#define SK_HWEV_PORT_STOP 3 /* Port Stop Event by RLMT */ +#define SK_HWEV_CLEAR_STAT 4 /* Clear Statistics by PNMI */ +#define SK_HWEV_UPDATE_STAT 5 /* Update Statistics by PNMI */ +#define SK_HWEV_SET_LMODE 6 /* Set Link Mode by PNMI */ +#define SK_HWEV_SET_FLOWMODE 7 /* Set Flow Control Mode by PNMI */ +#define SK_HWEV_SET_ROLE 8 /* Set Master/Slave (Role) by PNMI */ +#define SK_HWEV_SET_SPEED 9 /* Set Link Speed by PNMI */ +#define SK_HWEV_HALFDUP_CHK 10 /* Half Duplex Hangup Workaround */ + +#define SK_WA_ACT_TIME (5000000UL) /* 5 sec */ +#define SK_WA_INA_TIME (100000UL) /* 100 msec */ + +#define SK_HALFDUP_CHK_TIME (10000UL) /* 10 msec */ + +/* + * Define the error numbers and messages + */ +#define SKERR_SIRQ_E001 (SK_ERRBASE_SIRQ+0) +#define SKERR_SIRQ_E001MSG "Unknown event" +#define SKERR_SIRQ_E002 (SKERR_SIRQ_E001+1) +#define SKERR_SIRQ_E002MSG "Packet timeout RX1" +#define SKERR_SIRQ_E003 (SKERR_SIRQ_E002+1) +#define SKERR_SIRQ_E003MSG "Packet timeout RX2" +#define SKERR_SIRQ_E004 (SKERR_SIRQ_E003+1) +#define SKERR_SIRQ_E004MSG "MAC 1 not correctly initialized" +#define SKERR_SIRQ_E005 (SKERR_SIRQ_E004+1) +#define SKERR_SIRQ_E005MSG "MAC 2 not correctly initialized" +#define SKERR_SIRQ_E006 (SKERR_SIRQ_E005+1) +#define SKERR_SIRQ_E006MSG "CHECK failure R1" +#define SKERR_SIRQ_E007 (SKERR_SIRQ_E006+1) +#define SKERR_SIRQ_E007MSG "CHECK failure R2" +#define SKERR_SIRQ_E008 (SKERR_SIRQ_E007+1) +#define SKERR_SIRQ_E008MSG "CHECK failure XS1" +#define SKERR_SIRQ_E009 (SKERR_SIRQ_E008+1) +#define SKERR_SIRQ_E009MSG "CHECK failure XA1" +#define SKERR_SIRQ_E010 (SKERR_SIRQ_E009+1) +#define SKERR_SIRQ_E010MSG "CHECK failure XS2" +#define SKERR_SIRQ_E011 (SKERR_SIRQ_E010+1) +#define SKERR_SIRQ_E011MSG "CHECK failure XA2" +#define SKERR_SIRQ_E012 (SKERR_SIRQ_E011+1) +#define SKERR_SIRQ_E012MSG "unexpected IRQ Master error" +#define SKERR_SIRQ_E013 (SKERR_SIRQ_E012+1) +#define SKERR_SIRQ_E013MSG "unexpected IRQ Status error" +#define SKERR_SIRQ_E014 (SKERR_SIRQ_E013+1) +#define SKERR_SIRQ_E014MSG "Parity error on RAM (read)" +#define SKERR_SIRQ_E015 (SKERR_SIRQ_E014+1) +#define SKERR_SIRQ_E015MSG "Parity error on RAM (write)" +#define SKERR_SIRQ_E016 (SKERR_SIRQ_E015+1) +#define SKERR_SIRQ_E016MSG "Parity error MAC 1" +#define SKERR_SIRQ_E017 (SKERR_SIRQ_E016+1) +#define SKERR_SIRQ_E017MSG "Parity error MAC 2" +#define SKERR_SIRQ_E018 (SKERR_SIRQ_E017+1) +#define SKERR_SIRQ_E018MSG "Parity error RX 1" +#define SKERR_SIRQ_E019 (SKERR_SIRQ_E018+1) +#define SKERR_SIRQ_E019MSG "Parity error RX 2" +#define SKERR_SIRQ_E020 (SKERR_SIRQ_E019+1) +#define SKERR_SIRQ_E020MSG "MAC transmit FIFO underrun" +#define SKERR_SIRQ_E021 (SKERR_SIRQ_E020+1) +#define SKERR_SIRQ_E021MSG "Spurious TWSI interrupt" +#define SKERR_SIRQ_E022 (SKERR_SIRQ_E021+1) +#define SKERR_SIRQ_E022MSG "Cable pair swap error" +#define SKERR_SIRQ_E023 (SKERR_SIRQ_E022+1) +#define SKERR_SIRQ_E023MSG "Auto-negotiation error" +#define SKERR_SIRQ_E024 (SKERR_SIRQ_E023+1) +#define SKERR_SIRQ_E024MSG "FIFO overflow error" +#define SKERR_SIRQ_E025 (SKERR_SIRQ_E024+1) +#define SKERR_SIRQ_E025MSG "2 Pair Downshift detected" + +extern void SkGeSirqIsr(SK_AC *pAC, SK_IOC IoC, SK_U32 Istatus); +extern int SkGeSirqEvent(SK_AC *pAC, SK_IOC IoC, SK_U32 Event, SK_EVPARA Para); +extern void SkHWLinkDown(SK_AC *pAC, SK_IOC IoC, int Port); + +#endif /* _INC_SKGESIRQ_H_ */ diff --git a/drivers/net/sk98lin/h/ski2c.h b/drivers/net/sk98lin/h/ski2c.h new file mode 100644 index 000000000000..6a63f4a15de6 --- /dev/null +++ b/drivers/net/sk98lin/h/ski2c.h @@ -0,0 +1,174 @@ +/****************************************************************************** + * + * Name: ski2c.h + * Project: Gigabit Ethernet Adapters, TWSI-Module + * Version: $Revision: 1.35 $ + * Date: $Date: 2003/10/20 09:06:30 $ + * Purpose: Defines to access Voltage and Temperature Sensor + * + ******************************************************************************/ + +/****************************************************************************** + * + * (C)Copyright 1998-2002 SysKonnect. + * (C)Copyright 2002-2003 Marvell. + * + * 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. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/* + * SKI2C.H contains all I2C specific defines + */ + +#ifndef _SKI2C_H_ +#define _SKI2C_H_ + +typedef struct s_Sensor SK_SENSOR; + +#include "h/skgei2c.h" + +/* + * Define the I2C events. + */ +#define SK_I2CEV_IRQ 1 /* IRQ happened Event */ +#define SK_I2CEV_TIM 2 /* Timeout event */ +#define SK_I2CEV_CLEAR 3 /* Clear MIB Values */ + +/* + * Define READ and WRITE Constants. + */ +#define I2C_READ 0 +#define I2C_WRITE 1 +#define I2C_BURST 1 +#define I2C_SINGLE 0 + +#define SKERR_I2C_E001 (SK_ERRBASE_I2C+0) +#define SKERR_I2C_E001MSG "Sensor index unknown" +#define SKERR_I2C_E002 (SKERR_I2C_E001+1) +#define SKERR_I2C_E002MSG "TWSI: transfer does not complete" +#define SKERR_I2C_E003 (SKERR_I2C_E002+1) +#define SKERR_I2C_E003MSG "LM80: NAK on device send" +#define SKERR_I2C_E004 (SKERR_I2C_E003+1) +#define SKERR_I2C_E004MSG "LM80: NAK on register send" +#define SKERR_I2C_E005 (SKERR_I2C_E004+1) +#define SKERR_I2C_E005MSG "LM80: NAK on device (2) send" +#define SKERR_I2C_E006 (SKERR_I2C_E005+1) +#define SKERR_I2C_E006MSG "Unknown event" +#define SKERR_I2C_E007 (SKERR_I2C_E006+1) +#define SKERR_I2C_E007MSG "LM80 read out of state" +#define SKERR_I2C_E008 (SKERR_I2C_E007+1) +#define SKERR_I2C_E008MSG "Unexpected sensor read completed" +#define SKERR_I2C_E009 (SKERR_I2C_E008+1) +#define SKERR_I2C_E009MSG "WARNING: temperature sensor out of range" +#define SKERR_I2C_E010 (SKERR_I2C_E009+1) +#define SKERR_I2C_E010MSG "WARNING: voltage sensor out of range" +#define SKERR_I2C_E011 (SKERR_I2C_E010+1) +#define SKERR_I2C_E011MSG "ERROR: temperature sensor out of range" +#define SKERR_I2C_E012 (SKERR_I2C_E011+1) +#define SKERR_I2C_E012MSG "ERROR: voltage sensor out of range" +#define SKERR_I2C_E013 (SKERR_I2C_E012+1) +#define SKERR_I2C_E013MSG "ERROR: couldn't init sensor" +#define SKERR_I2C_E014 (SKERR_I2C_E013+1) +#define SKERR_I2C_E014MSG "WARNING: fan sensor out of range" +#define SKERR_I2C_E015 (SKERR_I2C_E014+1) +#define SKERR_I2C_E015MSG "ERROR: fan sensor out of range" +#define SKERR_I2C_E016 (SKERR_I2C_E015+1) +#define SKERR_I2C_E016MSG "TWSI: active transfer does not complete" + +/* + * Define Timeout values + */ +#define SK_I2C_TIM_LONG 2000000L /* 2 seconds */ +#define SK_I2C_TIM_SHORT 100000L /* 100 milliseconds */ +#define SK_I2C_TIM_WATCH 1000000L /* 1 second */ + +/* + * Define trap and error log hold times + */ +#ifndef SK_SEN_ERR_TR_HOLD +#define SK_SEN_ERR_TR_HOLD (4*SK_TICKS_PER_SEC) +#endif +#ifndef SK_SEN_ERR_LOG_HOLD +#define SK_SEN_ERR_LOG_HOLD (60*SK_TICKS_PER_SEC) +#endif +#ifndef SK_SEN_WARN_TR_HOLD +#define SK_SEN_WARN_TR_HOLD (15*SK_TICKS_PER_SEC) +#endif +#ifndef SK_SEN_WARN_LOG_HOLD +#define SK_SEN_WARN_LOG_HOLD (15*60*SK_TICKS_PER_SEC) +#endif + +/* + * Defines for SenType + */ +#define SK_SEN_UNKNOWN 0 +#define SK_SEN_TEMP 1 +#define SK_SEN_VOLT 2 +#define SK_SEN_FAN 3 + +/* + * Define for the SenErrorFlag + */ +#define SK_SEN_ERR_NOT_PRESENT 0 /* Error Flag: Sensor not present */ +#define SK_SEN_ERR_OK 1 /* Error Flag: O.K. */ +#define SK_SEN_ERR_WARN 2 /* Error Flag: Warning */ +#define SK_SEN_ERR_ERR 3 /* Error Flag: Error */ +#define SK_SEN_ERR_FAULTY 4 /* Error Flag: Faulty */ + +/* + * Define the Sensor struct + */ +struct s_Sensor { + char *SenDesc; /* Description */ + int SenType; /* Voltage or Temperature */ + SK_I32 SenValue; /* Current value of the sensor */ + SK_I32 SenThreErrHigh; /* High error Threshhold of this sensor */ + SK_I32 SenThreWarnHigh; /* High warning Threshhold of this sensor */ + SK_I32 SenThreErrLow; /* Lower error Threshold of the sensor */ + SK_I32 SenThreWarnLow; /* Lower warning Threshold of the sensor */ + int SenErrFlag; /* Sensor indicated an error */ + SK_BOOL SenInit; /* Is sensor initialized ? */ + SK_U64 SenErrCts; /* Error trap counter */ + SK_U64 SenWarnCts; /* Warning trap counter */ + SK_U64 SenBegErrTS; /* Begin error timestamp */ + SK_U64 SenBegWarnTS; /* Begin warning timestamp */ + SK_U64 SenLastErrTrapTS; /* Last error trap timestamp */ + SK_U64 SenLastErrLogTS; /* Last error log timestamp */ + SK_U64 SenLastWarnTrapTS; /* Last warning trap timestamp */ + SK_U64 SenLastWarnLogTS; /* Last warning log timestamp */ + int SenState; /* Sensor State (see HW specific include) */ + int (*SenRead)(SK_AC *pAC, SK_IOC IoC, struct s_Sensor *pSen); + /* Sensors read function */ + SK_U16 SenReg; /* Register Address for this sensor */ + SK_U8 SenDev; /* Device Selection for this sensor */ +}; + +typedef struct s_I2c { + SK_SENSOR SenTable[SK_MAX_SENSORS]; /* Sensor Table */ + int CurrSens; /* Which sensor is currently queried */ + int MaxSens; /* Max. number of sensors */ + int TimerMode; /* Use the timer also to watch the state machine */ + int InitLevel; /* Initialized Level */ +#ifndef SK_DIAG + int DummyReads; /* Number of non-checked dummy reads */ + SK_TIMER SenTimer; /* Sensors timer */ +#endif /* !SK_DIAG */ +} SK_I2C; + +extern int SkI2cInit(SK_AC *pAC, SK_IOC IoC, int Level); +#ifdef SK_DIAG +extern SK_U32 SkI2cRead(SK_AC *pAC, SK_IOC IoC, int Dev, int Size, int Reg, + int Burst); +#else /* !SK_DIAG */ +extern int SkI2cEvent(SK_AC *pAC, SK_IOC IoC, SK_U32 Event, SK_EVPARA Para); +extern void SkI2cWaitIrq(SK_AC *pAC, SK_IOC IoC); +extern void SkI2cIsr(SK_AC *pAC, SK_IOC IoC); +#endif /* !SK_DIAG */ +#endif /* n_SKI2C_H */ + diff --git a/drivers/net/sk98lin/h/skqueue.h b/drivers/net/sk98lin/h/skqueue.h new file mode 100644 index 000000000000..2ec40d4fdf60 --- /dev/null +++ b/drivers/net/sk98lin/h/skqueue.h @@ -0,0 +1,94 @@ +/****************************************************************************** + * + * Name: skqueue.h + * Project: Gigabit Ethernet Adapters, Event Scheduler Module + * Version: $Revision: 1.16 $ + * Date: $Date: 2003/09/16 12:50:32 $ + * Purpose: Defines for the Event queue + * + ******************************************************************************/ + +/****************************************************************************** + * + * (C)Copyright 1998-2002 SysKonnect GmbH. + * (C)Copyright 2002-2003 Marvell. + * + * 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. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/* + * SKQUEUE.H contains all defines and types for the event queue + */ + +#ifndef _SKQUEUE_H_ +#define _SKQUEUE_H_ + + +/* + * define the event classes to be served + */ +#define SKGE_DRV 1 /* Driver Event Class */ +#define SKGE_RLMT 2 /* RLMT Event Class */ +#define SKGE_I2C 3 /* I2C Event Class */ +#define SKGE_PNMI 4 /* PNMI Event Class */ +#define SKGE_CSUM 5 /* Checksum Event Class */ +#define SKGE_HWAC 6 /* Hardware Access Event Class */ + +#define SKGE_SWT 9 /* Software Timer Event Class */ +#define SKGE_LACP 10 /* LACP Aggregation Event Class */ +#define SKGE_RSF 11 /* RSF Aggregation Event Class */ +#define SKGE_MARKER 12 /* MARKER Aggregation Event Class */ +#define SKGE_FD 13 /* FD Distributor Event Class */ + +/* + * define event queue as circular buffer + */ +#define SK_MAX_EVENT 64 + +/* + * Parameter union for the Para stuff + */ +typedef union u_EvPara { + void *pParaPtr; /* Parameter Pointer */ + SK_U64 Para64; /* Parameter 64bit version */ + SK_U32 Para32[2]; /* Parameter Array of 32bit parameters */ +} SK_EVPARA; + +/* + * Event Queue + * skqueue.c + * events are class/value pairs + * class is addressee, e.g. RLMT, PNMI etc. + * value is command, e.g. line state change, ring op change etc. + */ +typedef struct s_EventElem { + SK_U32 Class; /* Event class */ + SK_U32 Event; /* Event value */ + SK_EVPARA Para; /* Event parameter */ +} SK_EVENTELEM; + +typedef struct s_Queue { + SK_EVENTELEM EvQueue[SK_MAX_EVENT]; + SK_EVENTELEM *EvPut; + SK_EVENTELEM *EvGet; +} SK_QUEUE; + +extern void SkEventInit(SK_AC *pAC, SK_IOC Ioc, int Level); +extern void SkEventQueue(SK_AC *pAC, SK_U32 Class, SK_U32 Event, + SK_EVPARA Para); +extern int SkEventDispatcher(SK_AC *pAC, SK_IOC Ioc); + + +/* Define Error Numbers and messages */ +#define SKERR_Q_E001 (SK_ERRBASE_QUEUE+0) +#define SKERR_Q_E001MSG "Event queue overflow" +#define SKERR_Q_E002 (SKERR_Q_E001+1) +#define SKERR_Q_E002MSG "Undefined event class" +#endif /* _SKQUEUE_H_ */ + diff --git a/drivers/net/sk98lin/h/skrlmt.h b/drivers/net/sk98lin/h/skrlmt.h new file mode 100644 index 000000000000..ca75dfdcf2d6 --- /dev/null +++ b/drivers/net/sk98lin/h/skrlmt.h @@ -0,0 +1,438 @@ +/****************************************************************************** + * + * Name: skrlmt.h + * Project: GEnesis, PCI Gigabit Ethernet Adapter + * Version: $Revision: 1.37 $ + * Date: $Date: 2003/04/15 09:43:43 $ + * Purpose: Header file for Redundant Link ManagemenT. + * + ******************************************************************************/ + +/****************************************************************************** + * + * (C)Copyright 1998-2002 SysKonnect GmbH. + * (C)Copyright 2002-2003 Marvell. + * + * 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. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/****************************************************************************** + * + * Description: + * + * This is the header file for Redundant Link ManagemenT. + * + * Include File Hierarchy: + * + * "skdrv1st.h" + * ... + * "sktypes.h" + * "skqueue.h" + * "skaddr.h" + * "skrlmt.h" + * ... + * "skdrv2nd.h" + * + ******************************************************************************/ + +#ifndef __INC_SKRLMT_H +#define __INC_SKRLMT_H + +#ifdef __cplusplus +extern "C" { +#endif /* cplusplus */ + +/* defines ********************************************************************/ + +#define SK_RLMT_NET_DOWN_TEMP 1 /* NET_DOWN due to last port down. */ +#define SK_RLMT_NET_DOWN_FINAL 2 /* NET_DOWN due to RLMT_STOP. */ + +/* ----- Default queue sizes - must be multiples of 8 KB ----- */ + +/* Less than 8 KB free in RX queue => pause frames. */ +#define SK_RLMT_STANDBY_QRXSIZE 128 /* Size of rx standby queue in KB. */ +#define SK_RLMT_STANDBY_QXASIZE 32 /* Size of async standby queue in KB. */ +#define SK_RLMT_STANDBY_QXSSIZE 0 /* Size of sync standby queue in KB. */ + +#define SK_RLMT_MAX_TX_BUF_SIZE 60 /* Maximum RLMT transmit size. */ + +/* ----- PORT states ----- */ + +#define SK_RLMT_PS_INIT 0 /* Port state: Init. */ +#define SK_RLMT_PS_LINK_DOWN 1 /* Port state: Link down. */ +#define SK_RLMT_PS_DOWN 2 /* Port state: Port down. */ +#define SK_RLMT_PS_GOING_UP 3 /* Port state: Going up. */ +#define SK_RLMT_PS_UP 4 /* Port state: Up. */ + +/* ----- RLMT states ----- */ + +#define SK_RLMT_RS_INIT 0 /* RLMT state: Init. */ +#define SK_RLMT_RS_NET_DOWN 1 /* RLMT state: Net down. */ +#define SK_RLMT_RS_NET_UP 2 /* RLMT state: Net up. */ + +/* ----- PORT events ----- */ + +#define SK_RLMT_LINK_UP 1001 /* Link came up. */ +#define SK_RLMT_LINK_DOWN 1002 /* Link went down. */ +#define SK_RLMT_PORT_ADDR 1003 /* Port address changed. */ + +/* ----- RLMT events ----- */ + +#define SK_RLMT_START 2001 /* Start RLMT. */ +#define SK_RLMT_STOP 2002 /* Stop RLMT. */ +#define SK_RLMT_PACKET_RECEIVED 2003 /* Packet was received for RLMT. */ +#define SK_RLMT_STATS_CLEAR 2004 /* Clear statistics. */ +#define SK_RLMT_STATS_UPDATE 2005 /* Update statistics. */ +#define SK_RLMT_PREFPORT_CHANGE 2006 /* Change preferred port. */ +#define SK_RLMT_MODE_CHANGE 2007 /* New RlmtMode. */ +#define SK_RLMT_SET_NETS 2008 /* Number of Nets (1 or 2). */ + +/* ----- RLMT mode bits ----- */ + +/* + * CAUTION: These defines are private to RLMT. + * Please use the RLMT mode defines below. + */ + +#define SK_RLMT_CHECK_LINK 1 /* Check Link. */ +#define SK_RLMT_CHECK_LOC_LINK 2 /* Check other link on same adapter. */ +#define SK_RLMT_CHECK_SEG 4 /* Check segmentation. */ + +#ifndef RLMT_CHECK_REMOTE +#define SK_RLMT_CHECK_OTHERS SK_RLMT_CHECK_LOC_LINK +#else /* RLMT_CHECK_REMOTE */ +#define SK_RLMT_CHECK_REM_LINK 8 /* Check link(s) on other adapter(s). */ +#define SK_RLMT_MAX_REMOTE_PORTS_CHECKED 3 +#define SK_RLMT_CHECK_OTHERS \ + (SK_RLMT_CHECK_LOC_LINK | SK_RLMT_CHECK_REM_LINK) +#endif /* RLMT_CHECK_REMOTE */ + +#ifndef SK_RLMT_ENABLE_TRANSPARENT +#define SK_RLMT_TRANSPARENT 0 /* RLMT transparent - inactive. */ +#else /* SK_RLMT_ENABLE_TRANSPARENT */ +#define SK_RLMT_TRANSPARENT 128 /* RLMT transparent. */ +#endif /* SK_RLMT_ENABLE_TRANSPARENT */ + +/* ----- RLMT modes ----- */ + +/* Check Link State. */ +#define SK_RLMT_MODE_CLS (SK_RLMT_CHECK_LINK) + +/* Check Local Ports: check other links on the same adapter. */ +#define SK_RLMT_MODE_CLP (SK_RLMT_CHECK_LINK | SK_RLMT_CHECK_LOC_LINK) + +/* Check Local Ports and Segmentation Status. */ +#define SK_RLMT_MODE_CLPSS \ + (SK_RLMT_CHECK_LINK | SK_RLMT_CHECK_LOC_LINK | SK_RLMT_CHECK_SEG) + +#ifdef RLMT_CHECK_REMOTE +/* Check Local and Remote Ports: check links (local or remote). */ + Name of define TBD! +#define SK_RLMT_MODE_CRP \ + (SK_RLMT_CHECK_LINK | SK_RLMT_CHECK_LOC_LINK | SK_RLMT_CHECK_REM_LINK) + +/* Check Local and Remote Ports and Segmentation Status. */ + Name of define TBD! +#define SK_RLMT_MODE_CRPSS \ + (SK_RLMT_CHECK_LINK | SK_RLMT_CHECK_LOC_LINK | \ + SK_RLMT_CHECK_REM_LINK | SK_RLMT_CHECK_SEG) +#endif /* RLMT_CHECK_REMOTE */ + +/* ----- RLMT lookahead result bits ----- */ + +#define SK_RLMT_RX_RLMT 1 /* Give packet to RLMT. */ +#define SK_RLMT_RX_PROTOCOL 2 /* Give packet to protocol. */ + +/* Macros */ + +#if 0 +SK_AC *pAC /* adapter context */ +SK_U32 PortNum /* receiving port */ +unsigned PktLen /* received packet's length */ +SK_BOOL IsBc /* Flag: packet is broadcast */ +unsigned *pOffset /* offs. of bytes to present to SK_RLMT_LOOKAHEAD */ +unsigned *pNumBytes /* #Bytes to present to SK_RLMT_LOOKAHEAD */ +#endif /* 0 */ + +#define SK_RLMT_PRE_LOOKAHEAD(pAC,PortNum,PktLen,IsBc,pOffset,pNumBytes) { \ + SK_AC *_pAC; \ + SK_U32 _PortNum; \ + _pAC = (pAC); \ + _PortNum = (SK_U32)(PortNum); \ + /* _pAC->Rlmt.Port[_PortNum].PacketsRx++; */ \ + _pAC->Rlmt.Port[_PortNum].PacketsPerTimeSlot++; \ + if (_pAC->Rlmt.RlmtOff) { \ + *(pNumBytes) = 0; \ + } \ + else {\ + if ((_pAC->Rlmt.Port[_PortNum].Net->RlmtMode & SK_RLMT_TRANSPARENT) != 0) { \ + *(pNumBytes) = 0; \ + } \ + else if (IsBc) { \ + if (_pAC->Rlmt.Port[_PortNum].Net->RlmtMode != SK_RLMT_MODE_CLS) { \ + *(pNumBytes) = 6; \ + *(pOffset) = 6; \ + } \ + else { \ + *(pNumBytes) = 0; \ + } \ + } \ + else { \ + if ((PktLen) > SK_RLMT_MAX_TX_BUF_SIZE) { \ + /* _pAC->Rlmt.Port[_PortNum].DataPacketsPerTimeSlot++; */ \ + *(pNumBytes) = 0; \ + } \ + else { \ + *(pNumBytes) = 6; \ + *(pOffset) = 0; \ + } \ + } \ + } \ +} + +#if 0 +SK_AC *pAC /* adapter context */ +SK_U32 PortNum /* receiving port */ +SK_U8 *pLaPacket, /* received packet's data (points to pOffset) */ +SK_BOOL IsBc /* Flag: packet is broadcast */ +SK_BOOL IsMc /* Flag: packet is multicast */ +unsigned *pForRlmt /* Result: bits SK_RLMT_RX_RLMT, SK_RLMT_RX_PROTOCOL */ +SK_RLMT_LOOKAHEAD() expects *pNumBytes from +packet offset *pOffset (s.a.) at *pLaPacket. + +If you use SK_RLMT_LOOKAHEAD in a path where you already know if the packet is +BC, MC, or UC, you should use constants for IsBc and IsMc, so that your compiler +can trash unneeded parts of the if construction. +#endif /* 0 */ + +#define SK_RLMT_LOOKAHEAD(pAC,PortNum,pLaPacket,IsBc,IsMc,pForRlmt) { \ + SK_AC *_pAC; \ + SK_U32 _PortNum; \ + SK_U8 *_pLaPacket; \ + _pAC = (pAC); \ + _PortNum = (SK_U32)(PortNum); \ + _pLaPacket = (SK_U8 *)(pLaPacket); \ + if (IsBc) {\ + if (!SK_ADDR_EQUAL(_pLaPacket, _pAC->Addr.Net[_pAC->Rlmt.Port[ \ + _PortNum].Net->NetNumber].CurrentMacAddress.a)) { \ + _pAC->Rlmt.Port[_PortNum].BcTimeStamp = SkOsGetTime(_pAC); \ + _pAC->Rlmt.CheckSwitch = SK_TRUE; \ + } \ + /* _pAC->Rlmt.Port[_PortNum].DataPacketsPerTimeSlot++; */ \ + *(pForRlmt) = SK_RLMT_RX_PROTOCOL; \ + } \ + else if (IsMc) { \ + if (SK_ADDR_EQUAL(_pLaPacket, BridgeMcAddr.a)) { \ + _pAC->Rlmt.Port[_PortNum].BpduPacketsPerTimeSlot++; \ + if (_pAC->Rlmt.Port[_PortNum].Net->RlmtMode & SK_RLMT_CHECK_SEG) { \ + *(pForRlmt) = SK_RLMT_RX_RLMT | SK_RLMT_RX_PROTOCOL; \ + } \ + else { \ + *(pForRlmt) = SK_RLMT_RX_PROTOCOL; \ + } \ + } \ + else if (SK_ADDR_EQUAL(_pLaPacket, SkRlmtMcAddr.a)) { \ + *(pForRlmt) = SK_RLMT_RX_RLMT; \ + } \ + else { \ + /* _pAC->Rlmt.Port[_PortNum].DataPacketsPerTimeSlot++; */ \ + *(pForRlmt) = SK_RLMT_RX_PROTOCOL; \ + } \ + } \ + else { \ + if (SK_ADDR_EQUAL( \ + _pLaPacket, \ + _pAC->Addr.Port[_PortNum].CurrentMacAddress.a)) { \ + *(pForRlmt) = SK_RLMT_RX_RLMT; \ + } \ + else { \ + /* _pAC->Rlmt.Port[_PortNum].DataPacketsPerTimeSlot++; */ \ + *(pForRlmt) = SK_RLMT_RX_PROTOCOL; \ + } \ + } \ +} + +#ifdef SK_RLMT_FAST_LOOKAHEAD +Error: SK_RLMT_FAST_LOOKAHEAD no longer used. Use new macros for lookahead. +#endif /* SK_RLMT_FAST_LOOKAHEAD */ +#ifdef SK_RLMT_SLOW_LOOKAHEAD +Error: SK_RLMT_SLOW_LOOKAHEAD no longer used. Use new macros for lookahead. +#endif /* SK_RLMT_SLOW_LOOKAHEAD */ + +/* typedefs *******************************************************************/ + +#ifdef SK_RLMT_MBUF_PRIVATE +typedef struct s_RlmtMbuf { + some content +} SK_RLMT_MBUF; +#endif /* SK_RLMT_MBUF_PRIVATE */ + + +#ifdef SK_LA_INFO +typedef struct s_Rlmt_PacketInfo { + unsigned PacketLength; /* Length of packet. */ + unsigned PacketType; /* Directed/Multicast/Broadcast. */ +} SK_RLMT_PINFO; +#endif /* SK_LA_INFO */ + + +typedef struct s_RootId { + SK_U8 Id[8]; /* Root Bridge Id. */ +} SK_RLMT_ROOT_ID; + + +typedef struct s_port { + SK_MAC_ADDR CheckAddr; + SK_BOOL SuspectTx; +} SK_PORT_CHECK; + + +typedef struct s_RlmtNet SK_RLMT_NET; + + +typedef struct s_RlmtPort { + +/* ----- Public part (read-only) ----- */ + + SK_U8 PortState; /* Current state of this port. */ + + /* For PNMI */ + SK_BOOL LinkDown; + SK_BOOL PortDown; + SK_U8 Align01; + + SK_U32 PortNumber; /* Number of port on adapter. */ + SK_RLMT_NET * Net; /* Net port belongs to. */ + + SK_U64 TxHelloCts; + SK_U64 RxHelloCts; + SK_U64 TxSpHelloReqCts; + SK_U64 RxSpHelloCts; + +/* ----- Private part ----- */ + +/* SK_U64 PacketsRx; */ /* Total packets received. */ + SK_U32 PacketsPerTimeSlot; /* Packets rxed between TOs. */ +/* SK_U32 DataPacketsPerTimeSlot; */ /* Data packets ... */ + SK_U32 BpduPacketsPerTimeSlot; /* BPDU packets rxed in TS. */ + SK_U64 BcTimeStamp; /* Time of last BC receive. */ + SK_U64 GuTimeStamp; /* Time of entering GOING_UP. */ + + SK_TIMER UpTimer; /* Timer struct Link/Port up. */ + SK_TIMER DownRxTimer; /* Timer struct down rx. */ + SK_TIMER DownTxTimer; /* Timer struct down tx. */ + + SK_U32 CheckingState; /* Checking State. */ + + SK_ADDR_PORT * AddrPort; + + SK_U8 Random[4]; /* Random value. */ + unsigned PortsChecked; /* #ports checked. */ + unsigned PortsSuspect; /* #ports checked that are s. */ + SK_PORT_CHECK PortCheck[1]; +/* SK_PORT_CHECK PortCheck[SK_MAX_MACS - 1]; */ + + SK_BOOL PortStarted; /* Port is started. */ + SK_BOOL PortNoRx; /* NoRx for >= 1 time slot. */ + SK_BOOL RootIdSet; + SK_RLMT_ROOT_ID Root; /* Root Bridge Id. */ +} SK_RLMT_PORT; + + +struct s_RlmtNet { + +/* ----- Public part (read-only) ----- */ + + SK_U32 NetNumber; /* Number of net. */ + + SK_RLMT_PORT * Port[SK_MAX_MACS]; /* Ports that belong to this net. */ + SK_U32 NumPorts; /* Number of ports. */ + SK_U32 PrefPort; /* Preferred port. */ + + /* For PNMI */ + + SK_U32 ChgBcPrio; /* Change Priority of last broadcast received */ + SK_U32 RlmtMode; /* Check ... */ + SK_U32 ActivePort; /* Active port. */ + SK_U32 Preference; /* 0xFFFFFFFF: Automatic. */ + + SK_U8 RlmtState; /* Current RLMT state. */ + +/* ----- Private part ----- */ + SK_BOOL RootIdSet; + SK_U16 Align01; + + int LinksUp; /* #Links up. */ + int PortsUp; /* #Ports up. */ + SK_U32 TimeoutValue; /* RLMT timeout value. */ + + SK_U32 CheckingState; /* Checking State. */ + SK_RLMT_ROOT_ID Root; /* Root Bridge Id. */ + + SK_TIMER LocTimer; /* Timer struct. */ + SK_TIMER SegTimer; /* Timer struct. */ +}; + + +typedef struct s_Rlmt { + +/* ----- Public part (read-only) ----- */ + + SK_U32 NumNets; /* Number of nets. */ + SK_U32 NetsStarted; /* Number of nets started. */ + SK_RLMT_NET Net[SK_MAX_NETS]; /* Array of available nets. */ + SK_RLMT_PORT Port[SK_MAX_MACS]; /* Array of available ports. */ + +/* ----- Private part ----- */ + SK_BOOL CheckSwitch; + SK_BOOL RlmtOff; /* set to zero if the Mac addresses + are equal or the second one + is zero */ + SK_U16 Align01; + +} SK_RLMT; + + +extern SK_MAC_ADDR BridgeMcAddr; +extern SK_MAC_ADDR SkRlmtMcAddr; + +/* function prototypes ********************************************************/ + + +#ifndef SK_KR_PROTO + +/* Functions provided by SkRlmt */ + +/* ANSI/C++ compliant function prototypes */ + +extern void SkRlmtInit( + SK_AC *pAC, + SK_IOC IoC, + int Level); + +extern int SkRlmtEvent( + SK_AC *pAC, + SK_IOC IoC, + SK_U32 Event, + SK_EVPARA Para); + +#else /* defined(SK_KR_PROTO) */ + +/* Non-ANSI/C++ compliant function prototypes */ + +#error KR-style function prototypes are not yet provided. + +#endif /* defined(SK_KR_PROTO)) */ + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __INC_SKRLMT_H */ diff --git a/drivers/net/sk98lin/h/sktimer.h b/drivers/net/sk98lin/h/sktimer.h new file mode 100644 index 000000000000..04e6d7c1ec33 --- /dev/null +++ b/drivers/net/sk98lin/h/sktimer.h @@ -0,0 +1,63 @@ +/****************************************************************************** + * + * Name: sktimer.h + * Project: Gigabit Ethernet Adapters, Event Scheduler Module + * Version: $Revision: 1.11 $ + * Date: $Date: 2003/09/16 12:58:18 $ + * Purpose: Defines for the timer functions + * + ******************************************************************************/ + +/****************************************************************************** + * + * (C)Copyright 1998-2002 SysKonnect GmbH. + * (C)Copyright 2002-2003 Marvell. + * + * 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. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/* + * SKTIMER.H contains all defines and types for the timer functions + */ + +#ifndef _SKTIMER_H_ +#define _SKTIMER_H_ + +#include "h/skqueue.h" + +/* + * SK timer + * - needed wherever a timer is used. Put this in your data structure + * wherever you want. + */ +typedef struct s_Timer SK_TIMER; + +struct s_Timer { + SK_TIMER *TmNext; /* linked list */ + SK_U32 TmClass; /* Timer Event class */ + SK_U32 TmEvent; /* Timer Event value */ + SK_EVPARA TmPara; /* Timer Event parameter */ + SK_U32 TmDelta; /* delta time */ + int TmActive; /* flag: active/inactive */ +}; + +/* + * Timer control struct. + * - use in Adapters context name pAC->Tim + */ +typedef struct s_TimCtrl { + SK_TIMER *StQueue; /* Head of Timer queue */ +} SK_TIMCTRL; + +extern void SkTimerInit(SK_AC *pAC, SK_IOC Ioc, int Level); +extern void SkTimerStop(SK_AC *pAC, SK_IOC Ioc, SK_TIMER *pTimer); +extern void SkTimerStart(SK_AC *pAC, SK_IOC Ioc, SK_TIMER *pTimer, + SK_U32 Time, SK_U32 Class, SK_U32 Event, SK_EVPARA Para); +extern void SkTimerDone(SK_AC *pAC, SK_IOC Ioc); +#endif /* _SKTIMER_H_ */ diff --git a/drivers/net/sk98lin/h/sktypes.h b/drivers/net/sk98lin/h/sktypes.h new file mode 100644 index 000000000000..40edc96e1055 --- /dev/null +++ b/drivers/net/sk98lin/h/sktypes.h @@ -0,0 +1,69 @@ +/****************************************************************************** + * + * Name: sktypes.h + * Project: GEnesis, PCI Gigabit Ethernet Adapter + * Version: $Revision: 1.2 $ + * Date: $Date: 2003/10/07 08:16:51 $ + * Purpose: Define data types for Linux + * + ******************************************************************************/ + +/****************************************************************************** + * + * (C)Copyright 1998-2002 SysKonnect GmbH. + * (C)Copyright 2002-2003 Marvell. + * + * 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. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/****************************************************************************** + * + * Description: + * + * In this file, all data types that are needed by the common modules + * are mapped to Linux data types. + * + * + * Include File Hierarchy: + * + * + ******************************************************************************/ + +#ifndef __INC_SKTYPES_H +#define __INC_SKTYPES_H + + +/* defines *******************************************************************/ + +/* + * Data types with a specific size. 'I' = signed, 'U' = unsigned. + */ +#define SK_I8 s8 +#define SK_U8 u8 +#define SK_I16 s16 +#define SK_U16 u16 +#define SK_I32 s32 +#define SK_U32 u32 +#define SK_I64 s64 +#define SK_U64 u64 + +#define SK_UPTR ulong /* casting pointer <-> integral */ + +/* +* Boolean type. +*/ +#define SK_BOOL SK_U8 +#define SK_FALSE 0 +#define SK_TRUE (!SK_FALSE) + +/* typedefs *******************************************************************/ + +/* function prototypes ********************************************************/ + +#endif /* __INC_SKTYPES_H */ diff --git a/drivers/net/sk98lin/h/skversion.h b/drivers/net/sk98lin/h/skversion.h new file mode 100644 index 000000000000..a1a7294828e5 --- /dev/null +++ b/drivers/net/sk98lin/h/skversion.h @@ -0,0 +1,38 @@ +/****************************************************************************** + * + * Name: version.h + * Project: GEnesis, PCI Gigabit Ethernet Adapter + * Version: $Revision: 1.5 $ + * Date: $Date: 2003/10/07 08:16:51 $ + * Purpose: SK specific Error log support + * + ******************************************************************************/ + +/****************************************************************************** + * + * (C)Copyright 1998-2002 SysKonnect GmbH. + * (C)Copyright 2002-2003 Marvell. + * + * 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. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +#ifdef lint +static const char SysKonnectFileId[] = "@(#) (C) SysKonnect GmbH."; +static const char SysKonnectBuildNumber[] = + "@(#)SK-BUILD: 6.23 PL: 01"; +#endif /* !defined(lint) */ + +#define BOOT_STRING "sk98lin: Network Device Driver v6.23\n" \ + "(C)Copyright 1999-2004 Marvell(R)." + +#define VER_STRING "6.23" +#define DRIVER_FILE_NAME "sk98lin" +#define DRIVER_REL_DATE "Feb-13-2004" + + diff --git a/drivers/net/sk98lin/h/skvpd.h b/drivers/net/sk98lin/h/skvpd.h new file mode 100644 index 000000000000..fdd9e48e8040 --- /dev/null +++ b/drivers/net/sk98lin/h/skvpd.h @@ -0,0 +1,248 @@ +/****************************************************************************** + * + * Name: skvpd.h + * Project: GEnesis, PCI Gigabit Ethernet Adapter + * Version: $Revision: 1.15 $ + * Date: $Date: 2003/01/13 10:39:38 $ + * Purpose: Defines and Macros for VPD handling + * + ******************************************************************************/ + +/****************************************************************************** + * + * (C)Copyright 1998-2003 SysKonnect GmbH. + * + * 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. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/* + * skvpd.h contains Diagnostic specific defines for VPD handling + */ + +#ifndef __INC_SKVPD_H_ +#define __INC_SKVPD_H_ + +/* + * Define Resource Type Identifiers and VPD keywords + */ +#define RES_ID 0x82 /* Resource Type ID String (Product Name) */ +#define RES_VPD_R 0x90 /* start of VPD read only area */ +#define RES_VPD_W 0x91 /* start of VPD read/write area */ +#define RES_END 0x78 /* Resource Type End Tag */ + +#ifndef VPD_NAME +#define VPD_NAME "Name" /* Product Name, VPD name of RES_ID */ +#endif /* VPD_NAME */ +#define VPD_PN "PN" /* Adapter Part Number */ +#define VPD_EC "EC" /* Adapter Engineering Level */ +#define VPD_MN "MN" /* Manufacture ID */ +#define VPD_SN "SN" /* Serial Number */ +#define VPD_CP "CP" /* Extended Capability */ +#define VPD_RV "RV" /* Checksum and Reserved */ +#define VPD_YA "YA" /* Asset Tag Identifier */ +#define VPD_VL "VL" /* First Error Log Message (SK specific) */ +#define VPD_VF "VF" /* Second Error Log Message (SK specific) */ +#define VPD_RW "RW" /* Remaining Read / Write Area */ + +/* 'type' values for vpd_setup_para() */ +#define VPD_RO_KEY 1 /* RO keys are "PN", "EC", "MN", "SN", "RV" */ +#define VPD_RW_KEY 2 /* RW keys are "Yx", "Vx", and "RW" */ + +/* 'op' values for vpd_setup_para() */ +#define ADD_KEY 1 /* add the key at the pos "RV" or "RW" */ +#define OWR_KEY 2 /* overwrite key if already exists */ + +/* + * Define READ and WRITE Constants. + */ + +#define VPD_DEV_ID_GENESIS 0x4300 + +#define VPD_SIZE_YUKON 256 +#define VPD_SIZE_GENESIS 512 +#define VPD_SIZE 512 +#define VPD_READ 0x0000 +#define VPD_WRITE 0x8000 + +#define VPD_STOP(pAC,IoC) VPD_OUT16(pAC,IoC,PCI_VPD_ADR_REG,VPD_WRITE) + +#define VPD_GET_RES_LEN(p) ((unsigned int) \ + (* (SK_U8 *)&(p)[1]) |\ + ((* (SK_U8 *)&(p)[2]) << 8)) +#define VPD_GET_VPD_LEN(p) ((unsigned int)(* (SK_U8 *)&(p)[2])) +#define VPD_GET_VAL(p) ((char *)&(p)[3]) + +#define VPD_MAX_LEN 50 + +/* VPD status */ + /* bit 7..1 reserved */ +#define VPD_VALID (1<<0) /* VPD data buffer, vpd_free_ro, */ + /* and vpd_free_rw valid */ + +/* + * VPD structs + */ +typedef struct s_vpd_status { + unsigned short Align01; /* Alignment */ + unsigned short vpd_status; /* VPD status, description see above */ + int vpd_free_ro; /* unused bytes in read only area */ + int vpd_free_rw; /* bytes available in read/write area */ +} SK_VPD_STATUS; + +typedef struct s_vpd { + SK_VPD_STATUS v; /* VPD status structure */ + char vpd_buf[VPD_SIZE]; /* VPD buffer */ + int rom_size; /* VPD ROM Size from PCI_OUR_REG_2 */ + int vpd_size; /* saved VPD-size */ +} SK_VPD; + +typedef struct s_vpd_para { + unsigned int p_len; /* parameter length */ + char *p_val; /* points to the value */ +} SK_VPD_PARA; + +/* + * structure of Large Resource Type Identifiers + */ + +/* was removed because of alignment problems */ + +/* + * structure of VPD keywords + */ +typedef struct s_vpd_key { + char p_key[2]; /* 2 bytes ID string */ + unsigned char p_len; /* 1 byte length */ + char p_val; /* start of the value string */ +} SK_VPD_KEY; + + +/* + * System specific VPD macros + */ +#ifndef SKDIAG +#ifndef VPD_DO_IO +#define VPD_OUT8(pAC,IoC,Addr,Val) (void)SkPciWriteCfgByte(pAC,Addr,Val) +#define VPD_OUT16(pAC,IoC,Addr,Val) (void)SkPciWriteCfgWord(pAC,Addr,Val) +#define VPD_IN8(pAC,IoC,Addr,pVal) (void)SkPciReadCfgByte(pAC,Addr,pVal) +#define VPD_IN16(pAC,IoC,Addr,pVal) (void)SkPciReadCfgWord(pAC,Addr,pVal) +#define VPD_IN32(pAC,IoC,Addr,pVal) (void)SkPciReadCfgDWord(pAC,Addr,pVal) +#else /* VPD_DO_IO */ +#define VPD_OUT8(pAC,IoC,Addr,Val) SK_OUT8(IoC,PCI_C(Addr),Val) +#define VPD_OUT16(pAC,IoC,Addr,Val) SK_OUT16(IoC,PCI_C(Addr),Val) +#define VPD_IN8(pAC,IoC,Addr,pVal) SK_IN8(IoC,PCI_C(Addr),pVal) +#define VPD_IN16(pAC,IoC,Addr,pVal) SK_IN16(IoC,PCI_C(Addr),pVal) +#define VPD_IN32(pAC,IoC,Addr,pVal) SK_IN32(IoC,PCI_C(Addr),pVal) +#endif /* VPD_DO_IO */ +#else /* SKDIAG */ +#define VPD_OUT8(pAC,Ioc,Addr,Val) { \ + if ((pAC)->DgT.DgUseCfgCycle) \ + SkPciWriteCfgByte(pAC,Addr,Val); \ + else \ + SK_OUT8(pAC,PCI_C(Addr),Val); \ + } +#define VPD_OUT16(pAC,Ioc,Addr,Val) { \ + if ((pAC)->DgT.DgUseCfgCycle) \ + SkPciWriteCfgWord(pAC,Addr,Val); \ + else \ + SK_OUT16(pAC,PCI_C(Addr),Val); \ + } +#define VPD_IN8(pAC,Ioc,Addr,pVal) { \ + if ((pAC)->DgT.DgUseCfgCycle) \ + SkPciReadCfgByte(pAC,Addr,pVal); \ + else \ + SK_IN8(pAC,PCI_C(Addr),pVal); \ + } +#define VPD_IN16(pAC,Ioc,Addr,pVal) { \ + if ((pAC)->DgT.DgUseCfgCycle) \ + SkPciReadCfgWord(pAC,Addr,pVal); \ + else \ + SK_IN16(pAC,PCI_C(Addr),pVal); \ + } +#define VPD_IN32(pAC,Ioc,Addr,pVal) { \ + if ((pAC)->DgT.DgUseCfgCycle) \ + SkPciReadCfgDWord(pAC,Addr,pVal); \ + else \ + SK_IN32(pAC,PCI_C(Addr),pVal); \ + } +#endif /* nSKDIAG */ + +/* function prototypes ********************************************************/ + +#ifndef SK_KR_PROTO +#ifdef SKDIAG +extern SK_U32 VpdReadDWord( + SK_AC *pAC, + SK_IOC IoC, + int addr); +#endif /* SKDIAG */ + +extern SK_VPD_STATUS *VpdStat( + SK_AC *pAC, + SK_IOC IoC); + +extern int VpdKeys( + SK_AC *pAC, + SK_IOC IoC, + char *buf, + int *len, + int *elements); + +extern int VpdRead( + SK_AC *pAC, + SK_IOC IoC, + const char *key, + char *buf, + int *len); + +extern SK_BOOL VpdMayWrite( + char *key); + +extern int VpdWrite( + SK_AC *pAC, + SK_IOC IoC, + const char *key, + const char *buf); + +extern int VpdDelete( + SK_AC *pAC, + SK_IOC IoC, + char *key); + +extern int VpdUpdate( + SK_AC *pAC, + SK_IOC IoC); + +#ifdef SKDIAG +extern int VpdReadBlock( + SK_AC *pAC, + SK_IOC IoC, + char *buf, + int addr, + int len); + +extern int VpdWriteBlock( + SK_AC *pAC, + SK_IOC IoC, + char *buf, + int addr, + int len); +#endif /* SKDIAG */ +#else /* SK_KR_PROTO */ +extern SK_U32 VpdReadDWord(); +extern SK_VPD_STATUS *VpdStat(); +extern int VpdKeys(); +extern int VpdRead(); +extern SK_BOOL VpdMayWrite(); +extern int VpdWrite(); +extern int VpdDelete(); +extern int VpdUpdate(); +#endif /* SK_KR_PROTO */ + +#endif /* __INC_SKVPD_H_ */ diff --git a/drivers/net/sk98lin/h/xmac_ii.h b/drivers/net/sk98lin/h/xmac_ii.h new file mode 100644 index 000000000000..7f8e6d0084c7 --- /dev/null +++ b/drivers/net/sk98lin/h/xmac_ii.h @@ -0,0 +1,1579 @@ +/****************************************************************************** + * + * Name: xmac_ii.h + * Project: Gigabit Ethernet Adapters, Common Modules + * Version: $Revision: 1.52 $ + * Date: $Date: 2003/10/02 16:35:50 $ + * Purpose: Defines and Macros for Gigabit Ethernet Controller + * + ******************************************************************************/ + +/****************************************************************************** + * + * (C)Copyright 1998-2002 SysKonnect. + * (C)Copyright 2002-2003 Marvell. + * + * 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. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +#ifndef __INC_XMAC_H +#define __INC_XMAC_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* defines ********************************************************************/ + +/* + * XMAC II registers + * + * The XMAC registers are 16 or 32 bits wide. + * The XMACs host processor interface is set to 16 bit mode, + * therefore ALL registers will be addressed with 16 bit accesses. + * + * The following macros are provided to access the XMAC registers + * XM_IN16(), XM_OUT16, XM_IN32(), XM_OUT32(), XM_INADR(), XM_OUTADR(), + * XM_INHASH(), and XM_OUTHASH(). + * The macros are defined in SkGeHw.h. + * + * Note: NA reg = Network Address e.g DA, SA etc. + * + */ +#define XM_MMU_CMD 0x0000 /* 16 bit r/w MMU Command Register */ + /* 0x0004: reserved */ +#define XM_POFF 0x0008 /* 32 bit r/w Packet Offset Register */ +#define XM_BURST 0x000c /* 32 bit r/w Burst Register for half duplex*/ +#define XM_1L_VLAN_TAG 0x0010 /* 16 bit r/w One Level VLAN Tag ID */ +#define XM_2L_VLAN_TAG 0x0014 /* 16 bit r/w Two Level VLAN Tag ID */ + /* 0x0018 - 0x001e: reserved */ +#define XM_TX_CMD 0x0020 /* 16 bit r/w Transmit Command Register */ +#define XM_TX_RT_LIM 0x0024 /* 16 bit r/w Transmit Retry Limit Register */ +#define XM_TX_STIME 0x0028 /* 16 bit r/w Transmit Slottime Register */ +#define XM_TX_IPG 0x002c /* 16 bit r/w Transmit Inter Packet Gap */ +#define XM_RX_CMD 0x0030 /* 16 bit r/w Receive Command Register */ +#define XM_PHY_ADDR 0x0034 /* 16 bit r/w PHY Address Register */ +#define XM_PHY_DATA 0x0038 /* 16 bit r/w PHY Data Register */ + /* 0x003c: reserved */ +#define XM_GP_PORT 0x0040 /* 32 bit r/w General Purpose Port Register */ +#define XM_IMSK 0x0044 /* 16 bit r/w Interrupt Mask Register */ +#define XM_ISRC 0x0048 /* 16 bit r/o Interrupt Status Register */ +#define XM_HW_CFG 0x004c /* 16 bit r/w Hardware Config Register */ + /* 0x0050 - 0x005e: reserved */ +#define XM_TX_LO_WM 0x0060 /* 16 bit r/w Tx FIFO Low Water Mark */ +#define XM_TX_HI_WM 0x0062 /* 16 bit r/w Tx FIFO High Water Mark */ +#define XM_TX_THR 0x0064 /* 16 bit r/w Tx Request Threshold */ +#define XM_HT_THR 0x0066 /* 16 bit r/w Host Request Threshold */ +#define XM_PAUSE_DA 0x0068 /* NA reg r/w Pause Destination Address */ + /* 0x006e: reserved */ +#define XM_CTL_PARA 0x0070 /* 32 bit r/w Control Parameter Register */ +#define XM_MAC_OPCODE 0x0074 /* 16 bit r/w Opcode for MAC control frames */ +#define XM_MAC_PTIME 0x0076 /* 16 bit r/w Pause time for MAC ctrl frames*/ +#define XM_TX_STAT 0x0078 /* 32 bit r/o Tx Status LIFO Register */ + + /* 0x0080 - 0x00fc: 16 NA reg r/w Exact Match Address Registers */ + /* use the XM_EXM() macro to address */ +#define XM_EXM_START 0x0080 /* r/w Start Address of the EXM Regs */ + + /* + * XM_EXM(Reg) + * + * returns the XMAC address offset of specified Exact Match Addr Reg + * + * para: Reg EXM register to addr (0 .. 15) + * + * usage: XM_INADDR(IoC, MAC_1, XM_EXM(i), &val[i]); + */ +#define XM_EXM(Reg) (XM_EXM_START + ((Reg) << 3)) + +#define XM_SRC_CHK 0x0100 /* NA reg r/w Source Check Address Register */ +#define XM_SA 0x0108 /* NA reg r/w Station Address Register */ +#define XM_HSM 0x0110 /* 64 bit r/w Hash Match Address Registers */ +#define XM_RX_LO_WM 0x0118 /* 16 bit r/w Receive Low Water Mark */ +#define XM_RX_HI_WM 0x011a /* 16 bit r/w Receive High Water Mark */ +#define XM_RX_THR 0x011c /* 32 bit r/w Receive Request Threshold */ +#define XM_DEV_ID 0x0120 /* 32 bit r/o Device ID Register */ +#define XM_MODE 0x0124 /* 32 bit r/w Mode Register */ +#define XM_LSA 0x0128 /* NA reg r/o Last Source Register */ + /* 0x012e: reserved */ +#define XM_TS_READ 0x0130 /* 32 bit r/o Time Stamp Read Register */ +#define XM_TS_LOAD 0x0134 /* 32 bit r/o Time Stamp Load Value */ + /* 0x0138 - 0x01fe: reserved */ +#define XM_STAT_CMD 0x0200 /* 16 bit r/w Statistics Command Register */ +#define XM_RX_CNT_EV 0x0204 /* 32 bit r/o Rx Counter Event Register */ +#define XM_TX_CNT_EV 0x0208 /* 32 bit r/o Tx Counter Event Register */ +#define XM_RX_EV_MSK 0x020c /* 32 bit r/w Rx Counter Event Mask */ +#define XM_TX_EV_MSK 0x0210 /* 32 bit r/w Tx Counter Event Mask */ + /* 0x0204 - 0x027e: reserved */ +#define XM_TXF_OK 0x0280 /* 32 bit r/o Frames Transmitted OK Conuter */ +#define XM_TXO_OK_HI 0x0284 /* 32 bit r/o Octets Transmitted OK High Cnt*/ +#define XM_TXO_OK_LO 0x0288 /* 32 bit r/o Octets Transmitted OK Low Cnt */ +#define XM_TXF_BC_OK 0x028c /* 32 bit r/o Broadcast Frames Xmitted OK */ +#define XM_TXF_MC_OK 0x0290 /* 32 bit r/o Multicast Frames Xmitted OK */ +#define XM_TXF_UC_OK 0x0294 /* 32 bit r/o Unicast Frames Xmitted OK */ +#define XM_TXF_LONG 0x0298 /* 32 bit r/o Tx Long Frame Counter */ +#define XM_TXE_BURST 0x029c /* 32 bit r/o Tx Burst Event Counter */ +#define XM_TXF_MPAUSE 0x02a0 /* 32 bit r/o Tx Pause MAC Ctrl Frame Cnt */ +#define XM_TXF_MCTRL 0x02a4 /* 32 bit r/o Tx MAC Ctrl Frame Counter */ +#define XM_TXF_SNG_COL 0x02a8 /* 32 bit r/o Tx Single Collision Counter */ +#define XM_TXF_MUL_COL 0x02ac /* 32 bit r/o Tx Multiple Collision Counter */ +#define XM_TXF_ABO_COL 0x02b0 /* 32 bit r/o Tx aborted due to Exces. Col. */ +#define XM_TXF_LAT_COL 0x02b4 /* 32 bit r/o Tx Late Collision Counter */ +#define XM_TXF_DEF 0x02b8 /* 32 bit r/o Tx Deferred Frame Counter */ +#define XM_TXF_EX_DEF 0x02bc /* 32 bit r/o Tx Excessive Deferall Counter */ +#define XM_TXE_FIFO_UR 0x02c0 /* 32 bit r/o Tx FIFO Underrun Event Cnt */ +#define XM_TXE_CS_ERR 0x02c4 /* 32 bit r/o Tx Carrier Sense Error Cnt */ +#define XM_TXP_UTIL 0x02c8 /* 32 bit r/o Tx Utilization in % */ + /* 0x02cc - 0x02ce: reserved */ +#define XM_TXF_64B 0x02d0 /* 32 bit r/o 64 Byte Tx Frame Counter */ +#define XM_TXF_127B 0x02d4 /* 32 bit r/o 65-127 Byte Tx Frame Counter */ +#define XM_TXF_255B 0x02d8 /* 32 bit r/o 128-255 Byte Tx Frame Counter */ +#define XM_TXF_511B 0x02dc /* 32 bit r/o 256-511 Byte Tx Frame Counter */ +#define XM_TXF_1023B 0x02e0 /* 32 bit r/o 512-1023 Byte Tx Frame Counter*/ +#define XM_TXF_MAX_SZ 0x02e4 /* 32 bit r/o 1024-MaxSize Byte Tx Frame Cnt*/ + /* 0x02e8 - 0x02fe: reserved */ +#define XM_RXF_OK 0x0300 /* 32 bit r/o Frames Received OK */ +#define XM_RXO_OK_HI 0x0304 /* 32 bit r/o Octets Received OK High Cnt */ +#define XM_RXO_OK_LO 0x0308 /* 32 bit r/o Octets Received OK Low Counter*/ +#define XM_RXF_BC_OK 0x030c /* 32 bit r/o Broadcast Frames Received OK */ +#define XM_RXF_MC_OK 0x0310 /* 32 bit r/o Multicast Frames Received OK */ +#define XM_RXF_UC_OK 0x0314 /* 32 bit r/o Unicast Frames Received OK */ +#define XM_RXF_MPAUSE 0x0318 /* 32 bit r/o Rx Pause MAC Ctrl Frame Cnt */ +#define XM_RXF_MCTRL 0x031c /* 32 bit r/o Rx MAC Ctrl Frame Counter */ +#define XM_RXF_INV_MP 0x0320 /* 32 bit r/o Rx invalid Pause Frame Cnt */ +#define XM_RXF_INV_MOC 0x0324 /* 32 bit r/o Rx Frames with inv. MAC Opcode*/ +#define XM_RXE_BURST 0x0328 /* 32 bit r/o Rx Burst Event Counter */ +#define XM_RXE_FMISS 0x032c /* 32 bit r/o Rx Missed Frames Event Cnt */ +#define XM_RXF_FRA_ERR 0x0330 /* 32 bit r/o Rx Framing Error Counter */ +#define XM_RXE_FIFO_OV 0x0334 /* 32 bit r/o Rx FIFO overflow Event Cnt */ +#define XM_RXF_JAB_PKT 0x0338 /* 32 bit r/o Rx Jabber Packet Frame Cnt */ +#define XM_RXE_CAR_ERR 0x033c /* 32 bit r/o Rx Carrier Event Error Cnt */ +#define XM_RXF_LEN_ERR 0x0340 /* 32 bit r/o Rx in Range Length Error */ +#define XM_RXE_SYM_ERR 0x0344 /* 32 bit r/o Rx Symbol Error Counter */ +#define XM_RXE_SHT_ERR 0x0348 /* 32 bit r/o Rx Short Event Error Cnt */ +#define XM_RXE_RUNT 0x034c /* 32 bit r/o Rx Runt Event Counter */ +#define XM_RXF_LNG_ERR 0x0350 /* 32 bit r/o Rx Frame too Long Error Cnt */ +#define XM_RXF_FCS_ERR 0x0354 /* 32 bit r/o Rx Frame Check Seq. Error Cnt */ + /* 0x0358 - 0x035a: reserved */ +#define XM_RXF_CEX_ERR 0x035c /* 32 bit r/o Rx Carrier Ext Error Frame Cnt*/ +#define XM_RXP_UTIL 0x0360 /* 32 bit r/o Rx Utilization in % */ + /* 0x0364 - 0x0366: reserved */ +#define XM_RXF_64B 0x0368 /* 32 bit r/o 64 Byte Rx Frame Counter */ +#define XM_RXF_127B 0x036c /* 32 bit r/o 65-127 Byte Rx Frame Counter */ +#define XM_RXF_255B 0x0370 /* 32 bit r/o 128-255 Byte Rx Frame Counter */ +#define XM_RXF_511B 0x0374 /* 32 bit r/o 256-511 Byte Rx Frame Counter */ +#define XM_RXF_1023B 0x0378 /* 32 bit r/o 512-1023 Byte Rx Frame Counter*/ +#define XM_RXF_MAX_SZ 0x037c /* 32 bit r/o 1024-MaxSize Byte Rx Frame Cnt*/ + /* 0x02e8 - 0x02fe: reserved */ + + +/*----------------------------------------------------------------------------*/ +/* + * XMAC Bit Definitions + * + * If the bit access behaviour differs from the register access behaviour + * (r/w, r/o) this is documented after the bit number. + * The following bit access behaviours are used: + * (sc) self clearing + * (ro) read only + */ + +/* XM_MMU_CMD 16 bit r/w MMU Command Register */ + /* Bit 15..13: reserved */ +#define XM_MMU_PHY_RDY (1<<12) /* Bit 12: PHY Read Ready */ +#define XM_MMU_PHY_BUSY (1<<11) /* Bit 11: PHY Busy */ +#define XM_MMU_IGN_PF (1<<10) /* Bit 10: Ignore Pause Frame */ +#define XM_MMU_MAC_LB (1<<9) /* Bit 9: Enable MAC Loopback */ + /* Bit 8: reserved */ +#define XM_MMU_FRC_COL (1<<7) /* Bit 7: Force Collision */ +#define XM_MMU_SIM_COL (1<<6) /* Bit 6: Simulate Collision */ +#define XM_MMU_NO_PRE (1<<5) /* Bit 5: No MDIO Preamble */ +#define XM_MMU_GMII_FD (1<<4) /* Bit 4: GMII uses Full Duplex */ +#define XM_MMU_RAT_CTRL (1<<3) /* Bit 3: Enable Rate Control */ +#define XM_MMU_GMII_LOOP (1<<2) /* Bit 2: PHY is in Loopback Mode */ +#define XM_MMU_ENA_RX (1<<1) /* Bit 1: Enable Receiver */ +#define XM_MMU_ENA_TX (1<<0) /* Bit 0: Enable Transmitter */ + + +/* XM_TX_CMD 16 bit r/w Transmit Command Register */ + /* Bit 15..7: reserved */ +#define XM_TX_BK2BK (1<<6) /* Bit 6: Ignor Carrier Sense (Tx Bk2Bk)*/ +#define XM_TX_ENC_BYP (1<<5) /* Bit 5: Set Encoder in Bypass Mode */ +#define XM_TX_SAM_LINE (1<<4) /* Bit 4: (sc) Start utilization calculation */ +#define XM_TX_NO_GIG_MD (1<<3) /* Bit 3: Disable Carrier Extension */ +#define XM_TX_NO_PRE (1<<2) /* Bit 2: Disable Preamble Generation */ +#define XM_TX_NO_CRC (1<<1) /* Bit 1: Disable CRC Generation */ +#define XM_TX_AUTO_PAD (1<<0) /* Bit 0: Enable Automatic Padding */ + + +/* XM_TX_RT_LIM 16 bit r/w Transmit Retry Limit Register */ + /* Bit 15..5: reserved */ +#define XM_RT_LIM_MSK 0x1f /* Bit 4..0: Tx Retry Limit */ + + +/* XM_TX_STIME 16 bit r/w Transmit Slottime Register */ + /* Bit 15..7: reserved */ +#define XM_STIME_MSK 0x7f /* Bit 6..0: Tx Slottime bits */ + + +/* XM_TX_IPG 16 bit r/w Transmit Inter Packet Gap */ + /* Bit 15..8: reserved */ +#define XM_IPG_MSK 0xff /* Bit 7..0: IPG value bits */ + + +/* XM_RX_CMD 16 bit r/w Receive Command Register */ + /* Bit 15..9: reserved */ +#define XM_RX_LENERR_OK (1<<8) /* Bit 8 don't set Rx Err bit for */ + /* inrange error packets */ +#define XM_RX_BIG_PK_OK (1<<7) /* Bit 7 don't set Rx Err bit for */ + /* jumbo packets */ +#define XM_RX_IPG_CAP (1<<6) /* Bit 6 repl. type field with IPG */ +#define XM_RX_TP_MD (1<<5) /* Bit 5: Enable transparent Mode */ +#define XM_RX_STRIP_FCS (1<<4) /* Bit 4: Enable FCS Stripping */ +#define XM_RX_SELF_RX (1<<3) /* Bit 3: Enable Rx of own packets */ +#define XM_RX_SAM_LINE (1<<2) /* Bit 2: (sc) Start utilization calculation */ +#define XM_RX_STRIP_PAD (1<<1) /* Bit 1: Strip pad bytes of Rx frames */ +#define XM_RX_DIS_CEXT (1<<0) /* Bit 0: Disable carrier ext. check */ + + +/* XM_PHY_ADDR 16 bit r/w PHY Address Register */ + /* Bit 15..5: reserved */ +#define XM_PHY_ADDR_SZ 0x1f /* Bit 4..0: PHY Address bits */ + + +/* XM_GP_PORT 32 bit r/w General Purpose Port Register */ + /* Bit 31..7: reserved */ +#define XM_GP_ANIP (1L<<6) /* Bit 6: (ro) Auto-Neg. in progress */ +#define XM_GP_FRC_INT (1L<<5) /* Bit 5: (sc) Force Interrupt */ + /* Bit 4: reserved */ +#define XM_GP_RES_MAC (1L<<3) /* Bit 3: (sc) Reset MAC and FIFOs */ +#define XM_GP_RES_STAT (1L<<2) /* Bit 2: (sc) Reset the statistics module */ + /* Bit 1: reserved */ +#define XM_GP_INP_ASS (1L<<0) /* Bit 0: (ro) GP Input Pin asserted */ + + +/* XM_IMSK 16 bit r/w Interrupt Mask Register */ +/* XM_ISRC 16 bit r/o Interrupt Status Register */ + /* Bit 15: reserved */ +#define XM_IS_LNK_AE (1<<14) /* Bit 14: Link Asynchronous Event */ +#define XM_IS_TX_ABORT (1<<13) /* Bit 13: Transmit Abort, late Col. etc */ +#define XM_IS_FRC_INT (1<<12) /* Bit 12: Force INT bit set in GP */ +#define XM_IS_INP_ASS (1<<11) /* Bit 11: Input Asserted, GP bit 0 set */ +#define XM_IS_LIPA_RC (1<<10) /* Bit 10: Link Partner requests config */ +#define XM_IS_RX_PAGE (1<<9) /* Bit 9: Page Received */ +#define XM_IS_TX_PAGE (1<<8) /* Bit 8: Next Page Loaded for Transmit */ +#define XM_IS_AND (1<<7) /* Bit 7: Auto-Negotiation Done */ +#define XM_IS_TSC_OV (1<<6) /* Bit 6: Time Stamp Counter Overflow */ +#define XM_IS_RXC_OV (1<<5) /* Bit 5: Rx Counter Event Overflow */ +#define XM_IS_TXC_OV (1<<4) /* Bit 4: Tx Counter Event Overflow */ +#define XM_IS_RXF_OV (1<<3) /* Bit 3: Receive FIFO Overflow */ +#define XM_IS_TXF_UR (1<<2) /* Bit 2: Transmit FIFO Underrun */ +#define XM_IS_TX_COMP (1<<1) /* Bit 1: Frame Tx Complete */ +#define XM_IS_RX_COMP (1<<0) /* Bit 0: Frame Rx Complete */ + +#define XM_DEF_MSK (~(XM_IS_INP_ASS | XM_IS_LIPA_RC | XM_IS_RX_PAGE |\ + XM_IS_AND | XM_IS_RXC_OV | XM_IS_TXC_OV | XM_IS_TXF_UR)) + + +/* XM_HW_CFG 16 bit r/w Hardware Config Register */ + /* Bit 15.. 4: reserved */ +#define XM_HW_GEN_EOP (1<<3) /* Bit 3: generate End of Packet pulse */ +#define XM_HW_COM4SIG (1<<2) /* Bit 2: use Comma Detect for Sig. Det.*/ + /* Bit 1: reserved */ +#define XM_HW_GMII_MD (1<<0) /* Bit 0: GMII Interface selected */ + + +/* XM_TX_LO_WM 16 bit r/w Tx FIFO Low Water Mark */ +/* XM_TX_HI_WM 16 bit r/w Tx FIFO High Water Mark */ + /* Bit 15..10 reserved */ +#define XM_TX_WM_MSK 0x01ff /* Bit 9.. 0 Tx FIFO Watermark bits */ + +/* XM_TX_THR 16 bit r/w Tx Request Threshold */ +/* XM_HT_THR 16 bit r/w Host Request Threshold */ +/* XM_RX_THR 16 bit r/w Rx Request Threshold */ + /* Bit 15..11 reserved */ +#define XM_THR_MSK 0x03ff /* Bit 10.. 0 Rx/Tx Request Threshold bits */ + + +/* XM_TX_STAT 32 bit r/o Tx Status LIFO Register */ +#define XM_ST_VALID (1UL<<31) /* Bit 31: Status Valid */ +#define XM_ST_BYTE_CNT (0x3fffL<<17) /* Bit 30..17: Tx frame Length */ +#define XM_ST_RETRY_CNT (0x1fL<<12) /* Bit 16..12: Retry Count */ +#define XM_ST_EX_COL (1L<<11) /* Bit 11: Excessive Collisions */ +#define XM_ST_EX_DEF (1L<<10) /* Bit 10: Excessive Deferral */ +#define XM_ST_BURST (1L<<9) /* Bit 9: p. xmitted in burst md*/ +#define XM_ST_DEFER (1L<<8) /* Bit 8: packet was defered */ +#define XM_ST_BC (1L<<7) /* Bit 7: Broadcast packet */ +#define XM_ST_MC (1L<<6) /* Bit 6: Multicast packet */ +#define XM_ST_UC (1L<<5) /* Bit 5: Unicast packet */ +#define XM_ST_TX_UR (1L<<4) /* Bit 4: FIFO Underrun occured */ +#define XM_ST_CS_ERR (1L<<3) /* Bit 3: Carrier Sense Error */ +#define XM_ST_LAT_COL (1L<<2) /* Bit 2: Late Collision Error */ +#define XM_ST_MUL_COL (1L<<1) /* Bit 1: Multiple Collisions */ +#define XM_ST_SGN_COL (1L<<0) /* Bit 0: Single Collision */ + +/* XM_RX_LO_WM 16 bit r/w Receive Low Water Mark */ +/* XM_RX_HI_WM 16 bit r/w Receive High Water Mark */ + /* Bit 15..11: reserved */ +#define XM_RX_WM_MSK 0x03ff /* Bit 11.. 0: Rx FIFO Watermark bits */ + + +/* XM_DEV_ID 32 bit r/o Device ID Register */ +#define XM_DEV_OUI (0x00ffffffUL<<8) /* Bit 31..8: Device OUI */ +#define XM_DEV_REV (0x07L << 5) /* Bit 7..5: Chip Rev Num */ + + +/* XM_MODE 32 bit r/w Mode Register */ + /* Bit 31..27: reserved */ +#define XM_MD_ENA_REJ (1L<<26) /* Bit 26: Enable Frame Reject */ +#define XM_MD_SPOE_E (1L<<25) /* Bit 25: Send Pause on Edge */ + /* extern generated */ +#define XM_MD_TX_REP (1L<<24) /* Bit 24: Transmit Repeater Mode */ +#define XM_MD_SPOFF_I (1L<<23) /* Bit 23: Send Pause on FIFO full */ + /* intern generated */ +#define XM_MD_LE_STW (1L<<22) /* Bit 22: Rx Stat Word in Little Endian */ +#define XM_MD_TX_CONT (1L<<21) /* Bit 21: Send Continuous */ +#define XM_MD_TX_PAUSE (1L<<20) /* Bit 20: (sc) Send Pause Frame */ +#define XM_MD_ATS (1L<<19) /* Bit 19: Append Time Stamp */ +#define XM_MD_SPOL_I (1L<<18) /* Bit 18: Send Pause on Low */ + /* intern generated */ +#define XM_MD_SPOH_I (1L<<17) /* Bit 17: Send Pause on High */ + /* intern generated */ +#define XM_MD_CAP (1L<<16) /* Bit 16: Check Address Pair */ +#define XM_MD_ENA_HASH (1L<<15) /* Bit 15: Enable Hashing */ +#define XM_MD_CSA (1L<<14) /* Bit 14: Check Station Address */ +#define XM_MD_CAA (1L<<13) /* Bit 13: Check Address Array */ +#define XM_MD_RX_MCTRL (1L<<12) /* Bit 12: Rx MAC Control Frame */ +#define XM_MD_RX_RUNT (1L<<11) /* Bit 11: Rx Runt Frames */ +#define XM_MD_RX_IRLE (1L<<10) /* Bit 10: Rx in Range Len Err Frame */ +#define XM_MD_RX_LONG (1L<<9) /* Bit 9: Rx Long Frame */ +#define XM_MD_RX_CRCE (1L<<8) /* Bit 8: Rx CRC Error Frame */ +#define XM_MD_RX_ERR (1L<<7) /* Bit 7: Rx Error Frame */ +#define XM_MD_DIS_UC (1L<<6) /* Bit 6: Disable Rx Unicast */ +#define XM_MD_DIS_MC (1L<<5) /* Bit 5: Disable Rx Multicast */ +#define XM_MD_DIS_BC (1L<<4) /* Bit 4: Disable Rx Broadcast */ +#define XM_MD_ENA_PROM (1L<<3) /* Bit 3: Enable Promiscuous */ +#define XM_MD_ENA_BE (1L<<2) /* Bit 2: Enable Big Endian */ +#define XM_MD_FTF (1L<<1) /* Bit 1: (sc) Flush Tx FIFO */ +#define XM_MD_FRF (1L<<0) /* Bit 0: (sc) Flush Rx FIFO */ + +#define XM_PAUSE_MODE (XM_MD_SPOE_E | XM_MD_SPOL_I | XM_MD_SPOH_I) +#define XM_DEF_MODE (XM_MD_RX_RUNT | XM_MD_RX_IRLE | XM_MD_RX_LONG |\ + XM_MD_RX_CRCE | XM_MD_RX_ERR | XM_MD_CSA | XM_MD_CAA) + +/* XM_STAT_CMD 16 bit r/w Statistics Command Register */ + /* Bit 16..6: reserved */ +#define XM_SC_SNP_RXC (1<<5) /* Bit 5: (sc) Snap Rx Counters */ +#define XM_SC_SNP_TXC (1<<4) /* Bit 4: (sc) Snap Tx Counters */ +#define XM_SC_CP_RXC (1<<3) /* Bit 3: Copy Rx Counters Continuously */ +#define XM_SC_CP_TXC (1<<2) /* Bit 2: Copy Tx Counters Continuously */ +#define XM_SC_CLR_RXC (1<<1) /* Bit 1: (sc) Clear Rx Counters */ +#define XM_SC_CLR_TXC (1<<0) /* Bit 0: (sc) Clear Tx Counters */ + + +/* XM_RX_CNT_EV 32 bit r/o Rx Counter Event Register */ +/* XM_RX_EV_MSK 32 bit r/w Rx Counter Event Mask */ +#define XMR_MAX_SZ_OV (1UL<<31) /* Bit 31: 1024-MaxSize Rx Cnt Ov*/ +#define XMR_1023B_OV (1L<<30) /* Bit 30: 512-1023Byte Rx Cnt Ov*/ +#define XMR_511B_OV (1L<<29) /* Bit 29: 256-511 Byte Rx Cnt Ov*/ +#define XMR_255B_OV (1L<<28) /* Bit 28: 128-255 Byte Rx Cnt Ov*/ +#define XMR_127B_OV (1L<<27) /* Bit 27: 65-127 Byte Rx Cnt Ov */ +#define XMR_64B_OV (1L<<26) /* Bit 26: 64 Byte Rx Cnt Ov */ +#define XMR_UTIL_OV (1L<<25) /* Bit 25: Rx Util Cnt Overflow */ +#define XMR_UTIL_UR (1L<<24) /* Bit 24: Rx Util Cnt Underrun */ +#define XMR_CEX_ERR_OV (1L<<23) /* Bit 23: CEXT Err Cnt Ov */ + /* Bit 22: reserved */ +#define XMR_FCS_ERR_OV (1L<<21) /* Bit 21: Rx FCS Error Cnt Ov */ +#define XMR_LNG_ERR_OV (1L<<20) /* Bit 20: Rx too Long Err Cnt Ov*/ +#define XMR_RUNT_OV (1L<<19) /* Bit 19: Runt Event Cnt Ov */ +#define XMR_SHT_ERR_OV (1L<<18) /* Bit 18: Rx Short Ev Err Cnt Ov*/ +#define XMR_SYM_ERR_OV (1L<<17) /* Bit 17: Rx Sym Err Cnt Ov */ + /* Bit 16: reserved */ +#define XMR_CAR_ERR_OV (1L<<15) /* Bit 15: Rx Carr Ev Err Cnt Ov */ +#define XMR_JAB_PKT_OV (1L<<14) /* Bit 14: Rx Jabb Packet Cnt Ov */ +#define XMR_FIFO_OV (1L<<13) /* Bit 13: Rx FIFO Ov Ev Cnt Ov */ +#define XMR_FRA_ERR_OV (1L<<12) /* Bit 12: Rx Framing Err Cnt Ov */ +#define XMR_FMISS_OV (1L<<11) /* Bit 11: Rx Missed Ev Cnt Ov */ +#define XMR_BURST (1L<<10) /* Bit 10: Rx Burst Event Cnt Ov */ +#define XMR_INV_MOC (1L<<9) /* Bit 9: Rx with inv. MAC OC Ov*/ +#define XMR_INV_MP (1L<<8) /* Bit 8: Rx inv Pause Frame Ov */ +#define XMR_MCTRL_OV (1L<<7) /* Bit 7: Rx MAC Ctrl-F Cnt Ov */ +#define XMR_MPAUSE_OV (1L<<6) /* Bit 6: Rx Pause MAC Ctrl-F Ov*/ +#define XMR_UC_OK_OV (1L<<5) /* Bit 5: Rx Unicast Frame CntOv*/ +#define XMR_MC_OK_OV (1L<<4) /* Bit 4: Rx Multicast Cnt Ov */ +#define XMR_BC_OK_OV (1L<<3) /* Bit 3: Rx Broadcast Cnt Ov */ +#define XMR_OK_LO_OV (1L<<2) /* Bit 2: Octets Rx OK Low CntOv*/ +#define XMR_OK_HI_OV (1L<<1) /* Bit 1: Octets Rx OK Hi Cnt Ov*/ +#define XMR_OK_OV (1L<<0) /* Bit 0: Frames Received Ok Ov */ + +#define XMR_DEF_MSK (XMR_OK_LO_OV | XMR_OK_HI_OV) + +/* XM_TX_CNT_EV 32 bit r/o Tx Counter Event Register */ +/* XM_TX_EV_MSK 32 bit r/w Tx Counter Event Mask */ + /* Bit 31..26: reserved */ +#define XMT_MAX_SZ_OV (1L<<25) /* Bit 25: 1024-MaxSize Tx Cnt Ov*/ +#define XMT_1023B_OV (1L<<24) /* Bit 24: 512-1023Byte Tx Cnt Ov*/ +#define XMT_511B_OV (1L<<23) /* Bit 23: 256-511 Byte Tx Cnt Ov*/ +#define XMT_255B_OV (1L<<22) /* Bit 22: 128-255 Byte Tx Cnt Ov*/ +#define XMT_127B_OV (1L<<21) /* Bit 21: 65-127 Byte Tx Cnt Ov */ +#define XMT_64B_OV (1L<<20) /* Bit 20: 64 Byte Tx Cnt Ov */ +#define XMT_UTIL_OV (1L<<19) /* Bit 19: Tx Util Cnt Overflow */ +#define XMT_UTIL_UR (1L<<18) /* Bit 18: Tx Util Cnt Underrun */ +#define XMT_CS_ERR_OV (1L<<17) /* Bit 17: Tx Carr Sen Err Cnt Ov*/ +#define XMT_FIFO_UR_OV (1L<<16) /* Bit 16: Tx FIFO Ur Ev Cnt Ov */ +#define XMT_EX_DEF_OV (1L<<15) /* Bit 15: Tx Ex Deferall Cnt Ov */ +#define XMT_DEF (1L<<14) /* Bit 14: Tx Deferred Cnt Ov */ +#define XMT_LAT_COL_OV (1L<<13) /* Bit 13: Tx Late Col Cnt Ov */ +#define XMT_ABO_COL_OV (1L<<12) /* Bit 12: Tx abo dueto Ex Col Ov*/ +#define XMT_MUL_COL_OV (1L<<11) /* Bit 11: Tx Mult Col Cnt Ov */ +#define XMT_SNG_COL (1L<<10) /* Bit 10: Tx Single Col Cnt Ov */ +#define XMT_MCTRL_OV (1L<<9) /* Bit 9: Tx MAC Ctrl Counter Ov*/ +#define XMT_MPAUSE (1L<<8) /* Bit 8: Tx Pause MAC Ctrl-F Ov*/ +#define XMT_BURST (1L<<7) /* Bit 7: Tx Burst Event Cnt Ov */ +#define XMT_LONG (1L<<6) /* Bit 6: Tx Long Frame Cnt Ov */ +#define XMT_UC_OK_OV (1L<<5) /* Bit 5: Tx Unicast Cnt Ov */ +#define XMT_MC_OK_OV (1L<<4) /* Bit 4: Tx Multicast Cnt Ov */ +#define XMT_BC_OK_OV (1L<<3) /* Bit 3: Tx Broadcast Cnt Ov */ +#define XMT_OK_LO_OV (1L<<2) /* Bit 2: Octets Tx OK Low CntOv*/ +#define XMT_OK_HI_OV (1L<<1) /* Bit 1: Octets Tx OK Hi Cnt Ov*/ +#define XMT_OK_OV (1L<<0) /* Bit 0: Frames Tx Ok Ov */ + +#define XMT_DEF_MSK (XMT_OK_LO_OV | XMT_OK_HI_OV) + +/* + * Receive Frame Status Encoding + */ +#define XMR_FS_LEN (0x3fffUL<<18) /* Bit 31..18: Rx Frame Length */ +#define XMR_FS_2L_VLAN (1L<<17) /* Bit 17: tagged wh 2Lev VLAN ID*/ +#define XMR_FS_1L_VLAN (1L<<16) /* Bit 16: tagged wh 1Lev VLAN ID*/ +#define XMR_FS_BC (1L<<15) /* Bit 15: Broadcast Frame */ +#define XMR_FS_MC (1L<<14) /* Bit 14: Multicast Frame */ +#define XMR_FS_UC (1L<<13) /* Bit 13: Unicast Frame */ + /* Bit 12: reserved */ +#define XMR_FS_BURST (1L<<11) /* Bit 11: Burst Mode */ +#define XMR_FS_CEX_ERR (1L<<10) /* Bit 10: Carrier Ext. Error */ +#define XMR_FS_802_3 (1L<<9) /* Bit 9: 802.3 Frame */ +#define XMR_FS_COL_ERR (1L<<8) /* Bit 8: Collision Error */ +#define XMR_FS_CAR_ERR (1L<<7) /* Bit 7: Carrier Event Error */ +#define XMR_FS_LEN_ERR (1L<<6) /* Bit 6: In-Range Length Error */ +#define XMR_FS_FRA_ERR (1L<<5) /* Bit 5: Framing Error */ +#define XMR_FS_RUNT (1L<<4) /* Bit 4: Runt Frame */ +#define XMR_FS_LNG_ERR (1L<<3) /* Bit 3: Giant (Jumbo) Frame */ +#define XMR_FS_FCS_ERR (1L<<2) /* Bit 2: Frame Check Sequ Err */ +#define XMR_FS_ERR (1L<<1) /* Bit 1: Frame Error */ +#define XMR_FS_MCTRL (1L<<0) /* Bit 0: MAC Control Packet */ + +/* + * XMR_FS_ERR will be set if + * XMR_FS_FCS_ERR, XMR_FS_LNG_ERR, XMR_FS_RUNT, + * XMR_FS_FRA_ERR, XMR_FS_LEN_ERR, or XMR_FS_CEX_ERR + * is set. XMR_FS_LNG_ERR and XMR_FS_LEN_ERR will issue + * XMR_FS_ERR unless the corresponding bit in the Receive Command + * Register is set. + */ +#define XMR_FS_ANY_ERR XMR_FS_ERR + +/*----------------------------------------------------------------------------*/ +/* + * XMAC-PHY Registers, indirect addressed over the XMAC + */ +#define PHY_XMAC_CTRL 0x00 /* 16 bit r/w PHY Control Register */ +#define PHY_XMAC_STAT 0x01 /* 16 bit r/w PHY Status Register */ +#define PHY_XMAC_ID0 0x02 /* 16 bit r/o PHY ID0 Register */ +#define PHY_XMAC_ID1 0x03 /* 16 bit r/o PHY ID1 Register */ +#define PHY_XMAC_AUNE_ADV 0x04 /* 16 bit r/w Auto-Neg. Advertisement */ +#define PHY_XMAC_AUNE_LP 0x05 /* 16 bit r/o Link Partner Abi Reg */ +#define PHY_XMAC_AUNE_EXP 0x06 /* 16 bit r/o Auto-Neg. Expansion Reg */ +#define PHY_XMAC_NEPG 0x07 /* 16 bit r/w Next Page Register */ +#define PHY_XMAC_NEPG_LP 0x08 /* 16 bit r/o Next Page Link Partner */ + /* 0x09 - 0x0e: reserved */ +#define PHY_XMAC_EXT_STAT 0x0f /* 16 bit r/o Ext Status Register */ +#define PHY_XMAC_RES_ABI 0x10 /* 16 bit r/o PHY Resolved Ability */ + +/*----------------------------------------------------------------------------*/ +/* + * Broadcom-PHY Registers, indirect addressed over XMAC + */ +#define PHY_BCOM_CTRL 0x00 /* 16 bit r/w PHY Control Register */ +#define PHY_BCOM_STAT 0x01 /* 16 bit r/o PHY Status Register */ +#define PHY_BCOM_ID0 0x02 /* 16 bit r/o PHY ID0 Register */ +#define PHY_BCOM_ID1 0x03 /* 16 bit r/o PHY ID1 Register */ +#define PHY_BCOM_AUNE_ADV 0x04 /* 16 bit r/w Auto-Neg. Advertisement */ +#define PHY_BCOM_AUNE_LP 0x05 /* 16 bit r/o Link Part Ability Reg */ +#define PHY_BCOM_AUNE_EXP 0x06 /* 16 bit r/o Auto-Neg. Expansion Reg */ +#define PHY_BCOM_NEPG 0x07 /* 16 bit r/w Next Page Register */ +#define PHY_BCOM_NEPG_LP 0x08 /* 16 bit r/o Next Page Link Partner */ + /* Broadcom-specific registers */ +#define PHY_BCOM_1000T_CTRL 0x09 /* 16 bit r/w 1000Base-T Ctrl Reg */ +#define PHY_BCOM_1000T_STAT 0x0a /* 16 bit r/o 1000Base-T Status Reg */ + /* 0x0b - 0x0e: reserved */ +#define PHY_BCOM_EXT_STAT 0x0f /* 16 bit r/o Extended Status Reg */ +#define PHY_BCOM_P_EXT_CTRL 0x10 /* 16 bit r/w PHY Extended Ctrl Reg */ +#define PHY_BCOM_P_EXT_STAT 0x11 /* 16 bit r/o PHY Extended Stat Reg */ +#define PHY_BCOM_RE_CTR 0x12 /* 16 bit r/w Receive Error Counter */ +#define PHY_BCOM_FC_CTR 0x13 /* 16 bit r/w False Carrier Sense Cnt */ +#define PHY_BCOM_RNO_CTR 0x14 /* 16 bit r/w Receiver NOT_OK Cnt */ + /* 0x15 - 0x17: reserved */ +#define PHY_BCOM_AUX_CTRL 0x18 /* 16 bit r/w Auxiliary Control Reg */ +#define PHY_BCOM_AUX_STAT 0x19 /* 16 bit r/o Auxiliary Stat Summary */ +#define PHY_BCOM_INT_STAT 0x1a /* 16 bit r/o Interrupt Status Reg */ +#define PHY_BCOM_INT_MASK 0x1b /* 16 bit r/w Interrupt Mask Reg */ + /* 0x1c: reserved */ + /* 0x1d - 0x1f: test registers */ + +/*----------------------------------------------------------------------------*/ +/* + * Marvel-PHY Registers, indirect addressed over GMAC + */ +#define PHY_MARV_CTRL 0x00 /* 16 bit r/w PHY Control Register */ +#define PHY_MARV_STAT 0x01 /* 16 bit r/o PHY Status Register */ +#define PHY_MARV_ID0 0x02 /* 16 bit r/o PHY ID0 Register */ +#define PHY_MARV_ID1 0x03 /* 16 bit r/o PHY ID1 Register */ +#define PHY_MARV_AUNE_ADV 0x04 /* 16 bit r/w Auto-Neg. Advertisement */ +#define PHY_MARV_AUNE_LP 0x05 /* 16 bit r/o Link Part Ability Reg */ +#define PHY_MARV_AUNE_EXP 0x06 /* 16 bit r/o Auto-Neg. Expansion Reg */ +#define PHY_MARV_NEPG 0x07 /* 16 bit r/w Next Page Register */ +#define PHY_MARV_NEPG_LP 0x08 /* 16 bit r/o Next Page Link Partner */ + /* Marvel-specific registers */ +#define PHY_MARV_1000T_CTRL 0x09 /* 16 bit r/w 1000Base-T Ctrl Reg */ +#define PHY_MARV_1000T_STAT 0x0a /* 16 bit r/o 1000Base-T Status Reg */ + /* 0x0b - 0x0e: reserved */ +#define PHY_MARV_EXT_STAT 0x0f /* 16 bit r/o Extended Status Reg */ +#define PHY_MARV_PHY_CTRL 0x10 /* 16 bit r/w PHY Specific Ctrl Reg */ +#define PHY_MARV_PHY_STAT 0x11 /* 16 bit r/o PHY Specific Stat Reg */ +#define PHY_MARV_INT_MASK 0x12 /* 16 bit r/w Interrupt Mask Reg */ +#define PHY_MARV_INT_STAT 0x13 /* 16 bit r/o Interrupt Status Reg */ +#define PHY_MARV_EXT_CTRL 0x14 /* 16 bit r/w Ext. PHY Specific Ctrl */ +#define PHY_MARV_RXE_CNT 0x15 /* 16 bit r/w Receive Error Counter */ +#define PHY_MARV_EXT_ADR 0x16 /* 16 bit r/w Ext. Ad. for Cable Diag. */ + /* 0x17: reserved */ +#define PHY_MARV_LED_CTRL 0x18 /* 16 bit r/w LED Control Reg */ +#define PHY_MARV_LED_OVER 0x19 /* 16 bit r/w Manual LED Override Reg */ +#define PHY_MARV_EXT_CTRL_2 0x1a /* 16 bit r/w Ext. PHY Specific Ctrl 2 */ +#define PHY_MARV_EXT_P_STAT 0x1b /* 16 bit r/w Ext. PHY Spec. Stat Reg */ +#define PHY_MARV_CABLE_DIAG 0x1c /* 16 bit r/o Cable Diagnostic Reg */ + /* 0x1d - 0x1f: reserved */ + +/*----------------------------------------------------------------------------*/ +/* + * Level One-PHY Registers, indirect addressed over XMAC + */ +#define PHY_LONE_CTRL 0x00 /* 16 bit r/w PHY Control Register */ +#define PHY_LONE_STAT 0x01 /* 16 bit r/o PHY Status Register */ +#define PHY_LONE_ID0 0x02 /* 16 bit r/o PHY ID0 Register */ +#define PHY_LONE_ID1 0x03 /* 16 bit r/o PHY ID1 Register */ +#define PHY_LONE_AUNE_ADV 0x04 /* 16 bit r/w Auto-Neg. Advertisement */ +#define PHY_LONE_AUNE_LP 0x05 /* 16 bit r/o Link Part Ability Reg */ +#define PHY_LONE_AUNE_EXP 0x06 /* 16 bit r/o Auto-Neg. Expansion Reg */ +#define PHY_LONE_NEPG 0x07 /* 16 bit r/w Next Page Register */ +#define PHY_LONE_NEPG_LP 0x08 /* 16 bit r/o Next Page Link Partner */ + /* Level One-specific registers */ +#define PHY_LONE_1000T_CTRL 0x09 /* 16 bit r/w 1000Base-T Control Reg*/ +#define PHY_LONE_1000T_STAT 0x0a /* 16 bit r/o 1000Base-T Status Reg */ + /* 0x0b -0x0e: reserved */ +#define PHY_LONE_EXT_STAT 0x0f /* 16 bit r/o Extended Status Reg */ +#define PHY_LONE_PORT_CFG 0x10 /* 16 bit r/w Port Configuration Reg*/ +#define PHY_LONE_Q_STAT 0x11 /* 16 bit r/o Quick Status Reg */ +#define PHY_LONE_INT_ENAB 0x12 /* 16 bit r/w Interrupt Enable Reg */ +#define PHY_LONE_INT_STAT 0x13 /* 16 bit r/o Interrupt Status Reg */ +#define PHY_LONE_LED_CFG 0x14 /* 16 bit r/w LED Configuration Reg */ +#define PHY_LONE_PORT_CTRL 0x15 /* 16 bit r/w Port Control Reg */ +#define PHY_LONE_CIM 0x16 /* 16 bit r/o CIM Reg */ + /* 0x17 -0x1c: reserved */ + +/*----------------------------------------------------------------------------*/ +/* + * National-PHY Registers, indirect addressed over XMAC + */ +#define PHY_NAT_CTRL 0x00 /* 16 bit r/w PHY Control Register */ +#define PHY_NAT_STAT 0x01 /* 16 bit r/w PHY Status Register */ +#define PHY_NAT_ID0 0x02 /* 16 bit r/o PHY ID0 Register */ +#define PHY_NAT_ID1 0x03 /* 16 bit r/o PHY ID1 Register */ +#define PHY_NAT_AUNE_ADV 0x04 /* 16 bit r/w Auto-Neg. Advertisement */ +#define PHY_NAT_AUNE_LP 0x05 /* 16 bit r/o Link Partner Ability Reg */ +#define PHY_NAT_AUNE_EXP 0x06 /* 16 bit r/o Auto-Neg. Expansion Reg */ +#define PHY_NAT_NEPG 0x07 /* 16 bit r/w Next Page Register */ +#define PHY_NAT_NEPG_LP 0x08 /* 16 bit r/o Next Page Link Partner Reg */ + /* National-specific registers */ +#define PHY_NAT_1000T_CTRL 0x09 /* 16 bit r/w 1000Base-T Control Reg */ +#define PHY_NAT_1000T_STAT 0x0a /* 16 bit r/o 1000Base-T Status Reg */ + /* 0x0b -0x0e: reserved */ +#define PHY_NAT_EXT_STAT 0x0f /* 16 bit r/o Extended Status Register */ +#define PHY_NAT_EXT_CTRL1 0x10 /* 16 bit r/o Extended Control Reg1 */ +#define PHY_NAT_Q_STAT1 0x11 /* 16 bit r/o Quick Status Reg1 */ +#define PHY_NAT_10B_OP 0x12 /* 16 bit r/o 10Base-T Operations Reg */ +#define PHY_NAT_EXT_CTRL2 0x13 /* 16 bit r/o Extended Control Reg1 */ +#define PHY_NAT_Q_STAT2 0x14 /* 16 bit r/o Quick Status Reg2 */ + /* 0x15 -0x18: reserved */ +#define PHY_NAT_PHY_ADDR 0x19 /* 16 bit r/o PHY Address Register */ + + +/*----------------------------------------------------------------------------*/ + +/* + * PHY bit definitions + * Bits defined as PHY_X_..., PHY_B_..., PHY_L_... or PHY_N_... are + * XMAC/Broadcom/LevelOne/National/Marvell-specific. + * All other are general. + */ + +/***** PHY_XMAC_CTRL 16 bit r/w PHY Control Register *****/ +/***** PHY_BCOM_CTRL 16 bit r/w PHY Control Register *****/ +/***** PHY_MARV_CTRL 16 bit r/w PHY Status Register *****/ +/***** PHY_LONE_CTRL 16 bit r/w PHY Control Register *****/ +#define PHY_CT_RESET (1<<15) /* Bit 15: (sc) clear all PHY related regs */ +#define PHY_CT_LOOP (1<<14) /* Bit 14: enable Loopback over PHY */ +#define PHY_CT_SPS_LSB (1<<13) /* Bit 13: (BC,L1) Speed select, lower bit */ +#define PHY_CT_ANE (1<<12) /* Bit 12: Auto-Negotiation Enabled */ +#define PHY_CT_PDOWN (1<<11) /* Bit 11: (BC,L1) Power Down Mode */ +#define PHY_CT_ISOL (1<<10) /* Bit 10: (BC,L1) Isolate Mode */ +#define PHY_CT_RE_CFG (1<<9) /* Bit 9: (sc) Restart Auto-Negotiation */ +#define PHY_CT_DUP_MD (1<<8) /* Bit 8: Duplex Mode */ +#define PHY_CT_COL_TST (1<<7) /* Bit 7: (BC,L1) Collision Test enabled */ +#define PHY_CT_SPS_MSB (1<<6) /* Bit 6: (BC,L1) Speed select, upper bit */ + /* Bit 5..0: reserved */ + +#define PHY_CT_SP1000 PHY_CT_SPS_MSB /* enable speed of 1000 Mbps */ +#define PHY_CT_SP100 PHY_CT_SPS_LSB /* enable speed of 100 Mbps */ +#define PHY_CT_SP10 (0) /* enable speed of 10 Mbps */ + + +/***** PHY_XMAC_STAT 16 bit r/w PHY Status Register *****/ +/***** PHY_BCOM_STAT 16 bit r/w PHY Status Register *****/ +/***** PHY_MARV_STAT 16 bit r/w PHY Status Register *****/ +/***** PHY_LONE_STAT 16 bit r/w PHY Status Register *****/ + /* Bit 15..9: reserved */ + /* (BC/L1) 100/10 Mbps cap bits ignored*/ +#define PHY_ST_EXT_ST (1<<8) /* Bit 8: Extended Status Present */ + /* Bit 7: reserved */ +#define PHY_ST_PRE_SUP (1<<6) /* Bit 6: (BC/L1) preamble suppression */ +#define PHY_ST_AN_OVER (1<<5) /* Bit 5: Auto-Negotiation Over */ +#define PHY_ST_REM_FLT (1<<4) /* Bit 4: Remote Fault Condition Occured */ +#define PHY_ST_AN_CAP (1<<3) /* Bit 3: Auto-Negotiation Capability */ +#define PHY_ST_LSYNC (1<<2) /* Bit 2: Link Synchronized */ +#define PHY_ST_JAB_DET (1<<1) /* Bit 1: (BC/L1) Jabber Detected */ +#define PHY_ST_EXT_REG (1<<0) /* Bit 0: Extended Register available */ + + +/***** PHY_XMAC_ID1 16 bit r/o PHY ID1 Register */ +/***** PHY_BCOM_ID1 16 bit r/o PHY ID1 Register */ +/***** PHY_MARV_ID1 16 bit r/o PHY ID1 Register */ +/***** PHY_LONE_ID1 16 bit r/o PHY ID1 Register */ +#define PHY_I1_OUI_MSK (0x3f<<10) /* Bit 15..10: Organization Unique ID */ +#define PHY_I1_MOD_NUM (0x3f<<4) /* Bit 9.. 4: Model Number */ +#define PHY_I1_REV_MSK 0x0f /* Bit 3.. 0: Revision Number */ + +/* different Broadcom PHY Ids */ +#define PHY_BCOM_ID1_A1 0x6041 +#define PHY_BCOM_ID1_B2 0x6043 +#define PHY_BCOM_ID1_C0 0x6044 +#define PHY_BCOM_ID1_C5 0x6047 + + +/***** PHY_XMAC_AUNE_ADV 16 bit r/w Auto-Negotiation Advertisement *****/ +/***** PHY_XMAC_AUNE_LP 16 bit r/o Link Partner Ability Reg *****/ +#define PHY_AN_NXT_PG (1<<15) /* Bit 15: Request Next Page */ +#define PHY_X_AN_ACK (1<<14) /* Bit 14: (ro) Acknowledge Received */ +#define PHY_X_AN_RFB (3<<12) /* Bit 13..12: Remote Fault Bits */ + /* Bit 11.. 9: reserved */ +#define PHY_X_AN_PAUSE (3<<7) /* Bit 8.. 7: Pause Bits */ +#define PHY_X_AN_HD (1<<6) /* Bit 6: Half Duplex */ +#define PHY_X_AN_FD (1<<5) /* Bit 5: Full Duplex */ + /* Bit 4.. 0: reserved */ + +/***** PHY_BCOM_AUNE_ADV 16 bit r/w Auto-Negotiation Advertisement *****/ +/***** PHY_BCOM_AUNE_LP 16 bit r/o Link Partner Ability Reg *****/ +/* PHY_AN_NXT_PG (see XMAC) Bit 15: Request Next Page */ + /* Bit 14: reserved */ +#define PHY_B_AN_RF (1<<13) /* Bit 13: Remote Fault */ + /* Bit 12: reserved */ +#define PHY_B_AN_ASP (1<<11) /* Bit 11: Asymmetric Pause */ +#define PHY_B_AN_PC (1<<10) /* Bit 10: Pause Capable */ + /* Bit 9..5: 100/10 BT cap bits ingnored */ +#define PHY_B_AN_SEL 0x1f /* Bit 4..0: Selector Field, 00001=Ethernet*/ + +/***** PHY_LONE_AUNE_ADV 16 bit r/w Auto-Negotiation Advertisement *****/ +/***** PHY_LONE_AUNE_LP 16 bit r/o Link Partner Ability Reg *****/ +/* PHY_AN_NXT_PG (see XMAC) Bit 15: Request Next Page */ + /* Bit 14: reserved */ +#define PHY_L_AN_RF (1<<13) /* Bit 13: Remote Fault */ + /* Bit 12: reserved */ +#define PHY_L_AN_ASP (1<<11) /* Bit 11: Asymmetric Pause */ +#define PHY_L_AN_PC (1<<10) /* Bit 10: Pause Capable */ + /* Bit 9..5: 100/10 BT cap bits ingnored */ +#define PHY_L_AN_SEL 0x1f /* Bit 4..0: Selector Field, 00001=Ethernet*/ + +/***** PHY_NAT_AUNE_ADV 16 bit r/w Auto-Negotiation Advertisement *****/ +/***** PHY_NAT_AUNE_LP 16 bit r/o Link Partner Ability Reg *****/ +/* PHY_AN_NXT_PG (see XMAC) Bit 15: Request Next Page */ + /* Bit 14: reserved */ +#define PHY_N_AN_RF (1<<13) /* Bit 13: Remote Fault */ + /* Bit 12: reserved */ +#define PHY_N_AN_100F (1<<11) /* Bit 11: 100Base-T2 FD Support */ +#define PHY_N_AN_100H (1<<10) /* Bit 10: 100Base-T2 HD Support */ + /* Bit 9..5: 100/10 BT cap bits ingnored */ +#define PHY_N_AN_SEL 0x1f /* Bit 4..0: Selector Field, 00001=Ethernet*/ + +/* field type definition for PHY_x_AN_SEL */ +#define PHY_SEL_TYPE 0x01 /* 00001 = Ethernet */ + +/***** PHY_XMAC_AUNE_EXP 16 bit r/o Auto-Negotiation Expansion Reg *****/ + /* Bit 15..4: reserved */ +#define PHY_ANE_LP_NP (1<<3) /* Bit 3: Link Partner can Next Page */ +#define PHY_ANE_LOC_NP (1<<2) /* Bit 2: Local PHY can Next Page */ +#define PHY_ANE_RX_PG (1<<1) /* Bit 1: Page Received */ + /* Bit 0: reserved */ + +/***** PHY_BCOM_AUNE_EXP 16 bit r/o Auto-Negotiation Expansion Reg *****/ +/***** PHY_LONE_AUNE_EXP 16 bit r/o Auto-Negotiation Expansion Reg *****/ +/***** PHY_MARV_AUNE_EXP 16 bit r/o Auto-Negotiation Expansion Reg *****/ + /* Bit 15..5: reserved */ +#define PHY_ANE_PAR_DF (1<<4) /* Bit 4: Parallel Detection Fault */ +/* PHY_ANE_LP_NP (see XMAC) Bit 3: Link Partner can Next Page */ +/* PHY_ANE_LOC_NP (see XMAC) Bit 2: Local PHY can Next Page */ +/* PHY_ANE_RX_PG (see XMAC) Bit 1: Page Received */ +#define PHY_ANE_LP_CAP (1<<0) /* Bit 0: Link Partner Auto-Neg. Cap. */ + +/***** PHY_XMAC_NEPG 16 bit r/w Next Page Register *****/ +/***** PHY_BCOM_NEPG 16 bit r/w Next Page Register *****/ +/***** PHY_LONE_NEPG 16 bit r/w Next Page Register *****/ +/***** PHY_XMAC_NEPG_LP 16 bit r/o Next Page Link Partner *****/ +/***** PHY_BCOM_NEPG_LP 16 bit r/o Next Page Link Partner *****/ +/***** PHY_LONE_NEPG_LP 16 bit r/o Next Page Link Partner *****/ +#define PHY_NP_MORE (1<<15) /* Bit 15: More, Next Pages to follow */ +#define PHY_NP_ACK1 (1<<14) /* Bit 14: (ro) Ack1, for receiving a message */ +#define PHY_NP_MSG_VAL (1<<13) /* Bit 13: Message Page valid */ +#define PHY_NP_ACK2 (1<<12) /* Bit 12: Ack2, comply with msg content */ +#define PHY_NP_TOG (1<<11) /* Bit 11: Toggle Bit, ensure sync */ +#define PHY_NP_MSG 0x07ff /* Bit 10..0: Message from/to Link Partner */ + +/* + * XMAC-Specific + */ +/***** PHY_XMAC_EXT_STAT 16 bit r/w Extended Status Register *****/ +#define PHY_X_EX_FD (1<<15) /* Bit 15: Device Supports Full Duplex */ +#define PHY_X_EX_HD (1<<14) /* Bit 14: Device Supports Half Duplex */ + /* Bit 13..0: reserved */ + +/***** PHY_XMAC_RES_ABI 16 bit r/o PHY Resolved Ability *****/ + /* Bit 15..9: reserved */ +#define PHY_X_RS_PAUSE (3<<7) /* Bit 8..7: selected Pause Mode */ +#define PHY_X_RS_HD (1<<6) /* Bit 6: Half Duplex Mode selected */ +#define PHY_X_RS_FD (1<<5) /* Bit 5: Full Duplex Mode selected */ +#define PHY_X_RS_ABLMIS (1<<4) /* Bit 4: duplex or pause cap mismatch */ +#define PHY_X_RS_PAUMIS (1<<3) /* Bit 3: pause capability mismatch */ + /* Bit 2..0: reserved */ +/* + * Remote Fault Bits (PHY_X_AN_RFB) encoding + */ +#define X_RFB_OK (0<<12) /* Bit 13..12 No errors, Link OK */ +#define X_RFB_LF (1<<12) /* Bit 13..12 Link Failure */ +#define X_RFB_OFF (2<<12) /* Bit 13..12 Offline */ +#define X_RFB_AN_ERR (3<<12) /* Bit 13..12 Auto-Negotiation Error */ + +/* + * Pause Bits (PHY_X_AN_PAUSE and PHY_X_RS_PAUSE) encoding + */ +#define PHY_X_P_NO_PAUSE (0<<7) /* Bit 8..7: no Pause Mode */ +#define PHY_X_P_SYM_MD (1<<7) /* Bit 8..7: symmetric Pause Mode */ +#define PHY_X_P_ASYM_MD (2<<7) /* Bit 8..7: asymmetric Pause Mode */ +#define PHY_X_P_BOTH_MD (3<<7) /* Bit 8..7: both Pause Mode */ + + +/* + * Broadcom-Specific + */ +/***** PHY_BCOM_1000T_CTRL 16 bit r/w 1000Base-T Control Reg *****/ +#define PHY_B_1000C_TEST (7<<13) /* Bit 15..13: Test Modes */ +#define PHY_B_1000C_MSE (1<<12) /* Bit 12: Master/Slave Enable */ +#define PHY_B_1000C_MSC (1<<11) /* Bit 11: M/S Configuration */ +#define PHY_B_1000C_RD (1<<10) /* Bit 10: Repeater/DTE */ +#define PHY_B_1000C_AFD (1<<9) /* Bit 9: Advertise Full Duplex */ +#define PHY_B_1000C_AHD (1<<8) /* Bit 8: Advertise Half Duplex */ + /* Bit 7..0: reserved */ + +/***** PHY_BCOM_1000T_STAT 16 bit r/o 1000Base-T Status Reg *****/ +/***** PHY_MARV_1000T_STAT 16 bit r/o 1000Base-T Status Reg *****/ +#define PHY_B_1000S_MSF (1<<15) /* Bit 15: Master/Slave Fault */ +#define PHY_B_1000S_MSR (1<<14) /* Bit 14: Master/Slave Result */ +#define PHY_B_1000S_LRS (1<<13) /* Bit 13: Local Receiver Status */ +#define PHY_B_1000S_RRS (1<<12) /* Bit 12: Remote Receiver Status */ +#define PHY_B_1000S_LP_FD (1<<11) /* Bit 11: Link Partner can FD */ +#define PHY_B_1000S_LP_HD (1<<10) /* Bit 10: Link Partner can HD */ + /* Bit 9..8: reserved */ +#define PHY_B_1000S_IEC 0xff /* Bit 7..0: Idle Error Count */ + +/***** PHY_BCOM_EXT_STAT 16 bit r/o Extended Status Register *****/ +#define PHY_B_ES_X_FD_CAP (1<<15) /* Bit 15: 1000Base-X FD capable */ +#define PHY_B_ES_X_HD_CAP (1<<14) /* Bit 14: 1000Base-X HD capable */ +#define PHY_B_ES_T_FD_CAP (1<<13) /* Bit 13: 1000Base-T FD capable */ +#define PHY_B_ES_T_HD_CAP (1<<12) /* Bit 12: 1000Base-T HD capable */ + /* Bit 11..0: reserved */ + +/***** PHY_BCOM_P_EXT_CTRL 16 bit r/w PHY Extended Control Reg *****/ +#define PHY_B_PEC_MAC_PHY (1<<15) /* Bit 15: 10BIT/GMI-Interface */ +#define PHY_B_PEC_DIS_CROSS (1<<14) /* Bit 14: Disable MDI Crossover */ +#define PHY_B_PEC_TX_DIS (1<<13) /* Bit 13: Tx output Disabled */ +#define PHY_B_PEC_INT_DIS (1<<12) /* Bit 12: Interrupts Disabled */ +#define PHY_B_PEC_F_INT (1<<11) /* Bit 11: Force Interrupt */ +#define PHY_B_PEC_BY_45 (1<<10) /* Bit 10: Bypass 4B5B-Decoder */ +#define PHY_B_PEC_BY_SCR (1<<9) /* Bit 9: Bypass Scrambler */ +#define PHY_B_PEC_BY_MLT3 (1<<8) /* Bit 8: Bypass MLT3 Encoder */ +#define PHY_B_PEC_BY_RXA (1<<7) /* Bit 7: Bypass Rx Alignm. */ +#define PHY_B_PEC_RES_SCR (1<<6) /* Bit 6: Reset Scrambler */ +#define PHY_B_PEC_EN_LTR (1<<5) /* Bit 5: Ena LED Traffic Mode */ +#define PHY_B_PEC_LED_ON (1<<4) /* Bit 4: Force LED's on */ +#define PHY_B_PEC_LED_OFF (1<<3) /* Bit 3: Force LED's off */ +#define PHY_B_PEC_EX_IPG (1<<2) /* Bit 2: Extend Tx IPG Mode */ +#define PHY_B_PEC_3_LED (1<<1) /* Bit 1: Three Link LED mode */ +#define PHY_B_PEC_HIGH_LA (1<<0) /* Bit 0: GMII FIFO Elasticy */ + +/***** PHY_BCOM_P_EXT_STAT 16 bit r/o PHY Extended Status Reg *****/ + /* Bit 15..14: reserved */ +#define PHY_B_PES_CROSS_STAT (1<<13) /* Bit 13: MDI Crossover Status */ +#define PHY_B_PES_INT_STAT (1<<12) /* Bit 12: Interrupt Status */ +#define PHY_B_PES_RRS (1<<11) /* Bit 11: Remote Receiver Stat. */ +#define PHY_B_PES_LRS (1<<10) /* Bit 10: Local Receiver Stat. */ +#define PHY_B_PES_LOCKED (1<<9) /* Bit 9: Locked */ +#define PHY_B_PES_LS (1<<8) /* Bit 8: Link Status */ +#define PHY_B_PES_RF (1<<7) /* Bit 7: Remote Fault */ +#define PHY_B_PES_CE_ER (1<<6) /* Bit 6: Carrier Ext Error */ +#define PHY_B_PES_BAD_SSD (1<<5) /* Bit 5: Bad SSD */ +#define PHY_B_PES_BAD_ESD (1<<4) /* Bit 4: Bad ESD */ +#define PHY_B_PES_RX_ER (1<<3) /* Bit 3: Receive Error */ +#define PHY_B_PES_TX_ER (1<<2) /* Bit 2: Transmit Error */ +#define PHY_B_PES_LOCK_ER (1<<1) /* Bit 1: Lock Error */ +#define PHY_B_PES_MLT3_ER (1<<0) /* Bit 0: MLT3 code Error */ + +/***** PHY_BCOM_FC_CTR 16 bit r/w False Carrier Counter *****/ + /* Bit 15..8: reserved */ +#define PHY_B_FC_CTR 0xff /* Bit 7..0: False Carrier Counter */ + +/***** PHY_BCOM_RNO_CTR 16 bit r/w Receive NOT_OK Counter *****/ +#define PHY_B_RC_LOC_MSK 0xff00 /* Bit 15..8: Local Rx NOT_OK cnt */ +#define PHY_B_RC_REM_MSK 0x00ff /* Bit 7..0: Remote Rx NOT_OK cnt */ + +/***** PHY_BCOM_AUX_CTRL 16 bit r/w Auxiliary Control Reg *****/ +#define PHY_B_AC_L_SQE (1<<15) /* Bit 15: Low Squelch */ +#define PHY_B_AC_LONG_PACK (1<<14) /* Bit 14: Rx Long Packets */ +#define PHY_B_AC_ER_CTRL (3<<12) /* Bit 13..12: Edgerate Control */ + /* Bit 11: reserved */ +#define PHY_B_AC_TX_TST (1<<10) /* Bit 10: Tx test bit, always 1 */ + /* Bit 9.. 8: reserved */ +#define PHY_B_AC_DIS_PRF (1<<7) /* Bit 7: dis part resp filter */ + /* Bit 6: reserved */ +#define PHY_B_AC_DIS_PM (1<<5) /* Bit 5: dis power management */ + /* Bit 4: reserved */ +#define PHY_B_AC_DIAG (1<<3) /* Bit 3: Diagnostic Mode */ + /* Bit 2.. 0: reserved */ + +/***** PHY_BCOM_AUX_STAT 16 bit r/o Auxiliary Status Reg *****/ +#define PHY_B_AS_AN_C (1<<15) /* Bit 15: AutoNeg complete */ +#define PHY_B_AS_AN_CA (1<<14) /* Bit 14: AN Complete Ack */ +#define PHY_B_AS_ANACK_D (1<<13) /* Bit 13: AN Ack Detect */ +#define PHY_B_AS_ANAB_D (1<<12) /* Bit 12: AN Ability Detect */ +#define PHY_B_AS_NPW (1<<11) /* Bit 11: AN Next Page Wait */ +#define PHY_B_AS_AN_RES_MSK (7<<8) /* Bit 10..8: AN HDC */ +#define PHY_B_AS_PDF (1<<7) /* Bit 7: Parallel Detect. Fault */ +#define PHY_B_AS_RF (1<<6) /* Bit 6: Remote Fault */ +#define PHY_B_AS_ANP_R (1<<5) /* Bit 5: AN Page Received */ +#define PHY_B_AS_LP_ANAB (1<<4) /* Bit 4: LP AN Ability */ +#define PHY_B_AS_LP_NPAB (1<<3) /* Bit 3: LP Next Page Ability */ +#define PHY_B_AS_LS (1<<2) /* Bit 2: Link Status */ +#define PHY_B_AS_PRR (1<<1) /* Bit 1: Pause Resolution-Rx */ +#define PHY_B_AS_PRT (1<<0) /* Bit 0: Pause Resolution-Tx */ + +#define PHY_B_AS_PAUSE_MSK (PHY_B_AS_PRR | PHY_B_AS_PRT) + +/***** PHY_BCOM_INT_STAT 16 bit r/o Interrupt Status Reg *****/ +/***** PHY_BCOM_INT_MASK 16 bit r/w Interrupt Mask Reg *****/ + /* Bit 15: reserved */ +#define PHY_B_IS_PSE (1<<14) /* Bit 14: Pair Swap Error */ +#define PHY_B_IS_MDXI_SC (1<<13) /* Bit 13: MDIX Status Change */ +#define PHY_B_IS_HCT (1<<12) /* Bit 12: counter above 32k */ +#define PHY_B_IS_LCT (1<<11) /* Bit 11: counter above 128 */ +#define PHY_B_IS_AN_PR (1<<10) /* Bit 10: Page Received */ +#define PHY_B_IS_NO_HDCL (1<<9) /* Bit 9: No HCD Link */ +#define PHY_B_IS_NO_HDC (1<<8) /* Bit 8: No HCD */ +#define PHY_B_IS_NEG_USHDC (1<<7) /* Bit 7: Negotiated Unsup. HCD */ +#define PHY_B_IS_SCR_S_ER (1<<6) /* Bit 6: Scrambler Sync Error */ +#define PHY_B_IS_RRS_CHANGE (1<<5) /* Bit 5: Remote Rx Stat Change */ +#define PHY_B_IS_LRS_CHANGE (1<<4) /* Bit 4: Local Rx Stat Change */ +#define PHY_B_IS_DUP_CHANGE (1<<3) /* Bit 3: Duplex Mode Change */ +#define PHY_B_IS_LSP_CHANGE (1<<2) /* Bit 2: Link Speed Change */ +#define PHY_B_IS_LST_CHANGE (1<<1) /* Bit 1: Link Status Changed */ +#define PHY_B_IS_CRC_ER (1<<0) /* Bit 0: CRC Error */ + +#define PHY_B_DEF_MSK (~(PHY_B_IS_AN_PR | PHY_B_IS_LST_CHANGE)) + +/* Pause Bits (PHY_B_AN_ASP and PHY_B_AN_PC) encoding */ +#define PHY_B_P_NO_PAUSE (0<<10) /* Bit 11..10: no Pause Mode */ +#define PHY_B_P_SYM_MD (1<<10) /* Bit 11..10: symmetric Pause Mode */ +#define PHY_B_P_ASYM_MD (2<<10) /* Bit 11..10: asymmetric Pause Mode */ +#define PHY_B_P_BOTH_MD (3<<10) /* Bit 11..10: both Pause Mode */ + +/* + * Resolved Duplex mode and Capabilities (Aux Status Summary Reg) + */ +#define PHY_B_RES_1000FD (7<<8) /* Bit 10..8: 1000Base-T Full Dup. */ +#define PHY_B_RES_1000HD (6<<8) /* Bit 10..8: 1000Base-T Half Dup. */ +/* others: 100/10: invalid for us */ + +/* + * Level One-Specific + */ +/***** PHY_LONE_1000T_CTRL 16 bit r/w 1000Base-T Control Reg *****/ +#define PHY_L_1000C_TEST (7<<13) /* Bit 15..13: Test Modes */ +#define PHY_L_1000C_MSE (1<<12) /* Bit 12: Master/Slave Enable */ +#define PHY_L_1000C_MSC (1<<11) /* Bit 11: M/S Configuration */ +#define PHY_L_1000C_RD (1<<10) /* Bit 10: Repeater/DTE */ +#define PHY_L_1000C_AFD (1<<9) /* Bit 9: Advertise Full Duplex */ +#define PHY_L_1000C_AHD (1<<8) /* Bit 8: Advertise Half Duplex */ + /* Bit 7..0: reserved */ + +/***** PHY_LONE_1000T_STAT 16 bit r/o 1000Base-T Status Reg *****/ +#define PHY_L_1000S_MSF (1<<15) /* Bit 15: Master/Slave Fault */ +#define PHY_L_1000S_MSR (1<<14) /* Bit 14: Master/Slave Result */ +#define PHY_L_1000S_LRS (1<<13) /* Bit 13: Local Receiver Status */ +#define PHY_L_1000S_RRS (1<<12) /* Bit 12: Remote Receiver Status */ +#define PHY_L_1000S_LP_FD (1<<11) /* Bit 11: Link Partner can FD */ +#define PHY_L_1000S_LP_HD (1<<10) /* Bit 10: Link Partner can HD */ + /* Bit 9..8: reserved */ +#define PHY_B_1000S_IEC 0xff /* Bit 7..0: Idle Error Count */ + +/***** PHY_LONE_EXT_STAT 16 bit r/o Extended Status Register *****/ +#define PHY_L_ES_X_FD_CAP (1<<15) /* Bit 15: 1000Base-X FD capable */ +#define PHY_L_ES_X_HD_CAP (1<<14) /* Bit 14: 1000Base-X HD capable */ +#define PHY_L_ES_T_FD_CAP (1<<13) /* Bit 13: 1000Base-T FD capable */ +#define PHY_L_ES_T_HD_CAP (1<<12) /* Bit 12: 1000Base-T HD capable */ + /* Bit 11..0: reserved */ + +/***** PHY_LONE_PORT_CFG 16 bit r/w Port Configuration Reg *****/ +#define PHY_L_PC_REP_MODE (1<<15) /* Bit 15: Repeater Mode */ + /* Bit 14: reserved */ +#define PHY_L_PC_TX_DIS (1<<13) /* Bit 13: Tx output Disabled */ +#define PHY_L_PC_BY_SCR (1<<12) /* Bit 12: Bypass Scrambler */ +#define PHY_L_PC_BY_45 (1<<11) /* Bit 11: Bypass 4B5B-Decoder */ +#define PHY_L_PC_JAB_DIS (1<<10) /* Bit 10: Jabber Disabled */ +#define PHY_L_PC_SQE (1<<9) /* Bit 9: Enable Heartbeat */ +#define PHY_L_PC_TP_LOOP (1<<8) /* Bit 8: TP Loopback */ +#define PHY_L_PC_SSS (1<<7) /* Bit 7: Smart Speed Selection */ +#define PHY_L_PC_FIFO_SIZE (1<<6) /* Bit 6: FIFO Size */ +#define PHY_L_PC_PRE_EN (1<<5) /* Bit 5: Preamble Enable */ +#define PHY_L_PC_CIM (1<<4) /* Bit 4: Carrier Integrity Mon */ +#define PHY_L_PC_10_SER (1<<3) /* Bit 3: Use Serial Output */ +#define PHY_L_PC_ANISOL (1<<2) /* Bit 2: Unisolate Port */ +#define PHY_L_PC_TEN_BIT (1<<1) /* Bit 1: 10bit iface mode on */ +#define PHY_L_PC_ALTCLOCK (1<<0) /* Bit 0: (ro) ALTCLOCK Mode on */ + +/***** PHY_LONE_Q_STAT 16 bit r/o Quick Status Reg *****/ +#define PHY_L_QS_D_RATE (3<<14) /* Bit 15..14: Data Rate */ +#define PHY_L_QS_TX_STAT (1<<13) /* Bit 13: Transmitting */ +#define PHY_L_QS_RX_STAT (1<<12) /* Bit 12: Receiving */ +#define PHY_L_QS_COL_STAT (1<<11) /* Bit 11: Collision */ +#define PHY_L_QS_L_STAT (1<<10) /* Bit 10: Link is up */ +#define PHY_L_QS_DUP_MOD (1<<9) /* Bit 9: Full/Half Duplex */ +#define PHY_L_QS_AN (1<<8) /* Bit 8: AutoNeg is On */ +#define PHY_L_QS_AN_C (1<<7) /* Bit 7: AN is Complete */ +#define PHY_L_QS_LLE (7<<4) /* Bit 6: Line Length Estim. */ +#define PHY_L_QS_PAUSE (1<<3) /* Bit 3: LP advertised Pause */ +#define PHY_L_QS_AS_PAUSE (1<<2) /* Bit 2: LP adv. asym. Pause */ +#define PHY_L_QS_ISOLATE (1<<1) /* Bit 1: CIM Isolated */ +#define PHY_L_QS_EVENT (1<<0) /* Bit 0: Event has occurred */ + +/***** PHY_LONE_INT_ENAB 16 bit r/w Interrupt Enable Reg *****/ +/***** PHY_LONE_INT_STAT 16 bit r/o Interrupt Status Reg *****/ + /* Bit 15..14: reserved */ +#define PHY_L_IS_AN_F (1<<13) /* Bit 13: Auto-Negotiation fault */ + /* Bit 12: not described */ +#define PHY_L_IS_CROSS (1<<11) /* Bit 11: Crossover used */ +#define PHY_L_IS_POL (1<<10) /* Bit 10: Polarity correct. used */ +#define PHY_L_IS_SS (1<<9) /* Bit 9: Smart Speed Downgrade */ +#define PHY_L_IS_CFULL (1<<8) /* Bit 8: Counter Full */ +#define PHY_L_IS_AN_C (1<<7) /* Bit 7: AutoNeg Complete */ +#define PHY_L_IS_SPEED (1<<6) /* Bit 6: Speed Changed */ +#define PHY_L_IS_DUP (1<<5) /* Bit 5: Duplex Changed */ +#define PHY_L_IS_LS (1<<4) /* Bit 4: Link Status Changed */ +#define PHY_L_IS_ISOL (1<<3) /* Bit 3: Isolate Occured */ +#define PHY_L_IS_MDINT (1<<2) /* Bit 2: (ro) STAT: MII Int Pending */ +#define PHY_L_IS_INTEN (1<<1) /* Bit 1: ENAB: Enable IRQs */ +#define PHY_L_IS_FORCE (1<<0) /* Bit 0: ENAB: Force Interrupt */ + +/* int. mask */ +#define PHY_L_DEF_MSK (PHY_L_IS_LS | PHY_L_IS_ISOL | PHY_L_IS_INTEN) + +/***** PHY_LONE_LED_CFG 16 bit r/w LED Configuration Reg *****/ +#define PHY_L_LC_LEDC (3<<14) /* Bit 15..14: Col/Blink/On/Off */ +#define PHY_L_LC_LEDR (3<<12) /* Bit 13..12: Rx/Blink/On/Off */ +#define PHY_L_LC_LEDT (3<<10) /* Bit 11..10: Tx/Blink/On/Off */ +#define PHY_L_LC_LEDG (3<<8) /* Bit 9..8: Giga/Blink/On/Off */ +#define PHY_L_LC_LEDS (3<<6) /* Bit 7..6: 10-100/Blink/On/Off */ +#define PHY_L_LC_LEDL (3<<4) /* Bit 5..4: Link/Blink/On/Off */ +#define PHY_L_LC_LEDF (3<<2) /* Bit 3..2: Duplex/Blink/On/Off */ +#define PHY_L_LC_PSTRECH (1<<1) /* Bit 1: Strech LED Pulses */ +#define PHY_L_LC_FREQ (1<<0) /* Bit 0: 30/100 ms */ + +/***** PHY_LONE_PORT_CTRL 16 bit r/w Port Control Reg *****/ +#define PHY_L_PC_TX_TCLK (1<<15) /* Bit 15: Enable TX_TCLK */ + /* Bit 14: reserved */ +#define PHY_L_PC_ALT_NP (1<<13) /* Bit 14: Alternate Next Page */ +#define PHY_L_PC_GMII_ALT (1<<12) /* Bit 13: Alternate GMII driver */ + /* Bit 11: reserved */ +#define PHY_L_PC_TEN_CRS (1<<10) /* Bit 10: Extend CRS*/ + /* Bit 9..0: not described */ + +/***** PHY_LONE_CIM 16 bit r/o CIM Reg *****/ +#define PHY_L_CIM_ISOL (255<<8)/* Bit 15..8: Isolate Count */ +#define PHY_L_CIM_FALSE_CAR (255<<0)/* Bit 7..0: False Carrier Count */ + + +/* + * Pause Bits (PHY_L_AN_ASP and PHY_L_AN_PC) encoding + */ +#define PHY_L_P_NO_PAUSE (0<<10) /* Bit 11..10: no Pause Mode */ +#define PHY_L_P_SYM_MD (1<<10) /* Bit 11..10: symmetric Pause Mode */ +#define PHY_L_P_ASYM_MD (2<<10) /* Bit 11..10: asymmetric Pause Mode */ +#define PHY_L_P_BOTH_MD (3<<10) /* Bit 11..10: both Pause Mode */ + + +/* + * National-Specific + */ +/***** PHY_NAT_1000T_CTRL 16 bit r/w 1000Base-T Control Reg *****/ +#define PHY_N_1000C_TEST (7<<13) /* Bit 15..13: Test Modes */ +#define PHY_N_1000C_MSE (1<<12) /* Bit 12: Master/Slave Enable */ +#define PHY_N_1000C_MSC (1<<11) /* Bit 11: M/S Configuration */ +#define PHY_N_1000C_RD (1<<10) /* Bit 10: Repeater/DTE */ +#define PHY_N_1000C_AFD (1<<9) /* Bit 9: Advertise Full Duplex */ +#define PHY_N_1000C_AHD (1<<8) /* Bit 8: Advertise Half Duplex */ +#define PHY_N_1000C_APC (1<<7) /* Bit 7: Asymmetric Pause Cap. */ + /* Bit 6..0: reserved */ + +/***** PHY_NAT_1000T_STAT 16 bit r/o 1000Base-T Status Reg *****/ +#define PHY_N_1000S_MSF (1<<15) /* Bit 15: Master/Slave Fault */ +#define PHY_N_1000S_MSR (1<<14) /* Bit 14: Master/Slave Result */ +#define PHY_N_1000S_LRS (1<<13) /* Bit 13: Local Receiver Status */ +#define PHY_N_1000S_RRS (1<<12) /* Bit 12: Remote Receiver Status*/ +#define PHY_N_1000S_LP_FD (1<<11) /* Bit 11: Link Partner can FD */ +#define PHY_N_1000S_LP_HD (1<<10) /* Bit 10: Link Partner can HD */ +#define PHY_N_1000C_LP_APC (1<<9) /* Bit 9: LP Asym. Pause Cap. */ + /* Bit 8: reserved */ +#define PHY_N_1000S_IEC 0xff /* Bit 7..0: Idle Error Count */ + +/***** PHY_NAT_EXT_STAT 16 bit r/o Extended Status Register *****/ +#define PHY_N_ES_X_FD_CAP (1<<15) /* Bit 15: 1000Base-X FD capable */ +#define PHY_N_ES_X_HD_CAP (1<<14) /* Bit 14: 1000Base-X HD capable */ +#define PHY_N_ES_T_FD_CAP (1<<13) /* Bit 13: 1000Base-T FD capable */ +#define PHY_N_ES_T_HD_CAP (1<<12) /* Bit 12: 1000Base-T HD capable */ + /* Bit 11..0: reserved */ + +/* todo: those are still missing */ +/***** PHY_NAT_EXT_CTRL1 16 bit r/o Extended Control Reg1 *****/ +/***** PHY_NAT_Q_STAT1 16 bit r/o Quick Status Reg1 *****/ +/***** PHY_NAT_10B_OP 16 bit r/o 10Base-T Operations Reg *****/ +/***** PHY_NAT_EXT_CTRL2 16 bit r/o Extended Control Reg1 *****/ +/***** PHY_NAT_Q_STAT2 16 bit r/o Quick Status Reg2 *****/ +/***** PHY_NAT_PHY_ADDR 16 bit r/o PHY Address Register *****/ + +/* + * Marvell-Specific + */ +/***** PHY_MARV_AUNE_ADV 16 bit r/w Auto-Negotiation Advertisement *****/ +/***** PHY_MARV_AUNE_LP 16 bit r/w Link Part Ability Reg *****/ +#define PHY_M_AN_NXT_PG BIT_15 /* Request Next Page */ +#define PHY_M_AN_ACK BIT_14 /* (ro) Acknowledge Received */ +#define PHY_M_AN_RF BIT_13 /* Remote Fault */ + /* Bit 12: reserved */ +#define PHY_M_AN_ASP BIT_11 /* Asymmetric Pause */ +#define PHY_M_AN_PC BIT_10 /* MAC Pause implemented */ +#define PHY_M_AN_100_FD BIT_8 /* Advertise 100Base-TX Full Duplex */ +#define PHY_M_AN_100_HD BIT_7 /* Advertise 100Base-TX Half Duplex */ +#define PHY_M_AN_10_FD BIT_6 /* Advertise 10Base-TX Full Duplex */ +#define PHY_M_AN_10_HD BIT_5 /* Advertise 10Base-TX Half Duplex */ + +/* special defines for FIBER (88E1011S only) */ +#define PHY_M_AN_ASP_X BIT_8 /* Asymmetric Pause */ +#define PHY_M_AN_PC_X BIT_7 /* MAC Pause implemented */ +#define PHY_M_AN_1000X_AHD BIT_6 /* Advertise 10000Base-X Half Duplex */ +#define PHY_M_AN_1000X_AFD BIT_5 /* Advertise 10000Base-X Full Duplex */ + +/* Pause Bits (PHY_M_AN_ASP_X and PHY_M_AN_PC_X) encoding */ +#define PHY_M_P_NO_PAUSE_X (0<<7) /* Bit 8.. 7: no Pause Mode */ +#define PHY_M_P_SYM_MD_X (1<<7) /* Bit 8.. 7: symmetric Pause Mode */ +#define PHY_M_P_ASYM_MD_X (2<<7) /* Bit 8.. 7: asymmetric Pause Mode */ +#define PHY_M_P_BOTH_MD_X (3<<7) /* Bit 8.. 7: both Pause Mode */ + +/***** PHY_MARV_1000T_CTRL 16 bit r/w 1000Base-T Control Reg *****/ +#define PHY_M_1000C_TEST (7<<13) /* Bit 15..13: Test Modes */ +#define PHY_M_1000C_MSE (1<<12) /* Bit 12: Manual Master/Slave Enable */ +#define PHY_M_1000C_MSC (1<<11) /* Bit 11: M/S Configuration (1=Master) */ +#define PHY_M_1000C_MPD (1<<10) /* Bit 10: Multi-Port Device */ +#define PHY_M_1000C_AFD (1<<9) /* Bit 9: Advertise Full Duplex */ +#define PHY_M_1000C_AHD (1<<8) /* Bit 8: Advertise Half Duplex */ + /* Bit 7..0: reserved */ + +/***** PHY_MARV_PHY_CTRL 16 bit r/w PHY Specific Ctrl Reg *****/ +#define PHY_M_PC_TX_FFD_MSK (3<<14) /* Bit 15..14: Tx FIFO Depth Mask */ +#define PHY_M_PC_RX_FFD_MSK (3<<12) /* Bit 13..12: Rx FIFO Depth Mask */ +#define PHY_M_PC_ASS_CRS_TX (1<<11) /* Bit 11: Assert CRS on Transmit */ +#define PHY_M_PC_FL_GOOD (1<<10) /* Bit 10: Force Link Good */ +#define PHY_M_PC_EN_DET_MSK (3<<8) /* Bit 9.. 8: Energy Detect Mask */ +#define PHY_M_PC_ENA_EXT_D (1<<7) /* Bit 7: Enable Ext. Distance (10BT) */ +#define PHY_M_PC_MDIX_MSK (3<<5) /* Bit 6.. 5: MDI/MDIX Config. Mask */ +#define PHY_M_PC_DIS_125CLK (1<<4) /* Bit 4: Disable 125 CLK */ +#define PHY_M_PC_MAC_POW_UP (1<<3) /* Bit 3: MAC Power up */ +#define PHY_M_PC_SQE_T_ENA (1<<2) /* Bit 2: SQE Test Enabled */ +#define PHY_M_PC_POL_R_DIS (1<<1) /* Bit 1: Polarity Reversal Disabled */ +#define PHY_M_PC_DIS_JABBER (1<<0) /* Bit 0: Disable Jabber */ + +#define PHY_M_PC_EN_DET SHIFT8(2) /* Energy Detect (Mode 1) */ +#define PHY_M_PC_EN_DET_PLUS SHIFT8(3) /* Energy Detect Plus (Mode 2) */ + +#define PHY_M_PC_MDI_XMODE(x) SHIFT5(x) +#define PHY_M_PC_MAN_MDI 0 /* 00 = Manual MDI configuration */ +#define PHY_M_PC_MAN_MDIX 1 /* 01 = Manual MDIX configuration */ +#define PHY_M_PC_ENA_AUTO 3 /* 11 = Enable Automatic Crossover */ + +/***** PHY_MARV_PHY_STAT 16 bit r/o PHY Specific Status Reg *****/ +#define PHY_M_PS_SPEED_MSK (3<<14) /* Bit 15..14: Speed Mask */ +#define PHY_M_PS_SPEED_1000 (1<<15) /* 10 = 1000 Mbps */ +#define PHY_M_PS_SPEED_100 (1<<14) /* 01 = 100 Mbps */ +#define PHY_M_PS_SPEED_10 0 /* 00 = 10 Mbps */ +#define PHY_M_PS_FULL_DUP (1<<13) /* Bit 13: Full Duplex */ +#define PHY_M_PS_PAGE_REC (1<<12) /* Bit 12: Page Received */ +#define PHY_M_PS_SPDUP_RES (1<<11) /* Bit 11: Speed & Duplex Resolved */ +#define PHY_M_PS_LINK_UP (1<<10) /* Bit 10: Link Up */ +#define PHY_M_PS_CABLE_MSK (3<<7) /* Bit 9.. 7: Cable Length Mask */ +#define PHY_M_PS_MDI_X_STAT (1<<6) /* Bit 6: MDI Crossover Stat (1=MDIX) */ +#define PHY_M_PS_DOWNS_STAT (1<<5) /* Bit 5: Downshift Status (1=downsh.) */ +#define PHY_M_PS_ENDET_STAT (1<<4) /* Bit 4: Energy Detect Status (1=act) */ +#define PHY_M_PS_TX_P_EN (1<<3) /* Bit 3: Tx Pause Enabled */ +#define PHY_M_PS_RX_P_EN (1<<2) /* Bit 2: Rx Pause Enabled */ +#define PHY_M_PS_POL_REV (1<<1) /* Bit 1: Polarity Reversed */ +#define PHY_M_PC_JABBER (1<<0) /* Bit 0: Jabber */ + +#define PHY_M_PS_PAUSE_MSK (PHY_M_PS_TX_P_EN | PHY_M_PS_RX_P_EN) + +/***** PHY_MARV_INT_MASK 16 bit r/w Interrupt Mask Reg *****/ +/***** PHY_MARV_INT_STAT 16 bit r/o Interrupt Status Reg *****/ +#define PHY_M_IS_AN_ERROR (1<<15) /* Bit 15: Auto-Negotiation Error */ +#define PHY_M_IS_LSP_CHANGE (1<<14) /* Bit 14: Link Speed Changed */ +#define PHY_M_IS_DUP_CHANGE (1<<13) /* Bit 13: Duplex Mode Changed */ +#define PHY_M_IS_AN_PR (1<<12) /* Bit 12: Page Received */ +#define PHY_M_IS_AN_COMPL (1<<11) /* Bit 11: Auto-Negotiation Completed */ +#define PHY_M_IS_LST_CHANGE (1<<10) /* Bit 10: Link Status Changed */ +#define PHY_M_IS_SYMB_ERROR (1<<9) /* Bit 9: Symbol Error */ +#define PHY_M_IS_FALSE_CARR (1<<8) /* Bit 8: False Carrier */ +#define PHY_M_IS_FIFO_ERROR (1<<7) /* Bit 7: FIFO Overflow/Underrun Error */ +#define PHY_M_IS_MDI_CHANGE (1<<6) /* Bit 6: MDI Crossover Changed */ +#define PHY_M_IS_DOWNSH_DET (1<<5) /* Bit 5: Downshift Detected */ +#define PHY_M_IS_END_CHANGE (1<<4) /* Bit 4: Energy Detect Changed */ + /* Bit 3..2: reserved */ +#define PHY_M_IS_POL_CHANGE (1<<1) /* Bit 1: Polarity Changed */ +#define PHY_M_IS_JABBER (1<<0) /* Bit 0: Jabber */ + +#define PHY_M_DEF_MSK (PHY_M_IS_AN_ERROR | PHY_M_IS_AN_PR | \ + PHY_M_IS_LST_CHANGE | PHY_M_IS_FIFO_ERROR) + +/***** PHY_MARV_EXT_CTRL 16 bit r/w Ext. PHY Specific Ctrl *****/ +#define PHY_M_EC_M_DSC_MSK (3<<10) /* Bit 11..10: Master downshift counter */ +#define PHY_M_EC_S_DSC_MSK (3<<8) /* Bit 9.. 8: Slave downshift counter */ +#define PHY_M_EC_MAC_S_MSK (7<<4) /* Bit 6.. 4: Def. MAC interface speed */ +#define PHY_M_EC_FIB_AN_ENA (1<<3) /* Bit 3: Fiber Auto-Neg. Enable */ + +#define PHY_M_EC_M_DSC(x) SHIFT10(x) /* 00=1x; 01=2x; 10=3x; 11=4x */ +#define PHY_M_EC_S_DSC(x) SHIFT8(x) /* 00=dis; 01=1x; 10=2x; 11=3x */ +#define PHY_M_EC_MAC_S(x) SHIFT4(x) /* 01X=0; 110=2.5; 111=25 (MHz) */ + +#define MAC_TX_CLK_0_MHZ 2 +#define MAC_TX_CLK_2_5_MHZ 6 +#define MAC_TX_CLK_25_MHZ 7 + +/***** PHY_MARV_LED_CTRL 16 bit r/w LED Control Reg *****/ +#define PHY_M_LEDC_DIS_LED (1<<15) /* Bit 15: Disable LED */ +#define PHY_M_LEDC_PULS_MSK (7<<12) /* Bit 14..12: Pulse Stretch Mask */ +#define PHY_M_LEDC_F_INT (1<<11) /* Bit 11: Force Interrupt */ +#define PHY_M_LEDC_BL_R_MSK (7<<8) /* Bit 10.. 8: Blink Rate Mask */ + /* Bit 7.. 5: reserved */ +#define PHY_M_LEDC_LINK_MSK (3<<3) /* Bit 4.. 3: Link Control Mask */ +#define PHY_M_LEDC_DP_CTRL (1<<2) /* Bit 2: Duplex Control */ +#define PHY_M_LEDC_RX_CTRL (1<<1) /* Bit 1: Rx activity / Link */ +#define PHY_M_LEDC_TX_CTRL (1<<0) /* Bit 0: Tx activity / Link */ + +#define PHY_M_LED_PULS_DUR(x) SHIFT12(x) /* Pulse Stretch Duration */ + +#define PULS_NO_STR 0 /* no pulse stretching */ +#define PULS_21MS 1 /* 21 ms to 42 ms */ +#define PULS_42MS 2 /* 42 ms to 84 ms */ +#define PULS_84MS 3 /* 84 ms to 170 ms */ +#define PULS_170MS 4 /* 170 ms to 340 ms */ +#define PULS_340MS 5 /* 340 ms to 670 ms */ +#define PULS_670MS 6 /* 670 ms to 1.3 s */ +#define PULS_1300MS 7 /* 1.3 s to 2.7 s */ + +#define PHY_M_LED_BLINK_RT(x) SHIFT8(x) /* Blink Rate */ + +#define BLINK_42MS 0 /* 42 ms */ +#define BLINK_84MS 1 /* 84 ms */ +#define BLINK_170MS 2 /* 170 ms */ +#define BLINK_340MS 3 /* 340 ms */ +#define BLINK_670MS 4 /* 670 ms */ + /* values 5 - 7: reserved */ + +/***** PHY_MARV_LED_OVER 16 bit r/w Manual LED Override Reg *****/ +#define PHY_M_LED_MO_DUP(x) SHIFT10(x) /* Bit 11..10: Duplex */ +#define PHY_M_LED_MO_10(x) SHIFT8(x) /* Bit 9.. 8: Link 10 */ +#define PHY_M_LED_MO_100(x) SHIFT6(x) /* Bit 7.. 6: Link 100 */ +#define PHY_M_LED_MO_1000(x) SHIFT4(x) /* Bit 5.. 4: Link 1000 */ +#define PHY_M_LED_MO_RX(x) SHIFT2(x) /* Bit 3.. 2: Rx */ +#define PHY_M_LED_MO_TX(x) SHIFT0(x) /* Bit 1.. 0: Tx */ + +#define MO_LED_NORM 0 +#define MO_LED_BLINK 1 +#define MO_LED_OFF 2 +#define MO_LED_ON 3 + +/***** PHY_MARV_EXT_CTRL_2 16 bit r/w Ext. PHY Specific Ctrl 2 *****/ + /* Bit 15.. 7: reserved */ +#define PHY_M_EC2_FI_IMPED (1<<6) /* Bit 6: Fiber Input Impedance */ +#define PHY_M_EC2_FO_IMPED (1<<5) /* Bit 5: Fiber Output Impedance */ +#define PHY_M_EC2_FO_M_CLK (1<<4) /* Bit 4: Fiber Mode Clock Enable */ +#define PHY_M_EC2_FO_BOOST (1<<3) /* Bit 3: Fiber Output Boost */ +#define PHY_M_EC2_FO_AM_MSK 7 /* Bit 2.. 0: Fiber Output Amplitude */ + +/***** PHY_MARV_EXT_P_STAT 16 bit r/w Ext. PHY Specific Status *****/ +#define PHY_M_FC_AUTO_SEL (1<<15) /* Bit 15: Fiber/Copper Auto Sel. dis. */ +#define PHY_M_FC_AN_REG_ACC (1<<14) /* Bit 14: Fiber/Copper Autoneg. reg acc */ +#define PHY_M_FC_RESULUTION (1<<13) /* Bit 13: Fiber/Copper Resulution */ +#define PHY_M_SER_IF_AN_BP (1<<12) /* Bit 12: Ser IF autoneg. bypass enable */ +#define PHY_M_SER_IF_BP_ST (1<<11) /* Bit 11: Ser IF autoneg. bypass status */ +#define PHY_M_IRQ_POLARITY (1<<10) /* Bit 10: IRQ polarity */ + /* Bit 9..4: reserved */ +#define PHY_M_UNDOC1 (1<< 7) /* undocumented bit !! */ +#define PHY_M_MODE_MASK (0xf<<0)/* Bit 3..0: copy of HWCFG MODE[3:0] */ + + +/***** PHY_MARV_CABLE_DIAG 16 bit r/o Cable Diagnostic Reg *****/ +#define PHY_M_CABD_ENA_TEST (1<<15) /* Bit 15: Enable Test */ +#define PHY_M_CABD_STAT_MSK (3<<13) /* Bit 14..13: Status */ + /* Bit 12.. 8: reserved */ +#define PHY_M_CABD_DIST_MSK 0xff /* Bit 7.. 0: Distance */ + +/* values for Cable Diagnostic Status (11=fail; 00=OK; 10=open; 01=short) */ +#define CABD_STAT_NORMAL 0 +#define CABD_STAT_SHORT 1 +#define CABD_STAT_OPEN 2 +#define CABD_STAT_FAIL 3 + + +/* + * GMAC registers + * + * The GMAC registers are 16 or 32 bits wide. + * The GMACs host processor interface is 16 bits wide, + * therefore ALL registers will be addressed with 16 bit accesses. + * + * The following macros are provided to access the GMAC registers + * GM_IN16(), GM_OUT16, GM_IN32(), GM_OUT32(), GM_INADR(), GM_OUTADR(), + * GM_INHASH(), and GM_OUTHASH(). + * The macros are defined in SkGeHw.h. + * + * Note: NA reg = Network Address e.g DA, SA etc. + * + */ + +/* Port Registers */ +#define GM_GP_STAT 0x0000 /* 16 bit r/o General Purpose Status */ +#define GM_GP_CTRL 0x0004 /* 16 bit r/w General Purpose Control */ +#define GM_TX_CTRL 0x0008 /* 16 bit r/w Transmit Control Reg. */ +#define GM_RX_CTRL 0x000c /* 16 bit r/w Receive Control Reg. */ +#define GM_TX_FLOW_CTRL 0x0010 /* 16 bit r/w Transmit Flow-Control */ +#define GM_TX_PARAM 0x0014 /* 16 bit r/w Transmit Parameter Reg. */ +#define GM_SERIAL_MODE 0x0018 /* 16 bit r/w Serial Mode Register */ + +/* Source Address Registers */ +#define GM_SRC_ADDR_1L 0x001c /* 16 bit r/w Source Address 1 (low) */ +#define GM_SRC_ADDR_1M 0x0020 /* 16 bit r/w Source Address 1 (middle) */ +#define GM_SRC_ADDR_1H 0x0024 /* 16 bit r/w Source Address 1 (high) */ +#define GM_SRC_ADDR_2L 0x0028 /* 16 bit r/w Source Address 2 (low) */ +#define GM_SRC_ADDR_2M 0x002c /* 16 bit r/w Source Address 2 (middle) */ +#define GM_SRC_ADDR_2H 0x0030 /* 16 bit r/w Source Address 2 (high) */ + +/* Multicast Address Hash Registers */ +#define GM_MC_ADDR_H1 0x0034 /* 16 bit r/w Multicast Address Hash 1 */ +#define GM_MC_ADDR_H2 0x0038 /* 16 bit r/w Multicast Address Hash 2 */ +#define GM_MC_ADDR_H3 0x003c /* 16 bit r/w Multicast Address Hash 3 */ +#define GM_MC_ADDR_H4 0x0040 /* 16 bit r/w Multicast Address Hash 4 */ + +/* Interrupt Source Registers */ +#define GM_TX_IRQ_SRC 0x0044 /* 16 bit r/o Tx Overflow IRQ Source */ +#define GM_RX_IRQ_SRC 0x0048 /* 16 bit r/o Rx Overflow IRQ Source */ +#define GM_TR_IRQ_SRC 0x004c /* 16 bit r/o Tx/Rx Over. IRQ Source */ + +/* Interrupt Mask Registers */ +#define GM_TX_IRQ_MSK 0x0050 /* 16 bit r/w Tx Overflow IRQ Mask */ +#define GM_RX_IRQ_MSK 0x0054 /* 16 bit r/w Rx Overflow IRQ Mask */ +#define GM_TR_IRQ_MSK 0x0058 /* 16 bit r/w Tx/Rx Over. IRQ Mask */ + +/* Serial Management Interface (SMI) Registers */ +#define GM_SMI_CTRL 0x0080 /* 16 bit r/w SMI Control Register */ +#define GM_SMI_DATA 0x0084 /* 16 bit r/w SMI Data Register */ +#define GM_PHY_ADDR 0x0088 /* 16 bit r/w GPHY Address Register */ + +/* MIB Counters */ +#define GM_MIB_CNT_BASE 0x0100 /* Base Address of MIB Counters */ +#define GM_MIB_CNT_SIZE 44 /* Number of MIB Counters */ + +/* + * MIB Counters base address definitions (low word) - + * use offset 4 for access to high word (32 bit r/o) + */ +#define GM_RXF_UC_OK \ + (GM_MIB_CNT_BASE + 0) /* Unicast Frames Received OK */ +#define GM_RXF_BC_OK \ + (GM_MIB_CNT_BASE + 8) /* Broadcast Frames Received OK */ +#define GM_RXF_MPAUSE \ + (GM_MIB_CNT_BASE + 16) /* Pause MAC Ctrl Frames Received */ +#define GM_RXF_MC_OK \ + (GM_MIB_CNT_BASE + 24) /* Multicast Frames Received OK */ +#define GM_RXF_FCS_ERR \ + (GM_MIB_CNT_BASE + 32) /* Rx Frame Check Seq. Error */ + /* GM_MIB_CNT_BASE + 40: reserved */ +#define GM_RXO_OK_LO \ + (GM_MIB_CNT_BASE + 48) /* Octets Received OK Low */ +#define GM_RXO_OK_HI \ + (GM_MIB_CNT_BASE + 56) /* Octets Received OK High */ +#define GM_RXO_ERR_LO \ + (GM_MIB_CNT_BASE + 64) /* Octets Received Invalid Low */ +#define GM_RXO_ERR_HI \ + (GM_MIB_CNT_BASE + 72) /* Octets Received Invalid High */ +#define GM_RXF_SHT \ + (GM_MIB_CNT_BASE + 80) /* Frames <64 Byte Received OK */ +#define GM_RXE_FRAG \ + (GM_MIB_CNT_BASE + 88) /* Frames <64 Byte Received with FCS Err */ +#define GM_RXF_64B \ + (GM_MIB_CNT_BASE + 96) /* 64 Byte Rx Frame */ +#define GM_RXF_127B \ + (GM_MIB_CNT_BASE + 104) /* 65-127 Byte Rx Frame */ +#define GM_RXF_255B \ + (GM_MIB_CNT_BASE + 112) /* 128-255 Byte Rx Frame */ +#define GM_RXF_511B \ + (GM_MIB_CNT_BASE + 120) /* 256-511 Byte Rx Frame */ +#define GM_RXF_1023B \ + (GM_MIB_CNT_BASE + 128) /* 512-1023 Byte Rx Frame */ +#define GM_RXF_1518B \ + (GM_MIB_CNT_BASE + 136) /* 1024-1518 Byte Rx Frame */ +#define GM_RXF_MAX_SZ \ + (GM_MIB_CNT_BASE + 144) /* 1519-MaxSize Byte Rx Frame */ +#define GM_RXF_LNG_ERR \ + (GM_MIB_CNT_BASE + 152) /* Rx Frame too Long Error */ +#define GM_RXF_JAB_PKT \ + (GM_MIB_CNT_BASE + 160) /* Rx Jabber Packet Frame */ + /* GM_MIB_CNT_BASE + 168: reserved */ +#define GM_RXE_FIFO_OV \ + (GM_MIB_CNT_BASE + 176) /* Rx FIFO overflow Event */ + /* GM_MIB_CNT_BASE + 184: reserved */ +#define GM_TXF_UC_OK \ + (GM_MIB_CNT_BASE + 192) /* Unicast Frames Xmitted OK */ +#define GM_TXF_BC_OK \ + (GM_MIB_CNT_BASE + 200) /* Broadcast Frames Xmitted OK */ +#define GM_TXF_MPAUSE \ + (GM_MIB_CNT_BASE + 208) /* Pause MAC Ctrl Frames Xmitted */ +#define GM_TXF_MC_OK \ + (GM_MIB_CNT_BASE + 216) /* Multicast Frames Xmitted OK */ +#define GM_TXO_OK_LO \ + (GM_MIB_CNT_BASE + 224) /* Octets Transmitted OK Low */ +#define GM_TXO_OK_HI \ + (GM_MIB_CNT_BASE + 232) /* Octets Transmitted OK High */ +#define GM_TXF_64B \ + (GM_MIB_CNT_BASE + 240) /* 64 Byte Tx Frame */ +#define GM_TXF_127B \ + (GM_MIB_CNT_BASE + 248) /* 65-127 Byte Tx Frame */ +#define GM_TXF_255B \ + (GM_MIB_CNT_BASE + 256) /* 128-255 Byte Tx Frame */ +#define GM_TXF_511B \ + (GM_MIB_CNT_BASE + 264) /* 256-511 Byte Tx Frame */ +#define GM_TXF_1023B \ + (GM_MIB_CNT_BASE + 272) /* 512-1023 Byte Tx Frame */ +#define GM_TXF_1518B \ + (GM_MIB_CNT_BASE + 280) /* 1024-1518 Byte Tx Frame */ +#define GM_TXF_MAX_SZ \ + (GM_MIB_CNT_BASE + 288) /* 1519-MaxSize Byte Tx Frame */ + /* GM_MIB_CNT_BASE + 296: reserved */ +#define GM_TXF_COL \ + (GM_MIB_CNT_BASE + 304) /* Tx Collision */ +#define GM_TXF_LAT_COL \ + (GM_MIB_CNT_BASE + 312) /* Tx Late Collision */ +#define GM_TXF_ABO_COL \ + (GM_MIB_CNT_BASE + 320) /* Tx aborted due to Exces. Col. */ +#define GM_TXF_MUL_COL \ + (GM_MIB_CNT_BASE + 328) /* Tx Multiple Collision */ +#define GM_TXF_SNG_COL \ + (GM_MIB_CNT_BASE + 336) /* Tx Single Collision */ +#define GM_TXE_FIFO_UR \ + (GM_MIB_CNT_BASE + 344) /* Tx FIFO Underrun Event */ + +/*----------------------------------------------------------------------------*/ +/* + * GMAC Bit Definitions + * + * If the bit access behaviour differs from the register access behaviour + * (r/w, r/o) this is documented after the bit number. + * The following bit access behaviours are used: + * (sc) self clearing + * (r/o) read only + */ + +/* GM_GP_STAT 16 bit r/o General Purpose Status Register */ +#define GM_GPSR_SPEED (1<<15) /* Bit 15: Port Speed (1 = 100 Mbps) */ +#define GM_GPSR_DUPLEX (1<<14) /* Bit 14: Duplex Mode (1 = Full) */ +#define GM_GPSR_FC_TX_DIS (1<<13) /* Bit 13: Tx Flow-Control Mode Disabled */ +#define GM_GPSR_LINK_UP (1<<12) /* Bit 12: Link Up Status */ +#define GM_GPSR_PAUSE (1<<11) /* Bit 11: Pause State */ +#define GM_GPSR_TX_ACTIVE (1<<10) /* Bit 10: Tx in Progress */ +#define GM_GPSR_EXC_COL (1<<9) /* Bit 9: Excessive Collisions Occured */ +#define GM_GPSR_LAT_COL (1<<8) /* Bit 8: Late Collisions Occured */ + /* Bit 7..6: reserved */ +#define GM_GPSR_PHY_ST_CH (1<<5) /* Bit 5: PHY Status Change */ +#define GM_GPSR_GIG_SPEED (1<<4) /* Bit 4: Gigabit Speed (1 = 1000 Mbps) */ +#define GM_GPSR_PART_MODE (1<<3) /* Bit 3: Partition mode */ +#define GM_GPSR_FC_RX_DIS (1<<2) /* Bit 2: Rx Flow-Control Mode Disabled */ +#define GM_GPSR_PROM_EN (1<<1) /* Bit 1: Promiscuous Mode Enabled */ + /* Bit 0: reserved */ + +/* GM_GP_CTRL 16 bit r/w General Purpose Control Register */ + /* Bit 15: reserved */ +#define GM_GPCR_PROM_ENA (1<<14) /* Bit 14: Enable Promiscuous Mode */ +#define GM_GPCR_FC_TX_DIS (1<<13) /* Bit 13: Disable Tx Flow-Control Mode */ +#define GM_GPCR_TX_ENA (1<<12) /* Bit 12: Enable Transmit */ +#define GM_GPCR_RX_ENA (1<<11) /* Bit 11: Enable Receive */ +#define GM_GPCR_BURST_ENA (1<<10) /* Bit 10: Enable Burst Mode */ +#define GM_GPCR_LOOP_ENA (1<<9) /* Bit 9: Enable MAC Loopback Mode */ +#define GM_GPCR_PART_ENA (1<<8) /* Bit 8: Enable Partition Mode */ +#define GM_GPCR_GIGS_ENA (1<<7) /* Bit 7: Gigabit Speed (1000 Mbps) */ +#define GM_GPCR_FL_PASS (1<<6) /* Bit 6: Force Link Pass */ +#define GM_GPCR_DUP_FULL (1<<5) /* Bit 5: Full Duplex Mode */ +#define GM_GPCR_FC_RX_DIS (1<<4) /* Bit 4: Disable Rx Flow-Control Mode */ +#define GM_GPCR_SPEED_100 (1<<3) /* Bit 3: Port Speed 100 Mbps */ +#define GM_GPCR_AU_DUP_DIS (1<<2) /* Bit 2: Disable Auto-Update Duplex */ +#define GM_GPCR_AU_FCT_DIS (1<<1) /* Bit 1: Disable Auto-Update Flow-C. */ +#define GM_GPCR_AU_SPD_DIS (1<<0) /* Bit 0: Disable Auto-Update Speed */ + +#define GM_GPCR_SPEED_1000 (GM_GPCR_GIGS_ENA | GM_GPCR_SPEED_100) +#define GM_GPCR_AU_ALL_DIS (GM_GPCR_AU_DUP_DIS | GM_GPCR_AU_FCT_DIS |\ + GM_GPCR_AU_SPD_DIS) + +/* GM_TX_CTRL 16 bit r/w Transmit Control Register */ +#define GM_TXCR_FORCE_JAM (1<<15) /* Bit 15: Force Jam / Flow-Control */ +#define GM_TXCR_CRC_DIS (1<<14) /* Bit 14: Disable insertion of CRC */ +#define GM_TXCR_PAD_DIS (1<<13) /* Bit 13: Disable padding of packets */ +#define GM_TXCR_COL_THR_MSK (7<<10) /* Bit 12..10: Collision Threshold */ + +#define TX_COL_THR(x) (SHIFT10(x) & GM_TXCR_COL_THR_MSK) + +#define TX_COL_DEF 0x04 + +/* GM_RX_CTRL 16 bit r/w Receive Control Register */ +#define GM_RXCR_UCF_ENA (1<<15) /* Bit 15: Enable Unicast filtering */ +#define GM_RXCR_MCF_ENA (1<<14) /* Bit 14: Enable Multicast filtering */ +#define GM_RXCR_CRC_DIS (1<<13) /* Bit 13: Remove 4-byte CRC */ +#define GM_RXCR_PASS_FC (1<<12) /* Bit 12: Pass FC packets to FIFO */ + +/* GM_TX_PARAM 16 bit r/w Transmit Parameter Register */ +#define GM_TXPA_JAMLEN_MSK (0x03<<14) /* Bit 15..14: Jam Length */ +#define GM_TXPA_JAMIPG_MSK (0x1f<<9) /* Bit 13..9: Jam IPG */ +#define GM_TXPA_JAMDAT_MSK (0x1f<<4) /* Bit 8..4: IPG Jam to Data */ + /* Bit 3..0: reserved */ + +#define TX_JAM_LEN_VAL(x) (SHIFT14(x) & GM_TXPA_JAMLEN_MSK) +#define TX_JAM_IPG_VAL(x) (SHIFT9(x) & GM_TXPA_JAMIPG_MSK) +#define TX_IPG_JAM_DATA(x) (SHIFT4(x) & GM_TXPA_JAMDAT_MSK) + +#define TX_JAM_LEN_DEF 0x03 +#define TX_JAM_IPG_DEF 0x0b +#define TX_IPG_JAM_DEF 0x1c + +/* GM_SERIAL_MODE 16 bit r/w Serial Mode Register */ +#define GM_SMOD_DATABL_MSK (0x1f<<11) /* Bit 15..11: Data Blinder (r/o) */ +#define GM_SMOD_LIMIT_4 (1<<10) /* Bit 10: 4 consecutive Tx trials */ +#define GM_SMOD_VLAN_ENA (1<<9) /* Bit 9: Enable VLAN (Max. Frame Len) */ +#define GM_SMOD_JUMBO_ENA (1<<8) /* Bit 8: Enable Jumbo (Max. Frame Len) */ + /* Bit 7..5: reserved */ +#define GM_SMOD_IPG_MSK 0x1f /* Bit 4..0: Inter-Packet Gap (IPG) */ + +#define DATA_BLIND_VAL(x) (SHIFT11(x) & GM_SMOD_DATABL_MSK) +#define DATA_BLIND_DEF 0x04 + +#define IPG_DATA_VAL(x) (x & GM_SMOD_IPG_MSK) +#define IPG_DATA_DEF 0x1e + +/* GM_SMI_CTRL 16 bit r/w SMI Control Register */ +#define GM_SMI_CT_PHY_A_MSK (0x1f<<11) /* Bit 15..11: PHY Device Address */ +#define GM_SMI_CT_REG_A_MSK (0x1f<<6) /* Bit 10.. 6: PHY Register Address */ +#define GM_SMI_CT_OP_RD (1<<5) /* Bit 5: OpCode Read (0=Write)*/ +#define GM_SMI_CT_RD_VAL (1<<4) /* Bit 4: Read Valid (Read completed) */ +#define GM_SMI_CT_BUSY (1<<3) /* Bit 3: Busy (Operation in progress) */ + /* Bit 2..0: reserved */ + +#define GM_SMI_CT_PHY_AD(x) (SHIFT11(x) & GM_SMI_CT_PHY_A_MSK) +#define GM_SMI_CT_REG_AD(x) (SHIFT6(x) & GM_SMI_CT_REG_A_MSK) + + /* GM_PHY_ADDR 16 bit r/w GPHY Address Register */ + /* Bit 15..6: reserved */ +#define GM_PAR_MIB_CLR (1<<5) /* Bit 5: Set MIB Clear Counter Mode */ +#define GM_PAR_MIB_TST (1<<4) /* Bit 4: MIB Load Counter (Test Mode) */ + /* Bit 3..0: reserved */ + +/* Receive Frame Status Encoding */ +#define GMR_FS_LEN (0xffffUL<<16) /* Bit 31..16: Rx Frame Length */ + /* Bit 15..14: reserved */ +#define GMR_FS_VLAN (1L<<13) /* Bit 13: VLAN Packet */ +#define GMR_FS_JABBER (1L<<12) /* Bit 12: Jabber Packet */ +#define GMR_FS_UN_SIZE (1L<<11) /* Bit 11: Undersize Packet */ +#define GMR_FS_MC (1L<<10) /* Bit 10: Multicast Packet */ +#define GMR_FS_BC (1L<<9) /* Bit 9: Broadcast Packet */ +#define GMR_FS_RX_OK (1L<<8) /* Bit 8: Receive OK (Good Packet) */ +#define GMR_FS_GOOD_FC (1L<<7) /* Bit 7: Good Flow-Control Packet */ +#define GMR_FS_BAD_FC (1L<<6) /* Bit 6: Bad Flow-Control Packet */ +#define GMR_FS_MII_ERR (1L<<5) /* Bit 5: MII Error */ +#define GMR_FS_LONG_ERR (1L<<4) /* Bit 4: Too Long Packet */ +#define GMR_FS_FRAGMENT (1L<<3) /* Bit 3: Fragment */ + /* Bit 2: reserved */ +#define GMR_FS_CRC_ERR (1L<<1) /* Bit 1: CRC Error */ +#define GMR_FS_RX_FF_OV (1L<<0) /* Bit 0: Rx FIFO Overflow */ + +/* + * GMR_FS_ANY_ERR (analogous to XMR_FS_ANY_ERR) + */ +#define GMR_FS_ANY_ERR (GMR_FS_CRC_ERR | \ + GMR_FS_LONG_ERR | \ + GMR_FS_MII_ERR | \ + GMR_FS_BAD_FC | \ + GMR_FS_GOOD_FC | \ + GMR_FS_JABBER) + +/* Rx GMAC FIFO Flush Mask (default) */ +#define RX_FF_FL_DEF_MSK (GMR_FS_CRC_ERR | \ + GMR_FS_RX_FF_OV | \ + GMR_FS_MII_ERR | \ + GMR_FS_BAD_FC | \ + GMR_FS_GOOD_FC | \ + GMR_FS_UN_SIZE | \ + GMR_FS_JABBER) + +/* typedefs *******************************************************************/ + + +/* function prototypes ********************************************************/ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __INC_XMAC_H */ diff --git a/drivers/net/sk98lin/skaddr.c b/drivers/net/sk98lin/skaddr.c new file mode 100644 index 000000000000..6e6c56aa6d6f --- /dev/null +++ b/drivers/net/sk98lin/skaddr.c @@ -0,0 +1,1788 @@ +/****************************************************************************** + * + * Name: skaddr.c + * Project: Gigabit Ethernet Adapters, ADDR-Module + * Version: $Revision: 1.52 $ + * Date: $Date: 2003/06/02 13:46:15 $ + * Purpose: Manage Addresses (Multicast and Unicast) and Promiscuous Mode. + * + ******************************************************************************/ + +/****************************************************************************** + * + * (C)Copyright 1998-2002 SysKonnect GmbH. + * (C)Copyright 2002-2003 Marvell. + * + * 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. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/****************************************************************************** + * + * Description: + * + * This module is intended to manage multicast addresses, address override, + * and promiscuous mode on GEnesis and Yukon adapters. + * + * Address Layout: + * port address: physical MAC address + * 1st exact match: logical MAC address (GEnesis only) + * 2nd exact match: RLMT multicast (GEnesis only) + * exact match 3-13: OS-specific multicasts (GEnesis only) + * + * Include File Hierarchy: + * + * "skdrv1st.h" + * "skdrv2nd.h" + * + ******************************************************************************/ + +#if (defined(DEBUG) || ((!defined(LINT)) && (!defined(SK_SLIM)))) +static const char SysKonnectFileId[] = + "@(#) $Id: skaddr.c,v 1.52 2003/06/02 13:46:15 tschilli Exp $ (C) Marvell."; +#endif /* DEBUG ||!LINT || !SK_SLIM */ + +#define __SKADDR_C + +#ifdef __cplusplus +extern "C" { +#endif /* cplusplus */ + +#include "h/skdrv1st.h" +#include "h/skdrv2nd.h" + +/* defines ********************************************************************/ + + +#define XMAC_POLY 0xEDB88320UL /* CRC32-Poly - XMAC: Little Endian */ +#define GMAC_POLY 0x04C11DB7L /* CRC16-Poly - GMAC: Little Endian */ +#define HASH_BITS 6 /* #bits in hash */ +#define SK_MC_BIT 0x01 + +/* Error numbers and messages. */ + +#define SKERR_ADDR_E001 (SK_ERRBASE_ADDR + 0) +#define SKERR_ADDR_E001MSG "Bad Flags." +#define SKERR_ADDR_E002 (SKERR_ADDR_E001 + 1) +#define SKERR_ADDR_E002MSG "New Error." + +/* typedefs *******************************************************************/ + +/* None. */ + +/* global variables ***********************************************************/ + +/* 64-bit hash values with all bits set. */ + +static const SK_U16 OnesHash[4] = {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF}; + +/* local variables ************************************************************/ + +#ifdef DEBUG +static int Next0[SK_MAX_MACS] = {0}; +#endif /* DEBUG */ + +static int SkAddrGmacMcAdd(SK_AC *pAC, SK_IOC IoC, SK_U32 PortNumber, + SK_MAC_ADDR *pMc, int Flags); +static int SkAddrGmacMcClear(SK_AC *pAC, SK_IOC IoC, SK_U32 PortNumber, + int Flags); +static int SkAddrGmacMcUpdate(SK_AC *pAC, SK_IOC IoC, SK_U32 PortNumber); +static int SkAddrGmacPromiscuousChange(SK_AC *pAC, SK_IOC IoC, + SK_U32 PortNumber, int NewPromMode); +static int SkAddrXmacMcAdd(SK_AC *pAC, SK_IOC IoC, SK_U32 PortNumber, + SK_MAC_ADDR *pMc, int Flags); +static int SkAddrXmacMcClear(SK_AC *pAC, SK_IOC IoC, SK_U32 PortNumber, + int Flags); +static int SkAddrXmacMcUpdate(SK_AC *pAC, SK_IOC IoC, SK_U32 PortNumber); +static int SkAddrXmacPromiscuousChange(SK_AC *pAC, SK_IOC IoC, + SK_U32 PortNumber, int NewPromMode); + +/* functions ******************************************************************/ + +/****************************************************************************** + * + * SkAddrInit - initialize data, set state to init + * + * Description: + * + * SK_INIT_DATA + * ============ + * + * This routine clears the multicast tables and resets promiscuous mode. + * Some entries are reserved for the "logical MAC address", the + * SK-RLMT multicast address, and the BPDU multicast address. + * + * + * SK_INIT_IO + * ========== + * + * All permanent MAC addresses are read from EPROM. + * If the current MAC addresses are not already set in software, + * they are set to the values of the permanent addresses. + * The current addresses are written to the corresponding MAC. + * + * + * SK_INIT_RUN + * =========== + * + * Nothing. + * + * Context: + * init, pageable + * + * Returns: + * SK_ADDR_SUCCESS + */ +int SkAddrInit( +SK_AC *pAC, /* the adapter context */ +SK_IOC IoC, /* I/O context */ +int Level) /* initialization level */ +{ + int j; + SK_U32 i; + SK_U8 *InAddr; + SK_U16 *OutAddr; + SK_ADDR_PORT *pAPort; + + switch (Level) { + case SK_INIT_DATA: + SK_MEMSET((char *) &pAC->Addr, (SK_U8) 0, + (SK_U16) sizeof(SK_ADDR)); + + for (i = 0; i < SK_MAX_MACS; i++) { + pAPort = &pAC->Addr.Port[i]; + pAPort->PromMode = SK_PROM_MODE_NONE; + + pAPort->FirstExactMatchRlmt = SK_ADDR_FIRST_MATCH_RLMT; + pAPort->FirstExactMatchDrv = SK_ADDR_FIRST_MATCH_DRV; + pAPort->NextExactMatchRlmt = SK_ADDR_FIRST_MATCH_RLMT; + pAPort->NextExactMatchDrv = SK_ADDR_FIRST_MATCH_DRV; + } +#ifdef xDEBUG + for (i = 0; i < SK_MAX_MACS; i++) { + if (pAC->Addr.Port[i].NextExactMatchRlmt < + SK_ADDR_FIRST_MATCH_RLMT) { + Next0[i] |= 4; + } + } +#endif /* DEBUG */ + /* pAC->Addr.InitDone = SK_INIT_DATA; */ + break; + + case SK_INIT_IO: +#ifndef SK_NO_RLMT + for (i = 0; i < SK_MAX_NETS; i++) { + pAC->Addr.Net[i].ActivePort = pAC->Rlmt.Net[i].ActivePort; + } +#endif /* !SK_NO_RLMT */ +#ifdef xDEBUG + for (i = 0; i < SK_MAX_MACS; i++) { + if (pAC->Addr.Port[i].NextExactMatchRlmt < + SK_ADDR_FIRST_MATCH_RLMT) { + Next0[i] |= 8; + } + } +#endif /* DEBUG */ + + /* Read permanent logical MAC address from Control Register File. */ + for (j = 0; j < SK_MAC_ADDR_LEN; j++) { + InAddr = (SK_U8 *) &pAC->Addr.Net[0].PermanentMacAddress.a[j]; + SK_IN8(IoC, B2_MAC_1 + j, InAddr); + } + + if (!pAC->Addr.Net[0].CurrentMacAddressSet) { + /* Set the current logical MAC address to the permanent one. */ + pAC->Addr.Net[0].CurrentMacAddress = + pAC->Addr.Net[0].PermanentMacAddress; + pAC->Addr.Net[0].CurrentMacAddressSet = SK_TRUE; + } + + /* Set the current logical MAC address. */ + pAC->Addr.Port[pAC->Addr.Net[0].ActivePort].Exact[0] = + pAC->Addr.Net[0].CurrentMacAddress; +#if SK_MAX_NETS > 1 + /* Set logical MAC address for net 2 to (log | 3). */ + if (!pAC->Addr.Net[1].CurrentMacAddressSet) { + pAC->Addr.Net[1].PermanentMacAddress = + pAC->Addr.Net[0].PermanentMacAddress; + pAC->Addr.Net[1].PermanentMacAddress.a[5] |= 3; + /* Set the current logical MAC address to the permanent one. */ + pAC->Addr.Net[1].CurrentMacAddress = + pAC->Addr.Net[1].PermanentMacAddress; + pAC->Addr.Net[1].CurrentMacAddressSet = SK_TRUE; + } +#endif /* SK_MAX_NETS > 1 */ + +#ifdef DEBUG + for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) { + SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_INIT, + ("Permanent MAC Address (Net%d): %02X %02X %02X %02X %02X %02X\n", + i, + pAC->Addr.Net[i].PermanentMacAddress.a[0], + pAC->Addr.Net[i].PermanentMacAddress.a[1], + pAC->Addr.Net[i].PermanentMacAddress.a[2], + pAC->Addr.Net[i].PermanentMacAddress.a[3], + pAC->Addr.Net[i].PermanentMacAddress.a[4], + pAC->Addr.Net[i].PermanentMacAddress.a[5])) + + SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_INIT, + ("Logical MAC Address (Net%d): %02X %02X %02X %02X %02X %02X\n", + i, + pAC->Addr.Net[i].CurrentMacAddress.a[0], + pAC->Addr.Net[i].CurrentMacAddress.a[1], + pAC->Addr.Net[i].CurrentMacAddress.a[2], + pAC->Addr.Net[i].CurrentMacAddress.a[3], + pAC->Addr.Net[i].CurrentMacAddress.a[4], + pAC->Addr.Net[i].CurrentMacAddress.a[5])) + } +#endif /* DEBUG */ + + for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) { + pAPort = &pAC->Addr.Port[i]; + + /* Read permanent port addresses from Control Register File. */ + for (j = 0; j < SK_MAC_ADDR_LEN; j++) { + InAddr = (SK_U8 *) &pAPort->PermanentMacAddress.a[j]; + SK_IN8(IoC, B2_MAC_2 + 8 * i + j, InAddr); + } + + if (!pAPort->CurrentMacAddressSet) { + /* + * Set the current and previous physical MAC address + * of this port to its permanent MAC address. + */ + pAPort->CurrentMacAddress = pAPort->PermanentMacAddress; + pAPort->PreviousMacAddress = pAPort->PermanentMacAddress; + pAPort->CurrentMacAddressSet = SK_TRUE; + } + + /* Set port's current physical MAC address. */ + OutAddr = (SK_U16 *) &pAPort->CurrentMacAddress.a[0]; +#ifdef GENESIS + if (pAC->GIni.GIGenesis) { + XM_OUTADDR(IoC, i, XM_SA, OutAddr); + } +#endif /* GENESIS */ +#ifdef YUKON + if (!pAC->GIni.GIGenesis) { + GM_OUTADDR(IoC, i, GM_SRC_ADDR_1L, OutAddr); + } +#endif /* YUKON */ +#ifdef DEBUG + SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_INIT, + ("SkAddrInit: Permanent Physical MAC Address: %02X %02X %02X %02X %02X %02X\n", + pAPort->PermanentMacAddress.a[0], + pAPort->PermanentMacAddress.a[1], + pAPort->PermanentMacAddress.a[2], + pAPort->PermanentMacAddress.a[3], + pAPort->PermanentMacAddress.a[4], + pAPort->PermanentMacAddress.a[5])) + + SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_INIT, + ("SkAddrInit: Physical MAC Address: %02X %02X %02X %02X %02X %02X\n", + pAPort->CurrentMacAddress.a[0], + pAPort->CurrentMacAddress.a[1], + pAPort->CurrentMacAddress.a[2], + pAPort->CurrentMacAddress.a[3], + pAPort->CurrentMacAddress.a[4], + pAPort->CurrentMacAddress.a[5])) +#endif /* DEBUG */ + } + /* pAC->Addr.InitDone = SK_INIT_IO; */ + break; + + case SK_INIT_RUN: +#ifdef xDEBUG + for (i = 0; i < SK_MAX_MACS; i++) { + if (pAC->Addr.Port[i].NextExactMatchRlmt < + SK_ADDR_FIRST_MATCH_RLMT) { + Next0[i] |= 16; + } + } +#endif /* DEBUG */ + + /* pAC->Addr.InitDone = SK_INIT_RUN; */ + break; + + default: /* error */ + break; + } + + return (SK_ADDR_SUCCESS); + +} /* SkAddrInit */ + +#ifndef SK_SLIM + +/****************************************************************************** + * + * SkAddrMcClear - clear the multicast table + * + * Description: + * This routine clears the multicast table. + * + * If not suppressed by Flag SK_MC_SW_ONLY, the hardware is updated + * immediately. + * + * It calls either SkAddrXmacMcClear or SkAddrGmacMcClear, according + * to the adapter in use. The real work is done there. + * + * Context: + * runtime, pageable + * may be called starting with SK_INIT_DATA with flag SK_MC_SW_ONLY + * may be called after SK_INIT_IO without limitation + * + * Returns: + * SK_ADDR_SUCCESS + * SK_ADDR_ILLEGAL_PORT + */ +int SkAddrMcClear( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* I/O context */ +SK_U32 PortNumber, /* Index of affected port */ +int Flags) /* permanent/non-perm, sw-only */ +{ + int ReturnCode; + + if (PortNumber >= (SK_U32) pAC->GIni.GIMacsFound) { + return (SK_ADDR_ILLEGAL_PORT); + } + + if (pAC->GIni.GIGenesis) { + ReturnCode = SkAddrXmacMcClear(pAC, IoC, PortNumber, Flags); + } + else { + ReturnCode = SkAddrGmacMcClear(pAC, IoC, PortNumber, Flags); + } + + return (ReturnCode); + +} /* SkAddrMcClear */ + +#endif /* !SK_SLIM */ + +#ifndef SK_SLIM + +/****************************************************************************** + * + * SkAddrXmacMcClear - clear the multicast table + * + * Description: + * This routine clears the multicast table + * (either entry 2 or entries 3-16 and InexactFilter) of the given port. + * If not suppressed by Flag SK_MC_SW_ONLY, the hardware is updated + * immediately. + * + * Context: + * runtime, pageable + * may be called starting with SK_INIT_DATA with flag SK_MC_SW_ONLY + * may be called after SK_INIT_IO without limitation + * + * Returns: + * SK_ADDR_SUCCESS + * SK_ADDR_ILLEGAL_PORT + */ +static int SkAddrXmacMcClear( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* I/O context */ +SK_U32 PortNumber, /* Index of affected port */ +int Flags) /* permanent/non-perm, sw-only */ +{ + int i; + + if (Flags & SK_ADDR_PERMANENT) { /* permanent => RLMT */ + + /* Clear RLMT multicast addresses. */ + pAC->Addr.Port[PortNumber].NextExactMatchRlmt = SK_ADDR_FIRST_MATCH_RLMT; + } + else { /* not permanent => DRV */ + + /* Clear InexactFilter */ + for (i = 0; i < 8; i++) { + pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0; + } + + /* Clear DRV multicast addresses. */ + + pAC->Addr.Port[PortNumber].NextExactMatchDrv = SK_ADDR_FIRST_MATCH_DRV; + } + + if (!(Flags & SK_MC_SW_ONLY)) { + (void) SkAddrXmacMcUpdate(pAC, IoC, PortNumber); + } + + return (SK_ADDR_SUCCESS); + +} /* SkAddrXmacMcClear */ + +#endif /* !SK_SLIM */ + +#ifndef SK_SLIM + +/****************************************************************************** + * + * SkAddrGmacMcClear - clear the multicast table + * + * Description: + * This routine clears the multicast hashing table (InexactFilter) + * (either the RLMT or the driver bits) of the given port. + * + * If not suppressed by Flag SK_MC_SW_ONLY, the hardware is updated + * immediately. + * + * Context: + * runtime, pageable + * may be called starting with SK_INIT_DATA with flag SK_MC_SW_ONLY + * may be called after SK_INIT_IO without limitation + * + * Returns: + * SK_ADDR_SUCCESS + * SK_ADDR_ILLEGAL_PORT + */ +static int SkAddrGmacMcClear( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* I/O context */ +SK_U32 PortNumber, /* Index of affected port */ +int Flags) /* permanent/non-perm, sw-only */ +{ + int i; + +#ifdef DEBUG + SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL, + ("GMAC InexactFilter (not cleared): %02X %02X %02X %02X %02X %02X %02X %02X\n", + pAC->Addr.Port[PortNumber].InexactFilter.Bytes[0], + pAC->Addr.Port[PortNumber].InexactFilter.Bytes[1], + pAC->Addr.Port[PortNumber].InexactFilter.Bytes[2], + pAC->Addr.Port[PortNumber].InexactFilter.Bytes[3], + pAC->Addr.Port[PortNumber].InexactFilter.Bytes[4], + pAC->Addr.Port[PortNumber].InexactFilter.Bytes[5], + pAC->Addr.Port[PortNumber].InexactFilter.Bytes[6], + pAC->Addr.Port[PortNumber].InexactFilter.Bytes[7])) +#endif /* DEBUG */ + + /* Clear InexactFilter */ + for (i = 0; i < 8; i++) { + pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0; + } + + if (Flags & SK_ADDR_PERMANENT) { /* permanent => RLMT */ + + /* Copy DRV bits to InexactFilter. */ + for (i = 0; i < 8; i++) { + pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] |= + pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[i]; + + /* Clear InexactRlmtFilter. */ + pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[i] = 0; + + } + } + else { /* not permanent => DRV */ + + /* Copy RLMT bits to InexactFilter. */ + for (i = 0; i < 8; i++) { + pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] |= + pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[i]; + + /* Clear InexactDrvFilter. */ + pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[i] = 0; + } + } + +#ifdef DEBUG + SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL, + ("GMAC InexactFilter (cleared): %02X %02X %02X %02X %02X %02X %02X %02X\n", + pAC->Addr.Port[PortNumber].InexactFilter.Bytes[0], + pAC->Addr.Port[PortNumber].InexactFilter.Bytes[1], + pAC->Addr.Port[PortNumber].InexactFilter.Bytes[2], + pAC->Addr.Port[PortNumber].InexactFilter.Bytes[3], + pAC->Addr.Port[PortNumber].InexactFilter.Bytes[4], + pAC->Addr.Port[PortNumber].InexactFilter.Bytes[5], + pAC->Addr.Port[PortNumber].InexactFilter.Bytes[6], + pAC->Addr.Port[PortNumber].InexactFilter.Bytes[7])) +#endif /* DEBUG */ + + if (!(Flags & SK_MC_SW_ONLY)) { + (void) SkAddrGmacMcUpdate(pAC, IoC, PortNumber); + } + + return (SK_ADDR_SUCCESS); + +} /* SkAddrGmacMcClear */ + +#ifndef SK_ADDR_CHEAT + +/****************************************************************************** + * + * SkXmacMcHash - hash multicast address + * + * Description: + * This routine computes the hash value for a multicast address. + * A CRC32 algorithm is used. + * + * Notes: + * The code was adapted from the XaQti data sheet. + * + * Context: + * runtime, pageable + * + * Returns: + * Hash value of multicast address. + */ +static SK_U32 SkXmacMcHash( +unsigned char *pMc) /* Multicast address */ +{ + SK_U32 Idx; + SK_U32 Bit; + SK_U32 Data; + SK_U32 Crc; + + Crc = 0xFFFFFFFFUL; + for (Idx = 0; Idx < SK_MAC_ADDR_LEN; Idx++) { + Data = *pMc++; + for (Bit = 0; Bit < 8; Bit++, Data >>= 1) { + Crc = (Crc >> 1) ^ (((Crc ^ Data) & 1) ? XMAC_POLY : 0); + } + } + + return (Crc & ((1 << HASH_BITS) - 1)); + +} /* SkXmacMcHash */ + + +/****************************************************************************** + * + * SkGmacMcHash - hash multicast address + * + * Description: + * This routine computes the hash value for a multicast address. + * A CRC16 algorithm is used. + * + * Notes: + * + * + * Context: + * runtime, pageable + * + * Returns: + * Hash value of multicast address. + */ +static SK_U32 SkGmacMcHash( +unsigned char *pMc) /* Multicast address */ +{ + SK_U32 Data; + SK_U32 TmpData; + SK_U32 Crc; + int Byte; + int Bit; + + Crc = 0xFFFFFFFFUL; + for (Byte = 0; Byte < 6; Byte++) { + /* Get next byte. */ + Data = (SK_U32) pMc[Byte]; + + /* Change bit order in byte. */ + TmpData = Data; + for (Bit = 0; Bit < 8; Bit++) { + if (TmpData & 1L) { + Data |= 1L << (7 - Bit); + } + else { + Data &= ~(1L << (7 - Bit)); + } + TmpData >>= 1; + } + + Crc ^= (Data << 24); + for (Bit = 0; Bit < 8; Bit++) { + if (Crc & 0x80000000) { + Crc = (Crc << 1) ^ GMAC_POLY; + } + else { + Crc <<= 1; + } + } + } + + return (Crc & ((1 << HASH_BITS) - 1)); + +} /* SkGmacMcHash */ + +#endif /* !SK_ADDR_CHEAT */ + +/****************************************************************************** + * + * SkAddrMcAdd - add a multicast address to a port + * + * Description: + * This routine enables reception for a given address on the given port. + * + * It calls either SkAddrXmacMcAdd or SkAddrGmacMcAdd, according to the + * adapter in use. The real work is done there. + * + * Notes: + * The return code is only valid for SK_PROM_MODE_NONE. + * + * Context: + * runtime, pageable + * may be called after SK_INIT_DATA + * + * Returns: + * SK_MC_FILTERING_EXACT + * SK_MC_FILTERING_INEXACT + * SK_MC_ILLEGAL_ADDRESS + * SK_MC_ILLEGAL_PORT + * SK_MC_RLMT_OVERFLOW + */ +int SkAddrMcAdd( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* I/O context */ +SK_U32 PortNumber, /* Port Number */ +SK_MAC_ADDR *pMc, /* multicast address to be added */ +int Flags) /* permanent/non-permanent */ +{ + int ReturnCode; + + if (PortNumber >= (SK_U32) pAC->GIni.GIMacsFound) { + return (SK_ADDR_ILLEGAL_PORT); + } + + if (pAC->GIni.GIGenesis) { + ReturnCode = SkAddrXmacMcAdd(pAC, IoC, PortNumber, pMc, Flags); + } + else { + ReturnCode = SkAddrGmacMcAdd(pAC, IoC, PortNumber, pMc, Flags); + } + + return (ReturnCode); + +} /* SkAddrMcAdd */ + + +/****************************************************************************** + * + * SkAddrXmacMcAdd - add a multicast address to a port + * + * Description: + * This routine enables reception for a given address on the given port. + * + * Notes: + * The return code is only valid for SK_PROM_MODE_NONE. + * + * The multicast bit is only checked if there are no free exact match + * entries. + * + * Context: + * runtime, pageable + * may be called after SK_INIT_DATA + * + * Returns: + * SK_MC_FILTERING_EXACT + * SK_MC_FILTERING_INEXACT + * SK_MC_ILLEGAL_ADDRESS + * SK_MC_RLMT_OVERFLOW + */ +static int SkAddrXmacMcAdd( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* I/O context */ +SK_U32 PortNumber, /* Port Number */ +SK_MAC_ADDR *pMc, /* multicast address to be added */ +int Flags) /* permanent/non-permanent */ +{ + int i; + SK_U8 Inexact; +#ifndef SK_ADDR_CHEAT + SK_U32 HashBit; +#endif /* !defined(SK_ADDR_CHEAT) */ + + if (Flags & SK_ADDR_PERMANENT) { /* permanent => RLMT */ +#ifdef xDEBUG + if (pAC->Addr.Port[PortNumber].NextExactMatchRlmt < + SK_ADDR_FIRST_MATCH_RLMT) { + Next0[PortNumber] |= 1; + return (SK_MC_RLMT_OVERFLOW); + } +#endif /* DEBUG */ + + if (pAC->Addr.Port[PortNumber].NextExactMatchRlmt > + SK_ADDR_LAST_MATCH_RLMT) { + return (SK_MC_RLMT_OVERFLOW); + } + + /* Set a RLMT multicast address. */ + + pAC->Addr.Port[PortNumber].Exact[ + pAC->Addr.Port[PortNumber].NextExactMatchRlmt++] = *pMc; + + return (SK_MC_FILTERING_EXACT); + } + +#ifdef xDEBUG + if (pAC->Addr.Port[PortNumber].NextExactMatchDrv < + SK_ADDR_FIRST_MATCH_DRV) { + Next0[PortNumber] |= 2; + return (SK_MC_RLMT_OVERFLOW); + } +#endif /* DEBUG */ + + if (pAC->Addr.Port[PortNumber].NextExactMatchDrv <= SK_ADDR_LAST_MATCH_DRV) { + + /* Set exact match entry. */ + pAC->Addr.Port[PortNumber].Exact[ + pAC->Addr.Port[PortNumber].NextExactMatchDrv++] = *pMc; + + /* Clear InexactFilter */ + for (i = 0; i < 8; i++) { + pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0; + } + } + else { + if (!(pMc->a[0] & SK_MC_BIT)) { + /* Hashing only possible with multicast addresses */ + return (SK_MC_ILLEGAL_ADDRESS); + } +#ifndef SK_ADDR_CHEAT + /* Compute hash value of address. */ + HashBit = 63 - SkXmacMcHash(&pMc->a[0]); + + /* Add bit to InexactFilter. */ + pAC->Addr.Port[PortNumber].InexactFilter.Bytes[HashBit / 8] |= + 1 << (HashBit % 8); +#else /* SK_ADDR_CHEAT */ + /* Set all bits in InexactFilter. */ + for (i = 0; i < 8; i++) { + pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0xFF; + } +#endif /* SK_ADDR_CHEAT */ + } + + for (Inexact = 0, i = 0; i < 8; i++) { + Inexact |= pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i]; + } + + if (Inexact == 0 && pAC->Addr.Port[PortNumber].PromMode == 0) { + return (SK_MC_FILTERING_EXACT); + } + else { + return (SK_MC_FILTERING_INEXACT); + } + +} /* SkAddrXmacMcAdd */ + + +/****************************************************************************** + * + * SkAddrGmacMcAdd - add a multicast address to a port + * + * Description: + * This routine enables reception for a given address on the given port. + * + * Notes: + * The return code is only valid for SK_PROM_MODE_NONE. + * + * Context: + * runtime, pageable + * may be called after SK_INIT_DATA + * + * Returns: + * SK_MC_FILTERING_INEXACT + * SK_MC_ILLEGAL_ADDRESS + */ +static int SkAddrGmacMcAdd( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* I/O context */ +SK_U32 PortNumber, /* Port Number */ +SK_MAC_ADDR *pMc, /* multicast address to be added */ +int Flags) /* permanent/non-permanent */ +{ + int i; +#ifndef SK_ADDR_CHEAT + SK_U32 HashBit; +#endif /* !defined(SK_ADDR_CHEAT) */ + + if (!(pMc->a[0] & SK_MC_BIT)) { + /* Hashing only possible with multicast addresses */ + return (SK_MC_ILLEGAL_ADDRESS); + } + +#ifndef SK_ADDR_CHEAT + + /* Compute hash value of address. */ + HashBit = SkGmacMcHash(&pMc->a[0]); + + if (Flags & SK_ADDR_PERMANENT) { /* permanent => RLMT */ + + /* Add bit to InexactRlmtFilter. */ + pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[HashBit / 8] |= + 1 << (HashBit % 8); + + /* Copy bit to InexactFilter. */ + for (i = 0; i < 8; i++) { + pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] |= + pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[i]; + } +#ifdef DEBUG + SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL, + ("GMAC InexactRlmtFilter: %02X %02X %02X %02X %02X %02X %02X %02X\n", + pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[0], + pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[1], + pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[2], + pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[3], + pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[4], + pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[5], + pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[6], + pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[7])) +#endif /* DEBUG */ + } + else { /* not permanent => DRV */ + + /* Add bit to InexactDrvFilter. */ + pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[HashBit / 8] |= + 1 << (HashBit % 8); + + /* Copy bit to InexactFilter. */ + for (i = 0; i < 8; i++) { + pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] |= + pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[i]; + } +#ifdef DEBUG + SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL, + ("GMAC InexactDrvFilter: %02X %02X %02X %02X %02X %02X %02X %02X\n", + pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[0], + pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[1], + pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[2], + pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[3], + pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[4], + pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[5], + pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[6], + pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[7])) +#endif /* DEBUG */ + } + +#else /* SK_ADDR_CHEAT */ + + /* Set all bits in InexactFilter. */ + for (i = 0; i < 8; i++) { + pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0xFF; + } +#endif /* SK_ADDR_CHEAT */ + + return (SK_MC_FILTERING_INEXACT); + +} /* SkAddrGmacMcAdd */ + +#endif /* !SK_SLIM */ + +/****************************************************************************** + * + * SkAddrMcUpdate - update the HW MC address table and set the MAC address + * + * Description: + * This routine enables reception of the addresses contained in a local + * table for a given port. + * It also programs the port's current physical MAC address. + * + * It calls either SkAddrXmacMcUpdate or SkAddrGmacMcUpdate, according + * to the adapter in use. The real work is done there. + * + * Notes: + * The return code is only valid for SK_PROM_MODE_NONE. + * + * Context: + * runtime, pageable + * may be called after SK_INIT_IO + * + * Returns: + * SK_MC_FILTERING_EXACT + * SK_MC_FILTERING_INEXACT + * SK_ADDR_ILLEGAL_PORT + */ +int SkAddrMcUpdate( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* I/O context */ +SK_U32 PortNumber) /* Port Number */ +{ + int ReturnCode = 0; +#if (!defined(SK_SLIM) || defined(DEBUG)) + if (PortNumber >= (SK_U32) pAC->GIni.GIMacsFound) { + return (SK_ADDR_ILLEGAL_PORT); + } +#endif /* !SK_SLIM || DEBUG */ + +#ifdef GENESIS + if (pAC->GIni.GIGenesis) { + ReturnCode = SkAddrXmacMcUpdate(pAC, IoC, PortNumber); + } +#endif /* GENESIS */ +#ifdef YUKON + if (!pAC->GIni.GIGenesis) { + ReturnCode = SkAddrGmacMcUpdate(pAC, IoC, PortNumber); + } +#endif /* YUKON */ + return (ReturnCode); + +} /* SkAddrMcUpdate */ + + +#ifdef GENESIS + +/****************************************************************************** + * + * SkAddrXmacMcUpdate - update the HW MC address table and set the MAC address + * + * Description: + * This routine enables reception of the addresses contained in a local + * table for a given port. + * It also programs the port's current physical MAC address. + * + * Notes: + * The return code is only valid for SK_PROM_MODE_NONE. + * + * Context: + * runtime, pageable + * may be called after SK_INIT_IO + * + * Returns: + * SK_MC_FILTERING_EXACT + * SK_MC_FILTERING_INEXACT + * SK_ADDR_ILLEGAL_PORT + */ +static int SkAddrXmacMcUpdate( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* I/O context */ +SK_U32 PortNumber) /* Port Number */ +{ + SK_U32 i; + SK_U8 Inexact; + SK_U16 *OutAddr; + SK_ADDR_PORT *pAPort; + + SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL, + ("SkAddrXmacMcUpdate on Port %u.\n", PortNumber)) + + pAPort = &pAC->Addr.Port[PortNumber]; + +#ifdef DEBUG + SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL, + ("Next0 on Port %d: %d\n", PortNumber, Next0[PortNumber])) +#endif /* DEBUG */ + + /* Start with 0 to also program the logical MAC address. */ + for (i = 0; i < pAPort->NextExactMatchRlmt; i++) { + /* Set exact match address i on XMAC */ + OutAddr = (SK_U16 *) &pAPort->Exact[i].a[0]; + XM_OUTADDR(IoC, PortNumber, XM_EXM(i), OutAddr); + } + + /* Clear other permanent exact match addresses on XMAC */ + if (pAPort->NextExactMatchRlmt <= SK_ADDR_LAST_MATCH_RLMT) { + + SkXmClrExactAddr(pAC, IoC, PortNumber, pAPort->NextExactMatchRlmt, + SK_ADDR_LAST_MATCH_RLMT); + } + + for (i = pAPort->FirstExactMatchDrv; i < pAPort->NextExactMatchDrv; i++) { + OutAddr = (SK_U16 *) &pAPort->Exact[i].a[0]; + XM_OUTADDR(IoC, PortNumber, XM_EXM(i), OutAddr); + } + + /* Clear other non-permanent exact match addresses on XMAC */ + if (pAPort->NextExactMatchDrv <= SK_ADDR_LAST_MATCH_DRV) { + + SkXmClrExactAddr(pAC, IoC, PortNumber, pAPort->NextExactMatchDrv, + SK_ADDR_LAST_MATCH_DRV); + } + + for (Inexact = 0, i = 0; i < 8; i++) { + Inexact |= pAPort->InexactFilter.Bytes[i]; + } + + if (pAPort->PromMode & SK_PROM_MODE_ALL_MC) { + + /* Set all bits in 64-bit hash register. */ + XM_OUTHASH(IoC, PortNumber, XM_HSM, &OnesHash); + + /* Enable Hashing */ + SkMacHashing(pAC, IoC, (int) PortNumber, SK_TRUE); + } + else if (Inexact != 0) { + + /* Set 64-bit hash register to InexactFilter. */ + XM_OUTHASH(IoC, PortNumber, XM_HSM, &pAPort->InexactFilter.Bytes[0]); + + /* Enable Hashing */ + SkMacHashing(pAC, IoC, (int) PortNumber, SK_TRUE); + } + else { + /* Disable Hashing */ + SkMacHashing(pAC, IoC, (int) PortNumber, SK_FALSE); + } + + if (pAPort->PromMode != SK_PROM_MODE_NONE) { + (void) SkAddrXmacPromiscuousChange(pAC, IoC, PortNumber, pAPort->PromMode); + } + + /* Set port's current physical MAC address. */ + OutAddr = (SK_U16 *) &pAPort->CurrentMacAddress.a[0]; + + XM_OUTADDR(IoC, PortNumber, XM_SA, OutAddr); + +#ifdef xDEBUG + for (i = 0; i < pAPort->NextExactMatchRlmt; i++) { + SK_U8 InAddr8[6]; + SK_U16 *InAddr; + + /* Get exact match address i from port PortNumber. */ + InAddr = (SK_U16 *) &InAddr8[0]; + + XM_INADDR(IoC, PortNumber, XM_EXM(i), InAddr); + + SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL, + ("SkAddrXmacMcUpdate: MC address %d on Port %u: ", + "%02x %02x %02x %02x %02x %02x -- %02x %02x %02x %02x %02x %02x\n", + i, + PortNumber, + InAddr8[0], + InAddr8[1], + InAddr8[2], + InAddr8[3], + InAddr8[4], + InAddr8[5], + pAPort->Exact[i].a[0], + pAPort->Exact[i].a[1], + pAPort->Exact[i].a[2], + pAPort->Exact[i].a[3], + pAPort->Exact[i].a[4], + pAPort->Exact[i].a[5])) + } +#endif /* DEBUG */ + + /* Determine return value. */ + if (Inexact == 0 && pAPort->PromMode == 0) { + return (SK_MC_FILTERING_EXACT); + } + else { + return (SK_MC_FILTERING_INEXACT); + } + +} /* SkAddrXmacMcUpdate */ + +#endif /* GENESIS */ + +#ifdef YUKON + +/****************************************************************************** + * + * SkAddrGmacMcUpdate - update the HW MC address table and set the MAC address + * + * Description: + * This routine enables reception of the addresses contained in a local + * table for a given port. + * It also programs the port's current physical MAC address. + * + * Notes: + * The return code is only valid for SK_PROM_MODE_NONE. + * + * Context: + * runtime, pageable + * may be called after SK_INIT_IO + * + * Returns: + * SK_MC_FILTERING_EXACT + * SK_MC_FILTERING_INEXACT + * SK_ADDR_ILLEGAL_PORT + */ +static int SkAddrGmacMcUpdate( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* I/O context */ +SK_U32 PortNumber) /* Port Number */ +{ +#ifndef SK_SLIM + SK_U32 i; + SK_U8 Inexact; +#endif /* not SK_SLIM */ + SK_U16 *OutAddr; + SK_ADDR_PORT *pAPort; + + SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL, + ("SkAddrGmacMcUpdate on Port %u.\n", PortNumber)) + + pAPort = &pAC->Addr.Port[PortNumber]; + +#ifdef DEBUG + SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL, + ("Next0 on Port %d: %d\n", PortNumber, Next0[PortNumber])) +#endif /* DEBUG */ + +#ifndef SK_SLIM + for (Inexact = 0, i = 0; i < 8; i++) { + Inexact |= pAPort->InexactFilter.Bytes[i]; + } + + /* Set 64-bit hash register to InexactFilter. */ + GM_OUTHASH(IoC, PortNumber, GM_MC_ADDR_H1, + &pAPort->InexactFilter.Bytes[0]); + + if (pAPort->PromMode & SK_PROM_MODE_ALL_MC) { + + /* Set all bits in 64-bit hash register. */ + GM_OUTHASH(IoC, PortNumber, GM_MC_ADDR_H1, &OnesHash); + + /* Enable Hashing */ + SkMacHashing(pAC, IoC, (int) PortNumber, SK_TRUE); + } + else { + /* Enable Hashing. */ + SkMacHashing(pAC, IoC, (int) PortNumber, SK_TRUE); + } + + if (pAPort->PromMode != SK_PROM_MODE_NONE) { + (void) SkAddrGmacPromiscuousChange(pAC, IoC, PortNumber, pAPort->PromMode); + } +#else /* SK_SLIM */ + + /* Set all bits in 64-bit hash register. */ + GM_OUTHASH(IoC, PortNumber, GM_MC_ADDR_H1, &OnesHash); + + /* Enable Hashing */ + SkMacHashing(pAC, IoC, (int) PortNumber, SK_TRUE); + + (void) SkAddrGmacPromiscuousChange(pAC, IoC, PortNumber, pAPort->PromMode); + +#endif /* SK_SLIM */ + + /* Set port's current physical MAC address. */ + OutAddr = (SK_U16 *) &pAPort->CurrentMacAddress.a[0]; + GM_OUTADDR(IoC, PortNumber, GM_SRC_ADDR_1L, OutAddr); + + /* Set port's current logical MAC address. */ + OutAddr = (SK_U16 *) &pAPort->Exact[0].a[0]; + GM_OUTADDR(IoC, PortNumber, GM_SRC_ADDR_2L, OutAddr); + +#ifdef DEBUG + SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL, + ("SkAddrGmacMcUpdate: Permanent Physical MAC Address: %02X %02X %02X %02X %02X %02X\n", + pAPort->Exact[0].a[0], + pAPort->Exact[0].a[1], + pAPort->Exact[0].a[2], + pAPort->Exact[0].a[3], + pAPort->Exact[0].a[4], + pAPort->Exact[0].a[5])) + + SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL, + ("SkAddrGmacMcUpdate: Physical MAC Address: %02X %02X %02X %02X %02X %02X\n", + pAPort->CurrentMacAddress.a[0], + pAPort->CurrentMacAddress.a[1], + pAPort->CurrentMacAddress.a[2], + pAPort->CurrentMacAddress.a[3], + pAPort->CurrentMacAddress.a[4], + pAPort->CurrentMacAddress.a[5])) +#endif /* DEBUG */ + +#ifndef SK_SLIM + /* Determine return value. */ + if (Inexact == 0 && pAPort->PromMode == 0) { + return (SK_MC_FILTERING_EXACT); + } + else { + return (SK_MC_FILTERING_INEXACT); + } +#else /* SK_SLIM */ + return (SK_MC_FILTERING_INEXACT); +#endif /* SK_SLIM */ + +} /* SkAddrGmacMcUpdate */ + +#endif /* YUKON */ + +#ifndef SK_NO_MAO + +/****************************************************************************** + * + * SkAddrOverride - override a port's MAC address + * + * Description: + * This routine overrides the MAC address of one port. + * + * Context: + * runtime, pageable + * may be called after SK_INIT_IO + * + * Returns: + * SK_ADDR_SUCCESS if successful. + * SK_ADDR_DUPLICATE_ADDRESS if duplicate MAC address. + * SK_ADDR_MULTICAST_ADDRESS if multicast or broadcast address. + * SK_ADDR_TOO_EARLY if SK_INIT_IO was not executed before. + */ +int SkAddrOverride( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* I/O context */ +SK_U32 PortNumber, /* Port Number */ +SK_MAC_ADDR SK_FAR *pNewAddr, /* new MAC address */ +int Flags) /* logical/physical MAC address */ +{ +#ifndef SK_NO_RLMT + SK_EVPARA Para; +#endif /* !SK_NO_RLMT */ + SK_U32 NetNumber; + SK_U32 i; + SK_U16 SK_FAR *OutAddr; + +#ifndef SK_NO_RLMT + NetNumber = pAC->Rlmt.Port[PortNumber].Net->NetNumber; +#else + NetNumber = 0; +#endif /* SK_NO_RLMT */ +#if (!defined(SK_SLIM) || defined(DEBUG)) + if (PortNumber >= (SK_U32) pAC->GIni.GIMacsFound) { + return (SK_ADDR_ILLEGAL_PORT); + } +#endif /* !SK_SLIM || DEBUG */ + if (pNewAddr != NULL && (pNewAddr->a[0] & SK_MC_BIT) != 0) { + return (SK_ADDR_MULTICAST_ADDRESS); + } + + if (!pAC->Addr.Net[NetNumber].CurrentMacAddressSet) { + return (SK_ADDR_TOO_EARLY); + } + + if (Flags & SK_ADDR_SET_LOGICAL) { /* Activate logical MAC address. */ + /* Parameter *pNewAddr is ignored. */ + for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) { + if (!pAC->Addr.Port[i].CurrentMacAddressSet) { + return (SK_ADDR_TOO_EARLY); + } + } +#ifndef SK_NO_RLMT + /* Set PortNumber to number of net's active port. */ + PortNumber = pAC->Rlmt.Net[NetNumber]. + Port[pAC->Addr.Net[NetNumber].ActivePort]->PortNumber; +#endif /* !SK_NO_RLMT */ + pAC->Addr.Port[PortNumber].Exact[0] = + pAC->Addr.Net[NetNumber].CurrentMacAddress; + + /* Write address to first exact match entry of active port. */ + (void) SkAddrMcUpdate(pAC, IoC, PortNumber); + } + else if (Flags & SK_ADDR_CLEAR_LOGICAL) { + /* Deactivate logical MAC address. */ + /* Parameter *pNewAddr is ignored. */ + for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) { + if (!pAC->Addr.Port[i].CurrentMacAddressSet) { + return (SK_ADDR_TOO_EARLY); + } + } +#ifndef SK_NO_RLMT + /* Set PortNumber to number of net's active port. */ + PortNumber = pAC->Rlmt.Net[NetNumber]. + Port[pAC->Addr.Net[NetNumber].ActivePort]->PortNumber; +#endif /* !SK_NO_RLMT */ + for (i = 0; i < SK_MAC_ADDR_LEN; i++ ) { + pAC->Addr.Port[PortNumber].Exact[0].a[i] = 0; + } + + /* Write address to first exact match entry of active port. */ + (void) SkAddrMcUpdate(pAC, IoC, PortNumber); + } + else if (Flags & SK_ADDR_PHYSICAL_ADDRESS) { /* Physical MAC address. */ + if (SK_ADDR_EQUAL(pNewAddr->a, + pAC->Addr.Net[NetNumber].CurrentMacAddress.a)) { + return (SK_ADDR_DUPLICATE_ADDRESS); + } + + for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) { + if (!pAC->Addr.Port[i].CurrentMacAddressSet) { + return (SK_ADDR_TOO_EARLY); + } + + if (SK_ADDR_EQUAL(pNewAddr->a, + pAC->Addr.Port[i].CurrentMacAddress.a)) { + if (i == PortNumber) { + return (SK_ADDR_SUCCESS); + } + else { + return (SK_ADDR_DUPLICATE_ADDRESS); + } + } + } + + pAC->Addr.Port[PortNumber].PreviousMacAddress = + pAC->Addr.Port[PortNumber].CurrentMacAddress; + pAC->Addr.Port[PortNumber].CurrentMacAddress = *pNewAddr; + + /* Change port's physical MAC address. */ + OutAddr = (SK_U16 SK_FAR *) pNewAddr; +#ifdef GENESIS + if (pAC->GIni.GIGenesis) { + XM_OUTADDR(IoC, PortNumber, XM_SA, OutAddr); + } +#endif /* GENESIS */ +#ifdef YUKON + if (!pAC->GIni.GIGenesis) { + GM_OUTADDR(IoC, PortNumber, GM_SRC_ADDR_1L, OutAddr); + } +#endif /* YUKON */ + +#ifndef SK_NO_RLMT + /* Report address change to RLMT. */ + Para.Para32[0] = PortNumber; + Para.Para32[0] = -1; + SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_PORT_ADDR, Para); +#endif /* !SK_NO_RLMT */ + } + else { /* Logical MAC address. */ + if (SK_ADDR_EQUAL(pNewAddr->a, + pAC->Addr.Net[NetNumber].CurrentMacAddress.a)) { + return (SK_ADDR_SUCCESS); + } + + for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) { + if (!pAC->Addr.Port[i].CurrentMacAddressSet) { + return (SK_ADDR_TOO_EARLY); + } + + if (SK_ADDR_EQUAL(pNewAddr->a, + pAC->Addr.Port[i].CurrentMacAddress.a)) { + return (SK_ADDR_DUPLICATE_ADDRESS); + } + } + + /* + * In case that the physical and the logical MAC addresses are equal + * we must also change the physical MAC address here. + * In this case we have an adapter which initially was programmed with + * two identical MAC addresses. + */ + if (SK_ADDR_EQUAL(pAC->Addr.Port[PortNumber].CurrentMacAddress.a, + pAC->Addr.Port[PortNumber].Exact[0].a)) { + + pAC->Addr.Port[PortNumber].PreviousMacAddress = + pAC->Addr.Port[PortNumber].CurrentMacAddress; + pAC->Addr.Port[PortNumber].CurrentMacAddress = *pNewAddr; + +#ifndef SK_NO_RLMT + /* Report address change to RLMT. */ + Para.Para32[0] = PortNumber; + Para.Para32[0] = -1; + SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_PORT_ADDR, Para); +#endif /* !SK_NO_RLMT */ + } + +#ifndef SK_NO_RLMT + /* Set PortNumber to number of net's active port. */ + PortNumber = pAC->Rlmt.Net[NetNumber]. + Port[pAC->Addr.Net[NetNumber].ActivePort]->PortNumber; +#endif /* !SK_NO_RLMT */ + pAC->Addr.Net[NetNumber].CurrentMacAddress = *pNewAddr; + pAC->Addr.Port[PortNumber].Exact[0] = *pNewAddr; +#ifdef DEBUG + SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL, + ("SkAddrOverride: Permanent MAC Address: %02X %02X %02X %02X %02X %02X\n", + pAC->Addr.Net[NetNumber].PermanentMacAddress.a[0], + pAC->Addr.Net[NetNumber].PermanentMacAddress.a[1], + pAC->Addr.Net[NetNumber].PermanentMacAddress.a[2], + pAC->Addr.Net[NetNumber].PermanentMacAddress.a[3], + pAC->Addr.Net[NetNumber].PermanentMacAddress.a[4], + pAC->Addr.Net[NetNumber].PermanentMacAddress.a[5])) + + SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL, + ("SkAddrOverride: New logical MAC Address: %02X %02X %02X %02X %02X %02X\n", + pAC->Addr.Net[NetNumber].CurrentMacAddress.a[0], + pAC->Addr.Net[NetNumber].CurrentMacAddress.a[1], + pAC->Addr.Net[NetNumber].CurrentMacAddress.a[2], + pAC->Addr.Net[NetNumber].CurrentMacAddress.a[3], + pAC->Addr.Net[NetNumber].CurrentMacAddress.a[4], + pAC->Addr.Net[NetNumber].CurrentMacAddress.a[5])) +#endif /* DEBUG */ + + /* Write address to first exact match entry of active port. */ + (void) SkAddrMcUpdate(pAC, IoC, PortNumber); + } + + return (SK_ADDR_SUCCESS); + +} /* SkAddrOverride */ + + +#endif /* SK_NO_MAO */ + +/****************************************************************************** + * + * SkAddrPromiscuousChange - set promiscuous mode for given port + * + * Description: + * This routine manages promiscuous mode: + * - none + * - all LLC frames + * - all MC frames + * + * It calls either SkAddrXmacPromiscuousChange or + * SkAddrGmacPromiscuousChange, according to the adapter in use. + * The real work is done there. + * + * Context: + * runtime, pageable + * may be called after SK_INIT_IO + * + * Returns: + * SK_ADDR_SUCCESS + * SK_ADDR_ILLEGAL_PORT + */ +int SkAddrPromiscuousChange( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* I/O context */ +SK_U32 PortNumber, /* port whose promiscuous mode changes */ +int NewPromMode) /* new promiscuous mode */ +{ + int ReturnCode = 0; +#if (!defined(SK_SLIM) || defined(DEBUG)) + if (PortNumber >= (SK_U32) pAC->GIni.GIMacsFound) { + return (SK_ADDR_ILLEGAL_PORT); + } +#endif /* !SK_SLIM || DEBUG */ + +#ifdef GENESIS + if (pAC->GIni.GIGenesis) { + ReturnCode = + SkAddrXmacPromiscuousChange(pAC, IoC, PortNumber, NewPromMode); + } +#endif /* GENESIS */ +#ifdef YUKON + if (!pAC->GIni.GIGenesis) { + ReturnCode = + SkAddrGmacPromiscuousChange(pAC, IoC, PortNumber, NewPromMode); + } +#endif /* YUKON */ + + return (ReturnCode); + +} /* SkAddrPromiscuousChange */ + +#ifdef GENESIS + +/****************************************************************************** + * + * SkAddrXmacPromiscuousChange - set promiscuous mode for given port + * + * Description: + * This routine manages promiscuous mode: + * - none + * - all LLC frames + * - all MC frames + * + * Context: + * runtime, pageable + * may be called after SK_INIT_IO + * + * Returns: + * SK_ADDR_SUCCESS + * SK_ADDR_ILLEGAL_PORT + */ +static int SkAddrXmacPromiscuousChange( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* I/O context */ +SK_U32 PortNumber, /* port whose promiscuous mode changes */ +int NewPromMode) /* new promiscuous mode */ +{ + int i; + SK_BOOL InexactModeBit; + SK_U8 Inexact; + SK_U8 HwInexact; + SK_FILTER64 HwInexactFilter; + SK_U16 LoMode; /* Lower 16 bits of XMAC Mode Register. */ + int CurPromMode = SK_PROM_MODE_NONE; + + /* Read CurPromMode from Hardware. */ + XM_IN16(IoC, PortNumber, XM_MODE, &LoMode); + + if ((LoMode & XM_MD_ENA_PROM) != 0) { + /* Promiscuous mode! */ + CurPromMode |= SK_PROM_MODE_LLC; + } + + for (Inexact = 0xFF, i = 0; i < 8; i++) { + Inexact &= pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i]; + } + if (Inexact == 0xFF) { + CurPromMode |= (pAC->Addr.Port[PortNumber].PromMode & SK_PROM_MODE_ALL_MC); + } + else { + /* Get InexactModeBit (bit XM_MD_ENA_HASH in mode register) */ + XM_IN16(IoC, PortNumber, XM_MODE, &LoMode); + + InexactModeBit = (LoMode & XM_MD_ENA_HASH) != 0; + + /* Read 64-bit hash register from XMAC */ + XM_INHASH(IoC, PortNumber, XM_HSM, &HwInexactFilter.Bytes[0]); + + for (HwInexact = 0xFF, i = 0; i < 8; i++) { + HwInexact &= HwInexactFilter.Bytes[i]; + } + + if (InexactModeBit && (HwInexact == 0xFF)) { + CurPromMode |= SK_PROM_MODE_ALL_MC; + } + } + + pAC->Addr.Port[PortNumber].PromMode = NewPromMode; + + if (NewPromMode == CurPromMode) { + return (SK_ADDR_SUCCESS); + } + + if ((NewPromMode & SK_PROM_MODE_ALL_MC) && + !(CurPromMode & SK_PROM_MODE_ALL_MC)) { /* All MC. */ + + /* Set all bits in 64-bit hash register. */ + XM_OUTHASH(IoC, PortNumber, XM_HSM, &OnesHash); + + /* Enable Hashing */ + SkMacHashing(pAC, IoC, (int) PortNumber, SK_TRUE); + } + else if ((CurPromMode & SK_PROM_MODE_ALL_MC) && + !(NewPromMode & SK_PROM_MODE_ALL_MC)) { /* Norm MC. */ + for (Inexact = 0, i = 0; i < 8; i++) { + Inexact |= pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i]; + } + if (Inexact == 0) { + /* Disable Hashing */ + SkMacHashing(pAC, IoC, (int) PortNumber, SK_FALSE); + } + else { + /* Set 64-bit hash register to InexactFilter. */ + XM_OUTHASH(IoC, PortNumber, XM_HSM, + &pAC->Addr.Port[PortNumber].InexactFilter.Bytes[0]); + + /* Enable Hashing */ + SkMacHashing(pAC, IoC, (int) PortNumber, SK_TRUE); + } + } + + if ((NewPromMode & SK_PROM_MODE_LLC) && + !(CurPromMode & SK_PROM_MODE_LLC)) { /* Prom. LLC */ + /* Set the MAC in Promiscuous Mode */ + SkMacPromiscMode(pAC, IoC, (int) PortNumber, SK_TRUE); + } + else if ((CurPromMode & SK_PROM_MODE_LLC) && + !(NewPromMode & SK_PROM_MODE_LLC)) { /* Norm. LLC. */ + /* Clear Promiscuous Mode */ + SkMacPromiscMode(pAC, IoC, (int) PortNumber, SK_FALSE); + } + + return (SK_ADDR_SUCCESS); + +} /* SkAddrXmacPromiscuousChange */ + +#endif /* GENESIS */ + +#ifdef YUKON + +/****************************************************************************** + * + * SkAddrGmacPromiscuousChange - set promiscuous mode for given port + * + * Description: + * This routine manages promiscuous mode: + * - none + * - all LLC frames + * - all MC frames + * + * Context: + * runtime, pageable + * may be called after SK_INIT_IO + * + * Returns: + * SK_ADDR_SUCCESS + * SK_ADDR_ILLEGAL_PORT + */ +static int SkAddrGmacPromiscuousChange( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* I/O context */ +SK_U32 PortNumber, /* port whose promiscuous mode changes */ +int NewPromMode) /* new promiscuous mode */ +{ + SK_U16 ReceiveControl; /* GMAC Receive Control Register */ + int CurPromMode = SK_PROM_MODE_NONE; + + /* Read CurPromMode from Hardware. */ + GM_IN16(IoC, PortNumber, GM_RX_CTRL, &ReceiveControl); + + if ((ReceiveControl & (GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA)) == 0) { + /* Promiscuous mode! */ + CurPromMode |= SK_PROM_MODE_LLC; + } + + if ((ReceiveControl & GM_RXCR_MCF_ENA) == 0) { + /* All Multicast mode! */ + CurPromMode |= (pAC->Addr.Port[PortNumber].PromMode & SK_PROM_MODE_ALL_MC); + } + + pAC->Addr.Port[PortNumber].PromMode = NewPromMode; + + if (NewPromMode == CurPromMode) { + return (SK_ADDR_SUCCESS); + } + + if ((NewPromMode & SK_PROM_MODE_ALL_MC) && + !(CurPromMode & SK_PROM_MODE_ALL_MC)) { /* All MC */ + + /* Set all bits in 64-bit hash register. */ + GM_OUTHASH(IoC, PortNumber, GM_MC_ADDR_H1, &OnesHash); + + /* Enable Hashing */ + SkMacHashing(pAC, IoC, (int) PortNumber, SK_TRUE); + } + + if ((CurPromMode & SK_PROM_MODE_ALL_MC) && + !(NewPromMode & SK_PROM_MODE_ALL_MC)) { /* Norm. MC */ + + /* Set 64-bit hash register to InexactFilter. */ + GM_OUTHASH(IoC, PortNumber, GM_MC_ADDR_H1, + &pAC->Addr.Port[PortNumber].InexactFilter.Bytes[0]); + + /* Enable Hashing. */ + SkMacHashing(pAC, IoC, (int) PortNumber, SK_TRUE); + } + + if ((NewPromMode & SK_PROM_MODE_LLC) && + !(CurPromMode & SK_PROM_MODE_LLC)) { /* Prom. LLC */ + + /* Set the MAC to Promiscuous Mode. */ + SkMacPromiscMode(pAC, IoC, (int) PortNumber, SK_TRUE); + } + else if ((CurPromMode & SK_PROM_MODE_LLC) && + !(NewPromMode & SK_PROM_MODE_LLC)) { /* Norm. LLC */ + + /* Clear Promiscuous Mode. */ + SkMacPromiscMode(pAC, IoC, (int) PortNumber, SK_FALSE); + } + + return (SK_ADDR_SUCCESS); + +} /* SkAddrGmacPromiscuousChange */ + +#endif /* YUKON */ + +#ifndef SK_SLIM + +/****************************************************************************** + * + * SkAddrSwap - swap address info + * + * Description: + * This routine swaps address info of two ports. + * + * Context: + * runtime, pageable + * may be called after SK_INIT_IO + * + * Returns: + * SK_ADDR_SUCCESS + * SK_ADDR_ILLEGAL_PORT + */ +int SkAddrSwap( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* I/O context */ +SK_U32 FromPortNumber, /* Port1 Index */ +SK_U32 ToPortNumber) /* Port2 Index */ +{ + int i; + SK_U8 Byte; + SK_MAC_ADDR MacAddr; + SK_U32 DWord; + + if (FromPortNumber >= (SK_U32) pAC->GIni.GIMacsFound) { + return (SK_ADDR_ILLEGAL_PORT); + } + + if (ToPortNumber >= (SK_U32) pAC->GIni.GIMacsFound) { + return (SK_ADDR_ILLEGAL_PORT); + } + + if (pAC->Rlmt.Port[FromPortNumber].Net != pAC->Rlmt.Port[ToPortNumber].Net) { + return (SK_ADDR_ILLEGAL_PORT); + } + + /* + * Swap: + * - Exact Match Entries (GEnesis and Yukon) + * Yukon uses first entry for the logical MAC + * address (stored in the second GMAC register). + * - FirstExactMatchRlmt (GEnesis only) + * - NextExactMatchRlmt (GEnesis only) + * - FirstExactMatchDrv (GEnesis only) + * - NextExactMatchDrv (GEnesis only) + * - 64-bit filter (InexactFilter) + * - Promiscuous Mode + * of ports. + */ + + for (i = 0; i < SK_ADDR_EXACT_MATCHES; i++) { + MacAddr = pAC->Addr.Port[FromPortNumber].Exact[i]; + pAC->Addr.Port[FromPortNumber].Exact[i] = + pAC->Addr.Port[ToPortNumber].Exact[i]; + pAC->Addr.Port[ToPortNumber].Exact[i] = MacAddr; + } + + for (i = 0; i < 8; i++) { + Byte = pAC->Addr.Port[FromPortNumber].InexactFilter.Bytes[i]; + pAC->Addr.Port[FromPortNumber].InexactFilter.Bytes[i] = + pAC->Addr.Port[ToPortNumber].InexactFilter.Bytes[i]; + pAC->Addr.Port[ToPortNumber].InexactFilter.Bytes[i] = Byte; + } + + i = pAC->Addr.Port[FromPortNumber].PromMode; + pAC->Addr.Port[FromPortNumber].PromMode = pAC->Addr.Port[ToPortNumber].PromMode; + pAC->Addr.Port[ToPortNumber].PromMode = i; + + if (pAC->GIni.GIGenesis) { + DWord = pAC->Addr.Port[FromPortNumber].FirstExactMatchRlmt; + pAC->Addr.Port[FromPortNumber].FirstExactMatchRlmt = + pAC->Addr.Port[ToPortNumber].FirstExactMatchRlmt; + pAC->Addr.Port[ToPortNumber].FirstExactMatchRlmt = DWord; + + DWord = pAC->Addr.Port[FromPortNumber].NextExactMatchRlmt; + pAC->Addr.Port[FromPortNumber].NextExactMatchRlmt = + pAC->Addr.Port[ToPortNumber].NextExactMatchRlmt; + pAC->Addr.Port[ToPortNumber].NextExactMatchRlmt = DWord; + + DWord = pAC->Addr.Port[FromPortNumber].FirstExactMatchDrv; + pAC->Addr.Port[FromPortNumber].FirstExactMatchDrv = + pAC->Addr.Port[ToPortNumber].FirstExactMatchDrv; + pAC->Addr.Port[ToPortNumber].FirstExactMatchDrv = DWord; + + DWord = pAC->Addr.Port[FromPortNumber].NextExactMatchDrv; + pAC->Addr.Port[FromPortNumber].NextExactMatchDrv = + pAC->Addr.Port[ToPortNumber].NextExactMatchDrv; + pAC->Addr.Port[ToPortNumber].NextExactMatchDrv = DWord; + } + + /* CAUTION: Solution works if only ports of one adapter are in use. */ + for (i = 0; (SK_U32) i < pAC->Rlmt.Net[pAC->Rlmt.Port[ToPortNumber]. + Net->NetNumber].NumPorts; i++) { + if (pAC->Rlmt.Net[pAC->Rlmt.Port[ToPortNumber].Net->NetNumber]. + Port[i]->PortNumber == ToPortNumber) { + pAC->Addr.Net[pAC->Rlmt.Port[ToPortNumber].Net->NetNumber]. + ActivePort = i; + /* 20001207 RA: Was "ToPortNumber;". */ + } + } + + (void) SkAddrMcUpdate(pAC, IoC, FromPortNumber); + (void) SkAddrMcUpdate(pAC, IoC, ToPortNumber); + + return (SK_ADDR_SUCCESS); + +} /* SkAddrSwap */ + +#endif /* !SK_SLIM */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + diff --git a/drivers/net/sk98lin/skdim.c b/drivers/net/sk98lin/skdim.c new file mode 100644 index 000000000000..37ce03fb8de3 --- /dev/null +++ b/drivers/net/sk98lin/skdim.c @@ -0,0 +1,742 @@ +/****************************************************************************** + * + * Name: skdim.c + * Project: GEnesis, PCI Gigabit Ethernet Adapter + * Version: $Revision: 1.5 $ + * Date: $Date: 2003/11/28 12:55:40 $ + * Purpose: All functions to maintain interrupt moderation + * + ******************************************************************************/ + +/****************************************************************************** + * + * (C)Copyright 1998-2002 SysKonnect GmbH. + * (C)Copyright 2002-2003 Marvell. + * + * 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. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/****************************************************************************** + * + * Description: + * + * This module is intended to manage the dynamic interrupt moderation on both + * GEnesis and Yukon adapters. + * + * Include File Hierarchy: + * + * "skdrv1st.h" + * "skdrv2nd.h" + * + ******************************************************************************/ + +#ifndef lint +static const char SysKonnectFileId[] = + "@(#) $Id: skdim.c,v 1.5 2003/11/28 12:55:40 rroesler Exp $ (C) SysKonnect."; +#endif + +#define __SKADDR_C + +#ifdef __cplusplus +#error C++ is not yet supported. +extern "C" { +#endif + +/******************************************************************************* +** +** Includes +** +*******************************************************************************/ + +#ifndef __INC_SKDRV1ST_H +#include "h/skdrv1st.h" +#endif + +#ifndef __INC_SKDRV2ND_H +#include "h/skdrv2nd.h" +#endif + +#include <linux/kernel_stat.h> + +/******************************************************************************* +** +** Defines +** +*******************************************************************************/ + +/******************************************************************************* +** +** Typedefs +** +*******************************************************************************/ + +/******************************************************************************* +** +** Local function prototypes +** +*******************************************************************************/ + +static unsigned int GetCurrentSystemLoad(SK_AC *pAC); +static SK_U64 GetIsrCalls(SK_AC *pAC); +static SK_BOOL IsIntModEnabled(SK_AC *pAC); +static void SetCurrIntCtr(SK_AC *pAC); +static void EnableIntMod(SK_AC *pAC); +static void DisableIntMod(SK_AC *pAC); +static void ResizeDimTimerDuration(SK_AC *pAC); +static void DisplaySelectedModerationType(SK_AC *pAC); +static void DisplaySelectedModerationMask(SK_AC *pAC); +static void DisplayDescrRatio(SK_AC *pAC); + +/******************************************************************************* +** +** Global variables +** +*******************************************************************************/ + +/******************************************************************************* +** +** Local variables +** +*******************************************************************************/ + +/******************************************************************************* +** +** Global functions +** +*******************************************************************************/ + +/******************************************************************************* +** Function : SkDimModerate +** Description : Called in every ISR to check if moderation is to be applied +** or not for the current number of interrupts +** Programmer : Ralph Roesler +** Last Modified: 22-mar-03 +** Returns : void (!) +** Notes : - +*******************************************************************************/ + +void +SkDimModerate(SK_AC *pAC) { + unsigned int CurrSysLoad = 0; /* expressed in percent */ + unsigned int LoadIncrease = 0; /* expressed in percent */ + SK_U64 ThresholdInts = 0; + SK_U64 IsrCallsPerSec = 0; + +#define M_DIMINFO pAC->DynIrqModInfo + + if (!IsIntModEnabled(pAC)) { + if (M_DIMINFO.IntModTypeSelect == C_INT_MOD_DYNAMIC) { + CurrSysLoad = GetCurrentSystemLoad(pAC); + if (CurrSysLoad > 75) { + /* + ** More than 75% total system load! Enable the moderation + ** to shield the system against too many interrupts. + */ + EnableIntMod(pAC); + } else if (CurrSysLoad > M_DIMINFO.PrevSysLoad) { + LoadIncrease = (CurrSysLoad - M_DIMINFO.PrevSysLoad); + if (LoadIncrease > ((M_DIMINFO.PrevSysLoad * + C_INT_MOD_ENABLE_PERCENTAGE) / 100)) { + if (CurrSysLoad > 10) { + /* + ** More than 50% increase with respect to the + ** previous load of the system. Most likely this + ** is due to our ISR-proc... + */ + EnableIntMod(pAC); + } + } + } else { + /* + ** Neither too much system load at all nor too much increase + ** with respect to the previous system load. Hence, we can leave + ** the ISR-handling like it is without enabling moderation. + */ + } + M_DIMINFO.PrevSysLoad = CurrSysLoad; + } + } else { + if (M_DIMINFO.IntModTypeSelect == C_INT_MOD_DYNAMIC) { + ThresholdInts = ((M_DIMINFO.MaxModIntsPerSec * + C_INT_MOD_DISABLE_PERCENTAGE) / 100); + IsrCallsPerSec = GetIsrCalls(pAC); + if (IsrCallsPerSec <= ThresholdInts) { + /* + ** The number of interrupts within the last second is + ** lower than the disable_percentage of the desried + ** maxrate. Therefore we can disable the moderation. + */ + DisableIntMod(pAC); + M_DIMINFO.MaxModIntsPerSec = + (M_DIMINFO.MaxModIntsPerSecUpperLimit + + M_DIMINFO.MaxModIntsPerSecLowerLimit) / 2; + } else { + /* + ** The number of interrupts per sec is the same as expected. + ** Evalulate the descriptor-ratio. If it has changed, a resize + ** in the moderation timer might be useful + */ + if (M_DIMINFO.AutoSizing) { + ResizeDimTimerDuration(pAC); + } + } + } + } + + /* + ** Some information to the log... + */ + if (M_DIMINFO.DisplayStats) { + DisplaySelectedModerationType(pAC); + DisplaySelectedModerationMask(pAC); + DisplayDescrRatio(pAC); + } + + M_DIMINFO.NbrProcessedDescr = 0; + SetCurrIntCtr(pAC); +} + +/******************************************************************************* +** Function : SkDimStartModerationTimer +** Description : Starts the audit-timer for the dynamic interrupt moderation +** Programmer : Ralph Roesler +** Last Modified: 22-mar-03 +** Returns : void (!) +** Notes : - +*******************************************************************************/ + +void +SkDimStartModerationTimer(SK_AC *pAC) { + SK_EVPARA EventParam; /* Event struct for timer event */ + + SK_MEMSET((char *) &EventParam, 0, sizeof(EventParam)); + EventParam.Para32[0] = SK_DRV_MODERATION_TIMER; + SkTimerStart(pAC, pAC->IoBase, &pAC->DynIrqModInfo.ModTimer, + SK_DRV_MODERATION_TIMER_LENGTH, + SKGE_DRV, SK_DRV_TIMER, EventParam); +} + +/******************************************************************************* +** Function : SkDimEnableModerationIfNeeded +** Description : Either enables or disables moderation +** Programmer : Ralph Roesler +** Last Modified: 22-mar-03 +** Returns : void (!) +** Notes : This function is called when a particular adapter is opened +** There is no Disable function, because when all interrupts +** might be disable, the moderation timer has no meaning at all +******************************************************************************/ + +void +SkDimEnableModerationIfNeeded(SK_AC *pAC) { + + if (M_DIMINFO.IntModTypeSelect == C_INT_MOD_STATIC) { + EnableIntMod(pAC); /* notification print in this function */ + } else if (M_DIMINFO.IntModTypeSelect == C_INT_MOD_DYNAMIC) { + SkDimStartModerationTimer(pAC); + if (M_DIMINFO.DisplayStats) { + printk("Dynamic moderation has been enabled\n"); + } + } else { + if (M_DIMINFO.DisplayStats) { + printk("No moderation has been enabled\n"); + } + } +} + +/******************************************************************************* +** Function : SkDimDisplayModerationSettings +** Description : Displays the current settings regarding interrupt moderation +** Programmer : Ralph Roesler +** Last Modified: 22-mar-03 +** Returns : void (!) +** Notes : - +*******************************************************************************/ + +void +SkDimDisplayModerationSettings(SK_AC *pAC) { + DisplaySelectedModerationType(pAC); + DisplaySelectedModerationMask(pAC); +} + +/******************************************************************************* +** +** Local functions +** +*******************************************************************************/ + +/******************************************************************************* +** Function : GetCurrentSystemLoad +** Description : Retrieves the current system load of the system. This load +** is evaluated for all processors within the system. +** Programmer : Ralph Roesler +** Last Modified: 22-mar-03 +** Returns : unsigned int: load expressed in percentage +** Notes : The possible range being returned is from 0 up to 100. +** Whereas 0 means 'no load at all' and 100 'system fully loaded' +** It is impossible to determine what actually causes the system +** to be in 100%, but maybe that is due to too much interrupts. +*******************************************************************************/ + +static unsigned int +GetCurrentSystemLoad(SK_AC *pAC) { + unsigned long jif = jiffies; + unsigned int UserTime = 0; + unsigned int SystemTime = 0; + unsigned int NiceTime = 0; + unsigned int IdleTime = 0; + unsigned int TotalTime = 0; + unsigned int UsedTime = 0; + unsigned int SystemLoad = 0; + + /* unsigned int NbrCpu = 0; */ + + /* + ** The following lines have been commented out, because + ** from kernel 2.5.44 onwards, the kernel-owned structure + ** + ** struct kernel_stat kstat + ** + ** is not marked as an exported symbol in the file + ** + ** kernel/ksyms.c + ** + ** As a consequence, using this driver as KLM is not possible + ** and any access of the structure kernel_stat via the + ** dedicated macros kstat_cpu(i).cpustat.xxx is to be avoided. + ** + ** The kstat-information might be added again in future + ** versions of the 2.5.xx kernel, but for the time being, + ** number of interrupts will serve as indication how much + ** load we currently have... + ** + ** for (NbrCpu = 0; NbrCpu < num_online_cpus(); NbrCpu++) { + ** UserTime = UserTime + kstat_cpu(NbrCpu).cpustat.user; + ** NiceTime = NiceTime + kstat_cpu(NbrCpu).cpustat.nice; + ** SystemTime = SystemTime + kstat_cpu(NbrCpu).cpustat.system; + ** } + */ + SK_U64 ThresholdInts = 0; + SK_U64 IsrCallsPerSec = 0; + + ThresholdInts = ((M_DIMINFO.MaxModIntsPerSec * + C_INT_MOD_ENABLE_PERCENTAGE) + 100); + IsrCallsPerSec = GetIsrCalls(pAC); + if (IsrCallsPerSec >= ThresholdInts) { + /* + ** We do not know how much the real CPU-load is! + ** Return 80% as a default in order to activate DIM + */ + SystemLoad = 80; + return (SystemLoad); + } + + UsedTime = UserTime + NiceTime + SystemTime; + + IdleTime = jif * num_online_cpus() - UsedTime; + TotalTime = UsedTime + IdleTime; + + SystemLoad = ( 100 * (UsedTime - M_DIMINFO.PrevUsedTime) ) / + (TotalTime - M_DIMINFO.PrevTotalTime); + + if (M_DIMINFO.DisplayStats) { + printk("Current system load is: %u\n", SystemLoad); + } + + M_DIMINFO.PrevTotalTime = TotalTime; + M_DIMINFO.PrevUsedTime = UsedTime; + + return (SystemLoad); +} + +/******************************************************************************* +** Function : GetIsrCalls +** Description : Depending on the selected moderation mask, this function will +** return the number of interrupts handled in the previous time- +** frame. This evaluated number is based on the current number +** of interrupts stored in PNMI-context and the previous stored +** interrupts. +** Programmer : Ralph Roesler +** Last Modified: 23-mar-03 +** Returns : int: the number of interrupts being executed in the last +** timeframe +** Notes : It makes only sense to call this function, when dynamic +** interrupt moderation is applied +*******************************************************************************/ + +static SK_U64 +GetIsrCalls(SK_AC *pAC) { + SK_U64 RxPort0IntDiff = 0; + SK_U64 RxPort1IntDiff = 0; + SK_U64 TxPort0IntDiff = 0; + SK_U64 TxPort1IntDiff = 0; + + if (pAC->DynIrqModInfo.MaskIrqModeration == IRQ_MASK_TX_ONLY) { + if (pAC->GIni.GIMacsFound == 2) { + TxPort1IntDiff = pAC->Pnmi.Port[1].TxIntrCts - + pAC->DynIrqModInfo.PrevPort1TxIntrCts; + } + TxPort0IntDiff = pAC->Pnmi.Port[0].TxIntrCts - + pAC->DynIrqModInfo.PrevPort0TxIntrCts; + } else if (pAC->DynIrqModInfo.MaskIrqModeration == IRQ_MASK_RX_ONLY) { + if (pAC->GIni.GIMacsFound == 2) { + RxPort1IntDiff = pAC->Pnmi.Port[1].RxIntrCts - + pAC->DynIrqModInfo.PrevPort1RxIntrCts; + } + RxPort0IntDiff = pAC->Pnmi.Port[0].RxIntrCts - + pAC->DynIrqModInfo.PrevPort0RxIntrCts; + } else { + if (pAC->GIni.GIMacsFound == 2) { + RxPort1IntDiff = pAC->Pnmi.Port[1].RxIntrCts - + pAC->DynIrqModInfo.PrevPort1RxIntrCts; + TxPort1IntDiff = pAC->Pnmi.Port[1].TxIntrCts - + pAC->DynIrqModInfo.PrevPort1TxIntrCts; + } + RxPort0IntDiff = pAC->Pnmi.Port[0].RxIntrCts - + pAC->DynIrqModInfo.PrevPort0RxIntrCts; + TxPort0IntDiff = pAC->Pnmi.Port[0].TxIntrCts - + pAC->DynIrqModInfo.PrevPort0TxIntrCts; + } + + return (RxPort0IntDiff + RxPort1IntDiff + TxPort0IntDiff + TxPort1IntDiff); +} + +/******************************************************************************* +** Function : GetRxCalls +** Description : This function will return the number of times a receive inter- +** rupt was processed. This is needed to evaluate any resizing +** factor. +** Programmer : Ralph Roesler +** Last Modified: 23-mar-03 +** Returns : SK_U64: the number of RX-ints being processed +** Notes : It makes only sense to call this function, when dynamic +** interrupt moderation is applied +*******************************************************************************/ + +static SK_U64 +GetRxCalls(SK_AC *pAC) { + SK_U64 RxPort0IntDiff = 0; + SK_U64 RxPort1IntDiff = 0; + + if (pAC->GIni.GIMacsFound == 2) { + RxPort1IntDiff = pAC->Pnmi.Port[1].RxIntrCts - + pAC->DynIrqModInfo.PrevPort1RxIntrCts; + } + RxPort0IntDiff = pAC->Pnmi.Port[0].RxIntrCts - + pAC->DynIrqModInfo.PrevPort0RxIntrCts; + + return (RxPort0IntDiff + RxPort1IntDiff); +} + +/******************************************************************************* +** Function : SetCurrIntCtr +** Description : Will store the current number orf occured interrupts in the +** adapter context. This is needed to evaluated the number of +** interrupts within a current timeframe. +** Programmer : Ralph Roesler +** Last Modified: 23-mar-03 +** Returns : void (!) +** Notes : - +*******************************************************************************/ + +static void +SetCurrIntCtr(SK_AC *pAC) { + if (pAC->GIni.GIMacsFound == 2) { + pAC->DynIrqModInfo.PrevPort1RxIntrCts = pAC->Pnmi.Port[1].RxIntrCts; + pAC->DynIrqModInfo.PrevPort1TxIntrCts = pAC->Pnmi.Port[1].TxIntrCts; + } + pAC->DynIrqModInfo.PrevPort0RxIntrCts = pAC->Pnmi.Port[0].RxIntrCts; + pAC->DynIrqModInfo.PrevPort0TxIntrCts = pAC->Pnmi.Port[0].TxIntrCts; +} + +/******************************************************************************* +** Function : IsIntModEnabled() +** Description : Retrieves the current value of the interrupts moderation +** command register. Its content determines whether any +** moderation is running or not. +** Programmer : Ralph Roesler +** Last Modified: 23-mar-03 +** Returns : SK_TRUE : if mod timer running +** SK_FALSE : if no moderation is being performed +** Notes : - +*******************************************************************************/ + +static SK_BOOL +IsIntModEnabled(SK_AC *pAC) { + unsigned long CtrCmd; + + SK_IN32(pAC->IoBase, B2_IRQM_CTRL, &CtrCmd); + if ((CtrCmd & TIM_START) == TIM_START) { + return SK_TRUE; + } else { + return SK_FALSE; + } +} + +/******************************************************************************* +** Function : EnableIntMod() +** Description : Enables the interrupt moderation using the values stored in +** in the pAC->DynIntMod data structure +** Programmer : Ralph Roesler +** Last Modified: 22-mar-03 +** Returns : - +** Notes : - +*******************************************************************************/ + +static void +EnableIntMod(SK_AC *pAC) { + unsigned long ModBase; + + if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) { + ModBase = C_CLK_FREQ_GENESIS / pAC->DynIrqModInfo.MaxModIntsPerSec; + } else { + ModBase = C_CLK_FREQ_YUKON / pAC->DynIrqModInfo.MaxModIntsPerSec; + } + + SK_OUT32(pAC->IoBase, B2_IRQM_INI, ModBase); + SK_OUT32(pAC->IoBase, B2_IRQM_MSK, pAC->DynIrqModInfo.MaskIrqModeration); + SK_OUT32(pAC->IoBase, B2_IRQM_CTRL, TIM_START); + if (M_DIMINFO.DisplayStats) { + printk("Enabled interrupt moderation (%i ints/sec)\n", + M_DIMINFO.MaxModIntsPerSec); + } +} + +/******************************************************************************* +** Function : DisableIntMod() +** Description : Disables the interrupt moderation independent of what inter- +** rupts are running or not +** Programmer : Ralph Roesler +** Last Modified: 23-mar-03 +** Returns : - +** Notes : - +*******************************************************************************/ + +static void +DisableIntMod(SK_AC *pAC) { + + SK_OUT32(pAC->IoBase, B2_IRQM_CTRL, TIM_STOP); + if (M_DIMINFO.DisplayStats) { + printk("Disabled interrupt moderation\n"); + } +} + +/******************************************************************************* +** Function : ResizeDimTimerDuration(); +** Description : Checks the current used descriptor ratio and resizes the +** duration timer (longer/smaller) if possible. +** Programmer : Ralph Roesler +** Last Modified: 23-mar-03 +** Returns : - +** Notes : There are both maximum and minimum timer duration value. +** This function assumes that interrupt moderation is already +** enabled! +*******************************************************************************/ + +static void +ResizeDimTimerDuration(SK_AC *pAC) { + SK_BOOL IncreaseTimerDuration; + int TotalMaxNbrDescr; + int UsedDescrRatio; + int RatioDiffAbs; + int RatioDiffRel; + int NewMaxModIntsPerSec; + int ModAdjValue; + long ModBase; + + /* + ** Check first if we are allowed to perform any modification + */ + if (IsIntModEnabled(pAC)) { + if (M_DIMINFO.IntModTypeSelect != C_INT_MOD_DYNAMIC) { + return; + } else { + if (M_DIMINFO.ModJustEnabled) { + M_DIMINFO.ModJustEnabled = SK_FALSE; + return; + } + } + } + + /* + ** If we got until here, we have to evaluate the amount of the + ** descriptor ratio change... + */ + TotalMaxNbrDescr = pAC->RxDescrPerRing * GetRxCalls(pAC); + UsedDescrRatio = (M_DIMINFO.NbrProcessedDescr * 100) / TotalMaxNbrDescr; + + if (UsedDescrRatio > M_DIMINFO.PrevUsedDescrRatio) { + RatioDiffAbs = (UsedDescrRatio - M_DIMINFO.PrevUsedDescrRatio); + RatioDiffRel = (RatioDiffAbs * 100) / UsedDescrRatio; + M_DIMINFO.PrevUsedDescrRatio = UsedDescrRatio; + IncreaseTimerDuration = SK_FALSE; /* in other words: DECREASE */ + } else if (UsedDescrRatio < M_DIMINFO.PrevUsedDescrRatio) { + RatioDiffAbs = (M_DIMINFO.PrevUsedDescrRatio - UsedDescrRatio); + RatioDiffRel = (RatioDiffAbs * 100) / M_DIMINFO.PrevUsedDescrRatio; + M_DIMINFO.PrevUsedDescrRatio = UsedDescrRatio; + IncreaseTimerDuration = SK_TRUE; /* in other words: INCREASE */ + } else { + RatioDiffAbs = (M_DIMINFO.PrevUsedDescrRatio - UsedDescrRatio); + RatioDiffRel = (RatioDiffAbs * 100) / M_DIMINFO.PrevUsedDescrRatio; + M_DIMINFO.PrevUsedDescrRatio = UsedDescrRatio; + IncreaseTimerDuration = SK_TRUE; /* in other words: INCREASE */ + } + + /* + ** Now we can determine the change in percent + */ + if ((RatioDiffRel >= 0) && (RatioDiffRel <= 5) ) { + ModAdjValue = 1; /* 1% change - maybe some other value in future */ + } else if ((RatioDiffRel > 5) && (RatioDiffRel <= 10) ) { + ModAdjValue = 1; /* 1% change - maybe some other value in future */ + } else if ((RatioDiffRel > 10) && (RatioDiffRel <= 15) ) { + ModAdjValue = 1; /* 1% change - maybe some other value in future */ + } else { + ModAdjValue = 1; /* 1% change - maybe some other value in future */ + } + + if (IncreaseTimerDuration) { + NewMaxModIntsPerSec = M_DIMINFO.MaxModIntsPerSec + + (M_DIMINFO.MaxModIntsPerSec * ModAdjValue) / 100; + } else { + NewMaxModIntsPerSec = M_DIMINFO.MaxModIntsPerSec - + (M_DIMINFO.MaxModIntsPerSec * ModAdjValue) / 100; + } + + /* + ** Check if we exceed boundaries... + */ + if ( (NewMaxModIntsPerSec > M_DIMINFO.MaxModIntsPerSecUpperLimit) || + (NewMaxModIntsPerSec < M_DIMINFO.MaxModIntsPerSecLowerLimit)) { + if (M_DIMINFO.DisplayStats) { + printk("Cannot change ModTim from %i to %i ints/sec\n", + M_DIMINFO.MaxModIntsPerSec, NewMaxModIntsPerSec); + } + return; + } else { + if (M_DIMINFO.DisplayStats) { + printk("Resized ModTim from %i to %i ints/sec\n", + M_DIMINFO.MaxModIntsPerSec, NewMaxModIntsPerSec); + } + } + + M_DIMINFO.MaxModIntsPerSec = NewMaxModIntsPerSec; + + if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) { + ModBase = C_CLK_FREQ_GENESIS / pAC->DynIrqModInfo.MaxModIntsPerSec; + } else { + ModBase = C_CLK_FREQ_YUKON / pAC->DynIrqModInfo.MaxModIntsPerSec; + } + + /* + ** We do not need to touch any other registers + */ + SK_OUT32(pAC->IoBase, B2_IRQM_INI, ModBase); +} + +/******************************************************************************* +** Function : DisplaySelectedModerationType() +** Description : Displays what type of moderation we have +** Programmer : Ralph Roesler +** Last Modified: 23-mar-03 +** Returns : void! +** Notes : - +*******************************************************************************/ + +static void +DisplaySelectedModerationType(SK_AC *pAC) { + + if (pAC->DynIrqModInfo.DisplayStats) { + if (pAC->DynIrqModInfo.IntModTypeSelect == C_INT_MOD_STATIC) { + printk("Static int moderation runs with %i INTS/sec\n", + pAC->DynIrqModInfo.MaxModIntsPerSec); + } else if (pAC->DynIrqModInfo.IntModTypeSelect == C_INT_MOD_DYNAMIC) { + if (IsIntModEnabled(pAC)) { + printk("Dynamic int moderation runs with %i INTS/sec\n", + pAC->DynIrqModInfo.MaxModIntsPerSec); + } else { + printk("Dynamic int moderation currently not applied\n"); + } + } else { + printk("No interrupt moderation selected!\n"); + } + } +} + +/******************************************************************************* +** Function : DisplaySelectedModerationMask() +** Description : Displays what interrupts are moderated +** Programmer : Ralph Roesler +** Last Modified: 23-mar-03 +** Returns : void! +** Notes : - +*******************************************************************************/ + +static void +DisplaySelectedModerationMask(SK_AC *pAC) { + + if (pAC->DynIrqModInfo.DisplayStats) { + if (pAC->DynIrqModInfo.IntModTypeSelect != C_INT_MOD_NONE) { + switch (pAC->DynIrqModInfo.MaskIrqModeration) { + case IRQ_MASK_TX_ONLY: + printk("Only Tx-interrupts are moderated\n"); + break; + case IRQ_MASK_RX_ONLY: + printk("Only Rx-interrupts are moderated\n"); + break; + case IRQ_MASK_SP_ONLY: + printk("Only special-interrupts are moderated\n"); + break; + case IRQ_MASK_TX_RX: + printk("Tx- and Rx-interrupts are moderated\n"); + break; + case IRQ_MASK_SP_RX: + printk("Special- and Rx-interrupts are moderated\n"); + break; + case IRQ_MASK_SP_TX: + printk("Special- and Tx-interrupts are moderated\n"); + break; + case IRQ_MASK_RX_TX_SP: + printk("All Rx-, Tx and special-interrupts are moderated\n"); + break; + default: + printk("Don't know what is moderated\n"); + break; + } + } else { + printk("No specific interrupts masked for moderation\n"); + } + } +} + +/******************************************************************************* +** Function : DisplayDescrRatio +** Description : Like the name states... +** Programmer : Ralph Roesler +** Last Modified: 23-mar-03 +** Returns : void! +** Notes : - +*******************************************************************************/ + +static void +DisplayDescrRatio(SK_AC *pAC) { + int TotalMaxNbrDescr = 0; + + if (pAC->DynIrqModInfo.DisplayStats) { + TotalMaxNbrDescr = pAC->RxDescrPerRing * GetRxCalls(pAC); + printk("Ratio descriptors: %i/%i\n", + M_DIMINFO.NbrProcessedDescr, TotalMaxNbrDescr); + } +} + +/******************************************************************************* +** +** End of file +** +*******************************************************************************/ diff --git a/drivers/net/sk98lin/skethtool.c b/drivers/net/sk98lin/skethtool.c new file mode 100644 index 000000000000..5a6da8950faa --- /dev/null +++ b/drivers/net/sk98lin/skethtool.c @@ -0,0 +1,627 @@ +/****************************************************************************** + * + * Name: skethtool.c + * Project: GEnesis, PCI Gigabit Ethernet Adapter + * Version: $Revision: 1.7 $ + * Date: $Date: 2004/09/29 13:32:07 $ + * Purpose: All functions regarding ethtool handling + * + ******************************************************************************/ + +/****************************************************************************** + * + * (C)Copyright 1998-2002 SysKonnect GmbH. + * (C)Copyright 2002-2004 Marvell. + * + * Driver for Marvell Yukon/2 chipset and SysKonnect Gigabit Ethernet + * Server Adapters. + * + * Author: Ralph Roesler (rroesler@syskonnect.de) + * Mirko Lindner (mlindner@syskonnect.de) + * + * Address all question to: linux@syskonnect.de + * + * The technical manual for the adapters is available from SysKonnect's + * web pages: www.syskonnect.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. + * + * The information in this file is provided "AS IS" without warranty. + * + *****************************************************************************/ + +#include "h/skdrv1st.h" +#include "h/skdrv2nd.h" +#include "h/skversion.h" + +#include <linux/ethtool.h> +#include <linux/timer.h> +#include <linux/delay.h> + +/****************************************************************************** + * + * Defines + * + *****************************************************************************/ + +#define SUPP_COPPER_ALL (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | \ + SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | \ + SUPPORTED_1000baseT_Half| SUPPORTED_1000baseT_Full| \ + SUPPORTED_TP) + +#define ADV_COPPER_ALL (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | \ + ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | \ + ADVERTISED_1000baseT_Half| ADVERTISED_1000baseT_Full| \ + ADVERTISED_TP) + +#define SUPP_FIBRE_ALL (SUPPORTED_1000baseT_Full | \ + SUPPORTED_FIBRE | \ + SUPPORTED_Autoneg) + +#define ADV_FIBRE_ALL (ADVERTISED_1000baseT_Full | \ + ADVERTISED_FIBRE | \ + ADVERTISED_Autoneg) + + +/****************************************************************************** + * + * Local Functions + * + *****************************************************************************/ + +/***************************************************************************** + * + * getSettings - retrieves the current settings of the selected adapter + * + * Description: + * The current configuration of the selected adapter is returned. + * This configuration involves a)speed, b)duplex and c)autoneg plus + * a number of other variables. + * + * Returns: always 0 + * + */ +static int getSettings(struct net_device *dev, struct ethtool_cmd *ecmd) +{ + const DEV_NET *pNet = netdev_priv(dev); + int port = pNet->PortNr; + const SK_AC *pAC = pNet->pAC; + const SK_GEPORT *pPort = &pAC->GIni.GP[port]; + + static int DuplexAutoNegConfMap[9][3]= { + { -1 , -1 , -1 }, + { 0 , -1 , -1 }, + { SK_LMODE_HALF , DUPLEX_HALF, AUTONEG_DISABLE }, + { SK_LMODE_FULL , DUPLEX_FULL, AUTONEG_DISABLE }, + { SK_LMODE_AUTOHALF , DUPLEX_HALF, AUTONEG_ENABLE }, + { SK_LMODE_AUTOFULL , DUPLEX_FULL, AUTONEG_ENABLE }, + { SK_LMODE_AUTOBOTH , DUPLEX_FULL, AUTONEG_ENABLE }, + { SK_LMODE_AUTOSENSE , -1 , -1 }, + { SK_LMODE_INDETERMINATED, -1 , -1 } + }; + static int SpeedConfMap[6][2] = { + { 0 , -1 }, + { SK_LSPEED_AUTO , -1 }, + { SK_LSPEED_10MBPS , SPEED_10 }, + { SK_LSPEED_100MBPS , SPEED_100 }, + { SK_LSPEED_1000MBPS , SPEED_1000 }, + { SK_LSPEED_INDETERMINATED, -1 } + }; + static int AdvSpeedMap[6][2] = { + { 0 , -1 }, + { SK_LSPEED_AUTO , -1 }, + { SK_LSPEED_10MBPS , ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full }, + { SK_LSPEED_100MBPS , ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full }, + { SK_LSPEED_1000MBPS , ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full}, + { SK_LSPEED_INDETERMINATED, -1 } + }; + + ecmd->phy_address = port; + ecmd->speed = SpeedConfMap[pPort->PLinkSpeedUsed][1]; + ecmd->duplex = DuplexAutoNegConfMap[pPort->PLinkModeStatus][1]; + ecmd->autoneg = DuplexAutoNegConfMap[pPort->PLinkModeStatus][2]; + ecmd->transceiver = XCVR_INTERNAL; + + if (pAC->GIni.GICopperType) { + ecmd->port = PORT_TP; + ecmd->supported = (SUPP_COPPER_ALL|SUPPORTED_Autoneg); + if (pAC->GIni.GIGenesis) { + ecmd->supported &= ~(SUPPORTED_10baseT_Half); + ecmd->supported &= ~(SUPPORTED_10baseT_Full); + ecmd->supported &= ~(SUPPORTED_100baseT_Half); + ecmd->supported &= ~(SUPPORTED_100baseT_Full); + } else { + if (pAC->GIni.GIChipId == CHIP_ID_YUKON) { + ecmd->supported &= ~(SUPPORTED_1000baseT_Half); + } +#ifdef CHIP_ID_YUKON_FE + if (pAC->GIni.GIChipId == CHIP_ID_YUKON_FE) { + ecmd->supported &= ~(SUPPORTED_1000baseT_Half); + ecmd->supported &= ~(SUPPORTED_1000baseT_Full); + } +#endif + } + if (pAC->GIni.GP[0].PLinkSpeed != SK_LSPEED_AUTO) { + ecmd->advertising = AdvSpeedMap[pPort->PLinkSpeed][1]; + if (pAC->GIni.GIChipId == CHIP_ID_YUKON) { + ecmd->advertising &= ~(SUPPORTED_1000baseT_Half); + } + } else { + ecmd->advertising = ecmd->supported; + } + + if (ecmd->autoneg == AUTONEG_ENABLE) + ecmd->advertising |= ADVERTISED_Autoneg; + } else { + ecmd->port = PORT_FIBRE; + ecmd->supported = SUPP_FIBRE_ALL; + ecmd->advertising = ADV_FIBRE_ALL; + } + return 0; +} + +/* + * MIB infrastructure uses instance value starting at 1 + * based on board and port. + */ +static inline u32 pnmiInstance(const DEV_NET *pNet) +{ + return 1 + (pNet->pAC->RlmtNets == 2) + pNet->PortNr; +} + +/***************************************************************************** + * + * setSettings - configures the settings of a selected adapter + * + * Description: + * Possible settings that may be altered are a)speed, b)duplex or + * c)autonegotiation. + * + * Returns: + * 0: everything fine, no error + * <0: the return value is the error code of the failure + */ +static int setSettings(struct net_device *dev, struct ethtool_cmd *ecmd) +{ + DEV_NET *pNet = netdev_priv(dev); + SK_AC *pAC = pNet->pAC; + u32 instance; + char buf[4]; + int len = 1; + + if (ecmd->speed != SPEED_10 && ecmd->speed != SPEED_100 + && ecmd->speed != SPEED_1000) + return -EINVAL; + + if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL) + return -EINVAL; + + if (ecmd->autoneg != AUTONEG_DISABLE && ecmd->autoneg != AUTONEG_ENABLE) + return -EINVAL; + + if (ecmd->autoneg == AUTONEG_DISABLE) + *buf = (ecmd->duplex == DUPLEX_FULL) + ? SK_LMODE_FULL : SK_LMODE_HALF; + else + *buf = (ecmd->duplex == DUPLEX_FULL) + ? SK_LMODE_AUTOFULL : SK_LMODE_AUTOHALF; + + instance = pnmiInstance(pNet); + if (SkPnmiSetVar(pAC, pAC->IoBase, OID_SKGE_LINK_MODE, + &buf, &len, instance, pNet->NetNr) != SK_PNMI_ERR_OK) + return -EINVAL; + + switch(ecmd->speed) { + case SPEED_1000: + *buf = SK_LSPEED_1000MBPS; + break; + case SPEED_100: + *buf = SK_LSPEED_100MBPS; + break; + case SPEED_10: + *buf = SK_LSPEED_10MBPS; + } + + if (SkPnmiSetVar(pAC, pAC->IoBase, OID_SKGE_SPEED_MODE, + &buf, &len, instance, pNet->NetNr) != SK_PNMI_ERR_OK) + return -EINVAL; + + return 0; +} + +/***************************************************************************** + * + * getDriverInfo - returns generic driver and adapter information + * + * Description: + * Generic driver information is returned via this function, such as + * the name of the driver, its version and and firmware version. + * In addition to this, the location of the selected adapter is + * returned as a bus info string (e.g. '01:05.0'). + * + * Returns: N/A + * + */ +static void getDriverInfo(struct net_device *dev, struct ethtool_drvinfo *info) +{ + const DEV_NET *pNet = netdev_priv(dev); + const SK_AC *pAC = pNet->pAC; + char vers[32]; + + snprintf(vers, sizeof(vers)-1, VER_STRING "(v%d.%d)", + (pAC->GIni.GIPciHwRev >> 4) & 0xf, pAC->GIni.GIPciHwRev & 0xf); + + strlcpy(info->driver, DRIVER_FILE_NAME, sizeof(info->driver)); + strcpy(info->version, vers); + strcpy(info->fw_version, "N/A"); + strlcpy(info->bus_info, pci_name(pAC->PciDev), ETHTOOL_BUSINFO_LEN); +} + +/* + * Ethtool statistics support. + */ +static const char StringsStats[][ETH_GSTRING_LEN] = { + "rx_packets", "tx_packets", + "rx_bytes", "tx_bytes", + "rx_errors", "tx_errors", + "rx_dropped", "tx_dropped", + "multicasts", "collisions", + "rx_length_errors", "rx_buffer_overflow_errors", + "rx_crc_errors", "rx_frame_errors", + "rx_too_short_errors", "rx_too_long_errors", + "rx_carrier_extension_errors", "rx_symbol_errors", + "rx_llc_mac_size_errors", "rx_carrier_errors", + "rx_jabber_errors", "rx_missed_errors", + "tx_abort_collision_errors", "tx_carrier_errors", + "tx_buffer_underrun_errors", "tx_heartbeat_errors", + "tx_window_errors", +}; + +static int getStatsCount(struct net_device *dev) +{ + return ARRAY_SIZE(StringsStats); +} + +static void getStrings(struct net_device *dev, u32 stringset, u8 *data) +{ + switch(stringset) { + case ETH_SS_STATS: + memcpy(data, *StringsStats, sizeof(StringsStats)); + break; + } +} + +static void getEthtoolStats(struct net_device *dev, + struct ethtool_stats *stats, u64 *data) +{ + const DEV_NET *pNet = netdev_priv(dev); + const SK_AC *pAC = pNet->pAC; + const SK_PNMI_STRUCT_DATA *pPnmiStruct = &pAC->PnmiStruct; + + *data++ = pPnmiStruct->Stat[0].StatRxOkCts; + *data++ = pPnmiStruct->Stat[0].StatTxOkCts; + *data++ = pPnmiStruct->Stat[0].StatRxOctetsOkCts; + *data++ = pPnmiStruct->Stat[0].StatTxOctetsOkCts; + *data++ = pPnmiStruct->InErrorsCts; + *data++ = pPnmiStruct->Stat[0].StatTxSingleCollisionCts; + *data++ = pPnmiStruct->RxNoBufCts; + *data++ = pPnmiStruct->TxNoBufCts; + *data++ = pPnmiStruct->Stat[0].StatRxMulticastOkCts; + *data++ = pPnmiStruct->Stat[0].StatTxSingleCollisionCts; + *data++ = pPnmiStruct->Stat[0].StatRxRuntCts; + *data++ = pPnmiStruct->Stat[0].StatRxFifoOverflowCts; + *data++ = pPnmiStruct->Stat[0].StatRxFcsCts; + *data++ = pPnmiStruct->Stat[0].StatRxFramingCts; + *data++ = pPnmiStruct->Stat[0].StatRxShortsCts; + *data++ = pPnmiStruct->Stat[0].StatRxTooLongCts; + *data++ = pPnmiStruct->Stat[0].StatRxCextCts; + *data++ = pPnmiStruct->Stat[0].StatRxSymbolCts; + *data++ = pPnmiStruct->Stat[0].StatRxIRLengthCts; + *data++ = pPnmiStruct->Stat[0].StatRxCarrierCts; + *data++ = pPnmiStruct->Stat[0].StatRxJabberCts; + *data++ = pPnmiStruct->Stat[0].StatRxMissedCts; + *data++ = pAC->stats.tx_aborted_errors; + *data++ = pPnmiStruct->Stat[0].StatTxCarrierCts; + *data++ = pPnmiStruct->Stat[0].StatTxFifoUnderrunCts; + *data++ = pPnmiStruct->Stat[0].StatTxCarrierCts; + *data++ = pAC->stats.tx_window_errors; +} + + +/***************************************************************************** + * + * toggleLeds - Changes the LED state of an adapter + * + * Description: + * This function changes the current state of all LEDs of an adapter so + * that it can be located by a user. + * + * Returns: N/A + * + */ +static void toggleLeds(DEV_NET *pNet, int on) +{ + SK_AC *pAC = pNet->pAC; + int port = pNet->PortNr; + void __iomem *io = pAC->IoBase; + + if (pAC->GIni.GIGenesis) { + SK_OUT8(io, MR_ADDR(port,LNK_LED_REG), + on ? SK_LNK_ON : SK_LNK_OFF); + SkGeYellowLED(pAC, io, + on ? (LED_ON >> 1) : (LED_OFF >> 1)); + SkGeXmitLED(pAC, io, MR_ADDR(port,RX_LED_INI), + on ? SK_LED_TST : SK_LED_DIS); + + if (pAC->GIni.GP[port].PhyType == SK_PHY_BCOM) + SkXmPhyWrite(pAC, io, port, PHY_BCOM_P_EXT_CTRL, + on ? PHY_B_PEC_LED_ON : PHY_B_PEC_LED_OFF); + else if (pAC->GIni.GP[port].PhyType == SK_PHY_LONE) + SkXmPhyWrite(pAC, io, port, PHY_LONE_LED_CFG, + on ? 0x0800 : PHY_L_LC_LEDT); + else + SkGeXmitLED(pAC, io, MR_ADDR(port,TX_LED_INI), + on ? SK_LED_TST : SK_LED_DIS); + } else { + const u16 YukLedOn = (PHY_M_LED_MO_DUP(MO_LED_ON) | + PHY_M_LED_MO_10(MO_LED_ON) | + PHY_M_LED_MO_100(MO_LED_ON) | + PHY_M_LED_MO_1000(MO_LED_ON) | + PHY_M_LED_MO_RX(MO_LED_ON)); + const u16 YukLedOff = (PHY_M_LED_MO_DUP(MO_LED_OFF) | + PHY_M_LED_MO_10(MO_LED_OFF) | + PHY_M_LED_MO_100(MO_LED_OFF) | + PHY_M_LED_MO_1000(MO_LED_OFF) | + PHY_M_LED_MO_RX(MO_LED_OFF)); + + + SkGmPhyWrite(pAC,io,port,PHY_MARV_LED_CTRL,0); + SkGmPhyWrite(pAC,io,port,PHY_MARV_LED_OVER, + on ? YukLedOn : YukLedOff); + } +} + +/***************************************************************************** + * + * skGeBlinkTimer - Changes the LED state of an adapter + * + * Description: + * This function changes the current state of all LEDs of an adapter so + * that it can be located by a user. If the requested time interval for + * this test has elapsed, this function cleans up everything that was + * temporarily setup during the locate NIC test. This involves of course + * also closing or opening any adapter so that the initial board state + * is recovered. + * + * Returns: N/A + * + */ +void SkGeBlinkTimer(unsigned long data) +{ + struct net_device *dev = (struct net_device *) data; + DEV_NET *pNet = netdev_priv(dev); + SK_AC *pAC = pNet->pAC; + + toggleLeds(pNet, pAC->LedsOn); + + pAC->LedsOn = !pAC->LedsOn; + mod_timer(&pAC->BlinkTimer, jiffies + HZ/4); +} + +/***************************************************************************** + * + * locateDevice - start the locate NIC feature of the elected adapter + * + * Description: + * This function is used if the user want to locate a particular NIC. + * All LEDs are regularly switched on and off, so the NIC can easily + * be identified. + * + * Returns: + * ==0: everything fine, no error, locateNIC test was started + * !=0: one locateNIC test runs already + * + */ +static int locateDevice(struct net_device *dev, u32 data) +{ + DEV_NET *pNet = netdev_priv(dev); + SK_AC *pAC = pNet->pAC; + + if(!data || data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ)) + data = (u32)(MAX_SCHEDULE_TIMEOUT / HZ); + + /* start blinking */ + pAC->LedsOn = 0; + mod_timer(&pAC->BlinkTimer, jiffies); + msleep_interruptible(data * 1000); + del_timer_sync(&pAC->BlinkTimer); + toggleLeds(pNet, 0); + + return 0; +} + +/***************************************************************************** + * + * getPauseParams - retrieves the pause parameters + * + * Description: + * All current pause parameters of a selected adapter are placed + * in the passed ethtool_pauseparam structure and are returned. + * + * Returns: N/A + * + */ +static void getPauseParams(struct net_device *dev, struct ethtool_pauseparam *epause) +{ + DEV_NET *pNet = netdev_priv(dev); + SK_AC *pAC = pNet->pAC; + SK_GEPORT *pPort = &pAC->GIni.GP[pNet->PortNr]; + + epause->rx_pause = (pPort->PFlowCtrlMode == SK_FLOW_MODE_SYMMETRIC) || + (pPort->PFlowCtrlMode == SK_FLOW_MODE_SYM_OR_REM); + + epause->tx_pause = epause->rx_pause || (pPort->PFlowCtrlMode == SK_FLOW_MODE_LOC_SEND); + epause->autoneg = epause->rx_pause || epause->tx_pause; +} + +/***************************************************************************** + * + * setPauseParams - configures the pause parameters of an adapter + * + * Description: + * This function sets the Rx or Tx pause parameters + * + * Returns: + * ==0: everything fine, no error + * !=0: the return value is the error code of the failure + */ +static int setPauseParams(struct net_device *dev , struct ethtool_pauseparam *epause) +{ + DEV_NET *pNet = netdev_priv(dev); + SK_AC *pAC = pNet->pAC; + SK_GEPORT *pPort = &pAC->GIni.GP[pNet->PortNr]; + u32 instance = pnmiInstance(pNet); + struct ethtool_pauseparam old; + u8 oldspeed = pPort->PLinkSpeedUsed; + char buf[4]; + int len = 1; + int ret; + + /* + ** we have to determine the current settings to see if + ** the operator requested any modification of the flow + ** control parameters... + */ + getPauseParams(dev, &old); + + /* + ** perform modifications regarding the changes + ** requested by the operator + */ + if (epause->autoneg != old.autoneg) + *buf = epause->autoneg ? SK_FLOW_MODE_NONE : SK_FLOW_MODE_SYMMETRIC; + else { + if (epause->rx_pause && epause->tx_pause) + *buf = SK_FLOW_MODE_SYMMETRIC; + else if (epause->rx_pause && !epause->tx_pause) + *buf = SK_FLOW_MODE_SYM_OR_REM; + else if (!epause->rx_pause && epause->tx_pause) + *buf = SK_FLOW_MODE_LOC_SEND; + else + *buf = SK_FLOW_MODE_NONE; + } + + ret = SkPnmiSetVar(pAC, pAC->IoBase, OID_SKGE_FLOWCTRL_MODE, + &buf, &len, instance, pNet->NetNr); + + if (ret != SK_PNMI_ERR_OK) { + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_CTRL, + ("ethtool (sk98lin): error changing rx/tx pause (%i)\n", ret)); + goto err; + } + + /* + ** It may be that autoneg has been disabled! Therefore + ** set the speed to the previously used value... + */ + if (!epause->autoneg) { + len = 1; + ret = SkPnmiSetVar(pAC, pAC->IoBase, OID_SKGE_SPEED_MODE, + &oldspeed, &len, instance, pNet->NetNr); + if (ret != SK_PNMI_ERR_OK) + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_CTRL, + ("ethtool (sk98lin): error setting speed (%i)\n", ret)); + } + err: + return ret ? -EIO : 0; +} + +/* Only Yukon supports checksum offload. */ +static int setScatterGather(struct net_device *dev, u32 data) +{ + DEV_NET *pNet = netdev_priv(dev); + SK_AC *pAC = pNet->pAC; + + if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) + return -EOPNOTSUPP; + return ethtool_op_set_sg(dev, data); +} + +static int setTxCsum(struct net_device *dev, u32 data) +{ + DEV_NET *pNet = netdev_priv(dev); + SK_AC *pAC = pNet->pAC; + + if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) + return -EOPNOTSUPP; + + return ethtool_op_set_tx_csum(dev, data); +} + +static u32 getRxCsum(struct net_device *dev) +{ + DEV_NET *pNet = netdev_priv(dev); + SK_AC *pAC = pNet->pAC; + + return pAC->RxPort[pNet->PortNr].RxCsum; +} + +static int setRxCsum(struct net_device *dev, u32 data) +{ + DEV_NET *pNet = netdev_priv(dev); + SK_AC *pAC = pNet->pAC; + + if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) + return -EOPNOTSUPP; + + pAC->RxPort[pNet->PortNr].RxCsum = data != 0; + return 0; +} + +static int getRegsLen(struct net_device *dev) +{ + return 0x4000; +} + +/* + * Returns copy of whole control register region + * Note: skip RAM address register because accessing it will + * cause bus hangs! + */ +static void getRegs(struct net_device *dev, struct ethtool_regs *regs, + void *p) +{ + DEV_NET *pNet = netdev_priv(dev); + const void __iomem *io = pNet->pAC->IoBase; + + regs->version = 1; + memset(p, 0, regs->len); + memcpy_fromio(p, io, B3_RAM_ADDR); + + memcpy_fromio(p + B3_RI_WTO_R1, io + B3_RI_WTO_R1, + regs->len - B3_RI_WTO_R1); +} + +const struct ethtool_ops SkGeEthtoolOps = { + .get_settings = getSettings, + .set_settings = setSettings, + .get_drvinfo = getDriverInfo, + .get_strings = getStrings, + .get_stats_count = getStatsCount, + .get_ethtool_stats = getEthtoolStats, + .phys_id = locateDevice, + .get_pauseparam = getPauseParams, + .set_pauseparam = setPauseParams, + .get_link = ethtool_op_get_link, + .get_sg = ethtool_op_get_sg, + .set_sg = setScatterGather, + .get_tx_csum = ethtool_op_get_tx_csum, + .set_tx_csum = setTxCsum, + .get_rx_csum = getRxCsum, + .set_rx_csum = setRxCsum, + .get_regs = getRegs, + .get_regs_len = getRegsLen, +}; diff --git a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c new file mode 100644 index 000000000000..7dc9c9ebf5e7 --- /dev/null +++ b/drivers/net/sk98lin/skge.c @@ -0,0 +1,5219 @@ +/****************************************************************************** + * + * Name: skge.c + * Project: GEnesis, PCI Gigabit Ethernet Adapter + * Version: $Revision: 1.45 $ + * Date: $Date: 2004/02/12 14:41:02 $ + * Purpose: The main driver source module + * + ******************************************************************************/ + +/****************************************************************************** + * + * (C)Copyright 1998-2002 SysKonnect GmbH. + * (C)Copyright 2002-2003 Marvell. + * + * Driver for Marvell Yukon chipset and SysKonnect Gigabit Ethernet + * Server Adapters. + * + * Created 10-Feb-1999, based on Linux' acenic.c, 3c59x.c and + * SysKonnects GEnesis Solaris driver + * Author: Christoph Goos (cgoos@syskonnect.de) + * Mirko Lindner (mlindner@syskonnect.de) + * + * Address all question to: linux@syskonnect.de + * + * The technical manual for the adapters is available from SysKonnect's + * web pages: www.syskonnect.com + * Goto "Support" and search Knowledge Base for "manual". + * + * 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. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/****************************************************************************** + * + * Possible compiler options (#define xxx / -Dxxx): + * + * debugging can be enable by changing SK_DEBUG_CHKMOD and + * SK_DEBUG_CHKCAT in makefile (described there). + * + ******************************************************************************/ + +/****************************************************************************** + * + * Description: + * + * This is the main module of the Linux GE driver. + * + * All source files except skge.c, skdrv1st.h, skdrv2nd.h and sktypes.h + * are part of SysKonnect's COMMON MODULES for the SK-98xx adapters. + * Those are used for drivers on multiple OS', so some thing may seem + * unnecessary complicated on Linux. Please do not try to 'clean up' + * them without VERY good reasons, because this will make it more + * difficult to keep the Linux driver in synchronisation with the + * other versions. + * + * Include file hierarchy: + * + * <linux/module.h> + * + * "h/skdrv1st.h" + * <linux/types.h> + * <linux/kernel.h> + * <linux/string.h> + * <linux/errno.h> + * <linux/ioport.h> + * <linux/slab.h> + * <linux/interrupt.h> + * <linux/pci.h> + * <linux/bitops.h> + * <asm/byteorder.h> + * <asm/io.h> + * <linux/netdevice.h> + * <linux/etherdevice.h> + * <linux/skbuff.h> + * those three depending on kernel version used: + * <linux/bios32.h> + * <linux/init.h> + * <asm/uaccess.h> + * <net/checksum.h> + * + * "h/skerror.h" + * "h/skdebug.h" + * "h/sktypes.h" + * "h/lm80.h" + * "h/xmac_ii.h" + * + * "h/skdrv2nd.h" + * "h/skqueue.h" + * "h/skgehwt.h" + * "h/sktimer.h" + * "h/ski2c.h" + * "h/skgepnmi.h" + * "h/skvpd.h" + * "h/skgehw.h" + * "h/skgeinit.h" + * "h/skaddr.h" + * "h/skgesirq.h" + * "h/skrlmt.h" + * + ******************************************************************************/ + +#include "h/skversion.h" + +#include <linux/in.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/dma-mapping.h> +#include <linux/ip.h> +#include <linux/mii.h> +#include <linux/mm.h> + +#include "h/skdrv1st.h" +#include "h/skdrv2nd.h" + +/******************************************************************************* + * + * Defines + * + ******************************************************************************/ + +/* for debuging on x86 only */ +/* #define BREAKPOINT() asm(" int $3"); */ + +/* use the transmit hw checksum driver functionality */ +#define USE_SK_TX_CHECKSUM + +/* use the receive hw checksum driver functionality */ +#define USE_SK_RX_CHECKSUM + +/* use the scatter-gather functionality with sendfile() */ +#define SK_ZEROCOPY + +/* use of a transmit complete interrupt */ +#define USE_TX_COMPLETE + +/* + * threshold for copying small receive frames + * set to 0 to avoid copying, set to 9001 to copy all frames + */ +#define SK_COPY_THRESHOLD 50 + +/* number of adapters that can be configured via command line params */ +#define SK_MAX_CARD_PARAM 16 + + + +/* + * use those defines for a compile-in version of the driver instead + * of command line parameters + */ +// #define LINK_SPEED_A {"Auto", } +// #define LINK_SPEED_B {"Auto", } +// #define AUTO_NEG_A {"Sense", } +// #define AUTO_NEG_B {"Sense", } +// #define DUP_CAP_A {"Both", } +// #define DUP_CAP_B {"Both", } +// #define FLOW_CTRL_A {"SymOrRem", } +// #define FLOW_CTRL_B {"SymOrRem", } +// #define ROLE_A {"Auto", } +// #define ROLE_B {"Auto", } +// #define PREF_PORT {"A", } +// #define CON_TYPE {"Auto", } +// #define RLMT_MODE {"CheckLinkState", } + +#define DEV_KFREE_SKB(skb) dev_kfree_skb(skb) +#define DEV_KFREE_SKB_IRQ(skb) dev_kfree_skb_irq(skb) +#define DEV_KFREE_SKB_ANY(skb) dev_kfree_skb_any(skb) + + +/* Set blink mode*/ +#define OEM_CONFIG_VALUE ( SK_ACT_LED_BLINK | \ + SK_DUP_LED_NORMAL | \ + SK_LED_LINK100_ON) + + +/* Isr return value */ +#define SkIsrRetVar irqreturn_t +#define SkIsrRetNone IRQ_NONE +#define SkIsrRetHandled IRQ_HANDLED + + +/******************************************************************************* + * + * Local Function Prototypes + * + ******************************************************************************/ + +static void FreeResources(struct SK_NET_DEVICE *dev); +static int SkGeBoardInit(struct SK_NET_DEVICE *dev, SK_AC *pAC); +static SK_BOOL BoardAllocMem(SK_AC *pAC); +static void BoardFreeMem(SK_AC *pAC); +static void BoardInitMem(SK_AC *pAC); +static void SetupRing(SK_AC*, void*, uintptr_t, RXD**, RXD**, RXD**, int*, SK_BOOL); +static SkIsrRetVar SkGeIsr(int irq, void *dev_id); +static SkIsrRetVar SkGeIsrOnePort(int irq, void *dev_id); +static int SkGeOpen(struct SK_NET_DEVICE *dev); +static int SkGeClose(struct SK_NET_DEVICE *dev); +static int SkGeXmit(struct sk_buff *skb, struct SK_NET_DEVICE *dev); +static int SkGeSetMacAddr(struct SK_NET_DEVICE *dev, void *p); +static void SkGeSetRxMode(struct SK_NET_DEVICE *dev); +static struct net_device_stats *SkGeStats(struct SK_NET_DEVICE *dev); +static int SkGeIoctl(struct SK_NET_DEVICE *dev, struct ifreq *rq, int cmd); +static void GetConfiguration(SK_AC*); +static int XmitFrame(SK_AC*, TX_PORT*, struct sk_buff*); +static void FreeTxDescriptors(SK_AC*pAC, TX_PORT*); +static void FillRxRing(SK_AC*, RX_PORT*); +static SK_BOOL FillRxDescriptor(SK_AC*, RX_PORT*); +static void ReceiveIrq(SK_AC*, RX_PORT*, SK_BOOL); +static void ClearAndStartRx(SK_AC*, int); +static void ClearTxIrq(SK_AC*, int, int); +static void ClearRxRing(SK_AC*, RX_PORT*); +static void ClearTxRing(SK_AC*, TX_PORT*); +static int SkGeChangeMtu(struct SK_NET_DEVICE *dev, int new_mtu); +static void PortReInitBmu(SK_AC*, int); +static int SkGeIocMib(DEV_NET*, unsigned int, int); +static int SkGeInitPCI(SK_AC *pAC); +static void StartDrvCleanupTimer(SK_AC *pAC); +static void StopDrvCleanupTimer(SK_AC *pAC); +static int XmitFrameSG(SK_AC*, TX_PORT*, struct sk_buff*); + +#ifdef SK_DIAG_SUPPORT +static SK_U32 ParseDeviceNbrFromSlotName(const char *SlotName); +static int SkDrvInitAdapter(SK_AC *pAC, int devNbr); +static int SkDrvDeInitAdapter(SK_AC *pAC, int devNbr); +#endif + +/******************************************************************************* + * + * Extern Function Prototypes + * + ******************************************************************************/ +extern void SkDimEnableModerationIfNeeded(SK_AC *pAC); +extern void SkDimDisplayModerationSettings(SK_AC *pAC); +extern void SkDimStartModerationTimer(SK_AC *pAC); +extern void SkDimModerate(SK_AC *pAC); +extern void SkGeBlinkTimer(unsigned long data); + +#ifdef DEBUG +static void DumpMsg(struct sk_buff*, char*); +static void DumpData(char*, int); +static void DumpLong(char*, int); +#endif + +/* global variables *********************************************************/ +static SK_BOOL DoPrintInterfaceChange = SK_TRUE; +extern const struct ethtool_ops SkGeEthtoolOps; + +/* local variables **********************************************************/ +static uintptr_t TxQueueAddr[SK_MAX_MACS][2] = {{0x680, 0x600},{0x780, 0x700}}; +static uintptr_t RxQueueAddr[SK_MAX_MACS] = {0x400, 0x480}; + +/***************************************************************************** + * + * SkPciWriteCfgDWord - write a 32 bit value to pci config space + * + * Description: + * This routine writes a 32 bit value to the pci configuration + * space. + * + * Returns: + * 0 - indicate everything worked ok. + * != 0 - error indication + */ +static inline int SkPciWriteCfgDWord( +SK_AC *pAC, /* Adapter Control structure pointer */ +int PciAddr, /* PCI register address */ +SK_U32 Val) /* pointer to store the read value */ +{ + pci_write_config_dword(pAC->PciDev, PciAddr, Val); + return(0); +} /* SkPciWriteCfgDWord */ + +/***************************************************************************** + * + * SkGeInitPCI - Init the PCI resources + * + * Description: + * This function initialize the PCI resources and IO + * + * Returns: + * 0 - indicate everything worked ok. + * != 0 - error indication + */ +static __devinit int SkGeInitPCI(SK_AC *pAC) +{ + struct SK_NET_DEVICE *dev = pAC->dev[0]; + struct pci_dev *pdev = pAC->PciDev; + int retval; + + dev->mem_start = pci_resource_start (pdev, 0); + pci_set_master(pdev); + + retval = pci_request_regions(pdev, "sk98lin"); + if (retval) + goto out; + +#ifdef SK_BIG_ENDIAN + /* + * On big endian machines, we use the adapter's aibility of + * reading the descriptors as big endian. + */ + { + SK_U32 our2; + SkPciReadCfgDWord(pAC, PCI_OUR_REG_2, &our2); + our2 |= PCI_REV_DESC; + SkPciWriteCfgDWord(pAC, PCI_OUR_REG_2, our2); + } +#endif + + /* + * Remap the regs into kernel space. + */ + pAC->IoBase = ioremap_nocache(dev->mem_start, 0x4000); + if (!pAC->IoBase) { + retval = -EIO; + goto out_release; + } + + return 0; + + out_release: + pci_release_regions(pdev); + out: + return retval; +} + + +/***************************************************************************** + * + * FreeResources - release resources allocated for adapter + * + * Description: + * This function releases the IRQ, unmaps the IO and + * frees the desriptor ring. + * + * Returns: N/A + * + */ +static void FreeResources(struct SK_NET_DEVICE *dev) +{ +SK_U32 AllocFlag; +DEV_NET *pNet; +SK_AC *pAC; + + pNet = netdev_priv(dev); + pAC = pNet->pAC; + AllocFlag = pAC->AllocFlag; + if (pAC->PciDev) { + pci_release_regions(pAC->PciDev); + } + if (AllocFlag & SK_ALLOC_IRQ) { + free_irq(dev->irq, dev); + } + if (pAC->IoBase) { + iounmap(pAC->IoBase); + } + if (pAC->pDescrMem) { + BoardFreeMem(pAC); + } + +} /* FreeResources */ + +MODULE_AUTHOR("Mirko Lindner <mlindner@syskonnect.de>"); +MODULE_DESCRIPTION("SysKonnect SK-NET Gigabit Ethernet SK-98xx driver"); +MODULE_LICENSE("GPL"); + +#ifdef LINK_SPEED_A +static char *Speed_A[SK_MAX_CARD_PARAM] = LINK_SPEED; +#else +static char *Speed_A[SK_MAX_CARD_PARAM] = {"", }; +#endif + +#ifdef LINK_SPEED_B +static char *Speed_B[SK_MAX_CARD_PARAM] = LINK_SPEED; +#else +static char *Speed_B[SK_MAX_CARD_PARAM] = {"", }; +#endif + +#ifdef AUTO_NEG_A +static char *AutoNeg_A[SK_MAX_CARD_PARAM] = AUTO_NEG_A; +#else +static char *AutoNeg_A[SK_MAX_CARD_PARAM] = {"", }; +#endif + +#ifdef DUP_CAP_A +static char *DupCap_A[SK_MAX_CARD_PARAM] = DUP_CAP_A; +#else +static char *DupCap_A[SK_MAX_CARD_PARAM] = {"", }; +#endif + +#ifdef FLOW_CTRL_A +static char *FlowCtrl_A[SK_MAX_CARD_PARAM] = FLOW_CTRL_A; +#else +static char *FlowCtrl_A[SK_MAX_CARD_PARAM] = {"", }; +#endif + +#ifdef ROLE_A +static char *Role_A[SK_MAX_CARD_PARAM] = ROLE_A; +#else +static char *Role_A[SK_MAX_CARD_PARAM] = {"", }; +#endif + +#ifdef AUTO_NEG_B +static char *AutoNeg_B[SK_MAX_CARD_PARAM] = AUTO_NEG_B; +#else +static char *AutoNeg_B[SK_MAX_CARD_PARAM] = {"", }; +#endif + +#ifdef DUP_CAP_B +static char *DupCap_B[SK_MAX_CARD_PARAM] = DUP_CAP_B; +#else +static char *DupCap_B[SK_MAX_CARD_PARAM] = {"", }; +#endif + +#ifdef FLOW_CTRL_B +static char *FlowCtrl_B[SK_MAX_CARD_PARAM] = FLOW_CTRL_B; +#else +static char *FlowCtrl_B[SK_MAX_CARD_PARAM] = {"", }; +#endif + +#ifdef ROLE_B +static char *Role_B[SK_MAX_CARD_PARAM] = ROLE_B; +#else +static char *Role_B[SK_MAX_CARD_PARAM] = {"", }; +#endif + +#ifdef CON_TYPE +static char *ConType[SK_MAX_CARD_PARAM] = CON_TYPE; +#else +static char *ConType[SK_MAX_CARD_PARAM] = {"", }; +#endif + +#ifdef PREF_PORT +static char *PrefPort[SK_MAX_CARD_PARAM] = PREF_PORT; +#else +static char *PrefPort[SK_MAX_CARD_PARAM] = {"", }; +#endif + +#ifdef RLMT_MODE +static char *RlmtMode[SK_MAX_CARD_PARAM] = RLMT_MODE; +#else +static char *RlmtMode[SK_MAX_CARD_PARAM] = {"", }; +#endif + +static int IntsPerSec[SK_MAX_CARD_PARAM]; +static char *Moderation[SK_MAX_CARD_PARAM]; +static char *ModerationMask[SK_MAX_CARD_PARAM]; +static char *AutoSizing[SK_MAX_CARD_PARAM]; +static char *Stats[SK_MAX_CARD_PARAM]; + +module_param_array(Speed_A, charp, NULL, 0); +module_param_array(Speed_B, charp, NULL, 0); +module_param_array(AutoNeg_A, charp, NULL, 0); +module_param_array(AutoNeg_B, charp, NULL, 0); +module_param_array(DupCap_A, charp, NULL, 0); +module_param_array(DupCap_B, charp, NULL, 0); +module_param_array(FlowCtrl_A, charp, NULL, 0); +module_param_array(FlowCtrl_B, charp, NULL, 0); +module_param_array(Role_A, charp, NULL, 0); +module_param_array(Role_B, charp, NULL, 0); +module_param_array(ConType, charp, NULL, 0); +module_param_array(PrefPort, charp, NULL, 0); +module_param_array(RlmtMode, charp, NULL, 0); +/* used for interrupt moderation */ +module_param_array(IntsPerSec, int, NULL, 0); +module_param_array(Moderation, charp, NULL, 0); +module_param_array(Stats, charp, NULL, 0); +module_param_array(ModerationMask, charp, NULL, 0); +module_param_array(AutoSizing, charp, NULL, 0); + +/***************************************************************************** + * + * SkGeBoardInit - do level 0 and 1 initialization + * + * Description: + * This function prepares the board hardware for running. The desriptor + * ring is set up, the IRQ is allocated and the configuration settings + * are examined. + * + * Returns: + * 0, if everything is ok + * !=0, on error + */ +static int __devinit SkGeBoardInit(struct SK_NET_DEVICE *dev, SK_AC *pAC) +{ +short i; +unsigned long Flags; +char *DescrString = "sk98lin: Driver for Linux"; /* this is given to PNMI */ +char *VerStr = VER_STRING; +int Ret; /* return code of request_irq */ +SK_BOOL DualNet; + + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, + ("IoBase: %08lX\n", (unsigned long)pAC->IoBase)); + for (i=0; i<SK_MAX_MACS; i++) { + pAC->TxPort[i][0].HwAddr = pAC->IoBase + TxQueueAddr[i][0]; + pAC->TxPort[i][0].PortIndex = i; + pAC->RxPort[i].HwAddr = pAC->IoBase + RxQueueAddr[i]; + pAC->RxPort[i].PortIndex = i; + } + + /* Initialize the mutexes */ + for (i=0; i<SK_MAX_MACS; i++) { + spin_lock_init(&pAC->TxPort[i][0].TxDesRingLock); + spin_lock_init(&pAC->RxPort[i].RxDesRingLock); + } + spin_lock_init(&pAC->SlowPathLock); + + /* setup phy_id blink timer */ + pAC->BlinkTimer.function = SkGeBlinkTimer; + pAC->BlinkTimer.data = (unsigned long) dev; + init_timer(&pAC->BlinkTimer); + + /* level 0 init common modules here */ + + spin_lock_irqsave(&pAC->SlowPathLock, Flags); + /* Does a RESET on board ...*/ + if (SkGeInit(pAC, pAC->IoBase, SK_INIT_DATA) != 0) { + printk("HWInit (0) failed.\n"); + spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); + return -EIO; + } + SkI2cInit( pAC, pAC->IoBase, SK_INIT_DATA); + SkEventInit(pAC, pAC->IoBase, SK_INIT_DATA); + SkPnmiInit( pAC, pAC->IoBase, SK_INIT_DATA); + SkAddrInit( pAC, pAC->IoBase, SK_INIT_DATA); + SkRlmtInit( pAC, pAC->IoBase, SK_INIT_DATA); + SkTimerInit(pAC, pAC->IoBase, SK_INIT_DATA); + + pAC->BoardLevel = SK_INIT_DATA; + pAC->RxBufSize = ETH_BUF_SIZE; + + SK_PNMI_SET_DRIVER_DESCR(pAC, DescrString); + SK_PNMI_SET_DRIVER_VER(pAC, VerStr); + + spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); + + /* level 1 init common modules here (HW init) */ + spin_lock_irqsave(&pAC->SlowPathLock, Flags); + if (SkGeInit(pAC, pAC->IoBase, SK_INIT_IO) != 0) { + printk("sk98lin: HWInit (1) failed.\n"); + spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); + return -EIO; + } + SkI2cInit( pAC, pAC->IoBase, SK_INIT_IO); + SkEventInit(pAC, pAC->IoBase, SK_INIT_IO); + SkPnmiInit( pAC, pAC->IoBase, SK_INIT_IO); + SkAddrInit( pAC, pAC->IoBase, SK_INIT_IO); + SkRlmtInit( pAC, pAC->IoBase, SK_INIT_IO); + SkTimerInit(pAC, pAC->IoBase, SK_INIT_IO); + + /* Set chipset type support */ + pAC->ChipsetType = 0; + if ((pAC->GIni.GIChipId == CHIP_ID_YUKON) || + (pAC->GIni.GIChipId == CHIP_ID_YUKON_LITE)) { + pAC->ChipsetType = 1; + } + + GetConfiguration(pAC); + if (pAC->RlmtNets == 2) { + pAC->GIni.GIPortUsage = SK_MUL_LINK; + } + + pAC->BoardLevel = SK_INIT_IO; + spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); + + if (pAC->GIni.GIMacsFound == 2) { + Ret = request_irq(dev->irq, SkGeIsr, IRQF_SHARED, "sk98lin", dev); + } else if (pAC->GIni.GIMacsFound == 1) { + Ret = request_irq(dev->irq, SkGeIsrOnePort, IRQF_SHARED, + "sk98lin", dev); + } else { + printk(KERN_WARNING "sk98lin: Illegal number of ports: %d\n", + pAC->GIni.GIMacsFound); + return -EIO; + } + + if (Ret) { + printk(KERN_WARNING "sk98lin: Requested IRQ %d is busy.\n", + dev->irq); + return Ret; + } + pAC->AllocFlag |= SK_ALLOC_IRQ; + + /* Alloc memory for this board (Mem for RxD/TxD) : */ + if(!BoardAllocMem(pAC)) { + printk("No memory for descriptor rings.\n"); + return -ENOMEM; + } + + BoardInitMem(pAC); + /* tschilling: New common function with minimum size check. */ + DualNet = SK_FALSE; + if (pAC->RlmtNets == 2) { + DualNet = SK_TRUE; + } + + if (SkGeInitAssignRamToQueues( + pAC, + pAC->ActivePort, + DualNet)) { + BoardFreeMem(pAC); + printk("sk98lin: SkGeInitAssignRamToQueues failed.\n"); + return -EIO; + } + + return (0); +} /* SkGeBoardInit */ + + +/***************************************************************************** + * + * BoardAllocMem - allocate the memory for the descriptor rings + * + * Description: + * This function allocates the memory for all descriptor rings. + * Each ring is aligned for the desriptor alignment and no ring + * has a 4 GByte boundary in it (because the upper 32 bit must + * be constant for all descriptiors in one rings). + * + * Returns: + * SK_TRUE, if all memory could be allocated + * SK_FALSE, if not + */ +static __devinit SK_BOOL BoardAllocMem(SK_AC *pAC) +{ +caddr_t pDescrMem; /* pointer to descriptor memory area */ +size_t AllocLength; /* length of complete descriptor area */ +int i; /* loop counter */ +unsigned long BusAddr; + + + /* rings plus one for alignment (do not cross 4 GB boundary) */ + /* RX_RING_SIZE is assumed bigger than TX_RING_SIZE */ +#if (BITS_PER_LONG == 32) + AllocLength = (RX_RING_SIZE + TX_RING_SIZE) * pAC->GIni.GIMacsFound + 8; +#else + AllocLength = (RX_RING_SIZE + TX_RING_SIZE) * pAC->GIni.GIMacsFound + + RX_RING_SIZE + 8; +#endif + + pDescrMem = pci_alloc_consistent(pAC->PciDev, AllocLength, + &pAC->pDescrMemDMA); + + if (pDescrMem == NULL) { + return (SK_FALSE); + } + pAC->pDescrMem = pDescrMem; + BusAddr = (unsigned long) pAC->pDescrMemDMA; + + /* Descriptors need 8 byte alignment, and this is ensured + * by pci_alloc_consistent. + */ + for (i=0; i<pAC->GIni.GIMacsFound; i++) { + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_TX_PROGRESS, + ("TX%d/A: pDescrMem: %lX, PhysDescrMem: %lX\n", + i, (unsigned long) pDescrMem, + BusAddr)); + pAC->TxPort[i][0].pTxDescrRing = pDescrMem; + pAC->TxPort[i][0].VTxDescrRing = BusAddr; + pDescrMem += TX_RING_SIZE; + BusAddr += TX_RING_SIZE; + + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_TX_PROGRESS, + ("RX%d: pDescrMem: %lX, PhysDescrMem: %lX\n", + i, (unsigned long) pDescrMem, + (unsigned long)BusAddr)); + pAC->RxPort[i].pRxDescrRing = pDescrMem; + pAC->RxPort[i].VRxDescrRing = BusAddr; + pDescrMem += RX_RING_SIZE; + BusAddr += RX_RING_SIZE; + } /* for */ + + return (SK_TRUE); +} /* BoardAllocMem */ + + +/**************************************************************************** + * + * BoardFreeMem - reverse of BoardAllocMem + * + * Description: + * Free all memory allocated in BoardAllocMem: adapter context, + * descriptor rings, locks. + * + * Returns: N/A + */ +static void BoardFreeMem( +SK_AC *pAC) +{ +size_t AllocLength; /* length of complete descriptor area */ + + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, + ("BoardFreeMem\n")); +#if (BITS_PER_LONG == 32) + AllocLength = (RX_RING_SIZE + TX_RING_SIZE) * pAC->GIni.GIMacsFound + 8; +#else + AllocLength = (RX_RING_SIZE + TX_RING_SIZE) * pAC->GIni.GIMacsFound + + RX_RING_SIZE + 8; +#endif + + pci_free_consistent(pAC->PciDev, AllocLength, + pAC->pDescrMem, pAC->pDescrMemDMA); + pAC->pDescrMem = NULL; +} /* BoardFreeMem */ + + +/***************************************************************************** + * + * BoardInitMem - initiate the descriptor rings + * + * Description: + * This function sets the descriptor rings up in memory. + * The adapter is initialized with the descriptor start addresses. + * + * Returns: N/A + */ +static __devinit void BoardInitMem(SK_AC *pAC) +{ +int i; /* loop counter */ +int RxDescrSize; /* the size of a rx descriptor rounded up to alignment*/ +int TxDescrSize; /* the size of a tx descriptor rounded up to alignment*/ + + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, + ("BoardInitMem\n")); + + RxDescrSize = (((sizeof(RXD) - 1) / DESCR_ALIGN) + 1) * DESCR_ALIGN; + pAC->RxDescrPerRing = RX_RING_SIZE / RxDescrSize; + TxDescrSize = (((sizeof(TXD) - 1) / DESCR_ALIGN) + 1) * DESCR_ALIGN; + pAC->TxDescrPerRing = TX_RING_SIZE / RxDescrSize; + + for (i=0; i<pAC->GIni.GIMacsFound; i++) { + SetupRing( + pAC, + pAC->TxPort[i][0].pTxDescrRing, + pAC->TxPort[i][0].VTxDescrRing, + (RXD**)&pAC->TxPort[i][0].pTxdRingHead, + (RXD**)&pAC->TxPort[i][0].pTxdRingTail, + (RXD**)&pAC->TxPort[i][0].pTxdRingPrev, + &pAC->TxPort[i][0].TxdRingFree, + SK_TRUE); + SetupRing( + pAC, + pAC->RxPort[i].pRxDescrRing, + pAC->RxPort[i].VRxDescrRing, + &pAC->RxPort[i].pRxdRingHead, + &pAC->RxPort[i].pRxdRingTail, + &pAC->RxPort[i].pRxdRingPrev, + &pAC->RxPort[i].RxdRingFree, + SK_FALSE); + } +} /* BoardInitMem */ + + +/***************************************************************************** + * + * SetupRing - create one descriptor ring + * + * Description: + * This function creates one descriptor ring in the given memory area. + * The head, tail and number of free descriptors in the ring are set. + * + * Returns: + * none + */ +static void SetupRing( +SK_AC *pAC, +void *pMemArea, /* a pointer to the memory area for the ring */ +uintptr_t VMemArea, /* the virtual bus address of the memory area */ +RXD **ppRingHead, /* address where the head should be written */ +RXD **ppRingTail, /* address where the tail should be written */ +RXD **ppRingPrev, /* address where the tail should be written */ +int *pRingFree, /* address where the # of free descr. goes */ +SK_BOOL IsTx) /* flag: is this a tx ring */ +{ +int i; /* loop counter */ +int DescrSize; /* the size of a descriptor rounded up to alignment*/ +int DescrNum; /* number of descriptors per ring */ +RXD *pDescr; /* pointer to a descriptor (receive or transmit) */ +RXD *pNextDescr; /* pointer to the next descriptor */ +RXD *pPrevDescr; /* pointer to the previous descriptor */ +uintptr_t VNextDescr; /* the virtual bus address of the next descriptor */ + + if (IsTx == SK_TRUE) { + DescrSize = (((sizeof(TXD) - 1) / DESCR_ALIGN) + 1) * + DESCR_ALIGN; + DescrNum = TX_RING_SIZE / DescrSize; + } else { + DescrSize = (((sizeof(RXD) - 1) / DESCR_ALIGN) + 1) * + DESCR_ALIGN; + DescrNum = RX_RING_SIZE / DescrSize; + } + + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_TX_PROGRESS, + ("Descriptor size: %d Descriptor Number: %d\n", + DescrSize,DescrNum)); + + pDescr = (RXD*) pMemArea; + pPrevDescr = NULL; + pNextDescr = (RXD*) (((char*)pDescr) + DescrSize); + VNextDescr = VMemArea + DescrSize; + for(i=0; i<DescrNum; i++) { + /* set the pointers right */ + pDescr->VNextRxd = VNextDescr & 0xffffffffULL; + pDescr->pNextRxd = pNextDescr; + if (!IsTx) pDescr->TcpSumStarts = ETH_HLEN << 16 | ETH_HLEN; + + /* advance one step */ + pPrevDescr = pDescr; + pDescr = pNextDescr; + pNextDescr = (RXD*) (((char*)pDescr) + DescrSize); + VNextDescr += DescrSize; + } + pPrevDescr->pNextRxd = (RXD*) pMemArea; + pPrevDescr->VNextRxd = VMemArea; + pDescr = (RXD*) pMemArea; + *ppRingHead = (RXD*) pMemArea; + *ppRingTail = *ppRingHead; + *ppRingPrev = pPrevDescr; + *pRingFree = DescrNum; +} /* SetupRing */ + + +/***************************************************************************** + * + * PortReInitBmu - re-initiate the descriptor rings for one port + * + * Description: + * This function reinitializes the descriptor rings of one port + * in memory. The port must be stopped before. + * The HW is initialized with the descriptor start addresses. + * + * Returns: + * none + */ +static void PortReInitBmu( +SK_AC *pAC, /* pointer to adapter context */ +int PortIndex) /* index of the port for which to re-init */ +{ + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, + ("PortReInitBmu ")); + + /* set address of first descriptor of ring in BMU */ + SK_OUT32(pAC->IoBase, TxQueueAddr[PortIndex][TX_PRIO_LOW]+ Q_DA_L, + (uint32_t)(((caddr_t) + (pAC->TxPort[PortIndex][TX_PRIO_LOW].pTxdRingHead) - + pAC->TxPort[PortIndex][TX_PRIO_LOW].pTxDescrRing + + pAC->TxPort[PortIndex][TX_PRIO_LOW].VTxDescrRing) & + 0xFFFFFFFF)); + SK_OUT32(pAC->IoBase, TxQueueAddr[PortIndex][TX_PRIO_LOW]+ Q_DA_H, + (uint32_t)(((caddr_t) + (pAC->TxPort[PortIndex][TX_PRIO_LOW].pTxdRingHead) - + pAC->TxPort[PortIndex][TX_PRIO_LOW].pTxDescrRing + + pAC->TxPort[PortIndex][TX_PRIO_LOW].VTxDescrRing) >> 32)); + SK_OUT32(pAC->IoBase, RxQueueAddr[PortIndex]+Q_DA_L, + (uint32_t)(((caddr_t)(pAC->RxPort[PortIndex].pRxdRingHead) - + pAC->RxPort[PortIndex].pRxDescrRing + + pAC->RxPort[PortIndex].VRxDescrRing) & 0xFFFFFFFF)); + SK_OUT32(pAC->IoBase, RxQueueAddr[PortIndex]+Q_DA_H, + (uint32_t)(((caddr_t)(pAC->RxPort[PortIndex].pRxdRingHead) - + pAC->RxPort[PortIndex].pRxDescrRing + + pAC->RxPort[PortIndex].VRxDescrRing) >> 32)); +} /* PortReInitBmu */ + + +/**************************************************************************** + * + * SkGeIsr - handle adapter interrupts + * + * Description: + * The interrupt routine is called when the network adapter + * generates an interrupt. It may also be called if another device + * shares this interrupt vector with the driver. + * + * Returns: N/A + * + */ +static SkIsrRetVar SkGeIsr(int irq, void *dev_id) +{ +struct SK_NET_DEVICE *dev = (struct SK_NET_DEVICE *)dev_id; +DEV_NET *pNet; +SK_AC *pAC; +SK_U32 IntSrc; /* interrupts source register contents */ + + pNet = netdev_priv(dev); + pAC = pNet->pAC; + + /* + * Check and process if its our interrupt + */ + SK_IN32(pAC->IoBase, B0_SP_ISRC, &IntSrc); + if (IntSrc == 0) { + return SkIsrRetNone; + } + + while (((IntSrc & IRQ_MASK) & ~SPECIAL_IRQS) != 0) { +#if 0 /* software irq currently not used */ + if (IntSrc & IS_IRQ_SW) { + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, + SK_DBGCAT_DRV_INT_SRC, + ("Software IRQ\n")); + } +#endif + if (IntSrc & IS_R1_F) { + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, + SK_DBGCAT_DRV_INT_SRC, + ("EOF RX1 IRQ\n")); + ReceiveIrq(pAC, &pAC->RxPort[0], SK_TRUE); + SK_PNMI_CNT_RX_INTR(pAC, 0); + } + if (IntSrc & IS_R2_F) { + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, + SK_DBGCAT_DRV_INT_SRC, + ("EOF RX2 IRQ\n")); + ReceiveIrq(pAC, &pAC->RxPort[1], SK_TRUE); + SK_PNMI_CNT_RX_INTR(pAC, 1); + } +#ifdef USE_TX_COMPLETE /* only if tx complete interrupt used */ + if (IntSrc & IS_XA1_F) { + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, + SK_DBGCAT_DRV_INT_SRC, + ("EOF AS TX1 IRQ\n")); + SK_PNMI_CNT_TX_INTR(pAC, 0); + spin_lock(&pAC->TxPort[0][TX_PRIO_LOW].TxDesRingLock); + FreeTxDescriptors(pAC, &pAC->TxPort[0][TX_PRIO_LOW]); + spin_unlock(&pAC->TxPort[0][TX_PRIO_LOW].TxDesRingLock); + } + if (IntSrc & IS_XA2_F) { + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, + SK_DBGCAT_DRV_INT_SRC, + ("EOF AS TX2 IRQ\n")); + SK_PNMI_CNT_TX_INTR(pAC, 1); + spin_lock(&pAC->TxPort[1][TX_PRIO_LOW].TxDesRingLock); + FreeTxDescriptors(pAC, &pAC->TxPort[1][TX_PRIO_LOW]); + spin_unlock(&pAC->TxPort[1][TX_PRIO_LOW].TxDesRingLock); + } +#if 0 /* only if sync. queues used */ + if (IntSrc & IS_XS1_F) { + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, + SK_DBGCAT_DRV_INT_SRC, + ("EOF SY TX1 IRQ\n")); + SK_PNMI_CNT_TX_INTR(pAC, 1); + spin_lock(&pAC->TxPort[0][TX_PRIO_HIGH].TxDesRingLock); + FreeTxDescriptors(pAC, 0, TX_PRIO_HIGH); + spin_unlock(&pAC->TxPort[0][TX_PRIO_HIGH].TxDesRingLock); + ClearTxIrq(pAC, 0, TX_PRIO_HIGH); + } + if (IntSrc & IS_XS2_F) { + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, + SK_DBGCAT_DRV_INT_SRC, + ("EOF SY TX2 IRQ\n")); + SK_PNMI_CNT_TX_INTR(pAC, 1); + spin_lock(&pAC->TxPort[1][TX_PRIO_HIGH].TxDesRingLock); + FreeTxDescriptors(pAC, 1, TX_PRIO_HIGH); + spin_unlock(&pAC->TxPort[1][TX_PRIO_HIGH].TxDesRingLock); + ClearTxIrq(pAC, 1, TX_PRIO_HIGH); + } +#endif +#endif + + /* do all IO at once */ + if (IntSrc & IS_R1_F) + ClearAndStartRx(pAC, 0); + if (IntSrc & IS_R2_F) + ClearAndStartRx(pAC, 1); +#ifdef USE_TX_COMPLETE /* only if tx complete interrupt used */ + if (IntSrc & IS_XA1_F) + ClearTxIrq(pAC, 0, TX_PRIO_LOW); + if (IntSrc & IS_XA2_F) + ClearTxIrq(pAC, 1, TX_PRIO_LOW); +#endif + SK_IN32(pAC->IoBase, B0_ISRC, &IntSrc); + } /* while (IntSrc & IRQ_MASK != 0) */ + + IntSrc &= pAC->GIni.GIValIrqMask; + if ((IntSrc & SPECIAL_IRQS) || pAC->CheckQueue) { + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_INT_SRC, + ("SPECIAL IRQ DP-Cards => %x\n", IntSrc)); + pAC->CheckQueue = SK_FALSE; + spin_lock(&pAC->SlowPathLock); + if (IntSrc & SPECIAL_IRQS) + SkGeSirqIsr(pAC, pAC->IoBase, IntSrc); + + SkEventDispatcher(pAC, pAC->IoBase); + spin_unlock(&pAC->SlowPathLock); + } + /* + * do it all again is case we cleared an interrupt that + * came in after handling the ring (OUTs may be delayed + * in hardware buffers, but are through after IN) + * + * rroesler: has been commented out and shifted to + * SkGeDrvEvent(), because it is timer + * guarded now + * + ReceiveIrq(pAC, &pAC->RxPort[0], SK_TRUE); + ReceiveIrq(pAC, &pAC->RxPort[1], SK_TRUE); + */ + + if (pAC->CheckQueue) { + pAC->CheckQueue = SK_FALSE; + spin_lock(&pAC->SlowPathLock); + SkEventDispatcher(pAC, pAC->IoBase); + spin_unlock(&pAC->SlowPathLock); + } + + /* IRQ is processed - Enable IRQs again*/ + SK_OUT32(pAC->IoBase, B0_IMSK, pAC->GIni.GIValIrqMask); + + return SkIsrRetHandled; +} /* SkGeIsr */ + + +/**************************************************************************** + * + * SkGeIsrOnePort - handle adapter interrupts for single port adapter + * + * Description: + * The interrupt routine is called when the network adapter + * generates an interrupt. It may also be called if another device + * shares this interrupt vector with the driver. + * This is the same as above, but handles only one port. + * + * Returns: N/A + * + */ +static SkIsrRetVar SkGeIsrOnePort(int irq, void *dev_id) +{ +struct SK_NET_DEVICE *dev = (struct SK_NET_DEVICE *)dev_id; +DEV_NET *pNet; +SK_AC *pAC; +SK_U32 IntSrc; /* interrupts source register contents */ + + pNet = netdev_priv(dev); + pAC = pNet->pAC; + + /* + * Check and process if its our interrupt + */ + SK_IN32(pAC->IoBase, B0_SP_ISRC, &IntSrc); + if (IntSrc == 0) { + return SkIsrRetNone; + } + + while (((IntSrc & IRQ_MASK) & ~SPECIAL_IRQS) != 0) { +#if 0 /* software irq currently not used */ + if (IntSrc & IS_IRQ_SW) { + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, + SK_DBGCAT_DRV_INT_SRC, + ("Software IRQ\n")); + } +#endif + if (IntSrc & IS_R1_F) { + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, + SK_DBGCAT_DRV_INT_SRC, + ("EOF RX1 IRQ\n")); + ReceiveIrq(pAC, &pAC->RxPort[0], SK_TRUE); + SK_PNMI_CNT_RX_INTR(pAC, 0); + } +#ifdef USE_TX_COMPLETE /* only if tx complete interrupt used */ + if (IntSrc & IS_XA1_F) { + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, + SK_DBGCAT_DRV_INT_SRC, + ("EOF AS TX1 IRQ\n")); + SK_PNMI_CNT_TX_INTR(pAC, 0); + spin_lock(&pAC->TxPort[0][TX_PRIO_LOW].TxDesRingLock); + FreeTxDescriptors(pAC, &pAC->TxPort[0][TX_PRIO_LOW]); + spin_unlock(&pAC->TxPort[0][TX_PRIO_LOW].TxDesRingLock); + } +#if 0 /* only if sync. queues used */ + if (IntSrc & IS_XS1_F) { + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, + SK_DBGCAT_DRV_INT_SRC, + ("EOF SY TX1 IRQ\n")); + SK_PNMI_CNT_TX_INTR(pAC, 0); + spin_lock(&pAC->TxPort[0][TX_PRIO_HIGH].TxDesRingLock); + FreeTxDescriptors(pAC, 0, TX_PRIO_HIGH); + spin_unlock(&pAC->TxPort[0][TX_PRIO_HIGH].TxDesRingLock); + ClearTxIrq(pAC, 0, TX_PRIO_HIGH); + } +#endif +#endif + + /* do all IO at once */ + if (IntSrc & IS_R1_F) + ClearAndStartRx(pAC, 0); +#ifdef USE_TX_COMPLETE /* only if tx complete interrupt used */ + if (IntSrc & IS_XA1_F) + ClearTxIrq(pAC, 0, TX_PRIO_LOW); +#endif + SK_IN32(pAC->IoBase, B0_ISRC, &IntSrc); + } /* while (IntSrc & IRQ_MASK != 0) */ + + IntSrc &= pAC->GIni.GIValIrqMask; + if ((IntSrc & SPECIAL_IRQS) || pAC->CheckQueue) { + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_INT_SRC, + ("SPECIAL IRQ SP-Cards => %x\n", IntSrc)); + pAC->CheckQueue = SK_FALSE; + spin_lock(&pAC->SlowPathLock); + if (IntSrc & SPECIAL_IRQS) + SkGeSirqIsr(pAC, pAC->IoBase, IntSrc); + + SkEventDispatcher(pAC, pAC->IoBase); + spin_unlock(&pAC->SlowPathLock); + } + /* + * do it all again is case we cleared an interrupt that + * came in after handling the ring (OUTs may be delayed + * in hardware buffers, but are through after IN) + * + * rroesler: has been commented out and shifted to + * SkGeDrvEvent(), because it is timer + * guarded now + * + ReceiveIrq(pAC, &pAC->RxPort[0], SK_TRUE); + */ + + /* IRQ is processed - Enable IRQs again*/ + SK_OUT32(pAC->IoBase, B0_IMSK, pAC->GIni.GIValIrqMask); + + return SkIsrRetHandled; +} /* SkGeIsrOnePort */ + +#ifdef CONFIG_NET_POLL_CONTROLLER +/**************************************************************************** + * + * SkGePollController - polling receive, for netconsole + * + * Description: + * Polling receive - used by netconsole and other diagnostic tools + * to allow network i/o with interrupts disabled. + * + * Returns: N/A + */ +static void SkGePollController(struct net_device *dev) +{ + disable_irq(dev->irq); + SkGeIsr(dev->irq, dev); + enable_irq(dev->irq); +} +#endif + +/**************************************************************************** + * + * SkGeOpen - handle start of initialized adapter + * + * Description: + * This function starts the initialized adapter. + * The board level variable is set and the adapter is + * brought to full functionality. + * The device flags are set for operation. + * Do all necessary level 2 initialization, enable interrupts and + * give start command to RLMT. + * + * Returns: + * 0 on success + * != 0 on error + */ +static int SkGeOpen( +struct SK_NET_DEVICE *dev) +{ + DEV_NET *pNet; + SK_AC *pAC; + unsigned long Flags; /* for spin lock */ + int i; + SK_EVPARA EvPara; /* an event parameter union */ + + pNet = netdev_priv(dev); + pAC = pNet->pAC; + + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, + ("SkGeOpen: pAC=0x%lX:\n", (unsigned long)pAC)); + +#ifdef SK_DIAG_SUPPORT + if (pAC->DiagModeActive == DIAG_ACTIVE) { + if (pAC->Pnmi.DiagAttached == SK_DIAG_RUNNING) { + return (-1); /* still in use by diag; deny actions */ + } + } +#endif + + /* Set blink mode */ + if ((pAC->PciDev->vendor == 0x1186) || (pAC->PciDev->vendor == 0x11ab )) + pAC->GIni.GILedBlinkCtrl = OEM_CONFIG_VALUE; + + if (pAC->BoardLevel == SK_INIT_DATA) { + /* level 1 init common modules here */ + if (SkGeInit(pAC, pAC->IoBase, SK_INIT_IO) != 0) { + printk("%s: HWInit (1) failed.\n", pAC->dev[pNet->PortNr]->name); + return (-1); + } + SkI2cInit (pAC, pAC->IoBase, SK_INIT_IO); + SkEventInit (pAC, pAC->IoBase, SK_INIT_IO); + SkPnmiInit (pAC, pAC->IoBase, SK_INIT_IO); + SkAddrInit (pAC, pAC->IoBase, SK_INIT_IO); + SkRlmtInit (pAC, pAC->IoBase, SK_INIT_IO); + SkTimerInit (pAC, pAC->IoBase, SK_INIT_IO); + pAC->BoardLevel = SK_INIT_IO; + } + + if (pAC->BoardLevel != SK_INIT_RUN) { + /* tschilling: Level 2 init modules here, check return value. */ + if (SkGeInit(pAC, pAC->IoBase, SK_INIT_RUN) != 0) { + printk("%s: HWInit (2) failed.\n", pAC->dev[pNet->PortNr]->name); + return (-1); + } + SkI2cInit (pAC, pAC->IoBase, SK_INIT_RUN); + SkEventInit (pAC, pAC->IoBase, SK_INIT_RUN); + SkPnmiInit (pAC, pAC->IoBase, SK_INIT_RUN); + SkAddrInit (pAC, pAC->IoBase, SK_INIT_RUN); + SkRlmtInit (pAC, pAC->IoBase, SK_INIT_RUN); + SkTimerInit (pAC, pAC->IoBase, SK_INIT_RUN); + pAC->BoardLevel = SK_INIT_RUN; + } + + for (i=0; i<pAC->GIni.GIMacsFound; i++) { + /* Enable transmit descriptor polling. */ + SkGePollTxD(pAC, pAC->IoBase, i, SK_TRUE); + FillRxRing(pAC, &pAC->RxPort[i]); + } + SkGeYellowLED(pAC, pAC->IoBase, 1); + + StartDrvCleanupTimer(pAC); + SkDimEnableModerationIfNeeded(pAC); + SkDimDisplayModerationSettings(pAC); + + pAC->GIni.GIValIrqMask &= IRQ_MASK; + + /* enable Interrupts */ + SK_OUT32(pAC->IoBase, B0_IMSK, pAC->GIni.GIValIrqMask); + SK_OUT32(pAC->IoBase, B0_HWE_IMSK, IRQ_HWE_MASK); + + spin_lock_irqsave(&pAC->SlowPathLock, Flags); + + if ((pAC->RlmtMode != 0) && (pAC->MaxPorts == 0)) { + EvPara.Para32[0] = pAC->RlmtNets; + EvPara.Para32[1] = -1; + SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_SET_NETS, + EvPara); + EvPara.Para32[0] = pAC->RlmtMode; + EvPara.Para32[1] = 0; + SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_MODE_CHANGE, + EvPara); + } + + EvPara.Para32[0] = pNet->NetNr; + EvPara.Para32[1] = -1; + SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_START, EvPara); + SkEventDispatcher(pAC, pAC->IoBase); + spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); + + pAC->MaxPorts++; + + + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, + ("SkGeOpen suceeded\n")); + + return (0); +} /* SkGeOpen */ + + +/**************************************************************************** + * + * SkGeClose - Stop initialized adapter + * + * Description: + * Close initialized adapter. + * + * Returns: + * 0 - on success + * error code - on error + */ +static int SkGeClose( +struct SK_NET_DEVICE *dev) +{ + DEV_NET *pNet; + DEV_NET *newPtrNet; + SK_AC *pAC; + + unsigned long Flags; /* for spin lock */ + int i; + int PortIdx; + SK_EVPARA EvPara; + + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, + ("SkGeClose: pAC=0x%lX ", (unsigned long)pAC)); + + pNet = netdev_priv(dev); + pAC = pNet->pAC; + +#ifdef SK_DIAG_SUPPORT + if (pAC->DiagModeActive == DIAG_ACTIVE) { + if (pAC->DiagFlowCtrl == SK_FALSE) { + /* + ** notify that the interface which has been closed + ** by operator interaction must not be started up + ** again when the DIAG has finished. + */ + newPtrNet = netdev_priv(pAC->dev[0]); + if (newPtrNet == pNet) { + pAC->WasIfUp[0] = SK_FALSE; + } else { + pAC->WasIfUp[1] = SK_FALSE; + } + return 0; /* return to system everything is fine... */ + } else { + pAC->DiagFlowCtrl = SK_FALSE; + } + } +#endif + + netif_stop_queue(dev); + + if (pAC->RlmtNets == 1) + PortIdx = pAC->ActivePort; + else + PortIdx = pNet->NetNr; + + StopDrvCleanupTimer(pAC); + + /* + * Clear multicast table, promiscuous mode .... + */ + SkAddrMcClear(pAC, pAC->IoBase, PortIdx, 0); + SkAddrPromiscuousChange(pAC, pAC->IoBase, PortIdx, + SK_PROM_MODE_NONE); + + if (pAC->MaxPorts == 1) { + spin_lock_irqsave(&pAC->SlowPathLock, Flags); + /* disable interrupts */ + SK_OUT32(pAC->IoBase, B0_IMSK, 0); + EvPara.Para32[0] = pNet->NetNr; + EvPara.Para32[1] = -1; + SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara); + SkEventDispatcher(pAC, pAC->IoBase); + SK_OUT32(pAC->IoBase, B0_IMSK, 0); + /* stop the hardware */ + SkGeDeInit(pAC, pAC->IoBase); + pAC->BoardLevel = SK_INIT_DATA; + spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); + } else { + + spin_lock_irqsave(&pAC->SlowPathLock, Flags); + EvPara.Para32[0] = pNet->NetNr; + EvPara.Para32[1] = -1; + SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara); + SkPnmiEvent(pAC, pAC->IoBase, SK_PNMI_EVT_XMAC_RESET, EvPara); + SkEventDispatcher(pAC, pAC->IoBase); + spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); + + /* Stop port */ + spin_lock_irqsave(&pAC->TxPort[pNet->PortNr] + [TX_PRIO_LOW].TxDesRingLock, Flags); + SkGeStopPort(pAC, pAC->IoBase, pNet->PortNr, + SK_STOP_ALL, SK_HARD_RST); + spin_unlock_irqrestore(&pAC->TxPort[pNet->PortNr] + [TX_PRIO_LOW].TxDesRingLock, Flags); + } + + if (pAC->RlmtNets == 1) { + /* clear all descriptor rings */ + for (i=0; i<pAC->GIni.GIMacsFound; i++) { + ReceiveIrq(pAC, &pAC->RxPort[i], SK_TRUE); + ClearRxRing(pAC, &pAC->RxPort[i]); + ClearTxRing(pAC, &pAC->TxPort[i][TX_PRIO_LOW]); + } + } else { + /* clear port descriptor rings */ + ReceiveIrq(pAC, &pAC->RxPort[pNet->PortNr], SK_TRUE); + ClearRxRing(pAC, &pAC->RxPort[pNet->PortNr]); + ClearTxRing(pAC, &pAC->TxPort[pNet->PortNr][TX_PRIO_LOW]); + } + + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, + ("SkGeClose: done ")); + + SK_MEMSET(&(pAC->PnmiBackup), 0, sizeof(SK_PNMI_STRUCT_DATA)); + SK_MEMCPY(&(pAC->PnmiBackup), &(pAC->PnmiStruct), + sizeof(SK_PNMI_STRUCT_DATA)); + + pAC->MaxPorts--; + + return (0); +} /* SkGeClose */ + + +/***************************************************************************** + * + * SkGeXmit - Linux frame transmit function + * + * Description: + * The system calls this function to send frames onto the wire. + * It puts the frame in the tx descriptor ring. If the ring is + * full then, the 'tbusy' flag is set. + * + * Returns: + * 0, if everything is ok + * !=0, on error + * WARNING: returning 1 in 'tbusy' case caused system crashes (double + * allocated skb's) !!! + */ +static int SkGeXmit(struct sk_buff *skb, struct SK_NET_DEVICE *dev) +{ +DEV_NET *pNet; +SK_AC *pAC; +int Rc; /* return code of XmitFrame */ + + pNet = netdev_priv(dev); + pAC = pNet->pAC; + + if ((!skb_shinfo(skb)->nr_frags) || + (pAC->GIni.GIChipId == CHIP_ID_GENESIS)) { + /* Don't activate scatter-gather and hardware checksum */ + + if (pAC->RlmtNets == 2) + Rc = XmitFrame( + pAC, + &pAC->TxPort[pNet->PortNr][TX_PRIO_LOW], + skb); + else + Rc = XmitFrame( + pAC, + &pAC->TxPort[pAC->ActivePort][TX_PRIO_LOW], + skb); + } else { + /* scatter-gather and hardware TCP checksumming anabled*/ + if (pAC->RlmtNets == 2) + Rc = XmitFrameSG( + pAC, + &pAC->TxPort[pNet->PortNr][TX_PRIO_LOW], + skb); + else + Rc = XmitFrameSG( + pAC, + &pAC->TxPort[pAC->ActivePort][TX_PRIO_LOW], + skb); + } + + /* Transmitter out of resources? */ + if (Rc <= 0) { + netif_stop_queue(dev); + } + + /* If not taken, give buffer ownership back to the + * queueing layer. + */ + if (Rc < 0) + return (1); + + dev->trans_start = jiffies; + return (0); +} /* SkGeXmit */ + + +/***************************************************************************** + * + * XmitFrame - fill one socket buffer into the transmit ring + * + * Description: + * This function puts a message into the transmit descriptor ring + * if there is a descriptors left. + * Linux skb's consist of only one continuous buffer. + * The first step locks the ring. It is held locked + * all time to avoid problems with SWITCH_../PORT_RESET. + * Then the descriptoris allocated. + * The second part is linking the buffer to the descriptor. + * At the very last, the Control field of the descriptor + * is made valid for the BMU and a start TX command is given + * if necessary. + * + * Returns: + * > 0 - on succes: the number of bytes in the message + * = 0 - on resource shortage: this frame sent or dropped, now + * the ring is full ( -> set tbusy) + * < 0 - on failure: other problems ( -> return failure to upper layers) + */ +static int XmitFrame( +SK_AC *pAC, /* pointer to adapter context */ +TX_PORT *pTxPort, /* pointer to struct of port to send to */ +struct sk_buff *pMessage) /* pointer to send-message */ +{ + TXD *pTxd; /* the rxd to fill */ + TXD *pOldTxd; + unsigned long Flags; + SK_U64 PhysAddr; + int BytesSend = pMessage->len; + + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_TX_PROGRESS, ("X")); + + spin_lock_irqsave(&pTxPort->TxDesRingLock, Flags); +#ifndef USE_TX_COMPLETE + FreeTxDescriptors(pAC, pTxPort); +#endif + if (pTxPort->TxdRingFree == 0) { + /* + ** no enough free descriptors in ring at the moment. + ** Maybe free'ing some old one help? + */ + FreeTxDescriptors(pAC, pTxPort); + if (pTxPort->TxdRingFree == 0) { + spin_unlock_irqrestore(&pTxPort->TxDesRingLock, Flags); + SK_PNMI_CNT_NO_TX_BUF(pAC, pTxPort->PortIndex); + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, + SK_DBGCAT_DRV_TX_PROGRESS, + ("XmitFrame failed\n")); + /* + ** the desired message can not be sent + ** Because tbusy seems to be set, the message + ** should not be freed here. It will be used + ** by the scheduler of the ethernet handler + */ + return (-1); + } + } + + /* + ** If the passed socket buffer is of smaller MTU-size than 60, + ** copy everything into new buffer and fill all bytes between + ** the original packet end and the new packet end of 60 with 0x00. + ** This is to resolve faulty padding by the HW with 0xaa bytes. + */ + if (BytesSend < C_LEN_ETHERNET_MINSIZE) { + if (skb_padto(pMessage, C_LEN_ETHERNET_MINSIZE)) { + spin_unlock_irqrestore(&pTxPort->TxDesRingLock, Flags); + return 0; + } + pMessage->len = C_LEN_ETHERNET_MINSIZE; + } + + /* + ** advance head counter behind descriptor needed for this frame, + ** so that needed descriptor is reserved from that on. The next + ** action will be to add the passed buffer to the TX-descriptor + */ + pTxd = pTxPort->pTxdRingHead; + pTxPort->pTxdRingHead = pTxd->pNextTxd; + pTxPort->TxdRingFree--; + +#ifdef SK_DUMP_TX + DumpMsg(pMessage, "XmitFrame"); +#endif + + /* + ** First step is to map the data to be sent via the adapter onto + ** the DMA memory. Kernel 2.2 uses virt_to_bus(), but kernels 2.4 + ** and 2.6 need to use pci_map_page() for that mapping. + */ + PhysAddr = (SK_U64) pci_map_page(pAC->PciDev, + virt_to_page(pMessage->data), + ((unsigned long) pMessage->data & ~PAGE_MASK), + pMessage->len, + PCI_DMA_TODEVICE); + pTxd->VDataLow = (SK_U32) (PhysAddr & 0xffffffff); + pTxd->VDataHigh = (SK_U32) (PhysAddr >> 32); + pTxd->pMBuf = pMessage; + + if (pMessage->ip_summed == CHECKSUM_PARTIAL) { + u16 hdrlen = skb_transport_offset(pMessage); + u16 offset = hdrlen + pMessage->csum_offset; + + if ((ipip_hdr(pMessage)->protocol == IPPROTO_UDP) && + (pAC->GIni.GIChipRev == 0) && + (pAC->GIni.GIChipId == CHIP_ID_YUKON)) { + pTxd->TBControl = BMU_TCP_CHECK; + } else { + pTxd->TBControl = BMU_UDP_CHECK; + } + + pTxd->TcpSumOfs = 0; + pTxd->TcpSumSt = hdrlen; + pTxd->TcpSumWr = offset; + + pTxd->TBControl |= BMU_OWN | BMU_STF | + BMU_SW | BMU_EOF | +#ifdef USE_TX_COMPLETE + BMU_IRQ_EOF | +#endif + pMessage->len; + } else { + pTxd->TBControl = BMU_OWN | BMU_STF | BMU_CHECK | + BMU_SW | BMU_EOF | +#ifdef USE_TX_COMPLETE + BMU_IRQ_EOF | +#endif + pMessage->len; + } + + /* + ** If previous descriptor already done, give TX start cmd + */ + pOldTxd = xchg(&pTxPort->pTxdRingPrev, pTxd); + if ((pOldTxd->TBControl & BMU_OWN) == 0) { + SK_OUT8(pTxPort->HwAddr, Q_CSR, CSR_START); + } + + /* + ** after releasing the lock, the skb may immediately be free'd + */ + spin_unlock_irqrestore(&pTxPort->TxDesRingLock, Flags); + if (pTxPort->TxdRingFree != 0) { + return (BytesSend); + } else { + return (0); + } + +} /* XmitFrame */ + +/***************************************************************************** + * + * XmitFrameSG - fill one socket buffer into the transmit ring + * (use SG and TCP/UDP hardware checksumming) + * + * Description: + * This function puts a message into the transmit descriptor ring + * if there is a descriptors left. + * + * Returns: + * > 0 - on succes: the number of bytes in the message + * = 0 - on resource shortage: this frame sent or dropped, now + * the ring is full ( -> set tbusy) + * < 0 - on failure: other problems ( -> return failure to upper layers) + */ +static int XmitFrameSG( +SK_AC *pAC, /* pointer to adapter context */ +TX_PORT *pTxPort, /* pointer to struct of port to send to */ +struct sk_buff *pMessage) /* pointer to send-message */ +{ + + TXD *pTxd; + TXD *pTxdFst; + TXD *pTxdLst; + int CurrFrag; + int BytesSend; + skb_frag_t *sk_frag; + SK_U64 PhysAddr; + unsigned long Flags; + SK_U32 Control; + + spin_lock_irqsave(&pTxPort->TxDesRingLock, Flags); +#ifndef USE_TX_COMPLETE + FreeTxDescriptors(pAC, pTxPort); +#endif + if ((skb_shinfo(pMessage)->nr_frags +1) > pTxPort->TxdRingFree) { + FreeTxDescriptors(pAC, pTxPort); + if ((skb_shinfo(pMessage)->nr_frags + 1) > pTxPort->TxdRingFree) { + spin_unlock_irqrestore(&pTxPort->TxDesRingLock, Flags); + SK_PNMI_CNT_NO_TX_BUF(pAC, pTxPort->PortIndex); + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, + SK_DBGCAT_DRV_TX_PROGRESS, + ("XmitFrameSG failed - Ring full\n")); + /* this message can not be sent now */ + return(-1); + } + } + + pTxd = pTxPort->pTxdRingHead; + pTxdFst = pTxd; + pTxdLst = pTxd; + BytesSend = 0; + + /* + ** Map the first fragment (header) into the DMA-space + */ + PhysAddr = (SK_U64) pci_map_page(pAC->PciDev, + virt_to_page(pMessage->data), + ((unsigned long) pMessage->data & ~PAGE_MASK), + skb_headlen(pMessage), + PCI_DMA_TODEVICE); + + pTxd->VDataLow = (SK_U32) (PhysAddr & 0xffffffff); + pTxd->VDataHigh = (SK_U32) (PhysAddr >> 32); + + /* + ** Does the HW need to evaluate checksum for TCP or UDP packets? + */ + if (pMessage->ip_summed == CHECKSUM_PARTIAL) { + u16 hdrlen = skb_transport_offset(pMessage); + u16 offset = hdrlen + pMessage->csum_offset; + + Control = BMU_STFWD; + + /* + ** We have to use the opcode for tcp here, because the + ** opcode for udp is not working in the hardware yet + ** (Revision 2.0) + */ + if ((ipip_hdr(pMessage)->protocol == IPPROTO_UDP) && + (pAC->GIni.GIChipRev == 0) && + (pAC->GIni.GIChipId == CHIP_ID_YUKON)) { + Control |= BMU_TCP_CHECK; + } else { + Control |= BMU_UDP_CHECK; + } + + pTxd->TcpSumOfs = 0; + pTxd->TcpSumSt = hdrlen; + pTxd->TcpSumWr = offset; + } else + Control = BMU_CHECK | BMU_SW; + + pTxd->TBControl = BMU_STF | Control | skb_headlen(pMessage); + + pTxd = pTxd->pNextTxd; + pTxPort->TxdRingFree--; + BytesSend += skb_headlen(pMessage); + + /* + ** Browse over all SG fragments and map each of them into the DMA space + */ + for (CurrFrag = 0; CurrFrag < skb_shinfo(pMessage)->nr_frags; CurrFrag++) { + sk_frag = &skb_shinfo(pMessage)->frags[CurrFrag]; + /* + ** we already have the proper value in entry + */ + PhysAddr = (SK_U64) pci_map_page(pAC->PciDev, + sk_frag->page, + sk_frag->page_offset, + sk_frag->size, + PCI_DMA_TODEVICE); + + pTxd->VDataLow = (SK_U32) (PhysAddr & 0xffffffff); + pTxd->VDataHigh = (SK_U32) (PhysAddr >> 32); + pTxd->pMBuf = pMessage; + + pTxd->TBControl = Control | BMU_OWN | sk_frag->size; + + /* + ** Do we have the last fragment? + */ + if( (CurrFrag+1) == skb_shinfo(pMessage)->nr_frags ) { +#ifdef USE_TX_COMPLETE + pTxd->TBControl |= BMU_EOF | BMU_IRQ_EOF; +#else + pTxd->TBControl |= BMU_EOF; +#endif + pTxdFst->TBControl |= BMU_OWN | BMU_SW; + } + pTxdLst = pTxd; + pTxd = pTxd->pNextTxd; + pTxPort->TxdRingFree--; + BytesSend += sk_frag->size; + } + + /* + ** If previous descriptor already done, give TX start cmd + */ + if ((pTxPort->pTxdRingPrev->TBControl & BMU_OWN) == 0) { + SK_OUT8(pTxPort->HwAddr, Q_CSR, CSR_START); + } + + pTxPort->pTxdRingPrev = pTxdLst; + pTxPort->pTxdRingHead = pTxd; + + spin_unlock_irqrestore(&pTxPort->TxDesRingLock, Flags); + + if (pTxPort->TxdRingFree > 0) { + return (BytesSend); + } else { + return (0); + } +} + +/***************************************************************************** + * + * FreeTxDescriptors - release descriptors from the descriptor ring + * + * Description: + * This function releases descriptors from a transmit ring if they + * have been sent by the BMU. + * If a descriptors is sent, it can be freed and the message can + * be freed, too. + * The SOFTWARE controllable bit is used to prevent running around a + * completely free ring for ever. If this bit is no set in the + * frame (by XmitFrame), this frame has never been sent or is + * already freed. + * The Tx descriptor ring lock must be held while calling this function !!! + * + * Returns: + * none + */ +static void FreeTxDescriptors( +SK_AC *pAC, /* pointer to the adapter context */ +TX_PORT *pTxPort) /* pointer to destination port structure */ +{ +TXD *pTxd; /* pointer to the checked descriptor */ +TXD *pNewTail; /* pointer to 'end' of the ring */ +SK_U32 Control; /* TBControl field of descriptor */ +SK_U64 PhysAddr; /* address of DMA mapping */ + + pNewTail = pTxPort->pTxdRingTail; + pTxd = pNewTail; + /* + ** loop forever; exits if BMU_SW bit not set in start frame + ** or BMU_OWN bit set in any frame + */ + while (1) { + Control = pTxd->TBControl; + if ((Control & BMU_SW) == 0) { + /* + ** software controllable bit is set in first + ** fragment when given to BMU. Not set means that + ** this fragment was never sent or is already + ** freed ( -> ring completely free now). + */ + pTxPort->pTxdRingTail = pTxd; + netif_wake_queue(pAC->dev[pTxPort->PortIndex]); + return; + } + if (Control & BMU_OWN) { + pTxPort->pTxdRingTail = pTxd; + if (pTxPort->TxdRingFree > 0) { + netif_wake_queue(pAC->dev[pTxPort->PortIndex]); + } + return; + } + + /* + ** release the DMA mapping, because until not unmapped + ** this buffer is considered being under control of the + ** adapter card! + */ + PhysAddr = ((SK_U64) pTxd->VDataHigh) << (SK_U64) 32; + PhysAddr |= (SK_U64) pTxd->VDataLow; + pci_unmap_page(pAC->PciDev, PhysAddr, + pTxd->pMBuf->len, + PCI_DMA_TODEVICE); + + if (Control & BMU_EOF) + DEV_KFREE_SKB_ANY(pTxd->pMBuf); /* free message */ + + pTxPort->TxdRingFree++; + pTxd->TBControl &= ~BMU_SW; + pTxd = pTxd->pNextTxd; /* point behind fragment with EOF */ + } /* while(forever) */ +} /* FreeTxDescriptors */ + +/***************************************************************************** + * + * FillRxRing - fill the receive ring with valid descriptors + * + * Description: + * This function fills the receive ring descriptors with data + * segments and makes them valid for the BMU. + * The active ring is filled completely, if possible. + * The non-active ring is filled only partial to save memory. + * + * Description of rx ring structure: + * head - points to the descriptor which will be used next by the BMU + * tail - points to the next descriptor to give to the BMU + * + * Returns: N/A + */ +static void FillRxRing( +SK_AC *pAC, /* pointer to the adapter context */ +RX_PORT *pRxPort) /* ptr to port struct for which the ring + should be filled */ +{ +unsigned long Flags; + + spin_lock_irqsave(&pRxPort->RxDesRingLock, Flags); + while (pRxPort->RxdRingFree > pRxPort->RxFillLimit) { + if(!FillRxDescriptor(pAC, pRxPort)) + break; + } + spin_unlock_irqrestore(&pRxPort->RxDesRingLock, Flags); +} /* FillRxRing */ + + +/***************************************************************************** + * + * FillRxDescriptor - fill one buffer into the receive ring + * + * Description: + * The function allocates a new receive buffer and + * puts it into the next descriptor. + * + * Returns: + * SK_TRUE - a buffer was added to the ring + * SK_FALSE - a buffer could not be added + */ +static SK_BOOL FillRxDescriptor( +SK_AC *pAC, /* pointer to the adapter context struct */ +RX_PORT *pRxPort) /* ptr to port struct of ring to fill */ +{ +struct sk_buff *pMsgBlock; /* pointer to a new message block */ +RXD *pRxd; /* the rxd to fill */ +SK_U16 Length; /* data fragment length */ +SK_U64 PhysAddr; /* physical address of a rx buffer */ + + pMsgBlock = alloc_skb(pAC->RxBufSize, GFP_ATOMIC); + if (pMsgBlock == NULL) { + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, + SK_DBGCAT_DRV_ENTRY, + ("%s: Allocation of rx buffer failed !\n", + pAC->dev[pRxPort->PortIndex]->name)); + SK_PNMI_CNT_NO_RX_BUF(pAC, pRxPort->PortIndex); + return(SK_FALSE); + } + skb_reserve(pMsgBlock, 2); /* to align IP frames */ + /* skb allocated ok, so add buffer */ + pRxd = pRxPort->pRxdRingTail; + pRxPort->pRxdRingTail = pRxd->pNextRxd; + pRxPort->RxdRingFree--; + Length = pAC->RxBufSize; + PhysAddr = (SK_U64) pci_map_page(pAC->PciDev, + virt_to_page(pMsgBlock->data), + ((unsigned long) pMsgBlock->data & + ~PAGE_MASK), + pAC->RxBufSize - 2, + PCI_DMA_FROMDEVICE); + + pRxd->VDataLow = (SK_U32) (PhysAddr & 0xffffffff); + pRxd->VDataHigh = (SK_U32) (PhysAddr >> 32); + pRxd->pMBuf = pMsgBlock; + pRxd->RBControl = BMU_OWN | + BMU_STF | + BMU_IRQ_EOF | + BMU_TCP_CHECK | + Length; + return (SK_TRUE); + +} /* FillRxDescriptor */ + + +/***************************************************************************** + * + * ReQueueRxBuffer - fill one buffer back into the receive ring + * + * Description: + * Fill a given buffer back into the rx ring. The buffer + * has been previously allocated and aligned, and its phys. + * address calculated, so this is no more necessary. + * + * Returns: N/A + */ +static void ReQueueRxBuffer( +SK_AC *pAC, /* pointer to the adapter context struct */ +RX_PORT *pRxPort, /* ptr to port struct of ring to fill */ +struct sk_buff *pMsg, /* pointer to the buffer */ +SK_U32 PhysHigh, /* phys address high dword */ +SK_U32 PhysLow) /* phys address low dword */ +{ +RXD *pRxd; /* the rxd to fill */ +SK_U16 Length; /* data fragment length */ + + pRxd = pRxPort->pRxdRingTail; + pRxPort->pRxdRingTail = pRxd->pNextRxd; + pRxPort->RxdRingFree--; + Length = pAC->RxBufSize; + + pRxd->VDataLow = PhysLow; + pRxd->VDataHigh = PhysHigh; + pRxd->pMBuf = pMsg; + pRxd->RBControl = BMU_OWN | + BMU_STF | + BMU_IRQ_EOF | + BMU_TCP_CHECK | + Length; + return; +} /* ReQueueRxBuffer */ + +/***************************************************************************** + * + * ReceiveIrq - handle a receive IRQ + * + * Description: + * This function is called when a receive IRQ is set. + * It walks the receive descriptor ring and sends up all + * frames that are complete. + * + * Returns: N/A + */ +static void ReceiveIrq( + SK_AC *pAC, /* pointer to adapter context */ + RX_PORT *pRxPort, /* pointer to receive port struct */ + SK_BOOL SlowPathLock) /* indicates if SlowPathLock is needed */ +{ +RXD *pRxd; /* pointer to receive descriptors */ +SK_U32 Control; /* control field of descriptor */ +struct sk_buff *pMsg; /* pointer to message holding frame */ +struct sk_buff *pNewMsg; /* pointer to a new message for copying frame */ +int FrameLength; /* total length of received frame */ +SK_MBUF *pRlmtMbuf; /* ptr to a buffer for giving a frame to rlmt */ +SK_EVPARA EvPara; /* an event parameter union */ +unsigned long Flags; /* for spin lock */ +int PortIndex = pRxPort->PortIndex; +unsigned int Offset; +unsigned int NumBytes; +unsigned int ForRlmt; +SK_BOOL IsBc; +SK_BOOL IsMc; +SK_BOOL IsBadFrame; /* Bad frame */ + +SK_U32 FrameStat; +SK_U64 PhysAddr; + +rx_start: + /* do forever; exit if BMU_OWN found */ + for ( pRxd = pRxPort->pRxdRingHead ; + pRxPort->RxdRingFree < pAC->RxDescrPerRing ; + pRxd = pRxd->pNextRxd, + pRxPort->pRxdRingHead = pRxd, + pRxPort->RxdRingFree ++) { + + /* + * For a better understanding of this loop + * Go through every descriptor beginning at the head + * Please note: the ring might be completely received so the OWN bit + * set is not a good crirteria to leave that loop. + * Therefore the RingFree counter is used. + * On entry of this loop pRxd is a pointer to the Rxd that needs + * to be checked next. + */ + + Control = pRxd->RBControl; + + /* check if this descriptor is ready */ + if ((Control & BMU_OWN) != 0) { + /* this descriptor is not yet ready */ + /* This is the usual end of the loop */ + /* We don't need to start the ring again */ + FillRxRing(pAC, pRxPort); + return; + } + pAC->DynIrqModInfo.NbrProcessedDescr++; + + /* get length of frame and check it */ + FrameLength = Control & BMU_BBC; + if (FrameLength > pAC->RxBufSize) { + goto rx_failed; + } + + /* check for STF and EOF */ + if ((Control & (BMU_STF | BMU_EOF)) != (BMU_STF | BMU_EOF)) { + goto rx_failed; + } + + /* here we have a complete frame in the ring */ + pMsg = pRxd->pMBuf; + + FrameStat = pRxd->FrameStat; + + /* check for frame length mismatch */ +#define XMR_FS_LEN_SHIFT 18 +#define GMR_FS_LEN_SHIFT 16 + if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) { + if (FrameLength != (SK_U32) (FrameStat >> XMR_FS_LEN_SHIFT)) { + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, + SK_DBGCAT_DRV_RX_PROGRESS, + ("skge: Frame length mismatch (%u/%u).\n", + FrameLength, + (SK_U32) (FrameStat >> XMR_FS_LEN_SHIFT))); + goto rx_failed; + } + } + else { + if (FrameLength != (SK_U32) (FrameStat >> GMR_FS_LEN_SHIFT)) { + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, + SK_DBGCAT_DRV_RX_PROGRESS, + ("skge: Frame length mismatch (%u/%u).\n", + FrameLength, + (SK_U32) (FrameStat >> XMR_FS_LEN_SHIFT))); + goto rx_failed; + } + } + + /* Set Rx Status */ + if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) { + IsBc = (FrameStat & XMR_FS_BC) != 0; + IsMc = (FrameStat & XMR_FS_MC) != 0; + IsBadFrame = (FrameStat & + (XMR_FS_ANY_ERR | XMR_FS_2L_VLAN)) != 0; + } else { + IsBc = (FrameStat & GMR_FS_BC) != 0; + IsMc = (FrameStat & GMR_FS_MC) != 0; + IsBadFrame = (((FrameStat & GMR_FS_ANY_ERR) != 0) || + ((FrameStat & GMR_FS_RX_OK) == 0)); + } + + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, 0, + ("Received frame of length %d on port %d\n", + FrameLength, PortIndex)); + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, 0, + ("Number of free rx descriptors: %d\n", + pRxPort->RxdRingFree)); +/* DumpMsg(pMsg, "Rx"); */ + + if ((Control & BMU_STAT_VAL) != BMU_STAT_VAL || (IsBadFrame)) { +#if 0 + (FrameStat & (XMR_FS_ANY_ERR | XMR_FS_2L_VLAN)) != 0) { +#endif + /* there is a receive error in this frame */ + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, + SK_DBGCAT_DRV_RX_PROGRESS, + ("skge: Error in received frame, dropped!\n" + "Control: %x\nRxStat: %x\n", + Control, FrameStat)); + + ReQueueRxBuffer(pAC, pRxPort, pMsg, + pRxd->VDataHigh, pRxd->VDataLow); + + continue; + } + + /* + * if short frame then copy data to reduce memory waste + */ + if ((FrameLength < SK_COPY_THRESHOLD) && + ((pNewMsg = alloc_skb(FrameLength+2, GFP_ATOMIC)) != NULL)) { + /* + * Short frame detected and allocation successfull + */ + /* use new skb and copy data */ + skb_reserve(pNewMsg, 2); + skb_put(pNewMsg, FrameLength); + PhysAddr = ((SK_U64) pRxd->VDataHigh) << (SK_U64)32; + PhysAddr |= (SK_U64) pRxd->VDataLow; + + pci_dma_sync_single_for_cpu(pAC->PciDev, + (dma_addr_t) PhysAddr, + FrameLength, + PCI_DMA_FROMDEVICE); + skb_copy_to_linear_data(pNewMsg, pMsg, FrameLength); + + pci_dma_sync_single_for_device(pAC->PciDev, + (dma_addr_t) PhysAddr, + FrameLength, + PCI_DMA_FROMDEVICE); + ReQueueRxBuffer(pAC, pRxPort, pMsg, + pRxd->VDataHigh, pRxd->VDataLow); + + pMsg = pNewMsg; + + } + else { + /* + * if large frame, or SKB allocation failed, pass + * the SKB directly to the networking + */ + + PhysAddr = ((SK_U64) pRxd->VDataHigh) << (SK_U64)32; + PhysAddr |= (SK_U64) pRxd->VDataLow; + + /* release the DMA mapping */ + pci_unmap_single(pAC->PciDev, + PhysAddr, + pAC->RxBufSize - 2, + PCI_DMA_FROMDEVICE); + + /* set length in message */ + skb_put(pMsg, FrameLength); + } /* frame > SK_COPY_TRESHOLD */ + +#ifdef USE_SK_RX_CHECKSUM + pMsg->csum = pRxd->TcpSums & 0xffff; + pMsg->ip_summed = CHECKSUM_COMPLETE; +#else + pMsg->ip_summed = CHECKSUM_NONE; +#endif + + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, 1,("V")); + ForRlmt = SK_RLMT_RX_PROTOCOL; +#if 0 + IsBc = (FrameStat & XMR_FS_BC)==XMR_FS_BC; +#endif + SK_RLMT_PRE_LOOKAHEAD(pAC, PortIndex, FrameLength, + IsBc, &Offset, &NumBytes); + if (NumBytes != 0) { +#if 0 + IsMc = (FrameStat & XMR_FS_MC)==XMR_FS_MC; +#endif + SK_RLMT_LOOKAHEAD(pAC, PortIndex, + &pMsg->data[Offset], + IsBc, IsMc, &ForRlmt); + } + if (ForRlmt == SK_RLMT_RX_PROTOCOL) { + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, 1,("W")); + /* send up only frames from active port */ + if ((PortIndex == pAC->ActivePort) || + (pAC->RlmtNets == 2)) { + /* frame for upper layer */ + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, 1,("U")); +#ifdef xDEBUG + DumpMsg(pMsg, "Rx"); +#endif + SK_PNMI_CNT_RX_OCTETS_DELIVERED(pAC, + FrameLength, pRxPort->PortIndex); + + pMsg->protocol = eth_type_trans(pMsg, + pAC->dev[pRxPort->PortIndex]); + netif_rx(pMsg); + pAC->dev[pRxPort->PortIndex]->last_rx = jiffies; + } + else { + /* drop frame */ + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, + SK_DBGCAT_DRV_RX_PROGRESS, + ("D")); + DEV_KFREE_SKB(pMsg); + } + + } /* if not for rlmt */ + else { + /* packet for rlmt */ + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, + SK_DBGCAT_DRV_RX_PROGRESS, ("R")); + pRlmtMbuf = SkDrvAllocRlmtMbuf(pAC, + pAC->IoBase, FrameLength); + if (pRlmtMbuf != NULL) { + pRlmtMbuf->pNext = NULL; + pRlmtMbuf->Length = FrameLength; + pRlmtMbuf->PortIdx = PortIndex; + EvPara.pParaPtr = pRlmtMbuf; + memcpy((char*)(pRlmtMbuf->pData), + (char*)(pMsg->data), + FrameLength); + + /* SlowPathLock needed? */ + if (SlowPathLock == SK_TRUE) { + spin_lock_irqsave(&pAC->SlowPathLock, Flags); + SkEventQueue(pAC, SKGE_RLMT, + SK_RLMT_PACKET_RECEIVED, + EvPara); + pAC->CheckQueue = SK_TRUE; + spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); + } else { + SkEventQueue(pAC, SKGE_RLMT, + SK_RLMT_PACKET_RECEIVED, + EvPara); + pAC->CheckQueue = SK_TRUE; + } + + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, + SK_DBGCAT_DRV_RX_PROGRESS, + ("Q")); + } + if ((pAC->dev[pRxPort->PortIndex]->flags & + (IFF_PROMISC | IFF_ALLMULTI)) != 0 || + (ForRlmt & SK_RLMT_RX_PROTOCOL) == + SK_RLMT_RX_PROTOCOL) { + pMsg->protocol = eth_type_trans(pMsg, + pAC->dev[pRxPort->PortIndex]); + netif_rx(pMsg); + pAC->dev[pRxPort->PortIndex]->last_rx = jiffies; + } + else { + DEV_KFREE_SKB(pMsg); + } + + } /* if packet for rlmt */ + } /* for ... scanning the RXD ring */ + + /* RXD ring is empty -> fill and restart */ + FillRxRing(pAC, pRxPort); + /* do not start if called from Close */ + if (pAC->BoardLevel > SK_INIT_DATA) { + ClearAndStartRx(pAC, PortIndex); + } + return; + +rx_failed: + /* remove error frame */ + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ERROR, + ("Schrottdescriptor, length: 0x%x\n", FrameLength)); + + /* release the DMA mapping */ + + PhysAddr = ((SK_U64) pRxd->VDataHigh) << (SK_U64)32; + PhysAddr |= (SK_U64) pRxd->VDataLow; + pci_unmap_page(pAC->PciDev, + PhysAddr, + pAC->RxBufSize - 2, + PCI_DMA_FROMDEVICE); + DEV_KFREE_SKB_IRQ(pRxd->pMBuf); + pRxd->pMBuf = NULL; + pRxPort->RxdRingFree++; + pRxPort->pRxdRingHead = pRxd->pNextRxd; + goto rx_start; + +} /* ReceiveIrq */ + + +/***************************************************************************** + * + * ClearAndStartRx - give a start receive command to BMU, clear IRQ + * + * Description: + * This function sends a start command and a clear interrupt + * command for one receive queue to the BMU. + * + * Returns: N/A + * none + */ +static void ClearAndStartRx( +SK_AC *pAC, /* pointer to the adapter context */ +int PortIndex) /* index of the receive port (XMAC) */ +{ + SK_OUT8(pAC->IoBase, + RxQueueAddr[PortIndex]+Q_CSR, + CSR_START | CSR_IRQ_CL_F); +} /* ClearAndStartRx */ + + +/***************************************************************************** + * + * ClearTxIrq - give a clear transmit IRQ command to BMU + * + * Description: + * This function sends a clear tx IRQ command for one + * transmit queue to the BMU. + * + * Returns: N/A + */ +static void ClearTxIrq( +SK_AC *pAC, /* pointer to the adapter context */ +int PortIndex, /* index of the transmit port (XMAC) */ +int Prio) /* priority or normal queue */ +{ + SK_OUT8(pAC->IoBase, + TxQueueAddr[PortIndex][Prio]+Q_CSR, + CSR_IRQ_CL_F); +} /* ClearTxIrq */ + + +/***************************************************************************** + * + * ClearRxRing - remove all buffers from the receive ring + * + * Description: + * This function removes all receive buffers from the ring. + * The receive BMU must be stopped before calling this function. + * + * Returns: N/A + */ +static void ClearRxRing( +SK_AC *pAC, /* pointer to adapter context */ +RX_PORT *pRxPort) /* pointer to rx port struct */ +{ +RXD *pRxd; /* pointer to the current descriptor */ +unsigned long Flags; +SK_U64 PhysAddr; + + if (pRxPort->RxdRingFree == pAC->RxDescrPerRing) { + return; + } + spin_lock_irqsave(&pRxPort->RxDesRingLock, Flags); + pRxd = pRxPort->pRxdRingHead; + do { + if (pRxd->pMBuf != NULL) { + + PhysAddr = ((SK_U64) pRxd->VDataHigh) << (SK_U64)32; + PhysAddr |= (SK_U64) pRxd->VDataLow; + pci_unmap_page(pAC->PciDev, + PhysAddr, + pAC->RxBufSize - 2, + PCI_DMA_FROMDEVICE); + DEV_KFREE_SKB(pRxd->pMBuf); + pRxd->pMBuf = NULL; + } + pRxd->RBControl &= BMU_OWN; + pRxd = pRxd->pNextRxd; + pRxPort->RxdRingFree++; + } while (pRxd != pRxPort->pRxdRingTail); + pRxPort->pRxdRingTail = pRxPort->pRxdRingHead; + spin_unlock_irqrestore(&pRxPort->RxDesRingLock, Flags); +} /* ClearRxRing */ + +/***************************************************************************** + * + * ClearTxRing - remove all buffers from the transmit ring + * + * Description: + * This function removes all transmit buffers from the ring. + * The transmit BMU must be stopped before calling this function + * and transmitting at the upper level must be disabled. + * The BMU own bit of all descriptors is cleared, the rest is + * done by calling FreeTxDescriptors. + * + * Returns: N/A + */ +static void ClearTxRing( +SK_AC *pAC, /* pointer to adapter context */ +TX_PORT *pTxPort) /* pointer to tx prt struct */ +{ +TXD *pTxd; /* pointer to the current descriptor */ +int i; +unsigned long Flags; + + spin_lock_irqsave(&pTxPort->TxDesRingLock, Flags); + pTxd = pTxPort->pTxdRingHead; + for (i=0; i<pAC->TxDescrPerRing; i++) { + pTxd->TBControl &= ~BMU_OWN; + pTxd = pTxd->pNextTxd; + } + FreeTxDescriptors(pAC, pTxPort); + spin_unlock_irqrestore(&pTxPort->TxDesRingLock, Flags); +} /* ClearTxRing */ + +/***************************************************************************** + * + * SkGeSetMacAddr - Set the hardware MAC address + * + * Description: + * This function sets the MAC address used by the adapter. + * + * Returns: + * 0, if everything is ok + * !=0, on error + */ +static int SkGeSetMacAddr(struct SK_NET_DEVICE *dev, void *p) +{ + +DEV_NET *pNet = netdev_priv(dev); +SK_AC *pAC = pNet->pAC; + +struct sockaddr *addr = p; +unsigned long Flags; + + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, + ("SkGeSetMacAddr starts now...\n")); + if(netif_running(dev)) + return -EBUSY; + + memcpy(dev->dev_addr, addr->sa_data,dev->addr_len); + + spin_lock_irqsave(&pAC->SlowPathLock, Flags); + + if (pAC->RlmtNets == 2) + SkAddrOverride(pAC, pAC->IoBase, pNet->NetNr, + (SK_MAC_ADDR*)dev->dev_addr, SK_ADDR_VIRTUAL_ADDRESS); + else + SkAddrOverride(pAC, pAC->IoBase, pAC->ActivePort, + (SK_MAC_ADDR*)dev->dev_addr, SK_ADDR_VIRTUAL_ADDRESS); + + + + spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); + return 0; +} /* SkGeSetMacAddr */ + + +/***************************************************************************** + * + * SkGeSetRxMode - set receive mode + * + * Description: + * This function sets the receive mode of an adapter. The adapter + * supports promiscuous mode, allmulticast mode and a number of + * multicast addresses. If more multicast addresses the available + * are selected, a hash function in the hardware is used. + * + * Returns: + * 0, if everything is ok + * !=0, on error + */ +static void SkGeSetRxMode(struct SK_NET_DEVICE *dev) +{ + +DEV_NET *pNet; +SK_AC *pAC; + +struct dev_mc_list *pMcList; +int i; +int PortIdx; +unsigned long Flags; + + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, + ("SkGeSetRxMode starts now... ")); + + pNet = netdev_priv(dev); + pAC = pNet->pAC; + if (pAC->RlmtNets == 1) + PortIdx = pAC->ActivePort; + else + PortIdx = pNet->NetNr; + + spin_lock_irqsave(&pAC->SlowPathLock, Flags); + if (dev->flags & IFF_PROMISC) { + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, + ("PROMISCUOUS mode\n")); + SkAddrPromiscuousChange(pAC, pAC->IoBase, PortIdx, + SK_PROM_MODE_LLC); + } else if (dev->flags & IFF_ALLMULTI) { + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, + ("ALLMULTI mode\n")); + SkAddrPromiscuousChange(pAC, pAC->IoBase, PortIdx, + SK_PROM_MODE_ALL_MC); + } else { + SkAddrPromiscuousChange(pAC, pAC->IoBase, PortIdx, + SK_PROM_MODE_NONE); + SkAddrMcClear(pAC, pAC->IoBase, PortIdx, 0); + + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, + ("Number of MC entries: %d ", dev->mc_count)); + + pMcList = dev->mc_list; + for (i=0; i<dev->mc_count; i++, pMcList = pMcList->next) { + SkAddrMcAdd(pAC, pAC->IoBase, PortIdx, + (SK_MAC_ADDR*)pMcList->dmi_addr, 0); + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_MCA, + ("%02x:%02x:%02x:%02x:%02x:%02x\n", + pMcList->dmi_addr[0], + pMcList->dmi_addr[1], + pMcList->dmi_addr[2], + pMcList->dmi_addr[3], + pMcList->dmi_addr[4], + pMcList->dmi_addr[5])); + } + SkAddrMcUpdate(pAC, pAC->IoBase, PortIdx); + } + spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); + + return; +} /* SkGeSetRxMode */ + + +/***************************************************************************** + * + * SkGeChangeMtu - set the MTU to another value + * + * Description: + * This function sets is called whenever the MTU size is changed + * (ifconfig mtu xxx dev ethX). If the MTU is bigger than standard + * ethernet MTU size, long frame support is activated. + * + * Returns: + * 0, if everything is ok + * !=0, on error + */ +static int SkGeChangeMtu(struct SK_NET_DEVICE *dev, int NewMtu) +{ +DEV_NET *pNet; +struct net_device *pOtherDev; +SK_AC *pAC; +unsigned long Flags; +int i; +SK_EVPARA EvPara; + + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, + ("SkGeChangeMtu starts now...\n")); + + pNet = netdev_priv(dev); + pAC = pNet->pAC; + + if ((NewMtu < 68) || (NewMtu > SK_JUMBO_MTU)) { + return -EINVAL; + } + + if(pAC->BoardLevel != SK_INIT_RUN) { + return -EINVAL; + } + +#ifdef SK_DIAG_SUPPORT + if (pAC->DiagModeActive == DIAG_ACTIVE) { + if (pAC->DiagFlowCtrl == SK_FALSE) { + return -1; /* still in use, deny any actions of MTU */ + } else { + pAC->DiagFlowCtrl = SK_FALSE; + } + } +#endif + + pOtherDev = pAC->dev[1 - pNet->NetNr]; + + if ( netif_running(pOtherDev) && (pOtherDev->mtu > 1500) + && (NewMtu <= 1500)) + return 0; + + pAC->RxBufSize = NewMtu + 32; + dev->mtu = NewMtu; + + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, + ("New MTU: %d\n", NewMtu)); + + /* + ** Prevent any reconfiguration while changing the MTU + ** by disabling any interrupts + */ + SK_OUT32(pAC->IoBase, B0_IMSK, 0); + spin_lock_irqsave(&pAC->SlowPathLock, Flags); + + /* + ** Notify RLMT that any ports are to be stopped + */ + EvPara.Para32[0] = 0; + EvPara.Para32[1] = -1; + if ((pAC->GIni.GIMacsFound == 2 ) && (pAC->RlmtNets == 2)) { + SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara); + EvPara.Para32[0] = 1; + SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara); + } else { + SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara); + } + + /* + ** After calling the SkEventDispatcher(), RLMT is aware about + ** the stopped ports -> configuration can take place! + */ + SkEventDispatcher(pAC, pAC->IoBase); + + for (i=0; i<pAC->GIni.GIMacsFound; i++) { + spin_lock(&pAC->TxPort[i][TX_PRIO_LOW].TxDesRingLock); + netif_stop_queue(pAC->dev[i]); + + } + + /* + ** Depending on the desired MTU size change, a different number of + ** RX buffers need to be allocated + */ + if (NewMtu > 1500) { + /* + ** Use less rx buffers + */ + for (i=0; i<pAC->GIni.GIMacsFound; i++) { + if ((pAC->GIni.GIMacsFound == 2 ) && (pAC->RlmtNets == 2)) { + pAC->RxPort[i].RxFillLimit = pAC->RxDescrPerRing - + (pAC->RxDescrPerRing / 4); + } else { + if (i == pAC->ActivePort) { + pAC->RxPort[i].RxFillLimit = pAC->RxDescrPerRing - + (pAC->RxDescrPerRing / 4); + } else { + pAC->RxPort[i].RxFillLimit = pAC->RxDescrPerRing - + (pAC->RxDescrPerRing / 10); + } + } + } + } else { + /* + ** Use the normal amount of rx buffers + */ + for (i=0; i<pAC->GIni.GIMacsFound; i++) { + if ((pAC->GIni.GIMacsFound == 2 ) && (pAC->RlmtNets == 2)) { + pAC->RxPort[i].RxFillLimit = 1; + } else { + if (i == pAC->ActivePort) { + pAC->RxPort[i].RxFillLimit = 1; + } else { + pAC->RxPort[i].RxFillLimit = pAC->RxDescrPerRing - + (pAC->RxDescrPerRing / 4); + } + } + } + } + + SkGeDeInit(pAC, pAC->IoBase); + + /* + ** enable/disable hardware support for long frames + */ + if (NewMtu > 1500) { +// pAC->JumboActivated = SK_TRUE; /* is never set back !!! */ + pAC->GIni.GIPortUsage = SK_JUMBO_LINK; + } else { + if ((pAC->GIni.GIMacsFound == 2 ) && (pAC->RlmtNets == 2)) { + pAC->GIni.GIPortUsage = SK_MUL_LINK; + } else { + pAC->GIni.GIPortUsage = SK_RED_LINK; + } + } + + SkGeInit( pAC, pAC->IoBase, SK_INIT_IO); + SkI2cInit( pAC, pAC->IoBase, SK_INIT_IO); + SkEventInit(pAC, pAC->IoBase, SK_INIT_IO); + SkPnmiInit( pAC, pAC->IoBase, SK_INIT_IO); + SkAddrInit( pAC, pAC->IoBase, SK_INIT_IO); + SkRlmtInit( pAC, pAC->IoBase, SK_INIT_IO); + SkTimerInit(pAC, pAC->IoBase, SK_INIT_IO); + + /* + ** tschilling: + ** Speed and others are set back to default in level 1 init! + */ + GetConfiguration(pAC); + + SkGeInit( pAC, pAC->IoBase, SK_INIT_RUN); + SkI2cInit( pAC, pAC->IoBase, SK_INIT_RUN); + SkEventInit(pAC, pAC->IoBase, SK_INIT_RUN); + SkPnmiInit( pAC, pAC->IoBase, SK_INIT_RUN); + SkAddrInit( pAC, pAC->IoBase, SK_INIT_RUN); + SkRlmtInit( pAC, pAC->IoBase, SK_INIT_RUN); + SkTimerInit(pAC, pAC->IoBase, SK_INIT_RUN); + + /* + ** clear and reinit the rx rings here + */ + for (i=0; i<pAC->GIni.GIMacsFound; i++) { + ReceiveIrq(pAC, &pAC->RxPort[i], SK_TRUE); + ClearRxRing(pAC, &pAC->RxPort[i]); + FillRxRing(pAC, &pAC->RxPort[i]); + + /* + ** Enable transmit descriptor polling + */ + SkGePollTxD(pAC, pAC->IoBase, i, SK_TRUE); + FillRxRing(pAC, &pAC->RxPort[i]); + }; + + SkGeYellowLED(pAC, pAC->IoBase, 1); + SkDimEnableModerationIfNeeded(pAC); + SkDimDisplayModerationSettings(pAC); + + netif_start_queue(pAC->dev[pNet->PortNr]); + for (i=pAC->GIni.GIMacsFound-1; i>=0; i--) { + spin_unlock(&pAC->TxPort[i][TX_PRIO_LOW].TxDesRingLock); + } + + /* + ** Enable Interrupts again + */ + SK_OUT32(pAC->IoBase, B0_IMSK, pAC->GIni.GIValIrqMask); + SK_OUT32(pAC->IoBase, B0_HWE_IMSK, IRQ_HWE_MASK); + + SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_START, EvPara); + SkEventDispatcher(pAC, pAC->IoBase); + + /* + ** Notify RLMT about the changing and restarting one (or more) ports + */ + if ((pAC->GIni.GIMacsFound == 2 ) && (pAC->RlmtNets == 2)) { + EvPara.Para32[0] = pAC->RlmtNets; + EvPara.Para32[1] = -1; + SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_SET_NETS, EvPara); + EvPara.Para32[0] = pNet->PortNr; + EvPara.Para32[1] = -1; + SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_START, EvPara); + + if (netif_running(pOtherDev)) { + DEV_NET *pOtherNet = netdev_priv(pOtherDev); + EvPara.Para32[0] = pOtherNet->PortNr; + SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_START, EvPara); + } + } else { + SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_START, EvPara); + } + + SkEventDispatcher(pAC, pAC->IoBase); + spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); + + /* + ** While testing this driver with latest kernel 2.5 (2.5.70), it + ** seems as if upper layers have a problem to handle a successful + ** return value of '0'. If such a zero is returned, the complete + ** system hangs for several minutes (!), which is in acceptable. + ** + ** Currently it is not clear, what the exact reason for this problem + ** is. The implemented workaround for 2.5 is to return the desired + ** new MTU size if all needed changes for the new MTU size where + ** performed. In kernels 2.2 and 2.4, a zero value is returned, + ** which indicates the successful change of the mtu-size. + */ + return NewMtu; + +} /* SkGeChangeMtu */ + + +/***************************************************************************** + * + * SkGeStats - return ethernet device statistics + * + * Description: + * This function return statistic data about the ethernet device + * to the operating system. + * + * Returns: + * pointer to the statistic structure. + */ +static struct net_device_stats *SkGeStats(struct SK_NET_DEVICE *dev) +{ +DEV_NET *pNet = netdev_priv(dev); +SK_AC *pAC = pNet->pAC; +SK_PNMI_STRUCT_DATA *pPnmiStruct; /* structure for all Pnmi-Data */ +SK_PNMI_STAT *pPnmiStat; /* pointer to virtual XMAC stat. data */ +SK_PNMI_CONF *pPnmiConf; /* pointer to virtual link config. */ +unsigned int Size; /* size of pnmi struct */ +unsigned long Flags; /* for spin lock */ + + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, + ("SkGeStats starts now...\n")); + pPnmiStruct = &pAC->PnmiStruct; + +#ifdef SK_DIAG_SUPPORT + if ((pAC->DiagModeActive == DIAG_NOTACTIVE) && + (pAC->BoardLevel == SK_INIT_RUN)) { +#endif + SK_MEMSET(pPnmiStruct, 0, sizeof(SK_PNMI_STRUCT_DATA)); + spin_lock_irqsave(&pAC->SlowPathLock, Flags); + Size = SK_PNMI_STRUCT_SIZE; + SkPnmiGetStruct(pAC, pAC->IoBase, pPnmiStruct, &Size, pNet->NetNr); + spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); +#ifdef SK_DIAG_SUPPORT + } +#endif + + pPnmiStat = &pPnmiStruct->Stat[0]; + pPnmiConf = &pPnmiStruct->Conf[0]; + + pAC->stats.rx_packets = (SK_U32) pPnmiStruct->RxDeliveredCts & 0xFFFFFFFF; + pAC->stats.tx_packets = (SK_U32) pPnmiStat->StatTxOkCts & 0xFFFFFFFF; + pAC->stats.rx_bytes = (SK_U32) pPnmiStruct->RxOctetsDeliveredCts; + pAC->stats.tx_bytes = (SK_U32) pPnmiStat->StatTxOctetsOkCts; + + if (dev->mtu <= 1500) { + pAC->stats.rx_errors = (SK_U32) pPnmiStruct->InErrorsCts & 0xFFFFFFFF; + } else { + pAC->stats.rx_errors = (SK_U32) ((pPnmiStruct->InErrorsCts - + pPnmiStat->StatRxTooLongCts) & 0xFFFFFFFF); + } + + + if (pAC->GIni.GP[0].PhyType == SK_PHY_XMAC && pAC->HWRevision < 12) + pAC->stats.rx_errors = pAC->stats.rx_errors - pPnmiStat->StatRxShortsCts; + + pAC->stats.tx_errors = (SK_U32) pPnmiStat->StatTxSingleCollisionCts & 0xFFFFFFFF; + pAC->stats.rx_dropped = (SK_U32) pPnmiStruct->RxNoBufCts & 0xFFFFFFFF; + pAC->stats.tx_dropped = (SK_U32) pPnmiStruct->TxNoBufCts & 0xFFFFFFFF; + pAC->stats.multicast = (SK_U32) pPnmiStat->StatRxMulticastOkCts & 0xFFFFFFFF; + pAC->stats.collisions = (SK_U32) pPnmiStat->StatTxSingleCollisionCts & 0xFFFFFFFF; + + /* detailed rx_errors: */ + pAC->stats.rx_length_errors = (SK_U32) pPnmiStat->StatRxRuntCts & 0xFFFFFFFF; + pAC->stats.rx_over_errors = (SK_U32) pPnmiStat->StatRxFifoOverflowCts & 0xFFFFFFFF; + pAC->stats.rx_crc_errors = (SK_U32) pPnmiStat->StatRxFcsCts & 0xFFFFFFFF; + pAC->stats.rx_frame_errors = (SK_U32) pPnmiStat->StatRxFramingCts & 0xFFFFFFFF; + pAC->stats.rx_fifo_errors = (SK_U32) pPnmiStat->StatRxFifoOverflowCts & 0xFFFFFFFF; + pAC->stats.rx_missed_errors = (SK_U32) pPnmiStat->StatRxMissedCts & 0xFFFFFFFF; + + /* detailed tx_errors */ + pAC->stats.tx_aborted_errors = (SK_U32) 0; + pAC->stats.tx_carrier_errors = (SK_U32) pPnmiStat->StatTxCarrierCts & 0xFFFFFFFF; + pAC->stats.tx_fifo_errors = (SK_U32) pPnmiStat->StatTxFifoUnderrunCts & 0xFFFFFFFF; + pAC->stats.tx_heartbeat_errors = (SK_U32) pPnmiStat->StatTxCarrierCts & 0xFFFFFFFF; + pAC->stats.tx_window_errors = (SK_U32) 0; + + return(&pAC->stats); +} /* SkGeStats */ + +/* + * Basic MII register access + */ +static int SkGeMiiIoctl(struct net_device *dev, + struct mii_ioctl_data *data, int cmd) +{ + DEV_NET *pNet = netdev_priv(dev); + SK_AC *pAC = pNet->pAC; + SK_IOC IoC = pAC->IoBase; + int Port = pNet->PortNr; + SK_GEPORT *pPrt = &pAC->GIni.GP[Port]; + unsigned long Flags; + int err = 0; + int reg = data->reg_num & 0x1f; + SK_U16 val = data->val_in; + + if (!netif_running(dev)) + return -ENODEV; /* Phy still in reset */ + + spin_lock_irqsave(&pAC->SlowPathLock, Flags); + switch(cmd) { + case SIOCGMIIPHY: + data->phy_id = pPrt->PhyAddr; + + /* fallthru */ + case SIOCGMIIREG: + if (pAC->GIni.GIGenesis) + SkXmPhyRead(pAC, IoC, Port, reg, &val); + else + SkGmPhyRead(pAC, IoC, Port, reg, &val); + + data->val_out = val; + break; + + case SIOCSMIIREG: + if (!capable(CAP_NET_ADMIN)) + err = -EPERM; + + else if (pAC->GIni.GIGenesis) + SkXmPhyWrite(pAC, IoC, Port, reg, val); + else + SkGmPhyWrite(pAC, IoC, Port, reg, val); + break; + default: + err = -EOPNOTSUPP; + } + spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); + return err; +} + + +/***************************************************************************** + * + * SkGeIoctl - IO-control function + * + * Description: + * This function is called if an ioctl is issued on the device. + * There are three subfunction for reading, writing and test-writing + * the private MIB data structure (useful for SysKonnect-internal tools). + * + * Returns: + * 0, if everything is ok + * !=0, on error + */ +static int SkGeIoctl(struct SK_NET_DEVICE *dev, struct ifreq *rq, int cmd) +{ +DEV_NET *pNet; +SK_AC *pAC; +void *pMemBuf; +struct pci_dev *pdev = NULL; +SK_GE_IOCTL Ioctl; +unsigned int Err = 0; +int Size = 0; +int Ret = 0; +unsigned int Length = 0; +int HeaderLength = sizeof(SK_U32) + sizeof(SK_U32); + + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, + ("SkGeIoctl starts now...\n")); + + pNet = netdev_priv(dev); + pAC = pNet->pAC; + + if (cmd == SIOCGMIIPHY || cmd == SIOCSMIIREG || cmd == SIOCGMIIREG) + return SkGeMiiIoctl(dev, if_mii(rq), cmd); + + if(copy_from_user(&Ioctl, rq->ifr_data, sizeof(SK_GE_IOCTL))) { + return -EFAULT; + } + + switch(cmd) { + case SK_IOCTL_SETMIB: + case SK_IOCTL_PRESETMIB: + if (!capable(CAP_NET_ADMIN)) return -EPERM; + case SK_IOCTL_GETMIB: + if(copy_from_user(&pAC->PnmiStruct, Ioctl.pData, + Ioctl.Len<sizeof(pAC->PnmiStruct)? + Ioctl.Len : sizeof(pAC->PnmiStruct))) { + return -EFAULT; + } + Size = SkGeIocMib(pNet, Ioctl.Len, cmd); + if(copy_to_user(Ioctl.pData, &pAC->PnmiStruct, + Ioctl.Len<Size? Ioctl.Len : Size)) { + return -EFAULT; + } + Ioctl.Len = Size; + if(copy_to_user(rq->ifr_data, &Ioctl, sizeof(SK_GE_IOCTL))) { + return -EFAULT; + } + break; + case SK_IOCTL_GEN: + if (Ioctl.Len < (sizeof(pAC->PnmiStruct) + HeaderLength)) { + Length = Ioctl.Len; + } else { + Length = sizeof(pAC->PnmiStruct) + HeaderLength; + } + if (NULL == (pMemBuf = kmalloc(Length, GFP_KERNEL))) { + return -ENOMEM; + } + if(copy_from_user(pMemBuf, Ioctl.pData, Length)) { + Err = -EFAULT; + goto fault_gen; + } + if ((Ret = SkPnmiGenIoctl(pAC, pAC->IoBase, pMemBuf, &Length, 0)) < 0) { + Err = -EFAULT; + goto fault_gen; + } + if(copy_to_user(Ioctl.pData, pMemBuf, Length) ) { + Err = -EFAULT; + goto fault_gen; + } + Ioctl.Len = Length; + if(copy_to_user(rq->ifr_data, &Ioctl, sizeof(SK_GE_IOCTL))) { + Err = -EFAULT; + goto fault_gen; + } +fault_gen: + kfree(pMemBuf); /* cleanup everything */ + break; +#ifdef SK_DIAG_SUPPORT + case SK_IOCTL_DIAG: + if (!capable(CAP_NET_ADMIN)) return -EPERM; + if (Ioctl.Len < (sizeof(pAC->PnmiStruct) + HeaderLength)) { + Length = Ioctl.Len; + } else { + Length = sizeof(pAC->PnmiStruct) + HeaderLength; + } + if (NULL == (pMemBuf = kmalloc(Length, GFP_KERNEL))) { + return -ENOMEM; + } + if(copy_from_user(pMemBuf, Ioctl.pData, Length)) { + Err = -EFAULT; + goto fault_diag; + } + pdev = pAC->PciDev; + Length = 3 * sizeof(SK_U32); /* Error, Bus and Device */ + /* + ** While coding this new IOCTL interface, only a few lines of code + ** are to to be added. Therefore no dedicated function has been + ** added. If more functionality is added, a separate function + ** should be used... + */ + * ((SK_U32 *)pMemBuf) = 0; + * ((SK_U32 *)pMemBuf + 1) = pdev->bus->number; + * ((SK_U32 *)pMemBuf + 2) = ParseDeviceNbrFromSlotName(pci_name(pdev)); + if(copy_to_user(Ioctl.pData, pMemBuf, Length) ) { + Err = -EFAULT; + goto fault_diag; + } + Ioctl.Len = Length; + if(copy_to_user(rq->ifr_data, &Ioctl, sizeof(SK_GE_IOCTL))) { + Err = -EFAULT; + goto fault_diag; + } +fault_diag: + kfree(pMemBuf); /* cleanup everything */ + break; +#endif + default: + Err = -EOPNOTSUPP; + } + + return(Err); + +} /* SkGeIoctl */ + + +/***************************************************************************** + * + * SkGeIocMib - handle a GetMib, SetMib- or PresetMib-ioctl message + * + * Description: + * This function reads/writes the MIB data using PNMI (Private Network + * Management Interface). + * The destination for the data must be provided with the + * ioctl call and is given to the driver in the form of + * a user space address. + * Copying from the user-provided data area into kernel messages + * and back is done by copy_from_user and copy_to_user calls in + * SkGeIoctl. + * + * Returns: + * returned size from PNMI call + */ +static int SkGeIocMib( +DEV_NET *pNet, /* pointer to the adapter context */ +unsigned int Size, /* length of ioctl data */ +int mode) /* flag for set/preset */ +{ +unsigned long Flags; /* for spin lock */ +SK_AC *pAC; + + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, + ("SkGeIocMib starts now...\n")); + pAC = pNet->pAC; + /* access MIB */ + spin_lock_irqsave(&pAC->SlowPathLock, Flags); + switch(mode) { + case SK_IOCTL_GETMIB: + SkPnmiGetStruct(pAC, pAC->IoBase, &pAC->PnmiStruct, &Size, + pNet->NetNr); + break; + case SK_IOCTL_PRESETMIB: + SkPnmiPreSetStruct(pAC, pAC->IoBase, &pAC->PnmiStruct, &Size, + pNet->NetNr); + break; + case SK_IOCTL_SETMIB: + SkPnmiSetStruct(pAC, pAC->IoBase, &pAC->PnmiStruct, &Size, + pNet->NetNr); + break; + default: + break; + } + spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, + ("MIB data access succeeded\n")); + return (Size); +} /* SkGeIocMib */ + + +/***************************************************************************** + * + * GetConfiguration - read configuration information + * + * Description: + * This function reads per-adapter configuration information from + * the options provided on the command line. + * + * Returns: + * none + */ +static void GetConfiguration( +SK_AC *pAC) /* pointer to the adapter context structure */ +{ +SK_I32 Port; /* preferred port */ +SK_BOOL AutoSet; +SK_BOOL DupSet; +int LinkSpeed = SK_LSPEED_AUTO; /* Link speed */ +int AutoNeg = 1; /* autoneg off (0) or on (1) */ +int DuplexCap = 0; /* 0=both,1=full,2=half */ +int FlowCtrl = SK_FLOW_MODE_SYM_OR_REM; /* FlowControl */ +int MSMode = SK_MS_MODE_AUTO; /* master/slave mode */ + +SK_BOOL IsConTypeDefined = SK_TRUE; +SK_BOOL IsLinkSpeedDefined = SK_TRUE; +SK_BOOL IsFlowCtrlDefined = SK_TRUE; +SK_BOOL IsRoleDefined = SK_TRUE; +SK_BOOL IsModeDefined = SK_TRUE; +/* + * The two parameters AutoNeg. and DuplexCap. map to one configuration + * parameter. The mapping is described by this table: + * DuplexCap -> | both | full | half | + * AutoNeg | | | | + * ----------------------------------------------------------------- + * Off | illegal | Full | Half | + * ----------------------------------------------------------------- + * On | AutoBoth | AutoFull | AutoHalf | + * ----------------------------------------------------------------- + * Sense | AutoSense | AutoSense | AutoSense | + */ +int Capabilities[3][3] = + { { -1, SK_LMODE_FULL , SK_LMODE_HALF }, + {SK_LMODE_AUTOBOTH , SK_LMODE_AUTOFULL , SK_LMODE_AUTOHALF }, + {SK_LMODE_AUTOSENSE, SK_LMODE_AUTOSENSE, SK_LMODE_AUTOSENSE} }; + +#define DC_BOTH 0 +#define DC_FULL 1 +#define DC_HALF 2 +#define AN_OFF 0 +#define AN_ON 1 +#define AN_SENS 2 +#define M_CurrPort pAC->GIni.GP[Port] + + + /* + ** Set the default values first for both ports! + */ + for (Port = 0; Port < SK_MAX_MACS; Port++) { + M_CurrPort.PLinkModeConf = Capabilities[AN_ON][DC_BOTH]; + M_CurrPort.PFlowCtrlMode = SK_FLOW_MODE_SYM_OR_REM; + M_CurrPort.PMSMode = SK_MS_MODE_AUTO; + M_CurrPort.PLinkSpeed = SK_LSPEED_AUTO; + } + + /* + ** Check merged parameter ConType. If it has not been used, + ** verify any other parameter (e.g. AutoNeg) and use default values. + ** + ** Stating both ConType and other lowlevel link parameters is also + ** possible. If this is the case, the passed ConType-parameter is + ** overwritten by the lowlevel link parameter. + ** + ** The following settings are used for a merged ConType-parameter: + ** + ** ConType DupCap AutoNeg FlowCtrl Role Speed + ** ------- ------ ------- -------- ---------- ----- + ** Auto Both On SymOrRem Auto Auto + ** 100FD Full Off None <ignored> 100 + ** 100HD Half Off None <ignored> 100 + ** 10FD Full Off None <ignored> 10 + ** 10HD Half Off None <ignored> 10 + ** + ** This ConType parameter is used for all ports of the adapter! + */ + if ( (ConType != NULL) && + (pAC->Index < SK_MAX_CARD_PARAM) && + (ConType[pAC->Index] != NULL) ) { + + /* Check chipset family */ + if ((!pAC->ChipsetType) && + (strcmp(ConType[pAC->Index],"Auto")!=0) && + (strcmp(ConType[pAC->Index],"")!=0)) { + /* Set the speed parameter back */ + printk("sk98lin: Illegal value \"%s\" " + "for ConType." + " Using Auto.\n", + ConType[pAC->Index]); + + sprintf(ConType[pAC->Index], "Auto"); + } + + if (strcmp(ConType[pAC->Index],"")==0) { + IsConTypeDefined = SK_FALSE; /* No ConType defined */ + } else if (strcmp(ConType[pAC->Index],"Auto")==0) { + for (Port = 0; Port < SK_MAX_MACS; Port++) { + M_CurrPort.PLinkModeConf = Capabilities[AN_ON][DC_BOTH]; + M_CurrPort.PFlowCtrlMode = SK_FLOW_MODE_SYM_OR_REM; + M_CurrPort.PMSMode = SK_MS_MODE_AUTO; + M_CurrPort.PLinkSpeed = SK_LSPEED_AUTO; + } + } else if (strcmp(ConType[pAC->Index],"100FD")==0) { + for (Port = 0; Port < SK_MAX_MACS; Port++) { + M_CurrPort.PLinkModeConf = Capabilities[AN_OFF][DC_FULL]; + M_CurrPort.PFlowCtrlMode = SK_FLOW_MODE_NONE; + M_CurrPort.PMSMode = SK_MS_MODE_AUTO; + M_CurrPort.PLinkSpeed = SK_LSPEED_100MBPS; + } + } else if (strcmp(ConType[pAC->Index],"100HD")==0) { + for (Port = 0; Port < SK_MAX_MACS; Port++) { + M_CurrPort.PLinkModeConf = Capabilities[AN_OFF][DC_HALF]; + M_CurrPort.PFlowCtrlMode = SK_FLOW_MODE_NONE; + M_CurrPort.PMSMode = SK_MS_MODE_AUTO; + M_CurrPort.PLinkSpeed = SK_LSPEED_100MBPS; + } + } else if (strcmp(ConType[pAC->Index],"10FD")==0) { + for (Port = 0; Port < SK_MAX_MACS; Port++) { + M_CurrPort.PLinkModeConf = Capabilities[AN_OFF][DC_FULL]; + M_CurrPort.PFlowCtrlMode = SK_FLOW_MODE_NONE; + M_CurrPort.PMSMode = SK_MS_MODE_AUTO; + M_CurrPort.PLinkSpeed = SK_LSPEED_10MBPS; + } + } else if (strcmp(ConType[pAC->Index],"10HD")==0) { + for (Port = 0; Port < SK_MAX_MACS; Port++) { + M_CurrPort.PLinkModeConf = Capabilities[AN_OFF][DC_HALF]; + M_CurrPort.PFlowCtrlMode = SK_FLOW_MODE_NONE; + M_CurrPort.PMSMode = SK_MS_MODE_AUTO; + M_CurrPort.PLinkSpeed = SK_LSPEED_10MBPS; + } + } else { + printk("sk98lin: Illegal value \"%s\" for ConType\n", + ConType[pAC->Index]); + IsConTypeDefined = SK_FALSE; /* Wrong ConType defined */ + } + } else { + IsConTypeDefined = SK_FALSE; /* No ConType defined */ + } + + /* + ** Parse any parameter settings for port A: + ** a) any LinkSpeed stated? + */ + if (Speed_A != NULL && pAC->Index<SK_MAX_CARD_PARAM && + Speed_A[pAC->Index] != NULL) { + if (strcmp(Speed_A[pAC->Index],"")==0) { + IsLinkSpeedDefined = SK_FALSE; + } else if (strcmp(Speed_A[pAC->Index],"Auto")==0) { + LinkSpeed = SK_LSPEED_AUTO; + } else if (strcmp(Speed_A[pAC->Index],"10")==0) { + LinkSpeed = SK_LSPEED_10MBPS; + } else if (strcmp(Speed_A[pAC->Index],"100")==0) { + LinkSpeed = SK_LSPEED_100MBPS; + } else if (strcmp(Speed_A[pAC->Index],"1000")==0) { + LinkSpeed = SK_LSPEED_1000MBPS; + } else { + printk("sk98lin: Illegal value \"%s\" for Speed_A\n", + Speed_A[pAC->Index]); + IsLinkSpeedDefined = SK_FALSE; + } + } else { + IsLinkSpeedDefined = SK_FALSE; + } + + /* + ** Check speed parameter: + ** Only copper type adapter and GE V2 cards + */ + if (((!pAC->ChipsetType) || (pAC->GIni.GICopperType != SK_TRUE)) && + ((LinkSpeed != SK_LSPEED_AUTO) && + (LinkSpeed != SK_LSPEED_1000MBPS))) { + printk("sk98lin: Illegal value for Speed_A. " + "Not a copper card or GE V2 card\n Using " + "speed 1000\n"); + LinkSpeed = SK_LSPEED_1000MBPS; + } + + /* + ** Decide whether to set new config value if somethig valid has + ** been received. + */ + if (IsLinkSpeedDefined) { + pAC->GIni.GP[0].PLinkSpeed = LinkSpeed; + } + + /* + ** b) Any Autonegotiation and DuplexCapabilities set? + ** Please note that both belong together... + */ + AutoNeg = AN_ON; /* tschilling: Default: Autonegotiation on! */ + AutoSet = SK_FALSE; + if (AutoNeg_A != NULL && pAC->Index<SK_MAX_CARD_PARAM && + AutoNeg_A[pAC->Index] != NULL) { + AutoSet = SK_TRUE; + if (strcmp(AutoNeg_A[pAC->Index],"")==0) { + AutoSet = SK_FALSE; + } else if (strcmp(AutoNeg_A[pAC->Index],"On")==0) { + AutoNeg = AN_ON; + } else if (strcmp(AutoNeg_A[pAC->Index],"Off")==0) { + AutoNeg = AN_OFF; + } else if (strcmp(AutoNeg_A[pAC->Index],"Sense")==0) { + AutoNeg = AN_SENS; + } else { + printk("sk98lin: Illegal value \"%s\" for AutoNeg_A\n", + AutoNeg_A[pAC->Index]); + } + } + + DuplexCap = DC_BOTH; + DupSet = SK_FALSE; + if (DupCap_A != NULL && pAC->Index<SK_MAX_CARD_PARAM && + DupCap_A[pAC->Index] != NULL) { + DupSet = SK_TRUE; + if (strcmp(DupCap_A[pAC->Index],"")==0) { + DupSet = SK_FALSE; + } else if (strcmp(DupCap_A[pAC->Index],"Both")==0) { + DuplexCap = DC_BOTH; + } else if (strcmp(DupCap_A[pAC->Index],"Full")==0) { + DuplexCap = DC_FULL; + } else if (strcmp(DupCap_A[pAC->Index],"Half")==0) { + DuplexCap = DC_HALF; + } else { + printk("sk98lin: Illegal value \"%s\" for DupCap_A\n", + DupCap_A[pAC->Index]); + } + } + + /* + ** Check for illegal combinations + */ + if ((LinkSpeed == SK_LSPEED_1000MBPS) && + ((DuplexCap == SK_LMODE_STAT_AUTOHALF) || + (DuplexCap == SK_LMODE_STAT_HALF)) && + (pAC->ChipsetType)) { + printk("sk98lin: Half Duplex not possible with Gigabit speed!\n" + " Using Full Duplex.\n"); + DuplexCap = DC_FULL; + } + + if ( AutoSet && AutoNeg==AN_SENS && DupSet) { + printk("sk98lin, Port A: DuplexCapabilities" + " ignored using Sense mode\n"); + } + + if (AutoSet && AutoNeg==AN_OFF && DupSet && DuplexCap==DC_BOTH){ + printk("sk98lin: Port A: Illegal combination" + " of values AutoNeg. and DuplexCap.\n Using " + "Full Duplex\n"); + DuplexCap = DC_FULL; + } + + if (AutoSet && AutoNeg==AN_OFF && !DupSet) { + DuplexCap = DC_FULL; + } + + if (!AutoSet && DupSet) { + printk("sk98lin: Port A: Duplex setting not" + " possible in\n default AutoNegotiation mode" + " (Sense).\n Using AutoNegotiation On\n"); + AutoNeg = AN_ON; + } + + /* + ** set the desired mode + */ + if (AutoSet || DupSet) { + pAC->GIni.GP[0].PLinkModeConf = Capabilities[AutoNeg][DuplexCap]; + } + + /* + ** c) Any Flowcontrol-parameter set? + */ + if (FlowCtrl_A != NULL && pAC->Index<SK_MAX_CARD_PARAM && + FlowCtrl_A[pAC->Index] != NULL) { + if (strcmp(FlowCtrl_A[pAC->Index],"") == 0) { + IsFlowCtrlDefined = SK_FALSE; + } else if (strcmp(FlowCtrl_A[pAC->Index],"SymOrRem") == 0) { + FlowCtrl = SK_FLOW_MODE_SYM_OR_REM; + } else if (strcmp(FlowCtrl_A[pAC->Index],"Sym")==0) { + FlowCtrl = SK_FLOW_MODE_SYMMETRIC; + } else if (strcmp(FlowCtrl_A[pAC->Index],"LocSend")==0) { + FlowCtrl = SK_FLOW_MODE_LOC_SEND; + } else if (strcmp(FlowCtrl_A[pAC->Index],"None")==0) { + FlowCtrl = SK_FLOW_MODE_NONE; + } else { + printk("sk98lin: Illegal value \"%s\" for FlowCtrl_A\n", + FlowCtrl_A[pAC->Index]); + IsFlowCtrlDefined = SK_FALSE; + } + } else { + IsFlowCtrlDefined = SK_FALSE; + } + + if (IsFlowCtrlDefined) { + if ((AutoNeg == AN_OFF) && (FlowCtrl != SK_FLOW_MODE_NONE)) { + printk("sk98lin: Port A: FlowControl" + " impossible without AutoNegotiation," + " disabled\n"); + FlowCtrl = SK_FLOW_MODE_NONE; + } + pAC->GIni.GP[0].PFlowCtrlMode = FlowCtrl; + } + + /* + ** d) What is with the RoleParameter? + */ + if (Role_A != NULL && pAC->Index<SK_MAX_CARD_PARAM && + Role_A[pAC->Index] != NULL) { + if (strcmp(Role_A[pAC->Index],"")==0) { + IsRoleDefined = SK_FALSE; + } else if (strcmp(Role_A[pAC->Index],"Auto")==0) { + MSMode = SK_MS_MODE_AUTO; + } else if (strcmp(Role_A[pAC->Index],"Master")==0) { + MSMode = SK_MS_MODE_MASTER; + } else if (strcmp(Role_A[pAC->Index],"Slave")==0) { + MSMode = SK_MS_MODE_SLAVE; + } else { + printk("sk98lin: Illegal value \"%s\" for Role_A\n", + Role_A[pAC->Index]); + IsRoleDefined = SK_FALSE; + } + } else { + IsRoleDefined = SK_FALSE; + } + + if (IsRoleDefined == SK_TRUE) { + pAC->GIni.GP[0].PMSMode = MSMode; + } + + + + /* + ** Parse any parameter settings for port B: + ** a) any LinkSpeed stated? + */ + IsConTypeDefined = SK_TRUE; + IsLinkSpeedDefined = SK_TRUE; + IsFlowCtrlDefined = SK_TRUE; + IsModeDefined = SK_TRUE; + + if (Speed_B != NULL && pAC->Index<SK_MAX_CARD_PARAM && + Speed_B[pAC->Index] != NULL) { + if (strcmp(Speed_B[pAC->Index],"")==0) { + IsLinkSpeedDefined = SK_FALSE; + } else if (strcmp(Speed_B[pAC->Index],"Auto")==0) { + LinkSpeed = SK_LSPEED_AUTO; + } else if (strcmp(Speed_B[pAC->Index],"10")==0) { + LinkSpeed = SK_LSPEED_10MBPS; + } else if (strcmp(Speed_B[pAC->Index],"100")==0) { + LinkSpeed = SK_LSPEED_100MBPS; + } else if (strcmp(Speed_B[pAC->Index],"1000")==0) { + LinkSpeed = SK_LSPEED_1000MBPS; + } else { + printk("sk98lin: Illegal value \"%s\" for Speed_B\n", + Speed_B[pAC->Index]); + IsLinkSpeedDefined = SK_FALSE; + } + } else { + IsLinkSpeedDefined = SK_FALSE; + } + + /* + ** Check speed parameter: + ** Only copper type adapter and GE V2 cards + */ + if (((!pAC->ChipsetType) || (pAC->GIni.GICopperType != SK_TRUE)) && + ((LinkSpeed != SK_LSPEED_AUTO) && + (LinkSpeed != SK_LSPEED_1000MBPS))) { + printk("sk98lin: Illegal value for Speed_B. " + "Not a copper card or GE V2 card\n Using " + "speed 1000\n"); + LinkSpeed = SK_LSPEED_1000MBPS; + } + + /* + ** Decide whether to set new config value if somethig valid has + ** been received. + */ + if (IsLinkSpeedDefined) { + pAC->GIni.GP[1].PLinkSpeed = LinkSpeed; + } + + /* + ** b) Any Autonegotiation and DuplexCapabilities set? + ** Please note that both belong together... + */ + AutoNeg = AN_SENS; /* default: do auto Sense */ + AutoSet = SK_FALSE; + if (AutoNeg_B != NULL && pAC->Index<SK_MAX_CARD_PARAM && + AutoNeg_B[pAC->Index] != NULL) { + AutoSet = SK_TRUE; + if (strcmp(AutoNeg_B[pAC->Index],"")==0) { + AutoSet = SK_FALSE; + } else if (strcmp(AutoNeg_B[pAC->Index],"On")==0) { + AutoNeg = AN_ON; + } else if (strcmp(AutoNeg_B[pAC->Index],"Off")==0) { + AutoNeg = AN_OFF; + } else if (strcmp(AutoNeg_B[pAC->Index],"Sense")==0) { + AutoNeg = AN_SENS; + } else { + printk("sk98lin: Illegal value \"%s\" for AutoNeg_B\n", + AutoNeg_B[pAC->Index]); + } + } + + DuplexCap = DC_BOTH; + DupSet = SK_FALSE; + if (DupCap_B != NULL && pAC->Index<SK_MAX_CARD_PARAM && + DupCap_B[pAC->Index] != NULL) { + DupSet = SK_TRUE; + if (strcmp(DupCap_B[pAC->Index],"")==0) { + DupSet = SK_FALSE; + } else if (strcmp(DupCap_B[pAC->Index],"Both")==0) { + DuplexCap = DC_BOTH; + } else if (strcmp(DupCap_B[pAC->Index],"Full")==0) { + DuplexCap = DC_FULL; + } else if (strcmp(DupCap_B[pAC->Index],"Half")==0) { + DuplexCap = DC_HALF; + } else { + printk("sk98lin: Illegal value \"%s\" for DupCap_B\n", + DupCap_B[pAC->Index]); + } + } + + + /* + ** Check for illegal combinations + */ + if ((LinkSpeed == SK_LSPEED_1000MBPS) && + ((DuplexCap == SK_LMODE_STAT_AUTOHALF) || + (DuplexCap == SK_LMODE_STAT_HALF)) && + (pAC->ChipsetType)) { + printk("sk98lin: Half Duplex not possible with Gigabit speed!\n" + " Using Full Duplex.\n"); + DuplexCap = DC_FULL; + } + + if (AutoSet && AutoNeg==AN_SENS && DupSet) { + printk("sk98lin, Port B: DuplexCapabilities" + " ignored using Sense mode\n"); + } + + if (AutoSet && AutoNeg==AN_OFF && DupSet && DuplexCap==DC_BOTH){ + printk("sk98lin: Port B: Illegal combination" + " of values AutoNeg. and DuplexCap.\n Using " + "Full Duplex\n"); + DuplexCap = DC_FULL; + } + + if (AutoSet && AutoNeg==AN_OFF && !DupSet) { + DuplexCap = DC_FULL; + } + + if (!AutoSet && DupSet) { + printk("sk98lin: Port B: Duplex setting not" + " possible in\n default AutoNegotiation mode" + " (Sense).\n Using AutoNegotiation On\n"); + AutoNeg = AN_ON; + } + + /* + ** set the desired mode + */ + if (AutoSet || DupSet) { + pAC->GIni.GP[1].PLinkModeConf = Capabilities[AutoNeg][DuplexCap]; + } + + /* + ** c) Any FlowCtrl parameter set? + */ + if (FlowCtrl_B != NULL && pAC->Index<SK_MAX_CARD_PARAM && + FlowCtrl_B[pAC->Index] != NULL) { + if (strcmp(FlowCtrl_B[pAC->Index],"") == 0) { + IsFlowCtrlDefined = SK_FALSE; + } else if (strcmp(FlowCtrl_B[pAC->Index],"SymOrRem") == 0) { + FlowCtrl = SK_FLOW_MODE_SYM_OR_REM; + } else if (strcmp(FlowCtrl_B[pAC->Index],"Sym")==0) { + FlowCtrl = SK_FLOW_MODE_SYMMETRIC; + } else if (strcmp(FlowCtrl_B[pAC->Index],"LocSend")==0) { + FlowCtrl = SK_FLOW_MODE_LOC_SEND; + } else if (strcmp(FlowCtrl_B[pAC->Index],"None")==0) { + FlowCtrl = SK_FLOW_MODE_NONE; + } else { + printk("sk98lin: Illegal value \"%s\" for FlowCtrl_B\n", + FlowCtrl_B[pAC->Index]); + IsFlowCtrlDefined = SK_FALSE; + } + } else { + IsFlowCtrlDefined = SK_FALSE; + } + + if (IsFlowCtrlDefined) { + if ((AutoNeg == AN_OFF) && (FlowCtrl != SK_FLOW_MODE_NONE)) { + printk("sk98lin: Port B: FlowControl" + " impossible without AutoNegotiation," + " disabled\n"); + FlowCtrl = SK_FLOW_MODE_NONE; + } + pAC->GIni.GP[1].PFlowCtrlMode = FlowCtrl; + } + + /* + ** d) What is the RoleParameter? + */ + if (Role_B != NULL && pAC->Index<SK_MAX_CARD_PARAM && + Role_B[pAC->Index] != NULL) { + if (strcmp(Role_B[pAC->Index],"")==0) { + IsRoleDefined = SK_FALSE; + } else if (strcmp(Role_B[pAC->Index],"Auto")==0) { + MSMode = SK_MS_MODE_AUTO; + } else if (strcmp(Role_B[pAC->Index],"Master")==0) { + MSMode = SK_MS_MODE_MASTER; + } else if (strcmp(Role_B[pAC->Index],"Slave")==0) { + MSMode = SK_MS_MODE_SLAVE; + } else { + printk("sk98lin: Illegal value \"%s\" for Role_B\n", + Role_B[pAC->Index]); + IsRoleDefined = SK_FALSE; + } + } else { + IsRoleDefined = SK_FALSE; + } + + if (IsRoleDefined) { + pAC->GIni.GP[1].PMSMode = MSMode; + } + + /* + ** Evaluate settings for both ports + */ + pAC->ActivePort = 0; + if (PrefPort != NULL && pAC->Index<SK_MAX_CARD_PARAM && + PrefPort[pAC->Index] != NULL) { + if (strcmp(PrefPort[pAC->Index],"") == 0) { /* Auto */ + pAC->ActivePort = 0; + pAC->Rlmt.Net[0].Preference = -1; /* auto */ + pAC->Rlmt.Net[0].PrefPort = 0; + } else if (strcmp(PrefPort[pAC->Index],"A") == 0) { + /* + ** do not set ActivePort here, thus a port + ** switch is issued after net up. + */ + Port = 0; + pAC->Rlmt.Net[0].Preference = Port; + pAC->Rlmt.Net[0].PrefPort = Port; + } else if (strcmp(PrefPort[pAC->Index],"B") == 0) { + /* + ** do not set ActivePort here, thus a port + ** switch is issued after net up. + */ + if (pAC->GIni.GIMacsFound == 1) { + printk("sk98lin: Illegal value \"B\" for PrefPort.\n" + " Port B not available on single port adapters.\n"); + + pAC->ActivePort = 0; + pAC->Rlmt.Net[0].Preference = -1; /* auto */ + pAC->Rlmt.Net[0].PrefPort = 0; + } else { + Port = 1; + pAC->Rlmt.Net[0].Preference = Port; + pAC->Rlmt.Net[0].PrefPort = Port; + } + } else { + printk("sk98lin: Illegal value \"%s\" for PrefPort\n", + PrefPort[pAC->Index]); + } + } + + pAC->RlmtNets = 1; + + if (RlmtMode != NULL && pAC->Index<SK_MAX_CARD_PARAM && + RlmtMode[pAC->Index] != NULL) { + if (strcmp(RlmtMode[pAC->Index], "") == 0) { + pAC->RlmtMode = 0; + } else if (strcmp(RlmtMode[pAC->Index], "CheckLinkState") == 0) { + pAC->RlmtMode = SK_RLMT_CHECK_LINK; + } else if (strcmp(RlmtMode[pAC->Index], "CheckLocalPort") == 0) { + pAC->RlmtMode = SK_RLMT_CHECK_LINK | + SK_RLMT_CHECK_LOC_LINK; + } else if (strcmp(RlmtMode[pAC->Index], "CheckSeg") == 0) { + pAC->RlmtMode = SK_RLMT_CHECK_LINK | + SK_RLMT_CHECK_LOC_LINK | + SK_RLMT_CHECK_SEG; + } else if ((strcmp(RlmtMode[pAC->Index], "DualNet") == 0) && + (pAC->GIni.GIMacsFound == 2)) { + pAC->RlmtMode = SK_RLMT_CHECK_LINK; + pAC->RlmtNets = 2; + } else { + printk("sk98lin: Illegal value \"%s\" for" + " RlmtMode, using default\n", + RlmtMode[pAC->Index]); + pAC->RlmtMode = 0; + } + } else { + pAC->RlmtMode = 0; + } + + /* + ** Check the interrupt moderation parameters + */ + if (Moderation[pAC->Index] != NULL) { + if (strcmp(Moderation[pAC->Index], "") == 0) { + pAC->DynIrqModInfo.IntModTypeSelect = C_INT_MOD_NONE; + } else if (strcmp(Moderation[pAC->Index], "Static") == 0) { + pAC->DynIrqModInfo.IntModTypeSelect = C_INT_MOD_STATIC; + } else if (strcmp(Moderation[pAC->Index], "Dynamic") == 0) { + pAC->DynIrqModInfo.IntModTypeSelect = C_INT_MOD_DYNAMIC; + } else if (strcmp(Moderation[pAC->Index], "None") == 0) { + pAC->DynIrqModInfo.IntModTypeSelect = C_INT_MOD_NONE; + } else { + printk("sk98lin: Illegal value \"%s\" for Moderation.\n" + " Disable interrupt moderation.\n", + Moderation[pAC->Index]); + pAC->DynIrqModInfo.IntModTypeSelect = C_INT_MOD_NONE; + } + } else { + pAC->DynIrqModInfo.IntModTypeSelect = C_INT_MOD_NONE; + } + + if (Stats[pAC->Index] != NULL) { + if (strcmp(Stats[pAC->Index], "Yes") == 0) { + pAC->DynIrqModInfo.DisplayStats = SK_TRUE; + } else { + pAC->DynIrqModInfo.DisplayStats = SK_FALSE; + } + } else { + pAC->DynIrqModInfo.DisplayStats = SK_FALSE; + } + + if (ModerationMask[pAC->Index] != NULL) { + if (strcmp(ModerationMask[pAC->Index], "Rx") == 0) { + pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_ONLY; + } else if (strcmp(ModerationMask[pAC->Index], "Tx") == 0) { + pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_TX_ONLY; + } else if (strcmp(ModerationMask[pAC->Index], "Sp") == 0) { + pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_SP_ONLY; + } else if (strcmp(ModerationMask[pAC->Index], "RxSp") == 0) { + pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_SP_RX; + } else if (strcmp(ModerationMask[pAC->Index], "SpRx") == 0) { + pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_SP_RX; + } else if (strcmp(ModerationMask[pAC->Index], "RxTx") == 0) { + pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_TX_RX; + } else if (strcmp(ModerationMask[pAC->Index], "TxRx") == 0) { + pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_TX_RX; + } else if (strcmp(ModerationMask[pAC->Index], "TxSp") == 0) { + pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_SP_TX; + } else if (strcmp(ModerationMask[pAC->Index], "SpTx") == 0) { + pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_SP_TX; + } else if (strcmp(ModerationMask[pAC->Index], "RxTxSp") == 0) { + pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_TX_SP; + } else if (strcmp(ModerationMask[pAC->Index], "RxSpTx") == 0) { + pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_TX_SP; + } else if (strcmp(ModerationMask[pAC->Index], "TxRxSp") == 0) { + pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_TX_SP; + } else if (strcmp(ModerationMask[pAC->Index], "TxSpRx") == 0) { + pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_TX_SP; + } else if (strcmp(ModerationMask[pAC->Index], "SpTxRx") == 0) { + pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_TX_SP; + } else if (strcmp(ModerationMask[pAC->Index], "SpRxTx") == 0) { + pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_TX_SP; + } else { /* some rubbish */ + pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_ONLY; + } + } else { /* operator has stated nothing */ + pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_TX_RX; + } + + if (AutoSizing[pAC->Index] != NULL) { + if (strcmp(AutoSizing[pAC->Index], "On") == 0) { + pAC->DynIrqModInfo.AutoSizing = SK_FALSE; + } else { + pAC->DynIrqModInfo.AutoSizing = SK_FALSE; + } + } else { /* operator has stated nothing */ + pAC->DynIrqModInfo.AutoSizing = SK_FALSE; + } + + if (IntsPerSec[pAC->Index] != 0) { + if ((IntsPerSec[pAC->Index]< C_INT_MOD_IPS_LOWER_RANGE) || + (IntsPerSec[pAC->Index] > C_INT_MOD_IPS_UPPER_RANGE)) { + printk("sk98lin: Illegal value \"%d\" for IntsPerSec. (Range: %d - %d)\n" + " Using default value of %i.\n", + IntsPerSec[pAC->Index], + C_INT_MOD_IPS_LOWER_RANGE, + C_INT_MOD_IPS_UPPER_RANGE, + C_INTS_PER_SEC_DEFAULT); + pAC->DynIrqModInfo.MaxModIntsPerSec = C_INTS_PER_SEC_DEFAULT; + } else { + pAC->DynIrqModInfo.MaxModIntsPerSec = IntsPerSec[pAC->Index]; + } + } else { + pAC->DynIrqModInfo.MaxModIntsPerSec = C_INTS_PER_SEC_DEFAULT; + } + + /* + ** Evaluate upper and lower moderation threshold + */ + pAC->DynIrqModInfo.MaxModIntsPerSecUpperLimit = + pAC->DynIrqModInfo.MaxModIntsPerSec + + (pAC->DynIrqModInfo.MaxModIntsPerSec / 2); + + pAC->DynIrqModInfo.MaxModIntsPerSecLowerLimit = + pAC->DynIrqModInfo.MaxModIntsPerSec - + (pAC->DynIrqModInfo.MaxModIntsPerSec / 2); + + pAC->DynIrqModInfo.PrevTimeVal = jiffies; /* initial value */ + + +} /* GetConfiguration */ + + +/***************************************************************************** + * + * ProductStr - return a adapter identification string from vpd + * + * Description: + * This function reads the product name string from the vpd area + * and puts it the field pAC->DeviceString. + * + * Returns: N/A + */ +static inline int ProductStr( + SK_AC *pAC, /* pointer to adapter context */ + char *DeviceStr, /* result string */ + int StrLen /* length of the string */ +) +{ +char Keyword[] = VPD_NAME; /* vpd productname identifier */ +int ReturnCode; /* return code from vpd_read */ +unsigned long Flags; + + spin_lock_irqsave(&pAC->SlowPathLock, Flags); + ReturnCode = VpdRead(pAC, pAC->IoBase, Keyword, DeviceStr, &StrLen); + spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); + + return ReturnCode; +} /* ProductStr */ + +/***************************************************************************** + * + * StartDrvCleanupTimer - Start timer to check for descriptors which + * might be placed in descriptor ring, but + * havent been handled up to now + * + * Description: + * This function requests a HW-timer fo the Yukon card. The actions to + * perform when this timer expires, are located in the SkDrvEvent(). + * + * Returns: N/A + */ +static void +StartDrvCleanupTimer(SK_AC *pAC) { + SK_EVPARA EventParam; /* Event struct for timer event */ + + SK_MEMSET((char *) &EventParam, 0, sizeof(EventParam)); + EventParam.Para32[0] = SK_DRV_RX_CLEANUP_TIMER; + SkTimerStart(pAC, pAC->IoBase, &pAC->DrvCleanupTimer, + SK_DRV_RX_CLEANUP_TIMER_LENGTH, + SKGE_DRV, SK_DRV_TIMER, EventParam); +} + +/***************************************************************************** + * + * StopDrvCleanupTimer - Stop timer to check for descriptors + * + * Description: + * This function requests a HW-timer fo the Yukon card. The actions to + * perform when this timer expires, are located in the SkDrvEvent(). + * + * Returns: N/A + */ +static void +StopDrvCleanupTimer(SK_AC *pAC) { + SkTimerStop(pAC, pAC->IoBase, &pAC->DrvCleanupTimer); + SK_MEMSET((char *) &pAC->DrvCleanupTimer, 0, sizeof(SK_TIMER)); +} + +/****************************************************************************/ +/* functions for common modules *********************************************/ +/****************************************************************************/ + + +/***************************************************************************** + * + * SkDrvAllocRlmtMbuf - allocate an RLMT mbuf + * + * Description: + * This routine returns an RLMT mbuf or NULL. The RLMT Mbuf structure + * is embedded into a socket buff data area. + * + * Context: + * runtime + * + * Returns: + * NULL or pointer to Mbuf. + */ +SK_MBUF *SkDrvAllocRlmtMbuf( +SK_AC *pAC, /* pointer to adapter context */ +SK_IOC IoC, /* the IO-context */ +unsigned BufferSize) /* size of the requested buffer */ +{ +SK_MBUF *pRlmtMbuf; /* pointer to a new rlmt-mbuf structure */ +struct sk_buff *pMsgBlock; /* pointer to a new message block */ + + pMsgBlock = alloc_skb(BufferSize + sizeof(SK_MBUF), GFP_ATOMIC); + if (pMsgBlock == NULL) { + return (NULL); + } + pRlmtMbuf = (SK_MBUF*) pMsgBlock->data; + skb_reserve(pMsgBlock, sizeof(SK_MBUF)); + pRlmtMbuf->pNext = NULL; + pRlmtMbuf->pOs = pMsgBlock; + pRlmtMbuf->pData = pMsgBlock->data; /* Data buffer. */ + pRlmtMbuf->Size = BufferSize; /* Data buffer size. */ + pRlmtMbuf->Length = 0; /* Length of packet (<= Size). */ + return (pRlmtMbuf); + +} /* SkDrvAllocRlmtMbuf */ + + +/***************************************************************************** + * + * SkDrvFreeRlmtMbuf - free an RLMT mbuf + * + * Description: + * This routine frees one or more RLMT mbuf(s). + * + * Context: + * runtime + * + * Returns: + * Nothing + */ +void SkDrvFreeRlmtMbuf( +SK_AC *pAC, /* pointer to adapter context */ +SK_IOC IoC, /* the IO-context */ +SK_MBUF *pMbuf) /* size of the requested buffer */ +{ +SK_MBUF *pFreeMbuf; +SK_MBUF *pNextMbuf; + + pFreeMbuf = pMbuf; + do { + pNextMbuf = pFreeMbuf->pNext; + DEV_KFREE_SKB_ANY(pFreeMbuf->pOs); + pFreeMbuf = pNextMbuf; + } while ( pFreeMbuf != NULL ); +} /* SkDrvFreeRlmtMbuf */ + + +/***************************************************************************** + * + * SkOsGetTime - provide a time value + * + * Description: + * This routine provides a time value. The unit is 1/HZ (defined by Linux). + * It is not used for absolute time, but only for time differences. + * + * + * Returns: + * Time value + */ +SK_U64 SkOsGetTime(SK_AC *pAC) +{ + SK_U64 PrivateJiffies; + SkOsGetTimeCurrent(pAC, &PrivateJiffies); + return PrivateJiffies; +} /* SkOsGetTime */ + + +/***************************************************************************** + * + * SkPciReadCfgDWord - read a 32 bit value from pci config space + * + * Description: + * This routine reads a 32 bit value from the pci configuration + * space. + * + * Returns: + * 0 - indicate everything worked ok. + * != 0 - error indication + */ +int SkPciReadCfgDWord( +SK_AC *pAC, /* Adapter Control structure pointer */ +int PciAddr, /* PCI register address */ +SK_U32 *pVal) /* pointer to store the read value */ +{ + pci_read_config_dword(pAC->PciDev, PciAddr, pVal); + return(0); +} /* SkPciReadCfgDWord */ + + +/***************************************************************************** + * + * SkPciReadCfgWord - read a 16 bit value from pci config space + * + * Description: + * This routine reads a 16 bit value from the pci configuration + * space. + * + * Returns: + * 0 - indicate everything worked ok. + * != 0 - error indication + */ +int SkPciReadCfgWord( +SK_AC *pAC, /* Adapter Control structure pointer */ +int PciAddr, /* PCI register address */ +SK_U16 *pVal) /* pointer to store the read value */ +{ + pci_read_config_word(pAC->PciDev, PciAddr, pVal); + return(0); +} /* SkPciReadCfgWord */ + + +/***************************************************************************** + * + * SkPciReadCfgByte - read a 8 bit value from pci config space + * + * Description: + * This routine reads a 8 bit value from the pci configuration + * space. + * + * Returns: + * 0 - indicate everything worked ok. + * != 0 - error indication + */ +int SkPciReadCfgByte( +SK_AC *pAC, /* Adapter Control structure pointer */ +int PciAddr, /* PCI register address */ +SK_U8 *pVal) /* pointer to store the read value */ +{ + pci_read_config_byte(pAC->PciDev, PciAddr, pVal); + return(0); +} /* SkPciReadCfgByte */ + + +/***************************************************************************** + * + * SkPciWriteCfgWord - write a 16 bit value to pci config space + * + * Description: + * This routine writes a 16 bit value to the pci configuration + * space. The flag PciConfigUp indicates whether the config space + * is accesible or must be set up first. + * + * Returns: + * 0 - indicate everything worked ok. + * != 0 - error indication + */ +int SkPciWriteCfgWord( +SK_AC *pAC, /* Adapter Control structure pointer */ +int PciAddr, /* PCI register address */ +SK_U16 Val) /* pointer to store the read value */ +{ + pci_write_config_word(pAC->PciDev, PciAddr, Val); + return(0); +} /* SkPciWriteCfgWord */ + + +/***************************************************************************** + * + * SkPciWriteCfgWord - write a 8 bit value to pci config space + * + * Description: + * This routine writes a 8 bit value to the pci configuration + * space. The flag PciConfigUp indicates whether the config space + * is accesible or must be set up first. + * + * Returns: + * 0 - indicate everything worked ok. + * != 0 - error indication + */ +int SkPciWriteCfgByte( +SK_AC *pAC, /* Adapter Control structure pointer */ +int PciAddr, /* PCI register address */ +SK_U8 Val) /* pointer to store the read value */ +{ + pci_write_config_byte(pAC->PciDev, PciAddr, Val); + return(0); +} /* SkPciWriteCfgByte */ + + +/***************************************************************************** + * + * SkDrvEvent - handle driver events + * + * Description: + * This function handles events from all modules directed to the driver + * + * Context: + * Is called under protection of slow path lock. + * + * Returns: + * 0 if everything ok + * < 0 on error + * + */ +int SkDrvEvent( +SK_AC *pAC, /* pointer to adapter context */ +SK_IOC IoC, /* io-context */ +SK_U32 Event, /* event-id */ +SK_EVPARA Param) /* event-parameter */ +{ +SK_MBUF *pRlmtMbuf; /* pointer to a rlmt-mbuf structure */ +struct sk_buff *pMsg; /* pointer to a message block */ +int FromPort; /* the port from which we switch away */ +int ToPort; /* the port we switch to */ +SK_EVPARA NewPara; /* parameter for further events */ +int Stat; +unsigned long Flags; +SK_BOOL DualNet; + + switch (Event) { + case SK_DRV_ADAP_FAIL: + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT, + ("ADAPTER FAIL EVENT\n")); + printk("%s: Adapter failed.\n", pAC->dev[0]->name); + /* disable interrupts */ + SK_OUT32(pAC->IoBase, B0_IMSK, 0); + /* cgoos */ + break; + case SK_DRV_PORT_FAIL: + FromPort = Param.Para32[0]; + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT, + ("PORT FAIL EVENT, Port: %d\n", FromPort)); + if (FromPort == 0) { + printk("%s: Port A failed.\n", pAC->dev[0]->name); + } else { + printk("%s: Port B failed.\n", pAC->dev[1]->name); + } + /* cgoos */ + break; + case SK_DRV_PORT_RESET: /* SK_U32 PortIdx */ + /* action list 4 */ + FromPort = Param.Para32[0]; + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT, + ("PORT RESET EVENT, Port: %d ", FromPort)); + NewPara.Para64 = FromPort; + SkPnmiEvent(pAC, IoC, SK_PNMI_EVT_XMAC_RESET, NewPara); + spin_lock_irqsave( + &pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock, + Flags); + + SkGeStopPort(pAC, IoC, FromPort, SK_STOP_ALL, SK_HARD_RST); + netif_carrier_off(pAC->dev[Param.Para32[0]]); + spin_unlock_irqrestore( + &pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock, + Flags); + + /* clear rx ring from received frames */ + ReceiveIrq(pAC, &pAC->RxPort[FromPort], SK_FALSE); + + ClearTxRing(pAC, &pAC->TxPort[FromPort][TX_PRIO_LOW]); + spin_lock_irqsave( + &pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock, + Flags); + + /* tschilling: Handling of return value inserted. */ + if (SkGeInitPort(pAC, IoC, FromPort)) { + if (FromPort == 0) { + printk("%s: SkGeInitPort A failed.\n", pAC->dev[0]->name); + } else { + printk("%s: SkGeInitPort B failed.\n", pAC->dev[1]->name); + } + } + SkAddrMcUpdate(pAC,IoC, FromPort); + PortReInitBmu(pAC, FromPort); + SkGePollTxD(pAC, IoC, FromPort, SK_TRUE); + ClearAndStartRx(pAC, FromPort); + spin_unlock_irqrestore( + &pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock, + Flags); + break; + case SK_DRV_NET_UP: /* SK_U32 PortIdx */ + { struct net_device *dev = pAC->dev[Param.Para32[0]]; + /* action list 5 */ + FromPort = Param.Para32[0]; + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT, + ("NET UP EVENT, Port: %d ", Param.Para32[0])); + /* Mac update */ + SkAddrMcUpdate(pAC,IoC, FromPort); + + if (DoPrintInterfaceChange) { + printk("%s: network connection up using" + " port %c\n", pAC->dev[Param.Para32[0]]->name, 'A'+Param.Para32[0]); + + /* tschilling: Values changed according to LinkSpeedUsed. */ + Stat = pAC->GIni.GP[FromPort].PLinkSpeedUsed; + if (Stat == SK_LSPEED_STAT_10MBPS) { + printk(" speed: 10\n"); + } else if (Stat == SK_LSPEED_STAT_100MBPS) { + printk(" speed: 100\n"); + } else if (Stat == SK_LSPEED_STAT_1000MBPS) { + printk(" speed: 1000\n"); + } else { + printk(" speed: unknown\n"); + } + + + Stat = pAC->GIni.GP[FromPort].PLinkModeStatus; + if (Stat == SK_LMODE_STAT_AUTOHALF || + Stat == SK_LMODE_STAT_AUTOFULL) { + printk(" autonegotiation: yes\n"); + } + else { + printk(" autonegotiation: no\n"); + } + if (Stat == SK_LMODE_STAT_AUTOHALF || + Stat == SK_LMODE_STAT_HALF) { + printk(" duplex mode: half\n"); + } + else { + printk(" duplex mode: full\n"); + } + Stat = pAC->GIni.GP[FromPort].PFlowCtrlStatus; + if (Stat == SK_FLOW_STAT_REM_SEND ) { + printk(" flowctrl: remote send\n"); + } + else if (Stat == SK_FLOW_STAT_LOC_SEND ){ + printk(" flowctrl: local send\n"); + } + else if (Stat == SK_FLOW_STAT_SYMMETRIC ){ + printk(" flowctrl: symmetric\n"); + } + else { + printk(" flowctrl: none\n"); + } + + /* tschilling: Check against CopperType now. */ + if ((pAC->GIni.GICopperType == SK_TRUE) && + (pAC->GIni.GP[FromPort].PLinkSpeedUsed == + SK_LSPEED_STAT_1000MBPS)) { + Stat = pAC->GIni.GP[FromPort].PMSStatus; + if (Stat == SK_MS_STAT_MASTER ) { + printk(" role: master\n"); + } + else if (Stat == SK_MS_STAT_SLAVE ) { + printk(" role: slave\n"); + } + else { + printk(" role: ???\n"); + } + } + + /* + Display dim (dynamic interrupt moderation) + informations + */ + if (pAC->DynIrqModInfo.IntModTypeSelect == C_INT_MOD_STATIC) + printk(" irq moderation: static (%d ints/sec)\n", + pAC->DynIrqModInfo.MaxModIntsPerSec); + else if (pAC->DynIrqModInfo.IntModTypeSelect == C_INT_MOD_DYNAMIC) + printk(" irq moderation: dynamic (%d ints/sec)\n", + pAC->DynIrqModInfo.MaxModIntsPerSec); + else + printk(" irq moderation: disabled\n"); + + + printk(" scatter-gather: %s\n", + (dev->features & NETIF_F_SG) ? "enabled" : "disabled"); + printk(" tx-checksum: %s\n", + (dev->features & NETIF_F_IP_CSUM) ? "enabled" : "disabled"); + printk(" rx-checksum: %s\n", + pAC->RxPort[Param.Para32[0]].RxCsum ? "enabled" : "disabled"); + + } else { + DoPrintInterfaceChange = SK_TRUE; + } + + if ((Param.Para32[0] != pAC->ActivePort) && + (pAC->RlmtNets == 1)) { + NewPara.Para32[0] = pAC->ActivePort; + NewPara.Para32[1] = Param.Para32[0]; + SkEventQueue(pAC, SKGE_DRV, SK_DRV_SWITCH_INTERN, + NewPara); + } + + /* Inform the world that link protocol is up. */ + netif_carrier_on(dev); + break; + } + case SK_DRV_NET_DOWN: /* SK_U32 Reason */ + /* action list 7 */ + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT, + ("NET DOWN EVENT ")); + if (DoPrintInterfaceChange) { + printk("%s: network connection down\n", + pAC->dev[Param.Para32[1]]->name); + } else { + DoPrintInterfaceChange = SK_TRUE; + } + netif_carrier_off(pAC->dev[Param.Para32[1]]); + break; + case SK_DRV_SWITCH_HARD: /* SK_U32 FromPortIdx SK_U32 ToPortIdx */ + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT, + ("PORT SWITCH HARD ")); + case SK_DRV_SWITCH_SOFT: /* SK_U32 FromPortIdx SK_U32 ToPortIdx */ + /* action list 6 */ + printk("%s: switching to port %c\n", pAC->dev[0]->name, + 'A'+Param.Para32[1]); + case SK_DRV_SWITCH_INTERN: /* SK_U32 FromPortIdx SK_U32 ToPortIdx */ + FromPort = Param.Para32[0]; + ToPort = Param.Para32[1]; + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT, + ("PORT SWITCH EVENT, From: %d To: %d (Pref %d) ", + FromPort, ToPort, pAC->Rlmt.Net[0].PrefPort)); + NewPara.Para64 = FromPort; + SkPnmiEvent(pAC, IoC, SK_PNMI_EVT_XMAC_RESET, NewPara); + NewPara.Para64 = ToPort; + SkPnmiEvent(pAC, IoC, SK_PNMI_EVT_XMAC_RESET, NewPara); + spin_lock_irqsave( + &pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock, + Flags); + spin_lock(&pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock); + SkGeStopPort(pAC, IoC, FromPort, SK_STOP_ALL, SK_SOFT_RST); + SkGeStopPort(pAC, IoC, ToPort, SK_STOP_ALL, SK_SOFT_RST); + spin_unlock(&pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock); + spin_unlock_irqrestore( + &pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock, + Flags); + + ReceiveIrq(pAC, &pAC->RxPort[FromPort], SK_FALSE); /* clears rx ring */ + ReceiveIrq(pAC, &pAC->RxPort[ToPort], SK_FALSE); /* clears rx ring */ + + ClearTxRing(pAC, &pAC->TxPort[FromPort][TX_PRIO_LOW]); + ClearTxRing(pAC, &pAC->TxPort[ToPort][TX_PRIO_LOW]); + spin_lock_irqsave( + &pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock, + Flags); + spin_lock(&pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock); + pAC->ActivePort = ToPort; +#if 0 + SetQueueSizes(pAC); +#else + /* tschilling: New common function with minimum size check. */ + DualNet = SK_FALSE; + if (pAC->RlmtNets == 2) { + DualNet = SK_TRUE; + } + + if (SkGeInitAssignRamToQueues( + pAC, + pAC->ActivePort, + DualNet)) { + spin_unlock(&pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock); + spin_unlock_irqrestore( + &pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock, + Flags); + printk("SkGeInitAssignRamToQueues failed.\n"); + break; + } +#endif + /* tschilling: Handling of return values inserted. */ + if (SkGeInitPort(pAC, IoC, FromPort) || + SkGeInitPort(pAC, IoC, ToPort)) { + printk("%s: SkGeInitPort failed.\n", pAC->dev[0]->name); + } + if (Event == SK_DRV_SWITCH_SOFT) { + SkMacRxTxEnable(pAC, IoC, FromPort); + } + SkMacRxTxEnable(pAC, IoC, ToPort); + SkAddrSwap(pAC, IoC, FromPort, ToPort); + SkAddrMcUpdate(pAC, IoC, FromPort); + SkAddrMcUpdate(pAC, IoC, ToPort); + PortReInitBmu(pAC, FromPort); + PortReInitBmu(pAC, ToPort); + SkGePollTxD(pAC, IoC, FromPort, SK_TRUE); + SkGePollTxD(pAC, IoC, ToPort, SK_TRUE); + ClearAndStartRx(pAC, FromPort); + ClearAndStartRx(pAC, ToPort); + spin_unlock(&pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock); + spin_unlock_irqrestore( + &pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock, + Flags); + break; + case SK_DRV_RLMT_SEND: /* SK_MBUF *pMb */ + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT, + ("RLS ")); + pRlmtMbuf = (SK_MBUF*) Param.pParaPtr; + pMsg = (struct sk_buff*) pRlmtMbuf->pOs; + skb_put(pMsg, pRlmtMbuf->Length); + if (XmitFrame(pAC, &pAC->TxPort[pRlmtMbuf->PortIdx][TX_PRIO_LOW], + pMsg) < 0) + + DEV_KFREE_SKB_ANY(pMsg); + break; + case SK_DRV_TIMER: + if (Param.Para32[0] == SK_DRV_MODERATION_TIMER) { + /* + ** expiration of the moderation timer implies that + ** dynamic moderation is to be applied + */ + SkDimStartModerationTimer(pAC); + SkDimModerate(pAC); + if (pAC->DynIrqModInfo.DisplayStats) { + SkDimDisplayModerationSettings(pAC); + } + } else if (Param.Para32[0] == SK_DRV_RX_CLEANUP_TIMER) { + /* + ** check if we need to check for descriptors which + ** haven't been handled the last millisecs + */ + StartDrvCleanupTimer(pAC); + if (pAC->GIni.GIMacsFound == 2) { + ReceiveIrq(pAC, &pAC->RxPort[1], SK_FALSE); + } + ReceiveIrq(pAC, &pAC->RxPort[0], SK_FALSE); + } else { + printk("Expiration of unknown timer\n"); + } + break; + default: + break; + } + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT, + ("END EVENT ")); + + return (0); +} /* SkDrvEvent */ + + +/***************************************************************************** + * + * SkErrorLog - log errors + * + * Description: + * This function logs errors to the system buffer and to the console + * + * Returns: + * 0 if everything ok + * < 0 on error + * + */ +void SkErrorLog( +SK_AC *pAC, +int ErrClass, +int ErrNum, +char *pErrorMsg) +{ +char ClassStr[80]; + + switch (ErrClass) { + case SK_ERRCL_OTHER: + strcpy(ClassStr, "Other error"); + break; + case SK_ERRCL_CONFIG: + strcpy(ClassStr, "Configuration error"); + break; + case SK_ERRCL_INIT: + strcpy(ClassStr, "Initialization error"); + break; + case SK_ERRCL_NORES: + strcpy(ClassStr, "Out of resources error"); + break; + case SK_ERRCL_SW: + strcpy(ClassStr, "internal Software error"); + break; + case SK_ERRCL_HW: + strcpy(ClassStr, "Hardware failure"); + break; + case SK_ERRCL_COMM: + strcpy(ClassStr, "Communication error"); + break; + } + printk(KERN_INFO "%s: -- ERROR --\n Class: %s\n" + " Nr: 0x%x\n Msg: %s\n", pAC->dev[0]->name, + ClassStr, ErrNum, pErrorMsg); + +} /* SkErrorLog */ + +#ifdef SK_DIAG_SUPPORT + +/***************************************************************************** + * + * SkDrvEnterDiagMode - handles DIAG attach request + * + * Description: + * Notify the kernel to NOT access the card any longer due to DIAG + * Deinitialize the Card + * + * Returns: + * int + */ +int SkDrvEnterDiagMode( +SK_AC *pAc) /* pointer to adapter context */ +{ + DEV_NET *pNet = netdev_priv(pAc->dev[0]); + SK_AC *pAC = pNet->pAC; + + SK_MEMCPY(&(pAc->PnmiBackup), &(pAc->PnmiStruct), + sizeof(SK_PNMI_STRUCT_DATA)); + + pAC->DiagModeActive = DIAG_ACTIVE; + if (pAC->BoardLevel > SK_INIT_DATA) { + if (netif_running(pAC->dev[0])) { + pAC->WasIfUp[0] = SK_TRUE; + pAC->DiagFlowCtrl = SK_TRUE; /* for SkGeClose */ + DoPrintInterfaceChange = SK_FALSE; + SkDrvDeInitAdapter(pAC, 0); /* performs SkGeClose */ + } else { + pAC->WasIfUp[0] = SK_FALSE; + } + if (pNet != netdev_priv(pAC->dev[1])) { + pNet = netdev_priv(pAC->dev[1]); + if (netif_running(pAC->dev[1])) { + pAC->WasIfUp[1] = SK_TRUE; + pAC->DiagFlowCtrl = SK_TRUE; /* for SkGeClose */ + DoPrintInterfaceChange = SK_FALSE; + SkDrvDeInitAdapter(pAC, 1); /* do SkGeClose */ + } else { + pAC->WasIfUp[1] = SK_FALSE; + } + } + pAC->BoardLevel = SK_INIT_DATA; + } + return(0); +} + +/***************************************************************************** + * + * SkDrvLeaveDiagMode - handles DIAG detach request + * + * Description: + * Notify the kernel to may access the card again after use by DIAG + * Initialize the Card + * + * Returns: + * int + */ +int SkDrvLeaveDiagMode( +SK_AC *pAc) /* pointer to adapter control context */ +{ + SK_MEMCPY(&(pAc->PnmiStruct), &(pAc->PnmiBackup), + sizeof(SK_PNMI_STRUCT_DATA)); + pAc->DiagModeActive = DIAG_NOTACTIVE; + pAc->Pnmi.DiagAttached = SK_DIAG_IDLE; + if (pAc->WasIfUp[0] == SK_TRUE) { + pAc->DiagFlowCtrl = SK_TRUE; /* for SkGeClose */ + DoPrintInterfaceChange = SK_FALSE; + SkDrvInitAdapter(pAc, 0); /* first device */ + } + if (pAc->WasIfUp[1] == SK_TRUE) { + pAc->DiagFlowCtrl = SK_TRUE; /* for SkGeClose */ + DoPrintInterfaceChange = SK_FALSE; + SkDrvInitAdapter(pAc, 1); /* second device */ + } + return(0); +} + +/***************************************************************************** + * + * ParseDeviceNbrFromSlotName - Evaluate PCI device number + * + * Description: + * This function parses the PCI slot name information string and will + * retrieve the devcie number out of it. The slot_name maintianed by + * linux is in the form of '02:0a.0', whereas the first two characters + * represent the bus number in hex (in the sample above this is + * pci bus 0x02) and the next two characters the device number (0x0a). + * + * Returns: + * SK_U32: The device number from the PCI slot name + */ + +static SK_U32 ParseDeviceNbrFromSlotName( +const char *SlotName) /* pointer to pci slot name eg. '02:0a.0' */ +{ + char *CurrCharPos = (char *) SlotName; + int FirstNibble = -1; + int SecondNibble = -1; + SK_U32 Result = 0; + + while (*CurrCharPos != '\0') { + if (*CurrCharPos == ':') { + while (*CurrCharPos != '.') { + CurrCharPos++; + if ( (*CurrCharPos >= '0') && + (*CurrCharPos <= '9')) { + if (FirstNibble == -1) { + /* dec. value for '0' */ + FirstNibble = *CurrCharPos - 48; + } else { + SecondNibble = *CurrCharPos - 48; + } + } else if ( (*CurrCharPos >= 'a') && + (*CurrCharPos <= 'f') ) { + if (FirstNibble == -1) { + FirstNibble = *CurrCharPos - 87; + } else { + SecondNibble = *CurrCharPos - 87; + } + } else { + Result = 0; + } + } + + Result = FirstNibble; + Result = Result << 4; /* first nibble is higher one */ + Result = Result | SecondNibble; + } + CurrCharPos++; /* next character */ + } + return (Result); +} + +/**************************************************************************** + * + * SkDrvDeInitAdapter - deinitialize adapter (this function is only + * called if Diag attaches to that card) + * + * Description: + * Close initialized adapter. + * + * Returns: + * 0 - on success + * error code - on error + */ +static int SkDrvDeInitAdapter( +SK_AC *pAC, /* pointer to adapter context */ +int devNbr) /* what device is to be handled */ +{ + struct SK_NET_DEVICE *dev; + + dev = pAC->dev[devNbr]; + + /* On Linux 2.6 the network driver does NOT mess with reference + ** counts. The driver MUST be able to be unloaded at any time + ** due to the possibility of hotplug. + */ + if (SkGeClose(dev) != 0) { + return (-1); + } + return (0); + +} /* SkDrvDeInitAdapter() */ + +/**************************************************************************** + * + * SkDrvInitAdapter - Initialize adapter (this function is only + * called if Diag deattaches from that card) + * + * Description: + * Close initialized adapter. + * + * Returns: + * 0 - on success + * error code - on error + */ +static int SkDrvInitAdapter( +SK_AC *pAC, /* pointer to adapter context */ +int devNbr) /* what device is to be handled */ +{ + struct SK_NET_DEVICE *dev; + + dev = pAC->dev[devNbr]; + + if (SkGeOpen(dev) != 0) { + return (-1); + } + + /* + ** Use correct MTU size and indicate to kernel TX queue can be started + */ + if (SkGeChangeMtu(dev, dev->mtu) != 0) { + return (-1); + } + return (0); + +} /* SkDrvInitAdapter */ + +#endif + +#ifdef DEBUG +/****************************************************************************/ +/* "debug only" section *****************************************************/ +/****************************************************************************/ + + +/***************************************************************************** + * + * DumpMsg - print a frame + * + * Description: + * This function prints frames to the system logfile/to the console. + * + * Returns: N/A + * + */ +static void DumpMsg(struct sk_buff *skb, char *str) +{ + int msglen; + + if (skb == NULL) { + printk("DumpMsg(): NULL-Message\n"); + return; + } + + if (skb->data == NULL) { + printk("DumpMsg(): Message empty\n"); + return; + } + + msglen = skb->len; + if (msglen > 64) + msglen = 64; + + printk("--- Begin of message from %s , len %d (from %d) ----\n", str, msglen, skb->len); + + DumpData((char *)skb->data, msglen); + + printk("------- End of message ---------\n"); +} /* DumpMsg */ + + + +/***************************************************************************** + * + * DumpData - print a data area + * + * Description: + * This function prints a area of data to the system logfile/to the + * console. + * + * Returns: N/A + * + */ +static void DumpData(char *p, int size) +{ +register int i; +int haddr, addr; +char hex_buffer[180]; +char asc_buffer[180]; +char HEXCHAR[] = "0123456789ABCDEF"; + + addr = 0; + haddr = 0; + hex_buffer[0] = 0; + asc_buffer[0] = 0; + for (i=0; i < size; ) { + if (*p >= '0' && *p <='z') + asc_buffer[addr] = *p; + else + asc_buffer[addr] = '.'; + addr++; + asc_buffer[addr] = 0; + hex_buffer[haddr] = HEXCHAR[(*p & 0xf0) >> 4]; + haddr++; + hex_buffer[haddr] = HEXCHAR[*p & 0x0f]; + haddr++; + hex_buffer[haddr] = ' '; + haddr++; + hex_buffer[haddr] = 0; + p++; + i++; + if (i%16 == 0) { + printk("%s %s\n", hex_buffer, asc_buffer); + addr = 0; + haddr = 0; + } + } +} /* DumpData */ + + +/***************************************************************************** + * + * DumpLong - print a data area as long values + * + * Description: + * This function prints a area of data to the system logfile/to the + * console. + * + * Returns: N/A + * + */ +static void DumpLong(char *pc, int size) +{ +register int i; +int haddr, addr; +char hex_buffer[180]; +char asc_buffer[180]; +char HEXCHAR[] = "0123456789ABCDEF"; +long *p; +int l; + + addr = 0; + haddr = 0; + hex_buffer[0] = 0; + asc_buffer[0] = 0; + p = (long*) pc; + for (i=0; i < size; ) { + l = (long) *p; + hex_buffer[haddr] = HEXCHAR[(l >> 28) & 0xf]; + haddr++; + hex_buffer[haddr] = HEXCHAR[(l >> 24) & 0xf]; + haddr++; + hex_buffer[haddr] = HEXCHAR[(l >> 20) & 0xf]; + haddr++; + hex_buffer[haddr] = HEXCHAR[(l >> 16) & 0xf]; + haddr++; + hex_buffer[haddr] = HEXCHAR[(l >> 12) & 0xf]; + haddr++; + hex_buffer[haddr] = HEXCHAR[(l >> 8) & 0xf]; + haddr++; + hex_buffer[haddr] = HEXCHAR[(l >> 4) & 0xf]; + haddr++; + hex_buffer[haddr] = HEXCHAR[l & 0x0f]; + haddr++; + hex_buffer[haddr] = ' '; + haddr++; + hex_buffer[haddr] = 0; + p++; + i++; + if (i%8 == 0) { + printk("%4x %s\n", (i-8)*4, hex_buffer); + haddr = 0; + } + } + printk("------------------------\n"); +} /* DumpLong */ + +#endif + +static int __devinit skge_probe_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + SK_AC *pAC; + DEV_NET *pNet = NULL; + struct net_device *dev = NULL; + static int boards_found = 0; + int error = -ENODEV; + int using_dac = 0; + char DeviceStr[80]; + + if (pci_enable_device(pdev)) + goto out; + + /* Configure DMA attributes. */ + if (sizeof(dma_addr_t) > sizeof(u32) && + !(error = pci_set_dma_mask(pdev, DMA_64BIT_MASK))) { + using_dac = 1; + error = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK); + if (error < 0) { + printk(KERN_ERR "sk98lin %s unable to obtain 64 bit DMA " + "for consistent allocations\n", pci_name(pdev)); + goto out_disable_device; + } + } else { + error = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + if (error) { + printk(KERN_ERR "sk98lin %s no usable DMA configuration\n", + pci_name(pdev)); + goto out_disable_device; + } + } + + error = -ENOMEM; + dev = alloc_etherdev(sizeof(DEV_NET)); + if (!dev) { + printk(KERN_ERR "sk98lin: unable to allocate etherdev " + "structure!\n"); + goto out_disable_device; + } + + pNet = netdev_priv(dev); + pNet->pAC = kzalloc(sizeof(SK_AC), GFP_KERNEL); + if (!pNet->pAC) { + printk(KERN_ERR "sk98lin: unable to allocate adapter " + "structure!\n"); + goto out_free_netdev; + } + + pAC = pNet->pAC; + pAC->PciDev = pdev; + + pAC->dev[0] = dev; + pAC->dev[1] = dev; + pAC->CheckQueue = SK_FALSE; + + dev->irq = pdev->irq; + + error = SkGeInitPCI(pAC); + if (error) { + printk(KERN_ERR "sk98lin: PCI setup failed: %i\n", error); + goto out_free_netdev; + } + + SET_MODULE_OWNER(dev); + dev->open = &SkGeOpen; + dev->stop = &SkGeClose; + dev->hard_start_xmit = &SkGeXmit; + dev->get_stats = &SkGeStats; + dev->set_multicast_list = &SkGeSetRxMode; + dev->set_mac_address = &SkGeSetMacAddr; + dev->do_ioctl = &SkGeIoctl; + dev->change_mtu = &SkGeChangeMtu; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = &SkGePollController; +#endif + SET_NETDEV_DEV(dev, &pdev->dev); + SET_ETHTOOL_OPS(dev, &SkGeEthtoolOps); + + /* Use only if yukon hardware */ + if (pAC->ChipsetType) { +#ifdef USE_SK_TX_CHECKSUM + dev->features |= NETIF_F_IP_CSUM; +#endif +#ifdef SK_ZEROCOPY + dev->features |= NETIF_F_SG; +#endif +#ifdef USE_SK_RX_CHECKSUM + pAC->RxPort[0].RxCsum = 1; +#endif + } + + if (using_dac) + dev->features |= NETIF_F_HIGHDMA; + + pAC->Index = boards_found++; + + error = SkGeBoardInit(dev, pAC); + if (error) + goto out_free_netdev; + + /* Read Adapter name from VPD */ + if (ProductStr(pAC, DeviceStr, sizeof(DeviceStr)) != 0) { + error = -EIO; + printk(KERN_ERR "sk98lin: Could not read VPD data.\n"); + goto out_free_resources; + } + + /* Register net device */ + error = register_netdev(dev); + if (error) { + printk(KERN_ERR "sk98lin: Could not register device.\n"); + goto out_free_resources; + } + + /* Print adapter specific string from vpd */ + printk("%s: %s\n", dev->name, DeviceStr); + + /* Print configuration settings */ + printk(" PrefPort:%c RlmtMode:%s\n", + 'A' + pAC->Rlmt.Net[0].Port[pAC->Rlmt.Net[0].PrefPort]->PortNumber, + (pAC->RlmtMode==0) ? "Check Link State" : + ((pAC->RlmtMode==1) ? "Check Link State" : + ((pAC->RlmtMode==3) ? "Check Local Port" : + ((pAC->RlmtMode==7) ? "Check Segmentation" : + ((pAC->RlmtMode==17) ? "Dual Check Link State" :"Error"))))); + + SkGeYellowLED(pAC, pAC->IoBase, 1); + + memcpy(&dev->dev_addr, &pAC->Addr.Net[0].CurrentMacAddress, 6); + memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); + + pNet->PortNr = 0; + pNet->NetNr = 0; + + boards_found++; + + pci_set_drvdata(pdev, dev); + + /* More then one port found */ + if ((pAC->GIni.GIMacsFound == 2 ) && (pAC->RlmtNets == 2)) { + dev = alloc_etherdev(sizeof(DEV_NET)); + if (!dev) { + printk(KERN_ERR "sk98lin: unable to allocate etherdev " + "structure!\n"); + goto single_port; + } + + pNet = netdev_priv(dev); + pNet->PortNr = 1; + pNet->NetNr = 1; + pNet->pAC = pAC; + + dev->open = &SkGeOpen; + dev->stop = &SkGeClose; + dev->hard_start_xmit = &SkGeXmit; + dev->get_stats = &SkGeStats; + dev->set_multicast_list = &SkGeSetRxMode; + dev->set_mac_address = &SkGeSetMacAddr; + dev->do_ioctl = &SkGeIoctl; + dev->change_mtu = &SkGeChangeMtu; + SET_NETDEV_DEV(dev, &pdev->dev); + SET_ETHTOOL_OPS(dev, &SkGeEthtoolOps); + + if (pAC->ChipsetType) { +#ifdef USE_SK_TX_CHECKSUM + dev->features |= NETIF_F_IP_CSUM; +#endif +#ifdef SK_ZEROCOPY + dev->features |= NETIF_F_SG; +#endif +#ifdef USE_SK_RX_CHECKSUM + pAC->RxPort[1].RxCsum = 1; +#endif + } + + if (using_dac) + dev->features |= NETIF_F_HIGHDMA; + + error = register_netdev(dev); + if (error) { + printk(KERN_ERR "sk98lin: Could not register device" + " for second port. (%d)\n", error); + free_netdev(dev); + goto single_port; + } + + pAC->dev[1] = dev; + memcpy(&dev->dev_addr, + &pAC->Addr.Net[1].CurrentMacAddress, 6); + memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); + + printk("%s: %s\n", dev->name, DeviceStr); + printk(" PrefPort:B RlmtMode:Dual Check Link State\n"); + } + +single_port: + + /* Save the hardware revision */ + pAC->HWRevision = (((pAC->GIni.GIPciHwRev >> 4) & 0x0F)*10) + + (pAC->GIni.GIPciHwRev & 0x0F); + + /* Set driver globals */ + pAC->Pnmi.pDriverFileName = DRIVER_FILE_NAME; + pAC->Pnmi.pDriverReleaseDate = DRIVER_REL_DATE; + + memset(&pAC->PnmiBackup, 0, sizeof(SK_PNMI_STRUCT_DATA)); + memcpy(&pAC->PnmiBackup, &pAC->PnmiStruct, sizeof(SK_PNMI_STRUCT_DATA)); + + return 0; + + out_free_resources: + FreeResources(dev); + out_free_netdev: + free_netdev(dev); + out_disable_device: + pci_disable_device(pdev); + out: + return error; +} + +static void __devexit skge_remove_one(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + DEV_NET *pNet = netdev_priv(dev); + SK_AC *pAC = pNet->pAC; + struct net_device *otherdev = pAC->dev[1]; + + unregister_netdev(dev); + + SkGeYellowLED(pAC, pAC->IoBase, 0); + + if (pAC->BoardLevel == SK_INIT_RUN) { + SK_EVPARA EvPara; + unsigned long Flags; + + /* board is still alive */ + spin_lock_irqsave(&pAC->SlowPathLock, Flags); + EvPara.Para32[0] = 0; + EvPara.Para32[1] = -1; + SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara); + EvPara.Para32[0] = 1; + EvPara.Para32[1] = -1; + SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara); + SkEventDispatcher(pAC, pAC->IoBase); + /* disable interrupts */ + SK_OUT32(pAC->IoBase, B0_IMSK, 0); + SkGeDeInit(pAC, pAC->IoBase); + spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); + pAC->BoardLevel = SK_INIT_DATA; + /* We do NOT check here, if IRQ was pending, of course*/ + } + + if (pAC->BoardLevel == SK_INIT_IO) { + /* board is still alive */ + SkGeDeInit(pAC, pAC->IoBase); + pAC->BoardLevel = SK_INIT_DATA; + } + + FreeResources(dev); + free_netdev(dev); + if (otherdev != dev) + free_netdev(otherdev); + kfree(pAC); +} + +#ifdef CONFIG_PM +static int skge_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct net_device *dev = pci_get_drvdata(pdev); + DEV_NET *pNet = netdev_priv(dev); + SK_AC *pAC = pNet->pAC; + struct net_device *otherdev = pAC->dev[1]; + + if (netif_running(dev)) { + netif_carrier_off(dev); + DoPrintInterfaceChange = SK_FALSE; + SkDrvDeInitAdapter(pAC, 0); /* performs SkGeClose */ + netif_device_detach(dev); + } + if (otherdev != dev) { + if (netif_running(otherdev)) { + netif_carrier_off(otherdev); + DoPrintInterfaceChange = SK_FALSE; + SkDrvDeInitAdapter(pAC, 1); /* performs SkGeClose */ + netif_device_detach(otherdev); + } + } + + pci_save_state(pdev); + pci_enable_wake(pdev, pci_choose_state(pdev, state), 0); + if (pAC->AllocFlag & SK_ALLOC_IRQ) { + free_irq(dev->irq, dev); + } + pci_disable_device(pdev); + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + + return 0; +} + +static int skge_resume(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + DEV_NET *pNet = netdev_priv(dev); + SK_AC *pAC = pNet->pAC; + struct net_device *otherdev = pAC->dev[1]; + int ret; + + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + ret = pci_enable_device(pdev); + if (ret) { + printk(KERN_WARNING "sk98lin: unable to enable device %s " + "in resume\n", dev->name); + goto err_out; + } + pci_set_master(pdev); + if (pAC->GIni.GIMacsFound == 2) + ret = request_irq(dev->irq, SkGeIsr, IRQF_SHARED, "sk98lin", dev); + else + ret = request_irq(dev->irq, SkGeIsrOnePort, IRQF_SHARED, "sk98lin", dev); + if (ret) { + printk(KERN_WARNING "sk98lin: unable to acquire IRQ %d\n", dev->irq); + ret = -EBUSY; + goto err_out_disable_pdev; + } + + netif_device_attach(dev); + if (netif_running(dev)) { + DoPrintInterfaceChange = SK_FALSE; + SkDrvInitAdapter(pAC, 0); /* first device */ + } + if (otherdev != dev) { + netif_device_attach(otherdev); + if (netif_running(otherdev)) { + DoPrintInterfaceChange = SK_FALSE; + SkDrvInitAdapter(pAC, 1); /* second device */ + } + } + + return 0; + +err_out_disable_pdev: + pci_disable_device(pdev); +err_out: + pAC->AllocFlag &= ~SK_ALLOC_IRQ; + dev->irq = 0; + return ret; +} +#else +#define skge_suspend NULL +#define skge_resume NULL +#endif + +static struct pci_device_id skge_pci_tbl[] = { +#ifdef SK98LIN_ALL_DEVICES + { PCI_VENDOR_ID_3COM, 0x1700, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_3COM, 0x80eb, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, +#endif +#ifdef GENESIS + /* Generic SysKonnect SK-98xx Gigabit Ethernet Server Adapter */ + { PCI_VENDOR_ID_SYSKONNECT, 0x4300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, +#endif + /* Generic SysKonnect SK-98xx V2.0 Gigabit Ethernet Adapter */ + { PCI_VENDOR_ID_SYSKONNECT, 0x4320, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, +#ifdef SK98LIN_ALL_DEVICES +/* DLink card does not have valid VPD so this driver gags + * { PCI_VENDOR_ID_DLINK, 0x4c00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + */ + { PCI_VENDOR_ID_MARVELL, 0x4320, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_MARVELL, 0x5005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_CNET, 0x434e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_LINKSYS, 0x1032, PCI_ANY_ID, 0x0015, }, + { PCI_VENDOR_ID_LINKSYS, 0x1064, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, +#endif + { 0 } +}; + +MODULE_DEVICE_TABLE(pci, skge_pci_tbl); + +static struct pci_driver skge_driver = { + .name = "sk98lin", + .id_table = skge_pci_tbl, + .probe = skge_probe_one, + .remove = __devexit_p(skge_remove_one), + .suspend = skge_suspend, + .resume = skge_resume, +}; + +static int __init skge_init(void) +{ + printk(KERN_NOTICE "sk98lin: driver has been replaced by the skge driver" + " and is scheduled for removal\n"); + + return pci_register_driver(&skge_driver); +} + +static void __exit skge_exit(void) +{ + pci_unregister_driver(&skge_driver); +} + +module_init(skge_init); +module_exit(skge_exit); diff --git a/drivers/net/sk98lin/skgehwt.c b/drivers/net/sk98lin/skgehwt.c new file mode 100644 index 000000000000..db670993c2df --- /dev/null +++ b/drivers/net/sk98lin/skgehwt.c @@ -0,0 +1,171 @@ +/****************************************************************************** + * + * Name: skgehwt.c + * Project: Gigabit Ethernet Adapters, Event Scheduler Module + * Version: $Revision: 1.15 $ + * Date: $Date: 2003/09/16 13:41:23 $ + * Purpose: Hardware Timer + * + ******************************************************************************/ + +/****************************************************************************** + * + * (C)Copyright 1998-2002 SysKonnect GmbH. + * (C)Copyright 2002-2003 Marvell. + * + * 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. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/* + * Event queue and dispatcher + */ +#if (defined(DEBUG) || ((!defined(LINT)) && (!defined(SK_SLIM)))) +static const char SysKonnectFileId[] = + "@(#) $Id: skgehwt.c,v 1.15 2003/09/16 13:41:23 rschmidt Exp $ (C) Marvell."; +#endif + +#include "h/skdrv1st.h" /* Driver Specific Definitions */ +#include "h/skdrv2nd.h" /* Adapter Control- and Driver specific Def. */ + +#ifdef __C2MAN__ +/* + * Hardware Timer function queue management. + */ +intro() +{} +#endif + +/* + * Prototypes of local functions. + */ +#define SK_HWT_MAX (65000) + +/* correction factor */ +#define SK_HWT_FAC (1000 * (SK_U32)pAC->GIni.GIHstClkFact / 100) + +/* + * Initialize hardware timer. + * + * Must be called during init level 1. + */ +void SkHwtInit( +SK_AC *pAC, /* Adapters context */ +SK_IOC Ioc) /* IoContext */ +{ + pAC->Hwt.TStart = 0 ; + pAC->Hwt.TStop = 0 ; + pAC->Hwt.TActive = SK_FALSE; + + SkHwtStop(pAC, Ioc); +} + +/* + * + * Start hardware timer (clock ticks are 16us). + * + */ +void SkHwtStart( +SK_AC *pAC, /* Adapters context */ +SK_IOC Ioc, /* IoContext */ +SK_U32 Time) /* Time in units of 16us to load the timer with. */ +{ + SK_U32 Cnt; + + if (Time > SK_HWT_MAX) + Time = SK_HWT_MAX; + + pAC->Hwt.TStart = Time; + pAC->Hwt.TStop = 0L; + + Cnt = Time; + + /* + * if time < 16 us + * time = 16 us + */ + if (!Cnt) { + Cnt++; + } + + SK_OUT32(Ioc, B2_TI_INI, Cnt * SK_HWT_FAC); + + SK_OUT16(Ioc, B2_TI_CTRL, TIM_START); /* Start timer. */ + + pAC->Hwt.TActive = SK_TRUE; +} + +/* + * Stop hardware timer. + * and clear the timer IRQ + */ +void SkHwtStop( +SK_AC *pAC, /* Adapters context */ +SK_IOC Ioc) /* IoContext */ +{ + SK_OUT16(Ioc, B2_TI_CTRL, TIM_STOP); + + SK_OUT16(Ioc, B2_TI_CTRL, TIM_CLR_IRQ); + + pAC->Hwt.TActive = SK_FALSE; +} + + +/* + * Stop hardware timer and read time elapsed since last start. + * + * returns + * The elapsed time since last start in units of 16us. + * + */ +SK_U32 SkHwtRead( +SK_AC *pAC, /* Adapters context */ +SK_IOC Ioc) /* IoContext */ +{ + SK_U32 TRead; + SK_U32 IStatus; + + if (pAC->Hwt.TActive) { + + SkHwtStop(pAC, Ioc); + + SK_IN32(Ioc, B2_TI_VAL, &TRead); + TRead /= SK_HWT_FAC; + + SK_IN32(Ioc, B0_ISRC, &IStatus); + + /* Check if timer expired (or wraped around) */ + if ((TRead > pAC->Hwt.TStart) || (IStatus & IS_TIMINT)) { + + SkHwtStop(pAC, Ioc); + + pAC->Hwt.TStop = pAC->Hwt.TStart; + } + else { + + pAC->Hwt.TStop = pAC->Hwt.TStart - TRead; + } + } + return(pAC->Hwt.TStop); +} + +/* + * interrupt source= timer + */ +void SkHwtIsr( +SK_AC *pAC, /* Adapters context */ +SK_IOC Ioc) /* IoContext */ +{ + SkHwtStop(pAC, Ioc); + + pAC->Hwt.TStop = pAC->Hwt.TStart; + + SkTimerDone(pAC, Ioc); +} + +/* End of file */ diff --git a/drivers/net/sk98lin/skgeinit.c b/drivers/net/sk98lin/skgeinit.c new file mode 100644 index 000000000000..67f1d6a5c15d --- /dev/null +++ b/drivers/net/sk98lin/skgeinit.c @@ -0,0 +1,2005 @@ +/****************************************************************************** + * + * Name: skgeinit.c + * Project: Gigabit Ethernet Adapters, Common Modules + * Version: $Revision: 1.97 $ + * Date: $Date: 2003/10/02 16:45:31 $ + * Purpose: Contains functions to initialize the adapter + * + ******************************************************************************/ + +/****************************************************************************** + * + * (C)Copyright 1998-2002 SysKonnect. + * (C)Copyright 2002-2003 Marvell. + * + * 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. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +#include "h/skdrv1st.h" +#include "h/skdrv2nd.h" + +/* global variables ***********************************************************/ + +/* local variables ************************************************************/ + +#if (defined(DEBUG) || ((!defined(LINT)) && (!defined(SK_SLIM)))) +static const char SysKonnectFileId[] = + "@(#) $Id: skgeinit.c,v 1.97 2003/10/02 16:45:31 rschmidt Exp $ (C) Marvell."; +#endif + +struct s_QOffTab { + int RxQOff; /* Receive Queue Address Offset */ + int XsQOff; /* Sync Tx Queue Address Offset */ + int XaQOff; /* Async Tx Queue Address Offset */ +}; +static struct s_QOffTab QOffTab[] = { + {Q_R1, Q_XS1, Q_XA1}, {Q_R2, Q_XS2, Q_XA2} +}; + +struct s_Config { + char ScanString[8]; + SK_U32 Value; +}; + +static struct s_Config OemConfig = { + {'O','E','M','_','C','o','n','f'}, +#ifdef SK_OEM_CONFIG + OEM_CONFIG_VALUE, +#else + 0, +#endif +}; + +/****************************************************************************** + * + * SkGePollTxD() - Enable / Disable Descriptor Polling of TxD Rings + * + * Description: + * Enable or disable the descriptor polling of the transmit descriptor + * ring(s) (TxD) for port 'Port'. + * The new configuration is *not* saved over any SkGeStopPort() and + * SkGeInitPort() calls. + * + * Returns: + * nothing + */ +void SkGePollTxD( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port, /* Port Index (MAC_1 + n) */ +SK_BOOL PollTxD) /* SK_TRUE (enable pol.), SK_FALSE (disable pol.) */ +{ + SK_GEPORT *pPrt; + SK_U32 DWord; + + pPrt = &pAC->GIni.GP[Port]; + + DWord = (SK_U32)(PollTxD ? CSR_ENA_POL : CSR_DIS_POL); + + if (pPrt->PXSQSize != 0) { + SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff, Q_CSR), DWord); + } + + if (pPrt->PXAQSize != 0) { + SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff, Q_CSR), DWord); + } +} /* SkGePollTxD */ + + +/****************************************************************************** + * + * SkGeYellowLED() - Switch the yellow LED on or off. + * + * Description: + * Switch the yellow LED on or off. + * + * Note: + * This function may be called any time after SkGeInit(Level 1). + * + * Returns: + * nothing + */ +void SkGeYellowLED( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int State) /* yellow LED state, 0 = OFF, 0 != ON */ +{ + if (State == 0) { + /* Switch yellow LED OFF */ + SK_OUT8(IoC, B0_LED, LED_STAT_OFF); + } + else { + /* Switch yellow LED ON */ + SK_OUT8(IoC, B0_LED, LED_STAT_ON); + } +} /* SkGeYellowLED */ + + +#if (!defined(SK_SLIM) || defined(GENESIS)) +/****************************************************************************** + * + * SkGeXmitLED() - Modify the Operational Mode of a transmission LED. + * + * Description: + * The Rx or Tx LED which is specified by 'Led' will be + * enabled, disabled or switched on in test mode. + * + * Note: + * 'Led' must contain the address offset of the LEDs INI register. + * + * Usage: + * SkGeXmitLED(pAC, IoC, MR_ADDR(Port, TX_LED_INI), SK_LED_ENA); + * + * Returns: + * nothing + */ +void SkGeXmitLED( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Led, /* offset to the LED Init Value register */ +int Mode) /* Mode may be SK_LED_DIS, SK_LED_ENA, SK_LED_TST */ +{ + SK_U32 LedIni; + + switch (Mode) { + case SK_LED_ENA: + LedIni = SK_XMIT_DUR * (SK_U32)pAC->GIni.GIHstClkFact / 100; + SK_OUT32(IoC, Led + XMIT_LED_INI, LedIni); + SK_OUT8(IoC, Led + XMIT_LED_CTRL, LED_START); + break; + case SK_LED_TST: + SK_OUT8(IoC, Led + XMIT_LED_TST, LED_T_ON); + SK_OUT32(IoC, Led + XMIT_LED_CNT, 100); + SK_OUT8(IoC, Led + XMIT_LED_CTRL, LED_START); + break; + case SK_LED_DIS: + default: + /* + * Do NOT stop the LED Timer here. The LED might be + * in on state. But it needs to go off. + */ + SK_OUT32(IoC, Led + XMIT_LED_CNT, 0); + SK_OUT8(IoC, Led + XMIT_LED_TST, LED_T_OFF); + break; + } + + /* + * 1000BT: The Transmit LED is driven by the PHY. + * But the default LED configuration is used for + * Level One and Broadcom PHYs. + * (Broadcom: It may be that PHY_B_PEC_EN_LTR has to be set.) + * (In this case it has to be added here. But we will see. XXX) + */ +} /* SkGeXmitLED */ +#endif /* !SK_SLIM || GENESIS */ + + +/****************************************************************************** + * + * DoCalcAddr() - Calculates the start and the end address of a queue. + * + * Description: + * This function calculates the start and the end address of a queue. + * Afterwards the 'StartVal' is incremented to the next start position. + * If the port is already initialized the calculated values + * will be checked against the configured values and an + * error will be returned, if they are not equal. + * If the port is not initialized the values will be written to + * *StartAdr and *EndAddr. + * + * Returns: + * 0: success + * 1: configuration error + */ +static int DoCalcAddr( +SK_AC *pAC, /* adapter context */ +SK_GEPORT SK_FAR *pPrt, /* port index */ +int QuSize, /* size of the queue to configure in kB */ +SK_U32 SK_FAR *StartVal, /* start value for address calculation */ +SK_U32 SK_FAR *QuStartAddr,/* start addr to calculate */ +SK_U32 SK_FAR *QuEndAddr) /* end address to calculate */ +{ + SK_U32 EndVal; + SK_U32 NextStart; + int Rtv; + + Rtv = 0; + if (QuSize == 0) { + EndVal = *StartVal; + NextStart = EndVal; + } + else { + EndVal = *StartVal + ((SK_U32)QuSize * 1024) - 1; + NextStart = EndVal + 1; + } + + if (pPrt->PState >= SK_PRT_INIT) { + if (*StartVal != *QuStartAddr || EndVal != *QuEndAddr) { + Rtv = 1; + } + } + else { + *QuStartAddr = *StartVal; + *QuEndAddr = EndVal; + } + + *StartVal = NextStart; + return(Rtv); +} /* DoCalcAddr */ + +/****************************************************************************** + * + * SkGeInitAssignRamToQueues() - allocate default queue sizes + * + * Description: + * This function assigns the memory to the different queues and ports. + * When DualNet is set to SK_TRUE all ports get the same amount of memory. + * Otherwise the first port gets most of the memory and all the + * other ports just the required minimum. + * This function can only be called when pAC->GIni.GIRamSize and + * pAC->GIni.GIMacsFound have been initialized, usually this happens + * at init level 1 + * + * Returns: + * 0 - ok + * 1 - invalid input values + * 2 - not enough memory + */ + +int SkGeInitAssignRamToQueues( +SK_AC *pAC, /* Adapter context */ +int ActivePort, /* Active Port in RLMT mode */ +SK_BOOL DualNet) /* adapter context */ +{ + int i; + int UsedKilobytes; /* memory already assigned */ + int ActivePortKilobytes; /* memory available for active port */ + SK_GEPORT *pGePort; + + UsedKilobytes = 0; + + if (ActivePort >= pAC->GIni.GIMacsFound) { + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_INIT, + ("SkGeInitAssignRamToQueues: ActivePort (%d) invalid\n", + ActivePort)); + return(1); + } + if (((pAC->GIni.GIMacsFound * (SK_MIN_RXQ_SIZE + SK_MIN_TXQ_SIZE)) + + ((RAM_QUOTA_SYNC == 0) ? 0 : SK_MIN_TXQ_SIZE)) > pAC->GIni.GIRamSize) { + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_INIT, + ("SkGeInitAssignRamToQueues: Not enough memory (%d)\n", + pAC->GIni.GIRamSize)); + return(2); + } + + if (DualNet) { + /* every port gets the same amount of memory */ + ActivePortKilobytes = pAC->GIni.GIRamSize / pAC->GIni.GIMacsFound; + for (i = 0; i < pAC->GIni.GIMacsFound; i++) { + + pGePort = &pAC->GIni.GP[i]; + + /* take away the minimum memory for active queues */ + ActivePortKilobytes -= (SK_MIN_RXQ_SIZE + SK_MIN_TXQ_SIZE); + + /* receive queue gets the minimum + 80% of the rest */ + pGePort->PRxQSize = (int) (ROUND_QUEUE_SIZE_KB(( + ActivePortKilobytes * (unsigned long) RAM_QUOTA_RX) / 100)) + + SK_MIN_RXQ_SIZE; + + ActivePortKilobytes -= (pGePort->PRxQSize - SK_MIN_RXQ_SIZE); + + /* synchronous transmit queue */ + pGePort->PXSQSize = 0; + + /* asynchronous transmit queue */ + pGePort->PXAQSize = (int) ROUND_QUEUE_SIZE_KB(ActivePortKilobytes + + SK_MIN_TXQ_SIZE); + } + } + else { + /* Rlmt Mode or single link adapter */ + + /* Set standby queue size defaults for all standby ports */ + for (i = 0; i < pAC->GIni.GIMacsFound; i++) { + + if (i != ActivePort) { + pGePort = &pAC->GIni.GP[i]; + + pGePort->PRxQSize = SK_MIN_RXQ_SIZE; + pGePort->PXAQSize = SK_MIN_TXQ_SIZE; + pGePort->PXSQSize = 0; + + /* Count used RAM */ + UsedKilobytes += pGePort->PRxQSize + pGePort->PXAQSize; + } + } + /* what's left? */ + ActivePortKilobytes = pAC->GIni.GIRamSize - UsedKilobytes; + + /* assign it to the active port */ + /* first take away the minimum memory */ + ActivePortKilobytes -= (SK_MIN_RXQ_SIZE + SK_MIN_TXQ_SIZE); + pGePort = &pAC->GIni.GP[ActivePort]; + + /* receive queue get's the minimum + 80% of the rest */ + pGePort->PRxQSize = (int) (ROUND_QUEUE_SIZE_KB((ActivePortKilobytes * + (unsigned long) RAM_QUOTA_RX) / 100)) + SK_MIN_RXQ_SIZE; + + ActivePortKilobytes -= (pGePort->PRxQSize - SK_MIN_RXQ_SIZE); + + /* synchronous transmit queue */ + pGePort->PXSQSize = 0; + + /* asynchronous transmit queue */ + pGePort->PXAQSize = (int) ROUND_QUEUE_SIZE_KB(ActivePortKilobytes) + + SK_MIN_TXQ_SIZE; + } +#ifdef VCPU + VCPUprintf(0, "PRxQSize=%u, PXSQSize=%u, PXAQSize=%u\n", + pGePort->PRxQSize, pGePort->PXSQSize, pGePort->PXAQSize); +#endif /* VCPU */ + + return(0); +} /* SkGeInitAssignRamToQueues */ + +/****************************************************************************** + * + * SkGeCheckQSize() - Checks the Adapters Queue Size Configuration + * + * Description: + * This function verifies the Queue Size Configuration specified + * in the variables PRxQSize, PXSQSize, and PXAQSize of all + * used ports. + * This requirements must be fullfilled to have a valid configuration: + * - The size of all queues must not exceed GIRamSize. + * - The queue sizes must be specified in units of 8 kB. + * - The size of Rx queues of available ports must not be + * smaller than 16 kB. + * - The size of at least one Tx queue (synch. or asynch.) + * of available ports must not be smaller than 16 kB + * when Jumbo Frames are used. + * - The RAM start and end addresses must not be changed + * for ports which are already initialized. + * Furthermore SkGeCheckQSize() defines the Start and End Addresses + * of all ports and stores them into the HWAC port structure. + * + * Returns: + * 0: Queue Size Configuration valid + * 1: Queue Size Configuration invalid + */ +static int SkGeCheckQSize( +SK_AC *pAC, /* adapter context */ +int Port) /* port index */ +{ + SK_GEPORT *pPrt; + int i; + int Rtv; + int Rtv2; + SK_U32 StartAddr; +#ifndef SK_SLIM + int UsedMem; /* total memory used (max. found ports) */ +#endif + + Rtv = 0; + +#ifndef SK_SLIM + + UsedMem = 0; + for (i = 0; i < pAC->GIni.GIMacsFound; i++) { + pPrt = &pAC->GIni.GP[i]; + + if ((pPrt->PRxQSize & QZ_UNITS) != 0 || + (pPrt->PXSQSize & QZ_UNITS) != 0 || + (pPrt->PXAQSize & QZ_UNITS) != 0) { + + SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E012, SKERR_HWI_E012MSG); + return(1); + } + + if (i == Port && pPrt->PRxQSize < SK_MIN_RXQ_SIZE) { + SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E011, SKERR_HWI_E011MSG); + return(1); + } + + /* + * the size of at least one Tx queue (synch. or asynch.) has to be > 0. + * if Jumbo Frames are used, this size has to be >= 16 kB. + */ + if ((i == Port && pPrt->PXSQSize == 0 && pPrt->PXAQSize == 0) || + (pAC->GIni.GIPortUsage == SK_JUMBO_LINK && + ((pPrt->PXSQSize > 0 && pPrt->PXSQSize < SK_MIN_TXQ_SIZE) || + (pPrt->PXAQSize > 0 && pPrt->PXAQSize < SK_MIN_TXQ_SIZE)))) { + SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E023, SKERR_HWI_E023MSG); + return(1); + } + + UsedMem += pPrt->PRxQSize + pPrt->PXSQSize + pPrt->PXAQSize; + } + + if (UsedMem > pAC->GIni.GIRamSize) { + SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E012, SKERR_HWI_E012MSG); + return(1); + } +#endif /* !SK_SLIM */ + + /* Now start address calculation */ + StartAddr = pAC->GIni.GIRamOffs; + for (i = 0; i < pAC->GIni.GIMacsFound; i++) { + pPrt = &pAC->GIni.GP[i]; + + /* Calculate/Check values for the receive queue */ + Rtv2 = DoCalcAddr(pAC, pPrt, pPrt->PRxQSize, &StartAddr, + &pPrt->PRxQRamStart, &pPrt->PRxQRamEnd); + Rtv |= Rtv2; + + /* Calculate/Check values for the synchronous Tx queue */ + Rtv2 = DoCalcAddr(pAC, pPrt, pPrt->PXSQSize, &StartAddr, + &pPrt->PXsQRamStart, &pPrt->PXsQRamEnd); + Rtv |= Rtv2; + + /* Calculate/Check values for the asynchronous Tx queue */ + Rtv2 = DoCalcAddr(pAC, pPrt, pPrt->PXAQSize, &StartAddr, + &pPrt->PXaQRamStart, &pPrt->PXaQRamEnd); + Rtv |= Rtv2; + + if (Rtv) { + SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E013, SKERR_HWI_E013MSG); + return(1); + } + } + + return(0); +} /* SkGeCheckQSize */ + + +#ifdef GENESIS +/****************************************************************************** + * + * SkGeInitMacArb() - Initialize the MAC Arbiter + * + * Description: + * This function initializes the MAC Arbiter. + * It must not be called if there is still an + * initialized or active port. + * + * Returns: + * nothing + */ +static void SkGeInitMacArb( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC) /* IO context */ +{ + /* release local reset */ + SK_OUT16(IoC, B3_MA_TO_CTRL, MA_RST_CLR); + + /* configure timeout values */ + SK_OUT8(IoC, B3_MA_TOINI_RX1, SK_MAC_TO_53); + SK_OUT8(IoC, B3_MA_TOINI_RX2, SK_MAC_TO_53); + SK_OUT8(IoC, B3_MA_TOINI_TX1, SK_MAC_TO_53); + SK_OUT8(IoC, B3_MA_TOINI_TX2, SK_MAC_TO_53); + + SK_OUT8(IoC, B3_MA_RCINI_RX1, 0); + SK_OUT8(IoC, B3_MA_RCINI_RX2, 0); + SK_OUT8(IoC, B3_MA_RCINI_TX1, 0); + SK_OUT8(IoC, B3_MA_RCINI_TX2, 0); + + /* recovery values are needed for XMAC II Rev. B2 only */ + /* Fast Output Enable Mode was intended to use with Rev. B2, but now? */ + + /* + * There is no start or enable button to push, therefore + * the MAC arbiter is configured and enabled now. + */ +} /* SkGeInitMacArb */ + + +/****************************************************************************** + * + * SkGeInitPktArb() - Initialize the Packet Arbiter + * + * Description: + * This function initializes the Packet Arbiter. + * It must not be called if there is still an + * initialized or active port. + * + * Returns: + * nothing + */ +static void SkGeInitPktArb( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC) /* IO context */ +{ + /* release local reset */ + SK_OUT16(IoC, B3_PA_CTRL, PA_RST_CLR); + + /* configure timeout values */ + SK_OUT16(IoC, B3_PA_TOINI_RX1, SK_PKT_TO_MAX); + SK_OUT16(IoC, B3_PA_TOINI_RX2, SK_PKT_TO_MAX); + SK_OUT16(IoC, B3_PA_TOINI_TX1, SK_PKT_TO_MAX); + SK_OUT16(IoC, B3_PA_TOINI_TX2, SK_PKT_TO_MAX); + + /* + * enable timeout timers if jumbo frames not used + * NOTE: the packet arbiter timeout interrupt is needed for + * half duplex hangup workaround + */ + if (pAC->GIni.GIPortUsage != SK_JUMBO_LINK) { + if (pAC->GIni.GIMacsFound == 1) { + SK_OUT16(IoC, B3_PA_CTRL, PA_ENA_TO_TX1); + } + else { + SK_OUT16(IoC, B3_PA_CTRL, PA_ENA_TO_TX1 | PA_ENA_TO_TX2); + } + } +} /* SkGeInitPktArb */ +#endif /* GENESIS */ + + +/****************************************************************************** + * + * SkGeInitMacFifo() - Initialize the MAC FIFOs + * + * Description: + * Initialize all MAC FIFOs of the specified port + * + * Returns: + * nothing + */ +static void SkGeInitMacFifo( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port) /* Port Index (MAC_1 + n) */ +{ + SK_U16 Word; +#ifdef VCPU + SK_U32 DWord; +#endif /* VCPU */ + /* + * For each FIFO: + * - release local reset + * - use default value for MAC FIFO size + * - setup defaults for the control register + * - enable the FIFO + */ + +#ifdef GENESIS + if (pAC->GIni.GIGenesis) { + /* Configure Rx MAC FIFO */ + SK_OUT8(IoC, MR_ADDR(Port, RX_MFF_CTRL2), MFF_RST_CLR); + SK_OUT16(IoC, MR_ADDR(Port, RX_MFF_CTRL1), MFF_RX_CTRL_DEF); + SK_OUT8(IoC, MR_ADDR(Port, RX_MFF_CTRL2), MFF_ENA_OP_MD); + + /* Configure Tx MAC FIFO */ + SK_OUT8(IoC, MR_ADDR(Port, TX_MFF_CTRL2), MFF_RST_CLR); + SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), MFF_TX_CTRL_DEF); + SK_OUT8(IoC, MR_ADDR(Port, TX_MFF_CTRL2), MFF_ENA_OP_MD); + + /* Enable frame flushing if jumbo frames used */ + if (pAC->GIni.GIPortUsage == SK_JUMBO_LINK) { + SK_OUT16(IoC, MR_ADDR(Port, RX_MFF_CTRL1), MFF_ENA_FLUSH); + } + } +#endif /* GENESIS */ + +#ifdef YUKON + if (pAC->GIni.GIYukon) { + /* set Rx GMAC FIFO Flush Mask */ + SK_OUT16(IoC, MR_ADDR(Port, RX_GMF_FL_MSK), (SK_U16)RX_FF_FL_DEF_MSK); + + Word = (SK_U16)GMF_RX_CTRL_DEF; + + /* disable Rx GMAC FIFO Flush for YUKON-Lite Rev. A0 only */ + if (pAC->GIni.GIYukonLite && pAC->GIni.GIChipId == CHIP_ID_YUKON) { + + Word &= ~GMF_RX_F_FL_ON; + } + + /* Configure Rx MAC FIFO */ + SK_OUT8(IoC, MR_ADDR(Port, RX_GMF_CTRL_T), (SK_U8)GMF_RST_CLR); + SK_OUT16(IoC, MR_ADDR(Port, RX_GMF_CTRL_T), Word); + + /* set Rx GMAC FIFO Flush Threshold (default: 0x0a -> 56 bytes) */ + SK_OUT16(IoC, MR_ADDR(Port, RX_GMF_FL_THR), RX_GMF_FL_THR_DEF); + + /* Configure Tx MAC FIFO */ + SK_OUT8(IoC, MR_ADDR(Port, TX_GMF_CTRL_T), (SK_U8)GMF_RST_CLR); + SK_OUT16(IoC, MR_ADDR(Port, TX_GMF_CTRL_T), (SK_U16)GMF_TX_CTRL_DEF); + +#ifdef VCPU + SK_IN32(IoC, MR_ADDR(Port, RX_GMF_AF_THR), &DWord); + SK_IN32(IoC, MR_ADDR(Port, TX_GMF_AE_THR), &DWord); +#endif /* VCPU */ + + /* set Tx GMAC FIFO Almost Empty Threshold */ +/* SK_OUT32(IoC, MR_ADDR(Port, TX_GMF_AE_THR), 0); */ + } +#endif /* YUKON */ + +} /* SkGeInitMacFifo */ + +#ifdef SK_LNK_SYNC_CNT +/****************************************************************************** + * + * SkGeLoadLnkSyncCnt() - Load the Link Sync Counter and starts counting + * + * Description: + * This function starts the Link Sync Counter of the specified + * port and enables the generation of an Link Sync IRQ. + * The Link Sync Counter may be used to detect an active link, + * if autonegotiation is not used. + * + * Note: + * o To ensure receiving the Link Sync Event the LinkSyncCounter + * should be initialized BEFORE clearing the XMAC's reset! + * o Enable IS_LNK_SYNC_M1 and IS_LNK_SYNC_M2 after calling this + * function. + * + * Returns: + * nothing + */ +void SkGeLoadLnkSyncCnt( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port, /* Port Index (MAC_1 + n) */ +SK_U32 CntVal) /* Counter value */ +{ + SK_U32 OrgIMsk; + SK_U32 NewIMsk; + SK_U32 ISrc; + SK_BOOL IrqPend; + + /* stop counter */ + SK_OUT8(IoC, MR_ADDR(Port, LNK_SYNC_CTRL), LED_STOP); + + /* + * ASIC problem: + * Each time starting the Link Sync Counter an IRQ is generated + * by the adapter. See problem report entry from 21.07.98 + * + * Workaround: Disable Link Sync IRQ and clear the unexpeced IRQ + * if no IRQ is already pending. + */ + IrqPend = SK_FALSE; + SK_IN32(IoC, B0_ISRC, &ISrc); + SK_IN32(IoC, B0_IMSK, &OrgIMsk); + if (Port == MAC_1) { + NewIMsk = OrgIMsk & ~IS_LNK_SYNC_M1; + if ((ISrc & IS_LNK_SYNC_M1) != 0) { + IrqPend = SK_TRUE; + } + } + else { + NewIMsk = OrgIMsk & ~IS_LNK_SYNC_M2; + if ((ISrc & IS_LNK_SYNC_M2) != 0) { + IrqPend = SK_TRUE; + } + } + if (!IrqPend) { + SK_OUT32(IoC, B0_IMSK, NewIMsk); + } + + /* load counter */ + SK_OUT32(IoC, MR_ADDR(Port, LNK_SYNC_INI), CntVal); + + /* start counter */ + SK_OUT8(IoC, MR_ADDR(Port, LNK_SYNC_CTRL), LED_START); + + if (!IrqPend) { + /* clear the unexpected IRQ, and restore the interrupt mask */ + SK_OUT8(IoC, MR_ADDR(Port, LNK_SYNC_CTRL), LED_CLR_IRQ); + SK_OUT32(IoC, B0_IMSK, OrgIMsk); + } +} /* SkGeLoadLnkSyncCnt*/ +#endif /* SK_LNK_SYNC_CNT */ + +#if defined(SK_DIAG) || defined(SK_CFG_SYNC) +/****************************************************************************** + * + * SkGeCfgSync() - Configure synchronous bandwidth for this port. + * + * Description: + * This function may be used to configure synchronous bandwidth + * to the specified port. This may be done any time after + * initializing the port. The configuration values are NOT saved + * in the HWAC port structure and will be overwritten any + * time when stopping and starting the port. + * Any values for the synchronous configuration will be ignored + * if the size of the synchronous queue is zero! + * + * The default configuration for the synchronous service is + * TXA_ENA_FSYNC. This means if the size of + * the synchronous queue is unequal zero but no specific + * synchronous bandwidth is configured, the synchronous queue + * will always have the 'unlimited' transmit priority! + * + * This mode will be restored if the synchronous bandwidth is + * deallocated ('IntTime' = 0 and 'LimCount' = 0). + * + * Returns: + * 0: success + * 1: parameter configuration error + * 2: try to configure quality of service although no + * synchronous queue is configured + */ +int SkGeCfgSync( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port, /* Port Index (MAC_1 + n) */ +SK_U32 IntTime, /* Interval Timer Value in units of 8ns */ +SK_U32 LimCount, /* Number of bytes to transfer during IntTime */ +int SyncMode) /* Sync Mode: TXA_ENA_ALLOC | TXA_DIS_ALLOC | 0 */ +{ + int Rtv; + + Rtv = 0; + + /* check the parameters */ + if (LimCount > IntTime || + (LimCount == 0 && IntTime != 0) || + (LimCount != 0 && IntTime == 0)) { + + SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E010, SKERR_HWI_E010MSG); + return(1); + } + + if (pAC->GIni.GP[Port].PXSQSize == 0) { + SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E009, SKERR_HWI_E009MSG); + return(2); + } + + /* calculate register values */ + IntTime = (IntTime / 2) * pAC->GIni.GIHstClkFact / 100; + LimCount = LimCount / 8; + + if (IntTime > TXA_MAX_VAL || LimCount > TXA_MAX_VAL) { + SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E010, SKERR_HWI_E010MSG); + return(1); + } + + /* + * - Enable 'Force Sync' to ensure the synchronous queue + * has the priority while configuring the new values. + * - Also 'disable alloc' to ensure the settings complies + * to the SyncMode parameter. + * - Disable 'Rate Control' to configure the new values. + * - write IntTime and LimCount + * - start 'Rate Control' and disable 'Force Sync' + * if Interval Timer or Limit Counter not zero. + */ + SK_OUT8(IoC, MR_ADDR(Port, TXA_CTRL), + TXA_ENA_FSYNC | TXA_DIS_ALLOC | TXA_STOP_RC); + + SK_OUT32(IoC, MR_ADDR(Port, TXA_ITI_INI), IntTime); + SK_OUT32(IoC, MR_ADDR(Port, TXA_LIM_INI), LimCount); + + SK_OUT8(IoC, MR_ADDR(Port, TXA_CTRL), + (SK_U8)(SyncMode & (TXA_ENA_ALLOC | TXA_DIS_ALLOC))); + + if (IntTime != 0 || LimCount != 0) { + SK_OUT8(IoC, MR_ADDR(Port, TXA_CTRL), TXA_DIS_FSYNC | TXA_START_RC); + } + + return(0); +} /* SkGeCfgSync */ +#endif /* SK_DIAG || SK_CFG_SYNC*/ + + +/****************************************************************************** + * + * DoInitRamQueue() - Initialize the RAM Buffer Address of a single Queue + * + * Desccription: + * If the queue is used, enable and initialize it. + * Make sure the queue is still reset, if it is not used. + * + * Returns: + * nothing + */ +static void DoInitRamQueue( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int QuIoOffs, /* Queue IO Address Offset */ +SK_U32 QuStartAddr, /* Queue Start Address */ +SK_U32 QuEndAddr, /* Queue End Address */ +int QuType) /* Queue Type (SK_RX_SRAM_Q|SK_RX_BRAM_Q|SK_TX_RAM_Q) */ +{ + SK_U32 RxUpThresVal; + SK_U32 RxLoThresVal; + + if (QuStartAddr != QuEndAddr) { + /* calculate thresholds, assume we have a big Rx queue */ + RxUpThresVal = (QuEndAddr + 1 - QuStartAddr - SK_RB_ULPP) / 8; + RxLoThresVal = (QuEndAddr + 1 - QuStartAddr - SK_RB_LLPP_B)/8; + + /* build HW address format */ + QuStartAddr = QuStartAddr / 8; + QuEndAddr = QuEndAddr / 8; + + /* release local reset */ + SK_OUT8(IoC, RB_ADDR(QuIoOffs, RB_CTRL), RB_RST_CLR); + + /* configure addresses */ + SK_OUT32(IoC, RB_ADDR(QuIoOffs, RB_START), QuStartAddr); + SK_OUT32(IoC, RB_ADDR(QuIoOffs, RB_END), QuEndAddr); + SK_OUT32(IoC, RB_ADDR(QuIoOffs, RB_WP), QuStartAddr); + SK_OUT32(IoC, RB_ADDR(QuIoOffs, RB_RP), QuStartAddr); + + switch (QuType) { + case SK_RX_SRAM_Q: + /* configure threshold for small Rx Queue */ + RxLoThresVal += (SK_RB_LLPP_B - SK_RB_LLPP_S) / 8; + + /* continue with SK_RX_BRAM_Q */ + case SK_RX_BRAM_Q: + /* write threshold for Rx Queue */ + + SK_OUT32(IoC, RB_ADDR(QuIoOffs, RB_RX_UTPP), RxUpThresVal); + SK_OUT32(IoC, RB_ADDR(QuIoOffs, RB_RX_LTPP), RxLoThresVal); + + /* the high priority threshold not used */ + break; + case SK_TX_RAM_Q: + /* + * Do NOT use Store & Forward under normal operation due to + * performance optimization (GENESIS only). + * But if Jumbo Frames are configured (XMAC Tx FIFO is only 4 kB) + * or YUKON is used ((GMAC Tx FIFO is only 1 kB) + * we NEED Store & Forward of the RAM buffer. + */ + if (pAC->GIni.GIPortUsage == SK_JUMBO_LINK || + pAC->GIni.GIYukon) { + /* enable Store & Forward Mode for the Tx Side */ + SK_OUT8(IoC, RB_ADDR(QuIoOffs, RB_CTRL), RB_ENA_STFWD); + } + break; + } + + /* set queue operational */ + SK_OUT8(IoC, RB_ADDR(QuIoOffs, RB_CTRL), RB_ENA_OP_MD); + } + else { + /* ensure the queue is still disabled */ + SK_OUT8(IoC, RB_ADDR(QuIoOffs, RB_CTRL), RB_RST_SET); + } +} /* DoInitRamQueue */ + + +/****************************************************************************** + * + * SkGeInitRamBufs() - Initialize the RAM Buffer Queues + * + * Description: + * Initialize all RAM Buffer Queues of the specified port + * + * Returns: + * nothing + */ +static void SkGeInitRamBufs( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port) /* Port Index (MAC_1 + n) */ +{ + SK_GEPORT *pPrt; + int RxQType; + + pPrt = &pAC->GIni.GP[Port]; + + if (pPrt->PRxQSize == SK_MIN_RXQ_SIZE) { + RxQType = SK_RX_SRAM_Q; /* small Rx Queue */ + } + else { + RxQType = SK_RX_BRAM_Q; /* big Rx Queue */ + } + + DoInitRamQueue(pAC, IoC, pPrt->PRxQOff, pPrt->PRxQRamStart, + pPrt->PRxQRamEnd, RxQType); + + DoInitRamQueue(pAC, IoC, pPrt->PXsQOff, pPrt->PXsQRamStart, + pPrt->PXsQRamEnd, SK_TX_RAM_Q); + + DoInitRamQueue(pAC, IoC, pPrt->PXaQOff, pPrt->PXaQRamStart, + pPrt->PXaQRamEnd, SK_TX_RAM_Q); + +} /* SkGeInitRamBufs */ + + +/****************************************************************************** + * + * SkGeInitRamIface() - Initialize the RAM Interface + * + * Description: + * This function initializes the Adapters RAM Interface. + * + * Note: + * This function is used in the diagnostics. + * + * Returns: + * nothing + */ +static void SkGeInitRamIface( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC) /* IO context */ +{ + /* release local reset */ + SK_OUT16(IoC, B3_RI_CTRL, RI_RST_CLR); + + /* configure timeout values */ + SK_OUT8(IoC, B3_RI_WTO_R1, SK_RI_TO_53); + SK_OUT8(IoC, B3_RI_WTO_XA1, SK_RI_TO_53); + SK_OUT8(IoC, B3_RI_WTO_XS1, SK_RI_TO_53); + SK_OUT8(IoC, B3_RI_RTO_R1, SK_RI_TO_53); + SK_OUT8(IoC, B3_RI_RTO_XA1, SK_RI_TO_53); + SK_OUT8(IoC, B3_RI_RTO_XS1, SK_RI_TO_53); + SK_OUT8(IoC, B3_RI_WTO_R2, SK_RI_TO_53); + SK_OUT8(IoC, B3_RI_WTO_XA2, SK_RI_TO_53); + SK_OUT8(IoC, B3_RI_WTO_XS2, SK_RI_TO_53); + SK_OUT8(IoC, B3_RI_RTO_R2, SK_RI_TO_53); + SK_OUT8(IoC, B3_RI_RTO_XA2, SK_RI_TO_53); + SK_OUT8(IoC, B3_RI_RTO_XS2, SK_RI_TO_53); + +} /* SkGeInitRamIface */ + + +/****************************************************************************** + * + * SkGeInitBmu() - Initialize the BMU state machines + * + * Description: + * Initialize all BMU state machines of the specified port + * + * Returns: + * nothing + */ +static void SkGeInitBmu( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port) /* Port Index (MAC_1 + n) */ +{ + SK_GEPORT *pPrt; + SK_U32 RxWm; + SK_U32 TxWm; + + pPrt = &pAC->GIni.GP[Port]; + + RxWm = SK_BMU_RX_WM; + TxWm = SK_BMU_TX_WM; + + if (!pAC->GIni.GIPciSlot64 && !pAC->GIni.GIPciClock66) { + /* for better performance */ + RxWm /= 2; + TxWm /= 2; + } + + /* Rx Queue: Release all local resets and set the watermark */ + SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff, Q_CSR), CSR_CLR_RESET); + SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff, Q_F), RxWm); + + /* + * Tx Queue: Release all local resets if the queue is used ! + * set watermark + */ + if (pPrt->PXSQSize != 0) { + SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff, Q_CSR), CSR_CLR_RESET); + SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff, Q_F), TxWm); + } + + if (pPrt->PXAQSize != 0) { + SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff, Q_CSR), CSR_CLR_RESET); + SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff, Q_F), TxWm); + } + /* + * Do NOT enable the descriptor poll timers here, because + * the descriptor addresses are not specified yet. + */ +} /* SkGeInitBmu */ + + +/****************************************************************************** + * + * TestStopBit() - Test the stop bit of the queue + * + * Description: + * Stopping a queue is not as simple as it seems to be. + * If descriptor polling is enabled, it may happen + * that RX/TX stop is done and SV idle is NOT set. + * In this case we have to issue another stop command. + * + * Returns: + * The queues control status register + */ +static SK_U32 TestStopBit( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* IO Context */ +int QuIoOffs) /* Queue IO Address Offset */ +{ + SK_U32 QuCsr; /* CSR contents */ + + SK_IN32(IoC, Q_ADDR(QuIoOffs, Q_CSR), &QuCsr); + + if ((QuCsr & (CSR_STOP | CSR_SV_IDLE)) == 0) { + /* Stop Descriptor overridden by start command */ + SK_OUT32(IoC, Q_ADDR(QuIoOffs, Q_CSR), CSR_STOP); + + SK_IN32(IoC, Q_ADDR(QuIoOffs, Q_CSR), &QuCsr); + } + + return(QuCsr); +} /* TestStopBit */ + + +/****************************************************************************** + * + * SkGeStopPort() - Stop the Rx/Tx activity of the port 'Port'. + * + * Description: + * After calling this function the descriptor rings and Rx and Tx + * queues of this port may be reconfigured. + * + * It is possible to stop the receive and transmit path separate or + * both together. + * + * Dir = SK_STOP_TX Stops the transmit path only and resets the MAC. + * The receive queue is still active and + * the pending Rx frames may be still transferred + * into the RxD. + * SK_STOP_RX Stop the receive path. The tansmit path + * has to be stopped once before. + * SK_STOP_ALL SK_STOP_TX + SK_STOP_RX + * + * RstMode = SK_SOFT_RST Resets the MAC. The PHY is still alive. + * SK_HARD_RST Resets the MAC and the PHY. + * + * Example: + * 1) A Link Down event was signaled for a port. Therefore the activity + * of this port should be stopped and a hardware reset should be issued + * to enable the workaround of XMAC Errata #2. But the received frames + * should not be discarded. + * ... + * SkGeStopPort(pAC, IoC, Port, SK_STOP_TX, SK_HARD_RST); + * (transfer all pending Rx frames) + * SkGeStopPort(pAC, IoC, Port, SK_STOP_RX, SK_HARD_RST); + * ... + * + * 2) An event was issued which request the driver to switch + * the 'virtual active' link to an other already active port + * as soon as possible. The frames in the receive queue of this + * port may be lost. But the PHY must not be reset during this + * event. + * ... + * SkGeStopPort(pAC, IoC, Port, SK_STOP_ALL, SK_SOFT_RST); + * ... + * + * Extended Description: + * If SK_STOP_TX is set, + * o disable the MAC's receive and transmitter to prevent + * from sending incomplete frames + * o stop the port's transmit queues before terminating the + * BMUs to prevent from performing incomplete PCI cycles + * on the PCI bus + * - The network Rx and Tx activity and PCI Tx transfer is + * disabled now. + * o reset the MAC depending on the RstMode + * o Stop Interval Timer and Limit Counter of Tx Arbiter, + * also disable Force Sync bit and Enable Alloc bit. + * o perform a local reset of the port's Tx path + * - reset the PCI FIFO of the async Tx queue + * - reset the PCI FIFO of the sync Tx queue + * - reset the RAM Buffer async Tx queue + * - reset the RAM Buffer sync Tx queue + * - reset the MAC Tx FIFO + * o switch Link and Tx LED off, stop the LED counters + * + * If SK_STOP_RX is set, + * o stop the port's receive queue + * - The path data transfer activity is fully stopped now. + * o perform a local reset of the port's Rx path + * - reset the PCI FIFO of the Rx queue + * - reset the RAM Buffer receive queue + * - reset the MAC Rx FIFO + * o switch Rx LED off, stop the LED counter + * + * If all ports are stopped, + * o reset the RAM Interface. + * + * Notes: + * o This function may be called during the driver states RESET_PORT and + * SWITCH_PORT. + */ +void SkGeStopPort( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* I/O context */ +int Port, /* port to stop (MAC_1 + n) */ +int Dir, /* Direction to Stop (SK_STOP_RX, SK_STOP_TX, SK_STOP_ALL) */ +int RstMode)/* Reset Mode (SK_SOFT_RST, SK_HARD_RST) */ +{ +#ifndef SK_DIAG + SK_EVPARA Para; +#endif /* !SK_DIAG */ + SK_GEPORT *pPrt; + SK_U32 DWord; + SK_U32 XsCsr; + SK_U32 XaCsr; + SK_U64 ToutStart; + int i; + int ToutCnt; + + pPrt = &pAC->GIni.GP[Port]; + + if ((Dir & SK_STOP_TX) != 0) { + /* disable receiver and transmitter */ + SkMacRxTxDisable(pAC, IoC, Port); + + /* stop both transmit queues */ + /* + * If the BMU is in the reset state CSR_STOP will terminate + * immediately. + */ + SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff, Q_CSR), CSR_STOP); + SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff, Q_CSR), CSR_STOP); + + ToutStart = SkOsGetTime(pAC); + ToutCnt = 0; + do { + /* + * Clear packet arbiter timeout to make sure + * this loop will terminate. + */ + SK_OUT16(IoC, B3_PA_CTRL, (SK_U16)((Port == MAC_1) ? + PA_CLR_TO_TX1 : PA_CLR_TO_TX2)); + + /* + * If the transfer stucks at the MAC the STOP command will not + * terminate if we don't flush the XMAC's transmit FIFO ! + */ + SkMacFlushTxFifo(pAC, IoC, Port); + + XsCsr = TestStopBit(pAC, IoC, pPrt->PXsQOff); + XaCsr = TestStopBit(pAC, IoC, pPrt->PXaQOff); + + if (SkOsGetTime(pAC) - ToutStart > (SK_TICKS_PER_SEC / 18)) { + /* + * Timeout of 1/18 second reached. + * This needs to be checked at 1/18 sec only. + */ + ToutCnt++; + if (ToutCnt > 1) { + /* Might be a problem when the driver event handler + * calls StopPort again. XXX. + */ + + /* Fatal Error, Loop aborted */ + SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_HWI_E018, + SKERR_HWI_E018MSG); +#ifndef SK_DIAG + Para.Para64 = Port; + SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para); +#endif /* !SK_DIAG */ + return; + } + /* + * Cache incoherency workaround: Assume a start command + * has been lost while sending the frame. + */ + ToutStart = SkOsGetTime(pAC); + + if ((XsCsr & CSR_STOP) != 0) { + SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff, Q_CSR), CSR_START); + } + if ((XaCsr & CSR_STOP) != 0) { + SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff, Q_CSR), CSR_START); + } + } + + /* + * Because of the ASIC problem report entry from 21.08.1998 it is + * required to wait until CSR_STOP is reset and CSR_SV_IDLE is set. + */ + } while ((XsCsr & (CSR_STOP | CSR_SV_IDLE)) != CSR_SV_IDLE || + (XaCsr & (CSR_STOP | CSR_SV_IDLE)) != CSR_SV_IDLE); + + /* Reset the MAC depending on the RstMode */ + if (RstMode == SK_SOFT_RST) { + SkMacSoftRst(pAC, IoC, Port); + } + else { + SkMacHardRst(pAC, IoC, Port); + } + + /* Disable Force Sync bit and Enable Alloc bit */ + SK_OUT8(IoC, MR_ADDR(Port, TXA_CTRL), + TXA_DIS_FSYNC | TXA_DIS_ALLOC | TXA_STOP_RC); + + /* Stop Interval Timer and Limit Counter of Tx Arbiter */ + SK_OUT32(IoC, MR_ADDR(Port, TXA_ITI_INI), 0L); + SK_OUT32(IoC, MR_ADDR(Port, TXA_LIM_INI), 0L); + + /* Perform a local reset of the port's Tx path */ + + /* Reset the PCI FIFO of the async Tx queue */ + SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff, Q_CSR), CSR_SET_RESET); + /* Reset the PCI FIFO of the sync Tx queue */ + SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff, Q_CSR), CSR_SET_RESET); + /* Reset the RAM Buffer async Tx queue */ + SK_OUT8(IoC, RB_ADDR(pPrt->PXaQOff, RB_CTRL), RB_RST_SET); + /* Reset the RAM Buffer sync Tx queue */ + SK_OUT8(IoC, RB_ADDR(pPrt->PXsQOff, RB_CTRL), RB_RST_SET); + + /* Reset Tx MAC FIFO */ +#ifdef GENESIS + if (pAC->GIni.GIGenesis) { + /* Note: MFF_RST_SET does NOT reset the XMAC ! */ + SK_OUT8(IoC, MR_ADDR(Port, TX_MFF_CTRL2), MFF_RST_SET); + + /* switch Link and Tx LED off, stop the LED counters */ + /* Link LED is switched off by the RLMT and the Diag itself */ + SkGeXmitLED(pAC, IoC, MR_ADDR(Port, TX_LED_INI), SK_LED_DIS); + } +#endif /* GENESIS */ + +#ifdef YUKON + if (pAC->GIni.GIYukon) { + /* Reset TX MAC FIFO */ + SK_OUT8(IoC, MR_ADDR(Port, TX_GMF_CTRL_T), (SK_U8)GMF_RST_SET); + } +#endif /* YUKON */ + } + + if ((Dir & SK_STOP_RX) != 0) { + /* + * The RX Stop Command will not terminate if no buffers + * are queued in the RxD ring. But it will always reach + * the Idle state. Therefore we can use this feature to + * stop the transfer of received packets. + */ + /* stop the port's receive queue */ + SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff, Q_CSR), CSR_STOP); + + i = 100; + do { + /* + * Clear packet arbiter timeout to make sure + * this loop will terminate + */ + SK_OUT16(IoC, B3_PA_CTRL, (SK_U16)((Port == MAC_1) ? + PA_CLR_TO_RX1 : PA_CLR_TO_RX2)); + + DWord = TestStopBit(pAC, IoC, pPrt->PRxQOff); + + /* timeout if i==0 (bug fix for #10748) */ + if (--i == 0) { + SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_HWI_E024, + SKERR_HWI_E024MSG); + break; + } + /* + * because of the ASIC problem report entry from 21.08.98 + * it is required to wait until CSR_STOP is reset and + * CSR_SV_IDLE is set. + */ + } while ((DWord & (CSR_STOP | CSR_SV_IDLE)) != CSR_SV_IDLE); + + /* The path data transfer activity is fully stopped now */ + + /* Perform a local reset of the port's Rx path */ + + /* Reset the PCI FIFO of the Rx queue */ + SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff, Q_CSR), CSR_SET_RESET); + /* Reset the RAM Buffer receive queue */ + SK_OUT8(IoC, RB_ADDR(pPrt->PRxQOff, RB_CTRL), RB_RST_SET); + + /* Reset Rx MAC FIFO */ +#ifdef GENESIS + if (pAC->GIni.GIGenesis) { + + SK_OUT8(IoC, MR_ADDR(Port, RX_MFF_CTRL2), MFF_RST_SET); + + /* switch Rx LED off, stop the LED counter */ + SkGeXmitLED(pAC, IoC, MR_ADDR(Port, RX_LED_INI), SK_LED_DIS); + } +#endif /* GENESIS */ + +#ifdef YUKON + if (pAC->GIni.GIYukon) { + /* Reset Rx MAC FIFO */ + SK_OUT8(IoC, MR_ADDR(Port, RX_GMF_CTRL_T), (SK_U8)GMF_RST_SET); + } +#endif /* YUKON */ + } +} /* SkGeStopPort */ + + +/****************************************************************************** + * + * SkGeInit0() - Level 0 Initialization + * + * Description: + * - Initialize the BMU address offsets + * + * Returns: + * nothing + */ +static void SkGeInit0( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC) /* IO context */ +{ + int i; + SK_GEPORT *pPrt; + + for (i = 0; i < SK_MAX_MACS; i++) { + pPrt = &pAC->GIni.GP[i]; + + pPrt->PState = SK_PRT_RESET; + pPrt->PRxQOff = QOffTab[i].RxQOff; + pPrt->PXsQOff = QOffTab[i].XsQOff; + pPrt->PXaQOff = QOffTab[i].XaQOff; + pPrt->PCheckPar = SK_FALSE; + pPrt->PIsave = 0; + pPrt->PPrevShorts = 0; + pPrt->PLinkResCt = 0; + pPrt->PAutoNegTOCt = 0; + pPrt->PPrevRx = 0; + pPrt->PPrevFcs = 0; + pPrt->PRxLim = SK_DEF_RX_WA_LIM; + pPrt->PLinkMode = (SK_U8)SK_LMODE_AUTOFULL; + pPrt->PLinkSpeedCap = (SK_U8)SK_LSPEED_CAP_1000MBPS; + pPrt->PLinkSpeed = (SK_U8)SK_LSPEED_1000MBPS; + pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_UNKNOWN; + pPrt->PLinkModeConf = (SK_U8)SK_LMODE_AUTOSENSE; + pPrt->PFlowCtrlMode = (SK_U8)SK_FLOW_MODE_SYM_OR_REM; + pPrt->PLinkCap = (SK_U8)(SK_LMODE_CAP_HALF | SK_LMODE_CAP_FULL | + SK_LMODE_CAP_AUTOHALF | SK_LMODE_CAP_AUTOFULL); + pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_UNKNOWN; + pPrt->PFlowCtrlCap = (SK_U8)SK_FLOW_MODE_SYM_OR_REM; + pPrt->PFlowCtrlStatus = (SK_U8)SK_FLOW_STAT_NONE; + pPrt->PMSCap = 0; + pPrt->PMSMode = (SK_U8)SK_MS_MODE_AUTO; + pPrt->PMSStatus = (SK_U8)SK_MS_STAT_UNSET; + pPrt->PLipaAutoNeg = (SK_U8)SK_LIPA_UNKNOWN; + pPrt->PAutoNegFail = SK_FALSE; + pPrt->PHWLinkUp = SK_FALSE; + pPrt->PLinkBroken = SK_TRUE; /* See WA code */ + pPrt->PPhyPowerState = PHY_PM_OPERATIONAL_MODE; + pPrt->PMacColThres = TX_COL_DEF; + pPrt->PMacJamLen = TX_JAM_LEN_DEF; + pPrt->PMacJamIpgVal = TX_JAM_IPG_DEF; + pPrt->PMacJamIpgData = TX_IPG_JAM_DEF; + pPrt->PMacIpgData = IPG_DATA_DEF; + pPrt->PMacLimit4 = SK_FALSE; + } + + pAC->GIni.GIPortUsage = SK_RED_LINK; + pAC->GIni.GILedBlinkCtrl = (SK_U16)OemConfig.Value; + pAC->GIni.GIValIrqMask = IS_ALL_MSK; + +} /* SkGeInit0*/ + + +/****************************************************************************** + * + * SkGeInit1() - Level 1 Initialization + * + * Description: + * o Do a software reset. + * o Clear all reset bits. + * o Verify that the detected hardware is present. + * Return an error if not. + * o Get the hardware configuration + * + Read the number of MACs/Ports. + * + Read the RAM size. + * + Read the PCI Revision Id. + * + Find out the adapters host clock speed + * + Read and check the PHY type + * + * Returns: + * 0: success + * 5: Unexpected PHY type detected + * 6: HW self test failed + */ +static int SkGeInit1( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC) /* IO context */ +{ + SK_U8 Byte; + SK_U16 Word; + SK_U16 CtrlStat; + SK_U32 DWord; + int RetVal; + int i; + + RetVal = 0; + + /* save CLK_RUN bits (YUKON-Lite) */ + SK_IN16(IoC, B0_CTST, &CtrlStat); + + /* do the SW-reset */ + SK_OUT8(IoC, B0_CTST, CS_RST_SET); + + /* release the SW-reset */ + SK_OUT8(IoC, B0_CTST, CS_RST_CLR); + + /* reset all error bits in the PCI STATUS register */ + /* + * Note: PCI Cfg cycles cannot be used, because they are not + * available on some platforms after 'boot time'. + */ + SK_IN16(IoC, PCI_C(PCI_STATUS), &Word); + + SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_ON); + SK_OUT16(IoC, PCI_C(PCI_STATUS), (SK_U16)(Word | PCI_ERRBITS)); + SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_OFF); + + /* release Master Reset */ + SK_OUT8(IoC, B0_CTST, CS_MRST_CLR); + +#ifdef CLK_RUN + CtrlStat |= CS_CLK_RUN_ENA; +#endif /* CLK_RUN */ + + /* restore CLK_RUN bits */ + SK_OUT16(IoC, B0_CTST, (SK_U16)(CtrlStat & + (CS_CLK_RUN_HOT | CS_CLK_RUN_RST | CS_CLK_RUN_ENA))); + + /* read Chip Identification Number */ + SK_IN8(IoC, B2_CHIP_ID, &Byte); + pAC->GIni.GIChipId = Byte; + + /* read number of MACs */ + SK_IN8(IoC, B2_MAC_CFG, &Byte); + pAC->GIni.GIMacsFound = (Byte & CFG_SNG_MAC) ? 1 : 2; + + /* get Chip Revision Number */ + pAC->GIni.GIChipRev = (SK_U8)((Byte & CFG_CHIP_R_MSK) >> 4); + + /* get diff. PCI parameters */ + SK_IN16(IoC, B0_CTST, &CtrlStat); + + /* read the adapters RAM size */ + SK_IN8(IoC, B2_E_0, &Byte); + + pAC->GIni.GIGenesis = SK_FALSE; + pAC->GIni.GIYukon = SK_FALSE; + pAC->GIni.GIYukonLite = SK_FALSE; + +#ifdef GENESIS + if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) { + + pAC->GIni.GIGenesis = SK_TRUE; + + if (Byte == (SK_U8)3) { + /* special case: 4 x 64k x 36, offset = 0x80000 */ + pAC->GIni.GIRamSize = 1024; + pAC->GIni.GIRamOffs = (SK_U32)512 * 1024; + } + else { + pAC->GIni.GIRamSize = (int)Byte * 512; + pAC->GIni.GIRamOffs = 0; + } + /* all GE adapters work with 53.125 MHz host clock */ + pAC->GIni.GIHstClkFact = SK_FACT_53; + + /* set Descr. Poll Timer Init Value to 250 ms */ + pAC->GIni.GIPollTimerVal = + SK_DPOLL_DEF * (SK_U32)pAC->GIni.GIHstClkFact / 100; + } +#endif /* GENESIS */ + +#ifdef YUKON + if (pAC->GIni.GIChipId != CHIP_ID_GENESIS) { + + pAC->GIni.GIYukon = SK_TRUE; + + pAC->GIni.GIRamSize = (Byte == (SK_U8)0) ? 128 : (int)Byte * 4; + + pAC->GIni.GIRamOffs = 0; + + /* WA for chip Rev. A */ + pAC->GIni.GIWolOffs = (pAC->GIni.GIChipId == CHIP_ID_YUKON && + pAC->GIni.GIChipRev == 0) ? WOL_REG_OFFS : 0; + + /* get PM Capabilities of PCI config space */ + SK_IN16(IoC, PCI_C(PCI_PM_CAP_REG), &Word); + + /* check if VAUX is available */ + if (((CtrlStat & CS_VAUX_AVAIL) != 0) && + /* check also if PME from D3cold is set */ + ((Word & PCI_PME_D3C_SUP) != 0)) { + /* set entry in GE init struct */ + pAC->GIni.GIVauxAvail = SK_TRUE; + } + + if (pAC->GIni.GIChipId == CHIP_ID_YUKON_LITE) { + /* this is Rev. A1 */ + pAC->GIni.GIYukonLite = SK_TRUE; + } + else { + /* save Flash-Address Register */ + SK_IN32(IoC, B2_FAR, &DWord); + + /* test Flash-Address Register */ + SK_OUT8(IoC, B2_FAR + 3, 0xff); + SK_IN8(IoC, B2_FAR + 3, &Byte); + + if (Byte != 0) { + /* this is Rev. A0 */ + pAC->GIni.GIYukonLite = SK_TRUE; + + /* restore Flash-Address Register */ + SK_OUT32(IoC, B2_FAR, DWord); + } + } + + /* switch power to VCC (WA for VAUX problem) */ + SK_OUT8(IoC, B0_POWER_CTRL, (SK_U8)(PC_VAUX_ENA | PC_VCC_ENA | + PC_VAUX_OFF | PC_VCC_ON)); + + /* read the Interrupt source */ + SK_IN32(IoC, B0_ISRC, &DWord); + + if ((DWord & IS_HW_ERR) != 0) { + /* read the HW Error Interrupt source */ + SK_IN32(IoC, B0_HWE_ISRC, &DWord); + + if ((DWord & IS_IRQ_SENSOR) != 0) { + /* disable HW Error IRQ */ + pAC->GIni.GIValIrqMask &= ~IS_HW_ERR; + } + } + + for (i = 0; i < pAC->GIni.GIMacsFound; i++) { + /* set GMAC Link Control reset */ + SK_OUT16(IoC, MR_ADDR(i, GMAC_LINK_CTRL), GMLC_RST_SET); + + /* clear GMAC Link Control reset */ + SK_OUT16(IoC, MR_ADDR(i, GMAC_LINK_CTRL), GMLC_RST_CLR); + } + /* all YU chips work with 78.125 MHz host clock */ + pAC->GIni.GIHstClkFact = SK_FACT_78; + + pAC->GIni.GIPollTimerVal = SK_DPOLL_MAX; /* 215 ms */ + } +#endif /* YUKON */ + + /* check if 64-bit PCI Slot is present */ + pAC->GIni.GIPciSlot64 = (SK_BOOL)((CtrlStat & CS_BUS_SLOT_SZ) != 0); + + /* check if 66 MHz PCI Clock is active */ + pAC->GIni.GIPciClock66 = (SK_BOOL)((CtrlStat & CS_BUS_CLOCK) != 0); + + /* read PCI HW Revision Id. */ + SK_IN8(IoC, PCI_C(PCI_REV_ID), &Byte); + pAC->GIni.GIPciHwRev = Byte; + + /* read the PMD type */ + SK_IN8(IoC, B2_PMD_TYP, &Byte); + pAC->GIni.GICopperType = (SK_U8)(Byte == 'T'); + + /* read the PHY type */ + SK_IN8(IoC, B2_E_1, &Byte); + + Byte &= 0x0f; /* the PHY type is stored in the lower nibble */ + for (i = 0; i < pAC->GIni.GIMacsFound; i++) { + +#ifdef GENESIS + if (pAC->GIni.GIGenesis) { + switch (Byte) { + case SK_PHY_XMAC: + pAC->GIni.GP[i].PhyAddr = PHY_ADDR_XMAC; + break; + case SK_PHY_BCOM: + pAC->GIni.GP[i].PhyAddr = PHY_ADDR_BCOM; + pAC->GIni.GP[i].PMSCap = (SK_U8)(SK_MS_CAP_AUTO | + SK_MS_CAP_MASTER | SK_MS_CAP_SLAVE); + break; +#ifdef OTHER_PHY + case SK_PHY_LONE: + pAC->GIni.GP[i].PhyAddr = PHY_ADDR_LONE; + break; + case SK_PHY_NAT: + pAC->GIni.GP[i].PhyAddr = PHY_ADDR_NAT; + break; +#endif /* OTHER_PHY */ + default: + /* ERROR: unexpected PHY type detected */ + RetVal = 5; + break; + } + } +#endif /* GENESIS */ + +#ifdef YUKON + if (pAC->GIni.GIYukon) { + + if (Byte < (SK_U8)SK_PHY_MARV_COPPER) { + /* if this field is not initialized */ + Byte = (SK_U8)SK_PHY_MARV_COPPER; + + pAC->GIni.GICopperType = SK_TRUE; + } + + pAC->GIni.GP[i].PhyAddr = PHY_ADDR_MARV; + + if (pAC->GIni.GICopperType) { + + pAC->GIni.GP[i].PLinkSpeedCap = (SK_U8)(SK_LSPEED_CAP_AUTO | + SK_LSPEED_CAP_10MBPS | SK_LSPEED_CAP_100MBPS | + SK_LSPEED_CAP_1000MBPS); + + pAC->GIni.GP[i].PLinkSpeed = (SK_U8)SK_LSPEED_AUTO; + + pAC->GIni.GP[i].PMSCap = (SK_U8)(SK_MS_CAP_AUTO | + SK_MS_CAP_MASTER | SK_MS_CAP_SLAVE); + } + else { + Byte = (SK_U8)SK_PHY_MARV_FIBER; + } + } +#endif /* YUKON */ + + pAC->GIni.GP[i].PhyType = (int)Byte; + + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_INIT, + ("PHY type: %d PHY addr: %04x\n", Byte, + pAC->GIni.GP[i].PhyAddr)); + } + + /* get MAC Type & set function pointers dependent on */ +#ifdef GENESIS + if (pAC->GIni.GIGenesis) { + + pAC->GIni.GIMacType = SK_MAC_XMAC; + + pAC->GIni.GIFunc.pFnMacUpdateStats = SkXmUpdateStats; + pAC->GIni.GIFunc.pFnMacStatistic = SkXmMacStatistic; + pAC->GIni.GIFunc.pFnMacResetCounter = SkXmResetCounter; + pAC->GIni.GIFunc.pFnMacOverflow = SkXmOverflowStatus; + } +#endif /* GENESIS */ + +#ifdef YUKON + if (pAC->GIni.GIYukon) { + + pAC->GIni.GIMacType = SK_MAC_GMAC; + + pAC->GIni.GIFunc.pFnMacUpdateStats = SkGmUpdateStats; + pAC->GIni.GIFunc.pFnMacStatistic = SkGmMacStatistic; + pAC->GIni.GIFunc.pFnMacResetCounter = SkGmResetCounter; + pAC->GIni.GIFunc.pFnMacOverflow = SkGmOverflowStatus; + +#ifdef SPECIAL_HANDLING + if (pAC->GIni.GIChipId == CHIP_ID_YUKON) { + /* check HW self test result */ + SK_IN8(IoC, B2_E_3, &Byte); + if (Byte & B2_E3_RES_MASK) { + RetVal = 6; + } + } +#endif + } +#endif /* YUKON */ + + return(RetVal); +} /* SkGeInit1 */ + + +/****************************************************************************** + * + * SkGeInit2() - Level 2 Initialization + * + * Description: + * - start the Blink Source Counter + * - start the Descriptor Poll Timer + * - configure the MAC-Arbiter + * - configure the Packet-Arbiter + * - enable the Tx Arbiters + * - enable the RAM Interface Arbiter + * + * Returns: + * nothing + */ +static void SkGeInit2( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC) /* IO context */ +{ +#ifdef GENESIS + SK_U32 DWord; +#endif /* GENESIS */ + int i; + + /* start the Descriptor Poll Timer */ + if (pAC->GIni.GIPollTimerVal != 0) { + if (pAC->GIni.GIPollTimerVal > SK_DPOLL_MAX) { + pAC->GIni.GIPollTimerVal = SK_DPOLL_MAX; + + SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E017, SKERR_HWI_E017MSG); + } + SK_OUT32(IoC, B28_DPT_INI, pAC->GIni.GIPollTimerVal); + SK_OUT8(IoC, B28_DPT_CTRL, DPT_START); + } + +#ifdef GENESIS + if (pAC->GIni.GIGenesis) { + /* start the Blink Source Counter */ + DWord = SK_BLK_DUR * (SK_U32)pAC->GIni.GIHstClkFact / 100; + + SK_OUT32(IoC, B2_BSC_INI, DWord); + SK_OUT8(IoC, B2_BSC_CTRL, BSC_START); + + /* + * Configure the MAC Arbiter and the Packet Arbiter. + * They will be started once and never be stopped. + */ + SkGeInitMacArb(pAC, IoC); + + SkGeInitPktArb(pAC, IoC); + } +#endif /* GENESIS */ + +#ifdef YUKON + if (pAC->GIni.GIYukon) { + /* start Time Stamp Timer */ + SK_OUT8(IoC, GMAC_TI_ST_CTRL, (SK_U8)GMT_ST_START); + } +#endif /* YUKON */ + + /* enable the Tx Arbiters */ + for (i = 0; i < pAC->GIni.GIMacsFound; i++) { + SK_OUT8(IoC, MR_ADDR(i, TXA_CTRL), TXA_ENA_ARB); + } + + /* enable the RAM Interface Arbiter */ + SkGeInitRamIface(pAC, IoC); + +} /* SkGeInit2 */ + +/****************************************************************************** + * + * SkGeInit() - Initialize the GE Adapter with the specified level. + * + * Description: + * Level 0: Initialize the Module structures. + * Level 1: Generic Hardware Initialization. The IOP/MemBase pointer has + * to be set before calling this level. + * + * o Do a software reset. + * o Clear all reset bits. + * o Verify that the detected hardware is present. + * Return an error if not. + * o Get the hardware configuration + * + Set GIMacsFound with the number of MACs. + * + Store the RAM size in GIRamSize. + * + Save the PCI Revision ID in GIPciHwRev. + * o return an error + * if Number of MACs > SK_MAX_MACS + * + * After returning from Level 0 the adapter + * may be accessed with IO operations. + * + * Level 2: start the Blink Source Counter + * + * Returns: + * 0: success + * 1: Number of MACs exceeds SK_MAX_MACS (after level 1) + * 2: Adapter not present or not accessible + * 3: Illegal initialization level + * 4: Initialization Level 1 Call missing + * 5: Unexpected PHY type detected + * 6: HW self test failed + */ +int SkGeInit( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Level) /* initialization level */ +{ + int RetVal; /* return value */ + SK_U32 DWord; + + RetVal = 0; + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_INIT, + ("SkGeInit(Level %d)\n", Level)); + + switch (Level) { + case SK_INIT_DATA: + /* Initialization Level 0 */ + SkGeInit0(pAC, IoC); + pAC->GIni.GILevel = SK_INIT_DATA; + break; + + case SK_INIT_IO: + /* Initialization Level 1 */ + RetVal = SkGeInit1(pAC, IoC); + if (RetVal != 0) { + break; + } + + /* check if the adapter seems to be accessible */ + SK_OUT32(IoC, B2_IRQM_INI, SK_TEST_VAL); + SK_IN32(IoC, B2_IRQM_INI, &DWord); + SK_OUT32(IoC, B2_IRQM_INI, 0L); + + if (DWord != SK_TEST_VAL) { + RetVal = 2; + break; + } + + /* check if the number of GIMacsFound matches SK_MAX_MACS */ + if (pAC->GIni.GIMacsFound > SK_MAX_MACS) { + RetVal = 1; + break; + } + + /* Level 1 successfully passed */ + pAC->GIni.GILevel = SK_INIT_IO; + break; + + case SK_INIT_RUN: + /* Initialization Level 2 */ + if (pAC->GIni.GILevel != SK_INIT_IO) { +#ifndef SK_DIAG + SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E002, SKERR_HWI_E002MSG); +#endif /* !SK_DIAG */ + RetVal = 4; + break; + } + SkGeInit2(pAC, IoC); + + /* Level 2 successfully passed */ + pAC->GIni.GILevel = SK_INIT_RUN; + break; + + default: + SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E003, SKERR_HWI_E003MSG); + RetVal = 3; + break; + } + + return(RetVal); +} /* SkGeInit */ + + +/****************************************************************************** + * + * SkGeDeInit() - Deinitialize the adapter + * + * Description: + * All ports of the adapter will be stopped if not already done. + * Do a software reset and switch off all LEDs. + * + * Returns: + * nothing + */ +void SkGeDeInit( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC) /* IO context */ +{ + int i; + SK_U16 Word; + +#if (!defined(SK_SLIM) && !defined(VCPU)) + /* ensure I2C is ready */ + SkI2cWaitIrq(pAC, IoC); +#endif + + /* stop all current transfer activity */ + for (i = 0; i < pAC->GIni.GIMacsFound; i++) { + if (pAC->GIni.GP[i].PState != SK_PRT_STOP && + pAC->GIni.GP[i].PState != SK_PRT_RESET) { + + SkGeStopPort(pAC, IoC, i, SK_STOP_ALL, SK_HARD_RST); + } + } + + /* Reset all bits in the PCI STATUS register */ + /* + * Note: PCI Cfg cycles cannot be used, because they are not + * available on some platforms after 'boot time'. + */ + SK_IN16(IoC, PCI_C(PCI_STATUS), &Word); + + SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_ON); + SK_OUT16(IoC, PCI_C(PCI_STATUS), (SK_U16)(Word | PCI_ERRBITS)); + SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_OFF); + + /* do the reset, all LEDs are switched off now */ + SK_OUT8(IoC, B0_CTST, CS_RST_SET); + + pAC->GIni.GILevel = SK_INIT_DATA; +} /* SkGeDeInit */ + + +/****************************************************************************** + * + * SkGeInitPort() Initialize the specified port. + * + * Description: + * PRxQSize, PXSQSize, and PXAQSize has to be + * configured for the specified port before calling this function. + * The descriptor rings has to be initialized too. + * + * o (Re)configure queues of the specified port. + * o configure the MAC of the specified port. + * o put ASIC and MAC(s) in operational mode. + * o initialize Rx/Tx and Sync LED + * o initialize RAM Buffers and MAC FIFOs + * + * The port is ready to connect when returning. + * + * Note: + * The MAC's Rx and Tx state machine is still disabled when returning. + * + * Returns: + * 0: success + * 1: Queue size initialization error. The configured values + * for PRxQSize, PXSQSize, or PXAQSize are invalid for one + * or more queues. The specified port was NOT initialized. + * An error log entry was generated. + * 2: The port has to be stopped before it can be initialized again. + */ +int SkGeInitPort( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port) /* Port to configure */ +{ + SK_GEPORT *pPrt; + + pPrt = &pAC->GIni.GP[Port]; + + if (SkGeCheckQSize(pAC, Port) != 0) { + SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E004, SKERR_HWI_E004MSG); + return(1); + } + + if (pPrt->PState == SK_PRT_INIT || pPrt->PState == SK_PRT_RUN) { + SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E005, SKERR_HWI_E005MSG); + return(2); + } + + /* configuration ok, initialize the Port now */ + +#ifdef GENESIS + if (pAC->GIni.GIGenesis) { + /* initialize Rx, Tx and Link LED */ + /* + * If 1000BT Phy needs LED initialization than swap + * LED and XMAC initialization order + */ + SkGeXmitLED(pAC, IoC, MR_ADDR(Port, TX_LED_INI), SK_LED_ENA); + SkGeXmitLED(pAC, IoC, MR_ADDR(Port, RX_LED_INI), SK_LED_ENA); + /* The Link LED is initialized by RLMT or Diagnostics itself */ + + SkXmInitMac(pAC, IoC, Port); + } +#endif /* GENESIS */ + +#ifdef YUKON + if (pAC->GIni.GIYukon) { + + SkGmInitMac(pAC, IoC, Port); + } +#endif /* YUKON */ + + /* do NOT initialize the Link Sync Counter */ + + SkGeInitMacFifo(pAC, IoC, Port); + + SkGeInitRamBufs(pAC, IoC, Port); + + if (pPrt->PXSQSize != 0) { + /* enable Force Sync bit if synchronous queue available */ + SK_OUT8(IoC, MR_ADDR(Port, TXA_CTRL), TXA_ENA_FSYNC); + } + + SkGeInitBmu(pAC, IoC, Port); + + /* mark port as initialized */ + pPrt->PState = SK_PRT_INIT; + + return(0); +} /* SkGeInitPort */ diff --git a/drivers/net/sk98lin/skgemib.c b/drivers/net/sk98lin/skgemib.c new file mode 100644 index 000000000000..0a6f67a7a395 --- /dev/null +++ b/drivers/net/sk98lin/skgemib.c @@ -0,0 +1,1075 @@ +/***************************************************************************** + * + * Name: skgemib.c + * Project: GEnesis, PCI Gigabit Ethernet Adapter + * Version: $Revision: 1.11 $ + * Date: $Date: 2003/09/15 13:38:12 $ + * Purpose: Private Network Management Interface Management Database + * + ****************************************************************************/ + +/****************************************************************************** + * + * (C)Copyright 1998-2002 SysKonnect GmbH. + * (C)Copyright 2002-2003 Marvell. + * + * 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. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/* + * PRIVATE OID handler function prototypes + */ +PNMI_STATIC int Addr(SK_AC *pAC, SK_IOC IoC, int action, + SK_U32 Id, char *pBuf, unsigned int *pLen, SK_U32 Instance, + unsigned int TableIndex, SK_U32 NetIndex); +PNMI_STATIC int CsumStat(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id, + char *pBuf, unsigned int *pLen, SK_U32 Instance, + unsigned int TableIndex, SK_U32 NetIndex); +PNMI_STATIC int General(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id, + char *pBuf, unsigned int *pLen, SK_U32 Instance, + unsigned int TableIndex, SK_U32 NetIndex); +PNMI_STATIC int Mac8023Stat(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id, + char *pBuf, unsigned int *pLen, SK_U32 Instance, + unsigned int TableIndex, SK_U32 NetIndex); +PNMI_STATIC int MacPrivateConf(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id, + char *pBuf, unsigned int *pLen, SK_U32 Instance, + unsigned int TableIndex, SK_U32 NetIndex); +PNMI_STATIC int MacPrivateStat(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id, + char *pBuf, unsigned int *pLen, SK_U32 Instance, + unsigned int TableIndex, SK_U32 NetIndex); +PNMI_STATIC int Monitor(SK_AC *pAC, SK_IOC IoC, int action, + SK_U32 Id, char *pBuf, unsigned int *pLen, SK_U32 Instance, + unsigned int TableIndex, SK_U32 NetIndex); +PNMI_STATIC int OidStruct(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id, + char *pBuf, unsigned int *pLen, SK_U32 Instance, + unsigned int TableIndex, SK_U32 NetIndex); +PNMI_STATIC int Perform(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id, + char *pBuf, unsigned int* pLen, SK_U32 Instance, + unsigned int TableIndex, SK_U32 NetIndex); +PNMI_STATIC int Rlmt(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id, + char *pBuf, unsigned int *pLen, SK_U32 Instance, + unsigned int TableIndex, SK_U32 NetIndex); +PNMI_STATIC int RlmtStat(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id, + char *pBuf, unsigned int *pLen, SK_U32 Instance, + unsigned int TableIndex, SK_U32 NetIndex); +PNMI_STATIC int SensorStat(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id, + char *pBuf, unsigned int *pLen, SK_U32 Instance, + unsigned int TableIndex, SK_U32 NetIndex); +PNMI_STATIC int Vpd(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id, + char *pBuf, unsigned int *pLen, SK_U32 Instance, + unsigned int TableIndex, SK_U32 NetIndex); +PNMI_STATIC int Vct(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id, + char *pBuf, unsigned int *pLen, SK_U32 Instance, + unsigned int TableIndex, SK_U32 NetIndex); + +#ifdef SK_POWER_MGMT +PNMI_STATIC int PowerManagement(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id, + char *pBuf, unsigned int *pLen, SK_U32 Instance, + unsigned int TableIndex, SK_U32 NetIndex); +#endif /* SK_POWER_MGMT */ + +#ifdef SK_DIAG_SUPPORT +PNMI_STATIC int DiagActions(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id, + char *pBuf, unsigned int *pLen, SK_U32 Instance, + unsigned int TableIndex, SK_U32 NetIndex); +#endif /* SK_DIAG_SUPPORT */ + + +/* defines *******************************************************************/ +#define ID_TABLE_SIZE (sizeof(IdTable)/sizeof(IdTable[0])) + + +/* global variables **********************************************************/ + +/* + * Table to correlate OID with handler function and index to + * hardware register stored in StatAddress if applicable. + */ +PNMI_STATIC const SK_PNMI_TAB_ENTRY IdTable[] = { + {OID_GEN_XMIT_OK, + 0, + 0, + 0, + SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX}, + {OID_GEN_RCV_OK, + 0, + 0, + 0, + SK_PNMI_RO, Mac8023Stat, SK_PNMI_HRX}, + {OID_GEN_XMIT_ERROR, + 0, + 0, + 0, + SK_PNMI_RO, General, 0}, + {OID_GEN_RCV_ERROR, + 0, + 0, + 0, + SK_PNMI_RO, General, 0}, + {OID_GEN_RCV_NO_BUFFER, + 0, + 0, + 0, + SK_PNMI_RO, General, 0}, + {OID_GEN_DIRECTED_FRAMES_XMIT, + 0, + 0, + 0, + SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_UNICAST}, + {OID_GEN_MULTICAST_FRAMES_XMIT, + 0, + 0, + 0, + SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_MULTICAST}, + {OID_GEN_BROADCAST_FRAMES_XMIT, + 0, + 0, + 0, + SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_BROADCAST}, + {OID_GEN_DIRECTED_FRAMES_RCV, + 0, + 0, + 0, + SK_PNMI_RO, Mac8023Stat, SK_PNMI_HRX_UNICAST}, + {OID_GEN_MULTICAST_FRAMES_RCV, + 0, + 0, + 0, + SK_PNMI_RO, Mac8023Stat, SK_PNMI_HRX_MULTICAST}, + {OID_GEN_BROADCAST_FRAMES_RCV, + 0, + 0, + 0, + SK_PNMI_RO, Mac8023Stat, SK_PNMI_HRX_BROADCAST}, + {OID_GEN_RCV_CRC_ERROR, + 0, + 0, + 0, + SK_PNMI_RO, Mac8023Stat, SK_PNMI_HRX_FCS}, + {OID_GEN_TRANSMIT_QUEUE_LENGTH, + 0, + 0, + 0, + SK_PNMI_RO, General, 0}, + {OID_802_3_PERMANENT_ADDRESS, + 0, + 0, + 0, + SK_PNMI_RO, Mac8023Stat, 0}, + {OID_802_3_CURRENT_ADDRESS, + 0, + 0, + 0, + SK_PNMI_RO, Mac8023Stat, 0}, + {OID_802_3_RCV_ERROR_ALIGNMENT, + 0, + 0, + 0, + SK_PNMI_RO, Mac8023Stat, SK_PNMI_HRX_FRAMING}, + {OID_802_3_XMIT_ONE_COLLISION, + 0, + 0, + 0, + SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_SINGLE_COL}, + {OID_802_3_XMIT_MORE_COLLISIONS, + 0, + 0, + 0, + SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_MULTI_COL}, + {OID_802_3_XMIT_DEFERRED, + 0, + 0, + 0, + SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_DEFFERAL}, + {OID_802_3_XMIT_MAX_COLLISIONS, + 0, + 0, + 0, + SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_EXCESS_COL}, + {OID_802_3_RCV_OVERRUN, + 0, + 0, + 0, + SK_PNMI_RO, Mac8023Stat, SK_PNMI_HRX_OVERFLOW}, + {OID_802_3_XMIT_UNDERRUN, + 0, + 0, + 0, + SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_UNDERRUN}, + {OID_802_3_XMIT_TIMES_CRS_LOST, + 0, + 0, + 0, + SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_CARRIER}, + {OID_802_3_XMIT_LATE_COLLISIONS, + 0, + 0, + 0, + SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_LATE_COL}, +#ifdef SK_POWER_MGMT + {OID_PNP_CAPABILITIES, + 0, + 0, + 0, + SK_PNMI_RO, PowerManagement, 0}, + {OID_PNP_SET_POWER, + 0, + 0, + 0, + SK_PNMI_WO, PowerManagement, 0}, + {OID_PNP_QUERY_POWER, + 0, + 0, + 0, + SK_PNMI_RO, PowerManagement, 0}, + {OID_PNP_ADD_WAKE_UP_PATTERN, + 0, + 0, + 0, + SK_PNMI_WO, PowerManagement, 0}, + {OID_PNP_REMOVE_WAKE_UP_PATTERN, + 0, + 0, + 0, + SK_PNMI_WO, PowerManagement, 0}, + {OID_PNP_ENABLE_WAKE_UP, + 0, + 0, + 0, + SK_PNMI_RW, PowerManagement, 0}, +#endif /* SK_POWER_MGMT */ +#ifdef SK_DIAG_SUPPORT + {OID_SKGE_DIAG_MODE, + 0, + 0, + 0, + SK_PNMI_RW, DiagActions, 0}, +#endif /* SK_DIAG_SUPPORT */ + {OID_SKGE_MDB_VERSION, + 1, + 0, + SK_PNMI_MAI_OFF(MgmtDBVersion), + SK_PNMI_RO, General, 0}, + {OID_SKGE_SUPPORTED_LIST, + 0, + 0, + 0, + SK_PNMI_RO, General, 0}, + {OID_SKGE_ALL_DATA, + 0, + 0, + 0, + SK_PNMI_RW, OidStruct, 0}, + {OID_SKGE_VPD_FREE_BYTES, + 1, + 0, + SK_PNMI_MAI_OFF(VpdFreeBytes), + SK_PNMI_RO, Vpd, 0}, + {OID_SKGE_VPD_ENTRIES_LIST, + 1, + 0, + SK_PNMI_MAI_OFF(VpdEntriesList), + SK_PNMI_RO, Vpd, 0}, + {OID_SKGE_VPD_ENTRIES_NUMBER, + 1, + 0, + SK_PNMI_MAI_OFF(VpdEntriesNumber), + SK_PNMI_RO, Vpd, 0}, + {OID_SKGE_VPD_KEY, + SK_PNMI_VPD_ENTRIES, + sizeof(SK_PNMI_VPD), + SK_PNMI_OFF(Vpd) + SK_PNMI_VPD_OFF(VpdKey), + SK_PNMI_RO, Vpd, 0}, + {OID_SKGE_VPD_VALUE, + SK_PNMI_VPD_ENTRIES, + sizeof(SK_PNMI_VPD), + SK_PNMI_OFF(Vpd) + SK_PNMI_VPD_OFF(VpdValue), + SK_PNMI_RO, Vpd, 0}, + {OID_SKGE_VPD_ACCESS, + SK_PNMI_VPD_ENTRIES, + sizeof(SK_PNMI_VPD), + SK_PNMI_OFF(Vpd) + SK_PNMI_VPD_OFF(VpdAccess), + SK_PNMI_RO, Vpd, 0}, + {OID_SKGE_VPD_ACTION, + SK_PNMI_VPD_ENTRIES, + sizeof(SK_PNMI_VPD), + SK_PNMI_OFF(Vpd) + SK_PNMI_VPD_OFF(VpdAction), + SK_PNMI_RW, Vpd, 0}, + {OID_SKGE_PORT_NUMBER, + 1, + 0, + SK_PNMI_MAI_OFF(PortNumber), + SK_PNMI_RO, General, 0}, + {OID_SKGE_DEVICE_TYPE, + 1, + 0, + SK_PNMI_MAI_OFF(DeviceType), + SK_PNMI_RO, General, 0}, + {OID_SKGE_DRIVER_DESCR, + 1, + 0, + SK_PNMI_MAI_OFF(DriverDescr), + SK_PNMI_RO, General, 0}, + {OID_SKGE_DRIVER_VERSION, + 1, + 0, + SK_PNMI_MAI_OFF(DriverVersion), + SK_PNMI_RO, General, 0}, + {OID_SKGE_DRIVER_RELDATE, + 1, + 0, + SK_PNMI_MAI_OFF(DriverReleaseDate), + SK_PNMI_RO, General, 0}, + {OID_SKGE_DRIVER_FILENAME, + 1, + 0, + SK_PNMI_MAI_OFF(DriverFileName), + SK_PNMI_RO, General, 0}, + {OID_SKGE_HW_DESCR, + 1, + 0, + SK_PNMI_MAI_OFF(HwDescr), + SK_PNMI_RO, General, 0}, + {OID_SKGE_HW_VERSION, + 1, + 0, + SK_PNMI_MAI_OFF(HwVersion), + SK_PNMI_RO, General, 0}, + {OID_SKGE_CHIPSET, + 1, + 0, + SK_PNMI_MAI_OFF(Chipset), + SK_PNMI_RO, General, 0}, + {OID_SKGE_CHIPID, + 1, + 0, + SK_PNMI_MAI_OFF(ChipId), + SK_PNMI_RO, General, 0}, + {OID_SKGE_RAMSIZE, + 1, + 0, + SK_PNMI_MAI_OFF(RamSize), + SK_PNMI_RO, General, 0}, + {OID_SKGE_VAUXAVAIL, + 1, + 0, + SK_PNMI_MAI_OFF(VauxAvail), + SK_PNMI_RO, General, 0}, + {OID_SKGE_ACTION, + 1, + 0, + SK_PNMI_MAI_OFF(Action), + SK_PNMI_RW, Perform, 0}, + {OID_SKGE_RESULT, + 1, + 0, + SK_PNMI_MAI_OFF(TestResult), + SK_PNMI_RO, General, 0}, + {OID_SKGE_BUS_TYPE, + 1, + 0, + SK_PNMI_MAI_OFF(BusType), + SK_PNMI_RO, General, 0}, + {OID_SKGE_BUS_SPEED, + 1, + 0, + SK_PNMI_MAI_OFF(BusSpeed), + SK_PNMI_RO, General, 0}, + {OID_SKGE_BUS_WIDTH, + 1, + 0, + SK_PNMI_MAI_OFF(BusWidth), + SK_PNMI_RO, General, 0}, + {OID_SKGE_TX_SW_QUEUE_LEN, + 1, + 0, + SK_PNMI_MAI_OFF(TxSwQueueLen), + SK_PNMI_RO, General, 0}, + {OID_SKGE_TX_SW_QUEUE_MAX, + 1, + 0, + SK_PNMI_MAI_OFF(TxSwQueueMax), + SK_PNMI_RO, General, 0}, + {OID_SKGE_TX_RETRY, + 1, + 0, + SK_PNMI_MAI_OFF(TxRetryCts), + SK_PNMI_RO, General, 0}, + {OID_SKGE_RX_INTR_CTS, + 1, + 0, + SK_PNMI_MAI_OFF(RxIntrCts), + SK_PNMI_RO, General, 0}, + {OID_SKGE_TX_INTR_CTS, + 1, + 0, + SK_PNMI_MAI_OFF(TxIntrCts), + SK_PNMI_RO, General, 0}, + {OID_SKGE_RX_NO_BUF_CTS, + 1, + 0, + SK_PNMI_MAI_OFF(RxNoBufCts), + SK_PNMI_RO, General, 0}, + {OID_SKGE_TX_NO_BUF_CTS, + 1, + 0, + SK_PNMI_MAI_OFF(TxNoBufCts), + SK_PNMI_RO, General, 0}, + {OID_SKGE_TX_USED_DESCR_NO, + 1, + 0, + SK_PNMI_MAI_OFF(TxUsedDescrNo), + SK_PNMI_RO, General, 0}, + {OID_SKGE_RX_DELIVERED_CTS, + 1, + 0, + SK_PNMI_MAI_OFF(RxDeliveredCts), + SK_PNMI_RO, General, 0}, + {OID_SKGE_RX_OCTETS_DELIV_CTS, + 1, + 0, + SK_PNMI_MAI_OFF(RxOctetsDeliveredCts), + SK_PNMI_RO, General, 0}, + {OID_SKGE_RX_HW_ERROR_CTS, + 1, + 0, + SK_PNMI_MAI_OFF(RxHwErrorsCts), + SK_PNMI_RO, General, 0}, + {OID_SKGE_TX_HW_ERROR_CTS, + 1, + 0, + SK_PNMI_MAI_OFF(TxHwErrorsCts), + SK_PNMI_RO, General, 0}, + {OID_SKGE_IN_ERRORS_CTS, + 1, + 0, + SK_PNMI_MAI_OFF(InErrorsCts), + SK_PNMI_RO, General, 0}, + {OID_SKGE_OUT_ERROR_CTS, + 1, + 0, + SK_PNMI_MAI_OFF(OutErrorsCts), + SK_PNMI_RO, General, 0}, + {OID_SKGE_ERR_RECOVERY_CTS, + 1, + 0, + SK_PNMI_MAI_OFF(ErrRecoveryCts), + SK_PNMI_RO, General, 0}, + {OID_SKGE_SYSUPTIME, + 1, + 0, + SK_PNMI_MAI_OFF(SysUpTime), + SK_PNMI_RO, General, 0}, + {OID_SKGE_SENSOR_NUMBER, + 1, + 0, + SK_PNMI_MAI_OFF(SensorNumber), + SK_PNMI_RO, General, 0}, + {OID_SKGE_SENSOR_INDEX, + SK_PNMI_SENSOR_ENTRIES, + sizeof(SK_PNMI_SENSOR), + SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorIndex), + SK_PNMI_RO, SensorStat, 0}, + {OID_SKGE_SENSOR_DESCR, + SK_PNMI_SENSOR_ENTRIES, + sizeof(SK_PNMI_SENSOR), + SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorDescr), + SK_PNMI_RO, SensorStat, 0}, + {OID_SKGE_SENSOR_TYPE, + SK_PNMI_SENSOR_ENTRIES, + sizeof(SK_PNMI_SENSOR), + SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorType), + SK_PNMI_RO, SensorStat, 0}, + {OID_SKGE_SENSOR_VALUE, + SK_PNMI_SENSOR_ENTRIES, + sizeof(SK_PNMI_SENSOR), + SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorValue), + SK_PNMI_RO, SensorStat, 0}, + {OID_SKGE_SENSOR_WAR_THRES_LOW, + SK_PNMI_SENSOR_ENTRIES, + sizeof(SK_PNMI_SENSOR), + SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorWarningThresholdLow), + SK_PNMI_RO, SensorStat, 0}, + {OID_SKGE_SENSOR_WAR_THRES_UPP, + SK_PNMI_SENSOR_ENTRIES, + sizeof(SK_PNMI_SENSOR), + SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorWarningThresholdHigh), + SK_PNMI_RO, SensorStat, 0}, + {OID_SKGE_SENSOR_ERR_THRES_LOW, + SK_PNMI_SENSOR_ENTRIES, + sizeof(SK_PNMI_SENSOR), + SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorErrorThresholdLow), + SK_PNMI_RO, SensorStat, 0}, + {OID_SKGE_SENSOR_ERR_THRES_UPP, + SK_PNMI_SENSOR_ENTRIES, + sizeof(SK_PNMI_SENSOR), + SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorErrorThresholdHigh), + SK_PNMI_RO, SensorStat, 0}, + {OID_SKGE_SENSOR_STATUS, + SK_PNMI_SENSOR_ENTRIES, + sizeof(SK_PNMI_SENSOR), + SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorStatus), + SK_PNMI_RO, SensorStat, 0}, + {OID_SKGE_SENSOR_WAR_CTS, + SK_PNMI_SENSOR_ENTRIES, + sizeof(SK_PNMI_SENSOR), + SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorWarningCts), + SK_PNMI_RO, SensorStat, 0}, + {OID_SKGE_SENSOR_ERR_CTS, + SK_PNMI_SENSOR_ENTRIES, + sizeof(SK_PNMI_SENSOR), + SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorErrorCts), + SK_PNMI_RO, SensorStat, 0}, + {OID_SKGE_SENSOR_WAR_TIME, + SK_PNMI_SENSOR_ENTRIES, + sizeof(SK_PNMI_SENSOR), + SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorWarningTimestamp), + SK_PNMI_RO, SensorStat, 0}, + {OID_SKGE_SENSOR_ERR_TIME, + SK_PNMI_SENSOR_ENTRIES, + sizeof(SK_PNMI_SENSOR), + SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorErrorTimestamp), + SK_PNMI_RO, SensorStat, 0}, + {OID_SKGE_CHKSM_NUMBER, + 1, + 0, + SK_PNMI_MAI_OFF(ChecksumNumber), + SK_PNMI_RO, General, 0}, + {OID_SKGE_CHKSM_RX_OK_CTS, + SKCS_NUM_PROTOCOLS, + sizeof(SK_PNMI_CHECKSUM), + SK_PNMI_OFF(Checksum) + SK_PNMI_CHK_OFF(ChecksumRxOkCts), + SK_PNMI_RO, CsumStat, 0}, + {OID_SKGE_CHKSM_RX_UNABLE_CTS, + SKCS_NUM_PROTOCOLS, + sizeof(SK_PNMI_CHECKSUM), + SK_PNMI_OFF(Checksum) + SK_PNMI_CHK_OFF(ChecksumRxUnableCts), + SK_PNMI_RO, CsumStat, 0}, + {OID_SKGE_CHKSM_RX_ERR_CTS, + SKCS_NUM_PROTOCOLS, + sizeof(SK_PNMI_CHECKSUM), + SK_PNMI_OFF(Checksum) + SK_PNMI_CHK_OFF(ChecksumRxErrCts), + SK_PNMI_RO, CsumStat, 0}, + {OID_SKGE_CHKSM_TX_OK_CTS, + SKCS_NUM_PROTOCOLS, + sizeof(SK_PNMI_CHECKSUM), + SK_PNMI_OFF(Checksum) + SK_PNMI_CHK_OFF(ChecksumTxOkCts), + SK_PNMI_RO, CsumStat, 0}, + {OID_SKGE_CHKSM_TX_UNABLE_CTS, + SKCS_NUM_PROTOCOLS, + sizeof(SK_PNMI_CHECKSUM), + SK_PNMI_OFF(Checksum) + SK_PNMI_CHK_OFF(ChecksumTxUnableCts), + SK_PNMI_RO, CsumStat, 0}, + {OID_SKGE_STAT_TX, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_STAT), + SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxOkCts), + SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX}, + {OID_SKGE_STAT_TX_OCTETS, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_STAT), + SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxOctetsOkCts), + SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_OCTET}, + {OID_SKGE_STAT_TX_BROADCAST, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_STAT), + SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxBroadcastOkCts), + SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_BROADCAST}, + {OID_SKGE_STAT_TX_MULTICAST, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_STAT), + SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxMulticastOkCts), + SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_MULTICAST}, + {OID_SKGE_STAT_TX_UNICAST, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_STAT), + SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxUnicastOkCts), + SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_UNICAST}, + {OID_SKGE_STAT_TX_LONGFRAMES, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_STAT), + SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxLongFramesCts), + SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_LONGFRAMES}, + {OID_SKGE_STAT_TX_BURST, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_STAT), + SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxBurstCts), + SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_BURST}, + {OID_SKGE_STAT_TX_PFLOWC, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_STAT), + SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxPauseMacCtrlCts), + SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_PMACC}, + {OID_SKGE_STAT_TX_FLOWC, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_STAT), + SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxMacCtrlCts), + SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_MACC}, + {OID_SKGE_STAT_TX_SINGLE_COL, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_STAT), + SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxSingleCollisionCts), + SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_SINGLE_COL}, + {OID_SKGE_STAT_TX_MULTI_COL, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_STAT), + SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxMultipleCollisionCts), + SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_MULTI_COL}, + {OID_SKGE_STAT_TX_EXCESS_COL, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_STAT), + SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxExcessiveCollisionCts), + SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_EXCESS_COL}, + {OID_SKGE_STAT_TX_LATE_COL, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_STAT), + SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxLateCollisionCts), + SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_LATE_COL}, + {OID_SKGE_STAT_TX_DEFFERAL, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_STAT), + SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxDeferralCts), + SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_DEFFERAL}, + {OID_SKGE_STAT_TX_EXCESS_DEF, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_STAT), + SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxExcessiveDeferralCts), + SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_EXCESS_DEF}, + {OID_SKGE_STAT_TX_UNDERRUN, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_STAT), + SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxFifoUnderrunCts), + SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_UNDERRUN}, + {OID_SKGE_STAT_TX_CARRIER, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_STAT), + SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxCarrierCts), + SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_CARRIER}, +/* {OID_SKGE_STAT_TX_UTIL, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_STAT), + SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxUtilization), + SK_PNMI_RO, MacPrivateStat, (SK_U16)(-1)}, */ + {OID_SKGE_STAT_TX_64, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_STAT), + SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTx64Cts), + SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_64}, + {OID_SKGE_STAT_TX_127, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_STAT), + SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTx127Cts), + SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_127}, + {OID_SKGE_STAT_TX_255, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_STAT), + SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTx255Cts), + SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_255}, + {OID_SKGE_STAT_TX_511, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_STAT), + SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTx511Cts), + SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_511}, + {OID_SKGE_STAT_TX_1023, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_STAT), + SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTx1023Cts), + SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_1023}, + {OID_SKGE_STAT_TX_MAX, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_STAT), + SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxMaxCts), + SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_MAX}, + {OID_SKGE_STAT_TX_SYNC, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_STAT), + SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxSyncCts), + SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_SYNC}, + {OID_SKGE_STAT_TX_SYNC_OCTETS, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_STAT), + SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxSyncOctetsCts), + SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_SYNC_OCTET}, + {OID_SKGE_STAT_RX, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_STAT), + SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxOkCts), + SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX}, + {OID_SKGE_STAT_RX_OCTETS, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_STAT), + SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxOctetsOkCts), + SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_OCTET}, + {OID_SKGE_STAT_RX_BROADCAST, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_STAT), + SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxBroadcastOkCts), + SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_BROADCAST}, + {OID_SKGE_STAT_RX_MULTICAST, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_STAT), + SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxMulticastOkCts), + SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_MULTICAST}, + {OID_SKGE_STAT_RX_UNICAST, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_STAT), + SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxUnicastOkCts), + SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_UNICAST}, + {OID_SKGE_STAT_RX_LONGFRAMES, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_STAT), + SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxLongFramesCts), + SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_LONGFRAMES}, + {OID_SKGE_STAT_RX_PFLOWC, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_STAT), + SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxPauseMacCtrlCts), + SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_PMACC}, + {OID_SKGE_STAT_RX_FLOWC, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_STAT), + SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxMacCtrlCts), + SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_MACC}, + {OID_SKGE_STAT_RX_PFLOWC_ERR, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_STAT), + SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxPauseMacCtrlErrorCts), + SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_PMACC_ERR}, + {OID_SKGE_STAT_RX_FLOWC_UNKWN, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_STAT), + SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxMacCtrlUnknownCts), + SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_MACC_UNKWN}, + {OID_SKGE_STAT_RX_BURST, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_STAT), + SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxBurstCts), + SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_BURST}, + {OID_SKGE_STAT_RX_MISSED, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_STAT), + SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxMissedCts), + SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_MISSED}, + {OID_SKGE_STAT_RX_FRAMING, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_STAT), + SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxFramingCts), + SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_FRAMING}, + {OID_SKGE_STAT_RX_OVERFLOW, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_STAT), + SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxFifoOverflowCts), + SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_OVERFLOW}, + {OID_SKGE_STAT_RX_JABBER, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_STAT), + SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxJabberCts), + SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_JABBER}, + {OID_SKGE_STAT_RX_CARRIER, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_STAT), + SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxCarrierCts), + SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_CARRIER}, + {OID_SKGE_STAT_RX_IR_LENGTH, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_STAT), + SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxIRLengthCts), + SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_IRLENGTH}, + {OID_SKGE_STAT_RX_SYMBOL, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_STAT), + SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxSymbolCts), + SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_SYMBOL}, + {OID_SKGE_STAT_RX_SHORTS, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_STAT), + SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxShortsCts), + SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_SHORTS}, + {OID_SKGE_STAT_RX_RUNT, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_STAT), + SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxRuntCts), + SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_RUNT}, + {OID_SKGE_STAT_RX_CEXT, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_STAT), + SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxCextCts), + SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_CEXT}, + {OID_SKGE_STAT_RX_TOO_LONG, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_STAT), + SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxTooLongCts), + SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_TOO_LONG}, + {OID_SKGE_STAT_RX_FCS, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_STAT), + SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxFcsCts), + SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_FCS}, +/* {OID_SKGE_STAT_RX_UTIL, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_STAT), + SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxUtilization), + SK_PNMI_RO, MacPrivateStat, (SK_U16)(-1)}, */ + {OID_SKGE_STAT_RX_64, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_STAT), + SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRx64Cts), + SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_64}, + {OID_SKGE_STAT_RX_127, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_STAT), + SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRx127Cts), + SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_127}, + {OID_SKGE_STAT_RX_255, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_STAT), + SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRx255Cts), + SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_255}, + {OID_SKGE_STAT_RX_511, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_STAT), + SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRx511Cts), + SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_511}, + {OID_SKGE_STAT_RX_1023, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_STAT), + SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRx1023Cts), + SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_1023}, + {OID_SKGE_STAT_RX_MAX, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_STAT), + SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxMaxCts), + SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_MAX}, + {OID_SKGE_PHYS_CUR_ADDR, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_CONF), + SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfMacCurrentAddr), + SK_PNMI_RW, Addr, 0}, + {OID_SKGE_PHYS_FAC_ADDR, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_CONF), + SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfMacFactoryAddr), + SK_PNMI_RO, Addr, 0}, + {OID_SKGE_PMD, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_CONF), + SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfPMD), + SK_PNMI_RO, MacPrivateConf, 0}, + {OID_SKGE_CONNECTOR, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_CONF), + SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfConnector), + SK_PNMI_RO, MacPrivateConf, 0}, + {OID_SKGE_PHY_TYPE, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_CONF), + SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfPhyType), + SK_PNMI_RO, MacPrivateConf, 0}, + {OID_SKGE_LINK_CAP, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_CONF), + SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfLinkCapability), + SK_PNMI_RO, MacPrivateConf, 0}, + {OID_SKGE_LINK_MODE, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_CONF), + SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfLinkMode), + SK_PNMI_RW, MacPrivateConf, 0}, + {OID_SKGE_LINK_MODE_STATUS, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_CONF), + SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfLinkModeStatus), + SK_PNMI_RO, MacPrivateConf, 0}, + {OID_SKGE_LINK_STATUS, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_CONF), + SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfLinkStatus), + SK_PNMI_RO, MacPrivateConf, 0}, + {OID_SKGE_FLOWCTRL_CAP, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_CONF), + SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfFlowCtrlCapability), + SK_PNMI_RO, MacPrivateConf, 0}, + {OID_SKGE_FLOWCTRL_MODE, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_CONF), + SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfFlowCtrlMode), + SK_PNMI_RW, MacPrivateConf, 0}, + {OID_SKGE_FLOWCTRL_STATUS, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_CONF), + SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfFlowCtrlStatus), + SK_PNMI_RO, MacPrivateConf, 0}, + {OID_SKGE_PHY_OPERATION_CAP, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_CONF), + SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfPhyOperationCapability), + SK_PNMI_RO, MacPrivateConf, 0}, + {OID_SKGE_PHY_OPERATION_MODE, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_CONF), + SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfPhyOperationMode), + SK_PNMI_RW, MacPrivateConf, 0}, + {OID_SKGE_PHY_OPERATION_STATUS, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_CONF), + SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfPhyOperationStatus), + SK_PNMI_RO, MacPrivateConf, 0}, + {OID_SKGE_SPEED_CAP, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_CONF), + SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfSpeedCapability), + SK_PNMI_RO, MacPrivateConf, 0}, + {OID_SKGE_SPEED_MODE, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_CONF), + SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfSpeedMode), + SK_PNMI_RW, MacPrivateConf, 0}, + {OID_SKGE_SPEED_STATUS, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_CONF), + SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfSpeedStatus), + SK_PNMI_RO, MacPrivateConf, 0}, + {OID_SKGE_TRAP, + 1, + 0, + SK_PNMI_MAI_OFF(Trap), + SK_PNMI_RO, General, 0}, + {OID_SKGE_TRAP_NUMBER, + 1, + 0, + SK_PNMI_MAI_OFF(TrapNumber), + SK_PNMI_RO, General, 0}, + {OID_SKGE_RLMT_MODE, + 1, + 0, + SK_PNMI_MAI_OFF(RlmtMode), + SK_PNMI_RW, Rlmt, 0}, + {OID_SKGE_RLMT_PORT_NUMBER, + 1, + 0, + SK_PNMI_MAI_OFF(RlmtPortNumber), + SK_PNMI_RO, Rlmt, 0}, + {OID_SKGE_RLMT_PORT_ACTIVE, + 1, + 0, + SK_PNMI_MAI_OFF(RlmtPortActive), + SK_PNMI_RO, Rlmt, 0}, + {OID_SKGE_RLMT_PORT_PREFERRED, + 1, + 0, + SK_PNMI_MAI_OFF(RlmtPortPreferred), + SK_PNMI_RW, Rlmt, 0}, + {OID_SKGE_RLMT_CHANGE_CTS, + 1, + 0, + SK_PNMI_MAI_OFF(RlmtChangeCts), + SK_PNMI_RO, Rlmt, 0}, + {OID_SKGE_RLMT_CHANGE_TIME, + 1, + 0, + SK_PNMI_MAI_OFF(RlmtChangeTime), + SK_PNMI_RO, Rlmt, 0}, + {OID_SKGE_RLMT_CHANGE_ESTIM, + 1, + 0, + SK_PNMI_MAI_OFF(RlmtChangeEstimate), + SK_PNMI_RO, Rlmt, 0}, + {OID_SKGE_RLMT_CHANGE_THRES, + 1, + 0, + SK_PNMI_MAI_OFF(RlmtChangeThreshold), + SK_PNMI_RW, Rlmt, 0}, + {OID_SKGE_RLMT_PORT_INDEX, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_RLMT), + SK_PNMI_OFF(Rlmt) + SK_PNMI_RLM_OFF(RlmtIndex), + SK_PNMI_RO, RlmtStat, 0}, + {OID_SKGE_RLMT_STATUS, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_RLMT), + SK_PNMI_OFF(Rlmt) + SK_PNMI_RLM_OFF(RlmtStatus), + SK_PNMI_RO, RlmtStat, 0}, + {OID_SKGE_RLMT_TX_HELLO_CTS, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_RLMT), + SK_PNMI_OFF(Rlmt) + SK_PNMI_RLM_OFF(RlmtTxHelloCts), + SK_PNMI_RO, RlmtStat, 0}, + {OID_SKGE_RLMT_RX_HELLO_CTS, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_RLMT), + SK_PNMI_OFF(Rlmt) + SK_PNMI_RLM_OFF(RlmtRxHelloCts), + SK_PNMI_RO, RlmtStat, 0}, + {OID_SKGE_RLMT_TX_SP_REQ_CTS, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_RLMT), + SK_PNMI_OFF(Rlmt) + SK_PNMI_RLM_OFF(RlmtTxSpHelloReqCts), + SK_PNMI_RO, RlmtStat, 0}, + {OID_SKGE_RLMT_RX_SP_CTS, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_RLMT), + SK_PNMI_OFF(Rlmt) + SK_PNMI_RLM_OFF(RlmtRxSpHelloCts), + SK_PNMI_RO, RlmtStat, 0}, + {OID_SKGE_RLMT_MONITOR_NUMBER, + 1, + 0, + SK_PNMI_MAI_OFF(RlmtMonitorNumber), + SK_PNMI_RO, General, 0}, + {OID_SKGE_RLMT_MONITOR_INDEX, + SK_PNMI_MONITOR_ENTRIES, + sizeof(SK_PNMI_RLMT_MONITOR), + SK_PNMI_OFF(RlmtMonitor) + SK_PNMI_MON_OFF(RlmtMonitorIndex), + SK_PNMI_RO, Monitor, 0}, + {OID_SKGE_RLMT_MONITOR_ADDR, + SK_PNMI_MONITOR_ENTRIES, + sizeof(SK_PNMI_RLMT_MONITOR), + SK_PNMI_OFF(RlmtMonitor) + SK_PNMI_MON_OFF(RlmtMonitorAddr), + SK_PNMI_RO, Monitor, 0}, + {OID_SKGE_RLMT_MONITOR_ERRS, + SK_PNMI_MONITOR_ENTRIES, + sizeof(SK_PNMI_RLMT_MONITOR), + SK_PNMI_OFF(RlmtMonitor) + SK_PNMI_MON_OFF(RlmtMonitorErrorCts), + SK_PNMI_RO, Monitor, 0}, + {OID_SKGE_RLMT_MONITOR_TIMESTAMP, + SK_PNMI_MONITOR_ENTRIES, + sizeof(SK_PNMI_RLMT_MONITOR), + SK_PNMI_OFF(RlmtMonitor) + SK_PNMI_MON_OFF(RlmtMonitorTimestamp), + SK_PNMI_RO, Monitor, 0}, + {OID_SKGE_RLMT_MONITOR_ADMIN, + SK_PNMI_MONITOR_ENTRIES, + sizeof(SK_PNMI_RLMT_MONITOR), + SK_PNMI_OFF(RlmtMonitor) + SK_PNMI_MON_OFF(RlmtMonitorAdmin), + SK_PNMI_RW, Monitor, 0}, + {OID_SKGE_MTU, + 1, + 0, + SK_PNMI_MAI_OFF(MtuSize), + SK_PNMI_RW, MacPrivateConf, 0}, + {OID_SKGE_VCT_GET, + 0, + 0, + 0, + SK_PNMI_RO, Vct, 0}, + {OID_SKGE_VCT_SET, + 0, + 0, + 0, + SK_PNMI_WO, Vct, 0}, + {OID_SKGE_VCT_STATUS, + 0, + 0, + 0, + SK_PNMI_RO, Vct, 0}, + {OID_SKGE_BOARDLEVEL, + 0, + 0, + 0, + SK_PNMI_RO, General, 0}, +}; + diff --git a/drivers/net/sk98lin/skgepnmi.c b/drivers/net/sk98lin/skgepnmi.c new file mode 100644 index 000000000000..b36dd9ac6b29 --- /dev/null +++ b/drivers/net/sk98lin/skgepnmi.c @@ -0,0 +1,8210 @@ +/***************************************************************************** + * + * Name: skgepnmi.c + * Project: GEnesis, PCI Gigabit Ethernet Adapter + * Version: $Revision: 1.111 $ + * Date: $Date: 2003/09/15 13:35:35 $ + * Purpose: Private Network Management Interface + * + ****************************************************************************/ + +/****************************************************************************** + * + * (C)Copyright 1998-2002 SysKonnect GmbH. + * (C)Copyright 2002-2003 Marvell. + * + * 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. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + + +#ifndef _lint +static const char SysKonnectFileId[] = + "@(#) $Id: skgepnmi.c,v 1.111 2003/09/15 13:35:35 tschilli Exp $ (C) Marvell."; +#endif /* !_lint */ + +#include "h/skdrv1st.h" +#include "h/sktypes.h" +#include "h/xmac_ii.h" +#include "h/skdebug.h" +#include "h/skqueue.h" +#include "h/skgepnmi.h" +#include "h/skgesirq.h" +#include "h/skcsum.h" +#include "h/skvpd.h" +#include "h/skgehw.h" +#include "h/skgeinit.h" +#include "h/skdrv2nd.h" +#include "h/skgepnm2.h" +#ifdef SK_POWER_MGMT +#include "h/skgepmgt.h" +#endif +/* defines *******************************************************************/ + +#ifndef DEBUG +#define PNMI_STATIC static +#else /* DEBUG */ +#define PNMI_STATIC +#endif /* DEBUG */ + +/* + * Public Function prototypes + */ +int SkPnmiInit(SK_AC *pAC, SK_IOC IoC, int level); +int SkPnmiSetVar(SK_AC *pAC, SK_IOC IoC, SK_U32 Id, void *pBuf, + unsigned int *pLen, SK_U32 Instance, SK_U32 NetIndex); +int SkPnmiGetStruct(SK_AC *pAC, SK_IOC IoC, void *pBuf, + unsigned int *pLen, SK_U32 NetIndex); +int SkPnmiPreSetStruct(SK_AC *pAC, SK_IOC IoC, void *pBuf, + unsigned int *pLen, SK_U32 NetIndex); +int SkPnmiSetStruct(SK_AC *pAC, SK_IOC IoC, void *pBuf, + unsigned int *pLen, SK_U32 NetIndex); +int SkPnmiEvent(SK_AC *pAC, SK_IOC IoC, SK_U32 Event, SK_EVPARA Param); +int SkPnmiGenIoctl(SK_AC *pAC, SK_IOC IoC, void * pBuf, + unsigned int * pLen, SK_U32 NetIndex); + + +/* + * Private Function prototypes + */ + +PNMI_STATIC SK_U8 CalculateLinkModeStatus(SK_AC *pAC, SK_IOC IoC, unsigned int + PhysPortIndex); +PNMI_STATIC SK_U8 CalculateLinkStatus(SK_AC *pAC, SK_IOC IoC, unsigned int + PhysPortIndex); +PNMI_STATIC void CopyMac(char *pDst, SK_MAC_ADDR *pMac); +PNMI_STATIC void CopyTrapQueue(SK_AC *pAC, char *pDstBuf); +PNMI_STATIC SK_U64 GetPhysStatVal(SK_AC *pAC, SK_IOC IoC, + unsigned int PhysPortIndex, unsigned int StatIndex); +PNMI_STATIC SK_U64 GetStatVal(SK_AC *pAC, SK_IOC IoC, unsigned int LogPortIndex, + unsigned int StatIndex, SK_U32 NetIndex); +PNMI_STATIC char* GetTrapEntry(SK_AC *pAC, SK_U32 TrapId, unsigned int Size); +PNMI_STATIC void GetTrapQueueLen(SK_AC *pAC, unsigned int *pLen, + unsigned int *pEntries); +PNMI_STATIC int GetVpdKeyArr(SK_AC *pAC, SK_IOC IoC, char *pKeyArr, + unsigned int KeyArrLen, unsigned int *pKeyNo); +PNMI_STATIC int LookupId(SK_U32 Id); +PNMI_STATIC int MacUpdate(SK_AC *pAC, SK_IOC IoC, unsigned int FirstMac, + unsigned int LastMac); +PNMI_STATIC int PnmiStruct(SK_AC *pAC, SK_IOC IoC, int Action, char *pBuf, + unsigned int *pLen, SK_U32 NetIndex); +PNMI_STATIC int PnmiVar(SK_AC *pAC, SK_IOC IoC, int Action, SK_U32 Id, + char *pBuf, unsigned int *pLen, SK_U32 Instance, SK_U32 NetIndex); +PNMI_STATIC void QueueRlmtNewMacTrap(SK_AC *pAC, unsigned int ActiveMac); +PNMI_STATIC void QueueRlmtPortTrap(SK_AC *pAC, SK_U32 TrapId, + unsigned int PortIndex); +PNMI_STATIC void QueueSensorTrap(SK_AC *pAC, SK_U32 TrapId, + unsigned int SensorIndex); +PNMI_STATIC void QueueSimpleTrap(SK_AC *pAC, SK_U32 TrapId); +PNMI_STATIC void ResetCounter(SK_AC *pAC, SK_IOC IoC, SK_U32 NetIndex); +PNMI_STATIC int RlmtUpdate(SK_AC *pAC, SK_IOC IoC, SK_U32 NetIndex); +PNMI_STATIC int SirqUpdate(SK_AC *pAC, SK_IOC IoC); +PNMI_STATIC void VirtualConf(SK_AC *pAC, SK_IOC IoC, SK_U32 Id, char *pBuf); +PNMI_STATIC int Vct(SK_AC *pAC, SK_IOC IoC, int Action, SK_U32 Id, char *pBuf, + unsigned int *pLen, SK_U32 Instance, unsigned int TableIndex, SK_U32 NetIndex); +PNMI_STATIC void CheckVctStatus(SK_AC *, SK_IOC, char *, SK_U32, SK_U32); + +/* + * Table to correlate OID with handler function and index to + * hardware register stored in StatAddress if applicable. + */ +#include "skgemib.c" + +/* global variables **********************************************************/ + +/* + * Overflow status register bit table and corresponding counter + * dependent on MAC type - the number relates to the size of overflow + * mask returned by the pFnMacOverflow function + */ +PNMI_STATIC const SK_U16 StatOvrflwBit[][SK_PNMI_MAC_TYPES] = { +/* Bit0 */ { SK_PNMI_HTX, SK_PNMI_HTX_UNICAST}, +/* Bit1 */ { SK_PNMI_HTX_OCTETHIGH, SK_PNMI_HTX_BROADCAST}, +/* Bit2 */ { SK_PNMI_HTX_OCTETLOW, SK_PNMI_HTX_PMACC}, +/* Bit3 */ { SK_PNMI_HTX_BROADCAST, SK_PNMI_HTX_MULTICAST}, +/* Bit4 */ { SK_PNMI_HTX_MULTICAST, SK_PNMI_HTX_OCTETLOW}, +/* Bit5 */ { SK_PNMI_HTX_UNICAST, SK_PNMI_HTX_OCTETHIGH}, +/* Bit6 */ { SK_PNMI_HTX_LONGFRAMES, SK_PNMI_HTX_64}, +/* Bit7 */ { SK_PNMI_HTX_BURST, SK_PNMI_HTX_127}, +/* Bit8 */ { SK_PNMI_HTX_PMACC, SK_PNMI_HTX_255}, +/* Bit9 */ { SK_PNMI_HTX_MACC, SK_PNMI_HTX_511}, +/* Bit10 */ { SK_PNMI_HTX_SINGLE_COL, SK_PNMI_HTX_1023}, +/* Bit11 */ { SK_PNMI_HTX_MULTI_COL, SK_PNMI_HTX_MAX}, +/* Bit12 */ { SK_PNMI_HTX_EXCESS_COL, SK_PNMI_HTX_LONGFRAMES}, +/* Bit13 */ { SK_PNMI_HTX_LATE_COL, SK_PNMI_HTX_RESERVED}, +/* Bit14 */ { SK_PNMI_HTX_DEFFERAL, SK_PNMI_HTX_COL}, +/* Bit15 */ { SK_PNMI_HTX_EXCESS_DEF, SK_PNMI_HTX_LATE_COL}, +/* Bit16 */ { SK_PNMI_HTX_UNDERRUN, SK_PNMI_HTX_EXCESS_COL}, +/* Bit17 */ { SK_PNMI_HTX_CARRIER, SK_PNMI_HTX_MULTI_COL}, +/* Bit18 */ { SK_PNMI_HTX_UTILUNDER, SK_PNMI_HTX_SINGLE_COL}, +/* Bit19 */ { SK_PNMI_HTX_UTILOVER, SK_PNMI_HTX_UNDERRUN}, +/* Bit20 */ { SK_PNMI_HTX_64, SK_PNMI_HTX_RESERVED}, +/* Bit21 */ { SK_PNMI_HTX_127, SK_PNMI_HTX_RESERVED}, +/* Bit22 */ { SK_PNMI_HTX_255, SK_PNMI_HTX_RESERVED}, +/* Bit23 */ { SK_PNMI_HTX_511, SK_PNMI_HTX_RESERVED}, +/* Bit24 */ { SK_PNMI_HTX_1023, SK_PNMI_HTX_RESERVED}, +/* Bit25 */ { SK_PNMI_HTX_MAX, SK_PNMI_HTX_RESERVED}, +/* Bit26 */ { SK_PNMI_HTX_RESERVED, SK_PNMI_HTX_RESERVED}, +/* Bit27 */ { SK_PNMI_HTX_RESERVED, SK_PNMI_HTX_RESERVED}, +/* Bit28 */ { SK_PNMI_HTX_RESERVED, SK_PNMI_HTX_RESERVED}, +/* Bit29 */ { SK_PNMI_HTX_RESERVED, SK_PNMI_HTX_RESERVED}, +/* Bit30 */ { SK_PNMI_HTX_RESERVED, SK_PNMI_HTX_RESERVED}, +/* Bit31 */ { SK_PNMI_HTX_RESERVED, SK_PNMI_HTX_RESERVED}, +/* Bit32 */ { SK_PNMI_HRX, SK_PNMI_HRX_UNICAST}, +/* Bit33 */ { SK_PNMI_HRX_OCTETHIGH, SK_PNMI_HRX_BROADCAST}, +/* Bit34 */ { SK_PNMI_HRX_OCTETLOW, SK_PNMI_HRX_PMACC}, +/* Bit35 */ { SK_PNMI_HRX_BROADCAST, SK_PNMI_HRX_MULTICAST}, +/* Bit36 */ { SK_PNMI_HRX_MULTICAST, SK_PNMI_HRX_FCS}, +/* Bit37 */ { SK_PNMI_HRX_UNICAST, SK_PNMI_HRX_RESERVED}, +/* Bit38 */ { SK_PNMI_HRX_PMACC, SK_PNMI_HRX_OCTETLOW}, +/* Bit39 */ { SK_PNMI_HRX_MACC, SK_PNMI_HRX_OCTETHIGH}, +/* Bit40 */ { SK_PNMI_HRX_PMACC_ERR, SK_PNMI_HRX_BADOCTETLOW}, +/* Bit41 */ { SK_PNMI_HRX_MACC_UNKWN, SK_PNMI_HRX_BADOCTETHIGH}, +/* Bit42 */ { SK_PNMI_HRX_BURST, SK_PNMI_HRX_UNDERSIZE}, +/* Bit43 */ { SK_PNMI_HRX_MISSED, SK_PNMI_HRX_RUNT}, +/* Bit44 */ { SK_PNMI_HRX_FRAMING, SK_PNMI_HRX_64}, +/* Bit45 */ { SK_PNMI_HRX_OVERFLOW, SK_PNMI_HRX_127}, +/* Bit46 */ { SK_PNMI_HRX_JABBER, SK_PNMI_HRX_255}, +/* Bit47 */ { SK_PNMI_HRX_CARRIER, SK_PNMI_HRX_511}, +/* Bit48 */ { SK_PNMI_HRX_IRLENGTH, SK_PNMI_HRX_1023}, +/* Bit49 */ { SK_PNMI_HRX_SYMBOL, SK_PNMI_HRX_MAX}, +/* Bit50 */ { SK_PNMI_HRX_SHORTS, SK_PNMI_HRX_LONGFRAMES}, +/* Bit51 */ { SK_PNMI_HRX_RUNT, SK_PNMI_HRX_TOO_LONG}, +/* Bit52 */ { SK_PNMI_HRX_TOO_LONG, SK_PNMI_HRX_JABBER}, +/* Bit53 */ { SK_PNMI_HRX_FCS, SK_PNMI_HRX_RESERVED}, +/* Bit54 */ { SK_PNMI_HRX_RESERVED, SK_PNMI_HRX_OVERFLOW}, +/* Bit55 */ { SK_PNMI_HRX_CEXT, SK_PNMI_HRX_RESERVED}, +/* Bit56 */ { SK_PNMI_HRX_UTILUNDER, SK_PNMI_HRX_RESERVED}, +/* Bit57 */ { SK_PNMI_HRX_UTILOVER, SK_PNMI_HRX_RESERVED}, +/* Bit58 */ { SK_PNMI_HRX_64, SK_PNMI_HRX_RESERVED}, +/* Bit59 */ { SK_PNMI_HRX_127, SK_PNMI_HRX_RESERVED}, +/* Bit60 */ { SK_PNMI_HRX_255, SK_PNMI_HRX_RESERVED}, +/* Bit61 */ { SK_PNMI_HRX_511, SK_PNMI_HRX_RESERVED}, +/* Bit62 */ { SK_PNMI_HRX_1023, SK_PNMI_HRX_RESERVED}, +/* Bit63 */ { SK_PNMI_HRX_MAX, SK_PNMI_HRX_RESERVED} +}; + +/* + * Table for hardware register saving on resets and port switches + */ +PNMI_STATIC const SK_PNMI_STATADDR StatAddr[SK_PNMI_MAX_IDX][SK_PNMI_MAC_TYPES] = { + /* SK_PNMI_HTX */ + {{XM_TXF_OK, SK_TRUE}, {0, SK_FALSE}}, + /* SK_PNMI_HTX_OCTETHIGH */ + {{XM_TXO_OK_HI, SK_TRUE}, {GM_TXO_OK_HI, SK_TRUE}}, + /* SK_PNMI_HTX_OCTETLOW */ + {{XM_TXO_OK_LO, SK_FALSE}, {GM_TXO_OK_LO, SK_FALSE}}, + /* SK_PNMI_HTX_BROADCAST */ + {{XM_TXF_BC_OK, SK_TRUE}, {GM_TXF_BC_OK, SK_TRUE}}, + /* SK_PNMI_HTX_MULTICAST */ + {{XM_TXF_MC_OK, SK_TRUE}, {GM_TXF_MC_OK, SK_TRUE}}, + /* SK_PNMI_HTX_UNICAST */ + {{XM_TXF_UC_OK, SK_TRUE}, {GM_TXF_UC_OK, SK_TRUE}}, + /* SK_PNMI_HTX_BURST */ + {{XM_TXE_BURST, SK_TRUE}, {0, SK_FALSE}}, + /* SK_PNMI_HTX_PMACC */ + {{XM_TXF_MPAUSE, SK_TRUE}, {GM_TXF_MPAUSE, SK_TRUE}}, + /* SK_PNMI_HTX_MACC */ + {{XM_TXF_MCTRL, SK_TRUE}, {0, SK_FALSE}}, + /* SK_PNMI_HTX_COL */ + {{0, SK_FALSE}, {GM_TXF_COL, SK_TRUE}}, + /* SK_PNMI_HTX_SINGLE_COL */ + {{XM_TXF_SNG_COL, SK_TRUE}, {GM_TXF_SNG_COL, SK_TRUE}}, + /* SK_PNMI_HTX_MULTI_COL */ + {{XM_TXF_MUL_COL, SK_TRUE}, {GM_TXF_MUL_COL, SK_TRUE}}, + /* SK_PNMI_HTX_EXCESS_COL */ + {{XM_TXF_ABO_COL, SK_TRUE}, {GM_TXF_ABO_COL, SK_TRUE}}, + /* SK_PNMI_HTX_LATE_COL */ + {{XM_TXF_LAT_COL, SK_TRUE}, {GM_TXF_LAT_COL, SK_TRUE}}, + /* SK_PNMI_HTX_DEFFERAL */ + {{XM_TXF_DEF, SK_TRUE}, {0, SK_FALSE}}, + /* SK_PNMI_HTX_EXCESS_DEF */ + {{XM_TXF_EX_DEF, SK_TRUE}, {0, SK_FALSE}}, + /* SK_PNMI_HTX_UNDERRUN */ + {{XM_TXE_FIFO_UR, SK_TRUE}, {GM_TXE_FIFO_UR, SK_TRUE}}, + /* SK_PNMI_HTX_CARRIER */ + {{XM_TXE_CS_ERR, SK_TRUE}, {0, SK_FALSE}}, + /* SK_PNMI_HTX_UTILUNDER */ + {{0, SK_FALSE}, {0, SK_FALSE}}, + /* SK_PNMI_HTX_UTILOVER */ + {{0, SK_FALSE}, {0, SK_FALSE}}, + /* SK_PNMI_HTX_64 */ + {{XM_TXF_64B, SK_TRUE}, {GM_TXF_64B, SK_TRUE}}, + /* SK_PNMI_HTX_127 */ + {{XM_TXF_127B, SK_TRUE}, {GM_TXF_127B, SK_TRUE}}, + /* SK_PNMI_HTX_255 */ + {{XM_TXF_255B, SK_TRUE}, {GM_TXF_255B, SK_TRUE}}, + /* SK_PNMI_HTX_511 */ + {{XM_TXF_511B, SK_TRUE}, {GM_TXF_511B, SK_TRUE}}, + /* SK_PNMI_HTX_1023 */ + {{XM_TXF_1023B, SK_TRUE}, {GM_TXF_1023B, SK_TRUE}}, + /* SK_PNMI_HTX_MAX */ + {{XM_TXF_MAX_SZ, SK_TRUE}, {GM_TXF_1518B, SK_TRUE}}, + /* SK_PNMI_HTX_LONGFRAMES */ + {{XM_TXF_LONG, SK_TRUE}, {GM_TXF_MAX_SZ, SK_TRUE}}, + /* SK_PNMI_HTX_SYNC */ + {{0, SK_FALSE}, {0, SK_FALSE}}, + /* SK_PNMI_HTX_SYNC_OCTET */ + {{0, SK_FALSE}, {0, SK_FALSE}}, + /* SK_PNMI_HTX_RESERVED */ + {{0, SK_FALSE}, {0, SK_FALSE}}, + /* SK_PNMI_HRX */ + {{XM_RXF_OK, SK_TRUE}, {0, SK_FALSE}}, + /* SK_PNMI_HRX_OCTETHIGH */ + {{XM_RXO_OK_HI, SK_TRUE}, {GM_RXO_OK_HI, SK_TRUE}}, + /* SK_PNMI_HRX_OCTETLOW */ + {{XM_RXO_OK_LO, SK_FALSE}, {GM_RXO_OK_LO, SK_FALSE}}, + /* SK_PNMI_HRX_BADOCTETHIGH */ + {{0, SK_FALSE}, {GM_RXO_ERR_HI, SK_TRUE}}, + /* SK_PNMI_HRX_BADOCTETLOW */ + {{0, SK_FALSE}, {GM_RXO_ERR_LO, SK_TRUE}}, + /* SK_PNMI_HRX_BROADCAST */ + {{XM_RXF_BC_OK, SK_TRUE}, {GM_RXF_BC_OK, SK_TRUE}}, + /* SK_PNMI_HRX_MULTICAST */ + {{XM_RXF_MC_OK, SK_TRUE}, {GM_RXF_MC_OK, SK_TRUE}}, + /* SK_PNMI_HRX_UNICAST */ + {{XM_RXF_UC_OK, SK_TRUE}, {GM_RXF_UC_OK, SK_TRUE}}, + /* SK_PNMI_HRX_PMACC */ + {{XM_RXF_MPAUSE, SK_TRUE}, {GM_RXF_MPAUSE, SK_TRUE}}, + /* SK_PNMI_HRX_MACC */ + {{XM_RXF_MCTRL, SK_TRUE}, {0, SK_FALSE}}, + /* SK_PNMI_HRX_PMACC_ERR */ + {{XM_RXF_INV_MP, SK_TRUE}, {0, SK_FALSE}}, + /* SK_PNMI_HRX_MACC_UNKWN */ + {{XM_RXF_INV_MOC, SK_TRUE}, {0, SK_FALSE}}, + /* SK_PNMI_HRX_BURST */ + {{XM_RXE_BURST, SK_TRUE}, {0, SK_FALSE}}, + /* SK_PNMI_HRX_MISSED */ + {{XM_RXE_FMISS, SK_TRUE}, {0, SK_FALSE}}, + /* SK_PNMI_HRX_FRAMING */ + {{XM_RXF_FRA_ERR, SK_TRUE}, {0, SK_FALSE}}, + /* SK_PNMI_HRX_UNDERSIZE */ + {{0, SK_FALSE}, {GM_RXF_SHT, SK_TRUE}}, + /* SK_PNMI_HRX_OVERFLOW */ + {{XM_RXE_FIFO_OV, SK_TRUE}, {GM_RXE_FIFO_OV, SK_TRUE}}, + /* SK_PNMI_HRX_JABBER */ + {{XM_RXF_JAB_PKT, SK_TRUE}, {GM_RXF_JAB_PKT, SK_TRUE}}, + /* SK_PNMI_HRX_CARRIER */ + {{XM_RXE_CAR_ERR, SK_TRUE}, {0, SK_FALSE}}, + /* SK_PNMI_HRX_IRLENGTH */ + {{XM_RXF_LEN_ERR, SK_TRUE}, {0, SK_FALSE}}, + /* SK_PNMI_HRX_SYMBOL */ + {{XM_RXE_SYM_ERR, SK_TRUE}, {0, SK_FALSE}}, + /* SK_PNMI_HRX_SHORTS */ + {{XM_RXE_SHT_ERR, SK_TRUE}, {0, SK_FALSE}}, + /* SK_PNMI_HRX_RUNT */ + {{XM_RXE_RUNT, SK_TRUE}, {GM_RXE_FRAG, SK_TRUE}}, + /* SK_PNMI_HRX_TOO_LONG */ + {{XM_RXF_LNG_ERR, SK_TRUE}, {GM_RXF_LNG_ERR, SK_TRUE}}, + /* SK_PNMI_HRX_FCS */ + {{XM_RXF_FCS_ERR, SK_TRUE}, {GM_RXF_FCS_ERR, SK_TRUE}}, + /* SK_PNMI_HRX_CEXT */ + {{XM_RXF_CEX_ERR, SK_TRUE}, {0, SK_FALSE}}, + /* SK_PNMI_HRX_UTILUNDER */ + {{0, SK_FALSE}, {0, SK_FALSE}}, + /* SK_PNMI_HRX_UTILOVER */ + {{0, SK_FALSE}, {0, SK_FALSE}}, + /* SK_PNMI_HRX_64 */ + {{XM_RXF_64B, SK_TRUE}, {GM_RXF_64B, SK_TRUE}}, + /* SK_PNMI_HRX_127 */ + {{XM_RXF_127B, SK_TRUE}, {GM_RXF_127B, SK_TRUE}}, + /* SK_PNMI_HRX_255 */ + {{XM_RXF_255B, SK_TRUE}, {GM_RXF_255B, SK_TRUE}}, + /* SK_PNMI_HRX_511 */ + {{XM_RXF_511B, SK_TRUE}, {GM_RXF_511B, SK_TRUE}}, + /* SK_PNMI_HRX_1023 */ + {{XM_RXF_1023B, SK_TRUE}, {GM_RXF_1023B, SK_TRUE}}, + /* SK_PNMI_HRX_MAX */ + {{XM_RXF_MAX_SZ, SK_TRUE}, {GM_RXF_1518B, SK_TRUE}}, + /* SK_PNMI_HRX_LONGFRAMES */ + {{0, SK_FALSE}, {GM_RXF_MAX_SZ, SK_TRUE}}, + /* SK_PNMI_HRX_RESERVED */ + {{0, SK_FALSE}, {0, SK_FALSE}} +}; + + +/***************************************************************************** + * + * Public functions + * + */ + +/***************************************************************************** + * + * SkPnmiInit - Init function of PNMI + * + * Description: + * SK_INIT_DATA: Initialises the data structures + * SK_INIT_IO: Resets the XMAC statistics, determines the device and + * connector type. + * SK_INIT_RUN: Starts a timer event for port switch per hour + * calculation. + * + * Returns: + * Always 0 + */ +int SkPnmiInit( +SK_AC *pAC, /* Pointer to adapter context */ +SK_IOC IoC, /* IO context handle */ +int Level) /* Initialization level */ +{ + unsigned int PortMax; /* Number of ports */ + unsigned int PortIndex; /* Current port index in loop */ + SK_U16 Val16; /* Multiple purpose 16 bit variable */ + SK_U8 Val8; /* Mulitple purpose 8 bit variable */ + SK_EVPARA EventParam; /* Event struct for timer event */ + SK_PNMI_VCT *pVctBackupData; + + + SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL, + ("PNMI: SkPnmiInit: Called, level=%d\n", Level)); + + switch (Level) { + + case SK_INIT_DATA: + SK_MEMSET((char *)&pAC->Pnmi, 0, sizeof(pAC->Pnmi)); + pAC->Pnmi.TrapBufFree = SK_PNMI_TRAP_QUEUE_LEN; + pAC->Pnmi.StartUpTime = SK_PNMI_HUNDREDS_SEC(SkOsGetTime(pAC)); + pAC->Pnmi.RlmtChangeThreshold = SK_PNMI_DEF_RLMT_CHG_THRES; + for (PortIndex = 0; PortIndex < SK_MAX_MACS; PortIndex ++) { + + pAC->Pnmi.Port[PortIndex].ActiveFlag = SK_FALSE; + pAC->Pnmi.DualNetActiveFlag = SK_FALSE; + } + +#ifdef SK_PNMI_CHECK + if (SK_PNMI_MAX_IDX != SK_PNMI_CNT_NO) { + + SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR049, SK_PNMI_ERR049MSG); + + SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_INIT | SK_DBGCAT_FATAL, + ("CounterOffset struct size (%d) differs from" + "SK_PNMI_MAX_IDX (%d)\n", + SK_PNMI_CNT_NO, SK_PNMI_MAX_IDX)); + } + + if (SK_PNMI_MAX_IDX != + (sizeof(StatAddr) / (sizeof(SK_PNMI_STATADDR) * SK_PNMI_MAC_TYPES))) { + + SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR050, SK_PNMI_ERR050MSG); + + SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_INIT | SK_DBGCAT_FATAL, + ("StatAddr table size (%d) differs from " + "SK_PNMI_MAX_IDX (%d)\n", + (sizeof(StatAddr) / + (sizeof(SK_PNMI_STATADDR) * SK_PNMI_MAC_TYPES)), + SK_PNMI_MAX_IDX)); + } +#endif /* SK_PNMI_CHECK */ + break; + + case SK_INIT_IO: + /* + * Reset MAC counters + */ + PortMax = pAC->GIni.GIMacsFound; + + for (PortIndex = 0; PortIndex < PortMax; PortIndex ++) { + + pAC->GIni.GIFunc.pFnMacResetCounter(pAC, IoC, PortIndex); + } + + /* Initialize DSP variables for Vct() to 0xff => Never written! */ + for (PortIndex = 0; PortIndex < PortMax; PortIndex ++) { + pAC->GIni.GP[PortIndex].PCableLen = 0xff; + pVctBackupData = &pAC->Pnmi.VctBackup[PortIndex]; + pVctBackupData->PCableLen = 0xff; + } + + /* + * Get pci bus speed + */ + SK_IN16(IoC, B0_CTST, &Val16); + if ((Val16 & CS_BUS_CLOCK) == 0) { + + pAC->Pnmi.PciBusSpeed = 33; + } + else { + pAC->Pnmi.PciBusSpeed = 66; + } + + /* + * Get pci bus width + */ + SK_IN16(IoC, B0_CTST, &Val16); + if ((Val16 & CS_BUS_SLOT_SZ) == 0) { + + pAC->Pnmi.PciBusWidth = 32; + } + else { + pAC->Pnmi.PciBusWidth = 64; + } + + /* + * Get chipset + */ + switch (pAC->GIni.GIChipId) { + case CHIP_ID_GENESIS: + pAC->Pnmi.Chipset = SK_PNMI_CHIPSET_XMAC; + break; + + case CHIP_ID_YUKON: + pAC->Pnmi.Chipset = SK_PNMI_CHIPSET_YUKON; + break; + + default: + break; + } + + /* + * Get PMD and DeviceType + */ + SK_IN8(IoC, B2_PMD_TYP, &Val8); + switch (Val8) { + case 'S': + pAC->Pnmi.PMD = 3; + if (pAC->GIni.GIMacsFound > 1) { + + pAC->Pnmi.DeviceType = 0x00020002; + } + else { + pAC->Pnmi.DeviceType = 0x00020001; + } + break; + + case 'L': + pAC->Pnmi.PMD = 2; + if (pAC->GIni.GIMacsFound > 1) { + + pAC->Pnmi.DeviceType = 0x00020004; + } + else { + pAC->Pnmi.DeviceType = 0x00020003; + } + break; + + case 'C': + pAC->Pnmi.PMD = 4; + if (pAC->GIni.GIMacsFound > 1) { + + pAC->Pnmi.DeviceType = 0x00020006; + } + else { + pAC->Pnmi.DeviceType = 0x00020005; + } + break; + + case 'T': + pAC->Pnmi.PMD = 5; + if (pAC->GIni.GIMacsFound > 1) { + + pAC->Pnmi.DeviceType = 0x00020008; + } + else { + pAC->Pnmi.DeviceType = 0x00020007; + } + break; + + default : + pAC->Pnmi.PMD = 1; + pAC->Pnmi.DeviceType = 0; + break; + } + + /* + * Get connector + */ + SK_IN8(IoC, B2_CONN_TYP, &Val8); + switch (Val8) { + case 'C': + pAC->Pnmi.Connector = 2; + break; + + case 'D': + pAC->Pnmi.Connector = 3; + break; + + case 'F': + pAC->Pnmi.Connector = 4; + break; + + case 'J': + pAC->Pnmi.Connector = 5; + break; + + case 'V': + pAC->Pnmi.Connector = 6; + break; + + default: + pAC->Pnmi.Connector = 1; + break; + } + break; + + case SK_INIT_RUN: + /* + * Start timer for RLMT change counter + */ + SK_MEMSET((char *)&EventParam, 0, sizeof(EventParam)); + SkTimerStart(pAC, IoC, &pAC->Pnmi.RlmtChangeEstimate.EstTimer, + 28125000, SKGE_PNMI, SK_PNMI_EVT_CHG_EST_TIMER, + EventParam); + break; + + default: + break; /* Nothing todo */ + } + + return (0); +} + +/***************************************************************************** + * + * SkPnmiGetVar - Retrieves the value of a single OID + * + * Description: + * Calls a general sub-function for all this stuff. If the instance + * -1 is passed, the values of all instances are returned in an + * array of values. + * + * Returns: + * SK_PNMI_ERR_OK The request was successfully performed + * SK_PNMI_ERR_GENERAL A general severe internal error occured + * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to take + * the data. + * SK_PNMI_ERR_UNKNOWN_OID The requested OID is unknown + * SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't + * exist (e.g. port instance 3 on a two port + * adapter. + */ +static int SkPnmiGetVar( +SK_AC *pAC, /* Pointer to adapter context */ +SK_IOC IoC, /* IO context handle */ +SK_U32 Id, /* Object ID that is to be processed */ +void *pBuf, /* Buffer to which the management data will be copied */ +unsigned int *pLen, /* On call: buffer length. On return: used buffer */ +SK_U32 Instance, /* Instance (1..n) that is to be queried or -1 */ +SK_U32 NetIndex) /* NetIndex (0..n), in single net mode always zero */ +{ + SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL, + ("PNMI: SkPnmiGetVar: Called, Id=0x%x, BufLen=%d, Instance=%d, NetIndex=%d\n", + Id, *pLen, Instance, NetIndex)); + + return (PnmiVar(pAC, IoC, SK_PNMI_GET, Id, (char *)pBuf, pLen, + Instance, NetIndex)); +} + +/***************************************************************************** + * + * SkPnmiPreSetVar - Presets the value of a single OID + * + * Description: + * Calls a general sub-function for all this stuff. The preset does + * the same as a set, but returns just before finally setting the + * new value. This is useful to check if a set might be successfull. + * If the instance -1 is passed, an array of values is supposed and + * all instances of the OID will be set. + * + * Returns: + * SK_PNMI_ERR_OK The request was successfully performed. + * SK_PNMI_ERR_GENERAL A general severe internal error occured. + * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain + * the correct data (e.g. a 32bit value is + * needed, but a 16 bit value was passed). + * SK_PNMI_ERR_BAD_VALUE The passed value is not in the valid + * value range. + * SK_PNMI_ERR_READ_ONLY The OID is read-only and cannot be set. + * SK_PNMI_ERR_UNKNOWN_OID The requested OID is unknown. + * SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't + * exist (e.g. port instance 3 on a two port + * adapter. + */ +static int SkPnmiPreSetVar( +SK_AC *pAC, /* Pointer to adapter context */ +SK_IOC IoC, /* IO context handle */ +SK_U32 Id, /* Object ID that is to be processed */ +void *pBuf, /* Buffer to which the management data will be copied */ +unsigned int *pLen, /* Total length of management data */ +SK_U32 Instance, /* Instance (1..n) that is to be set or -1 */ +SK_U32 NetIndex) /* NetIndex (0..n), in single net mode always zero */ +{ + SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL, + ("PNMI: SkPnmiPreSetVar: Called, Id=0x%x, BufLen=%d, Instance=%d, NetIndex=%d\n", + Id, *pLen, Instance, NetIndex)); + + + return (PnmiVar(pAC, IoC, SK_PNMI_PRESET, Id, (char *)pBuf, pLen, + Instance, NetIndex)); +} + +/***************************************************************************** + * + * SkPnmiSetVar - Sets the value of a single OID + * + * Description: + * Calls a general sub-function for all this stuff. The preset does + * the same as a set, but returns just before finally setting the + * new value. This is useful to check if a set might be successfull. + * If the instance -1 is passed, an array of values is supposed and + * all instances of the OID will be set. + * + * Returns: + * SK_PNMI_ERR_OK The request was successfully performed. + * SK_PNMI_ERR_GENERAL A general severe internal error occured. + * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain + * the correct data (e.g. a 32bit value is + * needed, but a 16 bit value was passed). + * SK_PNMI_ERR_BAD_VALUE The passed value is not in the valid + * value range. + * SK_PNMI_ERR_READ_ONLY The OID is read-only and cannot be set. + * SK_PNMI_ERR_UNKNOWN_OID The requested OID is unknown. + * SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't + * exist (e.g. port instance 3 on a two port + * adapter. + */ +int SkPnmiSetVar( +SK_AC *pAC, /* Pointer to adapter context */ +SK_IOC IoC, /* IO context handle */ +SK_U32 Id, /* Object ID that is to be processed */ +void *pBuf, /* Buffer to which the management data will be copied */ +unsigned int *pLen, /* Total length of management data */ +SK_U32 Instance, /* Instance (1..n) that is to be set or -1 */ +SK_U32 NetIndex) /* NetIndex (0..n), in single net mode always zero */ +{ + SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL, + ("PNMI: SkPnmiSetVar: Called, Id=0x%x, BufLen=%d, Instance=%d, NetIndex=%d\n", + Id, *pLen, Instance, NetIndex)); + + return (PnmiVar(pAC, IoC, SK_PNMI_SET, Id, (char *)pBuf, pLen, + Instance, NetIndex)); +} + +/***************************************************************************** + * + * SkPnmiGetStruct - Retrieves the management database in SK_PNMI_STRUCT_DATA + * + * Description: + * Runs through the IdTable, queries the single OIDs and stores the + * returned data into the management database structure + * SK_PNMI_STRUCT_DATA. The offset of the OID in the structure + * is stored in the IdTable. The return value of the function will also + * be stored in SK_PNMI_STRUCT_DATA if the passed buffer has the + * minimum size of SK_PNMI_MIN_STRUCT_SIZE. + * + * Returns: + * SK_PNMI_ERR_OK The request was successfully performed + * SK_PNMI_ERR_GENERAL A general severe internal error occured + * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to take + * the data. + * SK_PNMI_ERR_UNKNOWN_NET The requested NetIndex doesn't exist + */ +int SkPnmiGetStruct( +SK_AC *pAC, /* Pointer to adapter context */ +SK_IOC IoC, /* IO context handle */ +void *pBuf, /* Buffer to which the management data will be copied. */ +unsigned int *pLen, /* Length of buffer */ +SK_U32 NetIndex) /* NetIndex (0..n), in single net mode always zero */ +{ + int Ret; + unsigned int TableIndex; + unsigned int DstOffset; + unsigned int InstanceNo; + unsigned int InstanceCnt; + SK_U32 Instance; + unsigned int TmpLen; + char KeyArr[SK_PNMI_VPD_ENTRIES][SK_PNMI_VPD_KEY_SIZE]; + + + SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL, + ("PNMI: SkPnmiGetStruct: Called, BufLen=%d, NetIndex=%d\n", + *pLen, NetIndex)); + + if (*pLen < SK_PNMI_STRUCT_SIZE) { + + if (*pLen >= SK_PNMI_MIN_STRUCT_SIZE) { + + SK_PNMI_SET_STAT(pBuf, SK_PNMI_ERR_TOO_SHORT, + (SK_U32)(-1)); + } + + *pLen = SK_PNMI_STRUCT_SIZE; + return (SK_PNMI_ERR_TOO_SHORT); + } + + /* + * Check NetIndex + */ + if (NetIndex >= pAC->Rlmt.NumNets) { + return (SK_PNMI_ERR_UNKNOWN_NET); + } + + /* Update statistic */ + SK_PNMI_CHECKFLAGS("SkPnmiGetStruct: On call"); + + if ((Ret = MacUpdate(pAC, IoC, 0, pAC->GIni.GIMacsFound - 1)) != + SK_PNMI_ERR_OK) { + + SK_PNMI_SET_STAT(pBuf, Ret, (SK_U32)(-1)); + *pLen = SK_PNMI_MIN_STRUCT_SIZE; + return (Ret); + } + + if ((Ret = RlmtUpdate(pAC, IoC, NetIndex)) != SK_PNMI_ERR_OK) { + + SK_PNMI_SET_STAT(pBuf, Ret, (SK_U32)(-1)); + *pLen = SK_PNMI_MIN_STRUCT_SIZE; + return (Ret); + } + + if ((Ret = SirqUpdate(pAC, IoC)) != SK_PNMI_ERR_OK) { + + SK_PNMI_SET_STAT(pBuf, Ret, (SK_U32)(-1)); + *pLen = SK_PNMI_MIN_STRUCT_SIZE; + return (Ret); + } + + /* + * Increment semaphores to indicate that an update was + * already done + */ + pAC->Pnmi.MacUpdatedFlag ++; + pAC->Pnmi.RlmtUpdatedFlag ++; + pAC->Pnmi.SirqUpdatedFlag ++; + + /* Get vpd keys for instance calculation */ + Ret = GetVpdKeyArr(pAC, IoC, &KeyArr[0][0], sizeof(KeyArr), &TmpLen); + if (Ret != SK_PNMI_ERR_OK) { + + pAC->Pnmi.MacUpdatedFlag --; + pAC->Pnmi.RlmtUpdatedFlag --; + pAC->Pnmi.SirqUpdatedFlag --; + + SK_PNMI_CHECKFLAGS("SkPnmiGetStruct: On return"); + SK_PNMI_SET_STAT(pBuf, Ret, (SK_U32)(-1)); + *pLen = SK_PNMI_MIN_STRUCT_SIZE; + return (SK_PNMI_ERR_GENERAL); + } + + /* Retrieve values */ + SK_MEMSET((char *)pBuf, 0, SK_PNMI_STRUCT_SIZE); + for (TableIndex = 0; TableIndex < ID_TABLE_SIZE; TableIndex ++) { + + InstanceNo = IdTable[TableIndex].InstanceNo; + for (InstanceCnt = 1; InstanceCnt <= InstanceNo; + InstanceCnt ++) { + + DstOffset = IdTable[TableIndex].Offset + + (InstanceCnt - 1) * + IdTable[TableIndex].StructSize; + + /* + * For the VPD the instance is not an index number + * but the key itself. Determin with the instance + * counter the VPD key to be used. + */ + if (IdTable[TableIndex].Id == OID_SKGE_VPD_KEY || + IdTable[TableIndex].Id == OID_SKGE_VPD_VALUE || + IdTable[TableIndex].Id == OID_SKGE_VPD_ACCESS || + IdTable[TableIndex].Id == OID_SKGE_VPD_ACTION) { + + SK_STRNCPY((char *)&Instance, KeyArr[InstanceCnt - 1], 4); + } + else { + Instance = (SK_U32)InstanceCnt; + } + + TmpLen = *pLen - DstOffset; + Ret = IdTable[TableIndex].Func(pAC, IoC, SK_PNMI_GET, + IdTable[TableIndex].Id, (char *)pBuf + + DstOffset, &TmpLen, Instance, TableIndex, NetIndex); + + /* + * An unknown instance error means that we reached + * the last instance of that variable. Proceed with + * the next OID in the table and ignore the return + * code. + */ + if (Ret == SK_PNMI_ERR_UNKNOWN_INST) { + + break; + } + + if (Ret != SK_PNMI_ERR_OK) { + + pAC->Pnmi.MacUpdatedFlag --; + pAC->Pnmi.RlmtUpdatedFlag --; + pAC->Pnmi.SirqUpdatedFlag --; + + SK_PNMI_CHECKFLAGS("SkPnmiGetStruct: On return"); + SK_PNMI_SET_STAT(pBuf, Ret, DstOffset); + *pLen = SK_PNMI_MIN_STRUCT_SIZE; + return (Ret); + } + } + } + + pAC->Pnmi.MacUpdatedFlag --; + pAC->Pnmi.RlmtUpdatedFlag --; + pAC->Pnmi.SirqUpdatedFlag --; + + *pLen = SK_PNMI_STRUCT_SIZE; + SK_PNMI_CHECKFLAGS("SkPnmiGetStruct: On return"); + SK_PNMI_SET_STAT(pBuf, SK_PNMI_ERR_OK, (SK_U32)(-1)); + return (SK_PNMI_ERR_OK); +} + +/***************************************************************************** + * + * SkPnmiPreSetStruct - Presets the management database in SK_PNMI_STRUCT_DATA + * + * Description: + * Calls a general sub-function for all this set stuff. The preset does + * the same as a set, but returns just before finally setting the + * new value. This is useful to check if a set might be successfull. + * The sub-function runs through the IdTable, checks which OIDs are able + * to set, and calls the handler function of the OID to perform the + * preset. The return value of the function will also be stored in + * SK_PNMI_STRUCT_DATA if the passed buffer has the minimum size of + * SK_PNMI_MIN_STRUCT_SIZE. + * + * Returns: + * SK_PNMI_ERR_OK The request was successfully performed. + * SK_PNMI_ERR_GENERAL A general severe internal error occured. + * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain + * the correct data (e.g. a 32bit value is + * needed, but a 16 bit value was passed). + * SK_PNMI_ERR_BAD_VALUE The passed value is not in the valid + * value range. + */ +int SkPnmiPreSetStruct( +SK_AC *pAC, /* Pointer to adapter context */ +SK_IOC IoC, /* IO context handle */ +void *pBuf, /* Buffer which contains the data to be set */ +unsigned int *pLen, /* Length of buffer */ +SK_U32 NetIndex) /* NetIndex (0..n), in single net mode always zero */ +{ + SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL, + ("PNMI: SkPnmiPreSetStruct: Called, BufLen=%d, NetIndex=%d\n", + *pLen, NetIndex)); + + return (PnmiStruct(pAC, IoC, SK_PNMI_PRESET, (char *)pBuf, + pLen, NetIndex)); +} + +/***************************************************************************** + * + * SkPnmiSetStruct - Sets the management database in SK_PNMI_STRUCT_DATA + * + * Description: + * Calls a general sub-function for all this set stuff. The return value + * of the function will also be stored in SK_PNMI_STRUCT_DATA if the + * passed buffer has the minimum size of SK_PNMI_MIN_STRUCT_SIZE. + * The sub-function runs through the IdTable, checks which OIDs are able + * to set, and calls the handler function of the OID to perform the + * set. The return value of the function will also be stored in + * SK_PNMI_STRUCT_DATA if the passed buffer has the minimum size of + * SK_PNMI_MIN_STRUCT_SIZE. + * + * Returns: + * SK_PNMI_ERR_OK The request was successfully performed. + * SK_PNMI_ERR_GENERAL A general severe internal error occured. + * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain + * the correct data (e.g. a 32bit value is + * needed, but a 16 bit value was passed). + * SK_PNMI_ERR_BAD_VALUE The passed value is not in the valid + * value range. + */ +int SkPnmiSetStruct( +SK_AC *pAC, /* Pointer to adapter context */ +SK_IOC IoC, /* IO context handle */ +void *pBuf, /* Buffer which contains the data to be set */ +unsigned int *pLen, /* Length of buffer */ +SK_U32 NetIndex) /* NetIndex (0..n), in single net mode always zero */ +{ + SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL, + ("PNMI: SkPnmiSetStruct: Called, BufLen=%d, NetIndex=%d\n", + *pLen, NetIndex)); + + return (PnmiStruct(pAC, IoC, SK_PNMI_SET, (char *)pBuf, + pLen, NetIndex)); +} + +/***************************************************************************** + * + * SkPnmiEvent - Event handler + * + * Description: + * Handles the following events: + * SK_PNMI_EVT_SIRQ_OVERFLOW When a hardware counter overflows an + * interrupt will be generated which is + * first handled by SIRQ which generates a + * this event. The event increments the + * upper 32 bit of the 64 bit counter. + * SK_PNMI_EVT_SEN_XXX The event is generated by the I2C module + * when a sensor reports a warning or + * error. The event will store a trap + * message in the trap buffer. + * SK_PNMI_EVT_CHG_EST_TIMER The timer event was initiated by this + * module and is used to calculate the + * port switches per hour. + * SK_PNMI_EVT_CLEAR_COUNTER The event clears all counters and + * timestamps. + * SK_PNMI_EVT_XMAC_RESET The event is generated by the driver + * before a hard reset of the XMAC is + * performed. All counters will be saved + * and added to the hardware counter + * values after reset to grant continuous + * counter values. + * SK_PNMI_EVT_RLMT_PORT_UP Generated by RLMT to notify that a port + * went logically up. A trap message will + * be stored to the trap buffer. + * SK_PNMI_EVT_RLMT_PORT_DOWN Generated by RLMT to notify that a port + * went logically down. A trap message will + * be stored to the trap buffer. + * SK_PNMI_EVT_RLMT_SEGMENTATION Generated by RLMT to notify that two + * spanning tree root bridges were + * detected. A trap message will be stored + * to the trap buffer. + * SK_PNMI_EVT_RLMT_ACTIVE_DOWN Notifies PNMI that an active port went + * down. PNMI will not further add the + * statistic values to the virtual port. + * SK_PNMI_EVT_RLMT_ACTIVE_UP Notifies PNMI that a port went up and + * is now an active port. PNMI will now + * add the statistic data of this port to + * the virtual port. + * SK_PNMI_EVT_RLMT_SET_NETS Notifies PNMI about the net mode. The first parameter + * contains the number of nets. 1 means single net, 2 means + * dual net. The second parameter is -1 + * + * Returns: + * Always 0 + */ +int SkPnmiEvent( +SK_AC *pAC, /* Pointer to adapter context */ +SK_IOC IoC, /* IO context handle */ +SK_U32 Event, /* Event-Id */ +SK_EVPARA Param) /* Event dependent parameter */ +{ + unsigned int PhysPortIndex; + unsigned int MaxNetNumber; + int CounterIndex; + int Ret; + SK_U16 MacStatus; + SK_U64 OverflowStatus; + SK_U64 Mask; + int MacType; + SK_U64 Value; + SK_U32 Val32; + SK_U16 Register; + SK_EVPARA EventParam; + SK_U64 NewestValue; + SK_U64 OldestValue; + SK_U64 Delta; + SK_PNMI_ESTIMATE *pEst; + SK_U32 NetIndex; + SK_GEPORT *pPrt; + SK_PNMI_VCT *pVctBackupData; + SK_U32 RetCode; + int i; + SK_U32 CableLength; + + +#ifdef DEBUG + if (Event != SK_PNMI_EVT_XMAC_RESET) { + + SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL, + ("PNMI: SkPnmiEvent: Called, Event=0x%x, Param=0x%x\n", + (unsigned int)Event, (unsigned int)Param.Para64)); + } +#endif /* DEBUG */ + SK_PNMI_CHECKFLAGS("SkPnmiEvent: On call"); + + MacType = pAC->GIni.GIMacType; + + switch (Event) { + + case SK_PNMI_EVT_SIRQ_OVERFLOW: + PhysPortIndex = (int)Param.Para32[0]; + MacStatus = (SK_U16)Param.Para32[1]; +#ifdef DEBUG + if (PhysPortIndex >= SK_MAX_MACS) { + + SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL, + ("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_SIRQ_OVERFLOW parameter" + " wrong, PhysPortIndex=0x%x\n", + PhysPortIndex)); + return (0); + } +#endif /* DEBUG */ + OverflowStatus = 0; + + /* + * Check which source caused an overflow interrupt. + */ + if ((pAC->GIni.GIFunc.pFnMacOverflow(pAC, IoC, PhysPortIndex, + MacStatus, &OverflowStatus) != 0) || + (OverflowStatus == 0)) { + + SK_PNMI_CHECKFLAGS("SkPnmiEvent: On return"); + return (0); + } + + /* + * Check the overflow status register and increment + * the upper dword of corresponding counter. + */ + for (CounterIndex = 0; CounterIndex < sizeof(Mask) * 8; + CounterIndex ++) { + + Mask = (SK_U64)1 << CounterIndex; + if ((OverflowStatus & Mask) == 0) { + + continue; + } + + switch (StatOvrflwBit[CounterIndex][MacType]) { + + case SK_PNMI_HTX_UTILUNDER: + case SK_PNMI_HTX_UTILOVER: + if (MacType == SK_MAC_XMAC) { + XM_IN16(IoC, PhysPortIndex, XM_TX_CMD, &Register); + Register |= XM_TX_SAM_LINE; + XM_OUT16(IoC, PhysPortIndex, XM_TX_CMD, Register); + } + break; + + case SK_PNMI_HRX_UTILUNDER: + case SK_PNMI_HRX_UTILOVER: + if (MacType == SK_MAC_XMAC) { + XM_IN16(IoC, PhysPortIndex, XM_RX_CMD, &Register); + Register |= XM_RX_SAM_LINE; + XM_OUT16(IoC, PhysPortIndex, XM_RX_CMD, Register); + } + break; + + case SK_PNMI_HTX_OCTETHIGH: + case SK_PNMI_HTX_OCTETLOW: + case SK_PNMI_HTX_RESERVED: + case SK_PNMI_HRX_OCTETHIGH: + case SK_PNMI_HRX_OCTETLOW: + case SK_PNMI_HRX_IRLENGTH: + case SK_PNMI_HRX_RESERVED: + + /* + * the following counters aren't be handled (id > 63) + */ + case SK_PNMI_HTX_SYNC: + case SK_PNMI_HTX_SYNC_OCTET: + break; + + case SK_PNMI_HRX_LONGFRAMES: + if (MacType == SK_MAC_GMAC) { + pAC->Pnmi.Port[PhysPortIndex]. + CounterHigh[CounterIndex] ++; + } + break; + + default: + pAC->Pnmi.Port[PhysPortIndex]. + CounterHigh[CounterIndex] ++; + } + } + break; + + case SK_PNMI_EVT_SEN_WAR_LOW: +#ifdef DEBUG + if ((unsigned int)Param.Para64 >= (unsigned int)pAC->I2c.MaxSens) { + + SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL, + ("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_SEN_WAR_LOW parameter wrong, SensorIndex=%d\n", + (unsigned int)Param.Para64)); + return (0); + } +#endif /* DEBUG */ + + /* + * Store a trap message in the trap buffer and generate + * an event for user space applications with the + * SK_DRIVER_SENDEVENT macro. + */ + QueueSensorTrap(pAC, OID_SKGE_TRAP_SEN_WAR_LOW, + (unsigned int)Param.Para64); + (void)SK_DRIVER_SENDEVENT(pAC, IoC); + break; + + case SK_PNMI_EVT_SEN_WAR_UPP: +#ifdef DEBUG + if ((unsigned int)Param.Para64 >= (unsigned int)pAC->I2c.MaxSens) { + + SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL, + ("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_SEN_WAR_UPP parameter wrong, SensorIndex=%d\n", + (unsigned int)Param.Para64)); + return (0); + } +#endif /* DEBUG */ + + /* + * Store a trap message in the trap buffer and generate + * an event for user space applications with the + * SK_DRIVER_SENDEVENT macro. + */ + QueueSensorTrap(pAC, OID_SKGE_TRAP_SEN_WAR_UPP, + (unsigned int)Param.Para64); + (void)SK_DRIVER_SENDEVENT(pAC, IoC); + break; + + case SK_PNMI_EVT_SEN_ERR_LOW: +#ifdef DEBUG + if ((unsigned int)Param.Para64 >= (unsigned int)pAC->I2c.MaxSens) { + + SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL, + ("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_SEN_ERR_LOW parameter wrong, SensorIndex=%d\n", + (unsigned int)Param.Para64)); + return (0); + } +#endif /* DEBUG */ + + /* + * Store a trap message in the trap buffer and generate + * an event for user space applications with the + * SK_DRIVER_SENDEVENT macro. + */ + QueueSensorTrap(pAC, OID_SKGE_TRAP_SEN_ERR_LOW, + (unsigned int)Param.Para64); + (void)SK_DRIVER_SENDEVENT(pAC, IoC); + break; + + case SK_PNMI_EVT_SEN_ERR_UPP: +#ifdef DEBUG + if ((unsigned int)Param.Para64 >= (unsigned int)pAC->I2c.MaxSens) { + + SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL, + ("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_SEN_ERR_UPP parameter wrong, SensorIndex=%d\n", + (unsigned int)Param.Para64)); + return (0); + } +#endif /* DEBUG */ + + /* + * Store a trap message in the trap buffer and generate + * an event for user space applications with the + * SK_DRIVER_SENDEVENT macro. + */ + QueueSensorTrap(pAC, OID_SKGE_TRAP_SEN_ERR_UPP, + (unsigned int)Param.Para64); + (void)SK_DRIVER_SENDEVENT(pAC, IoC); + break; + + case SK_PNMI_EVT_CHG_EST_TIMER: + /* + * Calculate port switch average on a per hour basis + * Time interval for check : 28125 ms + * Number of values for average : 8 + * + * Be careful in changing these values, on change check + * - typedef of SK_PNMI_ESTIMATE (Size of EstValue + * array one less than value number) + * - Timer initialization SkTimerStart() in SkPnmiInit + * - Delta value below must be multiplicated with + * power of 2 + * + */ + pEst = &pAC->Pnmi.RlmtChangeEstimate; + CounterIndex = pEst->EstValueIndex + 1; + if (CounterIndex == 7) { + + CounterIndex = 0; + } + pEst->EstValueIndex = CounterIndex; + + NewestValue = pAC->Pnmi.RlmtChangeCts; + OldestValue = pEst->EstValue[CounterIndex]; + pEst->EstValue[CounterIndex] = NewestValue; + + /* + * Calculate average. Delta stores the number of + * port switches per 28125 * 8 = 225000 ms + */ + if (NewestValue >= OldestValue) { + + Delta = NewestValue - OldestValue; + } + else { + /* Overflow situation */ + Delta = (SK_U64)(0 - OldestValue) + NewestValue; + } + + /* + * Extrapolate delta to port switches per hour. + * Estimate = Delta * (3600000 / 225000) + * = Delta * 16 + * = Delta << 4 + */ + pAC->Pnmi.RlmtChangeEstimate.Estimate = Delta << 4; + + /* + * Check if threshold is exceeded. If the threshold is + * permanently exceeded every 28125 ms an event will be + * generated to remind the user of this condition. + */ + if ((pAC->Pnmi.RlmtChangeThreshold != 0) && + (pAC->Pnmi.RlmtChangeEstimate.Estimate >= + pAC->Pnmi.RlmtChangeThreshold)) { + + QueueSimpleTrap(pAC, OID_SKGE_TRAP_RLMT_CHANGE_THRES); + (void)SK_DRIVER_SENDEVENT(pAC, IoC); + } + + SK_MEMSET((char *)&EventParam, 0, sizeof(EventParam)); + SkTimerStart(pAC, IoC, &pAC->Pnmi.RlmtChangeEstimate.EstTimer, + 28125000, SKGE_PNMI, SK_PNMI_EVT_CHG_EST_TIMER, + EventParam); + break; + + case SK_PNMI_EVT_CLEAR_COUNTER: + /* + * Param.Para32[0] contains the NetIndex (0 ..1). + * Param.Para32[1] is reserved, contains -1. + */ + NetIndex = (SK_U32)Param.Para32[0]; + +#ifdef DEBUG + if (NetIndex >= pAC->Rlmt.NumNets) { + + SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL, + ("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_CLEAR_COUNTER parameter wrong, NetIndex=%d\n", + NetIndex)); + + return (0); + } +#endif /* DEBUG */ + + /* + * Set all counters and timestamps to zero. + * The according NetIndex is required as a + * parameter of the event. + */ + ResetCounter(pAC, IoC, NetIndex); + break; + + case SK_PNMI_EVT_XMAC_RESET: + /* + * To grant continuous counter values store the current + * XMAC statistic values to the entries 1..n of the + * CounterOffset array. XMAC Errata #2 + */ +#ifdef DEBUG + if ((unsigned int)Param.Para64 >= SK_MAX_MACS) { + + SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL, + ("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_XMAC_RESET parameter wrong, PhysPortIndex=%d\n", + (unsigned int)Param.Para64)); + return (0); + } +#endif + PhysPortIndex = (unsigned int)Param.Para64; + + /* + * Update XMAC statistic to get fresh values + */ + Ret = MacUpdate(pAC, IoC, 0, pAC->GIni.GIMacsFound - 1); + if (Ret != SK_PNMI_ERR_OK) { + + SK_PNMI_CHECKFLAGS("SkPnmiEvent: On return"); + return (0); + } + /* + * Increment semaphore to indicate that an update was + * already done + */ + pAC->Pnmi.MacUpdatedFlag ++; + + for (CounterIndex = 0; CounterIndex < SK_PNMI_MAX_IDX; + CounterIndex ++) { + + if (!StatAddr[CounterIndex][MacType].GetOffset) { + + continue; + } + + pAC->Pnmi.Port[PhysPortIndex].CounterOffset[CounterIndex] = + GetPhysStatVal(pAC, IoC, PhysPortIndex, CounterIndex); + + pAC->Pnmi.Port[PhysPortIndex].CounterHigh[CounterIndex] = 0; + } + + pAC->Pnmi.MacUpdatedFlag --; + break; + + case SK_PNMI_EVT_RLMT_PORT_UP: + PhysPortIndex = (unsigned int)Param.Para32[0]; +#ifdef DEBUG + if (PhysPortIndex >= SK_MAX_MACS) { + + SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL, + ("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_RLMT_PORT_UP parameter" + " wrong, PhysPortIndex=%d\n", PhysPortIndex)); + + return (0); + } +#endif /* DEBUG */ + + /* + * Store a trap message in the trap buffer and generate an event for + * user space applications with the SK_DRIVER_SENDEVENT macro. + */ + QueueRlmtPortTrap(pAC, OID_SKGE_TRAP_RLMT_PORT_UP, PhysPortIndex); + (void)SK_DRIVER_SENDEVENT(pAC, IoC); + + /* Bugfix for XMAC errata (#10620)*/ + if (MacType == SK_MAC_XMAC) { + /* Add incremental difference to offset (#10620)*/ + (void)pAC->GIni.GIFunc.pFnMacStatistic(pAC, IoC, PhysPortIndex, + XM_RXE_SHT_ERR, &Val32); + + Value = (((SK_U64)pAC->Pnmi.Port[PhysPortIndex]. + CounterHigh[SK_PNMI_HRX_SHORTS] << 32) | (SK_U64)Val32); + pAC->Pnmi.Port[PhysPortIndex].CounterOffset[SK_PNMI_HRX_SHORTS] += + Value - pAC->Pnmi.Port[PhysPortIndex].RxShortZeroMark; + } + + /* Tell VctStatus() that a link was up meanwhile. */ + pAC->Pnmi.VctStatus[PhysPortIndex] |= SK_PNMI_VCT_LINK; + break; + + case SK_PNMI_EVT_RLMT_PORT_DOWN: + PhysPortIndex = (unsigned int)Param.Para32[0]; + +#ifdef DEBUG + if (PhysPortIndex >= SK_MAX_MACS) { + + SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL, + ("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_RLMT_PORT_DOWN parameter" + " wrong, PhysPortIndex=%d\n", PhysPortIndex)); + + return (0); + } +#endif /* DEBUG */ + + /* + * Store a trap message in the trap buffer and generate an event for + * user space applications with the SK_DRIVER_SENDEVENT macro. + */ + QueueRlmtPortTrap(pAC, OID_SKGE_TRAP_RLMT_PORT_DOWN, PhysPortIndex); + (void)SK_DRIVER_SENDEVENT(pAC, IoC); + + /* Bugfix #10620 - get zero level for incremental difference */ + if (MacType == SK_MAC_XMAC) { + + (void)pAC->GIni.GIFunc.pFnMacStatistic(pAC, IoC, PhysPortIndex, + XM_RXE_SHT_ERR, &Val32); + + pAC->Pnmi.Port[PhysPortIndex].RxShortZeroMark = + (((SK_U64)pAC->Pnmi.Port[PhysPortIndex]. + CounterHigh[SK_PNMI_HRX_SHORTS] << 32) | (SK_U64)Val32); + } + break; + + case SK_PNMI_EVT_RLMT_ACTIVE_DOWN: + PhysPortIndex = (unsigned int)Param.Para32[0]; + NetIndex = (SK_U32)Param.Para32[1]; + +#ifdef DEBUG + if (PhysPortIndex >= SK_MAX_MACS) { + + SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL, + ("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_RLMT_ACTIVE_DOWN parameter too high, PhysPort=%d\n", + PhysPortIndex)); + } + + if (NetIndex >= pAC->Rlmt.NumNets) { + + SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL, + ("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_RLMT_ACTIVE_DOWN parameter too high, NetIndex=%d\n", + NetIndex)); + } +#endif /* DEBUG */ + + /* + * For now, ignore event if NetIndex != 0. + */ + if (Param.Para32[1] != 0) { + + return (0); + } + + /* + * Nothing to do if port is already inactive + */ + if (!pAC->Pnmi.Port[PhysPortIndex].ActiveFlag) { + + return (0); + } + + /* + * Update statistic counters to calculate new offset for the virtual + * port and increment semaphore to indicate that an update was already + * done. + */ + if (MacUpdate(pAC, IoC, 0, pAC->GIni.GIMacsFound - 1) != + SK_PNMI_ERR_OK) { + + SK_PNMI_CHECKFLAGS("SkPnmiEvent: On return"); + return (0); + } + pAC->Pnmi.MacUpdatedFlag ++; + + /* + * Calculate new counter offset for virtual port to grant continous + * counting on port switches. The virtual port consists of all currently + * active ports. The port down event indicates that a port is removed + * from the virtual port. Therefore add the counter value of the removed + * port to the CounterOffset for the virtual port to grant the same + * counter value. + */ + for (CounterIndex = 0; CounterIndex < SK_PNMI_MAX_IDX; + CounterIndex ++) { + + if (!StatAddr[CounterIndex][MacType].GetOffset) { + + continue; + } + + Value = GetPhysStatVal(pAC, IoC, PhysPortIndex, CounterIndex); + + pAC->Pnmi.VirtualCounterOffset[CounterIndex] += Value; + } + + /* + * Set port to inactive + */ + pAC->Pnmi.Port[PhysPortIndex].ActiveFlag = SK_FALSE; + + pAC->Pnmi.MacUpdatedFlag --; + break; + + case SK_PNMI_EVT_RLMT_ACTIVE_UP: + PhysPortIndex = (unsigned int)Param.Para32[0]; + NetIndex = (SK_U32)Param.Para32[1]; + +#ifdef DEBUG + if (PhysPortIndex >= SK_MAX_MACS) { + + SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL, + ("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_RLMT_ACTIVE_UP parameter too high, PhysPort=%d\n", + PhysPortIndex)); + } + + if (NetIndex >= pAC->Rlmt.NumNets) { + + SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL, + ("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_RLMT_ACTIVE_UP parameter too high, NetIndex=%d\n", + NetIndex)); + } +#endif /* DEBUG */ + + /* + * For now, ignore event if NetIndex != 0. + */ + if (Param.Para32[1] != 0) { + + return (0); + } + + /* + * Nothing to do if port is already active + */ + if (pAC->Pnmi.Port[PhysPortIndex].ActiveFlag) { + + return (0); + } + + /* + * Statistic maintenance + */ + pAC->Pnmi.RlmtChangeCts ++; + pAC->Pnmi.RlmtChangeTime = SK_PNMI_HUNDREDS_SEC(SkOsGetTime(pAC)); + + /* + * Store a trap message in the trap buffer and generate an event for + * user space applications with the SK_DRIVER_SENDEVENT macro. + */ + QueueRlmtNewMacTrap(pAC, PhysPortIndex); + (void)SK_DRIVER_SENDEVENT(pAC, IoC); + + /* + * Update statistic counters to calculate new offset for the virtual + * port and increment semaphore to indicate that an update was + * already done. + */ + if (MacUpdate(pAC, IoC, 0, pAC->GIni.GIMacsFound - 1) != + SK_PNMI_ERR_OK) { + + SK_PNMI_CHECKFLAGS("SkPnmiEvent: On return"); + return (0); + } + pAC->Pnmi.MacUpdatedFlag ++; + + /* + * Calculate new counter offset for virtual port to grant continous + * counting on port switches. A new port is added to the virtual port. + * Therefore substract the counter value of the new port from the + * CounterOffset for the virtual port to grant the same value. + */ + for (CounterIndex = 0; CounterIndex < SK_PNMI_MAX_IDX; + CounterIndex ++) { + + if (!StatAddr[CounterIndex][MacType].GetOffset) { + + continue; + } + + Value = GetPhysStatVal(pAC, IoC, PhysPortIndex, CounterIndex); + + pAC->Pnmi.VirtualCounterOffset[CounterIndex] -= Value; + } + + /* Set port to active */ + pAC->Pnmi.Port[PhysPortIndex].ActiveFlag = SK_TRUE; + + pAC->Pnmi.MacUpdatedFlag --; + break; + + case SK_PNMI_EVT_RLMT_SEGMENTATION: + /* + * Para.Para32[0] contains the NetIndex. + */ + + /* + * Store a trap message in the trap buffer and generate an event for + * user space applications with the SK_DRIVER_SENDEVENT macro. + */ + QueueSimpleTrap(pAC, OID_SKGE_TRAP_RLMT_SEGMENTATION); + (void)SK_DRIVER_SENDEVENT(pAC, IoC); + break; + + case SK_PNMI_EVT_RLMT_SET_NETS: + /* + * Param.Para32[0] contains the number of Nets. + * Param.Para32[1] is reserved, contains -1. + */ + /* + * Check number of nets + */ + MaxNetNumber = pAC->GIni.GIMacsFound; + if (((unsigned int)Param.Para32[0] < 1) + || ((unsigned int)Param.Para32[0] > MaxNetNumber)) { + return (SK_PNMI_ERR_UNKNOWN_NET); + } + + if ((unsigned int)Param.Para32[0] == 1) { /* single net mode */ + pAC->Pnmi.DualNetActiveFlag = SK_FALSE; + } + else { /* dual net mode */ + pAC->Pnmi.DualNetActiveFlag = SK_TRUE; + } + break; + + case SK_PNMI_EVT_VCT_RESET: + PhysPortIndex = Param.Para32[0]; + pPrt = &pAC->GIni.GP[PhysPortIndex]; + pVctBackupData = &pAC->Pnmi.VctBackup[PhysPortIndex]; + + if (pAC->Pnmi.VctStatus[PhysPortIndex] & SK_PNMI_VCT_PENDING) { + RetCode = SkGmCableDiagStatus(pAC, IoC, PhysPortIndex, SK_FALSE); + if (RetCode == 2) { + /* + * VCT test is still running. + * Start VCT timer counter again. + */ + SK_MEMSET((char *) &Param, 0, sizeof(Param)); + Param.Para32[0] = PhysPortIndex; + Param.Para32[1] = -1; + SkTimerStart(pAC, IoC, + &pAC->Pnmi.VctTimeout[PhysPortIndex].VctTimer, + 4000000, SKGE_PNMI, SK_PNMI_EVT_VCT_RESET, Param); + break; + } + pAC->Pnmi.VctStatus[PhysPortIndex] &= ~SK_PNMI_VCT_PENDING; + pAC->Pnmi.VctStatus[PhysPortIndex] |= + (SK_PNMI_VCT_NEW_VCT_DATA | SK_PNMI_VCT_TEST_DONE); + + /* Copy results for later use to PNMI struct. */ + for (i = 0; i < 4; i++) { + if (pPrt->PMdiPairSts[i] == SK_PNMI_VCT_NORMAL_CABLE) { + if ((pPrt->PMdiPairLen[i] > 35) && + (pPrt->PMdiPairLen[i] < 0xff)) { + pPrt->PMdiPairSts[i] = SK_PNMI_VCT_IMPEDANCE_MISMATCH; + } + } + if ((pPrt->PMdiPairLen[i] > 35) && + (pPrt->PMdiPairLen[i] != 0xff)) { + CableLength = 1000 * + (((175 * pPrt->PMdiPairLen[i]) / 210) - 28); + } + else { + CableLength = 0; + } + pVctBackupData->PMdiPairLen[i] = CableLength; + pVctBackupData->PMdiPairSts[i] = pPrt->PMdiPairSts[i]; + } + + Param.Para32[0] = PhysPortIndex; + Param.Para32[1] = -1; + SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_RESET, Param); + SkEventDispatcher(pAC, IoC); + } + + break; + + default: + break; + } + + SK_PNMI_CHECKFLAGS("SkPnmiEvent: On return"); + return (0); +} + + +/****************************************************************************** + * + * Private functions + * + */ + +/***************************************************************************** + * + * PnmiVar - Gets, presets, and sets single OIDs + * + * Description: + * Looks up the requested OID, calls the corresponding handler + * function, and passes the parameters with the get, preset, or + * set command. The function is called by SkGePnmiGetVar, + * SkGePnmiPreSetVar, or SkGePnmiSetVar. + * + * Returns: + * SK_PNMI_ERR_XXX. For details have a look at the description of the + * calling functions. + * SK_PNMI_ERR_UNKNOWN_NET The requested NetIndex doesn't exist + */ +PNMI_STATIC int PnmiVar( +SK_AC *pAC, /* Pointer to adapter context */ +SK_IOC IoC, /* IO context handle */ +int Action, /* GET/PRESET/SET action */ +SK_U32 Id, /* Object ID that is to be processed */ +char *pBuf, /* Buffer used for the management data transfer */ +unsigned int *pLen, /* Total length of pBuf management data */ +SK_U32 Instance, /* Instance (1..n) that is to be set or -1 */ +SK_U32 NetIndex) /* NetIndex (0..n), in single net mode always zero */ +{ + unsigned int TableIndex; + int Ret; + + + if ((TableIndex = LookupId(Id)) == (unsigned int)(-1)) { + + *pLen = 0; + return (SK_PNMI_ERR_UNKNOWN_OID); + } + + /* Check NetIndex */ + if (NetIndex >= pAC->Rlmt.NumNets) { + return (SK_PNMI_ERR_UNKNOWN_NET); + } + + SK_PNMI_CHECKFLAGS("PnmiVar: On call"); + + Ret = IdTable[TableIndex].Func(pAC, IoC, Action, Id, pBuf, pLen, + Instance, TableIndex, NetIndex); + + SK_PNMI_CHECKFLAGS("PnmiVar: On return"); + + return (Ret); +} + +/***************************************************************************** + * + * PnmiStruct - Presets and Sets data in structure SK_PNMI_STRUCT_DATA + * + * Description: + * The return value of the function will also be stored in + * SK_PNMI_STRUCT_DATA if the passed buffer has the minimum size of + * SK_PNMI_MIN_STRUCT_SIZE. The sub-function runs through the IdTable, + * checks which OIDs are able to set, and calls the handler function of + * the OID to perform the set. The return value of the function will + * also be stored in SK_PNMI_STRUCT_DATA if the passed buffer has the + * minimum size of SK_PNMI_MIN_STRUCT_SIZE. The function is called + * by SkGePnmiPreSetStruct and SkGePnmiSetStruct. + * + * Returns: + * SK_PNMI_ERR_XXX. The codes are described in the calling functions. + * SK_PNMI_ERR_UNKNOWN_NET The requested NetIndex doesn't exist + */ +PNMI_STATIC int PnmiStruct( +SK_AC *pAC, /* Pointer to adapter context */ +SK_IOC IoC, /* IO context handle */ +int Action, /* PRESET/SET action to be performed */ +char *pBuf, /* Buffer used for the management data transfer */ +unsigned int *pLen, /* Length of pBuf management data buffer */ +SK_U32 NetIndex) /* NetIndex (0..n), in single net mode always zero */ +{ + int Ret; + unsigned int TableIndex; + unsigned int DstOffset; + unsigned int Len; + unsigned int InstanceNo; + unsigned int InstanceCnt; + SK_U32 Instance; + SK_U32 Id; + + + /* Check if the passed buffer has the right size */ + if (*pLen < SK_PNMI_STRUCT_SIZE) { + + /* Check if we can return the error within the buffer */ + if (*pLen >= SK_PNMI_MIN_STRUCT_SIZE) { + + SK_PNMI_SET_STAT(pBuf, SK_PNMI_ERR_TOO_SHORT, + (SK_U32)(-1)); + } + + *pLen = SK_PNMI_STRUCT_SIZE; + return (SK_PNMI_ERR_TOO_SHORT); + } + + /* Check NetIndex */ + if (NetIndex >= pAC->Rlmt.NumNets) { + return (SK_PNMI_ERR_UNKNOWN_NET); + } + + SK_PNMI_CHECKFLAGS("PnmiStruct: On call"); + + /* + * Update the values of RLMT and SIRQ and increment semaphores to + * indicate that an update was already done. + */ + if ((Ret = RlmtUpdate(pAC, IoC, NetIndex)) != SK_PNMI_ERR_OK) { + + SK_PNMI_SET_STAT(pBuf, Ret, (SK_U32)(-1)); + *pLen = SK_PNMI_MIN_STRUCT_SIZE; + return (Ret); + } + + if ((Ret = SirqUpdate(pAC, IoC)) != SK_PNMI_ERR_OK) { + + SK_PNMI_SET_STAT(pBuf, Ret, (SK_U32)(-1)); + *pLen = SK_PNMI_MIN_STRUCT_SIZE; + return (Ret); + } + + pAC->Pnmi.RlmtUpdatedFlag ++; + pAC->Pnmi.SirqUpdatedFlag ++; + + /* Preset/Set values */ + for (TableIndex = 0; TableIndex < ID_TABLE_SIZE; TableIndex ++) { + + if ((IdTable[TableIndex].Access != SK_PNMI_RW) && + (IdTable[TableIndex].Access != SK_PNMI_WO)) { + + continue; + } + + InstanceNo = IdTable[TableIndex].InstanceNo; + Id = IdTable[TableIndex].Id; + + for (InstanceCnt = 1; InstanceCnt <= InstanceNo; + InstanceCnt ++) { + + DstOffset = IdTable[TableIndex].Offset + + (InstanceCnt - 1) * + IdTable[TableIndex].StructSize; + + /* + * Because VPD multiple instance variables are + * not setable we do not need to evaluate VPD + * instances. Have a look to VPD instance + * calculation in SkPnmiGetStruct(). + */ + Instance = (SK_U32)InstanceCnt; + + /* + * Evaluate needed buffer length + */ + Len = 0; + Ret = IdTable[TableIndex].Func(pAC, IoC, + SK_PNMI_GET, IdTable[TableIndex].Id, + NULL, &Len, Instance, TableIndex, NetIndex); + + if (Ret == SK_PNMI_ERR_UNKNOWN_INST) { + + break; + } + if (Ret != SK_PNMI_ERR_TOO_SHORT) { + + pAC->Pnmi.RlmtUpdatedFlag --; + pAC->Pnmi.SirqUpdatedFlag --; + + SK_PNMI_CHECKFLAGS("PnmiStruct: On return"); + SK_PNMI_SET_STAT(pBuf, + SK_PNMI_ERR_GENERAL, DstOffset); + *pLen = SK_PNMI_MIN_STRUCT_SIZE; + return (SK_PNMI_ERR_GENERAL); + } + if (Id == OID_SKGE_VPD_ACTION) { + + switch (*(pBuf + DstOffset)) { + + case SK_PNMI_VPD_CREATE: + Len = 3 + *(pBuf + DstOffset + 3); + break; + + case SK_PNMI_VPD_DELETE: + Len = 3; + break; + + default: + Len = 1; + break; + } + } + + /* Call the OID handler function */ + Ret = IdTable[TableIndex].Func(pAC, IoC, Action, + IdTable[TableIndex].Id, pBuf + DstOffset, + &Len, Instance, TableIndex, NetIndex); + + if (Ret != SK_PNMI_ERR_OK) { + + pAC->Pnmi.RlmtUpdatedFlag --; + pAC->Pnmi.SirqUpdatedFlag --; + + SK_PNMI_CHECKFLAGS("PnmiStruct: On return"); + SK_PNMI_SET_STAT(pBuf, SK_PNMI_ERR_BAD_VALUE, + DstOffset); + *pLen = SK_PNMI_MIN_STRUCT_SIZE; + return (SK_PNMI_ERR_BAD_VALUE); + } + } + } + + pAC->Pnmi.RlmtUpdatedFlag --; + pAC->Pnmi.SirqUpdatedFlag --; + + SK_PNMI_CHECKFLAGS("PnmiStruct: On return"); + SK_PNMI_SET_STAT(pBuf, SK_PNMI_ERR_OK, (SK_U32)(-1)); + return (SK_PNMI_ERR_OK); +} + +/***************************************************************************** + * + * LookupId - Lookup an OID in the IdTable + * + * Description: + * Scans the IdTable to find the table entry of an OID. + * + * Returns: + * The table index or -1 if not found. + */ +PNMI_STATIC int LookupId( +SK_U32 Id) /* Object identifier to be searched */ +{ + int i; + + for (i = 0; i < ID_TABLE_SIZE; i++) { + + if (IdTable[i].Id == Id) { + + return i; + } + } + + return (-1); +} + +/***************************************************************************** + * + * OidStruct - Handler of OID_SKGE_ALL_DATA + * + * Description: + * This OID performs a Get/Preset/SetStruct call and returns all data + * in a SK_PNMI_STRUCT_DATA structure. + * + * Returns: + * SK_PNMI_ERR_OK The request was successfully performed. + * SK_PNMI_ERR_GENERAL A general severe internal error occured. + * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain + * the correct data (e.g. a 32bit value is + * needed, but a 16 bit value was passed). + * SK_PNMI_ERR_BAD_VALUE The passed value is not in the valid + * value range. + * SK_PNMI_ERR_READ_ONLY The OID is read-only and cannot be set. + * SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't + * exist (e.g. port instance 3 on a two port + * adapter. + */ +PNMI_STATIC int OidStruct( +SK_AC *pAC, /* Pointer to adapter context */ +SK_IOC IoC, /* IO context handle */ +int Action, /* GET/PRESET/SET action */ +SK_U32 Id, /* Object ID that is to be processed */ +char *pBuf, /* Buffer used for the management data transfer */ +unsigned int *pLen, /* On call: pBuf buffer length. On return: used buffer */ +SK_U32 Instance, /* Instance (1..n) that is to be queried or -1 */ +unsigned int TableIndex, /* Index to the Id table */ +SK_U32 NetIndex) /* NetIndex (0..n), in single net mode always zero */ +{ + if (Id != OID_SKGE_ALL_DATA) { + + SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR003, + SK_PNMI_ERR003MSG); + + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + + /* + * Check instance. We only handle single instance variables + */ + if (Instance != (SK_U32)(-1) && Instance != 1) { + + *pLen = 0; + return (SK_PNMI_ERR_UNKNOWN_INST); + } + + switch (Action) { + + case SK_PNMI_GET: + return (SkPnmiGetStruct(pAC, IoC, pBuf, pLen, NetIndex)); + + case SK_PNMI_PRESET: + return (SkPnmiPreSetStruct(pAC, IoC, pBuf, pLen, NetIndex)); + + case SK_PNMI_SET: + return (SkPnmiSetStruct(pAC, IoC, pBuf, pLen, NetIndex)); + } + + SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR004, SK_PNMI_ERR004MSG); + + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); +} + +/***************************************************************************** + * + * Perform - OID handler of OID_SKGE_ACTION + * + * Description: + * None. + * + * Returns: + * SK_PNMI_ERR_OK The request was successfully performed. + * SK_PNMI_ERR_GENERAL A general severe internal error occured. + * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain + * the correct data (e.g. a 32bit value is + * needed, but a 16 bit value was passed). + * SK_PNMI_ERR_BAD_VALUE The passed value is not in the valid + * value range. + * SK_PNMI_ERR_READ_ONLY The OID is read-only and cannot be set. + * SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't + * exist (e.g. port instance 3 on a two port + * adapter. + */ +PNMI_STATIC int Perform( +SK_AC *pAC, /* Pointer to adapter context */ +SK_IOC IoC, /* IO context handle */ +int Action, /* GET/PRESET/SET action */ +SK_U32 Id, /* Object ID that is to be processed */ +char *pBuf, /* Buffer used for the management data transfer */ +unsigned int *pLen, /* On call: pBuf buffer length. On return: used buffer */ +SK_U32 Instance, /* Instance (1..n) that is to be queried or -1 */ +unsigned int TableIndex, /* Index to the Id table */ +SK_U32 NetIndex) /* NetIndex (0..n), in single net mode always zero */ +{ + int Ret; + SK_U32 ActionOp; + + + /* + * Check instance. We only handle single instance variables + */ + if (Instance != (SK_U32)(-1) && Instance != 1) { + + *pLen = 0; + return (SK_PNMI_ERR_UNKNOWN_INST); + } + + if (*pLen < sizeof(SK_U32)) { + + *pLen = sizeof(SK_U32); + return (SK_PNMI_ERR_TOO_SHORT); + } + + /* Check if a get should be performed */ + if (Action == SK_PNMI_GET) { + + /* A get is easy. We always return the same value */ + ActionOp = (SK_U32)SK_PNMI_ACT_IDLE; + SK_PNMI_STORE_U32(pBuf, ActionOp); + *pLen = sizeof(SK_U32); + + return (SK_PNMI_ERR_OK); + } + + /* Continue with PRESET/SET action */ + if (*pLen > sizeof(SK_U32)) { + + return (SK_PNMI_ERR_BAD_VALUE); + } + + /* Check if the command is a known one */ + SK_PNMI_READ_U32(pBuf, ActionOp); + if (*pLen > sizeof(SK_U32) || + (ActionOp != SK_PNMI_ACT_IDLE && + ActionOp != SK_PNMI_ACT_RESET && + ActionOp != SK_PNMI_ACT_SELFTEST && + ActionOp != SK_PNMI_ACT_RESETCNT)) { + + *pLen = 0; + return (SK_PNMI_ERR_BAD_VALUE); + } + + /* A preset ends here */ + if (Action == SK_PNMI_PRESET) { + + return (SK_PNMI_ERR_OK); + } + + switch (ActionOp) { + + case SK_PNMI_ACT_IDLE: + /* Nothing to do */ + break; + + case SK_PNMI_ACT_RESET: + /* + * Perform a driver reset or something that comes near + * to this. + */ + Ret = SK_DRIVER_RESET(pAC, IoC); + if (Ret != 0) { + + SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR005, + SK_PNMI_ERR005MSG); + + return (SK_PNMI_ERR_GENERAL); + } + break; + + case SK_PNMI_ACT_SELFTEST: + /* + * Perform a driver selftest or something similar to this. + * Currently this feature is not used and will probably + * implemented in another way. + */ + Ret = SK_DRIVER_SELFTEST(pAC, IoC); + pAC->Pnmi.TestResult = Ret; + break; + + case SK_PNMI_ACT_RESETCNT: + /* Set all counters and timestamps to zero */ + ResetCounter(pAC, IoC, NetIndex); + break; + + default: + SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR006, + SK_PNMI_ERR006MSG); + + return (SK_PNMI_ERR_GENERAL); + } + + return (SK_PNMI_ERR_OK); +} + +/***************************************************************************** + * + * Mac8023Stat - OID handler of OID_GEN_XXX and OID_802_3_XXX + * + * Description: + * Retrieves the statistic values of the virtual port (logical + * index 0). Only special OIDs of NDIS are handled which consist + * of a 32 bit instead of a 64 bit value. The OIDs are public + * because perhaps some other platform can use them too. + * + * Returns: + * SK_PNMI_ERR_OK The request was successfully performed. + * SK_PNMI_ERR_GENERAL A general severe internal error occured. + * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain + * the correct data (e.g. a 32bit value is + * needed, but a 16 bit value was passed). + * SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't + * exist (e.g. port instance 3 on a two port + * adapter. + */ +PNMI_STATIC int Mac8023Stat( +SK_AC *pAC, /* Pointer to adapter context */ +SK_IOC IoC, /* IO context handle */ +int Action, /* GET/PRESET/SET action */ +SK_U32 Id, /* Object ID that is to be processed */ +char *pBuf, /* Buffer used for the management data transfer */ +unsigned int *pLen, /* On call: pBuf buffer length. On return: used buffer */ +SK_U32 Instance, /* Instance (1..n) that is to be queried or -1 */ +unsigned int TableIndex, /* Index to the Id table */ +SK_U32 NetIndex) /* NetIndex (0..n), in single net mode always zero */ +{ + int Ret; + SK_U64 StatVal; + SK_U32 StatVal32; + SK_BOOL Is64BitReq = SK_FALSE; + + /* + * Only the active Mac is returned + */ + if (Instance != (SK_U32)(-1) && Instance != 1) { + + *pLen = 0; + return (SK_PNMI_ERR_UNKNOWN_INST); + } + + /* + * Check action type + */ + if (Action != SK_PNMI_GET) { + + *pLen = 0; + return (SK_PNMI_ERR_READ_ONLY); + } + + /* Check length */ + switch (Id) { + + case OID_802_3_PERMANENT_ADDRESS: + case OID_802_3_CURRENT_ADDRESS: + if (*pLen < sizeof(SK_MAC_ADDR)) { + + *pLen = sizeof(SK_MAC_ADDR); + return (SK_PNMI_ERR_TOO_SHORT); + } + break; + + default: +#ifndef SK_NDIS_64BIT_CTR + if (*pLen < sizeof(SK_U32)) { + *pLen = sizeof(SK_U32); + return (SK_PNMI_ERR_TOO_SHORT); + } + +#else /* SK_NDIS_64BIT_CTR */ + + /* for compatibility, at least 32bit are required for OID */ + if (*pLen < sizeof(SK_U32)) { + /* + * but indicate handling for 64bit values, + * if insufficient space is provided + */ + *pLen = sizeof(SK_U64); + return (SK_PNMI_ERR_TOO_SHORT); + } + + Is64BitReq = (*pLen < sizeof(SK_U64)) ? SK_FALSE : SK_TRUE; +#endif /* SK_NDIS_64BIT_CTR */ + break; + } + + /* + * Update all statistics, because we retrieve virtual MAC, which + * consists of multiple physical statistics and increment semaphore + * to indicate that an update was already done. + */ + Ret = MacUpdate(pAC, IoC, 0, pAC->GIni.GIMacsFound - 1); + if ( Ret != SK_PNMI_ERR_OK) { + + *pLen = 0; + return (Ret); + } + pAC->Pnmi.MacUpdatedFlag ++; + + /* + * Get value (MAC Index 0 identifies the virtual MAC) + */ + switch (Id) { + + case OID_802_3_PERMANENT_ADDRESS: + CopyMac(pBuf, &pAC->Addr.Net[NetIndex].PermanentMacAddress); + *pLen = sizeof(SK_MAC_ADDR); + break; + + case OID_802_3_CURRENT_ADDRESS: + CopyMac(pBuf, &pAC->Addr.Net[NetIndex].CurrentMacAddress); + *pLen = sizeof(SK_MAC_ADDR); + break; + + default: + StatVal = GetStatVal(pAC, IoC, 0, IdTable[TableIndex].Param, NetIndex); + + /* by default 32bit values are evaluated */ + if (!Is64BitReq) { + StatVal32 = (SK_U32)StatVal; + SK_PNMI_STORE_U32(pBuf, StatVal32); + *pLen = sizeof(SK_U32); + } + else { + SK_PNMI_STORE_U64(pBuf, StatVal); + *pLen = sizeof(SK_U64); + } + break; + } + + pAC->Pnmi.MacUpdatedFlag --; + + return (SK_PNMI_ERR_OK); +} + +/***************************************************************************** + * + * MacPrivateStat - OID handler function of OID_SKGE_STAT_XXX + * + * Description: + * Retrieves the MAC statistic data. + * + * Returns: + * SK_PNMI_ERR_OK The request was successfully performed. + * SK_PNMI_ERR_GENERAL A general severe internal error occured. + * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain + * the correct data (e.g. a 32bit value is + * needed, but a 16 bit value was passed). + * SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't + * exist (e.g. port instance 3 on a two port + * adapter. + */ +PNMI_STATIC int MacPrivateStat( +SK_AC *pAC, /* Pointer to adapter context */ +SK_IOC IoC, /* IO context handle */ +int Action, /* GET/PRESET/SET action */ +SK_U32 Id, /* Object ID that is to be processed */ +char *pBuf, /* Buffer used for the management data transfer */ +unsigned int *pLen, /* On call: pBuf buffer length. On return: used buffer */ +SK_U32 Instance, /* Instance (1..n) that is to be queried or -1 */ +unsigned int TableIndex, /* Index to the Id table */ +SK_U32 NetIndex) /* NetIndex (0..n), in single net mode always zero */ +{ + unsigned int LogPortMax; + unsigned int LogPortIndex; + unsigned int PhysPortMax; + unsigned int Limit; + unsigned int Offset; + int MacType; + int Ret; + SK_U64 StatVal; + + + + /* Calculate instance if wished. MAC index 0 is the virtual MAC */ + PhysPortMax = pAC->GIni.GIMacsFound; + LogPortMax = SK_PNMI_PORT_PHYS2LOG(PhysPortMax); + + MacType = pAC->GIni.GIMacType; + + if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) { /* Dual net mode */ + LogPortMax--; + } + + if ((Instance != (SK_U32)(-1))) { /* Only one specific instance is queried */ + /* Check instance range */ + if ((Instance < 1) || (Instance > LogPortMax)) { + + *pLen = 0; + return (SK_PNMI_ERR_UNKNOWN_INST); + } + LogPortIndex = SK_PNMI_PORT_INST2LOG(Instance); + Limit = LogPortIndex + 1; + } + + else { /* Instance == (SK_U32)(-1), get all Instances of that OID */ + + LogPortIndex = 0; + Limit = LogPortMax; + } + + /* Check action */ + if (Action != SK_PNMI_GET) { + + *pLen = 0; + return (SK_PNMI_ERR_READ_ONLY); + } + + /* Check length */ + if (*pLen < (Limit - LogPortIndex) * sizeof(SK_U64)) { + + *pLen = (Limit - LogPortIndex) * sizeof(SK_U64); + return (SK_PNMI_ERR_TOO_SHORT); + } + + /* + * Update MAC statistic and increment semaphore to indicate that + * an update was already done. + */ + Ret = MacUpdate(pAC, IoC, 0, pAC->GIni.GIMacsFound - 1); + if (Ret != SK_PNMI_ERR_OK) { + + *pLen = 0; + return (Ret); + } + pAC->Pnmi.MacUpdatedFlag ++; + + /* Get value */ + Offset = 0; + for (; LogPortIndex < Limit; LogPortIndex ++) { + + switch (Id) { + +/* XXX not yet implemented due to XMAC problems + case OID_SKGE_STAT_TX_UTIL: + return (SK_PNMI_ERR_GENERAL); +*/ +/* XXX not yet implemented due to XMAC problems + case OID_SKGE_STAT_RX_UTIL: + return (SK_PNMI_ERR_GENERAL); +*/ + case OID_SKGE_STAT_RX: + if (MacType == SK_MAC_GMAC) { + StatVal = + GetStatVal(pAC, IoC, LogPortIndex, + SK_PNMI_HRX_BROADCAST, NetIndex) + + GetStatVal(pAC, IoC, LogPortIndex, + SK_PNMI_HRX_MULTICAST, NetIndex) + + GetStatVal(pAC, IoC, LogPortIndex, + SK_PNMI_HRX_UNICAST, NetIndex) + + GetStatVal(pAC, IoC, LogPortIndex, + SK_PNMI_HRX_UNDERSIZE, NetIndex); + } + else { + StatVal = GetStatVal(pAC, IoC, LogPortIndex, + IdTable[TableIndex].Param, NetIndex); + } + break; + + case OID_SKGE_STAT_TX: + if (MacType == SK_MAC_GMAC) { + StatVal = + GetStatVal(pAC, IoC, LogPortIndex, + SK_PNMI_HTX_BROADCAST, NetIndex) + + GetStatVal(pAC, IoC, LogPortIndex, + SK_PNMI_HTX_MULTICAST, NetIndex) + + GetStatVal(pAC, IoC, LogPortIndex, + SK_PNMI_HTX_UNICAST, NetIndex); + } + else { + StatVal = GetStatVal(pAC, IoC, LogPortIndex, + IdTable[TableIndex].Param, NetIndex); + } + break; + + default: + StatVal = GetStatVal(pAC, IoC, LogPortIndex, + IdTable[TableIndex].Param, NetIndex); + } + SK_PNMI_STORE_U64(pBuf + Offset, StatVal); + + Offset += sizeof(SK_U64); + } + *pLen = Offset; + + pAC->Pnmi.MacUpdatedFlag --; + + return (SK_PNMI_ERR_OK); +} + +/***************************************************************************** + * + * Addr - OID handler function of OID_SKGE_PHYS_CUR_ADDR and _FAC_ADDR + * + * Description: + * Get/Presets/Sets the current and factory MAC address. The MAC + * address of the virtual port, which is reported to the OS, may + * not be changed, but the physical ones. A set to the virtual port + * will be ignored. No error should be reported because otherwise + * a multiple instance set (-1) would always fail. + * + * Returns: + * SK_PNMI_ERR_OK The request was successfully performed. + * SK_PNMI_ERR_GENERAL A general severe internal error occured. + * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain + * the correct data (e.g. a 32bit value is + * needed, but a 16 bit value was passed). + * SK_PNMI_ERR_BAD_VALUE The passed value is not in the valid + * value range. + * SK_PNMI_ERR_READ_ONLY The OID is read-only and cannot be set. + * SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't + * exist (e.g. port instance 3 on a two port + * adapter. + */ +PNMI_STATIC int Addr( +SK_AC *pAC, /* Pointer to adapter context */ +SK_IOC IoC, /* IO context handle */ +int Action, /* GET/PRESET/SET action */ +SK_U32 Id, /* Object ID that is to be processed */ +char *pBuf, /* Buffer used for the management data transfer */ +unsigned int *pLen, /* On call: pBuf buffer length. On return: used buffer */ +SK_U32 Instance, /* Instance (1..n) that is to be queried or -1 */ +unsigned int TableIndex, /* Index to the Id table */ +SK_U32 NetIndex) /* NetIndex (0..n), in single net mode always zero */ +{ + int Ret; + unsigned int LogPortMax; + unsigned int PhysPortMax; + unsigned int LogPortIndex; + unsigned int PhysPortIndex; + unsigned int Limit; + unsigned int Offset = 0; + + /* + * Calculate instance if wished. MAC index 0 is the virtual + * MAC. + */ + PhysPortMax = pAC->GIni.GIMacsFound; + LogPortMax = SK_PNMI_PORT_PHYS2LOG(PhysPortMax); + + if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) { /* Dual net mode */ + LogPortMax--; + } + + if ((Instance != (SK_U32)(-1))) { /* Only one specific instance is queried */ + /* Check instance range */ + if ((Instance < 1) || (Instance > LogPortMax)) { + + *pLen = 0; + return (SK_PNMI_ERR_UNKNOWN_INST); + } + LogPortIndex = SK_PNMI_PORT_INST2LOG(Instance); + Limit = LogPortIndex + 1; + } + else { /* Instance == (SK_U32)(-1), get all Instances of that OID */ + + LogPortIndex = 0; + Limit = LogPortMax; + } + + /* + * Perform Action + */ + if (Action == SK_PNMI_GET) { + + /* Check length */ + if (*pLen < (Limit - LogPortIndex) * 6) { + + *pLen = (Limit - LogPortIndex) * 6; + return (SK_PNMI_ERR_TOO_SHORT); + } + + /* + * Get value + */ + for (; LogPortIndex < Limit; LogPortIndex ++) { + + switch (Id) { + + case OID_SKGE_PHYS_CUR_ADDR: + if (LogPortIndex == 0) { + CopyMac(pBuf + Offset, &pAC->Addr.Net[NetIndex].CurrentMacAddress); + } + else { + PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(pAC, LogPortIndex); + + CopyMac(pBuf + Offset, + &pAC->Addr.Port[PhysPortIndex].CurrentMacAddress); + } + Offset += 6; + break; + + case OID_SKGE_PHYS_FAC_ADDR: + if (LogPortIndex == 0) { + CopyMac(pBuf + Offset, + &pAC->Addr.Net[NetIndex].PermanentMacAddress); + } + else { + PhysPortIndex = SK_PNMI_PORT_LOG2PHYS( + pAC, LogPortIndex); + + CopyMac(pBuf + Offset, + &pAC->Addr.Port[PhysPortIndex].PermanentMacAddress); + } + Offset += 6; + break; + + default: + SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR008, + SK_PNMI_ERR008MSG); + + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + } + + *pLen = Offset; + } + else { + /* + * The logical MAC address may not be changed only + * the physical ones + */ + if (Id == OID_SKGE_PHYS_FAC_ADDR) { + + *pLen = 0; + return (SK_PNMI_ERR_READ_ONLY); + } + + /* + * Only the current address may be changed + */ + if (Id != OID_SKGE_PHYS_CUR_ADDR) { + + SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR009, + SK_PNMI_ERR009MSG); + + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + + /* Check length */ + if (*pLen < (Limit - LogPortIndex) * 6) { + + *pLen = (Limit - LogPortIndex) * 6; + return (SK_PNMI_ERR_TOO_SHORT); + } + if (*pLen > (Limit - LogPortIndex) * 6) { + + *pLen = 0; + return (SK_PNMI_ERR_BAD_VALUE); + } + + /* + * Check Action + */ + if (Action == SK_PNMI_PRESET) { + + *pLen = 0; + return (SK_PNMI_ERR_OK); + } + + /* + * Set OID_SKGE_MAC_CUR_ADDR + */ + for (; LogPortIndex < Limit; LogPortIndex ++, Offset += 6) { + + /* + * A set to virtual port and set of broadcast + * address will be ignored + */ + if (LogPortIndex == 0 || SK_MEMCMP(pBuf + Offset, + "\xff\xff\xff\xff\xff\xff", 6) == 0) { + + continue; + } + + PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(pAC, + LogPortIndex); + + Ret = SkAddrOverride(pAC, IoC, PhysPortIndex, + (SK_MAC_ADDR *)(pBuf + Offset), + (LogPortIndex == 0 ? SK_ADDR_VIRTUAL_ADDRESS : + SK_ADDR_PHYSICAL_ADDRESS)); + if (Ret != SK_ADDR_OVERRIDE_SUCCESS) { + + return (SK_PNMI_ERR_GENERAL); + } + } + *pLen = Offset; + } + + return (SK_PNMI_ERR_OK); +} + +/***************************************************************************** + * + * CsumStat - OID handler function of OID_SKGE_CHKSM_XXX + * + * Description: + * Retrieves the statistic values of the CSUM module. The CSUM data + * structure must be available in the SK_AC even if the CSUM module + * is not included, because PNMI reads the statistic data from the + * CSUM part of SK_AC directly. + * + * Returns: + * SK_PNMI_ERR_OK The request was successfully performed. + * SK_PNMI_ERR_GENERAL A general severe internal error occured. + * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain + * the correct data (e.g. a 32bit value is + * needed, but a 16 bit value was passed). + * SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't + * exist (e.g. port instance 3 on a two port + * adapter. + */ +PNMI_STATIC int CsumStat( +SK_AC *pAC, /* Pointer to adapter context */ +SK_IOC IoC, /* IO context handle */ +int Action, /* GET/PRESET/SET action */ +SK_U32 Id, /* Object ID that is to be processed */ +char *pBuf, /* Buffer used for the management data transfer */ +unsigned int *pLen, /* On call: pBuf buffer length. On return: used buffer */ +SK_U32 Instance, /* Instance (1..n) that is to be queried or -1 */ +unsigned int TableIndex, /* Index to the Id table */ +SK_U32 NetIndex) /* NetIndex (0..n), in single net mode always zero */ +{ + unsigned int Index; + unsigned int Limit; + unsigned int Offset = 0; + SK_U64 StatVal; + + + /* + * Calculate instance if wished + */ + if (Instance != (SK_U32)(-1)) { + + if ((Instance < 1) || (Instance > SKCS_NUM_PROTOCOLS)) { + + *pLen = 0; + return (SK_PNMI_ERR_UNKNOWN_INST); + } + Index = (unsigned int)Instance - 1; + Limit = Index + 1; + } + else { + Index = 0; + Limit = SKCS_NUM_PROTOCOLS; + } + + /* + * Check action + */ + if (Action != SK_PNMI_GET) { + + *pLen = 0; + return (SK_PNMI_ERR_READ_ONLY); + } + + /* Check length */ + if (*pLen < (Limit - Index) * sizeof(SK_U64)) { + + *pLen = (Limit - Index) * sizeof(SK_U64); + return (SK_PNMI_ERR_TOO_SHORT); + } + + /* + * Get value + */ + for (; Index < Limit; Index ++) { + + switch (Id) { + + case OID_SKGE_CHKSM_RX_OK_CTS: + StatVal = pAC->Csum.ProtoStats[NetIndex][Index].RxOkCts; + break; + + case OID_SKGE_CHKSM_RX_UNABLE_CTS: + StatVal = pAC->Csum.ProtoStats[NetIndex][Index].RxUnableCts; + break; + + case OID_SKGE_CHKSM_RX_ERR_CTS: + StatVal = pAC->Csum.ProtoStats[NetIndex][Index].RxErrCts; + break; + + case OID_SKGE_CHKSM_TX_OK_CTS: + StatVal = pAC->Csum.ProtoStats[NetIndex][Index].TxOkCts; + break; + + case OID_SKGE_CHKSM_TX_UNABLE_CTS: + StatVal = pAC->Csum.ProtoStats[NetIndex][Index].TxUnableCts; + break; + + default: + SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR010, + SK_PNMI_ERR010MSG); + + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + + SK_PNMI_STORE_U64(pBuf + Offset, StatVal); + Offset += sizeof(SK_U64); + } + + /* + * Store used buffer space + */ + *pLen = Offset; + + return (SK_PNMI_ERR_OK); +} + +/***************************************************************************** + * + * SensorStat - OID handler function of OID_SKGE_SENSOR_XXX + * + * Description: + * Retrieves the statistic values of the I2C module, which handles + * the temperature and voltage sensors. + * + * Returns: + * SK_PNMI_ERR_OK The request was successfully performed. + * SK_PNMI_ERR_GENERAL A general severe internal error occured. + * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain + * the correct data (e.g. a 32bit value is + * needed, but a 16 bit value was passed). + * SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't + * exist (e.g. port instance 3 on a two port + * adapter. + */ +PNMI_STATIC int SensorStat( +SK_AC *pAC, /* Pointer to adapter context */ +SK_IOC IoC, /* IO context handle */ +int Action, /* GET/PRESET/SET action */ +SK_U32 Id, /* Object ID that is to be processed */ +char *pBuf, /* Buffer used for the management data transfer */ +unsigned int *pLen, /* On call: pBuf buffer length. On return: used buffer */ +SK_U32 Instance, /* Instance (1..n) that is to be queried or -1 */ +unsigned int TableIndex, /* Index to the Id table */ +SK_U32 NetIndex) /* NetIndex (0..n), in single net mode always zero */ +{ + unsigned int i; + unsigned int Index; + unsigned int Limit; + unsigned int Offset; + unsigned int Len; + SK_U32 Val32; + SK_U64 Val64; + + + /* + * Calculate instance if wished + */ + if ((Instance != (SK_U32)(-1))) { + + if ((Instance < 1) || (Instance > (SK_U32)pAC->I2c.MaxSens)) { + + *pLen = 0; + return (SK_PNMI_ERR_UNKNOWN_INST); + } + + Index = (unsigned int)Instance -1; + Limit = (unsigned int)Instance; + } + else { + Index = 0; + Limit = (unsigned int) pAC->I2c.MaxSens; + } + + /* + * Check action + */ + if (Action != SK_PNMI_GET) { + + *pLen = 0; + return (SK_PNMI_ERR_READ_ONLY); + } + + /* Check length */ + switch (Id) { + + case OID_SKGE_SENSOR_VALUE: + case OID_SKGE_SENSOR_WAR_THRES_LOW: + case OID_SKGE_SENSOR_WAR_THRES_UPP: + case OID_SKGE_SENSOR_ERR_THRES_LOW: + case OID_SKGE_SENSOR_ERR_THRES_UPP: + if (*pLen < (Limit - Index) * sizeof(SK_U32)) { + + *pLen = (Limit - Index) * sizeof(SK_U32); + return (SK_PNMI_ERR_TOO_SHORT); + } + break; + + case OID_SKGE_SENSOR_DESCR: + for (Offset = 0, i = Index; i < Limit; i ++) { + + Len = (unsigned int) + SK_STRLEN(pAC->I2c.SenTable[i].SenDesc) + 1; + if (Len >= SK_PNMI_STRINGLEN2) { + + SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR011, + SK_PNMI_ERR011MSG); + + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + Offset += Len; + } + if (*pLen < Offset) { + + *pLen = Offset; + return (SK_PNMI_ERR_TOO_SHORT); + } + break; + + case OID_SKGE_SENSOR_INDEX: + case OID_SKGE_SENSOR_TYPE: + case OID_SKGE_SENSOR_STATUS: + if (*pLen < Limit - Index) { + + *pLen = Limit - Index; + return (SK_PNMI_ERR_TOO_SHORT); + } + break; + + case OID_SKGE_SENSOR_WAR_CTS: + case OID_SKGE_SENSOR_WAR_TIME: + case OID_SKGE_SENSOR_ERR_CTS: + case OID_SKGE_SENSOR_ERR_TIME: + if (*pLen < (Limit - Index) * sizeof(SK_U64)) { + + *pLen = (Limit - Index) * sizeof(SK_U64); + return (SK_PNMI_ERR_TOO_SHORT); + } + break; + + default: + SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR012, + SK_PNMI_ERR012MSG); + + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + + } + + /* + * Get value + */ + for (Offset = 0; Index < Limit; Index ++) { + + switch (Id) { + + case OID_SKGE_SENSOR_INDEX: + *(pBuf + Offset) = (char)Index; + Offset += sizeof(char); + break; + + case OID_SKGE_SENSOR_DESCR: + Len = SK_STRLEN(pAC->I2c.SenTable[Index].SenDesc); + SK_MEMCPY(pBuf + Offset + 1, + pAC->I2c.SenTable[Index].SenDesc, Len); + *(pBuf + Offset) = (char)Len; + Offset += Len + 1; + break; + + case OID_SKGE_SENSOR_TYPE: + *(pBuf + Offset) = + (char)pAC->I2c.SenTable[Index].SenType; + Offset += sizeof(char); + break; + + case OID_SKGE_SENSOR_VALUE: + Val32 = (SK_U32)pAC->I2c.SenTable[Index].SenValue; + SK_PNMI_STORE_U32(pBuf + Offset, Val32); + Offset += sizeof(SK_U32); + break; + + case OID_SKGE_SENSOR_WAR_THRES_LOW: + Val32 = (SK_U32)pAC->I2c.SenTable[Index]. + SenThreWarnLow; + SK_PNMI_STORE_U32(pBuf + Offset, Val32); + Offset += sizeof(SK_U32); + break; + + case OID_SKGE_SENSOR_WAR_THRES_UPP: + Val32 = (SK_U32)pAC->I2c.SenTable[Index]. + SenThreWarnHigh; + SK_PNMI_STORE_U32(pBuf + Offset, Val32); + Offset += sizeof(SK_U32); + break; + + case OID_SKGE_SENSOR_ERR_THRES_LOW: + Val32 = (SK_U32)pAC->I2c.SenTable[Index]. + SenThreErrLow; + SK_PNMI_STORE_U32(pBuf + Offset, Val32); + Offset += sizeof(SK_U32); + break; + + case OID_SKGE_SENSOR_ERR_THRES_UPP: + Val32 = pAC->I2c.SenTable[Index].SenThreErrHigh; + SK_PNMI_STORE_U32(pBuf + Offset, Val32); + Offset += sizeof(SK_U32); + break; + + case OID_SKGE_SENSOR_STATUS: + *(pBuf + Offset) = + (char)pAC->I2c.SenTable[Index].SenErrFlag; + Offset += sizeof(char); + break; + + case OID_SKGE_SENSOR_WAR_CTS: + Val64 = pAC->I2c.SenTable[Index].SenWarnCts; + SK_PNMI_STORE_U64(pBuf + Offset, Val64); + Offset += sizeof(SK_U64); + break; + + case OID_SKGE_SENSOR_ERR_CTS: + Val64 = pAC->I2c.SenTable[Index].SenErrCts; + SK_PNMI_STORE_U64(pBuf + Offset, Val64); + Offset += sizeof(SK_U64); + break; + + case OID_SKGE_SENSOR_WAR_TIME: + Val64 = SK_PNMI_HUNDREDS_SEC(pAC->I2c.SenTable[Index]. + SenBegWarnTS); + SK_PNMI_STORE_U64(pBuf + Offset, Val64); + Offset += sizeof(SK_U64); + break; + + case OID_SKGE_SENSOR_ERR_TIME: + Val64 = SK_PNMI_HUNDREDS_SEC(pAC->I2c.SenTable[Index]. + SenBegErrTS); + SK_PNMI_STORE_U64(pBuf + Offset, Val64); + Offset += sizeof(SK_U64); + break; + + default: + SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_ERR, + ("SensorStat: Unknown OID should be handled before")); + + return (SK_PNMI_ERR_GENERAL); + } + } + + /* + * Store used buffer space + */ + *pLen = Offset; + + return (SK_PNMI_ERR_OK); +} + +/***************************************************************************** + * + * Vpd - OID handler function of OID_SKGE_VPD_XXX + * + * Description: + * Get/preset/set of VPD data. As instance the name of a VPD key + * can be passed. The Instance parameter is a SK_U32 and can be + * used as a string buffer for the VPD key, because their maximum + * length is 4 byte. + * + * Returns: + * SK_PNMI_ERR_OK The request was successfully performed. + * SK_PNMI_ERR_GENERAL A general severe internal error occured. + * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain + * the correct data (e.g. a 32bit value is + * needed, but a 16 bit value was passed). + * SK_PNMI_ERR_BAD_VALUE The passed value is not in the valid + * value range. + * SK_PNMI_ERR_READ_ONLY The OID is read-only and cannot be set. + * SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't + * exist (e.g. port instance 3 on a two port + * adapter. + */ +PNMI_STATIC int Vpd( +SK_AC *pAC, /* Pointer to adapter context */ +SK_IOC IoC, /* IO context handle */ +int Action, /* GET/PRESET/SET action */ +SK_U32 Id, /* Object ID that is to be processed */ +char *pBuf, /* Buffer used for the management data transfer */ +unsigned int *pLen, /* On call: pBuf buffer length. On return: used buffer */ +SK_U32 Instance, /* Instance (1..n) that is to be queried or -1 */ +unsigned int TableIndex, /* Index to the Id table */ +SK_U32 NetIndex) /* NetIndex (0..n), in single net mode always zero */ +{ + SK_VPD_STATUS *pVpdStatus; + unsigned int BufLen; + char Buf[256]; + char KeyArr[SK_PNMI_VPD_ENTRIES][SK_PNMI_VPD_KEY_SIZE]; + char KeyStr[SK_PNMI_VPD_KEY_SIZE]; + unsigned int KeyNo; + unsigned int Offset; + unsigned int Index; + unsigned int FirstIndex; + unsigned int LastIndex; + unsigned int Len; + int Ret; + SK_U32 Val32; + + /* + * Get array of all currently stored VPD keys + */ + Ret = GetVpdKeyArr(pAC, IoC, &KeyArr[0][0], sizeof(KeyArr), &KeyNo); + if (Ret != SK_PNMI_ERR_OK) { + *pLen = 0; + return (Ret); + } + + /* + * If instance is not -1, try to find the requested VPD key for + * the multiple instance variables. The other OIDs as for example + * OID VPD_ACTION are single instance variables and must be + * handled separatly. + */ + FirstIndex = 0; + LastIndex = KeyNo; + + if ((Instance != (SK_U32)(-1))) { + + if (Id == OID_SKGE_VPD_KEY || Id == OID_SKGE_VPD_VALUE || + Id == OID_SKGE_VPD_ACCESS) { + + SK_STRNCPY(KeyStr, (char *)&Instance, 4); + KeyStr[4] = 0; + + for (Index = 0; Index < KeyNo; Index ++) { + + if (SK_STRCMP(KeyStr, KeyArr[Index]) == 0) { + FirstIndex = Index; + LastIndex = Index+1; + break; + } + } + if (Index == KeyNo) { + + *pLen = 0; + return (SK_PNMI_ERR_UNKNOWN_INST); + } + } + else if (Instance != 1) { + + *pLen = 0; + return (SK_PNMI_ERR_UNKNOWN_INST); + } + } + + /* + * Get value, if a query should be performed + */ + if (Action == SK_PNMI_GET) { + + switch (Id) { + + case OID_SKGE_VPD_FREE_BYTES: + /* Check length of buffer */ + if (*pLen < sizeof(SK_U32)) { + + *pLen = sizeof(SK_U32); + return (SK_PNMI_ERR_TOO_SHORT); + } + /* Get number of free bytes */ + pVpdStatus = VpdStat(pAC, IoC); + if (pVpdStatus == NULL) { + + SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR017, + SK_PNMI_ERR017MSG); + + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + if ((pVpdStatus->vpd_status & VPD_VALID) == 0) { + + SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR018, + SK_PNMI_ERR018MSG); + + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + + Val32 = (SK_U32)pVpdStatus->vpd_free_rw; + SK_PNMI_STORE_U32(pBuf, Val32); + *pLen = sizeof(SK_U32); + break; + + case OID_SKGE_VPD_ENTRIES_LIST: + /* Check length */ + for (Len = 0, Index = 0; Index < KeyNo; Index ++) { + + Len += SK_STRLEN(KeyArr[Index]) + 1; + } + if (*pLen < Len) { + + *pLen = Len; + return (SK_PNMI_ERR_TOO_SHORT); + } + + /* Get value */ + *(pBuf) = (char)Len - 1; + for (Offset = 1, Index = 0; Index < KeyNo; Index ++) { + + Len = SK_STRLEN(KeyArr[Index]); + SK_MEMCPY(pBuf + Offset, KeyArr[Index], Len); + + Offset += Len; + + if (Index < KeyNo - 1) { + + *(pBuf + Offset) = ' '; + Offset ++; + } + } + *pLen = Offset; + break; + + case OID_SKGE_VPD_ENTRIES_NUMBER: + /* Check length */ + if (*pLen < sizeof(SK_U32)) { + + *pLen = sizeof(SK_U32); + return (SK_PNMI_ERR_TOO_SHORT); + } + + Val32 = (SK_U32)KeyNo; + SK_PNMI_STORE_U32(pBuf, Val32); + *pLen = sizeof(SK_U32); + break; + + case OID_SKGE_VPD_KEY: + /* Check buffer length, if it is large enough */ + for (Len = 0, Index = FirstIndex; + Index < LastIndex; Index ++) { + + Len += SK_STRLEN(KeyArr[Index]) + 1; + } + if (*pLen < Len) { + + *pLen = Len; + return (SK_PNMI_ERR_TOO_SHORT); + } + + /* + * Get the key to an intermediate buffer, because + * we have to prepend a length byte. + */ + for (Offset = 0, Index = FirstIndex; + Index < LastIndex; Index ++) { + + Len = SK_STRLEN(KeyArr[Index]); + + *(pBuf + Offset) = (char)Len; + SK_MEMCPY(pBuf + Offset + 1, KeyArr[Index], + Len); + Offset += Len + 1; + } + *pLen = Offset; + break; + + case OID_SKGE_VPD_VALUE: + /* Check the buffer length if it is large enough */ + for (Offset = 0, Index = FirstIndex; + Index < LastIndex; Index ++) { + + BufLen = 256; + if (VpdRead(pAC, IoC, KeyArr[Index], Buf, + (int *)&BufLen) > 0 || + BufLen >= SK_PNMI_VPD_DATALEN) { + + SK_ERR_LOG(pAC, SK_ERRCL_SW, + SK_PNMI_ERR021, + SK_PNMI_ERR021MSG); + + return (SK_PNMI_ERR_GENERAL); + } + Offset += BufLen + 1; + } + if (*pLen < Offset) { + + *pLen = Offset; + return (SK_PNMI_ERR_TOO_SHORT); + } + + /* + * Get the value to an intermediate buffer, because + * we have to prepend a length byte. + */ + for (Offset = 0, Index = FirstIndex; + Index < LastIndex; Index ++) { + + BufLen = 256; + if (VpdRead(pAC, IoC, KeyArr[Index], Buf, + (int *)&BufLen) > 0 || + BufLen >= SK_PNMI_VPD_DATALEN) { + + SK_ERR_LOG(pAC, SK_ERRCL_SW, + SK_PNMI_ERR022, + SK_PNMI_ERR022MSG); + + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + + *(pBuf + Offset) = (char)BufLen; + SK_MEMCPY(pBuf + Offset + 1, Buf, BufLen); + Offset += BufLen + 1; + } + *pLen = Offset; + break; + + case OID_SKGE_VPD_ACCESS: + if (*pLen < LastIndex - FirstIndex) { + + *pLen = LastIndex - FirstIndex; + return (SK_PNMI_ERR_TOO_SHORT); + } + + for (Offset = 0, Index = FirstIndex; + Index < LastIndex; Index ++) { + + if (VpdMayWrite(KeyArr[Index])) { + + *(pBuf + Offset) = SK_PNMI_VPD_RW; + } + else { + *(pBuf + Offset) = SK_PNMI_VPD_RO; + } + Offset ++; + } + *pLen = Offset; + break; + + case OID_SKGE_VPD_ACTION: + Offset = LastIndex - FirstIndex; + if (*pLen < Offset) { + + *pLen = Offset; + return (SK_PNMI_ERR_TOO_SHORT); + } + SK_MEMSET(pBuf, 0, Offset); + *pLen = Offset; + break; + + default: + SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR023, + SK_PNMI_ERR023MSG); + + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + } + else { + /* The only OID which can be set is VPD_ACTION */ + if (Id != OID_SKGE_VPD_ACTION) { + + if (Id == OID_SKGE_VPD_FREE_BYTES || + Id == OID_SKGE_VPD_ENTRIES_LIST || + Id == OID_SKGE_VPD_ENTRIES_NUMBER || + Id == OID_SKGE_VPD_KEY || + Id == OID_SKGE_VPD_VALUE || + Id == OID_SKGE_VPD_ACCESS) { + + *pLen = 0; + return (SK_PNMI_ERR_READ_ONLY); + } + + SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR024, + SK_PNMI_ERR024MSG); + + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + + /* + * From this point we handle VPD_ACTION. Check the buffer + * length. It should at least have the size of one byte. + */ + if (*pLen < 1) { + + *pLen = 1; + return (SK_PNMI_ERR_TOO_SHORT); + } + + /* + * The first byte contains the VPD action type we should + * perform. + */ + switch (*pBuf) { + + case SK_PNMI_VPD_IGNORE: + /* Nothing to do */ + break; + + case SK_PNMI_VPD_CREATE: + /* + * We have to create a new VPD entry or we modify + * an existing one. Check first the buffer length. + */ + if (*pLen < 4) { + + *pLen = 4; + return (SK_PNMI_ERR_TOO_SHORT); + } + KeyStr[0] = pBuf[1]; + KeyStr[1] = pBuf[2]; + KeyStr[2] = 0; + + /* + * Is the entry writable or does it belong to the + * read-only area? + */ + if (!VpdMayWrite(KeyStr)) { + + *pLen = 0; + return (SK_PNMI_ERR_BAD_VALUE); + } + + Offset = (int)pBuf[3] & 0xFF; + + SK_MEMCPY(Buf, pBuf + 4, Offset); + Buf[Offset] = 0; + + /* A preset ends here */ + if (Action == SK_PNMI_PRESET) { + + return (SK_PNMI_ERR_OK); + } + + /* Write the new entry or modify an existing one */ + Ret = VpdWrite(pAC, IoC, KeyStr, Buf); + if (Ret == SK_PNMI_VPD_NOWRITE ) { + + *pLen = 0; + return (SK_PNMI_ERR_BAD_VALUE); + } + else if (Ret != SK_PNMI_VPD_OK) { + + SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR025, + SK_PNMI_ERR025MSG); + + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + + /* + * Perform an update of the VPD data. This is + * not mandantory, but just to be sure. + */ + Ret = VpdUpdate(pAC, IoC); + if (Ret != SK_PNMI_VPD_OK) { + + SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR026, + SK_PNMI_ERR026MSG); + + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + break; + + case SK_PNMI_VPD_DELETE: + /* Check if the buffer size is plausible */ + if (*pLen < 3) { + + *pLen = 3; + return (SK_PNMI_ERR_TOO_SHORT); + } + if (*pLen > 3) { + + *pLen = 0; + return (SK_PNMI_ERR_BAD_VALUE); + } + KeyStr[0] = pBuf[1]; + KeyStr[1] = pBuf[2]; + KeyStr[2] = 0; + + /* Find the passed key in the array */ + for (Index = 0; Index < KeyNo; Index ++) { + + if (SK_STRCMP(KeyStr, KeyArr[Index]) == 0) { + + break; + } + } + /* + * If we cannot find the key it is wrong, so we + * return an appropriate error value. + */ + if (Index == KeyNo) { + + *pLen = 0; + return (SK_PNMI_ERR_BAD_VALUE); + } + + if (Action == SK_PNMI_PRESET) { + + return (SK_PNMI_ERR_OK); + } + + /* Ok, you wanted it and you will get it */ + Ret = VpdDelete(pAC, IoC, KeyStr); + if (Ret != SK_PNMI_VPD_OK) { + + SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR027, + SK_PNMI_ERR027MSG); + + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + + /* + * Perform an update of the VPD data. This is + * not mandantory, but just to be sure. + */ + Ret = VpdUpdate(pAC, IoC); + if (Ret != SK_PNMI_VPD_OK) { + + SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR028, + SK_PNMI_ERR028MSG); + + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + break; + + default: + *pLen = 0; + return (SK_PNMI_ERR_BAD_VALUE); + } + } + + return (SK_PNMI_ERR_OK); +} + +/***************************************************************************** + * + * General - OID handler function of various single instance OIDs + * + * Description: + * The code is simple. No description necessary. + * + * Returns: + * SK_PNMI_ERR_OK The request was successfully performed. + * SK_PNMI_ERR_GENERAL A general severe internal error occured. + * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain + * the correct data (e.g. a 32bit value is + * needed, but a 16 bit value was passed). + * SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't + * exist (e.g. port instance 3 on a two port + * adapter. + */ +PNMI_STATIC int General( +SK_AC *pAC, /* Pointer to adapter context */ +SK_IOC IoC, /* IO context handle */ +int Action, /* GET/PRESET/SET action */ +SK_U32 Id, /* Object ID that is to be processed */ +char *pBuf, /* Buffer used for the management data transfer */ +unsigned int *pLen, /* On call: buffer length. On return: used buffer */ +SK_U32 Instance, /* Instance (1..n) that is to be queried or -1 */ +unsigned int TableIndex, /* Index to the Id table */ +SK_U32 NetIndex) /* NetIndex (0..n), in single net mode always zero */ +{ + int Ret; + unsigned int Index; + unsigned int Len; + unsigned int Offset; + unsigned int Val; + SK_U8 Val8; + SK_U16 Val16; + SK_U32 Val32; + SK_U64 Val64; + SK_U64 Val64RxHwErrs = 0; + SK_U64 Val64TxHwErrs = 0; + SK_BOOL Is64BitReq = SK_FALSE; + char Buf[256]; + int MacType; + + /* + * Check instance. We only handle single instance variables. + */ + if (Instance != (SK_U32)(-1) && Instance != 1) { + + *pLen = 0; + return (SK_PNMI_ERR_UNKNOWN_INST); + } + + /* + * Check action. We only allow get requests. + */ + if (Action != SK_PNMI_GET) { + + *pLen = 0; + return (SK_PNMI_ERR_READ_ONLY); + } + + MacType = pAC->GIni.GIMacType; + + /* + * Check length for the various supported OIDs + */ + switch (Id) { + + case OID_GEN_XMIT_ERROR: + case OID_GEN_RCV_ERROR: + case OID_GEN_RCV_NO_BUFFER: +#ifndef SK_NDIS_64BIT_CTR + if (*pLen < sizeof(SK_U32)) { + *pLen = sizeof(SK_U32); + return (SK_PNMI_ERR_TOO_SHORT); + } + +#else /* SK_NDIS_64BIT_CTR */ + + /* + * for compatibility, at least 32bit are required for oid + */ + if (*pLen < sizeof(SK_U32)) { + /* + * but indicate handling for 64bit values, + * if insufficient space is provided + */ + *pLen = sizeof(SK_U64); + return (SK_PNMI_ERR_TOO_SHORT); + } + + Is64BitReq = (*pLen < sizeof(SK_U64)) ? SK_FALSE : SK_TRUE; +#endif /* SK_NDIS_64BIT_CTR */ + break; + + case OID_SKGE_PORT_NUMBER: + case OID_SKGE_DEVICE_TYPE: + case OID_SKGE_RESULT: + case OID_SKGE_RLMT_MONITOR_NUMBER: + case OID_GEN_TRANSMIT_QUEUE_LENGTH: + case OID_SKGE_TRAP_NUMBER: + case OID_SKGE_MDB_VERSION: + case OID_SKGE_BOARDLEVEL: + case OID_SKGE_CHIPID: + case OID_SKGE_RAMSIZE: + if (*pLen < sizeof(SK_U32)) { + + *pLen = sizeof(SK_U32); + return (SK_PNMI_ERR_TOO_SHORT); + } + break; + + case OID_SKGE_CHIPSET: + if (*pLen < sizeof(SK_U16)) { + + *pLen = sizeof(SK_U16); + return (SK_PNMI_ERR_TOO_SHORT); + } + break; + + case OID_SKGE_BUS_TYPE: + case OID_SKGE_BUS_SPEED: + case OID_SKGE_BUS_WIDTH: + case OID_SKGE_SENSOR_NUMBER: + case OID_SKGE_CHKSM_NUMBER: + case OID_SKGE_VAUXAVAIL: + if (*pLen < sizeof(SK_U8)) { + + *pLen = sizeof(SK_U8); + return (SK_PNMI_ERR_TOO_SHORT); + } + break; + + case OID_SKGE_TX_SW_QUEUE_LEN: + case OID_SKGE_TX_SW_QUEUE_MAX: + case OID_SKGE_TX_RETRY: + case OID_SKGE_RX_INTR_CTS: + case OID_SKGE_TX_INTR_CTS: + case OID_SKGE_RX_NO_BUF_CTS: + case OID_SKGE_TX_NO_BUF_CTS: + case OID_SKGE_TX_USED_DESCR_NO: + case OID_SKGE_RX_DELIVERED_CTS: + case OID_SKGE_RX_OCTETS_DELIV_CTS: + case OID_SKGE_RX_HW_ERROR_CTS: + case OID_SKGE_TX_HW_ERROR_CTS: + case OID_SKGE_IN_ERRORS_CTS: + case OID_SKGE_OUT_ERROR_CTS: + case OID_SKGE_ERR_RECOVERY_CTS: + case OID_SKGE_SYSUPTIME: + if (*pLen < sizeof(SK_U64)) { + + *pLen = sizeof(SK_U64); + return (SK_PNMI_ERR_TOO_SHORT); + } + break; + + default: + /* Checked later */ + break; + } + + /* Update statistic */ + if (Id == OID_SKGE_RX_HW_ERROR_CTS || + Id == OID_SKGE_TX_HW_ERROR_CTS || + Id == OID_SKGE_IN_ERRORS_CTS || + Id == OID_SKGE_OUT_ERROR_CTS || + Id == OID_GEN_XMIT_ERROR || + Id == OID_GEN_RCV_ERROR) { + + /* Force the XMAC to update its statistic counters and + * Increment semaphore to indicate that an update was + * already done. + */ + Ret = MacUpdate(pAC, IoC, 0, pAC->GIni.GIMacsFound - 1); + if (Ret != SK_PNMI_ERR_OK) { + + *pLen = 0; + return (Ret); + } + pAC->Pnmi.MacUpdatedFlag ++; + + /* + * Some OIDs consist of multiple hardware counters. Those + * values which are contained in all of them will be added + * now. + */ + switch (Id) { + + case OID_SKGE_RX_HW_ERROR_CTS: + case OID_SKGE_IN_ERRORS_CTS: + case OID_GEN_RCV_ERROR: + Val64RxHwErrs = + GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_MISSED, NetIndex) + + GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_FRAMING, NetIndex) + + GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_OVERFLOW, NetIndex) + + GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_JABBER, NetIndex) + + GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_CARRIER, NetIndex) + + GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_IRLENGTH, NetIndex) + + GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_SYMBOL, NetIndex) + + GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_SHORTS, NetIndex) + + GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_RUNT, NetIndex) + + GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_TOO_LONG, NetIndex) + + GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_FCS, NetIndex) + + GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_CEXT, NetIndex); + break; + + case OID_SKGE_TX_HW_ERROR_CTS: + case OID_SKGE_OUT_ERROR_CTS: + case OID_GEN_XMIT_ERROR: + Val64TxHwErrs = + GetStatVal(pAC, IoC, 0, SK_PNMI_HTX_EXCESS_COL, NetIndex) + + GetStatVal(pAC, IoC, 0, SK_PNMI_HTX_LATE_COL, NetIndex) + + GetStatVal(pAC, IoC, 0, SK_PNMI_HTX_UNDERRUN, NetIndex) + + GetStatVal(pAC, IoC, 0, SK_PNMI_HTX_CARRIER, NetIndex); + break; + } + } + + /* + * Retrieve value + */ + switch (Id) { + + case OID_SKGE_SUPPORTED_LIST: + Len = ID_TABLE_SIZE * sizeof(SK_U32); + if (*pLen < Len) { + + *pLen = Len; + return (SK_PNMI_ERR_TOO_SHORT); + } + for (Offset = 0, Index = 0; Offset < Len; + Offset += sizeof(SK_U32), Index ++) { + + Val32 = (SK_U32)IdTable[Index].Id; + SK_PNMI_STORE_U32(pBuf + Offset, Val32); + } + *pLen = Len; + break; + + case OID_SKGE_BOARDLEVEL: + Val32 = (SK_U32)pAC->GIni.GILevel; + SK_PNMI_STORE_U32(pBuf, Val32); + *pLen = sizeof(SK_U32); + break; + + case OID_SKGE_PORT_NUMBER: + Val32 = (SK_U32)pAC->GIni.GIMacsFound; + SK_PNMI_STORE_U32(pBuf, Val32); + *pLen = sizeof(SK_U32); + break; + + case OID_SKGE_DEVICE_TYPE: + Val32 = (SK_U32)pAC->Pnmi.DeviceType; + SK_PNMI_STORE_U32(pBuf, Val32); + *pLen = sizeof(SK_U32); + break; + + case OID_SKGE_DRIVER_DESCR: + if (pAC->Pnmi.pDriverDescription == NULL) { + + SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR007, + SK_PNMI_ERR007MSG); + + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + + Len = SK_STRLEN(pAC->Pnmi.pDriverDescription) + 1; + if (Len > SK_PNMI_STRINGLEN1) { + + SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR029, + SK_PNMI_ERR029MSG); + + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + + if (*pLen < Len) { + + *pLen = Len; + return (SK_PNMI_ERR_TOO_SHORT); + } + *pBuf = (char)(Len - 1); + SK_MEMCPY(pBuf + 1, pAC->Pnmi.pDriverDescription, Len - 1); + *pLen = Len; + break; + + case OID_SKGE_DRIVER_VERSION: + if (pAC->Pnmi.pDriverVersion == NULL) { + + SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR030, + SK_PNMI_ERR030MSG); + + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + + Len = SK_STRLEN(pAC->Pnmi.pDriverVersion) + 1; + if (Len > SK_PNMI_STRINGLEN1) { + + SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR031, + SK_PNMI_ERR031MSG); + + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + + if (*pLen < Len) { + + *pLen = Len; + return (SK_PNMI_ERR_TOO_SHORT); + } + *pBuf = (char)(Len - 1); + SK_MEMCPY(pBuf + 1, pAC->Pnmi.pDriverVersion, Len - 1); + *pLen = Len; + break; + + case OID_SKGE_DRIVER_RELDATE: + if (pAC->Pnmi.pDriverReleaseDate == NULL) { + + SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR030, + SK_PNMI_ERR053MSG); + + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + + Len = SK_STRLEN(pAC->Pnmi.pDriverReleaseDate) + 1; + if (Len > SK_PNMI_STRINGLEN1) { + + SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR031, + SK_PNMI_ERR054MSG); + + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + + if (*pLen < Len) { + + *pLen = Len; + return (SK_PNMI_ERR_TOO_SHORT); + } + *pBuf = (char)(Len - 1); + SK_MEMCPY(pBuf + 1, pAC->Pnmi.pDriverReleaseDate, Len - 1); + *pLen = Len; + break; + + case OID_SKGE_DRIVER_FILENAME: + if (pAC->Pnmi.pDriverFileName == NULL) { + + SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR030, + SK_PNMI_ERR055MSG); + + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + + Len = SK_STRLEN(pAC->Pnmi.pDriverFileName) + 1; + if (Len > SK_PNMI_STRINGLEN1) { + + SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR031, + SK_PNMI_ERR056MSG); + + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + + if (*pLen < Len) { + + *pLen = Len; + return (SK_PNMI_ERR_TOO_SHORT); + } + *pBuf = (char)(Len - 1); + SK_MEMCPY(pBuf + 1, pAC->Pnmi.pDriverFileName, Len - 1); + *pLen = Len; + break; + + case OID_SKGE_HW_DESCR: + /* + * The hardware description is located in the VPD. This + * query may move to the initialisation routine. But + * the VPD data is cached and therefore a call here + * will not make much difference. + */ + Len = 256; + if (VpdRead(pAC, IoC, VPD_NAME, Buf, (int *)&Len) > 0) { + + SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR032, + SK_PNMI_ERR032MSG); + + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + Len ++; + if (Len > SK_PNMI_STRINGLEN1) { + + SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR033, + SK_PNMI_ERR033MSG); + + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + if (*pLen < Len) { + + *pLen = Len; + return (SK_PNMI_ERR_TOO_SHORT); + } + *pBuf = (char)(Len - 1); + SK_MEMCPY(pBuf + 1, Buf, Len - 1); + *pLen = Len; + break; + + case OID_SKGE_HW_VERSION: + /* Oh, I love to do some string manipulation */ + if (*pLen < 5) { + + *pLen = 5; + return (SK_PNMI_ERR_TOO_SHORT); + } + Val8 = (SK_U8)pAC->GIni.GIPciHwRev; + pBuf[0] = 4; + pBuf[1] = 'v'; + pBuf[2] = (char)(0x30 | ((Val8 >> 4) & 0x0F)); + pBuf[3] = '.'; + pBuf[4] = (char)(0x30 | (Val8 & 0x0F)); + *pLen = 5; + break; + + case OID_SKGE_CHIPSET: + Val16 = pAC->Pnmi.Chipset; + SK_PNMI_STORE_U16(pBuf, Val16); + *pLen = sizeof(SK_U16); + break; + + case OID_SKGE_CHIPID: + Val32 = pAC->GIni.GIChipId; + SK_PNMI_STORE_U32(pBuf, Val32); + *pLen = sizeof(SK_U32); + break; + + case OID_SKGE_RAMSIZE: + Val32 = pAC->GIni.GIRamSize; + SK_PNMI_STORE_U32(pBuf, Val32); + *pLen = sizeof(SK_U32); + break; + + case OID_SKGE_VAUXAVAIL: + *pBuf = (char) pAC->GIni.GIVauxAvail; + *pLen = sizeof(char); + break; + + case OID_SKGE_BUS_TYPE: + *pBuf = (char) SK_PNMI_BUS_PCI; + *pLen = sizeof(char); + break; + + case OID_SKGE_BUS_SPEED: + *pBuf = pAC->Pnmi.PciBusSpeed; + *pLen = sizeof(char); + break; + + case OID_SKGE_BUS_WIDTH: + *pBuf = pAC->Pnmi.PciBusWidth; + *pLen = sizeof(char); + break; + + case OID_SKGE_RESULT: + Val32 = pAC->Pnmi.TestResult; + SK_PNMI_STORE_U32(pBuf, Val32); + *pLen = sizeof(SK_U32); + break; + + case OID_SKGE_SENSOR_NUMBER: + *pBuf = (char)pAC->I2c.MaxSens; + *pLen = sizeof(char); + break; + + case OID_SKGE_CHKSM_NUMBER: + *pBuf = SKCS_NUM_PROTOCOLS; + *pLen = sizeof(char); + break; + + case OID_SKGE_TRAP_NUMBER: + GetTrapQueueLen(pAC, &Len, &Val); + Val32 = (SK_U32)Val; + SK_PNMI_STORE_U32(pBuf, Val32); + *pLen = sizeof(SK_U32); + break; + + case OID_SKGE_TRAP: + GetTrapQueueLen(pAC, &Len, &Val); + if (*pLen < Len) { + + *pLen = Len; + return (SK_PNMI_ERR_TOO_SHORT); + } + CopyTrapQueue(pAC, pBuf); + *pLen = Len; + break; + + case OID_SKGE_RLMT_MONITOR_NUMBER: +/* XXX Not yet implemented by RLMT therefore we return zero elements */ + Val32 = 0; + SK_PNMI_STORE_U32(pBuf, Val32); + *pLen = sizeof(SK_U32); + break; + + case OID_SKGE_TX_SW_QUEUE_LEN: + /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */ + if (MacType == SK_MAC_XMAC) { + /* Dual net mode */ + if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) { + Val64 = pAC->Pnmi.BufPort[NetIndex].TxSwQueueLen; + } + /* Single net mode */ + else { + Val64 = pAC->Pnmi.BufPort[0].TxSwQueueLen + + pAC->Pnmi.BufPort[1].TxSwQueueLen; + } + } + else { + /* Dual net mode */ + if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) { + Val64 = pAC->Pnmi.Port[NetIndex].TxSwQueueLen; + } + /* Single net mode */ + else { + Val64 = pAC->Pnmi.Port[0].TxSwQueueLen + + pAC->Pnmi.Port[1].TxSwQueueLen; + } + } + SK_PNMI_STORE_U64(pBuf, Val64); + *pLen = sizeof(SK_U64); + break; + + + case OID_SKGE_TX_SW_QUEUE_MAX: + /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */ + if (MacType == SK_MAC_XMAC) { + /* Dual net mode */ + if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) { + Val64 = pAC->Pnmi.BufPort[NetIndex].TxSwQueueMax; + } + /* Single net mode */ + else { + Val64 = pAC->Pnmi.BufPort[0].TxSwQueueMax + + pAC->Pnmi.BufPort[1].TxSwQueueMax; + } + } + else { + /* Dual net mode */ + if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) { + Val64 = pAC->Pnmi.Port[NetIndex].TxSwQueueMax; + } + /* Single net mode */ + else { + Val64 = pAC->Pnmi.Port[0].TxSwQueueMax + + pAC->Pnmi.Port[1].TxSwQueueMax; + } + } + SK_PNMI_STORE_U64(pBuf, Val64); + *pLen = sizeof(SK_U64); + break; + + case OID_SKGE_TX_RETRY: + /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */ + if (MacType == SK_MAC_XMAC) { + /* Dual net mode */ + if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) { + Val64 = pAC->Pnmi.BufPort[NetIndex].TxRetryCts; + } + /* Single net mode */ + else { + Val64 = pAC->Pnmi.BufPort[0].TxRetryCts + + pAC->Pnmi.BufPort[1].TxRetryCts; + } + } + else { + /* Dual net mode */ + if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) { + Val64 = pAC->Pnmi.Port[NetIndex].TxRetryCts; + } + /* Single net mode */ + else { + Val64 = pAC->Pnmi.Port[0].TxRetryCts + + pAC->Pnmi.Port[1].TxRetryCts; + } + } + SK_PNMI_STORE_U64(pBuf, Val64); + *pLen = sizeof(SK_U64); + break; + + case OID_SKGE_RX_INTR_CTS: + /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */ + if (MacType == SK_MAC_XMAC) { + /* Dual net mode */ + if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) { + Val64 = pAC->Pnmi.BufPort[NetIndex].RxIntrCts; + } + /* Single net mode */ + else { + Val64 = pAC->Pnmi.BufPort[0].RxIntrCts + + pAC->Pnmi.BufPort[1].RxIntrCts; + } + } + else { + /* Dual net mode */ + if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) { + Val64 = pAC->Pnmi.Port[NetIndex].RxIntrCts; + } + /* Single net mode */ + else { + Val64 = pAC->Pnmi.Port[0].RxIntrCts + + pAC->Pnmi.Port[1].RxIntrCts; + } + } + SK_PNMI_STORE_U64(pBuf, Val64); + *pLen = sizeof(SK_U64); + break; + + case OID_SKGE_TX_INTR_CTS: + /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */ + if (MacType == SK_MAC_XMAC) { + /* Dual net mode */ + if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) { + Val64 = pAC->Pnmi.BufPort[NetIndex].TxIntrCts; + } + /* Single net mode */ + else { + Val64 = pAC->Pnmi.BufPort[0].TxIntrCts + + pAC->Pnmi.BufPort[1].TxIntrCts; + } + } + else { + /* Dual net mode */ + if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) { + Val64 = pAC->Pnmi.Port[NetIndex].TxIntrCts; + } + /* Single net mode */ + else { + Val64 = pAC->Pnmi.Port[0].TxIntrCts + + pAC->Pnmi.Port[1].TxIntrCts; + } + } + SK_PNMI_STORE_U64(pBuf, Val64); + *pLen = sizeof(SK_U64); + break; + + case OID_SKGE_RX_NO_BUF_CTS: + /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */ + if (MacType == SK_MAC_XMAC) { + /* Dual net mode */ + if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) { + Val64 = pAC->Pnmi.BufPort[NetIndex].RxNoBufCts; + } + /* Single net mode */ + else { + Val64 = pAC->Pnmi.BufPort[0].RxNoBufCts + + pAC->Pnmi.BufPort[1].RxNoBufCts; + } + } + else { + /* Dual net mode */ + if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) { + Val64 = pAC->Pnmi.Port[NetIndex].RxNoBufCts; + } + /* Single net mode */ + else { + Val64 = pAC->Pnmi.Port[0].RxNoBufCts + + pAC->Pnmi.Port[1].RxNoBufCts; + } + } + SK_PNMI_STORE_U64(pBuf, Val64); + *pLen = sizeof(SK_U64); + break; + + case OID_SKGE_TX_NO_BUF_CTS: + /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */ + if (MacType == SK_MAC_XMAC) { + /* Dual net mode */ + if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) { + Val64 = pAC->Pnmi.BufPort[NetIndex].TxNoBufCts; + } + /* Single net mode */ + else { + Val64 = pAC->Pnmi.BufPort[0].TxNoBufCts + + pAC->Pnmi.BufPort[1].TxNoBufCts; + } + } + else { + /* Dual net mode */ + if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) { + Val64 = pAC->Pnmi.Port[NetIndex].TxNoBufCts; + } + /* Single net mode */ + else { + Val64 = pAC->Pnmi.Port[0].TxNoBufCts + + pAC->Pnmi.Port[1].TxNoBufCts; + } + } + SK_PNMI_STORE_U64(pBuf, Val64); + *pLen = sizeof(SK_U64); + break; + + case OID_SKGE_TX_USED_DESCR_NO: + /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */ + if (MacType == SK_MAC_XMAC) { + /* Dual net mode */ + if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) { + Val64 = pAC->Pnmi.BufPort[NetIndex].TxUsedDescrNo; + } + /* Single net mode */ + else { + Val64 = pAC->Pnmi.BufPort[0].TxUsedDescrNo + + pAC->Pnmi.BufPort[1].TxUsedDescrNo; + } + } + else { + /* Dual net mode */ + if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) { + Val64 = pAC->Pnmi.Port[NetIndex].TxUsedDescrNo; + } + /* Single net mode */ + else { + Val64 = pAC->Pnmi.Port[0].TxUsedDescrNo + + pAC->Pnmi.Port[1].TxUsedDescrNo; + } + } + SK_PNMI_STORE_U64(pBuf, Val64); + *pLen = sizeof(SK_U64); + break; + + case OID_SKGE_RX_DELIVERED_CTS: + /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */ + if (MacType == SK_MAC_XMAC) { + /* Dual net mode */ + if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) { + Val64 = pAC->Pnmi.BufPort[NetIndex].RxDeliveredCts; + } + /* Single net mode */ + else { + Val64 = pAC->Pnmi.BufPort[0].RxDeliveredCts + + pAC->Pnmi.BufPort[1].RxDeliveredCts; + } + } + else { + /* Dual net mode */ + if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) { + Val64 = pAC->Pnmi.Port[NetIndex].RxDeliveredCts; + } + /* Single net mode */ + else { + Val64 = pAC->Pnmi.Port[0].RxDeliveredCts + + pAC->Pnmi.Port[1].RxDeliveredCts; + } + } + SK_PNMI_STORE_U64(pBuf, Val64); + *pLen = sizeof(SK_U64); + break; + + case OID_SKGE_RX_OCTETS_DELIV_CTS: + /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */ + if (MacType == SK_MAC_XMAC) { + /* Dual net mode */ + if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) { + Val64 = pAC->Pnmi.BufPort[NetIndex].RxOctetsDeliveredCts; + } + /* Single net mode */ + else { + Val64 = pAC->Pnmi.BufPort[0].RxOctetsDeliveredCts + + pAC->Pnmi.BufPort[1].RxOctetsDeliveredCts; + } + } + else { + /* Dual net mode */ + if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) { + Val64 = pAC->Pnmi.Port[NetIndex].RxOctetsDeliveredCts; + } + /* Single net mode */ + else { + Val64 = pAC->Pnmi.Port[0].RxOctetsDeliveredCts + + pAC->Pnmi.Port[1].RxOctetsDeliveredCts; + } + } + SK_PNMI_STORE_U64(pBuf, Val64); + *pLen = sizeof(SK_U64); + break; + + case OID_SKGE_RX_HW_ERROR_CTS: + SK_PNMI_STORE_U64(pBuf, Val64RxHwErrs); + *pLen = sizeof(SK_U64); + break; + + case OID_SKGE_TX_HW_ERROR_CTS: + SK_PNMI_STORE_U64(pBuf, Val64TxHwErrs); + *pLen = sizeof(SK_U64); + break; + + case OID_SKGE_IN_ERRORS_CTS: + /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */ + if (MacType == SK_MAC_XMAC) { + /* Dual net mode */ + if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) { + Val64 = Val64RxHwErrs + pAC->Pnmi.BufPort[NetIndex].RxNoBufCts; + } + /* Single net mode */ + else { + Val64 = Val64RxHwErrs + + pAC->Pnmi.BufPort[0].RxNoBufCts + + pAC->Pnmi.BufPort[1].RxNoBufCts; + } + } + else { + /* Dual net mode */ + if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) { + Val64 = Val64RxHwErrs + pAC->Pnmi.Port[NetIndex].RxNoBufCts; + } + /* Single net mode */ + else { + Val64 = Val64RxHwErrs + + pAC->Pnmi.Port[0].RxNoBufCts + + pAC->Pnmi.Port[1].RxNoBufCts; + } + } + SK_PNMI_STORE_U64(pBuf, Val64); + *pLen = sizeof(SK_U64); + break; + + case OID_SKGE_OUT_ERROR_CTS: + /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */ + if (MacType == SK_MAC_XMAC) { + /* Dual net mode */ + if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) { + Val64 = Val64TxHwErrs + pAC->Pnmi.BufPort[NetIndex].TxNoBufCts; + } + /* Single net mode */ + else { + Val64 = Val64TxHwErrs + + pAC->Pnmi.BufPort[0].TxNoBufCts + + pAC->Pnmi.BufPort[1].TxNoBufCts; + } + } + else { + /* Dual net mode */ + if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) { + Val64 = Val64TxHwErrs + pAC->Pnmi.Port[NetIndex].TxNoBufCts; + } + /* Single net mode */ + else { + Val64 = Val64TxHwErrs + + pAC->Pnmi.Port[0].TxNoBufCts + + pAC->Pnmi.Port[1].TxNoBufCts; + } + } + SK_PNMI_STORE_U64(pBuf, Val64); + *pLen = sizeof(SK_U64); + break; + + case OID_SKGE_ERR_RECOVERY_CTS: + /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */ + if (MacType == SK_MAC_XMAC) { + /* Dual net mode */ + if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) { + Val64 = pAC->Pnmi.BufPort[NetIndex].ErrRecoveryCts; + } + /* Single net mode */ + else { + Val64 = pAC->Pnmi.BufPort[0].ErrRecoveryCts + + pAC->Pnmi.BufPort[1].ErrRecoveryCts; + } + } + else { + /* Dual net mode */ + if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) { + Val64 = pAC->Pnmi.Port[NetIndex].ErrRecoveryCts; + } + /* Single net mode */ + else { + Val64 = pAC->Pnmi.Port[0].ErrRecoveryCts + + pAC->Pnmi.Port[1].ErrRecoveryCts; + } + } + SK_PNMI_STORE_U64(pBuf, Val64); + *pLen = sizeof(SK_U64); + break; + + case OID_SKGE_SYSUPTIME: + Val64 = SK_PNMI_HUNDREDS_SEC(SkOsGetTime(pAC)); + Val64 -= pAC->Pnmi.StartUpTime; + SK_PNMI_STORE_U64(pBuf, Val64); + *pLen = sizeof(SK_U64); + break; + + case OID_SKGE_MDB_VERSION: + Val32 = SK_PNMI_MDB_VERSION; + SK_PNMI_STORE_U32(pBuf, Val32); + *pLen = sizeof(SK_U32); + break; + + case OID_GEN_RCV_ERROR: + /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */ + if (MacType == SK_MAC_XMAC) { + Val64 = Val64RxHwErrs + pAC->Pnmi.BufPort[NetIndex].RxNoBufCts; + } + else { + Val64 = Val64RxHwErrs + pAC->Pnmi.Port[NetIndex].RxNoBufCts; + } + + /* + * by default 32bit values are evaluated + */ + if (!Is64BitReq) { + Val32 = (SK_U32)Val64; + SK_PNMI_STORE_U32(pBuf, Val32); + *pLen = sizeof(SK_U32); + } + else { + SK_PNMI_STORE_U64(pBuf, Val64); + *pLen = sizeof(SK_U64); + } + break; + + case OID_GEN_XMIT_ERROR: + /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */ + if (MacType == SK_MAC_XMAC) { + Val64 = Val64TxHwErrs + pAC->Pnmi.BufPort[NetIndex].TxNoBufCts; + } + else { + Val64 = Val64TxHwErrs + pAC->Pnmi.Port[NetIndex].TxNoBufCts; + } + + /* + * by default 32bit values are evaluated + */ + if (!Is64BitReq) { + Val32 = (SK_U32)Val64; + SK_PNMI_STORE_U32(pBuf, Val32); + *pLen = sizeof(SK_U32); + } + else { + SK_PNMI_STORE_U64(pBuf, Val64); + *pLen = sizeof(SK_U64); + } + break; + + case OID_GEN_RCV_NO_BUFFER: + /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */ + if (MacType == SK_MAC_XMAC) { + Val64 = pAC->Pnmi.BufPort[NetIndex].RxNoBufCts; + } + else { + Val64 = pAC->Pnmi.Port[NetIndex].RxNoBufCts; + } + + /* + * by default 32bit values are evaluated + */ + if (!Is64BitReq) { + Val32 = (SK_U32)Val64; + SK_PNMI_STORE_U32(pBuf, Val32); + *pLen = sizeof(SK_U32); + } + else { + SK_PNMI_STORE_U64(pBuf, Val64); + *pLen = sizeof(SK_U64); + } + break; + + case OID_GEN_TRANSMIT_QUEUE_LENGTH: + Val32 = (SK_U32)pAC->Pnmi.Port[NetIndex].TxSwQueueLen; + SK_PNMI_STORE_U32(pBuf, Val32); + *pLen = sizeof(SK_U32); + break; + + default: + SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR034, + SK_PNMI_ERR034MSG); + + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + + if (Id == OID_SKGE_RX_HW_ERROR_CTS || + Id == OID_SKGE_TX_HW_ERROR_CTS || + Id == OID_SKGE_IN_ERRORS_CTS || + Id == OID_SKGE_OUT_ERROR_CTS || + Id == OID_GEN_XMIT_ERROR || + Id == OID_GEN_RCV_ERROR) { + + pAC->Pnmi.MacUpdatedFlag --; + } + + return (SK_PNMI_ERR_OK); +} + +/***************************************************************************** + * + * Rlmt - OID handler function of OID_SKGE_RLMT_XXX single instance. + * + * Description: + * Get/Presets/Sets the RLMT OIDs. + * + * Returns: + * SK_PNMI_ERR_OK The request was successfully performed. + * SK_PNMI_ERR_GENERAL A general severe internal error occured. + * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain + * the correct data (e.g. a 32bit value is + * needed, but a 16 bit value was passed). + * SK_PNMI_ERR_BAD_VALUE The passed value is not in the valid + * value range. + * SK_PNMI_ERR_READ_ONLY The OID is read-only and cannot be set. + * SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't + * exist (e.g. port instance 3 on a two port + * adapter. + */ +PNMI_STATIC int Rlmt( +SK_AC *pAC, /* Pointer to adapter context */ +SK_IOC IoC, /* IO context handle */ +int Action, /* GET/PRESET/SET action */ +SK_U32 Id, /* Object ID that is to be processed */ +char *pBuf, /* Buffer used for the management data transfer */ +unsigned int *pLen, /* On call: pBuf buffer length. On return: used buffer */ +SK_U32 Instance, /* Instance (1..n) that is to be queried or -1 */ +unsigned int TableIndex, /* Index to the Id table */ +SK_U32 NetIndex) /* NetIndex (0..n), in single net mode always zero */ +{ + int Ret; + unsigned int PhysPortIndex; + unsigned int PhysPortMax; + SK_EVPARA EventParam; + SK_U32 Val32; + SK_U64 Val64; + + + /* + * Check instance. Only single instance OIDs are allowed here. + */ + if (Instance != (SK_U32)(-1) && Instance != 1) { + + *pLen = 0; + return (SK_PNMI_ERR_UNKNOWN_INST); + } + + /* + * Perform the requested action. + */ + if (Action == SK_PNMI_GET) { + + /* + * Check if the buffer length is large enough. + */ + + switch (Id) { + + case OID_SKGE_RLMT_MODE: + case OID_SKGE_RLMT_PORT_ACTIVE: + case OID_SKGE_RLMT_PORT_PREFERRED: + if (*pLen < sizeof(SK_U8)) { + + *pLen = sizeof(SK_U8); + return (SK_PNMI_ERR_TOO_SHORT); + } + break; + + case OID_SKGE_RLMT_PORT_NUMBER: + if (*pLen < sizeof(SK_U32)) { + + *pLen = sizeof(SK_U32); + return (SK_PNMI_ERR_TOO_SHORT); + } + break; + + case OID_SKGE_RLMT_CHANGE_CTS: + case OID_SKGE_RLMT_CHANGE_TIME: + case OID_SKGE_RLMT_CHANGE_ESTIM: + case OID_SKGE_RLMT_CHANGE_THRES: + if (*pLen < sizeof(SK_U64)) { + + *pLen = sizeof(SK_U64); + return (SK_PNMI_ERR_TOO_SHORT); + } + break; + + default: + SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR035, + SK_PNMI_ERR035MSG); + + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + + /* + * Update RLMT statistic and increment semaphores to indicate + * that an update was already done. Maybe RLMT will hold its + * statistic always up to date some time. Then we can + * remove this type of call. + */ + if ((Ret = RlmtUpdate(pAC, IoC, NetIndex)) != SK_PNMI_ERR_OK) { + + *pLen = 0; + return (Ret); + } + pAC->Pnmi.RlmtUpdatedFlag ++; + + /* + * Retrieve Value + */ + switch (Id) { + + case OID_SKGE_RLMT_MODE: + *pBuf = (char)pAC->Rlmt.Net[0].RlmtMode; + *pLen = sizeof(char); + break; + + case OID_SKGE_RLMT_PORT_NUMBER: + Val32 = (SK_U32)pAC->GIni.GIMacsFound; + SK_PNMI_STORE_U32(pBuf, Val32); + *pLen = sizeof(SK_U32); + break; + + case OID_SKGE_RLMT_PORT_ACTIVE: + *pBuf = 0; + /* + * If multiple ports may become active this OID + * doesn't make sense any more. A new variable in + * the port structure should be created. However, + * for this variable the first active port is + * returned. + */ + PhysPortMax = pAC->GIni.GIMacsFound; + + for (PhysPortIndex = 0; PhysPortIndex < PhysPortMax; + PhysPortIndex ++) { + + if (pAC->Pnmi.Port[PhysPortIndex].ActiveFlag) { + + *pBuf = (char)SK_PNMI_PORT_PHYS2LOG(PhysPortIndex); + break; + } + } + *pLen = sizeof(char); + break; + + case OID_SKGE_RLMT_PORT_PREFERRED: + *pBuf = (char)SK_PNMI_PORT_PHYS2LOG(pAC->Rlmt.Net[NetIndex].Preference); + *pLen = sizeof(char); + break; + + case OID_SKGE_RLMT_CHANGE_CTS: + Val64 = pAC->Pnmi.RlmtChangeCts; + SK_PNMI_STORE_U64(pBuf, Val64); + *pLen = sizeof(SK_U64); + break; + + case OID_SKGE_RLMT_CHANGE_TIME: + Val64 = pAC->Pnmi.RlmtChangeTime; + SK_PNMI_STORE_U64(pBuf, Val64); + *pLen = sizeof(SK_U64); + break; + + case OID_SKGE_RLMT_CHANGE_ESTIM: + Val64 = pAC->Pnmi.RlmtChangeEstimate.Estimate; + SK_PNMI_STORE_U64(pBuf, Val64); + *pLen = sizeof(SK_U64); + break; + + case OID_SKGE_RLMT_CHANGE_THRES: + Val64 = pAC->Pnmi.RlmtChangeThreshold; + SK_PNMI_STORE_U64(pBuf, Val64); + *pLen = sizeof(SK_U64); + break; + + default: + SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_ERR, + ("Rlmt: Unknown OID should be handled before")); + + pAC->Pnmi.RlmtUpdatedFlag --; + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + + pAC->Pnmi.RlmtUpdatedFlag --; + } + else { + /* Perform a preset or set */ + switch (Id) { + + case OID_SKGE_RLMT_MODE: + /* Check if the buffer length is plausible */ + if (*pLen < sizeof(char)) { + + *pLen = sizeof(char); + return (SK_PNMI_ERR_TOO_SHORT); + } + /* Check if the value range is correct */ + if (*pLen != sizeof(char) || + (*pBuf & SK_PNMI_RLMT_MODE_CHK_LINK) == 0 || + *(SK_U8 *)pBuf > 15) { + + *pLen = 0; + return (SK_PNMI_ERR_BAD_VALUE); + } + /* The preset ends here */ + if (Action == SK_PNMI_PRESET) { + + *pLen = 0; + return (SK_PNMI_ERR_OK); + } + /* Send an event to RLMT to change the mode */ + SK_MEMSET((char *)&EventParam, 0, sizeof(EventParam)); + EventParam.Para32[0] |= (SK_U32)(*pBuf); + EventParam.Para32[1] = 0; + if (SkRlmtEvent(pAC, IoC, SK_RLMT_MODE_CHANGE, + EventParam) > 0) { + + SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR037, + SK_PNMI_ERR037MSG); + + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + break; + + case OID_SKGE_RLMT_PORT_PREFERRED: + /* Check if the buffer length is plausible */ + if (*pLen < sizeof(char)) { + + *pLen = sizeof(char); + return (SK_PNMI_ERR_TOO_SHORT); + } + /* Check if the value range is correct */ + if (*pLen != sizeof(char) || *(SK_U8 *)pBuf > + (SK_U8)pAC->GIni.GIMacsFound) { + + *pLen = 0; + return (SK_PNMI_ERR_BAD_VALUE); + } + /* The preset ends here */ + if (Action == SK_PNMI_PRESET) { + + *pLen = 0; + return (SK_PNMI_ERR_OK); + } + + /* + * Send an event to RLMT change the preferred port. + * A param of -1 means automatic mode. RLMT will + * make the decision which is the preferred port. + */ + SK_MEMSET((char *)&EventParam, 0, sizeof(EventParam)); + EventParam.Para32[0] = (SK_U32)(*pBuf) - 1; + EventParam.Para32[1] = NetIndex; + if (SkRlmtEvent(pAC, IoC, SK_RLMT_PREFPORT_CHANGE, + EventParam) > 0) { + + SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR038, + SK_PNMI_ERR038MSG); + + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + break; + + case OID_SKGE_RLMT_CHANGE_THRES: + /* Check if the buffer length is plausible */ + if (*pLen < sizeof(SK_U64)) { + + *pLen = sizeof(SK_U64); + return (SK_PNMI_ERR_TOO_SHORT); + } + /* + * There are not many restrictions to the + * value range. + */ + if (*pLen != sizeof(SK_U64)) { + + *pLen = 0; + return (SK_PNMI_ERR_BAD_VALUE); + } + /* A preset ends here */ + if (Action == SK_PNMI_PRESET) { + + *pLen = 0; + return (SK_PNMI_ERR_OK); + } + /* + * Store the new threshold, which will be taken + * on the next timer event. + */ + SK_PNMI_READ_U64(pBuf, Val64); + pAC->Pnmi.RlmtChangeThreshold = Val64; + break; + + default: + /* The other OIDs are not be able for set */ + *pLen = 0; + return (SK_PNMI_ERR_READ_ONLY); + } + } + + return (SK_PNMI_ERR_OK); +} + +/***************************************************************************** + * + * RlmtStat - OID handler function of OID_SKGE_RLMT_XXX multiple instance. + * + * Description: + * Performs get requests on multiple instance variables. + * + * Returns: + * SK_PNMI_ERR_OK The request was successfully performed. + * SK_PNMI_ERR_GENERAL A general severe internal error occured. + * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain + * the correct data (e.g. a 32bit value is + * needed, but a 16 bit value was passed). + * SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't + * exist (e.g. port instance 3 on a two port + * adapter. + */ +PNMI_STATIC int RlmtStat( +SK_AC *pAC, /* Pointer to adapter context */ +SK_IOC IoC, /* IO context handle */ +int Action, /* GET/PRESET/SET action */ +SK_U32 Id, /* Object ID that is to be processed */ +char *pBuf, /* Buffer used for the management data transfer */ +unsigned int *pLen, /* On call: pBuf buffer length. On return: used buffer */ +SK_U32 Instance, /* Instance (1..n) that is to be queried or -1 */ +unsigned int TableIndex, /* Index to the Id table */ +SK_U32 NetIndex) /* NetIndex (0..n), in single net mode always zero */ +{ + unsigned int PhysPortMax; + unsigned int PhysPortIndex; + unsigned int Limit; + unsigned int Offset; + int Ret; + SK_U32 Val32; + SK_U64 Val64; + + /* + * Calculate the port indexes from the instance. + */ + PhysPortMax = pAC->GIni.GIMacsFound; + + if ((Instance != (SK_U32)(-1))) { + /* Check instance range */ + if ((Instance < 1) || (Instance > PhysPortMax)) { + + *pLen = 0; + return (SK_PNMI_ERR_UNKNOWN_INST); + } + + /* Single net mode */ + PhysPortIndex = Instance - 1; + + /* Dual net mode */ + if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) { + PhysPortIndex = NetIndex; + } + + /* Both net modes */ + Limit = PhysPortIndex + 1; + } + else { + /* Single net mode */ + PhysPortIndex = 0; + Limit = PhysPortMax; + + /* Dual net mode */ + if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) { + PhysPortIndex = NetIndex; + Limit = PhysPortIndex + 1; + } + } + + /* + * Currently only get requests are allowed. + */ + if (Action != SK_PNMI_GET) { + + *pLen = 0; + return (SK_PNMI_ERR_READ_ONLY); + } + + /* + * Check if the buffer length is large enough. + */ + switch (Id) { + + case OID_SKGE_RLMT_PORT_INDEX: + case OID_SKGE_RLMT_STATUS: + if (*pLen < (Limit - PhysPortIndex) * sizeof(SK_U32)) { + + *pLen = (Limit - PhysPortIndex) * sizeof(SK_U32); + return (SK_PNMI_ERR_TOO_SHORT); + } + break; + + case OID_SKGE_RLMT_TX_HELLO_CTS: + case OID_SKGE_RLMT_RX_HELLO_CTS: + case OID_SKGE_RLMT_TX_SP_REQ_CTS: + case OID_SKGE_RLMT_RX_SP_CTS: + if (*pLen < (Limit - PhysPortIndex) * sizeof(SK_U64)) { + + *pLen = (Limit - PhysPortIndex) * sizeof(SK_U64); + return (SK_PNMI_ERR_TOO_SHORT); + } + break; + + default: + SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR039, + SK_PNMI_ERR039MSG); + + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + + } + + /* + * Update statistic and increment semaphores to indicate that + * an update was already done. + */ + if ((Ret = RlmtUpdate(pAC, IoC, NetIndex)) != SK_PNMI_ERR_OK) { + + *pLen = 0; + return (Ret); + } + pAC->Pnmi.RlmtUpdatedFlag ++; + + /* + * Get value + */ + Offset = 0; + for (; PhysPortIndex < Limit; PhysPortIndex ++) { + + switch (Id) { + + case OID_SKGE_RLMT_PORT_INDEX: + Val32 = PhysPortIndex; + SK_PNMI_STORE_U32(pBuf + Offset, Val32); + Offset += sizeof(SK_U32); + break; + + case OID_SKGE_RLMT_STATUS: + if (pAC->Rlmt.Port[PhysPortIndex].PortState == + SK_RLMT_PS_INIT || + pAC->Rlmt.Port[PhysPortIndex].PortState == + SK_RLMT_PS_DOWN) { + + Val32 = SK_PNMI_RLMT_STATUS_ERROR; + } + else if (pAC->Pnmi.Port[PhysPortIndex].ActiveFlag) { + + Val32 = SK_PNMI_RLMT_STATUS_ACTIVE; + } + else { + Val32 = SK_PNMI_RLMT_STATUS_STANDBY; + } + SK_PNMI_STORE_U32(pBuf + Offset, Val32); + Offset += sizeof(SK_U32); + break; + + case OID_SKGE_RLMT_TX_HELLO_CTS: + Val64 = pAC->Rlmt.Port[PhysPortIndex].TxHelloCts; + SK_PNMI_STORE_U64(pBuf + Offset, Val64); + Offset += sizeof(SK_U64); + break; + + case OID_SKGE_RLMT_RX_HELLO_CTS: + Val64 = pAC->Rlmt.Port[PhysPortIndex].RxHelloCts; + SK_PNMI_STORE_U64(pBuf + Offset, Val64); + Offset += sizeof(SK_U64); + break; + + case OID_SKGE_RLMT_TX_SP_REQ_CTS: + Val64 = pAC->Rlmt.Port[PhysPortIndex].TxSpHelloReqCts; + SK_PNMI_STORE_U64(pBuf + Offset, Val64); + Offset += sizeof(SK_U64); + break; + + case OID_SKGE_RLMT_RX_SP_CTS: + Val64 = pAC->Rlmt.Port[PhysPortIndex].RxSpHelloCts; + SK_PNMI_STORE_U64(pBuf + Offset, Val64); + Offset += sizeof(SK_U64); + break; + + default: + SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_ERR, + ("RlmtStat: Unknown OID should be errored before")); + + pAC->Pnmi.RlmtUpdatedFlag --; + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + } + *pLen = Offset; + + pAC->Pnmi.RlmtUpdatedFlag --; + + return (SK_PNMI_ERR_OK); +} + +/***************************************************************************** + * + * MacPrivateConf - OID handler function of OIDs concerning the configuration + * + * Description: + * Get/Presets/Sets the OIDs concerning the configuration. + * + * Returns: + * SK_PNMI_ERR_OK The request was successfully performed. + * SK_PNMI_ERR_GENERAL A general severe internal error occured. + * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain + * the correct data (e.g. a 32bit value is + * needed, but a 16 bit value was passed). + * SK_PNMI_ERR_BAD_VALUE The passed value is not in the valid + * value range. + * SK_PNMI_ERR_READ_ONLY The OID is read-only and cannot be set. + * SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't + * exist (e.g. port instance 3 on a two port + * adapter. + */ +PNMI_STATIC int MacPrivateConf( +SK_AC *pAC, /* Pointer to adapter context */ +SK_IOC IoC, /* IO context handle */ +int Action, /* GET/PRESET/SET action */ +SK_U32 Id, /* Object ID that is to be processed */ +char *pBuf, /* Buffer used for the management data transfer */ +unsigned int *pLen, /* On call: pBuf buffer length. On return: used buffer */ +SK_U32 Instance, /* Instance (1..n) that is to be queried or -1 */ +unsigned int TableIndex, /* Index to the Id table */ +SK_U32 NetIndex) /* NetIndex (0..n), in single net mode always zero */ +{ + unsigned int PhysPortMax; + unsigned int PhysPortIndex; + unsigned int LogPortMax; + unsigned int LogPortIndex; + unsigned int Limit; + unsigned int Offset; + char Val8; + char *pBufPtr; + int Ret; + SK_EVPARA EventParam; + SK_U32 Val32; + + /* + * Calculate instance if wished. MAC index 0 is the virtual MAC. + */ + PhysPortMax = pAC->GIni.GIMacsFound; + LogPortMax = SK_PNMI_PORT_PHYS2LOG(PhysPortMax); + + if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) { /* Dual net mode */ + LogPortMax--; + } + + if ((Instance != (SK_U32)(-1))) { /* Only one specific instance is queried */ + /* Check instance range */ + if ((Instance < 1) || (Instance > LogPortMax)) { + + *pLen = 0; + return (SK_PNMI_ERR_UNKNOWN_INST); + } + LogPortIndex = SK_PNMI_PORT_INST2LOG(Instance); + Limit = LogPortIndex + 1; + } + + else { /* Instance == (SK_U32)(-1), get all Instances of that OID */ + + LogPortIndex = 0; + Limit = LogPortMax; + } + + /* + * Perform action + */ + if (Action == SK_PNMI_GET) { + + /* Check length */ + switch (Id) { + + case OID_SKGE_PMD: + case OID_SKGE_CONNECTOR: + case OID_SKGE_LINK_CAP: + case OID_SKGE_LINK_MODE: + case OID_SKGE_LINK_MODE_STATUS: + case OID_SKGE_LINK_STATUS: + case OID_SKGE_FLOWCTRL_CAP: + case OID_SKGE_FLOWCTRL_MODE: + case OID_SKGE_FLOWCTRL_STATUS: + case OID_SKGE_PHY_OPERATION_CAP: + case OID_SKGE_PHY_OPERATION_MODE: + case OID_SKGE_PHY_OPERATION_STATUS: + case OID_SKGE_SPEED_CAP: + case OID_SKGE_SPEED_MODE: + case OID_SKGE_SPEED_STATUS: + if (*pLen < (Limit - LogPortIndex) * sizeof(SK_U8)) { + + *pLen = (Limit - LogPortIndex) * sizeof(SK_U8); + return (SK_PNMI_ERR_TOO_SHORT); + } + break; + + case OID_SKGE_MTU: + case OID_SKGE_PHY_TYPE: + if (*pLen < (Limit - LogPortIndex) * sizeof(SK_U32)) { + + *pLen = (Limit - LogPortIndex) * sizeof(SK_U32); + return (SK_PNMI_ERR_TOO_SHORT); + } + break; + + default: + SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR041, + SK_PNMI_ERR041MSG); + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + + /* + * Update statistic and increment semaphore to indicate + * that an update was already done. + */ + if ((Ret = SirqUpdate(pAC, IoC)) != SK_PNMI_ERR_OK) { + + *pLen = 0; + return (Ret); + } + pAC->Pnmi.SirqUpdatedFlag ++; + + /* + * Get value + */ + Offset = 0; + for (; LogPortIndex < Limit; LogPortIndex ++) { + + pBufPtr = pBuf + Offset; + + switch (Id) { + + case OID_SKGE_PMD: + *pBufPtr = pAC->Pnmi.PMD; + Offset += sizeof(char); + break; + + case OID_SKGE_CONNECTOR: + *pBufPtr = pAC->Pnmi.Connector; + Offset += sizeof(char); + break; + + case OID_SKGE_PHY_TYPE: + if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */ + if (LogPortIndex == 0) { + continue; + } + else { + /* Get value for physical ports */ + PhysPortIndex = SK_PNMI_PORT_LOG2PHYS( + pAC, LogPortIndex); + Val32 = pAC->GIni.GP[PhysPortIndex].PhyType; + SK_PNMI_STORE_U32(pBufPtr, Val32); + } + } + else { /* DualNetMode */ + + Val32 = pAC->GIni.GP[NetIndex].PhyType; + SK_PNMI_STORE_U32(pBufPtr, Val32); + } + Offset += sizeof(SK_U32); + break; + + case OID_SKGE_LINK_CAP: + if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */ + if (LogPortIndex == 0) { + /* Get value for virtual port */ + VirtualConf(pAC, IoC, Id, pBufPtr); + } + else { + /* Get value for physical ports */ + PhysPortIndex = SK_PNMI_PORT_LOG2PHYS( + pAC, LogPortIndex); + + *pBufPtr = pAC->GIni.GP[PhysPortIndex].PLinkCap; + } + } + else { /* DualNetMode */ + + *pBufPtr = pAC->GIni.GP[NetIndex].PLinkCap; + } + Offset += sizeof(char); + break; + + case OID_SKGE_LINK_MODE: + if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */ + if (LogPortIndex == 0) { + /* Get value for virtual port */ + VirtualConf(pAC, IoC, Id, pBufPtr); + } + else { + /* Get value for physical ports */ + PhysPortIndex = SK_PNMI_PORT_LOG2PHYS( + pAC, LogPortIndex); + + *pBufPtr = pAC->GIni.GP[PhysPortIndex].PLinkModeConf; + } + } + else { /* DualNetMode */ + + *pBufPtr = pAC->GIni.GP[NetIndex].PLinkModeConf; + } + Offset += sizeof(char); + break; + + case OID_SKGE_LINK_MODE_STATUS: + if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */ + if (LogPortIndex == 0) { + /* Get value for virtual port */ + VirtualConf(pAC, IoC, Id, pBufPtr); + } + else { + /* Get value for physical port */ + PhysPortIndex = SK_PNMI_PORT_LOG2PHYS( + pAC, LogPortIndex); + + *pBufPtr = + CalculateLinkModeStatus(pAC, IoC, PhysPortIndex); + } + } + else { /* DualNetMode */ + + *pBufPtr = CalculateLinkModeStatus(pAC, IoC, NetIndex); + } + Offset += sizeof(char); + break; + + case OID_SKGE_LINK_STATUS: + if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */ + if (LogPortIndex == 0) { + /* Get value for virtual port */ + VirtualConf(pAC, IoC, Id, pBufPtr); + } + else { + /* Get value for physical ports */ + PhysPortIndex = SK_PNMI_PORT_LOG2PHYS( + pAC, LogPortIndex); + + *pBufPtr = CalculateLinkStatus(pAC, IoC, PhysPortIndex); + } + } + else { /* DualNetMode */ + + *pBufPtr = CalculateLinkStatus(pAC, IoC, NetIndex); + } + Offset += sizeof(char); + break; + + case OID_SKGE_FLOWCTRL_CAP: + if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */ + if (LogPortIndex == 0) { + /* Get value for virtual port */ + VirtualConf(pAC, IoC, Id, pBufPtr); + } + else { + /* Get value for physical ports */ + PhysPortIndex = SK_PNMI_PORT_LOG2PHYS( + pAC, LogPortIndex); + + *pBufPtr = pAC->GIni.GP[PhysPortIndex].PFlowCtrlCap; + } + } + else { /* DualNetMode */ + + *pBufPtr = pAC->GIni.GP[NetIndex].PFlowCtrlCap; + } + Offset += sizeof(char); + break; + + case OID_SKGE_FLOWCTRL_MODE: + if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */ + if (LogPortIndex == 0) { + /* Get value for virtual port */ + VirtualConf(pAC, IoC, Id, pBufPtr); + } + else { + /* Get value for physical port */ + PhysPortIndex = SK_PNMI_PORT_LOG2PHYS( + pAC, LogPortIndex); + + *pBufPtr = pAC->GIni.GP[PhysPortIndex].PFlowCtrlMode; + } + } + else { /* DualNetMode */ + + *pBufPtr = pAC->GIni.GP[NetIndex].PFlowCtrlMode; + } + Offset += sizeof(char); + break; + + case OID_SKGE_FLOWCTRL_STATUS: + if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */ + if (LogPortIndex == 0) { + /* Get value for virtual port */ + VirtualConf(pAC, IoC, Id, pBufPtr); + } + else { + /* Get value for physical port */ + PhysPortIndex = SK_PNMI_PORT_LOG2PHYS( + pAC, LogPortIndex); + + *pBufPtr = pAC->GIni.GP[PhysPortIndex].PFlowCtrlStatus; + } + } + else { /* DualNetMode */ + + *pBufPtr = pAC->GIni.GP[NetIndex].PFlowCtrlStatus; + } + Offset += sizeof(char); + break; + + case OID_SKGE_PHY_OPERATION_CAP: + if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */ + if (LogPortIndex == 0) { + /* Get value for virtual port */ + VirtualConf(pAC, IoC, Id, pBufPtr); + } + else { + /* Get value for physical ports */ + PhysPortIndex = SK_PNMI_PORT_LOG2PHYS( + pAC, LogPortIndex); + + *pBufPtr = pAC->GIni.GP[PhysPortIndex].PMSCap; + } + } + else { /* DualNetMode */ + + *pBufPtr = pAC->GIni.GP[NetIndex].PMSCap; + } + Offset += sizeof(char); + break; + + case OID_SKGE_PHY_OPERATION_MODE: + if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */ + if (LogPortIndex == 0) { + /* Get value for virtual port */ + VirtualConf(pAC, IoC, Id, pBufPtr); + } + else { + /* Get value for physical port */ + PhysPortIndex = SK_PNMI_PORT_LOG2PHYS( + pAC, LogPortIndex); + + *pBufPtr = pAC->GIni.GP[PhysPortIndex].PMSMode; + } + } + else { /* DualNetMode */ + + *pBufPtr = pAC->GIni.GP[NetIndex].PMSMode; + } + Offset += sizeof(char); + break; + + case OID_SKGE_PHY_OPERATION_STATUS: + if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */ + if (LogPortIndex == 0) { + /* Get value for virtual port */ + VirtualConf(pAC, IoC, Id, pBufPtr); + } + else { + /* Get value for physical port */ + PhysPortIndex = SK_PNMI_PORT_LOG2PHYS( + pAC, LogPortIndex); + + *pBufPtr = pAC->GIni.GP[PhysPortIndex].PMSStatus; + } + } + else { + + *pBufPtr = pAC->GIni.GP[NetIndex].PMSStatus; + } + Offset += sizeof(char); + break; + + case OID_SKGE_SPEED_CAP: + if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */ + if (LogPortIndex == 0) { + /* Get value for virtual port */ + VirtualConf(pAC, IoC, Id, pBufPtr); + } + else { + /* Get value for physical ports */ + PhysPortIndex = SK_PNMI_PORT_LOG2PHYS( + pAC, LogPortIndex); + + *pBufPtr = pAC->GIni.GP[PhysPortIndex].PLinkSpeedCap; + } + } + else { /* DualNetMode */ + + *pBufPtr = pAC->GIni.GP[NetIndex].PLinkSpeedCap; + } + Offset += sizeof(char); + break; + + case OID_SKGE_SPEED_MODE: + if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */ + if (LogPortIndex == 0) { + /* Get value for virtual port */ + VirtualConf(pAC, IoC, Id, pBufPtr); + } + else { + /* Get value for physical port */ + PhysPortIndex = SK_PNMI_PORT_LOG2PHYS( + pAC, LogPortIndex); + + *pBufPtr = pAC->GIni.GP[PhysPortIndex].PLinkSpeed; + } + } + else { /* DualNetMode */ + + *pBufPtr = pAC->GIni.GP[NetIndex].PLinkSpeed; + } + Offset += sizeof(char); + break; + + case OID_SKGE_SPEED_STATUS: + if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */ + if (LogPortIndex == 0) { + /* Get value for virtual port */ + VirtualConf(pAC, IoC, Id, pBufPtr); + } + else { + /* Get value for physical port */ + PhysPortIndex = SK_PNMI_PORT_LOG2PHYS( + pAC, LogPortIndex); + + *pBufPtr = pAC->GIni.GP[PhysPortIndex].PLinkSpeedUsed; + } + } + else { /* DualNetMode */ + + *pBufPtr = pAC->GIni.GP[NetIndex].PLinkSpeedUsed; + } + Offset += sizeof(char); + break; + + case OID_SKGE_MTU: + Val32 = SK_DRIVER_GET_MTU(pAC, IoC, NetIndex); + SK_PNMI_STORE_U32(pBufPtr, Val32); + Offset += sizeof(SK_U32); + break; + + default: + SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_ERR, + ("MacPrivateConf: Unknown OID should be handled before")); + + pAC->Pnmi.SirqUpdatedFlag --; + return (SK_PNMI_ERR_GENERAL); + } + } + *pLen = Offset; + pAC->Pnmi.SirqUpdatedFlag --; + + return (SK_PNMI_ERR_OK); + } + + /* + * From here SET or PRESET action. Check if the passed + * buffer length is plausible. + */ + switch (Id) { + + case OID_SKGE_LINK_MODE: + case OID_SKGE_FLOWCTRL_MODE: + case OID_SKGE_PHY_OPERATION_MODE: + case OID_SKGE_SPEED_MODE: + if (*pLen < Limit - LogPortIndex) { + + *pLen = Limit - LogPortIndex; + return (SK_PNMI_ERR_TOO_SHORT); + } + if (*pLen != Limit - LogPortIndex) { + + *pLen = 0; + return (SK_PNMI_ERR_BAD_VALUE); + } + break; + + case OID_SKGE_MTU: + if (*pLen < sizeof(SK_U32)) { + + *pLen = sizeof(SK_U32); + return (SK_PNMI_ERR_TOO_SHORT); + } + if (*pLen != sizeof(SK_U32)) { + + *pLen = 0; + return (SK_PNMI_ERR_BAD_VALUE); + } + break; + + default: + *pLen = 0; + return (SK_PNMI_ERR_READ_ONLY); + } + + /* + * Perform preset or set + */ + Offset = 0; + for (; LogPortIndex < Limit; LogPortIndex ++) { + + switch (Id) { + + case OID_SKGE_LINK_MODE: + /* Check the value range */ + Val8 = *(pBuf + Offset); + if (Val8 == 0) { + + Offset += sizeof(char); + break; + } + if (Val8 < SK_LMODE_HALF || + (LogPortIndex != 0 && Val8 > SK_LMODE_AUTOSENSE) || + (LogPortIndex == 0 && Val8 > SK_LMODE_INDETERMINATED)) { + + *pLen = 0; + return (SK_PNMI_ERR_BAD_VALUE); + } + + /* The preset ends here */ + if (Action == SK_PNMI_PRESET) { + + return (SK_PNMI_ERR_OK); + } + + if (LogPortIndex == 0) { + + /* + * The virtual port consists of all currently + * active ports. Find them and send an event + * with the new link mode to SIRQ. + */ + for (PhysPortIndex = 0; + PhysPortIndex < PhysPortMax; + PhysPortIndex ++) { + + if (!pAC->Pnmi.Port[PhysPortIndex]. + ActiveFlag) { + + continue; + } + + EventParam.Para32[0] = PhysPortIndex; + EventParam.Para32[1] = (SK_U32)Val8; + if (SkGeSirqEvent(pAC, IoC, + SK_HWEV_SET_LMODE, + EventParam) > 0) { + + SK_ERR_LOG(pAC, SK_ERRCL_SW, + SK_PNMI_ERR043, + SK_PNMI_ERR043MSG); + + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + } + } + else { + /* + * Send an event with the new link mode to + * the SIRQ module. + */ + EventParam.Para32[0] = SK_PNMI_PORT_LOG2PHYS( + pAC, LogPortIndex); + EventParam.Para32[1] = (SK_U32)Val8; + if (SkGeSirqEvent(pAC, IoC, SK_HWEV_SET_LMODE, + EventParam) > 0) { + + SK_ERR_LOG(pAC, SK_ERRCL_SW, + SK_PNMI_ERR043, + SK_PNMI_ERR043MSG); + + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + } + Offset += sizeof(char); + break; + + case OID_SKGE_FLOWCTRL_MODE: + /* Check the value range */ + Val8 = *(pBuf + Offset); + if (Val8 == 0) { + + Offset += sizeof(char); + break; + } + if (Val8 < SK_FLOW_MODE_NONE || + (LogPortIndex != 0 && Val8 > SK_FLOW_MODE_SYM_OR_REM) || + (LogPortIndex == 0 && Val8 > SK_FLOW_MODE_INDETERMINATED)) { + + *pLen = 0; + return (SK_PNMI_ERR_BAD_VALUE); + } + + /* The preset ends here */ + if (Action == SK_PNMI_PRESET) { + + return (SK_PNMI_ERR_OK); + } + + if (LogPortIndex == 0) { + + /* + * The virtual port consists of all currently + * active ports. Find them and send an event + * with the new flow control mode to SIRQ. + */ + for (PhysPortIndex = 0; + PhysPortIndex < PhysPortMax; + PhysPortIndex ++) { + + if (!pAC->Pnmi.Port[PhysPortIndex]. + ActiveFlag) { + + continue; + } + + EventParam.Para32[0] = PhysPortIndex; + EventParam.Para32[1] = (SK_U32)Val8; + if (SkGeSirqEvent(pAC, IoC, + SK_HWEV_SET_FLOWMODE, + EventParam) > 0) { + + SK_ERR_LOG(pAC, SK_ERRCL_SW, + SK_PNMI_ERR044, + SK_PNMI_ERR044MSG); + + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + } + } + else { + /* + * Send an event with the new flow control + * mode to the SIRQ module. + */ + EventParam.Para32[0] = SK_PNMI_PORT_LOG2PHYS( + pAC, LogPortIndex); + EventParam.Para32[1] = (SK_U32)Val8; + if (SkGeSirqEvent(pAC, IoC, + SK_HWEV_SET_FLOWMODE, EventParam) + > 0) { + + SK_ERR_LOG(pAC, SK_ERRCL_SW, + SK_PNMI_ERR044, + SK_PNMI_ERR044MSG); + + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + } + Offset += sizeof(char); + break; + + case OID_SKGE_PHY_OPERATION_MODE : + /* Check the value range */ + Val8 = *(pBuf + Offset); + if (Val8 == 0) { + /* mode of this port remains unchanged */ + Offset += sizeof(char); + break; + } + if (Val8 < SK_MS_MODE_AUTO || + (LogPortIndex != 0 && Val8 > SK_MS_MODE_SLAVE) || + (LogPortIndex == 0 && Val8 > SK_MS_MODE_INDETERMINATED)) { + + *pLen = 0; + return (SK_PNMI_ERR_BAD_VALUE); + } + + /* The preset ends here */ + if (Action == SK_PNMI_PRESET) { + + return (SK_PNMI_ERR_OK); + } + + if (LogPortIndex == 0) { + + /* + * The virtual port consists of all currently + * active ports. Find them and send an event + * with new master/slave (role) mode to SIRQ. + */ + for (PhysPortIndex = 0; + PhysPortIndex < PhysPortMax; + PhysPortIndex ++) { + + if (!pAC->Pnmi.Port[PhysPortIndex]. + ActiveFlag) { + + continue; + } + + EventParam.Para32[0] = PhysPortIndex; + EventParam.Para32[1] = (SK_U32)Val8; + if (SkGeSirqEvent(pAC, IoC, + SK_HWEV_SET_ROLE, + EventParam) > 0) { + + SK_ERR_LOG(pAC, SK_ERRCL_SW, + SK_PNMI_ERR042, + SK_PNMI_ERR042MSG); + + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + } + } + else { + /* + * Send an event with the new master/slave + * (role) mode to the SIRQ module. + */ + EventParam.Para32[0] = SK_PNMI_PORT_LOG2PHYS( + pAC, LogPortIndex); + EventParam.Para32[1] = (SK_U32)Val8; + if (SkGeSirqEvent(pAC, IoC, + SK_HWEV_SET_ROLE, EventParam) > 0) { + + SK_ERR_LOG(pAC, SK_ERRCL_SW, + SK_PNMI_ERR042, + SK_PNMI_ERR042MSG); + + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + } + + Offset += sizeof(char); + break; + + case OID_SKGE_SPEED_MODE: + /* Check the value range */ + Val8 = *(pBuf + Offset); + if (Val8 == 0) { + + Offset += sizeof(char); + break; + } + if (Val8 < (SK_LSPEED_AUTO) || + (LogPortIndex != 0 && Val8 > (SK_LSPEED_1000MBPS)) || + (LogPortIndex == 0 && Val8 > (SK_LSPEED_INDETERMINATED))) { + + *pLen = 0; + return (SK_PNMI_ERR_BAD_VALUE); + } + + /* The preset ends here */ + if (Action == SK_PNMI_PRESET) { + + return (SK_PNMI_ERR_OK); + } + + if (LogPortIndex == 0) { + + /* + * The virtual port consists of all currently + * active ports. Find them and send an event + * with the new flow control mode to SIRQ. + */ + for (PhysPortIndex = 0; + PhysPortIndex < PhysPortMax; + PhysPortIndex ++) { + + if (!pAC->Pnmi.Port[PhysPortIndex].ActiveFlag) { + + continue; + } + + EventParam.Para32[0] = PhysPortIndex; + EventParam.Para32[1] = (SK_U32)Val8; + if (SkGeSirqEvent(pAC, IoC, + SK_HWEV_SET_SPEED, + EventParam) > 0) { + + SK_ERR_LOG(pAC, SK_ERRCL_SW, + SK_PNMI_ERR045, + SK_PNMI_ERR045MSG); + + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + } + } + else { + /* + * Send an event with the new flow control + * mode to the SIRQ module. + */ + EventParam.Para32[0] = SK_PNMI_PORT_LOG2PHYS( + pAC, LogPortIndex); + EventParam.Para32[1] = (SK_U32)Val8; + if (SkGeSirqEvent(pAC, IoC, + SK_HWEV_SET_SPEED, + EventParam) > 0) { + + SK_ERR_LOG(pAC, SK_ERRCL_SW, + SK_PNMI_ERR045, + SK_PNMI_ERR045MSG); + + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + } + Offset += sizeof(char); + break; + + case OID_SKGE_MTU : + /* Check the value range */ + Val32 = *(SK_U32*)(pBuf + Offset); + if (Val32 == 0) { + /* mtu of this port remains unchanged */ + Offset += sizeof(SK_U32); + break; + } + if (SK_DRIVER_PRESET_MTU(pAC, IoC, NetIndex, Val32) != 0) { + *pLen = 0; + return (SK_PNMI_ERR_BAD_VALUE); + } + + /* The preset ends here */ + if (Action == SK_PNMI_PRESET) { + return (SK_PNMI_ERR_OK); + } + + if (SK_DRIVER_SET_MTU(pAC, IoC, NetIndex, Val32) != 0) { + return (SK_PNMI_ERR_GENERAL); + } + + Offset += sizeof(SK_U32); + break; + + default: + SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_ERR, + ("MacPrivateConf: Unknown OID should be handled before set")); + + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + } + + return (SK_PNMI_ERR_OK); +} + +/***************************************************************************** + * + * Monitor - OID handler function for RLMT_MONITOR_XXX + * + * Description: + * Because RLMT currently does not support the monitoring of + * remote adapter cards, we return always an empty table. + * + * Returns: + * SK_PNMI_ERR_OK The request was successfully performed. + * SK_PNMI_ERR_GENERAL A general severe internal error occured. + * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain + * the correct data (e.g. a 32bit value is + * needed, but a 16 bit value was passed). + * SK_PNMI_ERR_BAD_VALUE The passed value is not in the valid + * value range. + * SK_PNMI_ERR_READ_ONLY The OID is read-only and cannot be set. + * SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't + * exist (e.g. port instance 3 on a two port + * adapter. + */ +PNMI_STATIC int Monitor( +SK_AC *pAC, /* Pointer to adapter context */ +SK_IOC IoC, /* IO context handle */ +int Action, /* GET/PRESET/SET action */ +SK_U32 Id, /* Object ID that is to be processed */ +char *pBuf, /* Buffer used for the management data transfer */ +unsigned int *pLen, /* On call: pBuf buffer length. On return: used buffer */ +SK_U32 Instance, /* Instance (1..n) that is to be queried or -1 */ +unsigned int TableIndex, /* Index to the Id table */ +SK_U32 NetIndex) /* NetIndex (0..n), in single net mode always zero */ +{ + unsigned int Index; + unsigned int Limit; + unsigned int Offset; + unsigned int Entries; + + + /* + * Calculate instance if wished. + */ + /* XXX Not yet implemented. Return always an empty table. */ + Entries = 0; + + if ((Instance != (SK_U32)(-1))) { + + if ((Instance < 1) || (Instance > Entries)) { + + *pLen = 0; + return (SK_PNMI_ERR_UNKNOWN_INST); + } + + Index = (unsigned int)Instance - 1; + Limit = (unsigned int)Instance; + } + else { + Index = 0; + Limit = Entries; + } + + /* + * Get/Set value + */ + if (Action == SK_PNMI_GET) { + + for (Offset=0; Index < Limit; Index ++) { + + switch (Id) { + + case OID_SKGE_RLMT_MONITOR_INDEX: + case OID_SKGE_RLMT_MONITOR_ADDR: + case OID_SKGE_RLMT_MONITOR_ERRS: + case OID_SKGE_RLMT_MONITOR_TIMESTAMP: + case OID_SKGE_RLMT_MONITOR_ADMIN: + break; + + default: + SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR046, + SK_PNMI_ERR046MSG); + + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + } + *pLen = Offset; + } + else { + /* Only MONITOR_ADMIN can be set */ + if (Id != OID_SKGE_RLMT_MONITOR_ADMIN) { + + *pLen = 0; + return (SK_PNMI_ERR_READ_ONLY); + } + + /* Check if the length is plausible */ + if (*pLen < (Limit - Index)) { + + return (SK_PNMI_ERR_TOO_SHORT); + } + /* Okay, we have a wide value range */ + if (*pLen != (Limit - Index)) { + + *pLen = 0; + return (SK_PNMI_ERR_BAD_VALUE); + } +/* + for (Offset=0; Index < Limit; Index ++) { + } +*/ +/* + * XXX Not yet implemented. Return always BAD_VALUE, because the table + * is empty. + */ + *pLen = 0; + return (SK_PNMI_ERR_BAD_VALUE); + } + + return (SK_PNMI_ERR_OK); +} + +/***************************************************************************** + * + * VirtualConf - Calculates the values of configuration OIDs for virtual port + * + * Description: + * We handle here the get of the configuration group OIDs, which are + * a little bit complicated. The virtual port consists of all currently + * active physical ports. If multiple ports are active and configured + * differently we get in some trouble to return a single value. So we + * get the value of the first active port and compare it with that of + * the other active ports. If they are not the same, we return a value + * that indicates that the state is indeterminated. + * + * Returns: + * Nothing + */ +PNMI_STATIC void VirtualConf( +SK_AC *pAC, /* Pointer to adapter context */ +SK_IOC IoC, /* IO context handle */ +SK_U32 Id, /* Object ID that is to be processed */ +char *pBuf) /* Buffer used for the management data transfer */ +{ + unsigned int PhysPortMax; + unsigned int PhysPortIndex; + SK_U8 Val8; + SK_U32 Val32; + SK_BOOL PortActiveFlag; + SK_GEPORT *pPrt; + + *pBuf = 0; + PortActiveFlag = SK_FALSE; + PhysPortMax = pAC->GIni.GIMacsFound; + + for (PhysPortIndex = 0; PhysPortIndex < PhysPortMax; + PhysPortIndex ++) { + + pPrt = &pAC->GIni.GP[PhysPortIndex]; + + /* Check if the physical port is active */ + if (!pAC->Pnmi.Port[PhysPortIndex].ActiveFlag) { + + continue; + } + + PortActiveFlag = SK_TRUE; + + switch (Id) { + + case OID_SKGE_PHY_TYPE: + /* Check if it is the first active port */ + if (*pBuf == 0) { + Val32 = pPrt->PhyType; + SK_PNMI_STORE_U32(pBuf, Val32); + continue; + } + + case OID_SKGE_LINK_CAP: + + /* + * Different capabilities should not happen, but + * in the case of the cases OR them all together. + * From a curious point of view the virtual port + * is capable of all found capabilities. + */ + *pBuf |= pPrt->PLinkCap; + break; + + case OID_SKGE_LINK_MODE: + /* Check if it is the first active port */ + if (*pBuf == 0) { + + *pBuf = pPrt->PLinkModeConf; + continue; + } + + /* + * If we find an active port with a different link + * mode than the first one we return a value that + * indicates that the link mode is indeterminated. + */ + if (*pBuf != pPrt->PLinkModeConf) { + + *pBuf = SK_LMODE_INDETERMINATED; + } + break; + + case OID_SKGE_LINK_MODE_STATUS: + /* Get the link mode of the physical port */ + Val8 = CalculateLinkModeStatus(pAC, IoC, PhysPortIndex); + + /* Check if it is the first active port */ + if (*pBuf == 0) { + + *pBuf = Val8; + continue; + } + + /* + * If we find an active port with a different link + * mode status than the first one we return a value + * that indicates that the link mode status is + * indeterminated. + */ + if (*pBuf != Val8) { + + *pBuf = SK_LMODE_STAT_INDETERMINATED; + } + break; + + case OID_SKGE_LINK_STATUS: + /* Get the link status of the physical port */ + Val8 = CalculateLinkStatus(pAC, IoC, PhysPortIndex); + + /* Check if it is the first active port */ + if (*pBuf == 0) { + + *pBuf = Val8; + continue; + } + + /* + * If we find an active port with a different link + * status than the first one, we return a value + * that indicates that the link status is + * indeterminated. + */ + if (*pBuf != Val8) { + + *pBuf = SK_PNMI_RLMT_LSTAT_INDETERMINATED; + } + break; + + case OID_SKGE_FLOWCTRL_CAP: + /* Check if it is the first active port */ + if (*pBuf == 0) { + + *pBuf = pPrt->PFlowCtrlCap; + continue; + } + + /* + * From a curious point of view the virtual port + * is capable of all found capabilities. + */ + *pBuf |= pPrt->PFlowCtrlCap; + break; + + case OID_SKGE_FLOWCTRL_MODE: + /* Check if it is the first active port */ + if (*pBuf == 0) { + + *pBuf = pPrt->PFlowCtrlMode; + continue; + } + + /* + * If we find an active port with a different flow + * control mode than the first one, we return a value + * that indicates that the mode is indeterminated. + */ + if (*pBuf != pPrt->PFlowCtrlMode) { + + *pBuf = SK_FLOW_MODE_INDETERMINATED; + } + break; + + case OID_SKGE_FLOWCTRL_STATUS: + /* Check if it is the first active port */ + if (*pBuf == 0) { + + *pBuf = pPrt->PFlowCtrlStatus; + continue; + } + + /* + * If we find an active port with a different flow + * control status than the first one, we return a + * value that indicates that the status is + * indeterminated. + */ + if (*pBuf != pPrt->PFlowCtrlStatus) { + + *pBuf = SK_FLOW_STAT_INDETERMINATED; + } + break; + + case OID_SKGE_PHY_OPERATION_CAP: + /* Check if it is the first active port */ + if (*pBuf == 0) { + + *pBuf = pPrt->PMSCap; + continue; + } + + /* + * From a curious point of view the virtual port + * is capable of all found capabilities. + */ + *pBuf |= pPrt->PMSCap; + break; + + case OID_SKGE_PHY_OPERATION_MODE: + /* Check if it is the first active port */ + if (*pBuf == 0) { + + *pBuf = pPrt->PMSMode; + continue; + } + + /* + * If we find an active port with a different master/ + * slave mode than the first one, we return a value + * that indicates that the mode is indeterminated. + */ + if (*pBuf != pPrt->PMSMode) { + + *pBuf = SK_MS_MODE_INDETERMINATED; + } + break; + + case OID_SKGE_PHY_OPERATION_STATUS: + /* Check if it is the first active port */ + if (*pBuf == 0) { + + *pBuf = pPrt->PMSStatus; + continue; + } + + /* + * If we find an active port with a different master/ + * slave status than the first one, we return a + * value that indicates that the status is + * indeterminated. + */ + if (*pBuf != pPrt->PMSStatus) { + + *pBuf = SK_MS_STAT_INDETERMINATED; + } + break; + + case OID_SKGE_SPEED_MODE: + /* Check if it is the first active port */ + if (*pBuf == 0) { + + *pBuf = pPrt->PLinkSpeed; + continue; + } + + /* + * If we find an active port with a different flow + * control mode than the first one, we return a value + * that indicates that the mode is indeterminated. + */ + if (*pBuf != pPrt->PLinkSpeed) { + + *pBuf = SK_LSPEED_INDETERMINATED; + } + break; + + case OID_SKGE_SPEED_STATUS: + /* Check if it is the first active port */ + if (*pBuf == 0) { + + *pBuf = pPrt->PLinkSpeedUsed; + continue; + } + + /* + * If we find an active port with a different flow + * control status than the first one, we return a + * value that indicates that the status is + * indeterminated. + */ + if (*pBuf != pPrt->PLinkSpeedUsed) { + + *pBuf = SK_LSPEED_STAT_INDETERMINATED; + } + break; + } + } + + /* + * If no port is active return an indeterminated answer + */ + if (!PortActiveFlag) { + + switch (Id) { + + case OID_SKGE_LINK_CAP: + *pBuf = SK_LMODE_CAP_INDETERMINATED; + break; + + case OID_SKGE_LINK_MODE: + *pBuf = SK_LMODE_INDETERMINATED; + break; + + case OID_SKGE_LINK_MODE_STATUS: + *pBuf = SK_LMODE_STAT_INDETERMINATED; + break; + + case OID_SKGE_LINK_STATUS: + *pBuf = SK_PNMI_RLMT_LSTAT_INDETERMINATED; + break; + + case OID_SKGE_FLOWCTRL_CAP: + case OID_SKGE_FLOWCTRL_MODE: + *pBuf = SK_FLOW_MODE_INDETERMINATED; + break; + + case OID_SKGE_FLOWCTRL_STATUS: + *pBuf = SK_FLOW_STAT_INDETERMINATED; + break; + + case OID_SKGE_PHY_OPERATION_CAP: + *pBuf = SK_MS_CAP_INDETERMINATED; + break; + + case OID_SKGE_PHY_OPERATION_MODE: + *pBuf = SK_MS_MODE_INDETERMINATED; + break; + + case OID_SKGE_PHY_OPERATION_STATUS: + *pBuf = SK_MS_STAT_INDETERMINATED; + break; + case OID_SKGE_SPEED_CAP: + *pBuf = SK_LSPEED_CAP_INDETERMINATED; + break; + + case OID_SKGE_SPEED_MODE: + *pBuf = SK_LSPEED_INDETERMINATED; + break; + + case OID_SKGE_SPEED_STATUS: + *pBuf = SK_LSPEED_STAT_INDETERMINATED; + break; + } + } +} + +/***************************************************************************** + * + * CalculateLinkStatus - Determins the link status of a physical port + * + * Description: + * Determins the link status the following way: + * LSTAT_PHY_DOWN: Link is down + * LSTAT_AUTONEG: Auto-negotiation failed + * LSTAT_LOG_DOWN: Link is up but RLMT did not yet put the port + * logically up. + * LSTAT_LOG_UP: RLMT marked the port as up + * + * Returns: + * Link status of physical port + */ +PNMI_STATIC SK_U8 CalculateLinkStatus( +SK_AC *pAC, /* Pointer to adapter context */ +SK_IOC IoC, /* IO context handle */ +unsigned int PhysPortIndex) /* Physical port index */ +{ + SK_U8 Result; + + if (!pAC->GIni.GP[PhysPortIndex].PHWLinkUp) { + + Result = SK_PNMI_RLMT_LSTAT_PHY_DOWN; + } + else if (pAC->GIni.GP[PhysPortIndex].PAutoNegFail > 0) { + + Result = SK_PNMI_RLMT_LSTAT_AUTONEG; + } + else if (!pAC->Rlmt.Port[PhysPortIndex].PortDown) { + + Result = SK_PNMI_RLMT_LSTAT_LOG_UP; + } + else { + Result = SK_PNMI_RLMT_LSTAT_LOG_DOWN; + } + + return (Result); +} + +/***************************************************************************** + * + * CalculateLinkModeStatus - Determins the link mode status of a phys. port + * + * Description: + * The COMMON module only tells us if the mode is half or full duplex. + * But in the decade of auto sensing it is useful for the user to + * know if the mode was negotiated or forced. Therefore we have a + * look to the mode, which was last used by the negotiation process. + * + * Returns: + * The link mode status + */ +PNMI_STATIC SK_U8 CalculateLinkModeStatus( +SK_AC *pAC, /* Pointer to adapter context */ +SK_IOC IoC, /* IO context handle */ +unsigned int PhysPortIndex) /* Physical port index */ +{ + SK_U8 Result; + + /* Get the current mode, which can be full or half duplex */ + Result = pAC->GIni.GP[PhysPortIndex].PLinkModeStatus; + + /* Check if no valid mode could be found (link is down) */ + if (Result < SK_LMODE_STAT_HALF) { + + Result = SK_LMODE_STAT_UNKNOWN; + } + else if (pAC->GIni.GP[PhysPortIndex].PLinkMode >= SK_LMODE_AUTOHALF) { + + /* + * Auto-negotiation was used to bring up the link. Change + * the already found duplex status that it indicates + * auto-negotiation was involved. + */ + if (Result == SK_LMODE_STAT_HALF) { + + Result = SK_LMODE_STAT_AUTOHALF; + } + else if (Result == SK_LMODE_STAT_FULL) { + + Result = SK_LMODE_STAT_AUTOFULL; + } + } + + return (Result); +} + +/***************************************************************************** + * + * GetVpdKeyArr - Obtain an array of VPD keys + * + * Description: + * Read the VPD keys and build an array of VPD keys, which are + * easy to access. + * + * Returns: + * SK_PNMI_ERR_OK Task successfully performed. + * SK_PNMI_ERR_GENERAL Something went wrong. + */ +PNMI_STATIC int GetVpdKeyArr( +SK_AC *pAC, /* Pointer to adapter context */ +SK_IOC IoC, /* IO context handle */ +char *pKeyArr, /* Ptr KeyArray */ +unsigned int KeyArrLen, /* Length of array in bytes */ +unsigned int *pKeyNo) /* Number of keys */ +{ + unsigned int BufKeysLen = SK_PNMI_VPD_BUFSIZE; + char BufKeys[SK_PNMI_VPD_BUFSIZE]; + unsigned int StartOffset; + unsigned int Offset; + int Index; + int Ret; + + + SK_MEMSET(pKeyArr, 0, KeyArrLen); + + /* + * Get VPD key list + */ + Ret = VpdKeys(pAC, IoC, (char *)&BufKeys, (int *)&BufKeysLen, + (int *)pKeyNo); + if (Ret > 0) { + + SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR014, + SK_PNMI_ERR014MSG); + + return (SK_PNMI_ERR_GENERAL); + } + /* If no keys are available return now */ + if (*pKeyNo == 0 || BufKeysLen == 0) { + + return (SK_PNMI_ERR_OK); + } + /* + * If the key list is too long for us trunc it and give a + * errorlog notification. This case should not happen because + * the maximum number of keys is limited due to RAM limitations + */ + if (*pKeyNo > SK_PNMI_VPD_ENTRIES) { + + SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR015, + SK_PNMI_ERR015MSG); + + *pKeyNo = SK_PNMI_VPD_ENTRIES; + } + + /* + * Now build an array of fixed string length size and copy + * the keys together. + */ + for (Index = 0, StartOffset = 0, Offset = 0; Offset < BufKeysLen; + Offset ++) { + + if (BufKeys[Offset] != 0) { + + continue; + } + + if (Offset - StartOffset > SK_PNMI_VPD_KEY_SIZE) { + + SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR016, + SK_PNMI_ERR016MSG); + return (SK_PNMI_ERR_GENERAL); + } + + SK_STRNCPY(pKeyArr + Index * SK_PNMI_VPD_KEY_SIZE, + &BufKeys[StartOffset], SK_PNMI_VPD_KEY_SIZE); + + Index ++; + StartOffset = Offset + 1; + } + + /* Last key not zero terminated? Get it anyway */ + if (StartOffset < Offset) { + + SK_STRNCPY(pKeyArr + Index * SK_PNMI_VPD_KEY_SIZE, + &BufKeys[StartOffset], SK_PNMI_VPD_KEY_SIZE); + } + + return (SK_PNMI_ERR_OK); +} + +/***************************************************************************** + * + * SirqUpdate - Let the SIRQ update its internal values + * + * Description: + * Just to be sure that the SIRQ module holds its internal data + * structures up to date, we send an update event before we make + * any access. + * + * Returns: + * SK_PNMI_ERR_OK Task successfully performed. + * SK_PNMI_ERR_GENERAL Something went wrong. + */ +PNMI_STATIC int SirqUpdate( +SK_AC *pAC, /* Pointer to adapter context */ +SK_IOC IoC) /* IO context handle */ +{ + SK_EVPARA EventParam; + + + /* Was the module already updated during the current PNMI call? */ + if (pAC->Pnmi.SirqUpdatedFlag > 0) { + + return (SK_PNMI_ERR_OK); + } + + /* Send an synchronuous update event to the module */ + SK_MEMSET((char *)&EventParam, 0, sizeof(EventParam)); + if (SkGeSirqEvent(pAC, IoC, SK_HWEV_UPDATE_STAT, EventParam) > 0) { + + SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR047, + SK_PNMI_ERR047MSG); + + return (SK_PNMI_ERR_GENERAL); + } + + return (SK_PNMI_ERR_OK); +} + +/***************************************************************************** + * + * RlmtUpdate - Let the RLMT update its internal values + * + * Description: + * Just to be sure that the RLMT module holds its internal data + * structures up to date, we send an update event before we make + * any access. + * + * Returns: + * SK_PNMI_ERR_OK Task successfully performed. + * SK_PNMI_ERR_GENERAL Something went wrong. + */ +PNMI_STATIC int RlmtUpdate( +SK_AC *pAC, /* Pointer to adapter context */ +SK_IOC IoC, /* IO context handle */ +SK_U32 NetIndex) /* NetIndex (0..n), in single net mode allways zero */ +{ + SK_EVPARA EventParam; + + + /* Was the module already updated during the current PNMI call? */ + if (pAC->Pnmi.RlmtUpdatedFlag > 0) { + + return (SK_PNMI_ERR_OK); + } + + /* Send an synchronuous update event to the module */ + SK_MEMSET((char *)&EventParam, 0, sizeof(EventParam)); + EventParam.Para32[0] = NetIndex; + EventParam.Para32[1] = (SK_U32)-1; + if (SkRlmtEvent(pAC, IoC, SK_RLMT_STATS_UPDATE, EventParam) > 0) { + + SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR048, + SK_PNMI_ERR048MSG); + + return (SK_PNMI_ERR_GENERAL); + } + + return (SK_PNMI_ERR_OK); +} + +/***************************************************************************** + * + * MacUpdate - Force the XMAC to output the current statistic + * + * Description: + * The XMAC holds its statistic internally. To obtain the current + * values we must send a command so that the statistic data will + * be written to a predefined memory area on the adapter. + * + * Returns: + * SK_PNMI_ERR_OK Task successfully performed. + * SK_PNMI_ERR_GENERAL Something went wrong. + */ +PNMI_STATIC int MacUpdate( +SK_AC *pAC, /* Pointer to adapter context */ +SK_IOC IoC, /* IO context handle */ +unsigned int FirstMac, /* Index of the first Mac to be updated */ +unsigned int LastMac) /* Index of the last Mac to be updated */ +{ + unsigned int MacIndex; + + /* + * Were the statistics already updated during the + * current PNMI call? + */ + if (pAC->Pnmi.MacUpdatedFlag > 0) { + + return (SK_PNMI_ERR_OK); + } + + /* Send an update command to all MACs specified */ + for (MacIndex = FirstMac; MacIndex <= LastMac; MacIndex ++) { + + /* + * 2002-09-13 pweber: Freeze the current SW counters. + * (That should be done as close as + * possible to the update of the + * HW counters) + */ + if (pAC->GIni.GIMacType == SK_MAC_XMAC) { + pAC->Pnmi.BufPort[MacIndex] = pAC->Pnmi.Port[MacIndex]; + } + + /* 2002-09-13 pweber: Update the HW counter */ + if (pAC->GIni.GIFunc.pFnMacUpdateStats(pAC, IoC, MacIndex) != 0) { + + return (SK_PNMI_ERR_GENERAL); + } + } + + return (SK_PNMI_ERR_OK); +} + +/***************************************************************************** + * + * GetStatVal - Retrieve an XMAC statistic counter + * + * Description: + * Retrieves the statistic counter of a virtual or physical port. The + * virtual port is identified by the index 0. It consists of all + * currently active ports. To obtain the counter value for this port + * we must add the statistic counter of all active ports. To grant + * continuous counter values for the virtual port even when port + * switches occur we must additionally add a delta value, which was + * calculated during a SK_PNMI_EVT_RLMT_ACTIVE_UP event. + * + * Returns: + * Requested statistic value + */ +PNMI_STATIC SK_U64 GetStatVal( +SK_AC *pAC, /* Pointer to adapter context */ +SK_IOC IoC, /* IO context handle */ +unsigned int LogPortIndex, /* Index of the logical Port to be processed */ +unsigned int StatIndex, /* Index to statistic value */ +SK_U32 NetIndex) /* NetIndex (0..n), in single net mode allways zero */ +{ + unsigned int PhysPortIndex; + unsigned int PhysPortMax; + SK_U64 Val = 0; + + + if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) { /* Dual net mode */ + + PhysPortIndex = NetIndex; + + Val = GetPhysStatVal(pAC, IoC, PhysPortIndex, StatIndex); + } + else { /* Single Net mode */ + + if (LogPortIndex == 0) { + + PhysPortMax = pAC->GIni.GIMacsFound; + + /* Add counter of all active ports */ + for (PhysPortIndex = 0; PhysPortIndex < PhysPortMax; + PhysPortIndex ++) { + + if (pAC->Pnmi.Port[PhysPortIndex].ActiveFlag) { + + Val += GetPhysStatVal(pAC, IoC, PhysPortIndex, StatIndex); + } + } + + /* Correct value because of port switches */ + Val += pAC->Pnmi.VirtualCounterOffset[StatIndex]; + } + else { + /* Get counter value of physical port */ + PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(pAC, LogPortIndex); + + Val = GetPhysStatVal(pAC, IoC, PhysPortIndex, StatIndex); + } + } + return (Val); +} + +/***************************************************************************** + * + * GetPhysStatVal - Get counter value for physical port + * + * Description: + * Builds a 64bit counter value. Except for the octet counters + * the lower 32bit are counted in hardware and the upper 32bit + * in software by monitoring counter overflow interrupts in the + * event handler. To grant continous counter values during XMAC + * resets (caused by a workaround) we must add a delta value. + * The delta was calculated in the event handler when a + * SK_PNMI_EVT_XMAC_RESET was received. + * + * Returns: + * Counter value + */ +PNMI_STATIC SK_U64 GetPhysStatVal( +SK_AC *pAC, /* Pointer to adapter context */ +SK_IOC IoC, /* IO context handle */ +unsigned int PhysPortIndex, /* Index of the logical Port to be processed */ +unsigned int StatIndex) /* Index to statistic value */ +{ + SK_U64 Val = 0; + SK_U32 LowVal = 0; + SK_U32 HighVal = 0; + SK_U16 Word; + int MacType; + unsigned int HelpIndex; + SK_GEPORT *pPrt; + + SK_PNMI_PORT *pPnmiPrt; + SK_GEMACFUNC *pFnMac; + + pPrt = &pAC->GIni.GP[PhysPortIndex]; + + MacType = pAC->GIni.GIMacType; + + /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */ + if (MacType == SK_MAC_XMAC) { + pPnmiPrt = &pAC->Pnmi.BufPort[PhysPortIndex]; + } + else { + pPnmiPrt = &pAC->Pnmi.Port[PhysPortIndex]; + } + + pFnMac = &pAC->GIni.GIFunc; + + switch (StatIndex) { + case SK_PNMI_HTX: + if (MacType == SK_MAC_GMAC) { + (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex, + StatAddr[SK_PNMI_HTX_BROADCAST][MacType].Reg, + &LowVal); + (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex, + StatAddr[SK_PNMI_HTX_MULTICAST][MacType].Reg, + &HighVal); + LowVal += HighVal; + (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex, + StatAddr[SK_PNMI_HTX_UNICAST][MacType].Reg, + &HighVal); + LowVal += HighVal; + } + else { + (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex, + StatAddr[StatIndex][MacType].Reg, + &LowVal); + } + HighVal = pPnmiPrt->CounterHigh[StatIndex]; + break; + + case SK_PNMI_HRX: + if (MacType == SK_MAC_GMAC) { + (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex, + StatAddr[SK_PNMI_HRX_BROADCAST][MacType].Reg, + &LowVal); + (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex, + StatAddr[SK_PNMI_HRX_MULTICAST][MacType].Reg, + &HighVal); + LowVal += HighVal; + (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex, + StatAddr[SK_PNMI_HRX_UNICAST][MacType].Reg, + &HighVal); + LowVal += HighVal; + } + else { + (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex, + StatAddr[StatIndex][MacType].Reg, + &LowVal); + } + HighVal = pPnmiPrt->CounterHigh[StatIndex]; + break; + + case SK_PNMI_HTX_OCTET: + case SK_PNMI_HRX_OCTET: + (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex, + StatAddr[StatIndex][MacType].Reg, + &HighVal); + (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex, + StatAddr[StatIndex + 1][MacType].Reg, + &LowVal); + break; + + case SK_PNMI_HTX_BURST: + case SK_PNMI_HTX_EXCESS_DEF: + case SK_PNMI_HTX_CARRIER: + /* Not supported by GMAC */ + if (MacType == SK_MAC_GMAC) { + return (Val); + } + + (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex, + StatAddr[StatIndex][MacType].Reg, + &LowVal); + HighVal = pPnmiPrt->CounterHigh[StatIndex]; + break; + + case SK_PNMI_HTX_MACC: + /* GMAC only supports PAUSE MAC control frames */ + if (MacType == SK_MAC_GMAC) { + HelpIndex = SK_PNMI_HTX_PMACC; + } + else { + HelpIndex = StatIndex; + } + + (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex, + StatAddr[HelpIndex][MacType].Reg, + &LowVal); + + HighVal = pPnmiPrt->CounterHigh[StatIndex]; + break; + + case SK_PNMI_HTX_COL: + case SK_PNMI_HRX_UNDERSIZE: + /* Not supported by XMAC */ + if (MacType == SK_MAC_XMAC) { + return (Val); + } + + (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex, + StatAddr[StatIndex][MacType].Reg, + &LowVal); + HighVal = pPnmiPrt->CounterHigh[StatIndex]; + break; + + case SK_PNMI_HTX_DEFFERAL: + /* Not supported by GMAC */ + if (MacType == SK_MAC_GMAC) { + return (Val); + } + + /* + * XMAC counts frames with deferred transmission + * even in full-duplex mode. + * + * In full-duplex mode the counter remains constant! + */ + if ((pPrt->PLinkModeStatus == SK_LMODE_STAT_AUTOFULL) || + (pPrt->PLinkModeStatus == SK_LMODE_STAT_FULL)) { + + LowVal = 0; + HighVal = 0; + } + else { + /* Otherwise get contents of hardware register */ + (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex, + StatAddr[StatIndex][MacType].Reg, + &LowVal); + HighVal = pPnmiPrt->CounterHigh[StatIndex]; + } + break; + + case SK_PNMI_HRX_BADOCTET: + /* Not supported by XMAC */ + if (MacType == SK_MAC_XMAC) { + return (Val); + } + + (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex, + StatAddr[StatIndex][MacType].Reg, + &HighVal); + (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex, + StatAddr[StatIndex + 1][MacType].Reg, + &LowVal); + break; + + case SK_PNMI_HTX_OCTETLOW: + case SK_PNMI_HRX_OCTETLOW: + case SK_PNMI_HRX_BADOCTETLOW: + return (Val); + + case SK_PNMI_HRX_LONGFRAMES: + /* For XMAC the SW counter is managed by PNMI */ + if (MacType == SK_MAC_XMAC) { + return (pPnmiPrt->StatRxLongFrameCts); + } + + (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex, + StatAddr[StatIndex][MacType].Reg, + &LowVal); + HighVal = pPnmiPrt->CounterHigh[StatIndex]; + break; + + case SK_PNMI_HRX_TOO_LONG: + (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex, + StatAddr[StatIndex][MacType].Reg, + &LowVal); + HighVal = pPnmiPrt->CounterHigh[StatIndex]; + + Val = (((SK_U64)HighVal << 32) | (SK_U64)LowVal); + + if (MacType == SK_MAC_GMAC) { + /* For GMAC the SW counter is additionally managed by PNMI */ + Val += pPnmiPrt->StatRxFrameTooLongCts; + } + else { + /* + * Frames longer than IEEE 802.3 frame max size are counted + * by XMAC in frame_too_long counter even reception of long + * frames was enabled and the frame was correct. + * So correct the value by subtracting RxLongFrame counter. + */ + Val -= pPnmiPrt->StatRxLongFrameCts; + } + + LowVal = (SK_U32)Val; + HighVal = (SK_U32)(Val >> 32); + break; + + case SK_PNMI_HRX_SHORTS: + /* Not supported by GMAC */ + if (MacType == SK_MAC_GMAC) { + /* GM_RXE_FRAG?? */ + return (Val); + } + + /* + * XMAC counts short frame errors even if link down (#10620) + * + * If link-down the counter remains constant + */ + if (pPrt->PLinkModeStatus != SK_LMODE_STAT_UNKNOWN) { + + /* Otherwise get incremental difference */ + (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex, + StatAddr[StatIndex][MacType].Reg, + &LowVal); + HighVal = pPnmiPrt->CounterHigh[StatIndex]; + + Val = (((SK_U64)HighVal << 32) | (SK_U64)LowVal); + Val -= pPnmiPrt->RxShortZeroMark; + + LowVal = (SK_U32)Val; + HighVal = (SK_U32)(Val >> 32); + } + break; + + case SK_PNMI_HRX_MACC: + case SK_PNMI_HRX_MACC_UNKWN: + case SK_PNMI_HRX_BURST: + case SK_PNMI_HRX_MISSED: + case SK_PNMI_HRX_FRAMING: + case SK_PNMI_HRX_CARRIER: + case SK_PNMI_HRX_IRLENGTH: + case SK_PNMI_HRX_SYMBOL: + case SK_PNMI_HRX_CEXT: + /* Not supported by GMAC */ + if (MacType == SK_MAC_GMAC) { + return (Val); + } + + (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex, + StatAddr[StatIndex][MacType].Reg, + &LowVal); + HighVal = pPnmiPrt->CounterHigh[StatIndex]; + break; + + case SK_PNMI_HRX_PMACC_ERR: + /* For GMAC the SW counter is managed by PNMI */ + if (MacType == SK_MAC_GMAC) { + return (pPnmiPrt->StatRxPMaccErr); + } + + (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex, + StatAddr[StatIndex][MacType].Reg, + &LowVal); + HighVal = pPnmiPrt->CounterHigh[StatIndex]; + break; + + /* SW counter managed by PNMI */ + case SK_PNMI_HTX_SYNC: + LowVal = (SK_U32)pPnmiPrt->StatSyncCts; + HighVal = (SK_U32)(pPnmiPrt->StatSyncCts >> 32); + break; + + /* SW counter managed by PNMI */ + case SK_PNMI_HTX_SYNC_OCTET: + LowVal = (SK_U32)pPnmiPrt->StatSyncOctetsCts; + HighVal = (SK_U32)(pPnmiPrt->StatSyncOctetsCts >> 32); + break; + + case SK_PNMI_HRX_FCS: + /* + * Broadcom filters FCS errors and counts it in + * Receive Error Counter register + */ + if (pPrt->PhyType == SK_PHY_BCOM) { + /* do not read while not initialized (PHY_READ hangs!)*/ + if (pPrt->PState != SK_PRT_RESET) { + SkXmPhyRead(pAC, IoC, PhysPortIndex, PHY_BCOM_RE_CTR, &Word); + + LowVal = Word; + } + HighVal = pPnmiPrt->CounterHigh[StatIndex]; + } + else { + (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex, + StatAddr[StatIndex][MacType].Reg, + &LowVal); + HighVal = pPnmiPrt->CounterHigh[StatIndex]; + } + break; + + default: + (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex, + StatAddr[StatIndex][MacType].Reg, + &LowVal); + HighVal = pPnmiPrt->CounterHigh[StatIndex]; + break; + } + + Val = (((SK_U64)HighVal << 32) | (SK_U64)LowVal); + + /* Correct value because of possible XMAC reset. XMAC Errata #2 */ + Val += pPnmiPrt->CounterOffset[StatIndex]; + + return (Val); +} + +/***************************************************************************** + * + * ResetCounter - Set all counters and timestamps to zero + * + * Description: + * Notifies other common modules which store statistic data to + * reset their counters and finally reset our own counters. + * + * Returns: + * Nothing + */ +PNMI_STATIC void ResetCounter( +SK_AC *pAC, /* Pointer to adapter context */ +SK_IOC IoC, /* IO context handle */ +SK_U32 NetIndex) +{ + unsigned int PhysPortIndex; + SK_EVPARA EventParam; + + + SK_MEMSET((char *)&EventParam, 0, sizeof(EventParam)); + + /* Notify sensor module */ + SkEventQueue(pAC, SKGE_I2C, SK_I2CEV_CLEAR, EventParam); + + /* Notify RLMT module */ + EventParam.Para32[0] = NetIndex; + EventParam.Para32[1] = (SK_U32)-1; + SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STATS_CLEAR, EventParam); + EventParam.Para32[1] = 0; + + /* Notify SIRQ module */ + SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_CLEAR_STAT, EventParam); + + /* Notify CSUM module */ +#ifdef SK_USE_CSUM + EventParam.Para32[0] = NetIndex; + EventParam.Para32[1] = (SK_U32)-1; + SkEventQueue(pAC, SKGE_CSUM, SK_CSUM_EVENT_CLEAR_PROTO_STATS, + EventParam); +#endif /* SK_USE_CSUM */ + + /* Clear XMAC statistic */ + for (PhysPortIndex = 0; PhysPortIndex < + (unsigned int)pAC->GIni.GIMacsFound; PhysPortIndex ++) { + + (void)pAC->GIni.GIFunc.pFnMacResetCounter(pAC, IoC, PhysPortIndex); + + SK_MEMSET((char *)&pAC->Pnmi.Port[PhysPortIndex].CounterHigh, + 0, sizeof(pAC->Pnmi.Port[PhysPortIndex].CounterHigh)); + SK_MEMSET((char *)&pAC->Pnmi.Port[PhysPortIndex]. + CounterOffset, 0, sizeof(pAC->Pnmi.Port[ + PhysPortIndex].CounterOffset)); + SK_MEMSET((char *)&pAC->Pnmi.Port[PhysPortIndex].StatSyncCts, + 0, sizeof(pAC->Pnmi.Port[PhysPortIndex].StatSyncCts)); + SK_MEMSET((char *)&pAC->Pnmi.Port[PhysPortIndex]. + StatSyncOctetsCts, 0, sizeof(pAC->Pnmi.Port[ + PhysPortIndex].StatSyncOctetsCts)); + SK_MEMSET((char *)&pAC->Pnmi.Port[PhysPortIndex]. + StatRxLongFrameCts, 0, sizeof(pAC->Pnmi.Port[ + PhysPortIndex].StatRxLongFrameCts)); + SK_MEMSET((char *)&pAC->Pnmi.Port[PhysPortIndex]. + StatRxFrameTooLongCts, 0, sizeof(pAC->Pnmi.Port[ + PhysPortIndex].StatRxFrameTooLongCts)); + SK_MEMSET((char *)&pAC->Pnmi.Port[PhysPortIndex]. + StatRxPMaccErr, 0, sizeof(pAC->Pnmi.Port[ + PhysPortIndex].StatRxPMaccErr)); + } + + /* + * Clear local statistics + */ + SK_MEMSET((char *)&pAC->Pnmi.VirtualCounterOffset, 0, + sizeof(pAC->Pnmi.VirtualCounterOffset)); + pAC->Pnmi.RlmtChangeCts = 0; + pAC->Pnmi.RlmtChangeTime = 0; + SK_MEMSET((char *)&pAC->Pnmi.RlmtChangeEstimate.EstValue[0], 0, + sizeof(pAC->Pnmi.RlmtChangeEstimate.EstValue)); + pAC->Pnmi.RlmtChangeEstimate.EstValueIndex = 0; + pAC->Pnmi.RlmtChangeEstimate.Estimate = 0; + pAC->Pnmi.Port[NetIndex].TxSwQueueMax = 0; + pAC->Pnmi.Port[NetIndex].TxRetryCts = 0; + pAC->Pnmi.Port[NetIndex].RxIntrCts = 0; + pAC->Pnmi.Port[NetIndex].TxIntrCts = 0; + pAC->Pnmi.Port[NetIndex].RxNoBufCts = 0; + pAC->Pnmi.Port[NetIndex].TxNoBufCts = 0; + pAC->Pnmi.Port[NetIndex].TxUsedDescrNo = 0; + pAC->Pnmi.Port[NetIndex].RxDeliveredCts = 0; + pAC->Pnmi.Port[NetIndex].RxOctetsDeliveredCts = 0; + pAC->Pnmi.Port[NetIndex].ErrRecoveryCts = 0; +} + +/***************************************************************************** + * + * GetTrapEntry - Get an entry in the trap buffer + * + * Description: + * The trap buffer stores various events. A user application somehow + * gets notified that an event occured and retrieves the trap buffer + * contens (or simply polls the buffer). The buffer is organized as + * a ring which stores the newest traps at the beginning. The oldest + * traps are overwritten by the newest ones. Each trap entry has a + * unique number, so that applications may detect new trap entries. + * + * Returns: + * A pointer to the trap entry + */ +PNMI_STATIC char* GetTrapEntry( +SK_AC *pAC, /* Pointer to adapter context */ +SK_U32 TrapId, /* SNMP ID of the trap */ +unsigned int Size) /* Space needed for trap entry */ +{ + unsigned int BufPad = pAC->Pnmi.TrapBufPad; + unsigned int BufFree = pAC->Pnmi.TrapBufFree; + unsigned int Beg = pAC->Pnmi.TrapQueueBeg; + unsigned int End = pAC->Pnmi.TrapQueueEnd; + char *pBuf = &pAC->Pnmi.TrapBuf[0]; + int Wrap; + unsigned int NeededSpace; + unsigned int EntrySize; + SK_U32 Val32; + SK_U64 Val64; + + + /* Last byte of entry will get a copy of the entry length */ + Size ++; + + /* + * Calculate needed buffer space */ + if (Beg >= Size) { + + NeededSpace = Size; + Wrap = SK_FALSE; + } + else { + NeededSpace = Beg + Size; + Wrap = SK_TRUE; + } + + /* + * Check if enough buffer space is provided. Otherwise + * free some entries. Leave one byte space between begin + * and end of buffer to make it possible to detect whether + * the buffer is full or empty + */ + while (BufFree < NeededSpace + 1) { + + if (End == 0) { + + End = SK_PNMI_TRAP_QUEUE_LEN; + } + + EntrySize = (unsigned int)*((unsigned char *)pBuf + End - 1); + BufFree += EntrySize; + End -= EntrySize; +#ifdef DEBUG + SK_MEMSET(pBuf + End, (char)(-1), EntrySize); +#endif /* DEBUG */ + if (End == BufPad) { +#ifdef DEBUG + SK_MEMSET(pBuf, (char)(-1), End); +#endif /* DEBUG */ + BufFree += End; + End = 0; + BufPad = 0; + } + } + + /* + * Insert new entry as first entry. Newest entries are + * stored at the beginning of the queue. + */ + if (Wrap) { + + BufPad = Beg; + Beg = SK_PNMI_TRAP_QUEUE_LEN - Size; + } + else { + Beg = Beg - Size; + } + BufFree -= NeededSpace; + + /* Save the current offsets */ + pAC->Pnmi.TrapQueueBeg = Beg; + pAC->Pnmi.TrapQueueEnd = End; + pAC->Pnmi.TrapBufPad = BufPad; + pAC->Pnmi.TrapBufFree = BufFree; + + /* Initialize the trap entry */ + *(pBuf + Beg + Size - 1) = (char)Size; + *(pBuf + Beg) = (char)Size; + Val32 = (pAC->Pnmi.TrapUnique) ++; + SK_PNMI_STORE_U32(pBuf + Beg + 1, Val32); + SK_PNMI_STORE_U32(pBuf + Beg + 1 + sizeof(SK_U32), TrapId); + Val64 = SK_PNMI_HUNDREDS_SEC(SkOsGetTime(pAC)); + SK_PNMI_STORE_U64(pBuf + Beg + 1 + 2 * sizeof(SK_U32), Val64); + + return (pBuf + Beg); +} + +/***************************************************************************** + * + * CopyTrapQueue - Copies the trap buffer for the TRAP OID + * + * Description: + * On a query of the TRAP OID the trap buffer contents will be + * copied continuously to the request buffer, which must be large + * enough. No length check is performed. + * + * Returns: + * Nothing + */ +PNMI_STATIC void CopyTrapQueue( +SK_AC *pAC, /* Pointer to adapter context */ +char *pDstBuf) /* Buffer to which the queued traps will be copied */ +{ + unsigned int BufPad = pAC->Pnmi.TrapBufPad; + unsigned int Trap = pAC->Pnmi.TrapQueueBeg; + unsigned int End = pAC->Pnmi.TrapQueueEnd; + char *pBuf = &pAC->Pnmi.TrapBuf[0]; + unsigned int Len; + unsigned int DstOff = 0; + + + while (Trap != End) { + + Len = (unsigned int)*(pBuf + Trap); + + /* + * Last byte containing a copy of the length will + * not be copied. + */ + *(pDstBuf + DstOff) = (char)(Len - 1); + SK_MEMCPY(pDstBuf + DstOff + 1, pBuf + Trap + 1, Len - 2); + DstOff += Len - 1; + + Trap += Len; + if (Trap == SK_PNMI_TRAP_QUEUE_LEN) { + + Trap = BufPad; + } + } +} + +/***************************************************************************** + * + * GetTrapQueueLen - Get the length of the trap buffer + * + * Description: + * Evaluates the number of currently stored traps and the needed + * buffer size to retrieve them. + * + * Returns: + * Nothing + */ +PNMI_STATIC void GetTrapQueueLen( +SK_AC *pAC, /* Pointer to adapter context */ +unsigned int *pLen, /* Length in Bytes of all queued traps */ +unsigned int *pEntries) /* Returns number of trapes stored in queue */ +{ + unsigned int BufPad = pAC->Pnmi.TrapBufPad; + unsigned int Trap = pAC->Pnmi.TrapQueueBeg; + unsigned int End = pAC->Pnmi.TrapQueueEnd; + char *pBuf = &pAC->Pnmi.TrapBuf[0]; + unsigned int Len; + unsigned int Entries = 0; + unsigned int TotalLen = 0; + + + while (Trap != End) { + + Len = (unsigned int)*(pBuf + Trap); + TotalLen += Len - 1; + Entries ++; + + Trap += Len; + if (Trap == SK_PNMI_TRAP_QUEUE_LEN) { + + Trap = BufPad; + } + } + + *pEntries = Entries; + *pLen = TotalLen; +} + +/***************************************************************************** + * + * QueueSimpleTrap - Store a simple trap to the trap buffer + * + * Description: + * A simple trap is a trap with now additional data. It consists + * simply of a trap code. + * + * Returns: + * Nothing + */ +PNMI_STATIC void QueueSimpleTrap( +SK_AC *pAC, /* Pointer to adapter context */ +SK_U32 TrapId) /* Type of sensor trap */ +{ + GetTrapEntry(pAC, TrapId, SK_PNMI_TRAP_SIMPLE_LEN); +} + +/***************************************************************************** + * + * QueueSensorTrap - Stores a sensor trap in the trap buffer + * + * Description: + * Gets an entry in the trap buffer and fills it with sensor related + * data. + * + * Returns: + * Nothing + */ +PNMI_STATIC void QueueSensorTrap( +SK_AC *pAC, /* Pointer to adapter context */ +SK_U32 TrapId, /* Type of sensor trap */ +unsigned int SensorIndex) /* Index of sensor which caused the trap */ +{ + char *pBuf; + unsigned int Offset; + unsigned int DescrLen; + SK_U32 Val32; + + + /* Get trap buffer entry */ + DescrLen = SK_STRLEN(pAC->I2c.SenTable[SensorIndex].SenDesc); + pBuf = GetTrapEntry(pAC, TrapId, + SK_PNMI_TRAP_SENSOR_LEN_BASE + DescrLen); + Offset = SK_PNMI_TRAP_SIMPLE_LEN; + + /* Store additionally sensor trap related data */ + Val32 = OID_SKGE_SENSOR_INDEX; + SK_PNMI_STORE_U32(pBuf + Offset, Val32); + *(pBuf + Offset + 4) = 4; + Val32 = (SK_U32)SensorIndex; + SK_PNMI_STORE_U32(pBuf + Offset + 5, Val32); + Offset += 9; + + Val32 = (SK_U32)OID_SKGE_SENSOR_DESCR; + SK_PNMI_STORE_U32(pBuf + Offset, Val32); + *(pBuf + Offset + 4) = (char)DescrLen; + SK_MEMCPY(pBuf + Offset + 5, pAC->I2c.SenTable[SensorIndex].SenDesc, + DescrLen); + Offset += DescrLen + 5; + + Val32 = OID_SKGE_SENSOR_TYPE; + SK_PNMI_STORE_U32(pBuf + Offset, Val32); + *(pBuf + Offset + 4) = 1; + *(pBuf + Offset + 5) = (char)pAC->I2c.SenTable[SensorIndex].SenType; + Offset += 6; + + Val32 = OID_SKGE_SENSOR_VALUE; + SK_PNMI_STORE_U32(pBuf + Offset, Val32); + *(pBuf + Offset + 4) = 4; + Val32 = (SK_U32)pAC->I2c.SenTable[SensorIndex].SenValue; + SK_PNMI_STORE_U32(pBuf + Offset + 5, Val32); +} + +/***************************************************************************** + * + * QueueRlmtNewMacTrap - Store a port switch trap in the trap buffer + * + * Description: + * Nothing further to explain. + * + * Returns: + * Nothing + */ +PNMI_STATIC void QueueRlmtNewMacTrap( +SK_AC *pAC, /* Pointer to adapter context */ +unsigned int ActiveMac) /* Index (0..n) of the currently active port */ +{ + char *pBuf; + SK_U32 Val32; + + + pBuf = GetTrapEntry(pAC, OID_SKGE_TRAP_RLMT_CHANGE_PORT, + SK_PNMI_TRAP_RLMT_CHANGE_LEN); + + Val32 = OID_SKGE_RLMT_PORT_ACTIVE; + SK_PNMI_STORE_U32(pBuf + SK_PNMI_TRAP_SIMPLE_LEN, Val32); + *(pBuf + SK_PNMI_TRAP_SIMPLE_LEN + 4) = 1; + *(pBuf + SK_PNMI_TRAP_SIMPLE_LEN + 5) = (char)ActiveMac; +} + +/***************************************************************************** + * + * QueueRlmtPortTrap - Store port related RLMT trap to trap buffer + * + * Description: + * Nothing further to explain. + * + * Returns: + * Nothing + */ +PNMI_STATIC void QueueRlmtPortTrap( +SK_AC *pAC, /* Pointer to adapter context */ +SK_U32 TrapId, /* Type of RLMT port trap */ +unsigned int PortIndex) /* Index of the port, which changed its state */ +{ + char *pBuf; + SK_U32 Val32; + + + pBuf = GetTrapEntry(pAC, TrapId, SK_PNMI_TRAP_RLMT_PORT_LEN); + + Val32 = OID_SKGE_RLMT_PORT_INDEX; + SK_PNMI_STORE_U32(pBuf + SK_PNMI_TRAP_SIMPLE_LEN, Val32); + *(pBuf + SK_PNMI_TRAP_SIMPLE_LEN + 4) = 1; + *(pBuf + SK_PNMI_TRAP_SIMPLE_LEN + 5) = (char)PortIndex; +} + +/***************************************************************************** + * + * CopyMac - Copies a MAC address + * + * Description: + * Nothing further to explain. + * + * Returns: + * Nothing + */ +PNMI_STATIC void CopyMac( +char *pDst, /* Pointer to destination buffer */ +SK_MAC_ADDR *pMac) /* Pointer of Source */ +{ + int i; + + + for (i = 0; i < sizeof(SK_MAC_ADDR); i ++) { + + *(pDst + i) = pMac->a[i]; + } +} + +#ifdef SK_POWER_MGMT +/***************************************************************************** + * + * PowerManagement - OID handler function of PowerManagement OIDs + * + * Description: + * The code is simple. No description necessary. + * + * Returns: + * SK_PNMI_ERR_OK The request was successfully performed. + * SK_PNMI_ERR_GENERAL A general severe internal error occured. + * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain + * the correct data (e.g. a 32bit value is + * needed, but a 16 bit value was passed). + * SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't + * exist (e.g. port instance 3 on a two port + * adapter. + */ + +PNMI_STATIC int PowerManagement( +SK_AC *pAC, /* Pointer to adapter context */ +SK_IOC IoC, /* IO context handle */ +int Action, /* Get/PreSet/Set action */ +SK_U32 Id, /* Object ID that is to be processed */ +char *pBuf, /* Buffer to which to mgmt data will be retrieved */ +unsigned int *pLen, /* On call: buffer length. On return: used buffer */ +SK_U32 Instance, /* Instance (1..n) that is to be queried or -1 */ +unsigned int TableIndex, /* Index to the Id table */ +SK_U32 NetIndex) /* NetIndex (0..n), in single net mode allways zero */ +{ + + SK_U32 RetCode = SK_PNMI_ERR_GENERAL; + + /* + * Check instance. We only handle single instance variables + */ + if (Instance != (SK_U32)(-1) && Instance != 1) { + + *pLen = 0; + return (SK_PNMI_ERR_UNKNOWN_INST); + } + + + /* Check length */ + switch (Id) { + + case OID_PNP_CAPABILITIES: + if (*pLen < sizeof(SK_PNP_CAPABILITIES)) { + + *pLen = sizeof(SK_PNP_CAPABILITIES); + return (SK_PNMI_ERR_TOO_SHORT); + } + break; + + case OID_PNP_SET_POWER: + case OID_PNP_QUERY_POWER: + if (*pLen < sizeof(SK_DEVICE_POWER_STATE)) + { + *pLen = sizeof(SK_DEVICE_POWER_STATE); + return (SK_PNMI_ERR_TOO_SHORT); + } + break; + + case OID_PNP_ADD_WAKE_UP_PATTERN: + case OID_PNP_REMOVE_WAKE_UP_PATTERN: + if (*pLen < sizeof(SK_PM_PACKET_PATTERN)) { + + *pLen = sizeof(SK_PM_PACKET_PATTERN); + return (SK_PNMI_ERR_TOO_SHORT); + } + break; + + case OID_PNP_ENABLE_WAKE_UP: + if (*pLen < sizeof(SK_U32)) { + + *pLen = sizeof(SK_U32); + return (SK_PNMI_ERR_TOO_SHORT); + } + break; + } + + /* + * Perform action + */ + if (Action == SK_PNMI_GET) { + + /* + * Get value + */ + switch (Id) { + + case OID_PNP_CAPABILITIES: + RetCode = SkPowerQueryPnPCapabilities(pAC, IoC, pBuf, pLen); + break; + + case OID_PNP_QUERY_POWER: + /* The Windows DDK describes: An OID_PNP_QUERY_POWER requests + the miniport to indicate whether it can transition its NIC + to the low-power state. + A miniport driver must always return NDIS_STATUS_SUCCESS + to a query of OID_PNP_QUERY_POWER. */ + *pLen = sizeof(SK_DEVICE_POWER_STATE); + RetCode = SK_PNMI_ERR_OK; + break; + + /* NDIS handles these OIDs as write-only. + * So in case of get action the buffer with written length = 0 + * is returned + */ + case OID_PNP_SET_POWER: + case OID_PNP_ADD_WAKE_UP_PATTERN: + case OID_PNP_REMOVE_WAKE_UP_PATTERN: + *pLen = 0; + RetCode = SK_PNMI_ERR_NOT_SUPPORTED; + break; + + case OID_PNP_ENABLE_WAKE_UP: + RetCode = SkPowerGetEnableWakeUp(pAC, IoC, pBuf, pLen); + break; + + default: + RetCode = SK_PNMI_ERR_GENERAL; + break; + } + + return (RetCode); + } + + + /* + * Perform preset or set + */ + + /* POWER module does not support PRESET action */ + if (Action == SK_PNMI_PRESET) { + return (SK_PNMI_ERR_OK); + } + + switch (Id) { + case OID_PNP_SET_POWER: + RetCode = SkPowerSetPower(pAC, IoC, pBuf, pLen); + break; + + case OID_PNP_ADD_WAKE_UP_PATTERN: + RetCode = SkPowerAddWakeUpPattern(pAC, IoC, pBuf, pLen); + break; + + case OID_PNP_REMOVE_WAKE_UP_PATTERN: + RetCode = SkPowerRemoveWakeUpPattern(pAC, IoC, pBuf, pLen); + break; + + case OID_PNP_ENABLE_WAKE_UP: + RetCode = SkPowerSetEnableWakeUp(pAC, IoC, pBuf, pLen); + break; + + default: + RetCode = SK_PNMI_ERR_READ_ONLY; + } + + return (RetCode); +} +#endif /* SK_POWER_MGMT */ + +#ifdef SK_DIAG_SUPPORT +/***************************************************************************** + * + * DiagActions - OID handler function of Diagnostic driver + * + * Description: + * The code is simple. No description necessary. + * + * Returns: + * SK_PNMI_ERR_OK The request was successfully performed. + * SK_PNMI_ERR_GENERAL A general severe internal error occured. + * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain + * the correct data (e.g. a 32bit value is + * needed, but a 16 bit value was passed). + * SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't + * exist (e.g. port instance 3 on a two port + * adapter. + */ + +PNMI_STATIC int DiagActions( +SK_AC *pAC, /* Pointer to adapter context */ +SK_IOC IoC, /* IO context handle */ +int Action, /* GET/PRESET/SET action */ +SK_U32 Id, /* Object ID that is to be processed */ +char *pBuf, /* Buffer used for the management data transfer */ +unsigned int *pLen, /* On call: pBuf buffer length. On return: used buffer */ +SK_U32 Instance, /* Instance (1..n) that is to be queried or -1 */ +unsigned int TableIndex, /* Index to the Id table */ +SK_U32 NetIndex) /* NetIndex (0..n), in single net mode always zero */ +{ + + SK_U32 DiagStatus; + SK_U32 RetCode = SK_PNMI_ERR_GENERAL; + + /* + * Check instance. We only handle single instance variables. + */ + if (Instance != (SK_U32)(-1) && Instance != 1) { + + *pLen = 0; + return (SK_PNMI_ERR_UNKNOWN_INST); + } + + /* + * Check length. + */ + switch (Id) { + + case OID_SKGE_DIAG_MODE: + if (*pLen < sizeof(SK_U32)) { + + *pLen = sizeof(SK_U32); + return (SK_PNMI_ERR_TOO_SHORT); + } + break; + + default: + SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR040, SK_PNMI_ERR040MSG); + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + + /* Perform action. */ + + /* GET value. */ + if (Action == SK_PNMI_GET) { + + switch (Id) { + + case OID_SKGE_DIAG_MODE: + DiagStatus = pAC->Pnmi.DiagAttached; + SK_PNMI_STORE_U32(pBuf, DiagStatus); + *pLen = sizeof(SK_U32); + RetCode = SK_PNMI_ERR_OK; + break; + + default: + *pLen = 0; + RetCode = SK_PNMI_ERR_GENERAL; + break; + } + return (RetCode); + } + + /* From here SET or PRESET value. */ + + /* PRESET value is not supported. */ + if (Action == SK_PNMI_PRESET) { + return (SK_PNMI_ERR_OK); + } + + /* SET value. */ + switch (Id) { + case OID_SKGE_DIAG_MODE: + + /* Handle the SET. */ + switch (*pBuf) { + + /* Attach the DIAG to this adapter. */ + case SK_DIAG_ATTACHED: + /* Check if we come from running */ + if (pAC->Pnmi.DiagAttached == SK_DIAG_RUNNING) { + + RetCode = SkDrvLeaveDiagMode(pAC); + + } + else if (pAC->Pnmi.DiagAttached == SK_DIAG_IDLE) { + + RetCode = SK_PNMI_ERR_OK; + } + + else { + + RetCode = SK_PNMI_ERR_GENERAL; + + } + + if (RetCode == SK_PNMI_ERR_OK) { + + pAC->Pnmi.DiagAttached = SK_DIAG_ATTACHED; + } + break; + + /* Enter the DIAG mode in the driver. */ + case SK_DIAG_RUNNING: + RetCode = SK_PNMI_ERR_OK; + + /* + * If DiagAttached is set, we can tell the driver + * to enter the DIAG mode. + */ + if (pAC->Pnmi.DiagAttached == SK_DIAG_ATTACHED) { + /* If DiagMode is not active, we can enter it. */ + if (!pAC->DiagModeActive) { + + RetCode = SkDrvEnterDiagMode(pAC); + } + else { + + RetCode = SK_PNMI_ERR_GENERAL; + } + } + else { + + RetCode = SK_PNMI_ERR_GENERAL; + } + + if (RetCode == SK_PNMI_ERR_OK) { + + pAC->Pnmi.DiagAttached = SK_DIAG_RUNNING; + } + break; + + case SK_DIAG_IDLE: + /* Check if we come from running */ + if (pAC->Pnmi.DiagAttached == SK_DIAG_RUNNING) { + + RetCode = SkDrvLeaveDiagMode(pAC); + + } + else if (pAC->Pnmi.DiagAttached == SK_DIAG_ATTACHED) { + + RetCode = SK_PNMI_ERR_OK; + } + + else { + + RetCode = SK_PNMI_ERR_GENERAL; + + } + + if (RetCode == SK_PNMI_ERR_OK) { + + pAC->Pnmi.DiagAttached = SK_DIAG_IDLE; + } + break; + + default: + RetCode = SK_PNMI_ERR_BAD_VALUE; + break; + } + break; + + default: + RetCode = SK_PNMI_ERR_GENERAL; + } + + if (RetCode == SK_PNMI_ERR_OK) { + *pLen = sizeof(SK_U32); + } + else { + + *pLen = 0; + } + return (RetCode); +} +#endif /* SK_DIAG_SUPPORT */ + +/***************************************************************************** + * + * Vct - OID handler function of OIDs + * + * Description: + * The code is simple. No description necessary. + * + * Returns: + * SK_PNMI_ERR_OK The request was performed successfully. + * SK_PNMI_ERR_GENERAL A general severe internal error occured. + * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain + * the correct data (e.g. a 32bit value is + * needed, but a 16 bit value was passed). + * SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't + * exist (e.g. port instance 3 on a two port + * adapter). + * SK_PNMI_ERR_READ_ONLY Only the Get action is allowed. + * + */ + +PNMI_STATIC int Vct( +SK_AC *pAC, /* Pointer to adapter context */ +SK_IOC IoC, /* IO context handle */ +int Action, /* GET/PRESET/SET action */ +SK_U32 Id, /* Object ID that is to be processed */ +char *pBuf, /* Buffer used for the management data transfer */ +unsigned int *pLen, /* On call: pBuf buffer length. On return: used buffer */ +SK_U32 Instance, /* Instance (-1,2..n) that is to be queried */ +unsigned int TableIndex, /* Index to the Id table */ +SK_U32 NetIndex) /* NetIndex (0..n), in single net mode always zero */ +{ + SK_GEPORT *pPrt; + SK_PNMI_VCT *pVctBackupData; + SK_U32 LogPortMax; + SK_U32 PhysPortMax; + SK_U32 PhysPortIndex; + SK_U32 Limit; + SK_U32 Offset; + SK_BOOL Link; + SK_U32 RetCode = SK_PNMI_ERR_GENERAL; + int i; + SK_EVPARA Para; + SK_U32 CableLength; + + /* + * Calculate the port indexes from the instance. + */ + PhysPortMax = pAC->GIni.GIMacsFound; + LogPortMax = SK_PNMI_PORT_PHYS2LOG(PhysPortMax); + + /* Dual net mode? */ + if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) { + LogPortMax--; + } + + if ((Instance != (SK_U32) (-1))) { + /* Check instance range. */ + if ((Instance < 2) || (Instance > LogPortMax)) { + *pLen = 0; + return (SK_PNMI_ERR_UNKNOWN_INST); + } + + if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) { + PhysPortIndex = NetIndex; + } + else { + PhysPortIndex = Instance - 2; + } + Limit = PhysPortIndex + 1; + } + else { + /* + * Instance == (SK_U32) (-1), get all Instances of that OID. + * + * Not implemented yet. May be used in future releases. + */ + PhysPortIndex = 0; + Limit = PhysPortMax; + } + + pPrt = &pAC->GIni.GP[PhysPortIndex]; + if (pPrt->PHWLinkUp) { + Link = SK_TRUE; + } + else { + Link = SK_FALSE; + } + + /* Check MAC type */ + if (pPrt->PhyType != SK_PHY_MARV_COPPER) { + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + + /* Initialize backup data pointer. */ + pVctBackupData = &pAC->Pnmi.VctBackup[PhysPortIndex]; + + /* Check action type */ + if (Action == SK_PNMI_GET) { + /* Check length */ + switch (Id) { + + case OID_SKGE_VCT_GET: + if (*pLen < (Limit - PhysPortIndex) * sizeof(SK_PNMI_VCT)) { + *pLen = (Limit - PhysPortIndex) * sizeof(SK_PNMI_VCT); + return (SK_PNMI_ERR_TOO_SHORT); + } + break; + + case OID_SKGE_VCT_STATUS: + if (*pLen < (Limit - PhysPortIndex) * sizeof(SK_U8)) { + *pLen = (Limit - PhysPortIndex) * sizeof(SK_U8); + return (SK_PNMI_ERR_TOO_SHORT); + } + break; + + default: + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + + /* Get value */ + Offset = 0; + for (; PhysPortIndex < Limit; PhysPortIndex++) { + switch (Id) { + + case OID_SKGE_VCT_GET: + if ((Link == SK_FALSE) && + (pAC->Pnmi.VctStatus[PhysPortIndex] & SK_PNMI_VCT_PENDING)) { + RetCode = SkGmCableDiagStatus(pAC, IoC, PhysPortIndex, SK_FALSE); + if (RetCode == 0) { + pAC->Pnmi.VctStatus[PhysPortIndex] &= ~SK_PNMI_VCT_PENDING; + pAC->Pnmi.VctStatus[PhysPortIndex] |= + (SK_PNMI_VCT_NEW_VCT_DATA | SK_PNMI_VCT_TEST_DONE); + + /* Copy results for later use to PNMI struct. */ + for (i = 0; i < 4; i++) { + if (pPrt->PMdiPairSts[i] == SK_PNMI_VCT_NORMAL_CABLE) { + if ((pPrt->PMdiPairLen[i] > 35) && (pPrt->PMdiPairLen[i] < 0xff)) { + pPrt->PMdiPairSts[i] = SK_PNMI_VCT_IMPEDANCE_MISMATCH; + } + } + if ((pPrt->PMdiPairLen[i] > 35) && (pPrt->PMdiPairLen[i] != 0xff)) { + CableLength = 1000 * (((175 * pPrt->PMdiPairLen[i]) / 210) - 28); + } + else { + CableLength = 0; + } + pVctBackupData->PMdiPairLen[i] = CableLength; + pVctBackupData->PMdiPairSts[i] = pPrt->PMdiPairSts[i]; + } + + Para.Para32[0] = PhysPortIndex; + Para.Para32[1] = -1; + SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_RESET, Para); + SkEventDispatcher(pAC, IoC); + } + else { + ; /* VCT test is running. */ + } + } + + /* Get all results. */ + CheckVctStatus(pAC, IoC, pBuf, Offset, PhysPortIndex); + Offset += sizeof(SK_U8); + *(pBuf + Offset) = pPrt->PCableLen; + Offset += sizeof(SK_U8); + for (i = 0; i < 4; i++) { + SK_PNMI_STORE_U32((pBuf + Offset), pVctBackupData->PMdiPairLen[i]); + Offset += sizeof(SK_U32); + } + for (i = 0; i < 4; i++) { + *(pBuf + Offset) = pVctBackupData->PMdiPairSts[i]; + Offset += sizeof(SK_U8); + } + + RetCode = SK_PNMI_ERR_OK; + break; + + case OID_SKGE_VCT_STATUS: + CheckVctStatus(pAC, IoC, pBuf, Offset, PhysPortIndex); + Offset += sizeof(SK_U8); + RetCode = SK_PNMI_ERR_OK; + break; + + default: + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + } /* for */ + *pLen = Offset; + return (RetCode); + + } /* if SK_PNMI_GET */ + + /* + * From here SET or PRESET action. Check if the passed + * buffer length is plausible. + */ + + /* Check length */ + switch (Id) { + case OID_SKGE_VCT_SET: + if (*pLen < (Limit - PhysPortIndex) * sizeof(SK_U32)) { + *pLen = (Limit - PhysPortIndex) * sizeof(SK_U32); + return (SK_PNMI_ERR_TOO_SHORT); + } + break; + + default: + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + + /* + * Perform preset or set. + */ + + /* VCT does not support PRESET action. */ + if (Action == SK_PNMI_PRESET) { + return (SK_PNMI_ERR_OK); + } + + Offset = 0; + for (; PhysPortIndex < Limit; PhysPortIndex++) { + switch (Id) { + case OID_SKGE_VCT_SET: /* Start VCT test. */ + if (Link == SK_FALSE) { + SkGeStopPort(pAC, IoC, PhysPortIndex, SK_STOP_ALL, SK_SOFT_RST); + + RetCode = SkGmCableDiagStatus(pAC, IoC, PhysPortIndex, SK_TRUE); + if (RetCode == 0) { /* RetCode: 0 => Start! */ + pAC->Pnmi.VctStatus[PhysPortIndex] |= SK_PNMI_VCT_PENDING; + pAC->Pnmi.VctStatus[PhysPortIndex] &= ~SK_PNMI_VCT_NEW_VCT_DATA; + pAC->Pnmi.VctStatus[PhysPortIndex] &= ~SK_PNMI_VCT_LINK; + + /* + * Start VCT timer counter. + */ + SK_MEMSET((char *) &Para, 0, sizeof(Para)); + Para.Para32[0] = PhysPortIndex; + Para.Para32[1] = -1; + SkTimerStart(pAC, IoC, &pAC->Pnmi.VctTimeout[PhysPortIndex].VctTimer, + 4000000, SKGE_PNMI, SK_PNMI_EVT_VCT_RESET, Para); + SK_PNMI_STORE_U32((pBuf + Offset), RetCode); + RetCode = SK_PNMI_ERR_OK; + } + else { /* RetCode: 2 => Running! */ + SK_PNMI_STORE_U32((pBuf + Offset), RetCode); + RetCode = SK_PNMI_ERR_OK; + } + } + else { /* RetCode: 4 => Link! */ + RetCode = 4; + SK_PNMI_STORE_U32((pBuf + Offset), RetCode); + RetCode = SK_PNMI_ERR_OK; + } + Offset += sizeof(SK_U32); + break; + + default: + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + } /* for */ + *pLen = Offset; + return (RetCode); + +} /* Vct */ + + +PNMI_STATIC void CheckVctStatus( +SK_AC *pAC, +SK_IOC IoC, +char *pBuf, +SK_U32 Offset, +SK_U32 PhysPortIndex) +{ + SK_GEPORT *pPrt; + SK_PNMI_VCT *pVctData; + SK_U32 RetCode; + + pPrt = &pAC->GIni.GP[PhysPortIndex]; + + pVctData = (SK_PNMI_VCT *) (pBuf + Offset); + pVctData->VctStatus = SK_PNMI_VCT_NONE; + + if (!pPrt->PHWLinkUp) { + + /* Was a VCT test ever made before? */ + if (pAC->Pnmi.VctStatus[PhysPortIndex] & SK_PNMI_VCT_TEST_DONE) { + if ((pAC->Pnmi.VctStatus[PhysPortIndex] & SK_PNMI_VCT_LINK)) { + pVctData->VctStatus |= SK_PNMI_VCT_OLD_VCT_DATA; + } + else { + pVctData->VctStatus |= SK_PNMI_VCT_NEW_VCT_DATA; + } + } + + /* Check VCT test status. */ + RetCode = SkGmCableDiagStatus(pAC,IoC, PhysPortIndex, SK_FALSE); + if (RetCode == 2) { /* VCT test is running. */ + pVctData->VctStatus |= SK_PNMI_VCT_RUNNING; + } + else { /* VCT data was copied to pAC here. Check PENDING state. */ + if (pAC->Pnmi.VctStatus[PhysPortIndex] & SK_PNMI_VCT_PENDING) { + pVctData->VctStatus |= SK_PNMI_VCT_NEW_VCT_DATA; + } + } + + if (pPrt->PCableLen != 0xff) { /* Old DSP value. */ + pVctData->VctStatus |= SK_PNMI_VCT_OLD_DSP_DATA; + } + } + else { + + /* Was a VCT test ever made before? */ + if (pAC->Pnmi.VctStatus[PhysPortIndex] & SK_PNMI_VCT_TEST_DONE) { + pVctData->VctStatus &= ~SK_PNMI_VCT_NEW_VCT_DATA; + pVctData->VctStatus |= SK_PNMI_VCT_OLD_VCT_DATA; + } + + /* DSP only valid in 100/1000 modes. */ + if (pAC->GIni.GP[PhysPortIndex].PLinkSpeedUsed != + SK_LSPEED_STAT_10MBPS) { + pVctData->VctStatus |= SK_PNMI_VCT_NEW_DSP_DATA; + } + } +} /* CheckVctStatus */ + + +/***************************************************************************** + * + * SkPnmiGenIoctl - Handles new generic PNMI IOCTL, calls the needed + * PNMI function depending on the subcommand and + * returns all data belonging to the complete database + * or OID request. + * + * Description: + * Looks up the requested subcommand, calls the corresponding handler + * function and passes all required parameters to it. + * The function is called by the driver. It is needed to handle the new + * generic PNMI IOCTL. This IOCTL is given to the driver and contains both + * the OID and a subcommand to decide what kind of request has to be done. + * + * Returns: + * SK_PNMI_ERR_OK The request was successfully performed + * SK_PNMI_ERR_GENERAL A general severe internal error occured + * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to take + * the data. + * SK_PNMI_ERR_UNKNOWN_OID The requested OID is unknown + * SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't + * exist (e.g. port instance 3 on a two port + * adapter. + */ +int SkPnmiGenIoctl( +SK_AC *pAC, /* Pointer to adapter context struct */ +SK_IOC IoC, /* I/O context */ +void *pBuf, /* Buffer used for the management data transfer */ +unsigned int *pLen, /* Length of buffer */ +SK_U32 NetIndex) /* NetIndex (0..n), in single net mode always zero */ +{ +SK_I32 Mode; /* Store value of subcommand. */ +SK_U32 Oid; /* Store value of OID. */ +int ReturnCode; /* Store return value to show status of PNMI action. */ +int HeaderLength; /* Length of desired action plus OID. */ + + ReturnCode = SK_PNMI_ERR_GENERAL; + + SK_MEMCPY(&Mode, pBuf, sizeof(SK_I32)); + SK_MEMCPY(&Oid, (char *) pBuf + sizeof(SK_I32), sizeof(SK_U32)); + HeaderLength = sizeof(SK_I32) + sizeof(SK_U32); + *pLen = *pLen - HeaderLength; + SK_MEMCPY((char *) pBuf + sizeof(SK_I32), (char *) pBuf + HeaderLength, *pLen); + + switch(Mode) { + case SK_GET_SINGLE_VAR: + ReturnCode = SkPnmiGetVar(pAC, IoC, Oid, + (char *) pBuf + sizeof(SK_I32), pLen, + ((SK_U32) (-1)), NetIndex); + SK_PNMI_STORE_U32(pBuf, ReturnCode); + *pLen = *pLen + sizeof(SK_I32); + break; + case SK_PRESET_SINGLE_VAR: + ReturnCode = SkPnmiPreSetVar(pAC, IoC, Oid, + (char *) pBuf + sizeof(SK_I32), pLen, + ((SK_U32) (-1)), NetIndex); + SK_PNMI_STORE_U32(pBuf, ReturnCode); + *pLen = *pLen + sizeof(SK_I32); + break; + case SK_SET_SINGLE_VAR: + ReturnCode = SkPnmiSetVar(pAC, IoC, Oid, + (char *) pBuf + sizeof(SK_I32), pLen, + ((SK_U32) (-1)), NetIndex); + SK_PNMI_STORE_U32(pBuf, ReturnCode); + *pLen = *pLen + sizeof(SK_I32); + break; + case SK_GET_FULL_MIB: + ReturnCode = SkPnmiGetStruct(pAC, IoC, pBuf, pLen, NetIndex); + break; + case SK_PRESET_FULL_MIB: + ReturnCode = SkPnmiPreSetStruct(pAC, IoC, pBuf, pLen, NetIndex); + break; + case SK_SET_FULL_MIB: + ReturnCode = SkPnmiSetStruct(pAC, IoC, pBuf, pLen, NetIndex); + break; + default: + break; + } + + return (ReturnCode); + +} /* SkGeIocGen */ diff --git a/drivers/net/sk98lin/skgesirq.c b/drivers/net/sk98lin/skgesirq.c new file mode 100644 index 000000000000..3e7aa49afd00 --- /dev/null +++ b/drivers/net/sk98lin/skgesirq.c @@ -0,0 +1,2229 @@ +/****************************************************************************** + * + * Name: skgesirq.c + * Project: Gigabit Ethernet Adapters, Common Modules + * Version: $Revision: 1.92 $ + * Date: $Date: 2003/09/16 14:37:07 $ + * Purpose: Special IRQ module + * + ******************************************************************************/ + +/****************************************************************************** + * + * (C)Copyright 1998-2002 SysKonnect. + * (C)Copyright 2002-2003 Marvell. + * + * 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. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/* + * Special Interrupt handler + * + * The following abstract should show how this module is included + * in the driver path: + * + * In the ISR of the driver the bits for frame transmission complete and + * for receive complete are checked and handled by the driver itself. + * The bits of the slow path mask are checked after that and then the + * entry into the so-called "slow path" is prepared. It is an implementors + * decision whether this is executed directly or just scheduled by + * disabling the mask. In the interrupt service routine some events may be + * generated, so it would be a good idea to call the EventDispatcher + * right after this ISR. + * + * The Interrupt source register of the adapter is NOT read by this module. + * SO if the drivers implementor needs a while loop around the + * slow data paths interrupt bits, he needs to call the SkGeSirqIsr() for + * each loop entered. + * + * However, the MAC Interrupt status registers are read in a while loop. + * + */ + +#if (defined(DEBUG) || ((!defined(LINT)) && (!defined(SK_SLIM)))) +static const char SysKonnectFileId[] = + "@(#) $Id: skgesirq.c,v 1.92 2003/09/16 14:37:07 rschmidt Exp $ (C) Marvell."; +#endif + +#include "h/skdrv1st.h" /* Driver Specific Definitions */ +#ifndef SK_SLIM +#include "h/skgepnmi.h" /* PNMI Definitions */ +#include "h/skrlmt.h" /* RLMT Definitions */ +#endif +#include "h/skdrv2nd.h" /* Adapter Control and Driver specific Def. */ + +/* local function prototypes */ +#ifdef GENESIS +static int SkGePortCheckUpXmac(SK_AC*, SK_IOC, int, SK_BOOL); +static int SkGePortCheckUpBcom(SK_AC*, SK_IOC, int, SK_BOOL); +static void SkPhyIsrBcom(SK_AC*, SK_IOC, int, SK_U16); +#endif /* GENESIS */ +#ifdef YUKON +static int SkGePortCheckUpGmac(SK_AC*, SK_IOC, int, SK_BOOL); +static void SkPhyIsrGmac(SK_AC*, SK_IOC, int, SK_U16); +#endif /* YUKON */ +#ifdef OTHER_PHY +static int SkGePortCheckUpLone(SK_AC*, SK_IOC, int, SK_BOOL); +static int SkGePortCheckUpNat(SK_AC*, SK_IOC, int, SK_BOOL); +static void SkPhyIsrLone(SK_AC*, SK_IOC, int, SK_U16); +#endif /* OTHER_PHY */ + +#ifdef GENESIS +/* + * array of Rx counter from XMAC which are checked + * in AutoSense mode to check whether a link is not able to auto-negotiate. + */ +static const SK_U16 SkGeRxRegs[]= { + XM_RXF_64B, + XM_RXF_127B, + XM_RXF_255B, + XM_RXF_511B, + XM_RXF_1023B, + XM_RXF_MAX_SZ +} ; +#endif /* GENESIS */ + +#ifdef __C2MAN__ +/* + * Special IRQ function + * + * General Description: + * + */ +intro() +{} +#endif + +/****************************************************************************** + * + * SkHWInitDefSense() - Default Autosensing mode initialization + * + * Description: sets the PLinkMode for HWInit + * + * Returns: N/A + */ +static void SkHWInitDefSense( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port) /* Port Index (MAC_1 + n) */ +{ + SK_GEPORT *pPrt; /* GIni Port struct pointer */ + + pPrt = &pAC->GIni.GP[Port]; + + pPrt->PAutoNegTimeOut = 0; + + if (pPrt->PLinkModeConf != SK_LMODE_AUTOSENSE) { + pPrt->PLinkMode = pPrt->PLinkModeConf; + return; + } + + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ, + ("AutoSensing: First mode %d on Port %d\n", + (int)SK_LMODE_AUTOFULL, Port)); + + pPrt->PLinkMode = (SK_U8)SK_LMODE_AUTOFULL; + + return; +} /* SkHWInitDefSense */ + + +#ifdef GENESIS +/****************************************************************************** + * + * SkHWSenseGetNext() - Get Next Autosensing Mode + * + * Description: gets the appropriate next mode + * + * Note: + * + */ +static SK_U8 SkHWSenseGetNext( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port) /* Port Index (MAC_1 + n) */ +{ + SK_GEPORT *pPrt; /* GIni Port struct pointer */ + + pPrt = &pAC->GIni.GP[Port]; + + pPrt->PAutoNegTimeOut = 0; + + if (pPrt->PLinkModeConf != (SK_U8)SK_LMODE_AUTOSENSE) { + /* Leave all as configured */ + return(pPrt->PLinkModeConf); + } + + if (pPrt->PLinkMode == (SK_U8)SK_LMODE_AUTOFULL) { + /* Return next mode AUTOBOTH */ + return ((SK_U8)SK_LMODE_AUTOBOTH); + } + + /* Return default autofull */ + return ((SK_U8)SK_LMODE_AUTOFULL); +} /* SkHWSenseGetNext */ + + +/****************************************************************************** + * + * SkHWSenseSetNext() - Autosensing Set next mode + * + * Description: sets the appropriate next mode + * + * Returns: N/A + */ +static void SkHWSenseSetNext( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port, /* Port Index (MAC_1 + n) */ +SK_U8 NewMode) /* New Mode to be written in sense mode */ +{ + SK_GEPORT *pPrt; /* GIni Port struct pointer */ + + pPrt = &pAC->GIni.GP[Port]; + + pPrt->PAutoNegTimeOut = 0; + + if (pPrt->PLinkModeConf != (SK_U8)SK_LMODE_AUTOSENSE) { + return; + } + + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ, + ("AutoSensing: next mode %d on Port %d\n", + (int)NewMode, Port)); + + pPrt->PLinkMode = NewMode; + + return; +} /* SkHWSenseSetNext */ +#endif /* GENESIS */ + + +/****************************************************************************** + * + * SkHWLinkDown() - Link Down handling + * + * Description: handles the hardware link down signal + * + * Returns: N/A + */ +void SkHWLinkDown( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port) /* Port Index (MAC_1 + n) */ +{ + SK_GEPORT *pPrt; /* GIni Port struct pointer */ + + pPrt = &pAC->GIni.GP[Port]; + + /* Disable all MAC interrupts */ + SkMacIrqDisable(pAC, IoC, Port); + + /* Disable Receiver and Transmitter */ + SkMacRxTxDisable(pAC, IoC, Port); + + /* Init default sense mode */ + SkHWInitDefSense(pAC, IoC, Port); + + if (pPrt->PHWLinkUp == SK_FALSE) { + return; + } + + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ, + ("Link down Port %d\n", Port)); + + /* Set Link to DOWN */ + pPrt->PHWLinkUp = SK_FALSE; + + /* Reset Port stati */ + pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_UNKNOWN; + pPrt->PFlowCtrlStatus = (SK_U8)SK_FLOW_STAT_NONE; + pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_INDETERMINATED; + + /* Re-init Phy especially when the AutoSense default is set now */ + SkMacInitPhy(pAC, IoC, Port, SK_FALSE); + + /* GP0: used for workaround of Rev. C Errata 2 */ + + /* Do NOT signal to RLMT */ + + /* Do NOT start the timer here */ +} /* SkHWLinkDown */ + + +/****************************************************************************** + * + * SkHWLinkUp() - Link Up handling + * + * Description: handles the hardware link up signal + * + * Returns: N/A + */ +static void SkHWLinkUp( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port) /* Port Index (MAC_1 + n) */ +{ + SK_GEPORT *pPrt; /* GIni Port struct pointer */ + + pPrt = &pAC->GIni.GP[Port]; + + if (pPrt->PHWLinkUp) { + /* We do NOT need to proceed on active link */ + return; + } + + pPrt->PHWLinkUp = SK_TRUE; + pPrt->PAutoNegFail = SK_FALSE; + pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_UNKNOWN; + + if (pPrt->PLinkMode != (SK_U8)SK_LMODE_AUTOHALF && + pPrt->PLinkMode != (SK_U8)SK_LMODE_AUTOFULL && + pPrt->PLinkMode != (SK_U8)SK_LMODE_AUTOBOTH) { + /* Link is up and no Auto-negotiation should be done */ + + /* Link speed should be the configured one */ + switch (pPrt->PLinkSpeed) { + case SK_LSPEED_AUTO: + /* default is 1000 Mbps */ + case SK_LSPEED_1000MBPS: + pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_1000MBPS; + break; + case SK_LSPEED_100MBPS: + pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_100MBPS; + break; + case SK_LSPEED_10MBPS: + pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_10MBPS; + break; + } + + /* Set Link Mode Status */ + if (pPrt->PLinkMode == SK_LMODE_FULL) { + pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_FULL; + } + else { + pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_HALF; + } + + /* No flow control without auto-negotiation */ + pPrt->PFlowCtrlStatus = (SK_U8)SK_FLOW_STAT_NONE; + + /* enable Rx/Tx */ + (void)SkMacRxTxEnable(pAC, IoC, Port); + } +} /* SkHWLinkUp */ + + +/****************************************************************************** + * + * SkMacParity() - MAC parity workaround + * + * Description: handles MAC parity errors correctly + * + * Returns: N/A + */ +static void SkMacParity( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port) /* Port Index of the port failed */ +{ + SK_EVPARA Para; + SK_GEPORT *pPrt; /* GIni Port struct pointer */ + SK_U32 TxMax; /* Tx Max Size Counter */ + + pPrt = &pAC->GIni.GP[Port]; + + /* Clear IRQ Tx Parity Error */ +#ifdef GENESIS + if (pAC->GIni.GIGenesis) { + + SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), MFF_CLR_PERR); + } +#endif /* GENESIS */ + +#ifdef YUKON + if (pAC->GIni.GIYukon) { + /* HW-Bug #8: cleared by GMF_CLI_TX_FC instead of GMF_CLI_TX_PE */ + SK_OUT8(IoC, MR_ADDR(Port, TX_GMF_CTRL_T), + (SK_U8)((pAC->GIni.GIChipId == CHIP_ID_YUKON && + pAC->GIni.GIChipRev == 0) ? GMF_CLI_TX_FC : GMF_CLI_TX_PE)); + } +#endif /* YUKON */ + + if (pPrt->PCheckPar) { + + if (Port == MAC_1) { + SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E016, SKERR_SIRQ_E016MSG); + } + else { + SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E017, SKERR_SIRQ_E017MSG); + } + Para.Para64 = Port; + SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para); + + Para.Para32[0] = Port; + SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para); + + return; + } + + /* Check whether frames with a size of 1k were sent */ +#ifdef GENESIS + if (pAC->GIni.GIGenesis) { + /* Snap statistic counters */ + (void)SkXmUpdateStats(pAC, IoC, Port); + + (void)SkXmMacStatistic(pAC, IoC, Port, XM_TXF_MAX_SZ, &TxMax); + } +#endif /* GENESIS */ + +#ifdef YUKON + if (pAC->GIni.GIYukon) { + + (void)SkGmMacStatistic(pAC, IoC, Port, GM_TXF_1518B, &TxMax); + } +#endif /* YUKON */ + + if (TxMax > 0) { + /* From now on check the parity */ + pPrt->PCheckPar = SK_TRUE; + } +} /* SkMacParity */ + + +/****************************************************************************** + * + * SkGeHwErr() - Hardware Error service routine + * + * Description: handles all HW Error interrupts + * + * Returns: N/A + */ +static void SkGeHwErr( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +SK_U32 HwStatus) /* Interrupt status word */ +{ + SK_EVPARA Para; + SK_U16 Word; + + if ((HwStatus & (IS_IRQ_MST_ERR | IS_IRQ_STAT)) != 0) { + /* PCI Errors occured */ + if ((HwStatus & IS_IRQ_STAT) != 0) { + SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E013, SKERR_SIRQ_E013MSG); + } + else { + SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E012, SKERR_SIRQ_E012MSG); + } + + /* Reset all bits in the PCI STATUS register */ + SK_IN16(IoC, PCI_C(PCI_STATUS), &Word); + + SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_ON); + SK_OUT16(IoC, PCI_C(PCI_STATUS), (SK_U16)(Word | PCI_ERRBITS)); + SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_OFF); + + Para.Para64 = 0; + SkEventQueue(pAC, SKGE_DRV, SK_DRV_ADAP_FAIL, Para); + } + +#ifdef GENESIS + if (pAC->GIni.GIGenesis) { + + if ((HwStatus & IS_NO_STAT_M1) != 0) { + /* Ignore it */ + /* This situation is also indicated in the descriptor */ + SK_OUT16(IoC, MR_ADDR(MAC_1, RX_MFF_CTRL1), MFF_CLR_INSTAT); + } + + if ((HwStatus & IS_NO_STAT_M2) != 0) { + /* Ignore it */ + /* This situation is also indicated in the descriptor */ + SK_OUT16(IoC, MR_ADDR(MAC_2, RX_MFF_CTRL1), MFF_CLR_INSTAT); + } + + if ((HwStatus & IS_NO_TIST_M1) != 0) { + /* Ignore it */ + /* This situation is also indicated in the descriptor */ + SK_OUT16(IoC, MR_ADDR(MAC_1, RX_MFF_CTRL1), MFF_CLR_INTIST); + } + + if ((HwStatus & IS_NO_TIST_M2) != 0) { + /* Ignore it */ + /* This situation is also indicated in the descriptor */ + SK_OUT16(IoC, MR_ADDR(MAC_2, RX_MFF_CTRL1), MFF_CLR_INTIST); + } + } +#endif /* GENESIS */ + +#ifdef YUKON + if (pAC->GIni.GIYukon) { + /* This is necessary only for Rx timing measurements */ + if ((HwStatus & IS_IRQ_TIST_OV) != 0) { + /* increment Time Stamp Timer counter (high) */ + pAC->GIni.GITimeStampCnt++; + + /* Clear Time Stamp Timer IRQ */ + SK_OUT8(IoC, GMAC_TI_ST_CTRL, (SK_U8)GMT_ST_CLR_IRQ); + } + + if ((HwStatus & IS_IRQ_SENSOR) != 0) { + /* no sensors on 32-bit Yukon */ + if (pAC->GIni.GIYukon32Bit) { + /* disable HW Error IRQ */ + pAC->GIni.GIValIrqMask &= ~IS_HW_ERR; + } + } + } +#endif /* YUKON */ + + if ((HwStatus & IS_RAM_RD_PAR) != 0) { + SK_OUT16(IoC, B3_RI_CTRL, RI_CLR_RD_PERR); + SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E014, SKERR_SIRQ_E014MSG); + Para.Para64 = 0; + SkEventQueue(pAC, SKGE_DRV, SK_DRV_ADAP_FAIL, Para); + } + + if ((HwStatus & IS_RAM_WR_PAR) != 0) { + SK_OUT16(IoC, B3_RI_CTRL, RI_CLR_WR_PERR); + SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E015, SKERR_SIRQ_E015MSG); + Para.Para64 = 0; + SkEventQueue(pAC, SKGE_DRV, SK_DRV_ADAP_FAIL, Para); + } + + if ((HwStatus & IS_M1_PAR_ERR) != 0) { + SkMacParity(pAC, IoC, MAC_1); + } + + if ((HwStatus & IS_M2_PAR_ERR) != 0) { + SkMacParity(pAC, IoC, MAC_2); + } + + if ((HwStatus & IS_R1_PAR_ERR) != 0) { + /* Clear IRQ */ + SK_OUT32(IoC, B0_R1_CSR, CSR_IRQ_CL_P); + + SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E018, SKERR_SIRQ_E018MSG); + Para.Para64 = MAC_1; + SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para); + + Para.Para32[0] = MAC_1; + SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para); + } + + if ((HwStatus & IS_R2_PAR_ERR) != 0) { + /* Clear IRQ */ + SK_OUT32(IoC, B0_R2_CSR, CSR_IRQ_CL_P); + + SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E019, SKERR_SIRQ_E019MSG); + Para.Para64 = MAC_2; + SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para); + + Para.Para32[0] = MAC_2; + SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para); + } +} /* SkGeHwErr */ + + +/****************************************************************************** + * + * SkGeSirqIsr() - Special Interrupt Service Routine + * + * Description: handles all non data transfer specific interrupts (slow path) + * + * Returns: N/A + */ +void SkGeSirqIsr( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +SK_U32 Istatus) /* Interrupt status word */ +{ + SK_EVPARA Para; + SK_U32 RegVal32; /* Read register value */ + SK_GEPORT *pPrt; /* GIni Port struct pointer */ + SK_U16 PhyInt; + int i; + + if (((Istatus & IS_HW_ERR) & pAC->GIni.GIValIrqMask) != 0) { + /* read the HW Error Interrupt source */ + SK_IN32(IoC, B0_HWE_ISRC, &RegVal32); + + SkGeHwErr(pAC, IoC, RegVal32); + } + + /* + * Packet Timeout interrupts + */ + /* Check whether MACs are correctly initialized */ + if (((Istatus & (IS_PA_TO_RX1 | IS_PA_TO_TX1)) != 0) && + pAC->GIni.GP[MAC_1].PState == SK_PRT_RESET) { + /* MAC 1 was not initialized but Packet timeout occured */ + SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E004, + SKERR_SIRQ_E004MSG); + } + + if (((Istatus & (IS_PA_TO_RX2 | IS_PA_TO_TX2)) != 0) && + pAC->GIni.GP[MAC_2].PState == SK_PRT_RESET) { + /* MAC 2 was not initialized but Packet timeout occured */ + SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E005, + SKERR_SIRQ_E005MSG); + } + + if ((Istatus & IS_PA_TO_RX1) != 0) { + /* Means network is filling us up */ + SK_ERR_LOG(pAC, SK_ERRCL_HW | SK_ERRCL_INIT, SKERR_SIRQ_E002, + SKERR_SIRQ_E002MSG); + SK_OUT16(IoC, B3_PA_CTRL, PA_CLR_TO_RX1); + } + + if ((Istatus & IS_PA_TO_RX2) != 0) { + /* Means network is filling us up */ + SK_ERR_LOG(pAC, SK_ERRCL_HW | SK_ERRCL_INIT, SKERR_SIRQ_E003, + SKERR_SIRQ_E003MSG); + SK_OUT16(IoC, B3_PA_CTRL, PA_CLR_TO_RX2); + } + + if ((Istatus & IS_PA_TO_TX1) != 0) { + + pPrt = &pAC->GIni.GP[0]; + + /* May be a normal situation in a server with a slow network */ + SK_OUT16(IoC, B3_PA_CTRL, PA_CLR_TO_TX1); + +#ifdef GENESIS + if (pAC->GIni.GIGenesis) { + /* + * workaround: if in half duplex mode, check for Tx hangup. + * Read number of TX'ed bytes, wait for 10 ms, then compare + * the number with current value. If nothing changed, we assume + * that Tx is hanging and do a FIFO flush (see event routine). + */ + if ((pPrt->PLinkModeStatus == SK_LMODE_STAT_HALF || + pPrt->PLinkModeStatus == SK_LMODE_STAT_AUTOHALF) && + !pPrt->HalfDupTimerActive) { + /* + * many more pack. arb. timeouts may come in between, + * we ignore those + */ + pPrt->HalfDupTimerActive = SK_TRUE; + /* Snap statistic counters */ + (void)SkXmUpdateStats(pAC, IoC, 0); + + (void)SkXmMacStatistic(pAC, IoC, 0, XM_TXO_OK_HI, &RegVal32); + + pPrt->LastOctets = (SK_U64)RegVal32 << 32; + + (void)SkXmMacStatistic(pAC, IoC, 0, XM_TXO_OK_LO, &RegVal32); + + pPrt->LastOctets += RegVal32; + + Para.Para32[0] = 0; + SkTimerStart(pAC, IoC, &pPrt->HalfDupChkTimer, SK_HALFDUP_CHK_TIME, + SKGE_HWAC, SK_HWEV_HALFDUP_CHK, Para); + } + } +#endif /* GENESIS */ + } + + if ((Istatus & IS_PA_TO_TX2) != 0) { + + pPrt = &pAC->GIni.GP[1]; + + /* May be a normal situation in a server with a slow network */ + SK_OUT16(IoC, B3_PA_CTRL, PA_CLR_TO_TX2); + +#ifdef GENESIS + if (pAC->GIni.GIGenesis) { + /* workaround: see above */ + if ((pPrt->PLinkModeStatus == SK_LMODE_STAT_HALF || + pPrt->PLinkModeStatus == SK_LMODE_STAT_AUTOHALF) && + !pPrt->HalfDupTimerActive) { + pPrt->HalfDupTimerActive = SK_TRUE; + /* Snap statistic counters */ + (void)SkXmUpdateStats(pAC, IoC, 1); + + (void)SkXmMacStatistic(pAC, IoC, 1, XM_TXO_OK_HI, &RegVal32); + + pPrt->LastOctets = (SK_U64)RegVal32 << 32; + + (void)SkXmMacStatistic(pAC, IoC, 1, XM_TXO_OK_LO, &RegVal32); + + pPrt->LastOctets += RegVal32; + + Para.Para32[0] = 1; + SkTimerStart(pAC, IoC, &pPrt->HalfDupChkTimer, SK_HALFDUP_CHK_TIME, + SKGE_HWAC, SK_HWEV_HALFDUP_CHK, Para); + } + } +#endif /* GENESIS */ + } + + /* Check interrupts of the particular queues */ + if ((Istatus & IS_R1_C) != 0) { + /* Clear IRQ */ + SK_OUT32(IoC, B0_R1_CSR, CSR_IRQ_CL_C); + SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E006, + SKERR_SIRQ_E006MSG); + Para.Para64 = MAC_1; + SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para); + Para.Para32[0] = MAC_1; + SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para); + } + + if ((Istatus & IS_R2_C) != 0) { + /* Clear IRQ */ + SK_OUT32(IoC, B0_R2_CSR, CSR_IRQ_CL_C); + SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E007, + SKERR_SIRQ_E007MSG); + Para.Para64 = MAC_2; + SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para); + Para.Para32[0] = MAC_2; + SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para); + } + + if ((Istatus & IS_XS1_C) != 0) { + /* Clear IRQ */ + SK_OUT32(IoC, B0_XS1_CSR, CSR_IRQ_CL_C); + SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E008, + SKERR_SIRQ_E008MSG); + Para.Para64 = MAC_1; + SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para); + Para.Para32[0] = MAC_1; + SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para); + } + + if ((Istatus & IS_XA1_C) != 0) { + /* Clear IRQ */ + SK_OUT32(IoC, B0_XA1_CSR, CSR_IRQ_CL_C); + SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E009, + SKERR_SIRQ_E009MSG); + Para.Para64 = MAC_1; + SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para); + Para.Para32[0] = MAC_1; + SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para); + } + + if ((Istatus & IS_XS2_C) != 0) { + /* Clear IRQ */ + SK_OUT32(IoC, B0_XS2_CSR, CSR_IRQ_CL_C); + SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E010, + SKERR_SIRQ_E010MSG); + Para.Para64 = MAC_2; + SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para); + Para.Para32[0] = MAC_2; + SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para); + } + + if ((Istatus & IS_XA2_C) != 0) { + /* Clear IRQ */ + SK_OUT32(IoC, B0_XA2_CSR, CSR_IRQ_CL_C); + SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E011, + SKERR_SIRQ_E011MSG); + Para.Para64 = MAC_2; + SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para); + Para.Para32[0] = MAC_2; + SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para); + } + + /* External reg interrupt */ + if ((Istatus & IS_EXT_REG) != 0) { + /* Test IRQs from PHY */ + for (i = 0; i < pAC->GIni.GIMacsFound; i++) { + + pPrt = &pAC->GIni.GP[i]; + + if (pPrt->PState == SK_PRT_RESET) { + continue; + } + +#ifdef GENESIS + if (pAC->GIni.GIGenesis) { + + switch (pPrt->PhyType) { + + case SK_PHY_XMAC: + break; + + case SK_PHY_BCOM: + SkXmPhyRead(pAC, IoC, i, PHY_BCOM_INT_STAT, &PhyInt); + + if ((PhyInt & ~PHY_B_DEF_MSK) != 0) { + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ, + ("Port %d Bcom Int: 0x%04X\n", + i, PhyInt)); + SkPhyIsrBcom(pAC, IoC, i, PhyInt); + } + break; +#ifdef OTHER_PHY + case SK_PHY_LONE: + SkXmPhyRead(pAC, IoC, i, PHY_LONE_INT_STAT, &PhyInt); + + if ((PhyInt & PHY_L_DEF_MSK) != 0) { + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ, + ("Port %d Lone Int: %x\n", + i, PhyInt)); + SkPhyIsrLone(pAC, IoC, i, PhyInt); + } + break; +#endif /* OTHER_PHY */ + } + } +#endif /* GENESIS */ + +#ifdef YUKON + if (pAC->GIni.GIYukon) { + /* Read PHY Interrupt Status */ + SkGmPhyRead(pAC, IoC, i, PHY_MARV_INT_STAT, &PhyInt); + + if ((PhyInt & PHY_M_DEF_MSK) != 0) { + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ, + ("Port %d Marv Int: 0x%04X\n", + i, PhyInt)); + SkPhyIsrGmac(pAC, IoC, i, PhyInt); + } + } +#endif /* YUKON */ + } + } + + /* I2C Ready interrupt */ + if ((Istatus & IS_I2C_READY) != 0) { +#ifdef SK_SLIM + SK_OUT32(IoC, B2_I2C_IRQ, I2C_CLR_IRQ); +#else + SkI2cIsr(pAC, IoC); +#endif + } + + /* SW forced interrupt */ + if ((Istatus & IS_IRQ_SW) != 0) { + /* clear the software IRQ */ + SK_OUT8(IoC, B0_CTST, CS_CL_SW_IRQ); + } + + if ((Istatus & IS_LNK_SYNC_M1) != 0) { + /* + * We do NOT need the Link Sync interrupt, because it shows + * us only a link going down. + */ + /* clear interrupt */ + SK_OUT8(IoC, MR_ADDR(MAC_1, LNK_SYNC_CTRL), LED_CLR_IRQ); + } + + /* Check MAC after link sync counter */ + if ((Istatus & IS_MAC1) != 0) { + /* IRQ from MAC 1 */ + SkMacIrq(pAC, IoC, MAC_1); + } + + if ((Istatus & IS_LNK_SYNC_M2) != 0) { + /* + * We do NOT need the Link Sync interrupt, because it shows + * us only a link going down. + */ + /* clear interrupt */ + SK_OUT8(IoC, MR_ADDR(MAC_2, LNK_SYNC_CTRL), LED_CLR_IRQ); + } + + /* Check MAC after link sync counter */ + if ((Istatus & IS_MAC2) != 0) { + /* IRQ from MAC 2 */ + SkMacIrq(pAC, IoC, MAC_2); + } + + /* Timer interrupt (served last) */ + if ((Istatus & IS_TIMINT) != 0) { + /* check for HW Errors */ + if (((Istatus & IS_HW_ERR) & ~pAC->GIni.GIValIrqMask) != 0) { + /* read the HW Error Interrupt source */ + SK_IN32(IoC, B0_HWE_ISRC, &RegVal32); + + SkGeHwErr(pAC, IoC, RegVal32); + } + + SkHwtIsr(pAC, IoC); + } + +} /* SkGeSirqIsr */ + + +#ifdef GENESIS +/****************************************************************************** + * + * SkGePortCheckShorts() - Implementing XMAC Workaround Errata # 2 + * + * return: + * 0 o.k. nothing needed + * 1 Restart needed on this port + */ +static int SkGePortCheckShorts( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* IO Context */ +int Port) /* Which port should be checked */ +{ + SK_U32 Shorts; /* Short Event Counter */ + SK_U32 CheckShorts; /* Check value for Short Event Counter */ + SK_U64 RxCts; /* Rx Counter (packets on network) */ + SK_U32 RxTmp; /* Rx temp. Counter */ + SK_U32 FcsErrCts; /* FCS Error Counter */ + SK_GEPORT *pPrt; /* GIni Port struct pointer */ + int Rtv; /* Return value */ + int i; + + pPrt = &pAC->GIni.GP[Port]; + + /* Default: no action */ + Rtv = SK_HW_PS_NONE; + + (void)SkXmUpdateStats(pAC, IoC, Port); + + /* Extra precaution: check for short Event counter */ + (void)SkXmMacStatistic(pAC, IoC, Port, XM_RXE_SHT_ERR, &Shorts); + + /* + * Read Rx counters (packets seen on the network and not necessarily + * really received. + */ + RxCts = 0; + + for (i = 0; i < sizeof(SkGeRxRegs)/sizeof(SkGeRxRegs[0]); i++) { + + (void)SkXmMacStatistic(pAC, IoC, Port, SkGeRxRegs[i], &RxTmp); + + RxCts += (SK_U64)RxTmp; + } + + /* On default: check shorts against zero */ + CheckShorts = 0; + + /* Extra precaution on active links */ + if (pPrt->PHWLinkUp) { + /* Reset Link Restart counter */ + pPrt->PLinkResCt = 0; + pPrt->PAutoNegTOCt = 0; + + /* If link is up check for 2 */ + CheckShorts = 2; + + (void)SkXmMacStatistic(pAC, IoC, Port, XM_RXF_FCS_ERR, &FcsErrCts); + + if (pPrt->PLinkModeConf == SK_LMODE_AUTOSENSE && + pPrt->PLipaAutoNeg == SK_LIPA_UNKNOWN && + (pPrt->PLinkMode == SK_LMODE_HALF || + pPrt->PLinkMode == SK_LMODE_FULL)) { + /* + * This is autosensing and we are in the fallback + * manual full/half duplex mode. + */ + if (RxCts == pPrt->PPrevRx) { + /* Nothing received, restart link */ + pPrt->PPrevFcs = FcsErrCts; + pPrt->PPrevShorts = Shorts; + + return(SK_HW_PS_RESTART); + } + else { + pPrt->PLipaAutoNeg = SK_LIPA_MANUAL; + } + } + + if (((RxCts - pPrt->PPrevRx) > pPrt->PRxLim) || + (!(FcsErrCts - pPrt->PPrevFcs))) { + /* + * Note: The compare with zero above has to be done the way shown, + * otherwise the Linux driver will have a problem. + */ + /* + * We received a bunch of frames or no CRC error occured on the + * network -> ok. + */ + pPrt->PPrevRx = RxCts; + pPrt->PPrevFcs = FcsErrCts; + pPrt->PPrevShorts = Shorts; + + return(SK_HW_PS_NONE); + } + + pPrt->PPrevFcs = FcsErrCts; + } + + + if ((Shorts - pPrt->PPrevShorts) > CheckShorts) { + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ, + ("Short Event Count Restart Port %d \n", Port)); + Rtv = SK_HW_PS_RESTART; + } + + pPrt->PPrevShorts = Shorts; + pPrt->PPrevRx = RxCts; + + return(Rtv); +} /* SkGePortCheckShorts */ +#endif /* GENESIS */ + + +/****************************************************************************** + * + * SkGePortCheckUp() - Check if the link is up + * + * return: + * 0 o.k. nothing needed + * 1 Restart needed on this port + * 2 Link came up + */ +static int SkGePortCheckUp( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* IO Context */ +int Port) /* Which port should be checked */ +{ + SK_GEPORT *pPrt; /* GIni Port struct pointer */ + SK_BOOL AutoNeg; /* Is Auto-negotiation used ? */ + int Rtv; /* Return value */ + + Rtv = SK_HW_PS_NONE; + + pPrt = &pAC->GIni.GP[Port]; + + if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) { + AutoNeg = SK_FALSE; + } + else { + AutoNeg = SK_TRUE; + } + +#ifdef GENESIS + if (pAC->GIni.GIGenesis) { + + switch (pPrt->PhyType) { + + case SK_PHY_XMAC: + Rtv = SkGePortCheckUpXmac(pAC, IoC, Port, AutoNeg); + break; + case SK_PHY_BCOM: + Rtv = SkGePortCheckUpBcom(pAC, IoC, Port, AutoNeg); + break; +#ifdef OTHER_PHY + case SK_PHY_LONE: + Rtv = SkGePortCheckUpLone(pAC, IoC, Port, AutoNeg); + break; + case SK_PHY_NAT: + Rtv = SkGePortCheckUpNat(pAC, IoC, Port, AutoNeg); + break; +#endif /* OTHER_PHY */ + } + } +#endif /* GENESIS */ + +#ifdef YUKON + if (pAC->GIni.GIYukon) { + + Rtv = SkGePortCheckUpGmac(pAC, IoC, Port, AutoNeg); + } +#endif /* YUKON */ + + return(Rtv); +} /* SkGePortCheckUp */ + + +#ifdef GENESIS +/****************************************************************************** + * + * SkGePortCheckUpXmac() - Implementing of the Workaround Errata # 2 + * + * return: + * 0 o.k. nothing needed + * 1 Restart needed on this port + * 2 Link came up + */ +static int SkGePortCheckUpXmac( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* IO Context */ +int Port, /* Which port should be checked */ +SK_BOOL AutoNeg) /* Is Auto-negotiation used ? */ +{ + SK_U32 Shorts; /* Short Event Counter */ + SK_GEPORT *pPrt; /* GIni Port struct pointer */ + int Done; + SK_U32 GpReg; /* General Purpose register value */ + SK_U16 Isrc; /* Interrupt source register */ + SK_U16 IsrcSum; /* Interrupt source register sum */ + SK_U16 LpAb; /* Link Partner Ability */ + SK_U16 ResAb; /* Resolved Ability */ + SK_U16 ExtStat; /* Extended Status Register */ + SK_U8 NextMode; /* Next AutoSensing Mode */ + + pPrt = &pAC->GIni.GP[Port]; + + if (pPrt->PHWLinkUp) { + if (pPrt->PhyType != SK_PHY_XMAC) { + return(SK_HW_PS_NONE); + } + else { + return(SkGePortCheckShorts(pAC, IoC, Port)); + } + } + + IsrcSum = pPrt->PIsave; + pPrt->PIsave = 0; + + /* Now wait for each port's link */ + if (pPrt->PLinkBroken) { + /* Link was broken */ + XM_IN32(IoC, Port, XM_GP_PORT, &GpReg); + + if ((GpReg & XM_GP_INP_ASS) == 0) { + /* The Link is in sync */ + XM_IN16(IoC, Port, XM_ISRC, &Isrc); + IsrcSum |= Isrc; + SkXmAutoNegLipaXmac(pAC, IoC, Port, IsrcSum); + + if ((Isrc & XM_IS_INP_ASS) == 0) { + /* It has been in sync since last time */ + /* Restart the PORT */ + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ, + ("Link in sync Restart Port %d\n", Port)); + + (void)SkXmUpdateStats(pAC, IoC, Port); + + /* We now need to reinitialize the PrevShorts counter */ + (void)SkXmMacStatistic(pAC, IoC, Port, XM_RXE_SHT_ERR, &Shorts); + pPrt->PPrevShorts = Shorts; + + pPrt->PLinkBroken = SK_FALSE; + + /* + * Link Restart Workaround: + * it may be possible that the other Link side + * restarts its link as well an we detect + * another LinkBroken. To prevent this + * happening we check for a maximum number + * of consecutive restart. If those happens, + * we do NOT restart the active link and + * check whether the link is now o.k. + */ + pPrt->PLinkResCt++; + + pPrt->PAutoNegTimeOut = 0; + + if (pPrt->PLinkResCt < SK_MAX_LRESTART) { + return(SK_HW_PS_RESTART); + } + + pPrt->PLinkResCt = 0; + + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("Do NOT restart on Port %d %x %x\n", Port, Isrc, IsrcSum)); + } + else { + pPrt->PIsave = (SK_U16)(IsrcSum & XM_IS_AND); + + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("Save Sync/nosync Port %d %x %x\n", Port, Isrc, IsrcSum)); + + /* Do nothing more if link is broken */ + return(SK_HW_PS_NONE); + } + } + else { + /* Do nothing more if link is broken */ + return(SK_HW_PS_NONE); + } + + } + else { + /* Link was not broken, check if it is */ + XM_IN16(IoC, Port, XM_ISRC, &Isrc); + IsrcSum |= Isrc; + if ((Isrc & XM_IS_INP_ASS) != 0) { + XM_IN16(IoC, Port, XM_ISRC, &Isrc); + IsrcSum |= Isrc; + if ((Isrc & XM_IS_INP_ASS) != 0) { + XM_IN16(IoC, Port, XM_ISRC, &Isrc); + IsrcSum |= Isrc; + if ((Isrc & XM_IS_INP_ASS) != 0) { + pPrt->PLinkBroken = SK_TRUE; + /* Re-Init Link partner Autoneg flag */ + pPrt->PLipaAutoNeg = SK_LIPA_UNKNOWN; + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ, + ("Link broken Port %d\n", Port)); + + /* Cable removed-> reinit sense mode */ + SkHWInitDefSense(pAC, IoC, Port); + + return(SK_HW_PS_RESTART); + } + } + } + else { + SkXmAutoNegLipaXmac(pAC, IoC, Port, Isrc); + + if (SkGePortCheckShorts(pAC, IoC, Port) == SK_HW_PS_RESTART) { + return(SK_HW_PS_RESTART); + } + } + } + + /* + * here we usually can check whether the link is in sync and + * auto-negotiation is done. + */ + XM_IN32(IoC, Port, XM_GP_PORT, &GpReg); + XM_IN16(IoC, Port, XM_ISRC, &Isrc); + IsrcSum |= Isrc; + + SkXmAutoNegLipaXmac(pAC, IoC, Port, IsrcSum); + + if ((GpReg & XM_GP_INP_ASS) != 0 || (IsrcSum & XM_IS_INP_ASS) != 0) { + if ((GpReg & XM_GP_INP_ASS) == 0) { + /* Save Auto-negotiation Done interrupt only if link is in sync */ + pPrt->PIsave = (SK_U16)(IsrcSum & XM_IS_AND); + } +#ifdef DEBUG + if ((pPrt->PIsave & XM_IS_AND) != 0) { + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("AutoNeg done rescheduled Port %d\n", Port)); + } +#endif /* DEBUG */ + return(SK_HW_PS_NONE); + } + + if (AutoNeg) { + if ((IsrcSum & XM_IS_AND) != 0) { + SkHWLinkUp(pAC, IoC, Port); + Done = SkMacAutoNegDone(pAC, IoC, Port); + if (Done != SK_AND_OK) { + /* Get PHY parameters, for debugging only */ + SkXmPhyRead(pAC, IoC, Port, PHY_XMAC_AUNE_LP, &LpAb); + SkXmPhyRead(pAC, IoC, Port, PHY_XMAC_RES_ABI, &ResAb); + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("AutoNeg FAIL Port %d (LpAb %x, ResAb %x)\n", + Port, LpAb, ResAb)); + + /* Try next possible mode */ + NextMode = SkHWSenseGetNext(pAC, IoC, Port); + SkHWLinkDown(pAC, IoC, Port); + if (Done == SK_AND_DUP_CAP) { + /* GoTo next mode */ + SkHWSenseSetNext(pAC, IoC, Port, NextMode); + } + + return(SK_HW_PS_RESTART); + } + /* + * Dummy Read extended status to prevent extra link down/ups + * (clear Page Received bit if set) + */ + SkXmPhyRead(pAC, IoC, Port, PHY_XMAC_AUNE_EXP, &ExtStat); + + return(SK_HW_PS_LINK); + } + + /* AutoNeg not done, but HW link is up. Check for timeouts */ + pPrt->PAutoNegTimeOut++; + if (pPrt->PAutoNegTimeOut >= SK_AND_MAX_TO) { + /* Increase the Timeout counter */ + pPrt->PAutoNegTOCt++; + + /* Timeout occured */ + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ, + ("AutoNeg timeout Port %d\n", Port)); + if (pPrt->PLinkModeConf == SK_LMODE_AUTOSENSE && + pPrt->PLipaAutoNeg != SK_LIPA_AUTO) { + /* Set Link manually up */ + SkHWSenseSetNext(pAC, IoC, Port, SK_LMODE_FULL); + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ, + ("Set manual full duplex Port %d\n", Port)); + } + + if (pPrt->PLinkModeConf == SK_LMODE_AUTOSENSE && + pPrt->PLipaAutoNeg == SK_LIPA_AUTO && + pPrt->PAutoNegTOCt >= SK_MAX_ANEG_TO) { + /* + * This is rather complicated. + * we need to check here whether the LIPA_AUTO + * we saw before is false alert. We saw at one + * switch ( SR8800) that on boot time it sends + * just one auto-neg packet and does no further + * auto-negotiation. + * Solution: we restart the autosensing after + * a few timeouts. + */ + pPrt->PAutoNegTOCt = 0; + pPrt->PLipaAutoNeg = SK_LIPA_UNKNOWN; + SkHWInitDefSense(pAC, IoC, Port); + } + + /* Do the restart */ + return(SK_HW_PS_RESTART); + } + } + else { + /* Link is up and we don't need more */ +#ifdef DEBUG + if (pPrt->PLipaAutoNeg == SK_LIPA_AUTO) { + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("ERROR: Lipa auto detected on port %d\n", Port)); + } +#endif /* DEBUG */ + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ, + ("Link sync(GP), Port %d\n", Port)); + SkHWLinkUp(pAC, IoC, Port); + + /* + * Link sync (GP) and so assume a good connection. But if not received + * a bunch of frames received in a time slot (maybe broken tx cable) + * the port is restart. + */ + return(SK_HW_PS_LINK); + } + + return(SK_HW_PS_NONE); +} /* SkGePortCheckUpXmac */ + + +/****************************************************************************** + * + * SkGePortCheckUpBcom() - Check if the link is up on Bcom PHY + * + * return: + * 0 o.k. nothing needed + * 1 Restart needed on this port + * 2 Link came up + */ +static int SkGePortCheckUpBcom( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* IO Context */ +int Port, /* Which port should be checked */ +SK_BOOL AutoNeg) /* Is Auto-negotiation used ? */ +{ + SK_GEPORT *pPrt; /* GIni Port struct pointer */ + int Done; + SK_U16 Isrc; /* Interrupt source register */ + SK_U16 PhyStat; /* Phy Status Register */ + SK_U16 ResAb; /* Master/Slave resolution */ + SK_U16 Ctrl; /* Broadcom control flags */ +#ifdef DEBUG + SK_U16 LpAb; + SK_U16 ExtStat; +#endif /* DEBUG */ + + pPrt = &pAC->GIni.GP[Port]; + + /* Check for No HCD Link events (#10523) */ + SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_INT_STAT, &Isrc); + +#ifdef xDEBUG + if ((Isrc & ~(PHY_B_IS_HCT | PHY_B_IS_LCT)) == + (PHY_B_IS_SCR_S_ER | PHY_B_IS_RRS_CHANGE | PHY_B_IS_LRS_CHANGE)) { + + SK_U32 Stat1, Stat2, Stat3; + + Stat1 = 0; + SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_INT_MASK, &Stat1); + CMSMPrintString( + pAC->pConfigTable, + MSG_TYPE_RUNTIME_INFO, + "CheckUp1 - Stat: %x, Mask: %x", + (void *)Isrc, + (void *)Stat1); + + Stat1 = 0; + SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_CTRL, &Stat1); + Stat2 = 0; + SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_STAT, &Stat2); + Stat1 = Stat1 << 16 | Stat2; + Stat2 = 0; + SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUNE_ADV, &Stat2); + Stat3 = 0; + SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUNE_LP, &Stat3); + Stat2 = Stat2 << 16 | Stat3; + CMSMPrintString( + pAC->pConfigTable, + MSG_TYPE_RUNTIME_INFO, + "Ctrl/Stat: %x, AN Adv/LP: %x", + (void *)Stat1, + (void *)Stat2); + + Stat1 = 0; + SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUNE_EXP, &Stat1); + Stat2 = 0; + SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_EXT_STAT, &Stat2); + Stat1 = Stat1 << 16 | Stat2; + Stat2 = 0; + SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_1000T_CTRL, &Stat2); + Stat3 = 0; + SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_1000T_STAT, &Stat3); + Stat2 = Stat2 << 16 | Stat3; + CMSMPrintString( + pAC->pConfigTable, + MSG_TYPE_RUNTIME_INFO, + "AN Exp/IEEE Ext: %x, 1000T Ctrl/Stat: %x", + (void *)Stat1, + (void *)Stat2); + + Stat1 = 0; + SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_P_EXT_CTRL, &Stat1); + Stat2 = 0; + SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_P_EXT_STAT, &Stat2); + Stat1 = Stat1 << 16 | Stat2; + Stat2 = 0; + SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUX_CTRL, &Stat2); + Stat3 = 0; + SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUX_STAT, &Stat3); + Stat2 = Stat2 << 16 | Stat3; + CMSMPrintString( + pAC->pConfigTable, + MSG_TYPE_RUNTIME_INFO, + "PHY Ext Ctrl/Stat: %x, Aux Ctrl/Stat: %x", + (void *)Stat1, + (void *)Stat2); + } +#endif /* DEBUG */ + + if ((Isrc & (PHY_B_IS_NO_HDCL /* | PHY_B_IS_NO_HDC */)) != 0) { + /* + * Workaround BCom Errata: + * enable and disable loopback mode if "NO HCD" occurs. + */ + SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_CTRL, &Ctrl); + SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_CTRL, + (SK_U16)(Ctrl | PHY_CT_LOOP)); + SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_CTRL, + (SK_U16)(Ctrl & ~PHY_CT_LOOP)); + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("No HCD Link event, Port %d\n", Port)); +#ifdef xDEBUG + CMSMPrintString( + pAC->pConfigTable, + MSG_TYPE_RUNTIME_INFO, + "No HCD link event, port %d.", + (void *)Port, + (void *)NULL); +#endif /* DEBUG */ + } + + /* Not obsolete: link status bit is latched to 0 and autoclearing! */ + SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_STAT, &PhyStat); + + if (pPrt->PHWLinkUp) { + return(SK_HW_PS_NONE); + } + +#ifdef xDEBUG + { + SK_U32 Stat1, Stat2, Stat3; + + Stat1 = 0; + SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_INT_MASK, &Stat1); + CMSMPrintString( + pAC->pConfigTable, + MSG_TYPE_RUNTIME_INFO, + "CheckUp1a - Stat: %x, Mask: %x", + (void *)Isrc, + (void *)Stat1); + + Stat1 = 0; + SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_CTRL, &Stat1); + Stat2 = 0; + SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_STAT, &PhyStat); + Stat1 = Stat1 << 16 | PhyStat; + Stat2 = 0; + SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUNE_ADV, &Stat2); + Stat3 = 0; + SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUNE_LP, &Stat3); + Stat2 = Stat2 << 16 | Stat3; + CMSMPrintString( + pAC->pConfigTable, + MSG_TYPE_RUNTIME_INFO, + "Ctrl/Stat: %x, AN Adv/LP: %x", + (void *)Stat1, + (void *)Stat2); + + Stat1 = 0; + SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUNE_EXP, &Stat1); + Stat2 = 0; + SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_EXT_STAT, &Stat2); + Stat1 = Stat1 << 16 | Stat2; + Stat2 = 0; + SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_1000T_CTRL, &Stat2); + Stat3 = 0; + SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_1000T_STAT, &ResAb); + Stat2 = Stat2 << 16 | ResAb; + CMSMPrintString( + pAC->pConfigTable, + MSG_TYPE_RUNTIME_INFO, + "AN Exp/IEEE Ext: %x, 1000T Ctrl/Stat: %x", + (void *)Stat1, + (void *)Stat2); + + Stat1 = 0; + SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_P_EXT_CTRL, &Stat1); + Stat2 = 0; + SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_P_EXT_STAT, &Stat2); + Stat1 = Stat1 << 16 | Stat2; + Stat2 = 0; + SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUX_CTRL, &Stat2); + Stat3 = 0; + SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUX_STAT, &Stat3); + Stat2 = Stat2 << 16 | Stat3; + CMSMPrintString( + pAC->pConfigTable, + MSG_TYPE_RUNTIME_INFO, + "PHY Ext Ctrl/Stat: %x, Aux Ctrl/Stat: %x", + (void *)Stat1, + (void *)Stat2); + } +#endif /* DEBUG */ + + /* + * Here we usually can check whether the link is in sync and + * auto-negotiation is done. + */ + + SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_STAT, &PhyStat); + + SkMacAutoNegLipaPhy(pAC, IoC, Port, PhyStat); + + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("CheckUp Port %d, PhyStat: 0x%04X\n", Port, PhyStat)); + + SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_1000T_STAT, &ResAb); + + if ((ResAb & PHY_B_1000S_MSF) != 0) { + /* Error */ + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("Master/Slave Fault port %d\n", Port)); + + pPrt->PAutoNegFail = SK_TRUE; + pPrt->PMSStatus = SK_MS_STAT_FAULT; + + return(SK_HW_PS_RESTART); + } + + if ((PhyStat & PHY_ST_LSYNC) == 0) { + return(SK_HW_PS_NONE); + } + + pPrt->PMSStatus = ((ResAb & PHY_B_1000S_MSR) != 0) ? + SK_MS_STAT_MASTER : SK_MS_STAT_SLAVE; + + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("Port %d, ResAb: 0x%04X\n", Port, ResAb)); + + if (AutoNeg) { + if ((PhyStat & PHY_ST_AN_OVER) != 0) { + + SkHWLinkUp(pAC, IoC, Port); + + Done = SkMacAutoNegDone(pAC, IoC, Port); + + if (Done != SK_AND_OK) { +#ifdef DEBUG + /* Get PHY parameters, for debugging only */ + SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUNE_LP, &LpAb); + SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_1000T_STAT, &ExtStat); + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("AutoNeg FAIL Port %d (LpAb %x, 1000TStat %x)\n", + Port, LpAb, ExtStat)); +#endif /* DEBUG */ + return(SK_HW_PS_RESTART); + } + else { +#ifdef xDEBUG + /* Dummy read ISR to prevent extra link downs/ups */ + SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_INT_STAT, &ExtStat); + + if ((ExtStat & ~(PHY_B_IS_HCT | PHY_B_IS_LCT)) != 0) { + CMSMPrintString( + pAC->pConfigTable, + MSG_TYPE_RUNTIME_INFO, + "CheckUp2 - Stat: %x", + (void *)ExtStat, + (void *)NULL); + } +#endif /* DEBUG */ + return(SK_HW_PS_LINK); + } + } + } + else { /* !AutoNeg */ + /* Link is up and we don't need more. */ +#ifdef DEBUG + if (pPrt->PLipaAutoNeg == SK_LIPA_AUTO) { + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("ERROR: Lipa auto detected on port %d\n", Port)); + } +#endif /* DEBUG */ + +#ifdef xDEBUG + /* Dummy read ISR to prevent extra link downs/ups */ + SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_INT_STAT, &ExtStat); + + if ((ExtStat & ~(PHY_B_IS_HCT | PHY_B_IS_LCT)) != 0) { + CMSMPrintString( + pAC->pConfigTable, + MSG_TYPE_RUNTIME_INFO, + "CheckUp3 - Stat: %x", + (void *)ExtStat, + (void *)NULL); + } +#endif /* DEBUG */ + + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ, + ("Link sync(GP), Port %d\n", Port)); + SkHWLinkUp(pAC, IoC, Port); + + return(SK_HW_PS_LINK); + } + + return(SK_HW_PS_NONE); +} /* SkGePortCheckUpBcom */ +#endif /* GENESIS */ + + +#ifdef YUKON +/****************************************************************************** + * + * SkGePortCheckUpGmac() - Check if the link is up on Marvell PHY + * + * return: + * 0 o.k. nothing needed + * 1 Restart needed on this port + * 2 Link came up + */ +static int SkGePortCheckUpGmac( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* IO Context */ +int Port, /* Which port should be checked */ +SK_BOOL AutoNeg) /* Is Auto-negotiation used ? */ +{ + SK_GEPORT *pPrt; /* GIni Port struct pointer */ + int Done; + SK_U16 PhyIsrc; /* PHY Interrupt source */ + SK_U16 PhyStat; /* PPY Status */ + SK_U16 PhySpecStat;/* PHY Specific Status */ + SK_U16 ResAb; /* Master/Slave resolution */ + SK_EVPARA Para; +#ifdef DEBUG + SK_U16 Word; /* I/O helper */ +#endif /* DEBUG */ + + pPrt = &pAC->GIni.GP[Port]; + + if (pPrt->PHWLinkUp) { + return(SK_HW_PS_NONE); + } + + /* Read PHY Status */ + SkGmPhyRead(pAC, IoC, Port, PHY_MARV_STAT, &PhyStat); + + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("CheckUp Port %d, PhyStat: 0x%04X\n", Port, PhyStat)); + + /* Read PHY Interrupt Status */ + SkGmPhyRead(pAC, IoC, Port, PHY_MARV_INT_STAT, &PhyIsrc); + + if ((PhyIsrc & PHY_M_IS_AN_COMPL) != 0) { + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("Auto-Negotiation Completed, PhyIsrc: 0x%04X\n", PhyIsrc)); + } + + if ((PhyIsrc & PHY_M_IS_LSP_CHANGE) != 0) { + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("Link Speed Changed, PhyIsrc: 0x%04X\n", PhyIsrc)); + } + + SkMacAutoNegLipaPhy(pAC, IoC, Port, PhyStat); + + SkGmPhyRead(pAC, IoC, Port, PHY_MARV_1000T_STAT, &ResAb); + + if ((ResAb & PHY_B_1000S_MSF) != 0) { + /* Error */ + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("Master/Slave Fault port %d\n", Port)); + + pPrt->PAutoNegFail = SK_TRUE; + pPrt->PMSStatus = SK_MS_STAT_FAULT; + + return(SK_HW_PS_RESTART); + } + + /* Read PHY Specific Status */ + SkGmPhyRead(pAC, IoC, Port, PHY_MARV_PHY_STAT, &PhySpecStat); + + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("Phy1000BT: 0x%04X, PhySpecStat: 0x%04X\n", ResAb, PhySpecStat)); + +#ifdef DEBUG + SkGmPhyRead(pAC, IoC, Port, PHY_MARV_AUNE_EXP, &Word); + + if ((PhyIsrc & PHY_M_IS_AN_PR) != 0 || (Word & PHY_ANE_RX_PG) != 0 || + (PhySpecStat & PHY_M_PS_PAGE_REC) != 0) { + /* Read PHY Next Page Link Partner */ + SkGmPhyRead(pAC, IoC, Port, PHY_MARV_NEPG_LP, &Word); + + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("Page Received, NextPage: 0x%04X\n", Word)); + } +#endif /* DEBUG */ + + if ((PhySpecStat & PHY_M_PS_LINK_UP) == 0) { + return(SK_HW_PS_NONE); + } + + if ((PhySpecStat & PHY_M_PS_DOWNS_STAT) != 0 || + (PhyIsrc & PHY_M_IS_DOWNSH_DET) != 0) { + /* Downshift detected */ + SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E025, SKERR_SIRQ_E025MSG); + + Para.Para64 = Port; + SkEventQueue(pAC, SKGE_DRV, SK_DRV_DOWNSHIFT_DET, Para); + + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("Downshift detected, PhyIsrc: 0x%04X\n", PhyIsrc)); + } + + pPrt->PMSStatus = ((ResAb & PHY_B_1000S_MSR) != 0) ? + SK_MS_STAT_MASTER : SK_MS_STAT_SLAVE; + + pPrt->PCableLen = (SK_U8)((PhySpecStat & PHY_M_PS_CABLE_MSK) >> 7); + + if (AutoNeg) { + /* Auto-Negotiation Over ? */ + if ((PhyStat & PHY_ST_AN_OVER) != 0) { + + SkHWLinkUp(pAC, IoC, Port); + + Done = SkMacAutoNegDone(pAC, IoC, Port); + + if (Done != SK_AND_OK) { + return(SK_HW_PS_RESTART); + } + + return(SK_HW_PS_LINK); + } + } + else { /* !AutoNeg */ + /* Link is up and we don't need more */ +#ifdef DEBUG + if (pPrt->PLipaAutoNeg == SK_LIPA_AUTO) { + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("ERROR: Lipa auto detected on port %d\n", Port)); + } +#endif /* DEBUG */ + + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ, + ("Link sync, Port %d\n", Port)); + SkHWLinkUp(pAC, IoC, Port); + + return(SK_HW_PS_LINK); + } + + return(SK_HW_PS_NONE); +} /* SkGePortCheckUpGmac */ +#endif /* YUKON */ + + +#ifdef OTHER_PHY +/****************************************************************************** + * + * SkGePortCheckUpLone() - Check if the link is up on Level One PHY + * + * return: + * 0 o.k. nothing needed + * 1 Restart needed on this port + * 2 Link came up + */ +static int SkGePortCheckUpLone( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* IO Context */ +int Port, /* Which port should be checked */ +SK_BOOL AutoNeg) /* Is Auto-negotiation used ? */ +{ + SK_GEPORT *pPrt; /* GIni Port struct pointer */ + int Done; + SK_U16 Isrc; /* Interrupt source register */ + SK_U16 LpAb; /* Link Partner Ability */ + SK_U16 ExtStat; /* Extended Status Register */ + SK_U16 PhyStat; /* Phy Status Register */ + SK_U16 StatSum; + SK_U8 NextMode; /* Next AutoSensing Mode */ + + pPrt = &pAC->GIni.GP[Port]; + + if (pPrt->PHWLinkUp) { + return(SK_HW_PS_NONE); + } + + StatSum = pPrt->PIsave; + pPrt->PIsave = 0; + + /* + * here we usually can check whether the link is in sync and + * auto-negotiation is done. + */ + SkXmPhyRead(pAC, IoC, Port, PHY_LONE_STAT, &PhyStat); + StatSum |= PhyStat; + + SkMacAutoNegLipaPhy(pAC, IoC, Port, PhyStat); + + if ((PhyStat & PHY_ST_LSYNC) == 0) { + /* Save Auto-negotiation Done bit */ + pPrt->PIsave = (SK_U16)(StatSum & PHY_ST_AN_OVER); +#ifdef DEBUG + if ((pPrt->PIsave & PHY_ST_AN_OVER) != 0) { + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("AutoNeg done rescheduled Port %d\n", Port)); + } +#endif /* DEBUG */ + return(SK_HW_PS_NONE); + } + + if (AutoNeg) { + if ((StatSum & PHY_ST_AN_OVER) != 0) { + SkHWLinkUp(pAC, IoC, Port); + Done = SkMacAutoNegDone(pAC, IoC, Port); + if (Done != SK_AND_OK) { + /* Get PHY parameters, for debugging only */ + SkXmPhyRead(pAC, IoC, Port, PHY_LONE_AUNE_LP, &LpAb); + SkXmPhyRead(pAC, IoC, Port, PHY_LONE_1000T_STAT, &ExtStat); + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("AutoNeg FAIL Port %d (LpAb %x, 1000TStat %x)\n", + Port, LpAb, ExtStat)); + + /* Try next possible mode */ + NextMode = SkHWSenseGetNext(pAC, IoC, Port); + SkHWLinkDown(pAC, IoC, Port); + if (Done == SK_AND_DUP_CAP) { + /* GoTo next mode */ + SkHWSenseSetNext(pAC, IoC, Port, NextMode); + } + + return(SK_HW_PS_RESTART); + + } + else { + /* + * Dummy Read interrupt status to prevent + * extra link down/ups + */ + SkXmPhyRead(pAC, IoC, Port, PHY_LONE_INT_STAT, &ExtStat); + return(SK_HW_PS_LINK); + } + } + + /* AutoNeg not done, but HW link is up. Check for timeouts */ + pPrt->PAutoNegTimeOut++; + if (pPrt->PAutoNegTimeOut >= SK_AND_MAX_TO) { + /* Timeout occured */ + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ, + ("AutoNeg timeout Port %d\n", Port)); + if (pPrt->PLinkModeConf == SK_LMODE_AUTOSENSE && + pPrt->PLipaAutoNeg != SK_LIPA_AUTO) { + /* Set Link manually up */ + SkHWSenseSetNext(pAC, IoC, Port, SK_LMODE_FULL); + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ, + ("Set manual full duplex Port %d\n", Port)); + } + + /* Do the restart */ + return(SK_HW_PS_RESTART); + } + } + else { + /* Link is up and we don't need more */ +#ifdef DEBUG + if (pPrt->PLipaAutoNeg == SK_LIPA_AUTO) { + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("ERROR: Lipa auto detected on port %d\n", Port)); + } +#endif /* DEBUG */ + + /* + * Dummy Read interrupt status to prevent + * extra link down/ups + */ + SkXmPhyRead(pAC, IoC, Port, PHY_LONE_INT_STAT, &ExtStat); + + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ, + ("Link sync(GP), Port %d\n", Port)); + SkHWLinkUp(pAC, IoC, Port); + + return(SK_HW_PS_LINK); + } + + return(SK_HW_PS_NONE); +} /* SkGePortCheckUpLone */ + + +/****************************************************************************** + * + * SkGePortCheckUpNat() - Check if the link is up on National PHY + * + * return: + * 0 o.k. nothing needed + * 1 Restart needed on this port + * 2 Link came up + */ +static int SkGePortCheckUpNat( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* IO Context */ +int Port, /* Which port should be checked */ +SK_BOOL AutoNeg) /* Is Auto-negotiation used ? */ +{ + /* todo: National */ + return(SK_HW_PS_NONE); +} /* SkGePortCheckUpNat */ +#endif /* OTHER_PHY */ + + +/****************************************************************************** + * + * SkGeSirqEvent() - Event Service Routine + * + * Description: + * + * Notes: + */ +int SkGeSirqEvent( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* Io Context */ +SK_U32 Event, /* Module specific Event */ +SK_EVPARA Para) /* Event specific Parameter */ +{ + SK_GEPORT *pPrt; /* GIni Port struct pointer */ + SK_U32 Port; + SK_U32 Val32; + int PortStat; + SK_U8 Val8; +#ifdef GENESIS + SK_U64 Octets; +#endif /* GENESIS */ + + Port = Para.Para32[0]; + pPrt = &pAC->GIni.GP[Port]; + + switch (Event) { + case SK_HWEV_WATIM: + if (pPrt->PState == SK_PRT_RESET) { + + PortStat = SK_HW_PS_NONE; + } + else { + /* Check whether port came up */ + PortStat = SkGePortCheckUp(pAC, IoC, (int)Port); + } + + switch (PortStat) { + case SK_HW_PS_RESTART: + if (pPrt->PHWLinkUp) { + /* Set Link to down */ + SkHWLinkDown(pAC, IoC, (int)Port); + + /* + * Signal directly to RLMT to ensure correct + * sequence of SWITCH and RESET event. + */ + SkRlmtEvent(pAC, IoC, SK_RLMT_LINK_DOWN, Para); + } + + /* Restart needed */ + SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_RESET, Para); + break; + + case SK_HW_PS_LINK: + /* Signal to RLMT */ + SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_UP, Para); + break; + } + + /* Start again the check Timer */ + if (pPrt->PHWLinkUp) { + Val32 = SK_WA_ACT_TIME; + } + else { + Val32 = SK_WA_INA_TIME; + } + + /* Todo: still needed for non-XMAC PHYs??? */ + /* Start workaround Errata #2 timer */ + SkTimerStart(pAC, IoC, &pPrt->PWaTimer, Val32, + SKGE_HWAC, SK_HWEV_WATIM, Para); + break; + + case SK_HWEV_PORT_START: + if (pPrt->PHWLinkUp) { + /* + * Signal directly to RLMT to ensure correct + * sequence of SWITCH and RESET event. + */ + SkRlmtEvent(pAC, IoC, SK_RLMT_LINK_DOWN, Para); + } + + SkHWLinkDown(pAC, IoC, (int)Port); + + /* Schedule Port RESET */ + SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_RESET, Para); + + /* Start workaround Errata #2 timer */ + SkTimerStart(pAC, IoC, &pPrt->PWaTimer, SK_WA_INA_TIME, + SKGE_HWAC, SK_HWEV_WATIM, Para); + break; + + case SK_HWEV_PORT_STOP: + if (pPrt->PHWLinkUp) { + /* + * Signal directly to RLMT to ensure correct + * sequence of SWITCH and RESET event. + */ + SkRlmtEvent(pAC, IoC, SK_RLMT_LINK_DOWN, Para); + } + + /* Stop Workaround Timer */ + SkTimerStop(pAC, IoC, &pPrt->PWaTimer); + + SkHWLinkDown(pAC, IoC, (int)Port); + break; + + case SK_HWEV_UPDATE_STAT: + /* We do NOT need to update any statistics */ + break; + + case SK_HWEV_CLEAR_STAT: + /* We do NOT need to clear any statistics */ + for (Port = 0; Port < (SK_U32)pAC->GIni.GIMacsFound; Port++) { + pPrt->PPrevRx = 0; + pPrt->PPrevFcs = 0; + pPrt->PPrevShorts = 0; + } + break; + + case SK_HWEV_SET_LMODE: + Val8 = (SK_U8)Para.Para32[1]; + if (pPrt->PLinkModeConf != Val8) { + /* Set New link mode */ + pPrt->PLinkModeConf = Val8; + + /* Restart Port */ + SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_STOP, Para); + SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_START, Para); + } + break; + + case SK_HWEV_SET_FLOWMODE: + Val8 = (SK_U8)Para.Para32[1]; + if (pPrt->PFlowCtrlMode != Val8) { + /* Set New Flow Control mode */ + pPrt->PFlowCtrlMode = Val8; + + /* Restart Port */ + SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_STOP, Para); + SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_START, Para); + } + break; + + case SK_HWEV_SET_ROLE: + /* not possible for fiber */ + if (!pAC->GIni.GICopperType) { + break; + } + Val8 = (SK_U8)Para.Para32[1]; + if (pPrt->PMSMode != Val8) { + /* Set New Role (Master/Slave) mode */ + pPrt->PMSMode = Val8; + + /* Restart Port */ + SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_STOP, Para); + SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_START, Para); + } + break; + + case SK_HWEV_SET_SPEED: + if (pPrt->PhyType != SK_PHY_MARV_COPPER) { + break; + } + Val8 = (SK_U8)Para.Para32[1]; + if (pPrt->PLinkSpeed != Val8) { + /* Set New Speed parameter */ + pPrt->PLinkSpeed = Val8; + + /* Restart Port */ + SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_STOP, Para); + SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_START, Para); + } + break; + +#ifdef GENESIS + case SK_HWEV_HALFDUP_CHK: + if (pAC->GIni.GIGenesis) { + /* + * half duplex hangup workaround. + * See packet arbiter timeout interrupt for description + */ + pPrt->HalfDupTimerActive = SK_FALSE; + if (pPrt->PLinkModeStatus == SK_LMODE_STAT_HALF || + pPrt->PLinkModeStatus == SK_LMODE_STAT_AUTOHALF) { + /* Snap statistic counters */ + (void)SkXmUpdateStats(pAC, IoC, Port); + + (void)SkXmMacStatistic(pAC, IoC, Port, XM_TXO_OK_HI, &Val32); + + Octets = (SK_U64)Val32 << 32; + + (void)SkXmMacStatistic(pAC, IoC, Port, XM_TXO_OK_LO, &Val32); + + Octets += Val32; + + if (pPrt->LastOctets == Octets) { + /* Tx hanging, a FIFO flush restarts it */ + SkMacFlushTxFifo(pAC, IoC, Port); + } + } + } + break; +#endif /* GENESIS */ + + default: + SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_SIRQ_E001, SKERR_SIRQ_E001MSG); + break; + } + + return(0); +} /* SkGeSirqEvent */ + + +#ifdef GENESIS +/****************************************************************************** + * + * SkPhyIsrBcom() - PHY interrupt service routine + * + * Description: handles all interrupts from BCom PHY + * + * Returns: N/A + */ +static void SkPhyIsrBcom( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* Io Context */ +int Port, /* Port Num = PHY Num */ +SK_U16 IStatus) /* Interrupt Status */ +{ + SK_GEPORT *pPrt; /* GIni Port struct pointer */ + SK_EVPARA Para; + + pPrt = &pAC->GIni.GP[Port]; + + if ((IStatus & PHY_B_IS_PSE) != 0) { + /* Incorrectable pair swap error */ + SK_ERR_LOG(pAC, SK_ERRCL_HW | SK_ERRCL_INIT, SKERR_SIRQ_E022, + SKERR_SIRQ_E022MSG); + } + + if ((IStatus & (PHY_B_IS_AN_PR | PHY_B_IS_LST_CHANGE)) != 0) { + + SkHWLinkDown(pAC, IoC, Port); + + Para.Para32[0] = (SK_U32)Port; + /* Signal to RLMT */ + SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para); + + /* Start workaround Errata #2 timer */ + SkTimerStart(pAC, IoC, &pPrt->PWaTimer, SK_WA_INA_TIME, + SKGE_HWAC, SK_HWEV_WATIM, Para); + } + +} /* SkPhyIsrBcom */ +#endif /* GENESIS */ + + +#ifdef YUKON +/****************************************************************************** + * + * SkPhyIsrGmac() - PHY interrupt service routine + * + * Description: handles all interrupts from Marvell PHY + * + * Returns: N/A + */ +static void SkPhyIsrGmac( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* Io Context */ +int Port, /* Port Num = PHY Num */ +SK_U16 IStatus) /* Interrupt Status */ +{ + SK_GEPORT *pPrt; /* GIni Port struct pointer */ + SK_EVPARA Para; + SK_U16 Word; + + pPrt = &pAC->GIni.GP[Port]; + + if ((IStatus & (PHY_M_IS_AN_PR | PHY_M_IS_LST_CHANGE)) != 0) { + + SkHWLinkDown(pAC, IoC, Port); + + SkGmPhyRead(pAC, IoC, Port, PHY_MARV_AUNE_ADV, &Word); + + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("AutoNeg.Adv: 0x%04X\n", Word)); + + /* Set Auto-negotiation advertisement */ + if (pPrt->PFlowCtrlMode == SK_FLOW_MODE_SYM_OR_REM) { + /* restore Asymmetric Pause bit */ + SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_AUNE_ADV, + (SK_U16)(Word | PHY_M_AN_ASP)); + } + + Para.Para32[0] = (SK_U32)Port; + /* Signal to RLMT */ + SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para); + } + + if ((IStatus & PHY_M_IS_AN_ERROR) != 0) { + /* Auto-Negotiation Error */ + SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E023, SKERR_SIRQ_E023MSG); + } + + if ((IStatus & PHY_M_IS_FIFO_ERROR) != 0) { + /* FIFO Overflow/Underrun Error */ + SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E024, SKERR_SIRQ_E024MSG); + } + +} /* SkPhyIsrGmac */ +#endif /* YUKON */ + + +#ifdef OTHER_PHY +/****************************************************************************** + * + * SkPhyIsrLone() - PHY interrupt service routine + * + * Description: handles all interrupts from LONE PHY + * + * Returns: N/A + */ +static void SkPhyIsrLone( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* Io Context */ +int Port, /* Port Num = PHY Num */ +SK_U16 IStatus) /* Interrupt Status */ +{ + SK_EVPARA Para; + + if (IStatus & (PHY_L_IS_DUP | PHY_L_IS_ISOL)) { + + SkHWLinkDown(pAC, IoC, Port); + + Para.Para32[0] = (SK_U32)Port; + /* Signal to RLMT */ + SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para); + } + +} /* SkPhyIsrLone */ +#endif /* OTHER_PHY */ + +/* End of File */ diff --git a/drivers/net/sk98lin/ski2c.c b/drivers/net/sk98lin/ski2c.c new file mode 100644 index 000000000000..79bf57cb5326 --- /dev/null +++ b/drivers/net/sk98lin/ski2c.c @@ -0,0 +1,1296 @@ +/****************************************************************************** + * + * Name: ski2c.c + * Project: Gigabit Ethernet Adapters, TWSI-Module + * Version: $Revision: 1.59 $ + * Date: $Date: 2003/10/20 09:07:25 $ + * Purpose: Functions to access Voltage and Temperature Sensor + * + ******************************************************************************/ + +/****************************************************************************** + * + * (C)Copyright 1998-2002 SysKonnect. + * (C)Copyright 2002-2003 Marvell. + * + * 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. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/* + * I2C Protocol + */ +#if (defined(DEBUG) || ((!defined(LINT)) && (!defined(SK_SLIM)))) +static const char SysKonnectFileId[] = + "@(#) $Id: ski2c.c,v 1.59 2003/10/20 09:07:25 rschmidt Exp $ (C) Marvell. "; +#endif + +#include "h/skdrv1st.h" /* Driver Specific Definitions */ +#include "h/lm80.h" +#include "h/skdrv2nd.h" /* Adapter Control- and Driver specific Def. */ + +#ifdef __C2MAN__ +/* + I2C protocol implementation. + + General Description: + + The I2C protocol is used for the temperature sensors and for + the serial EEPROM which hold the configuration. + + This file covers functions that allow to read write and do + some bulk requests a specified I2C address. + + The Genesis has 2 I2C buses. One for the EEPROM which holds + the VPD Data and one for temperature and voltage sensor. + The following picture shows the I2C buses, I2C devices and + their control registers. + + Note: The VPD functions are in skvpd.c +. +. PCI Config I2C Bus for VPD Data: +. +. +------------+ +. | VPD EEPROM | +. +------------+ +. | +. | <-- I2C +. | +. +-----------+-----------+ +. | | +. +-----------------+ +-----------------+ +. | PCI_VPD_ADR_REG | | PCI_VPD_DAT_REG | +. +-----------------+ +-----------------+ +. +. +. I2C Bus for LM80 sensor: +. +. +-----------------+ +. | Temperature and | +. | Voltage Sensor | +. | LM80 | +. +-----------------+ +. | +. | +. I2C --> | +. | +. +----+ +. +-------------->| OR |<--+ +. | +----+ | +. +------+------+ | +. | | | +. +--------+ +--------+ +----------+ +. | B2_I2C | | B2_I2C | | B2_I2C | +. | _CTRL | | _DATA | | _SW | +. +--------+ +--------+ +----------+ +. + The I2C bus may be driven by the B2_I2C_SW or by the B2_I2C_CTRL + and B2_I2C_DATA registers. + For driver software it is recommended to use the I2C control and + data register, because I2C bus timing is done by the ASIC and + an interrupt may be received when the I2C request is completed. + + Clock Rate Timing: MIN MAX generated by + VPD EEPROM: 50 kHz 100 kHz HW + LM80 over I2C Ctrl/Data reg. 50 kHz 100 kHz HW + LM80 over B2_I2C_SW register 0 400 kHz SW + + Note: The clock generated by the hardware is dependend on the + PCI clock. If the PCI bus clock is 33 MHz, the I2C/VPD + clock is 50 kHz. + */ +intro() +{} +#endif + +#ifdef SK_DIAG +/* + * I2C Fast Mode timing values used by the LM80. + * If new devices are added to the I2C bus the timing values have to be checked. + */ +#ifndef I2C_SLOW_TIMING +#define T_CLK_LOW 1300L /* clock low time in ns */ +#define T_CLK_HIGH 600L /* clock high time in ns */ +#define T_DATA_IN_SETUP 100L /* data in Set-up Time */ +#define T_START_HOLD 600L /* start condition hold time */ +#define T_START_SETUP 600L /* start condition Set-up time */ +#define T_STOP_SETUP 600L /* stop condition Set-up time */ +#define T_BUS_IDLE 1300L /* time the bus must free after Tx */ +#define T_CLK_2_DATA_OUT 900L /* max. clock low to data output valid */ +#else /* I2C_SLOW_TIMING */ +/* I2C Standard Mode Timing */ +#define T_CLK_LOW 4700L /* clock low time in ns */ +#define T_CLK_HIGH 4000L /* clock high time in ns */ +#define T_DATA_IN_SETUP 250L /* data in Set-up Time */ +#define T_START_HOLD 4000L /* start condition hold time */ +#define T_START_SETUP 4700L /* start condition Set-up time */ +#define T_STOP_SETUP 4000L /* stop condition Set-up time */ +#define T_BUS_IDLE 4700L /* time the bus must free after Tx */ +#endif /* !I2C_SLOW_TIMING */ + +#define NS2BCLK(x) (((x)*125)/10000) + +/* + * I2C Wire Operations + * + * About I2C_CLK_LOW(): + * + * The Data Direction bit (I2C_DATA_DIR) has to be set to input when setting + * clock to low, to prevent the ASIC and the I2C data client from driving the + * serial data line simultaneously (ASIC: last bit of a byte = '1', I2C client + * send an 'ACK'). See also Concentrator Bugreport No. 10192. + */ +#define I2C_DATA_HIGH(IoC) SK_I2C_SET_BIT(IoC, I2C_DATA) +#define I2C_DATA_LOW(IoC) SK_I2C_CLR_BIT(IoC, I2C_DATA) +#define I2C_DATA_OUT(IoC) SK_I2C_SET_BIT(IoC, I2C_DATA_DIR) +#define I2C_DATA_IN(IoC) SK_I2C_CLR_BIT(IoC, I2C_DATA_DIR | I2C_DATA) +#define I2C_CLK_HIGH(IoC) SK_I2C_SET_BIT(IoC, I2C_CLK) +#define I2C_CLK_LOW(IoC) SK_I2C_CLR_BIT(IoC, I2C_CLK | I2C_DATA_DIR) +#define I2C_START_COND(IoC) SK_I2C_CLR_BIT(IoC, I2C_CLK) + +#define NS2CLKT(x) ((x*125L)/10000) + +/*--------------- I2C Interface Register Functions --------------- */ + +/* + * sending one bit + */ +void SkI2cSndBit( +SK_IOC IoC, /* I/O Context */ +SK_U8 Bit) /* Bit to send */ +{ + I2C_DATA_OUT(IoC); + if (Bit) { + I2C_DATA_HIGH(IoC); + } + else { + I2C_DATA_LOW(IoC); + } + SkDgWaitTime(IoC, NS2BCLK(T_DATA_IN_SETUP)); + I2C_CLK_HIGH(IoC); + SkDgWaitTime(IoC, NS2BCLK(T_CLK_HIGH)); + I2C_CLK_LOW(IoC); +} /* SkI2cSndBit*/ + + +/* + * Signal a start to the I2C Bus. + * + * A start is signaled when data goes to low in a high clock cycle. + * + * Ends with Clock Low. + * + * Status: not tested + */ +void SkI2cStart( +SK_IOC IoC) /* I/O Context */ +{ + /* Init data and Clock to output lines */ + /* Set Data high */ + I2C_DATA_OUT(IoC); + I2C_DATA_HIGH(IoC); + /* Set Clock high */ + I2C_CLK_HIGH(IoC); + + SkDgWaitTime(IoC, NS2BCLK(T_START_SETUP)); + + /* Set Data Low */ + I2C_DATA_LOW(IoC); + + SkDgWaitTime(IoC, NS2BCLK(T_START_HOLD)); + + /* Clock low without Data to Input */ + I2C_START_COND(IoC); + + SkDgWaitTime(IoC, NS2BCLK(T_CLK_LOW)); +} /* SkI2cStart */ + + +void SkI2cStop( +SK_IOC IoC) /* I/O Context */ +{ + /* Init data and Clock to output lines */ + /* Set Data low */ + I2C_DATA_OUT(IoC); + I2C_DATA_LOW(IoC); + + SkDgWaitTime(IoC, NS2BCLK(T_CLK_2_DATA_OUT)); + + /* Set Clock high */ + I2C_CLK_HIGH(IoC); + + SkDgWaitTime(IoC, NS2BCLK(T_STOP_SETUP)); + + /* + * Set Data High: Do it by setting the Data Line to Input. + * Because of a pull up resistor the Data Line + * floods to high. + */ + I2C_DATA_IN(IoC); + + /* + * When I2C activity is stopped + * o DATA should be set to input and + * o CLOCK should be set to high! + */ + SkDgWaitTime(IoC, NS2BCLK(T_BUS_IDLE)); +} /* SkI2cStop */ + + +/* + * Receive just one bit via the I2C bus. + * + * Note: Clock must be set to LOW before calling this function. + * + * Returns The received bit. + */ +int SkI2cRcvBit( +SK_IOC IoC) /* I/O Context */ +{ + int Bit; + SK_U8 I2cSwCtrl; + + /* Init data as input line */ + I2C_DATA_IN(IoC); + + SkDgWaitTime(IoC, NS2BCLK(T_CLK_2_DATA_OUT)); + + I2C_CLK_HIGH(IoC); + + SkDgWaitTime(IoC, NS2BCLK(T_CLK_HIGH)); + + SK_I2C_GET_SW(IoC, &I2cSwCtrl); + + Bit = (I2cSwCtrl & I2C_DATA) ? 1 : 0; + + I2C_CLK_LOW(IoC); + SkDgWaitTime(IoC, NS2BCLK(T_CLK_LOW-T_CLK_2_DATA_OUT)); + + return(Bit); +} /* SkI2cRcvBit */ + + +/* + * Receive an ACK. + * + * returns 0 If acknowledged + * 1 in case of an error + */ +int SkI2cRcvAck( +SK_IOC IoC) /* I/O Context */ +{ + /* + * Received bit must be zero. + */ + return(SkI2cRcvBit(IoC) != 0); +} /* SkI2cRcvAck */ + + +/* + * Send an NACK. + */ +void SkI2cSndNAck( +SK_IOC IoC) /* I/O Context */ +{ + /* + * Received bit must be zero. + */ + SkI2cSndBit(IoC, 1); +} /* SkI2cSndNAck */ + + +/* + * Send an ACK. + */ +void SkI2cSndAck( +SK_IOC IoC) /* I/O Context */ +{ + /* + * Received bit must be zero. + */ + SkI2cSndBit(IoC, 0); +} /* SkI2cSndAck */ + + +/* + * Send one byte to the I2C device and wait for ACK. + * + * Return acknowleged status. + */ +int SkI2cSndByte( +SK_IOC IoC, /* I/O Context */ +int Byte) /* byte to send */ +{ + int i; + + for (i = 0; i < 8; i++) { + if (Byte & (1<<(7-i))) { + SkI2cSndBit(IoC, 1); + } + else { + SkI2cSndBit(IoC, 0); + } + } + + return(SkI2cRcvAck(IoC)); +} /* SkI2cSndByte */ + + +/* + * Receive one byte and ack it. + * + * Return byte. + */ +int SkI2cRcvByte( +SK_IOC IoC, /* I/O Context */ +int Last) /* Last Byte Flag */ +{ + int i; + int Byte = 0; + + for (i = 0; i < 8; i++) { + Byte <<= 1; + Byte |= SkI2cRcvBit(IoC); + } + + if (Last) { + SkI2cSndNAck(IoC); + } + else { + SkI2cSndAck(IoC); + } + + return(Byte); +} /* SkI2cRcvByte */ + + +/* + * Start dialog and send device address + * + * Return 0 if acknowleged, 1 in case of an error + */ +int SkI2cSndDev( +SK_IOC IoC, /* I/O Context */ +int Addr, /* Device Address */ +int Rw) /* Read / Write Flag */ +{ + SkI2cStart(IoC); + Rw = ~Rw; + Rw &= I2C_WRITE; + return(SkI2cSndByte(IoC, (Addr<<1) | Rw)); +} /* SkI2cSndDev */ + +#endif /* SK_DIAG */ + +/*----------------- I2C CTRL Register Functions ----------*/ + +/* + * waits for a completion of an I2C transfer + * + * returns 0: success, transfer completes + * 1: error, transfer does not complete, I2C transfer + * killed, wait loop terminated. + */ +static int SkI2cWait( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +int Event) /* complete event to wait for (I2C_READ or I2C_WRITE) */ +{ + SK_U64 StartTime; + SK_U64 CurrentTime; + SK_U32 I2cCtrl; + + StartTime = SkOsGetTime(pAC); + + do { + CurrentTime = SkOsGetTime(pAC); + + if (CurrentTime - StartTime > SK_TICKS_PER_SEC / 8) { + + SK_I2C_STOP(IoC); +#ifndef SK_DIAG + SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_I2C_E002, SKERR_I2C_E002MSG); +#endif /* !SK_DIAG */ + return(1); + } + + SK_I2C_GET_CTL(IoC, &I2cCtrl); + +#ifdef xYUKON_DBG + printf("StartTime=%lu, CurrentTime=%lu\n", + StartTime, CurrentTime); + if (kbhit()) { + return(1); + } +#endif /* YUKON_DBG */ + + } while ((I2cCtrl & I2C_FLAG) == (SK_U32)Event << 31); + + return(0); +} /* SkI2cWait */ + + +/* + * waits for a completion of an I2C transfer + * + * Returns + * Nothing + */ +void SkI2cWaitIrq( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC) /* I/O Context */ +{ + SK_SENSOR *pSen; + SK_U64 StartTime; + SK_U32 IrqSrc; + + pSen = &pAC->I2c.SenTable[pAC->I2c.CurrSens]; + + if (pSen->SenState == SK_SEN_IDLE) { + return; + } + + StartTime = SkOsGetTime(pAC); + + do { + if (SkOsGetTime(pAC) - StartTime > SK_TICKS_PER_SEC / 8) { + + SK_I2C_STOP(IoC); +#ifndef SK_DIAG + SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_I2C_E016, SKERR_I2C_E016MSG); +#endif /* !SK_DIAG */ + return; + } + + SK_IN32(IoC, B0_ISRC, &IrqSrc); + + } while ((IrqSrc & IS_I2C_READY) == 0); + + pSen->SenState = SK_SEN_IDLE; + return; +} /* SkI2cWaitIrq */ + +/* + * writes a single byte or 4 bytes into the I2C device + * + * returns 0: success + * 1: error + */ +static int SkI2cWrite( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_U32 I2cData, /* I2C Data to write */ +int I2cDev, /* I2C Device Address */ +int I2cDevSize, /* I2C Device Size (e.g. I2C_025K_DEV or I2C_2K_DEV) */ +int I2cReg, /* I2C Device Register Address */ +int I2cBurst) /* I2C Burst Flag */ +{ + SK_OUT32(IoC, B2_I2C_DATA, I2cData); + + SK_I2C_CTL(IoC, I2C_WRITE, I2cDev, I2cDevSize, I2cReg, I2cBurst); + + return(SkI2cWait(pAC, IoC, I2C_WRITE)); +} /* SkI2cWrite*/ + + +#ifdef SK_DIAG +/* + * reads a single byte or 4 bytes from the I2C device + * + * returns the word read + */ +SK_U32 SkI2cRead( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +int I2cDev, /* I2C Device Address */ +int I2cDevSize, /* I2C Device Size (e.g. I2C_025K_DEV or I2C_2K_DEV) */ +int I2cReg, /* I2C Device Register Address */ +int I2cBurst) /* I2C Burst Flag */ +{ + SK_U32 Data; + + SK_OUT32(IoC, B2_I2C_DATA, 0); + SK_I2C_CTL(IoC, I2C_READ, I2cDev, I2cDevSize, I2cReg, I2cBurst); + + if (SkI2cWait(pAC, IoC, I2C_READ) != 0) { + w_print("%s\n", SKERR_I2C_E002MSG); + } + + SK_IN32(IoC, B2_I2C_DATA, &Data); + + return(Data); +} /* SkI2cRead */ +#endif /* SK_DIAG */ + + +/* + * read a sensor's value + * + * This function reads a sensor's value from the I2C sensor chip. The sensor + * is defined by its index into the sensors database in the struct pAC points + * to. + * Returns + * 1 if the read is completed + * 0 if the read must be continued (I2C Bus still allocated) + */ +static int SkI2cReadSensor( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_SENSOR *pSen) /* Sensor to be read */ +{ + if (pSen->SenRead != NULL) { + return((*pSen->SenRead)(pAC, IoC, pSen)); + } + else { + return(0); /* no success */ + } +} /* SkI2cReadSensor */ + +/* + * Do the Init state 0 initialization + */ +static int SkI2cInit0( +SK_AC *pAC) /* Adapter Context */ +{ + int i; + + /* Begin with first sensor */ + pAC->I2c.CurrSens = 0; + + /* Begin with timeout control for state machine */ + pAC->I2c.TimerMode = SK_TIMER_WATCH_SM; + + /* Set sensor number to zero */ + pAC->I2c.MaxSens = 0; + +#ifndef SK_DIAG + /* Initialize Number of Dummy Reads */ + pAC->I2c.DummyReads = SK_MAX_SENSORS; +#endif + + for (i = 0; i < SK_MAX_SENSORS; i++) { + pAC->I2c.SenTable[i].SenDesc = "unknown"; + pAC->I2c.SenTable[i].SenType = SK_SEN_UNKNOWN; + pAC->I2c.SenTable[i].SenThreErrHigh = 0; + pAC->I2c.SenTable[i].SenThreErrLow = 0; + pAC->I2c.SenTable[i].SenThreWarnHigh = 0; + pAC->I2c.SenTable[i].SenThreWarnLow = 0; + pAC->I2c.SenTable[i].SenReg = LM80_FAN2_IN; + pAC->I2c.SenTable[i].SenInit = SK_SEN_DYN_INIT_NONE; + pAC->I2c.SenTable[i].SenValue = 0; + pAC->I2c.SenTable[i].SenErrFlag = SK_SEN_ERR_NOT_PRESENT; + pAC->I2c.SenTable[i].SenErrCts = 0; + pAC->I2c.SenTable[i].SenBegErrTS = 0; + pAC->I2c.SenTable[i].SenState = SK_SEN_IDLE; + pAC->I2c.SenTable[i].SenRead = NULL; + pAC->I2c.SenTable[i].SenDev = 0; + } + + /* Now we are "INIT data"ed */ + pAC->I2c.InitLevel = SK_INIT_DATA; + return(0); +} /* SkI2cInit0*/ + + +/* + * Do the init state 1 initialization + * + * initialize the following register of the LM80: + * Configuration register: + * - START, noINT, activeLOW, noINT#Clear, noRESET, noCI, noGPO#, noINIT + * + * Interrupt Mask Register 1: + * - all interrupts are Disabled (0xff) + * + * Interrupt Mask Register 2: + * - all interrupts are Disabled (0xff) Interrupt modi doesn't matter. + * + * Fan Divisor/RST_OUT register: + * - Divisors set to 1 (bits 00), all others 0s. + * + * OS# Configuration/Temperature resolution Register: + * - all 0s + * + */ +static int SkI2cInit1( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC) /* I/O Context */ +{ + int i; + SK_U8 I2cSwCtrl; + SK_GEPORT *pPrt; /* GIni Port struct pointer */ + + if (pAC->I2c.InitLevel != SK_INIT_DATA) { + /* ReInit not needed in I2C module */ + return(0); + } + + /* Set the Direction of I2C-Data Pin to IN */ + SK_I2C_CLR_BIT(IoC, I2C_DATA_DIR | I2C_DATA); + /* Check for 32-Bit Yukon with Low at I2C-Data Pin */ + SK_I2C_GET_SW(IoC, &I2cSwCtrl); + + if ((I2cSwCtrl & I2C_DATA) == 0) { + /* this is a 32-Bit board */ + pAC->GIni.GIYukon32Bit = SK_TRUE; + return(0); + } + + /* Check for 64 Bit Yukon without sensors */ + if (SkI2cWrite(pAC, IoC, 0, LM80_ADDR, I2C_025K_DEV, LM80_CFG, 0) != 0) { + return(0); + } + + (void)SkI2cWrite(pAC, IoC, 0xffUL, LM80_ADDR, I2C_025K_DEV, LM80_IMSK_1, 0); + + (void)SkI2cWrite(pAC, IoC, 0xffUL, LM80_ADDR, I2C_025K_DEV, LM80_IMSK_2, 0); + + (void)SkI2cWrite(pAC, IoC, 0, LM80_ADDR, I2C_025K_DEV, LM80_FAN_CTRL, 0); + + (void)SkI2cWrite(pAC, IoC, 0, LM80_ADDR, I2C_025K_DEV, LM80_TEMP_CTRL, 0); + + (void)SkI2cWrite(pAC, IoC, (SK_U32)LM80_CFG_START, LM80_ADDR, I2C_025K_DEV, + LM80_CFG, 0); + + /* + * MaxSens has to be updated here, because PhyType is not + * set when performing Init Level 0 + */ + pAC->I2c.MaxSens = 5; + + pPrt = &pAC->GIni.GP[0]; + + if (pAC->GIni.GIGenesis) { + if (pPrt->PhyType == SK_PHY_BCOM) { + if (pAC->GIni.GIMacsFound == 1) { + pAC->I2c.MaxSens += 1; + } + else { + pAC->I2c.MaxSens += 3; + } + } + } + else { + pAC->I2c.MaxSens += 3; + } + + for (i = 0; i < pAC->I2c.MaxSens; i++) { + switch (i) { + case 0: + pAC->I2c.SenTable[i].SenDesc = "Temperature"; + pAC->I2c.SenTable[i].SenType = SK_SEN_TEMP; + pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_TEMP_HIGH_ERR; + pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_TEMP_HIGH_WARN; + pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_TEMP_LOW_WARN; + pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_TEMP_LOW_ERR; + pAC->I2c.SenTable[i].SenReg = LM80_TEMP_IN; + break; + case 1: + pAC->I2c.SenTable[i].SenDesc = "Voltage PCI"; + pAC->I2c.SenTable[i].SenType = SK_SEN_VOLT; + pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_PCI_5V_HIGH_ERR; + pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_PCI_5V_HIGH_WARN; + pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_PCI_5V_LOW_WARN; + pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_PCI_5V_LOW_ERR; + pAC->I2c.SenTable[i].SenReg = LM80_VT0_IN; + break; + case 2: + pAC->I2c.SenTable[i].SenDesc = "Voltage PCI-IO"; + pAC->I2c.SenTable[i].SenType = SK_SEN_VOLT; + pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_PCI_IO_5V_HIGH_ERR; + pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_PCI_IO_5V_HIGH_WARN; + pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_PCI_IO_3V3_LOW_WARN; + pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_PCI_IO_3V3_LOW_ERR; + pAC->I2c.SenTable[i].SenReg = LM80_VT1_IN; + pAC->I2c.SenTable[i].SenInit = SK_SEN_DYN_INIT_PCI_IO; + break; + case 3: + pAC->I2c.SenTable[i].SenDesc = "Voltage ASIC"; + pAC->I2c.SenTable[i].SenType = SK_SEN_VOLT; + pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_VDD_HIGH_ERR; + pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_VDD_HIGH_WARN; + pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_VDD_LOW_WARN; + pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_VDD_LOW_ERR; + pAC->I2c.SenTable[i].SenReg = LM80_VT2_IN; + break; + case 4: + if (pAC->GIni.GIGenesis) { + if (pPrt->PhyType == SK_PHY_BCOM) { + pAC->I2c.SenTable[i].SenDesc = "Voltage PHY A PLL"; + pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_PLL_3V3_HIGH_ERR; + pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_PLL_3V3_HIGH_WARN; + pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_PLL_3V3_LOW_WARN; + pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_PLL_3V3_LOW_ERR; + } + else { + pAC->I2c.SenTable[i].SenDesc = "Voltage PMA"; + pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_PLL_3V3_HIGH_ERR; + pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_PLL_3V3_HIGH_WARN; + pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_PLL_3V3_LOW_WARN; + pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_PLL_3V3_LOW_ERR; + } + } + else { + pAC->I2c.SenTable[i].SenDesc = "Voltage VAUX"; + pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_VAUX_3V3_HIGH_ERR; + pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_VAUX_3V3_HIGH_WARN; + if (pAC->GIni.GIVauxAvail) { + pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_VAUX_3V3_LOW_WARN; + pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_VAUX_3V3_LOW_ERR; + } + else { + pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_VAUX_0V_WARN_ERR; + pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_VAUX_0V_WARN_ERR; + } + } + pAC->I2c.SenTable[i].SenType = SK_SEN_VOLT; + pAC->I2c.SenTable[i].SenReg = LM80_VT3_IN; + break; + case 5: + if (pAC->GIni.GIGenesis) { + pAC->I2c.SenTable[i].SenDesc = "Voltage PHY 2V5"; + pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_PHY_2V5_HIGH_ERR; + pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_PHY_2V5_HIGH_WARN; + pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_PHY_2V5_LOW_WARN; + pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_PHY_2V5_LOW_ERR; + } + else { + pAC->I2c.SenTable[i].SenDesc = "Voltage Core 1V5"; + pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_CORE_1V5_HIGH_ERR; + pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_CORE_1V5_HIGH_WARN; + pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_CORE_1V5_LOW_WARN; + pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_CORE_1V5_LOW_ERR; + } + pAC->I2c.SenTable[i].SenType = SK_SEN_VOLT; + pAC->I2c.SenTable[i].SenReg = LM80_VT4_IN; + break; + case 6: + if (pAC->GIni.GIGenesis) { + pAC->I2c.SenTable[i].SenDesc = "Voltage PHY B PLL"; + } + else { + pAC->I2c.SenTable[i].SenDesc = "Voltage PHY 3V3"; + } + pAC->I2c.SenTable[i].SenType = SK_SEN_VOLT; + pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_PLL_3V3_HIGH_ERR; + pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_PLL_3V3_HIGH_WARN; + pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_PLL_3V3_LOW_WARN; + pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_PLL_3V3_LOW_ERR; + pAC->I2c.SenTable[i].SenReg = LM80_VT5_IN; + break; + case 7: + if (pAC->GIni.GIGenesis) { + pAC->I2c.SenTable[i].SenDesc = "Speed Fan"; + pAC->I2c.SenTable[i].SenType = SK_SEN_FAN; + pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_FAN_HIGH_ERR; + pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_FAN_HIGH_WARN; + pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_FAN_LOW_WARN; + pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_FAN_LOW_ERR; + pAC->I2c.SenTable[i].SenReg = LM80_FAN2_IN; + } + else { + pAC->I2c.SenTable[i].SenDesc = "Voltage PHY 2V5"; + pAC->I2c.SenTable[i].SenType = SK_SEN_VOLT; + pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_PHY_2V5_HIGH_ERR; + pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_PHY_2V5_HIGH_WARN; + pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_PHY_2V5_LOW_WARN; + pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_PHY_2V5_LOW_ERR; + pAC->I2c.SenTable[i].SenReg = LM80_VT6_IN; + } + break; + default: + SK_ERR_LOG(pAC, SK_ERRCL_INIT | SK_ERRCL_SW, + SKERR_I2C_E001, SKERR_I2C_E001MSG); + break; + } + + pAC->I2c.SenTable[i].SenValue = 0; + pAC->I2c.SenTable[i].SenErrFlag = SK_SEN_ERR_OK; + pAC->I2c.SenTable[i].SenErrCts = 0; + pAC->I2c.SenTable[i].SenBegErrTS = 0; + pAC->I2c.SenTable[i].SenState = SK_SEN_IDLE; + pAC->I2c.SenTable[i].SenRead = SkLm80ReadSensor; + pAC->I2c.SenTable[i].SenDev = LM80_ADDR; + } + +#ifndef SK_DIAG + pAC->I2c.DummyReads = pAC->I2c.MaxSens; +#endif /* !SK_DIAG */ + + /* Clear I2C IRQ */ + SK_OUT32(IoC, B2_I2C_IRQ, I2C_CLR_IRQ); + + /* Now we are I/O initialized */ + pAC->I2c.InitLevel = SK_INIT_IO; + return(0); +} /* SkI2cInit1 */ + + +/* + * Init level 2: Start first sensor read. + */ +static int SkI2cInit2( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC) /* I/O Context */ +{ + int ReadComplete; + SK_SENSOR *pSen; + + if (pAC->I2c.InitLevel != SK_INIT_IO) { + /* ReInit not needed in I2C module */ + /* Init0 and Init2 not permitted */ + return(0); + } + + pSen = &pAC->I2c.SenTable[pAC->I2c.CurrSens]; + ReadComplete = SkI2cReadSensor(pAC, IoC, pSen); + + if (ReadComplete) { + SK_ERR_LOG(pAC, SK_ERRCL_INIT, SKERR_I2C_E008, SKERR_I2C_E008MSG); + } + + /* Now we are correctly initialized */ + pAC->I2c.InitLevel = SK_INIT_RUN; + + return(0); +} /* SkI2cInit2*/ + + +/* + * Initialize I2C devices + * + * Get the first voltage value and discard it. + * Go into temperature read mode. A default pointer is not set. + * + * The things to be done depend on the init level in the parameter list: + * Level 0: + * Initialize only the data structures. Do NOT access hardware. + * Level 1: + * Initialize hardware through SK_IN / SK_OUT commands. Do NOT use interrupts. + * Level 2: + * Everything is possible. Interrupts may be used from now on. + * + * return: + * 0 = success + * other = error. + */ +int SkI2cInit( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context needed in levels 1 and 2 */ +int Level) /* Init Level */ +{ + + switch (Level) { + case SK_INIT_DATA: + return(SkI2cInit0(pAC)); + case SK_INIT_IO: + return(SkI2cInit1(pAC, IoC)); + case SK_INIT_RUN: + return(SkI2cInit2(pAC, IoC)); + default: + break; + } + + return(0); +} /* SkI2cInit */ + + +#ifndef SK_DIAG + +/* + * Interrupt service function for the I2C Interface + * + * Clears the Interrupt source + * + * Reads the register and check it for sending a trap. + * + * Starts the timer if necessary. + */ +void SkI2cIsr( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC) /* I/O Context */ +{ + SK_EVPARA Para; + + /* Clear I2C IRQ */ + SK_OUT32(IoC, B2_I2C_IRQ, I2C_CLR_IRQ); + + Para.Para64 = 0; + SkEventQueue(pAC, SKGE_I2C, SK_I2CEV_IRQ, Para); +} /* SkI2cIsr */ + + +/* + * Check this sensors Value against the threshold and send events. + */ +static void SkI2cCheckSensor( +SK_AC *pAC, /* Adapter Context */ +SK_SENSOR *pSen) +{ + SK_EVPARA ParaLocal; + SK_BOOL TooHigh; /* Is sensor too high? */ + SK_BOOL TooLow; /* Is sensor too low? */ + SK_U64 CurrTime; /* Current Time */ + SK_BOOL DoTrapSend; /* We need to send a trap */ + SK_BOOL DoErrLog; /* We need to log the error */ + SK_BOOL IsError; /* We need to log the error */ + + /* Check Dummy Reads first */ + if (pAC->I2c.DummyReads > 0) { + pAC->I2c.DummyReads--; + return; + } + + /* Get the current time */ + CurrTime = SkOsGetTime(pAC); + + /* Set para to the most useful setting: The current sensor. */ + ParaLocal.Para64 = (SK_U64)pAC->I2c.CurrSens; + + /* Check the Value against the thresholds. First: Error Thresholds */ + TooHigh = (pSen->SenValue > pSen->SenThreErrHigh); + TooLow = (pSen->SenValue < pSen->SenThreErrLow); + + IsError = SK_FALSE; + if (TooHigh || TooLow) { + /* Error condition is satisfied */ + DoTrapSend = SK_TRUE; + DoErrLog = SK_TRUE; + + /* Now error condition is satisfied */ + IsError = SK_TRUE; + + if (pSen->SenErrFlag == SK_SEN_ERR_ERR) { + /* This state is the former one */ + + /* So check first whether we have to send a trap */ + if (pSen->SenLastErrTrapTS + SK_SEN_ERR_TR_HOLD > + CurrTime) { + /* + * Do NOT send the Trap. The hold back time + * has to run out first. + */ + DoTrapSend = SK_FALSE; + } + + /* Check now whether we have to log an Error */ + if (pSen->SenLastErrLogTS + SK_SEN_ERR_LOG_HOLD > + CurrTime) { + /* + * Do NOT log the error. The hold back time + * has to run out first. + */ + DoErrLog = SK_FALSE; + } + } + else { + /* We came from a different state -> Set Begin Time Stamp */ + pSen->SenBegErrTS = CurrTime; + pSen->SenErrFlag = SK_SEN_ERR_ERR; + } + + if (DoTrapSend) { + /* Set current Time */ + pSen->SenLastErrTrapTS = CurrTime; + pSen->SenErrCts++; + + /* Queue PNMI Event */ + SkEventQueue(pAC, SKGE_PNMI, (TooHigh ? + SK_PNMI_EVT_SEN_ERR_UPP : + SK_PNMI_EVT_SEN_ERR_LOW), + ParaLocal); + } + + if (DoErrLog) { + /* Set current Time */ + pSen->SenLastErrLogTS = CurrTime; + + if (pSen->SenType == SK_SEN_TEMP) { + SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E011, SKERR_I2C_E011MSG); + } + else if (pSen->SenType == SK_SEN_VOLT) { + SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E012, SKERR_I2C_E012MSG); + } + else { + SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E015, SKERR_I2C_E015MSG); + } + } + } + + /* Check the Value against the thresholds */ + /* 2nd: Warning thresholds */ + TooHigh = (pSen->SenValue > pSen->SenThreWarnHigh); + TooLow = (pSen->SenValue < pSen->SenThreWarnLow); + + if (!IsError && (TooHigh || TooLow)) { + /* Error condition is satisfied */ + DoTrapSend = SK_TRUE; + DoErrLog = SK_TRUE; + + if (pSen->SenErrFlag == SK_SEN_ERR_WARN) { + /* This state is the former one */ + + /* So check first whether we have to send a trap */ + if (pSen->SenLastWarnTrapTS + SK_SEN_WARN_TR_HOLD > CurrTime) { + /* + * Do NOT send the Trap. The hold back time + * has to run out first. + */ + DoTrapSend = SK_FALSE; + } + + /* Check now whether we have to log an Error */ + if (pSen->SenLastWarnLogTS + SK_SEN_WARN_LOG_HOLD > CurrTime) { + /* + * Do NOT log the error. The hold back time + * has to run out first. + */ + DoErrLog = SK_FALSE; + } + } + else { + /* We came from a different state -> Set Begin Time Stamp */ + pSen->SenBegWarnTS = CurrTime; + pSen->SenErrFlag = SK_SEN_ERR_WARN; + } + + if (DoTrapSend) { + /* Set current Time */ + pSen->SenLastWarnTrapTS = CurrTime; + pSen->SenWarnCts++; + + /* Queue PNMI Event */ + SkEventQueue(pAC, SKGE_PNMI, (TooHigh ? + SK_PNMI_EVT_SEN_WAR_UPP : + SK_PNMI_EVT_SEN_WAR_LOW), + ParaLocal); + } + + if (DoErrLog) { + /* Set current Time */ + pSen->SenLastWarnLogTS = CurrTime; + + if (pSen->SenType == SK_SEN_TEMP) { + SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E009, SKERR_I2C_E009MSG); + } + else if (pSen->SenType == SK_SEN_VOLT) { + SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E010, SKERR_I2C_E010MSG); + } + else { + SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E014, SKERR_I2C_E014MSG); + } + } + } + + /* Check for NO error at all */ + if (!IsError && !TooHigh && !TooLow) { + /* Set o.k. Status if no error and no warning condition */ + pSen->SenErrFlag = SK_SEN_ERR_OK; + } + + /* End of check against the thresholds */ + + /* Bug fix AF: 16.Aug.2001: Correct the init base + * of LM80 sensor. + */ + if (pSen->SenInit == SK_SEN_DYN_INIT_PCI_IO) { + + pSen->SenInit = SK_SEN_DYN_INIT_NONE; + + if (pSen->SenValue > SK_SEN_PCI_IO_RANGE_LIMITER) { + /* 5V PCI-IO Voltage */ + pSen->SenThreWarnLow = SK_SEN_PCI_IO_5V_LOW_WARN; + pSen->SenThreErrLow = SK_SEN_PCI_IO_5V_LOW_ERR; + } + else { + /* 3.3V PCI-IO Voltage */ + pSen->SenThreWarnHigh = SK_SEN_PCI_IO_3V3_HIGH_WARN; + pSen->SenThreErrHigh = SK_SEN_PCI_IO_3V3_HIGH_ERR; + } + } + +#ifdef TEST_ONLY + /* Dynamic thresholds also for VAUX of LM80 sensor */ + if (pSen->SenInit == SK_SEN_DYN_INIT_VAUX) { + + pSen->SenInit = SK_SEN_DYN_INIT_NONE; + + /* 3.3V VAUX Voltage */ + if (pSen->SenValue > SK_SEN_VAUX_RANGE_LIMITER) { + pSen->SenThreWarnLow = SK_SEN_VAUX_3V3_LOW_WARN; + pSen->SenThreErrLow = SK_SEN_VAUX_3V3_LOW_ERR; + } + /* 0V VAUX Voltage */ + else { + pSen->SenThreWarnHigh = SK_SEN_VAUX_0V_WARN_ERR; + pSen->SenThreErrHigh = SK_SEN_VAUX_0V_WARN_ERR; + } + } + + /* + * Check initialization state: + * The VIO Thresholds need adaption + */ + if (!pSen->SenInit && pSen->SenReg == LM80_VT1_IN && + pSen->SenValue > SK_SEN_WARNLOW2C && + pSen->SenValue < SK_SEN_WARNHIGH2) { + pSen->SenThreErrLow = SK_SEN_ERRLOW2C; + pSen->SenThreWarnLow = SK_SEN_WARNLOW2C; + pSen->SenInit = SK_TRUE; + } + + if (!pSen->SenInit && pSen->SenReg == LM80_VT1_IN && + pSen->SenValue > SK_SEN_WARNLOW2 && + pSen->SenValue < SK_SEN_WARNHIGH2C) { + pSen->SenThreErrHigh = SK_SEN_ERRHIGH2C; + pSen->SenThreWarnHigh = SK_SEN_WARNHIGH2C; + pSen->SenInit = SK_TRUE; + } +#endif + + if (pSen->SenInit != SK_SEN_DYN_INIT_NONE) { + SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E013, SKERR_I2C_E013MSG); + } +} /* SkI2cCheckSensor */ + + +/* + * The only Event to be served is the timeout event + * + */ +int SkI2cEvent( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_U32 Event, /* Module specific Event */ +SK_EVPARA Para) /* Event specific Parameter */ +{ + int ReadComplete; + SK_SENSOR *pSen; + SK_U32 Time; + SK_EVPARA ParaLocal; + int i; + + /* New case: no sensors */ + if (pAC->I2c.MaxSens == 0) { + return(0); + } + + switch (Event) { + case SK_I2CEV_IRQ: + pSen = &pAC->I2c.SenTable[pAC->I2c.CurrSens]; + ReadComplete = SkI2cReadSensor(pAC, IoC, pSen); + + if (ReadComplete) { + /* Check sensor against defined thresholds */ + SkI2cCheckSensor(pAC, pSen); + + /* Increment Current sensor and set appropriate Timeout */ + pAC->I2c.CurrSens++; + if (pAC->I2c.CurrSens >= pAC->I2c.MaxSens) { + pAC->I2c.CurrSens = 0; + Time = SK_I2C_TIM_LONG; + } + else { + Time = SK_I2C_TIM_SHORT; + } + + /* Start Timer */ + ParaLocal.Para64 = (SK_U64)0; + + pAC->I2c.TimerMode = SK_TIMER_NEW_GAUGING; + + SkTimerStart(pAC, IoC, &pAC->I2c.SenTimer, Time, + SKGE_I2C, SK_I2CEV_TIM, ParaLocal); + } + else { + /* Start Timer */ + ParaLocal.Para64 = (SK_U64)0; + + pAC->I2c.TimerMode = SK_TIMER_WATCH_SM; + + SkTimerStart(pAC, IoC, &pAC->I2c.SenTimer, SK_I2C_TIM_WATCH, + SKGE_I2C, SK_I2CEV_TIM, ParaLocal); + } + break; + case SK_I2CEV_TIM: + if (pAC->I2c.TimerMode == SK_TIMER_NEW_GAUGING) { + + ParaLocal.Para64 = (SK_U64)0; + SkTimerStop(pAC, IoC, &pAC->I2c.SenTimer); + + pSen = &pAC->I2c.SenTable[pAC->I2c.CurrSens]; + ReadComplete = SkI2cReadSensor(pAC, IoC, pSen); + + if (ReadComplete) { + /* Check sensor against defined thresholds */ + SkI2cCheckSensor(pAC, pSen); + + /* Increment Current sensor and set appropriate Timeout */ + pAC->I2c.CurrSens++; + if (pAC->I2c.CurrSens == pAC->I2c.MaxSens) { + pAC->I2c.CurrSens = 0; + Time = SK_I2C_TIM_LONG; + } + else { + Time = SK_I2C_TIM_SHORT; + } + + /* Start Timer */ + ParaLocal.Para64 = (SK_U64)0; + + pAC->I2c.TimerMode = SK_TIMER_NEW_GAUGING; + + SkTimerStart(pAC, IoC, &pAC->I2c.SenTimer, Time, + SKGE_I2C, SK_I2CEV_TIM, ParaLocal); + } + } + else { + pSen = &pAC->I2c.SenTable[pAC->I2c.CurrSens]; + pSen->SenErrFlag = SK_SEN_ERR_FAULTY; + SK_I2C_STOP(IoC); + + /* Increment Current sensor and set appropriate Timeout */ + pAC->I2c.CurrSens++; + if (pAC->I2c.CurrSens == pAC->I2c.MaxSens) { + pAC->I2c.CurrSens = 0; + Time = SK_I2C_TIM_LONG; + } + else { + Time = SK_I2C_TIM_SHORT; + } + + /* Start Timer */ + ParaLocal.Para64 = (SK_U64)0; + + pAC->I2c.TimerMode = SK_TIMER_NEW_GAUGING; + + SkTimerStart(pAC, IoC, &pAC->I2c.SenTimer, Time, + SKGE_I2C, SK_I2CEV_TIM, ParaLocal); + } + break; + case SK_I2CEV_CLEAR: + for (i = 0; i < SK_MAX_SENSORS; i++) { + pAC->I2c.SenTable[i].SenErrFlag = SK_SEN_ERR_OK; + pAC->I2c.SenTable[i].SenErrCts = 0; + pAC->I2c.SenTable[i].SenWarnCts = 0; + pAC->I2c.SenTable[i].SenBegErrTS = 0; + pAC->I2c.SenTable[i].SenBegWarnTS = 0; + pAC->I2c.SenTable[i].SenLastErrTrapTS = (SK_U64)0; + pAC->I2c.SenTable[i].SenLastErrLogTS = (SK_U64)0; + pAC->I2c.SenTable[i].SenLastWarnTrapTS = (SK_U64)0; + pAC->I2c.SenTable[i].SenLastWarnLogTS = (SK_U64)0; + } + break; + default: + SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_I2C_E006, SKERR_I2C_E006MSG); + } + + return(0); +} /* SkI2cEvent*/ + +#endif /* !SK_DIAG */ diff --git a/drivers/net/sk98lin/sklm80.c b/drivers/net/sk98lin/sklm80.c new file mode 100644 index 000000000000..a204f5bb55d4 --- /dev/null +++ b/drivers/net/sk98lin/sklm80.c @@ -0,0 +1,141 @@ +/****************************************************************************** + * + * Name: sklm80.c + * Project: Gigabit Ethernet Adapters, TWSI-Module + * Version: $Revision: 1.22 $ + * Date: $Date: 2003/10/20 09:08:21 $ + * Purpose: Functions to access Voltage and Temperature Sensor (LM80) + * + ******************************************************************************/ + +/****************************************************************************** + * + * (C)Copyright 1998-2002 SysKonnect. + * (C)Copyright 2002-2003 Marvell. + * + * 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. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/* + LM80 functions +*/ +#if (defined(DEBUG) || ((!defined(LINT)) && (!defined(SK_SLIM)))) +static const char SysKonnectFileId[] = + "@(#) $Id: sklm80.c,v 1.22 2003/10/20 09:08:21 rschmidt Exp $ (C) Marvell. "; +#endif + +#include "h/skdrv1st.h" /* Driver Specific Definitions */ +#include "h/lm80.h" +#include "h/skdrv2nd.h" /* Adapter Control- and Driver specific Def. */ + +#define BREAK_OR_WAIT(pAC,IoC,Event) break + +/* + * read a sensors value (LM80 specific) + * + * This function reads a sensors value from the I2C sensor chip LM80. + * The sensor is defined by its index into the sensors database in the struct + * pAC points to. + * + * Returns 1 if the read is completed + * 0 if the read must be continued (I2C Bus still allocated) + */ +int SkLm80ReadSensor( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context needed in level 1 and 2 */ +SK_SENSOR *pSen) /* Sensor to be read */ +{ + SK_I32 Value; + + switch (pSen->SenState) { + case SK_SEN_IDLE: + /* Send address to ADDR register */ + SK_I2C_CTL(IoC, I2C_READ, pSen->SenDev, I2C_025K_DEV, pSen->SenReg, 0); + + pSen->SenState = SK_SEN_VALUE ; + BREAK_OR_WAIT(pAC, IoC, I2C_READ); + + case SK_SEN_VALUE: + /* Read value from data register */ + SK_IN32(IoC, B2_I2C_DATA, ((SK_U32 *)&Value)); + + Value &= 0xff; /* only least significant byte is valid */ + + /* Do NOT check the Value against the thresholds */ + /* Checking is done in the calling instance */ + + if (pSen->SenType == SK_SEN_VOLT) { + /* Voltage sensor */ + pSen->SenValue = Value * SK_LM80_VT_LSB; + pSen->SenState = SK_SEN_IDLE ; + return(1); + } + + if (pSen->SenType == SK_SEN_FAN) { + if (Value != 0 && Value != 0xff) { + /* Fan speed counter */ + pSen->SenValue = SK_LM80_FAN_FAKTOR/Value; + } + else { + /* Indicate Fan error */ + pSen->SenValue = 0; + } + pSen->SenState = SK_SEN_IDLE ; + return(1); + } + + /* First: correct the value: it might be negative */ + if ((Value & 0x80) != 0) { + /* Value is negative */ + Value = Value - 256; + } + + /* We have a temperature sensor and need to get the signed extension. + * For now we get the extension from the last reading, so in the normal + * case we won't see flickering temperatures. + */ + pSen->SenValue = (Value * SK_LM80_TEMP_LSB) + + (pSen->SenValue % SK_LM80_TEMP_LSB); + + /* Send address to ADDR register */ + SK_I2C_CTL(IoC, I2C_READ, pSen->SenDev, I2C_025K_DEV, LM80_TEMP_CTRL, 0); + + pSen->SenState = SK_SEN_VALEXT ; + BREAK_OR_WAIT(pAC, IoC, I2C_READ); + + case SK_SEN_VALEXT: + /* Read value from data register */ + SK_IN32(IoC, B2_I2C_DATA, ((SK_U32 *)&Value)); + Value &= LM80_TEMP_LSB_9; /* only bit 7 is valid */ + + /* cut the LSB bit */ + pSen->SenValue = ((pSen->SenValue / SK_LM80_TEMP_LSB) * + SK_LM80_TEMP_LSB); + + if (pSen->SenValue < 0) { + /* Value negative: The bit value must be subtracted */ + pSen->SenValue -= ((Value >> 7) * SK_LM80_TEMPEXT_LSB); + } + else { + /* Value positive: The bit value must be added */ + pSen->SenValue += ((Value >> 7) * SK_LM80_TEMPEXT_LSB); + } + + pSen->SenState = SK_SEN_IDLE ; + return(1); + + default: + SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_I2C_E007, SKERR_I2C_E007MSG); + return(1); + } + + /* Not completed */ + return(0); +} + diff --git a/drivers/net/sk98lin/skqueue.c b/drivers/net/sk98lin/skqueue.c new file mode 100644 index 000000000000..0275b4f71d9b --- /dev/null +++ b/drivers/net/sk98lin/skqueue.c @@ -0,0 +1,179 @@ +/****************************************************************************** + * + * Name: skqueue.c + * Project: Gigabit Ethernet Adapters, Event Scheduler Module + * Version: $Revision: 1.20 $ + * Date: $Date: 2003/09/16 13:44:00 $ + * Purpose: Management of an event queue. + * + ******************************************************************************/ + +/****************************************************************************** + * + * (C)Copyright 1998-2002 SysKonnect GmbH. + * (C)Copyright 2002-2003 Marvell. + * + * 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. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + + +/* + * Event queue and dispatcher + */ +#if (defined(DEBUG) || ((!defined(LINT)) && (!defined(SK_SLIM)))) +static const char SysKonnectFileId[] = + "@(#) $Id: skqueue.c,v 1.20 2003/09/16 13:44:00 rschmidt Exp $ (C) Marvell."; +#endif + +#include "h/skdrv1st.h" /* Driver Specific Definitions */ +#include "h/skqueue.h" /* Queue Definitions */ +#include "h/skdrv2nd.h" /* Adapter Control- and Driver specific Def. */ + +#ifdef __C2MAN__ +/* + Event queue management. + + General Description: + + */ +intro() +{} +#endif + +#define PRINTF(a,b,c) + +/* + * init event queue management + * + * Must be called during init level 0. + */ +void SkEventInit( +SK_AC *pAC, /* Adapter context */ +SK_IOC Ioc, /* IO context */ +int Level) /* Init level */ +{ + switch (Level) { + case SK_INIT_DATA: + pAC->Event.EvPut = pAC->Event.EvGet = pAC->Event.EvQueue; + break; + default: + break; + } +} + +/* + * add event to queue + */ +void SkEventQueue( +SK_AC *pAC, /* Adapters context */ +SK_U32 Class, /* Event Class */ +SK_U32 Event, /* Event to be queued */ +SK_EVPARA Para) /* Event parameter */ +{ + pAC->Event.EvPut->Class = Class; + pAC->Event.EvPut->Event = Event; + pAC->Event.EvPut->Para = Para; + + if (++pAC->Event.EvPut == &pAC->Event.EvQueue[SK_MAX_EVENT]) + pAC->Event.EvPut = pAC->Event.EvQueue; + + if (pAC->Event.EvPut == pAC->Event.EvGet) { + SK_ERR_LOG(pAC, SK_ERRCL_NORES, SKERR_Q_E001, SKERR_Q_E001MSG); + } +} + +/* + * event dispatcher + * while event queue is not empty + * get event from queue + * send command to state machine + * end + * return error reported by individual Event function + * 0 if no error occured. + */ +int SkEventDispatcher( +SK_AC *pAC, /* Adapters Context */ +SK_IOC Ioc) /* Io context */ +{ + SK_EVENTELEM *pEv; /* pointer into queue */ + SK_U32 Class; + int Rtv; + + pEv = pAC->Event.EvGet; + + PRINTF("dispatch get %x put %x\n", pEv, pAC->Event.ev_put); + + while (pEv != pAC->Event.EvPut) { + PRINTF("dispatch Class %d Event %d\n", pEv->Class, pEv->Event); + + switch (Class = pEv->Class) { +#ifndef SK_USE_LAC_EV +#ifndef SK_SLIM + case SKGE_RLMT: /* RLMT Event */ + Rtv = SkRlmtEvent(pAC, Ioc, pEv->Event, pEv->Para); + break; + case SKGE_I2C: /* I2C Event */ + Rtv = SkI2cEvent(pAC, Ioc, pEv->Event, pEv->Para); + break; + case SKGE_PNMI: /* PNMI Event */ + Rtv = SkPnmiEvent(pAC, Ioc, pEv->Event, pEv->Para); + break; +#endif /* not SK_SLIM */ +#endif /* not SK_USE_LAC_EV */ + case SKGE_DRV: /* Driver Event */ + Rtv = SkDrvEvent(pAC, Ioc, pEv->Event, pEv->Para); + break; +#ifndef SK_USE_SW_TIMER + case SKGE_HWAC: + Rtv = SkGeSirqEvent(pAC, Ioc, pEv->Event, pEv->Para); + break; +#else /* !SK_USE_SW_TIMER */ + case SKGE_SWT : + Rtv = SkSwtEvent(pAC, Ioc, pEv->Event, pEv->Para); + break; +#endif /* !SK_USE_SW_TIMER */ +#ifdef SK_USE_LAC_EV + case SKGE_LACP : + Rtv = SkLacpEvent(pAC, Ioc, pEv->Event, pEv->Para); + break; + case SKGE_RSF : + Rtv = SkRsfEvent(pAC, Ioc, pEv->Event, pEv->Para); + break; + case SKGE_MARKER : + Rtv = SkMarkerEvent(pAC, Ioc, pEv->Event, pEv->Para); + break; + case SKGE_FD : + Rtv = SkFdEvent(pAC, Ioc, pEv->Event, pEv->Para); + break; +#endif /* SK_USE_LAC_EV */ +#ifdef SK_USE_CSUM + case SKGE_CSUM : + Rtv = SkCsEvent(pAC, Ioc, pEv->Event, pEv->Para); + break; +#endif /* SK_USE_CSUM */ + default : + SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_Q_E002, SKERR_Q_E002MSG); + Rtv = 0; + } + + if (Rtv != 0) { + return(Rtv); + } + + if (++pEv == &pAC->Event.EvQueue[SK_MAX_EVENT]) + pEv = pAC->Event.EvQueue; + + /* Renew get: it is used in queue_events to detect overruns */ + pAC->Event.EvGet = pEv; + } + + return(0); +} + +/* End of file */ diff --git a/drivers/net/sk98lin/skrlmt.c b/drivers/net/sk98lin/skrlmt.c new file mode 100644 index 000000000000..be8d1ccddf6d --- /dev/null +++ b/drivers/net/sk98lin/skrlmt.c @@ -0,0 +1,3257 @@ +/****************************************************************************** + * + * Name: skrlmt.c + * Project: GEnesis, PCI Gigabit Ethernet Adapter + * Version: $Revision: 1.69 $ + * Date: $Date: 2003/04/15 09:39:22 $ + * Purpose: Manage links on SK-NET Adapters, esp. redundant ones. + * + ******************************************************************************/ + +/****************************************************************************** + * + * (C)Copyright 1998-2002 SysKonnect GmbH. + * (C)Copyright 2002-2003 Marvell. + * + * 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. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/****************************************************************************** + * + * Description: + * + * This module contains code for Link ManagemenT (LMT) of SK-NET Adapters. + * It is mainly intended for adapters with more than one link. + * For such adapters, this module realizes Redundant Link ManagemenT (RLMT). + * + * Include File Hierarchy: + * + * "skdrv1st.h" + * "skdrv2nd.h" + * + ******************************************************************************/ + +#ifndef lint +static const char SysKonnectFileId[] = + "@(#) $Id: skrlmt.c,v 1.69 2003/04/15 09:39:22 tschilli Exp $ (C) Marvell."; +#endif /* !defined(lint) */ + +#define __SKRLMT_C + +#ifdef __cplusplus +extern "C" { +#endif /* cplusplus */ + +#include "h/skdrv1st.h" +#include "h/skdrv2nd.h" + +/* defines ********************************************************************/ + +#ifndef SK_HWAC_LINK_LED +#define SK_HWAC_LINK_LED(a,b,c,d) +#endif /* !defined(SK_HWAC_LINK_LED) */ + +#ifndef DEBUG +#define RLMT_STATIC static +#else /* DEBUG */ +#define RLMT_STATIC + +#ifndef SK_LITTLE_ENDIAN +/* First 32 bits */ +#define OFFS_LO32 1 + +/* Second 32 bits */ +#define OFFS_HI32 0 +#else /* SK_LITTLE_ENDIAN */ +/* First 32 bits */ +#define OFFS_LO32 0 + +/* Second 32 bits */ +#define OFFS_HI32 1 +#endif /* SK_LITTLE_ENDIAN */ + +#endif /* DEBUG */ + +/* ----- Private timeout values ----- */ + +#define SK_RLMT_MIN_TO_VAL 125000 /* 1/8 sec. */ +#define SK_RLMT_DEF_TO_VAL 1000000 /* 1 sec. */ +#define SK_RLMT_PORTDOWN_TIM_VAL 900000 /* another 0.9 sec. */ +#define SK_RLMT_PORTSTART_TIM_VAL 100000 /* 0.1 sec. */ +#define SK_RLMT_PORTUP_TIM_VAL 2500000 /* 2.5 sec. */ +#define SK_RLMT_SEG_TO_VAL 900000000 /* 15 min. */ + +/* Assume tick counter increment is 1 - may be set OS-dependent. */ +#ifndef SK_TICK_INCR +#define SK_TICK_INCR SK_CONSTU64(1) +#endif /* !defined(SK_TICK_INCR) */ + +/* + * Amount that a time stamp must be later to be recognized as "substantially + * later". This is about 1/128 sec, but above 1 tick counter increment. + */ +#define SK_RLMT_BC_DELTA (1 + ((SK_TICKS_PER_SEC >> 7) > SK_TICK_INCR ? \ + (SK_TICKS_PER_SEC >> 7) : SK_TICK_INCR)) + +/* ----- Private RLMT defaults ----- */ + +#define SK_RLMT_DEF_PREF_PORT 0 /* "Lower" port. */ +#define SK_RLMT_DEF_MODE SK_RLMT_CHECK_LINK /* Default RLMT Mode. */ + +/* ----- Private RLMT checking states ----- */ + +#define SK_RLMT_RCS_SEG 1 /* RLMT Check State: check seg. */ +#define SK_RLMT_RCS_START_SEG 2 /* RLMT Check State: start check seg. */ +#define SK_RLMT_RCS_SEND_SEG 4 /* RLMT Check State: send BPDU packet */ +#define SK_RLMT_RCS_REPORT_SEG 8 /* RLMT Check State: report seg. */ + +/* ----- Private PORT checking states ----- */ + +#define SK_RLMT_PCS_TX 1 /* Port Check State: check tx. */ +#define SK_RLMT_PCS_RX 2 /* Port Check State: check rx. */ + +/* ----- Private PORT events ----- */ + +/* Note: Update simulation when changing these. */ +#define SK_RLMT_PORTSTART_TIM 1100 /* Port start timeout. */ +#define SK_RLMT_PORTUP_TIM 1101 /* Port can now go up. */ +#define SK_RLMT_PORTDOWN_RX_TIM 1102 /* Port did not receive once ... */ +#define SK_RLMT_PORTDOWN 1103 /* Port went down. */ +#define SK_RLMT_PORTDOWN_TX_TIM 1104 /* Partner did not receive ... */ + +/* ----- Private RLMT events ----- */ + +/* Note: Update simulation when changing these. */ +#define SK_RLMT_TIM 2100 /* RLMT timeout. */ +#define SK_RLMT_SEG_TIM 2101 /* RLMT segmentation check timeout. */ + +#define TO_SHORTEN(tim) ((tim) / 2) + +/* Error numbers and messages. */ +#define SKERR_RLMT_E001 (SK_ERRBASE_RLMT + 0) +#define SKERR_RLMT_E001_MSG "No Packet." +#define SKERR_RLMT_E002 (SKERR_RLMT_E001 + 1) +#define SKERR_RLMT_E002_MSG "Short Packet." +#define SKERR_RLMT_E003 (SKERR_RLMT_E002 + 1) +#define SKERR_RLMT_E003_MSG "Unknown RLMT event." +#define SKERR_RLMT_E004 (SKERR_RLMT_E003 + 1) +#define SKERR_RLMT_E004_MSG "PortsUp incorrect." +#define SKERR_RLMT_E005 (SKERR_RLMT_E004 + 1) +#define SKERR_RLMT_E005_MSG \ + "Net seems to be segmented (different root bridges are reported on the ports)." +#define SKERR_RLMT_E006 (SKERR_RLMT_E005 + 1) +#define SKERR_RLMT_E006_MSG "Duplicate MAC Address detected." +#define SKERR_RLMT_E007 (SKERR_RLMT_E006 + 1) +#define SKERR_RLMT_E007_MSG "LinksUp incorrect." +#define SKERR_RLMT_E008 (SKERR_RLMT_E007 + 1) +#define SKERR_RLMT_E008_MSG "Port not started but link came up." +#define SKERR_RLMT_E009 (SKERR_RLMT_E008 + 1) +#define SKERR_RLMT_E009_MSG "Corrected illegal setting of Preferred Port." +#define SKERR_RLMT_E010 (SKERR_RLMT_E009 + 1) +#define SKERR_RLMT_E010_MSG "Ignored illegal Preferred Port." + +/* LLC field values. */ +#define LLC_COMMAND_RESPONSE_BIT 1 +#define LLC_TEST_COMMAND 0xE3 +#define LLC_UI 0x03 + +/* RLMT Packet fields. */ +#define SK_RLMT_DSAP 0 +#define SK_RLMT_SSAP 0 +#define SK_RLMT_CTRL (LLC_TEST_COMMAND) +#define SK_RLMT_INDICATOR0 0x53 /* S */ +#define SK_RLMT_INDICATOR1 0x4B /* K */ +#define SK_RLMT_INDICATOR2 0x2D /* - */ +#define SK_RLMT_INDICATOR3 0x52 /* R */ +#define SK_RLMT_INDICATOR4 0x4C /* L */ +#define SK_RLMT_INDICATOR5 0x4D /* M */ +#define SK_RLMT_INDICATOR6 0x54 /* T */ +#define SK_RLMT_PACKET_VERSION 0 + +/* RLMT SPT Flag values. */ +#define SK_RLMT_SPT_FLAG_CHANGE 0x01 +#define SK_RLMT_SPT_FLAG_CHANGE_ACK 0x80 + +/* RLMT SPT Packet fields. */ +#define SK_RLMT_SPT_DSAP 0x42 +#define SK_RLMT_SPT_SSAP 0x42 +#define SK_RLMT_SPT_CTRL (LLC_UI) +#define SK_RLMT_SPT_PROTOCOL_ID0 0x00 +#define SK_RLMT_SPT_PROTOCOL_ID1 0x00 +#define SK_RLMT_SPT_PROTOCOL_VERSION_ID 0x00 +#define SK_RLMT_SPT_BPDU_TYPE 0x00 +#define SK_RLMT_SPT_FLAGS 0x00 /* ?? */ +#define SK_RLMT_SPT_ROOT_ID0 0xFF /* Lowest possible priority. */ +#define SK_RLMT_SPT_ROOT_ID1 0xFF /* Lowest possible priority. */ + +/* Remaining 6 bytes will be the current port address. */ +#define SK_RLMT_SPT_ROOT_PATH_COST0 0x00 +#define SK_RLMT_SPT_ROOT_PATH_COST1 0x00 +#define SK_RLMT_SPT_ROOT_PATH_COST2 0x00 +#define SK_RLMT_SPT_ROOT_PATH_COST3 0x00 +#define SK_RLMT_SPT_BRIDGE_ID0 0xFF /* Lowest possible priority. */ +#define SK_RLMT_SPT_BRIDGE_ID1 0xFF /* Lowest possible priority. */ + +/* Remaining 6 bytes will be the current port address. */ +#define SK_RLMT_SPT_PORT_ID0 0xFF /* Lowest possible priority. */ +#define SK_RLMT_SPT_PORT_ID1 0xFF /* Lowest possible priority. */ +#define SK_RLMT_SPT_MSG_AGE0 0x00 +#define SK_RLMT_SPT_MSG_AGE1 0x00 +#define SK_RLMT_SPT_MAX_AGE0 0x00 +#define SK_RLMT_SPT_MAX_AGE1 0xFF +#define SK_RLMT_SPT_HELLO_TIME0 0x00 +#define SK_RLMT_SPT_HELLO_TIME1 0xFF +#define SK_RLMT_SPT_FWD_DELAY0 0x00 +#define SK_RLMT_SPT_FWD_DELAY1 0x40 + +/* Size defines. */ +#define SK_RLMT_MIN_PACKET_SIZE 34 +#define SK_RLMT_MAX_PACKET_SIZE (SK_RLMT_MAX_TX_BUF_SIZE) +#define SK_PACKET_DATA_LEN (SK_RLMT_MAX_PACKET_SIZE - \ + SK_RLMT_MIN_PACKET_SIZE) + +/* ----- RLMT packet types ----- */ +#define SK_PACKET_ANNOUNCE 1 /* Port announcement. */ +#define SK_PACKET_ALIVE 2 /* Alive packet to port. */ +#define SK_PACKET_ADDR_CHANGED 3 /* Port address changed. */ +#define SK_PACKET_CHECK_TX 4 /* Check your tx line. */ + +#ifdef SK_LITTLE_ENDIAN +#define SK_U16_TO_NETWORK_ORDER(Val,Addr) { \ + SK_U8 *_Addr = (SK_U8*)(Addr); \ + SK_U16 _Val = (SK_U16)(Val); \ + *_Addr++ = (SK_U8)(_Val >> 8); \ + *_Addr = (SK_U8)(_Val & 0xFF); \ +} +#endif /* SK_LITTLE_ENDIAN */ + +#ifdef SK_BIG_ENDIAN +#define SK_U16_TO_NETWORK_ORDER(Val,Addr) (*(SK_U16*)(Addr) = (SK_U16)(Val)) +#endif /* SK_BIG_ENDIAN */ + +#define AUTONEG_FAILED SK_FALSE +#define AUTONEG_SUCCESS SK_TRUE + + +/* typedefs *******************************************************************/ + +/* RLMT packet. Length: SK_RLMT_MAX_PACKET_SIZE (60) bytes. */ +typedef struct s_RlmtPacket { + SK_U8 DstAddr[SK_MAC_ADDR_LEN]; + SK_U8 SrcAddr[SK_MAC_ADDR_LEN]; + SK_U8 TypeLen[2]; + SK_U8 DSap; + SK_U8 SSap; + SK_U8 Ctrl; + SK_U8 Indicator[7]; + SK_U8 RlmtPacketType[2]; + SK_U8 Align1[2]; + SK_U8 Random[4]; /* Random value of requesting(!) station. */ + SK_U8 RlmtPacketVersion[2]; /* RLMT Packet version. */ + SK_U8 Data[SK_PACKET_DATA_LEN]; +} SK_RLMT_PACKET; + +typedef struct s_SpTreeRlmtPacket { + SK_U8 DstAddr[SK_MAC_ADDR_LEN]; + SK_U8 SrcAddr[SK_MAC_ADDR_LEN]; + SK_U8 TypeLen[2]; + SK_U8 DSap; + SK_U8 SSap; + SK_U8 Ctrl; + SK_U8 ProtocolId[2]; + SK_U8 ProtocolVersionId; + SK_U8 BpduType; + SK_U8 Flags; + SK_U8 RootId[8]; + SK_U8 RootPathCost[4]; + SK_U8 BridgeId[8]; + SK_U8 PortId[2]; + SK_U8 MessageAge[2]; + SK_U8 MaxAge[2]; + SK_U8 HelloTime[2]; + SK_U8 ForwardDelay[2]; +} SK_SPTREE_PACKET; + +/* global variables ***********************************************************/ + +SK_MAC_ADDR SkRlmtMcAddr = {{0x01, 0x00, 0x5A, 0x52, 0x4C, 0x4D}}; +SK_MAC_ADDR BridgeMcAddr = {{0x01, 0x80, 0xC2, 0x00, 0x00, 0x00}}; + +/* local variables ************************************************************/ + +/* None. */ + +/* functions ******************************************************************/ + +RLMT_STATIC void SkRlmtCheckSwitch( + SK_AC *pAC, + SK_IOC IoC, + SK_U32 NetIdx); +RLMT_STATIC void SkRlmtCheckSeg( + SK_AC *pAC, + SK_IOC IoC, + SK_U32 NetIdx); +RLMT_STATIC void SkRlmtEvtSetNets( + SK_AC *pAC, + SK_IOC IoC, + SK_EVPARA Para); + +/****************************************************************************** + * + * SkRlmtInit - initialize data, set state to init + * + * Description: + * + * SK_INIT_DATA + * ============ + * + * This routine initializes all RLMT-related variables to a known state. + * The initial state is SK_RLMT_RS_INIT. + * All ports are initialized to SK_RLMT_PS_INIT. + * + * + * SK_INIT_IO + * ========== + * + * Nothing. + * + * + * SK_INIT_RUN + * =========== + * + * Determine the adapter's random value. + * Set the hw registers, the "logical MAC address", the + * RLMT multicast address, and eventually the BPDU multicast address. + * + * Context: + * init, pageable + * + * Returns: + * Nothing. + */ +void SkRlmtInit( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +int Level) /* Initialization Level */ +{ + SK_U32 i, j; + SK_U64 Random; + SK_EVPARA Para; + SK_MAC_ADDR VirtualMacAddress; + SK_MAC_ADDR PhysicalAMacAddress; + SK_BOOL VirtualMacAddressSet; + SK_BOOL PhysicalAMacAddressSet; + + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_INIT, + ("RLMT Init level %d.\n", Level)) + + switch (Level) { + case SK_INIT_DATA: /* Initialize data structures. */ + SK_MEMSET((char *)&pAC->Rlmt, 0, sizeof(SK_RLMT)); + + for (i = 0; i < SK_MAX_MACS; i++) { + pAC->Rlmt.Port[i].PortState = SK_RLMT_PS_INIT; + pAC->Rlmt.Port[i].LinkDown = SK_TRUE; + pAC->Rlmt.Port[i].PortDown = SK_TRUE; + pAC->Rlmt.Port[i].PortStarted = SK_FALSE; + pAC->Rlmt.Port[i].PortNoRx = SK_FALSE; + pAC->Rlmt.Port[i].RootIdSet = SK_FALSE; + pAC->Rlmt.Port[i].PortNumber = i; + pAC->Rlmt.Port[i].Net = &pAC->Rlmt.Net[0]; + pAC->Rlmt.Port[i].AddrPort = &pAC->Addr.Port[i]; + } + + pAC->Rlmt.NumNets = 1; + for (i = 0; i < SK_MAX_NETS; i++) { + pAC->Rlmt.Net[i].RlmtState = SK_RLMT_RS_INIT; + pAC->Rlmt.Net[i].RootIdSet = SK_FALSE; + pAC->Rlmt.Net[i].PrefPort = SK_RLMT_DEF_PREF_PORT; + pAC->Rlmt.Net[i].Preference = 0xFFFFFFFF; /* Automatic. */ + /* Just assuming. */ + pAC->Rlmt.Net[i].ActivePort = pAC->Rlmt.Net[i].PrefPort; + pAC->Rlmt.Net[i].RlmtMode = SK_RLMT_DEF_MODE; + pAC->Rlmt.Net[i].TimeoutValue = SK_RLMT_DEF_TO_VAL; + pAC->Rlmt.Net[i].NetNumber = i; + } + + pAC->Rlmt.Net[0].Port[0] = &pAC->Rlmt.Port[0]; + pAC->Rlmt.Net[0].Port[1] = &pAC->Rlmt.Port[1]; +#if SK_MAX_NETS > 1 + pAC->Rlmt.Net[1].Port[0] = &pAC->Rlmt.Port[1]; +#endif /* SK_MAX_NETS > 1 */ + break; + + case SK_INIT_IO: /* GIMacsFound first available here. */ + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_INIT, + ("RLMT: %d MACs were detected.\n", pAC->GIni.GIMacsFound)) + + pAC->Rlmt.Net[0].NumPorts = pAC->GIni.GIMacsFound; + + /* Initialize HW registers? */ + if (pAC->GIni.GIMacsFound == 1) { + Para.Para32[0] = SK_RLMT_MODE_CLS; + Para.Para32[1] = 0; + (void)SkRlmtEvent(pAC, IoC, SK_RLMT_MODE_CHANGE, Para); + } + break; + + case SK_INIT_RUN: + /* Ensure RLMT is set to one net. */ + if (pAC->Rlmt.NumNets > 1) { + Para.Para32[0] = 1; + Para.Para32[1] = -1; + SkRlmtEvtSetNets(pAC, IoC, Para); + } + + for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) { + Random = SkOsGetTime(pAC); + *(SK_U32*)&pAC->Rlmt.Port[i].Random = *(SK_U32*)&Random; + + for (j = 0; j < 4; j++) { + pAC->Rlmt.Port[i].Random[j] ^= pAC->Rlmt.Port[i].AddrPort-> + CurrentMacAddress.a[SK_MAC_ADDR_LEN - 1 - j]; + } + + (void)SkAddrMcClear(pAC, IoC, i, SK_ADDR_PERMANENT | SK_MC_SW_ONLY); + + /* Add RLMT MC address. */ + (void)SkAddrMcAdd(pAC, IoC, i, &SkRlmtMcAddr, SK_ADDR_PERMANENT); + + if (pAC->Rlmt.Net[0].RlmtMode & SK_RLMT_CHECK_SEG) { + /* Add BPDU MC address. */ + (void)SkAddrMcAdd(pAC, IoC, i, &BridgeMcAddr, SK_ADDR_PERMANENT); + } + + (void)SkAddrMcUpdate(pAC, IoC, i); + } + + VirtualMacAddressSet = SK_FALSE; + /* Read virtual MAC address from Control Register File. */ + for (j = 0; j < SK_MAC_ADDR_LEN; j++) { + + SK_IN8(IoC, B2_MAC_1 + j, &VirtualMacAddress.a[j]); + VirtualMacAddressSet |= VirtualMacAddress.a[j]; + } + + PhysicalAMacAddressSet = SK_FALSE; + /* Read physical MAC address for MAC A from Control Register File. */ + for (j = 0; j < SK_MAC_ADDR_LEN; j++) { + + SK_IN8(IoC, B2_MAC_2 + j, &PhysicalAMacAddress.a[j]); + PhysicalAMacAddressSet |= PhysicalAMacAddress.a[j]; + } + + /* check if the two mac addresses contain reasonable values */ + if (!VirtualMacAddressSet || !PhysicalAMacAddressSet) { + + pAC->Rlmt.RlmtOff = SK_TRUE; + } + + /* if the two mac addresses are equal switch off the RLMT_PRE_LOOKAHEAD + and the RLMT_LOOKAHEAD macros */ + else if (SK_ADDR_EQUAL(PhysicalAMacAddress.a, VirtualMacAddress.a)) { + + pAC->Rlmt.RlmtOff = SK_TRUE; + } + else { + pAC->Rlmt.RlmtOff = SK_FALSE; + } + break; + + default: /* error */ + break; + } + return; +} /* SkRlmtInit */ + + +/****************************************************************************** + * + * SkRlmtBuildCheckChain - build the check chain + * + * Description: + * This routine builds the local check chain: + * - Each port that is up checks the next port. + * - The last port that is up checks the first port that is up. + * + * Notes: + * - Currently only local ports are considered when building the chain. + * - Currently the SuspectState is just reset; + * it would be better to save it ... + * + * Context: + * runtime, pageable? + * + * Returns: + * Nothing + */ +RLMT_STATIC void SkRlmtBuildCheckChain( +SK_AC *pAC, /* Adapter Context */ +SK_U32 NetIdx) /* Net Number */ +{ + SK_U32 i; + SK_U32 NumMacsUp; + SK_RLMT_PORT * FirstMacUp; + SK_RLMT_PORT * PrevMacUp; + + FirstMacUp = NULL; + PrevMacUp = NULL; + + if (!(pAC->Rlmt.Net[NetIdx].RlmtMode & SK_RLMT_CHECK_LOC_LINK)) { + for (i = 0; i < pAC->Rlmt.Net[i].NumPorts; i++) { + pAC->Rlmt.Net[NetIdx].Port[i]->PortsChecked = 0; + } + return; /* Done. */ + } + + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SkRlmtBuildCheckChain.\n")) + + NumMacsUp = 0; + + for (i = 0; i < pAC->Rlmt.Net[NetIdx].NumPorts; i++) { + pAC->Rlmt.Net[NetIdx].Port[i]->PortsChecked = 0; + pAC->Rlmt.Net[NetIdx].Port[i]->PortsSuspect = 0; + pAC->Rlmt.Net[NetIdx].Port[i]->CheckingState &= + ~(SK_RLMT_PCS_RX | SK_RLMT_PCS_TX); + + /* + * If more than two links are detected we should consider + * checking at least two other ports: + * 1. the next port that is not LinkDown and + * 2. the next port that is not PortDown. + */ + if (!pAC->Rlmt.Net[NetIdx].Port[i]->LinkDown) { + if (NumMacsUp == 0) { + FirstMacUp = pAC->Rlmt.Net[NetIdx].Port[i]; + } + else { + PrevMacUp->PortCheck[ + pAC->Rlmt.Net[NetIdx].Port[i]->PortsChecked].CheckAddr = + pAC->Rlmt.Net[NetIdx].Port[i]->AddrPort->CurrentMacAddress; + PrevMacUp->PortCheck[ + PrevMacUp->PortsChecked].SuspectTx = SK_FALSE; + PrevMacUp->PortsChecked++; + } + PrevMacUp = pAC->Rlmt.Net[NetIdx].Port[i]; + NumMacsUp++; + } + } + + if (NumMacsUp > 1) { + PrevMacUp->PortCheck[PrevMacUp->PortsChecked].CheckAddr = + FirstMacUp->AddrPort->CurrentMacAddress; + PrevMacUp->PortCheck[PrevMacUp->PortsChecked].SuspectTx = + SK_FALSE; + PrevMacUp->PortsChecked++; + } + +#ifdef DEBUG + for (i = 0; i < pAC->Rlmt.Net[NetIdx].NumPorts; i++) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("Port %d checks %d other ports: %2X.\n", i, + pAC->Rlmt.Net[NetIdx].Port[i]->PortsChecked, + pAC->Rlmt.Net[NetIdx].Port[i]->PortCheck[0].CheckAddr.a[5])) + } +#endif /* DEBUG */ + + return; +} /* SkRlmtBuildCheckChain */ + + +/****************************************************************************** + * + * SkRlmtBuildPacket - build an RLMT packet + * + * Description: + * This routine sets up an RLMT packet. + * + * Context: + * runtime, pageable? + * + * Returns: + * NULL or pointer to RLMT mbuf + */ +RLMT_STATIC SK_MBUF *SkRlmtBuildPacket( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_U32 PortNumber, /* Sending port */ +SK_U16 PacketType, /* RLMT packet type */ +SK_MAC_ADDR *SrcAddr, /* Source address */ +SK_MAC_ADDR *DestAddr) /* Destination address */ +{ + int i; + SK_U16 Length; + SK_MBUF *pMb; + SK_RLMT_PACKET *pPacket; + +#ifdef DEBUG + SK_U8 CheckSrc = 0; + SK_U8 CheckDest = 0; + + for (i = 0; i < SK_MAC_ADDR_LEN; ++i) { + CheckSrc |= SrcAddr->a[i]; + CheckDest |= DestAddr->a[i]; + } + + if ((CheckSrc == 0) || (CheckDest == 0)) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_ERR, + ("SkRlmtBuildPacket: Invalid %s%saddr.\n", + (CheckSrc == 0 ? "Src" : ""), (CheckDest == 0 ? "Dest" : ""))) + } +#endif + + if ((pMb = SkDrvAllocRlmtMbuf(pAC, IoC, SK_RLMT_MAX_PACKET_SIZE)) != NULL) { + pPacket = (SK_RLMT_PACKET*)pMb->pData; + for (i = 0; i < SK_MAC_ADDR_LEN; i++) { + pPacket->DstAddr[i] = DestAddr->a[i]; + pPacket->SrcAddr[i] = SrcAddr->a[i]; + } + pPacket->DSap = SK_RLMT_DSAP; + pPacket->SSap = SK_RLMT_SSAP; + pPacket->Ctrl = SK_RLMT_CTRL; + pPacket->Indicator[0] = SK_RLMT_INDICATOR0; + pPacket->Indicator[1] = SK_RLMT_INDICATOR1; + pPacket->Indicator[2] = SK_RLMT_INDICATOR2; + pPacket->Indicator[3] = SK_RLMT_INDICATOR3; + pPacket->Indicator[4] = SK_RLMT_INDICATOR4; + pPacket->Indicator[5] = SK_RLMT_INDICATOR5; + pPacket->Indicator[6] = SK_RLMT_INDICATOR6; + + SK_U16_TO_NETWORK_ORDER(PacketType, &pPacket->RlmtPacketType[0]); + + for (i = 0; i < 4; i++) { + pPacket->Random[i] = pAC->Rlmt.Port[PortNumber].Random[i]; + } + + SK_U16_TO_NETWORK_ORDER( + SK_RLMT_PACKET_VERSION, &pPacket->RlmtPacketVersion[0]); + + for (i = 0; i < SK_PACKET_DATA_LEN; i++) { + pPacket->Data[i] = 0x00; + } + + Length = SK_RLMT_MAX_PACKET_SIZE; /* Or smaller. */ + pMb->Length = Length; + pMb->PortIdx = PortNumber; + Length -= 14; + SK_U16_TO_NETWORK_ORDER(Length, &pPacket->TypeLen[0]); + + if (PacketType == SK_PACKET_ALIVE) { + pAC->Rlmt.Port[PortNumber].TxHelloCts++; + } + } + + return (pMb); +} /* SkRlmtBuildPacket */ + + +/****************************************************************************** + * + * SkRlmtBuildSpanningTreePacket - build spanning tree check packet + * + * Description: + * This routine sets up a BPDU packet for spanning tree check. + * + * Context: + * runtime, pageable? + * + * Returns: + * NULL or pointer to RLMT mbuf + */ +RLMT_STATIC SK_MBUF *SkRlmtBuildSpanningTreePacket( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_U32 PortNumber) /* Sending port */ +{ + unsigned i; + SK_U16 Length; + SK_MBUF *pMb; + SK_SPTREE_PACKET *pSPacket; + + if ((pMb = SkDrvAllocRlmtMbuf(pAC, IoC, SK_RLMT_MAX_PACKET_SIZE)) != + NULL) { + pSPacket = (SK_SPTREE_PACKET*)pMb->pData; + for (i = 0; i < SK_MAC_ADDR_LEN; i++) { + pSPacket->DstAddr[i] = BridgeMcAddr.a[i]; + pSPacket->SrcAddr[i] = + pAC->Addr.Port[PortNumber].CurrentMacAddress.a[i]; + } + pSPacket->DSap = SK_RLMT_SPT_DSAP; + pSPacket->SSap = SK_RLMT_SPT_SSAP; + pSPacket->Ctrl = SK_RLMT_SPT_CTRL; + + pSPacket->ProtocolId[0] = SK_RLMT_SPT_PROTOCOL_ID0; + pSPacket->ProtocolId[1] = SK_RLMT_SPT_PROTOCOL_ID1; + pSPacket->ProtocolVersionId = SK_RLMT_SPT_PROTOCOL_VERSION_ID; + pSPacket->BpduType = SK_RLMT_SPT_BPDU_TYPE; + pSPacket->Flags = SK_RLMT_SPT_FLAGS; + pSPacket->RootId[0] = SK_RLMT_SPT_ROOT_ID0; + pSPacket->RootId[1] = SK_RLMT_SPT_ROOT_ID1; + pSPacket->RootPathCost[0] = SK_RLMT_SPT_ROOT_PATH_COST0; + pSPacket->RootPathCost[1] = SK_RLMT_SPT_ROOT_PATH_COST1; + pSPacket->RootPathCost[2] = SK_RLMT_SPT_ROOT_PATH_COST2; + pSPacket->RootPathCost[3] = SK_RLMT_SPT_ROOT_PATH_COST3; + pSPacket->BridgeId[0] = SK_RLMT_SPT_BRIDGE_ID0; + pSPacket->BridgeId[1] = SK_RLMT_SPT_BRIDGE_ID1; + + /* + * Use logical MAC address as bridge ID and filter these packets + * on receive. + */ + for (i = 0; i < SK_MAC_ADDR_LEN; i++) { + pSPacket->BridgeId[i + 2] = pSPacket->RootId[i + 2] = + pAC->Addr.Net[pAC->Rlmt.Port[PortNumber].Net->NetNumber]. + CurrentMacAddress.a[i]; + } + pSPacket->PortId[0] = SK_RLMT_SPT_PORT_ID0; + pSPacket->PortId[1] = SK_RLMT_SPT_PORT_ID1; + pSPacket->MessageAge[0] = SK_RLMT_SPT_MSG_AGE0; + pSPacket->MessageAge[1] = SK_RLMT_SPT_MSG_AGE1; + pSPacket->MaxAge[0] = SK_RLMT_SPT_MAX_AGE0; + pSPacket->MaxAge[1] = SK_RLMT_SPT_MAX_AGE1; + pSPacket->HelloTime[0] = SK_RLMT_SPT_HELLO_TIME0; + pSPacket->HelloTime[1] = SK_RLMT_SPT_HELLO_TIME1; + pSPacket->ForwardDelay[0] = SK_RLMT_SPT_FWD_DELAY0; + pSPacket->ForwardDelay[1] = SK_RLMT_SPT_FWD_DELAY1; + + Length = SK_RLMT_MAX_PACKET_SIZE; /* Or smaller. */ + pMb->Length = Length; + pMb->PortIdx = PortNumber; + Length -= 14; + SK_U16_TO_NETWORK_ORDER(Length, &pSPacket->TypeLen[0]); + + pAC->Rlmt.Port[PortNumber].TxSpHelloReqCts++; + } + + return (pMb); +} /* SkRlmtBuildSpanningTreePacket */ + + +/****************************************************************************** + * + * SkRlmtSend - build and send check packets + * + * Description: + * Depending on the RLMT state and the checking state, several packets + * are sent through the indicated port. + * + * Context: + * runtime, pageable? + * + * Returns: + * Nothing. + */ +RLMT_STATIC void SkRlmtSend( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_U32 PortNumber) /* Sending port */ +{ + unsigned j; + SK_EVPARA Para; + SK_RLMT_PORT *pRPort; + + pRPort = &pAC->Rlmt.Port[PortNumber]; + if (pAC->Rlmt.Port[PortNumber].Net->RlmtMode & SK_RLMT_CHECK_LOC_LINK) { + if (pRPort->CheckingState & (SK_RLMT_PCS_TX | SK_RLMT_PCS_RX)) { + /* Port is suspicious. Send the RLMT packet to the RLMT mc addr. */ + if ((Para.pParaPtr = SkRlmtBuildPacket(pAC, IoC, PortNumber, + SK_PACKET_ALIVE, &pAC->Addr.Port[PortNumber].CurrentMacAddress, + &SkRlmtMcAddr)) != NULL) { + SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para); + } + } + else { + /* + * Send a directed RLMT packet to all ports that are + * checked by the indicated port. + */ + for (j = 0; j < pRPort->PortsChecked; j++) { + if ((Para.pParaPtr = SkRlmtBuildPacket(pAC, IoC, PortNumber, + SK_PACKET_ALIVE, &pAC->Addr.Port[PortNumber].CurrentMacAddress, + &pRPort->PortCheck[j].CheckAddr)) != NULL) { + SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para); + } + } + } + } + + if ((pAC->Rlmt.Port[PortNumber].Net->RlmtMode & SK_RLMT_CHECK_SEG) && + (pAC->Rlmt.Port[PortNumber].Net->CheckingState & SK_RLMT_RCS_SEND_SEG)) { + /* + * Send a BPDU packet to make a connected switch tell us + * the correct root bridge. + */ + if ((Para.pParaPtr = + SkRlmtBuildSpanningTreePacket(pAC, IoC, PortNumber)) != NULL) { + pAC->Rlmt.Port[PortNumber].Net->CheckingState &= ~SK_RLMT_RCS_SEND_SEG; + pRPort->RootIdSet = SK_FALSE; + + SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para); + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_TX, + ("SkRlmtSend: BPDU Packet on Port %u.\n", PortNumber)) + } + } + return; +} /* SkRlmtSend */ + + +/****************************************************************************** + * + * SkRlmtPortReceives - check if port is (going) down and bring it up + * + * Description: + * This routine checks if a port who received a non-BPDU packet + * needs to go up or needs to be stopped going down. + * + * Context: + * runtime, pageable? + * + * Returns: + * Nothing. + */ +RLMT_STATIC void SkRlmtPortReceives( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_U32 PortNumber) /* Port to check */ +{ + SK_RLMT_PORT *pRPort; + SK_EVPARA Para; + + pRPort = &pAC->Rlmt.Port[PortNumber]; + pRPort->PortNoRx = SK_FALSE; + + if ((pRPort->PortState == SK_RLMT_PS_DOWN) && + !(pRPort->CheckingState & SK_RLMT_PCS_TX)) { + /* + * Port is marked down (rx), but received a non-BPDU packet. + * Bring it up. + */ + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX, + ("SkRlmtPacketReceive: Received on PortDown.\n")) + + pRPort->PortState = SK_RLMT_PS_GOING_UP; + pRPort->GuTimeStamp = SkOsGetTime(pAC); + Para.Para32[0] = PortNumber; + Para.Para32[1] = (SK_U32)-1; + SkTimerStart(pAC, IoC, &pRPort->UpTimer, SK_RLMT_PORTUP_TIM_VAL, + SKGE_RLMT, SK_RLMT_PORTUP_TIM, Para); + pRPort->CheckingState &= ~SK_RLMT_PCS_RX; + /* pAC->Rlmt.CheckSwitch = SK_TRUE; */ + SkRlmtCheckSwitch(pAC, IoC, pRPort->Net->NetNumber); + } /* PortDown && !SuspectTx */ + else if (pRPort->CheckingState & SK_RLMT_PCS_RX) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX, + ("SkRlmtPacketReceive: Stop bringing port down.\n")) + SkTimerStop(pAC, IoC, &pRPort->DownRxTimer); + pRPort->CheckingState &= ~SK_RLMT_PCS_RX; + /* pAC->Rlmt.CheckSwitch = SK_TRUE; */ + SkRlmtCheckSwitch(pAC, IoC, pRPort->Net->NetNumber); + } /* PortGoingDown */ + + return; +} /* SkRlmtPortReceives */ + + +/****************************************************************************** + * + * SkRlmtPacketReceive - receive a packet for closer examination + * + * Description: + * This routine examines a packet more closely than SK_RLMT_LOOKAHEAD. + * + * Context: + * runtime, pageable? + * + * Returns: + * Nothing. + */ +RLMT_STATIC void SkRlmtPacketReceive( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_MBUF *pMb) /* Received packet */ +{ +#ifdef xDEBUG + extern void DumpData(char *p, int size); +#endif /* DEBUG */ + int i; + unsigned j; + SK_U16 PacketType; + SK_U32 PortNumber; + SK_ADDR_PORT *pAPort; + SK_RLMT_PORT *pRPort; + SK_RLMT_PACKET *pRPacket; + SK_SPTREE_PACKET *pSPacket; + SK_EVPARA Para; + + PortNumber = pMb->PortIdx; + pAPort = &pAC->Addr.Port[PortNumber]; + pRPort = &pAC->Rlmt.Port[PortNumber]; + + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX, + ("SkRlmtPacketReceive: PortNumber == %d.\n", PortNumber)) + + pRPacket = (SK_RLMT_PACKET*)pMb->pData; + pSPacket = (SK_SPTREE_PACKET*)pRPacket; + +#ifdef xDEBUG + DumpData((char *)pRPacket, 32); +#endif /* DEBUG */ + + if ((pRPort->PacketsPerTimeSlot - pRPort->BpduPacketsPerTimeSlot) != 0) { + SkRlmtPortReceives(pAC, IoC, PortNumber); + } + + /* Check destination address. */ + + if (!SK_ADDR_EQUAL(pAPort->CurrentMacAddress.a, pRPacket->DstAddr) && + !SK_ADDR_EQUAL(SkRlmtMcAddr.a, pRPacket->DstAddr) && + !SK_ADDR_EQUAL(BridgeMcAddr.a, pRPacket->DstAddr)) { + + /* Not sent to current MAC or registered MC address => Trash it. */ + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX, + ("SkRlmtPacketReceive: Not for me.\n")) + + SkDrvFreeRlmtMbuf(pAC, IoC, pMb); + return; + } + else if (SK_ADDR_EQUAL(pAPort->CurrentMacAddress.a, pRPacket->SrcAddr)) { + + /* + * Was sent by same port (may happen during port switching + * or in case of duplicate MAC addresses). + */ + + /* + * Check for duplicate address here: + * If Packet.Random != My.Random => DupAddr. + */ + for (i = 3; i >= 0; i--) { + if (pRPort->Random[i] != pRPacket->Random[i]) { + break; + } + } + + /* + * CAUTION: Do not check for duplicate MAC address in RLMT Alive Reply + * packets (they have the LLC_COMMAND_RESPONSE_BIT set in + * pRPacket->SSap). + */ + if (i >= 0 && pRPacket->DSap == SK_RLMT_DSAP && + pRPacket->Ctrl == SK_RLMT_CTRL && + pRPacket->SSap == SK_RLMT_SSAP && + pRPacket->Indicator[0] == SK_RLMT_INDICATOR0 && + pRPacket->Indicator[1] == SK_RLMT_INDICATOR1 && + pRPacket->Indicator[2] == SK_RLMT_INDICATOR2 && + pRPacket->Indicator[3] == SK_RLMT_INDICATOR3 && + pRPacket->Indicator[4] == SK_RLMT_INDICATOR4 && + pRPacket->Indicator[5] == SK_RLMT_INDICATOR5 && + pRPacket->Indicator[6] == SK_RLMT_INDICATOR6) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX, + ("SkRlmtPacketReceive: Duplicate MAC Address.\n")) + + /* Error Log entry. */ + SK_ERR_LOG(pAC, SK_ERRCL_COMM, SKERR_RLMT_E006, SKERR_RLMT_E006_MSG); + } + else { + /* Simply trash it. */ + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX, + ("SkRlmtPacketReceive: Sent by me.\n")) + } + + SkDrvFreeRlmtMbuf(pAC, IoC, pMb); + return; + } + + /* Check SuspectTx entries. */ + if (pRPort->PortsSuspect > 0) { + for (j = 0; j < pRPort->PortsChecked; j++) { + if (pRPort->PortCheck[j].SuspectTx && + SK_ADDR_EQUAL( + pRPacket->SrcAddr, pRPort->PortCheck[j].CheckAddr.a)) { + pRPort->PortCheck[j].SuspectTx = SK_FALSE; + pRPort->PortsSuspect--; + break; + } + } + } + + /* Determine type of packet. */ + if (pRPacket->DSap == SK_RLMT_DSAP && + pRPacket->Ctrl == SK_RLMT_CTRL && + (pRPacket->SSap & ~LLC_COMMAND_RESPONSE_BIT) == SK_RLMT_SSAP && + pRPacket->Indicator[0] == SK_RLMT_INDICATOR0 && + pRPacket->Indicator[1] == SK_RLMT_INDICATOR1 && + pRPacket->Indicator[2] == SK_RLMT_INDICATOR2 && + pRPacket->Indicator[3] == SK_RLMT_INDICATOR3 && + pRPacket->Indicator[4] == SK_RLMT_INDICATOR4 && + pRPacket->Indicator[5] == SK_RLMT_INDICATOR5 && + pRPacket->Indicator[6] == SK_RLMT_INDICATOR6) { + + /* It's an RLMT packet. */ + PacketType = (SK_U16)((pRPacket->RlmtPacketType[0] << 8) | + pRPacket->RlmtPacketType[1]); + + switch (PacketType) { + case SK_PACKET_ANNOUNCE: /* Not yet used. */ +#if 0 + /* Build the check chain. */ + SkRlmtBuildCheckChain(pAC); +#endif /* 0 */ + + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX, + ("SkRlmtPacketReceive: Announce.\n")) + + SkDrvFreeRlmtMbuf(pAC, IoC, pMb); + break; + + case SK_PACKET_ALIVE: + if (pRPacket->SSap & LLC_COMMAND_RESPONSE_BIT) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX, + ("SkRlmtPacketReceive: Alive Reply.\n")) + + if (!(pAC->Addr.Port[PortNumber].PromMode & SK_PROM_MODE_LLC) || + SK_ADDR_EQUAL( + pRPacket->DstAddr, pAPort->CurrentMacAddress.a)) { + /* Obviously we could send something. */ + if (pRPort->CheckingState & SK_RLMT_PCS_TX) { + pRPort->CheckingState &= ~SK_RLMT_PCS_TX; + SkTimerStop(pAC, IoC, &pRPort->DownTxTimer); + } + + if ((pRPort->PortState == SK_RLMT_PS_DOWN) && + !(pRPort->CheckingState & SK_RLMT_PCS_RX)) { + pRPort->PortState = SK_RLMT_PS_GOING_UP; + pRPort->GuTimeStamp = SkOsGetTime(pAC); + + SkTimerStop(pAC, IoC, &pRPort->DownTxTimer); + + Para.Para32[0] = PortNumber; + Para.Para32[1] = (SK_U32)-1; + SkTimerStart(pAC, IoC, &pRPort->UpTimer, + SK_RLMT_PORTUP_TIM_VAL, SKGE_RLMT, + SK_RLMT_PORTUP_TIM, Para); + } + } + + /* Mark sending port as alive? */ + SkDrvFreeRlmtMbuf(pAC, IoC, pMb); + } + else { /* Alive Request Packet. */ + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX, + ("SkRlmtPacketReceive: Alive Request.\n")) + + pRPort->RxHelloCts++; + + /* Answer. */ + for (i = 0; i < SK_MAC_ADDR_LEN; i++) { + pRPacket->DstAddr[i] = pRPacket->SrcAddr[i]; + pRPacket->SrcAddr[i] = + pAC->Addr.Port[PortNumber].CurrentMacAddress.a[i]; + } + pRPacket->SSap |= LLC_COMMAND_RESPONSE_BIT; + + Para.pParaPtr = pMb; + SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para); + } + break; + + case SK_PACKET_CHECK_TX: + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX, + ("SkRlmtPacketReceive: Check your tx line.\n")) + + /* A port checking us requests us to check our tx line. */ + pRPort->CheckingState |= SK_RLMT_PCS_TX; + + /* Start PortDownTx timer. */ + Para.Para32[0] = PortNumber; + Para.Para32[1] = (SK_U32)-1; + SkTimerStart(pAC, IoC, &pRPort->DownTxTimer, + SK_RLMT_PORTDOWN_TIM_VAL, SKGE_RLMT, + SK_RLMT_PORTDOWN_TX_TIM, Para); + + SkDrvFreeRlmtMbuf(pAC, IoC, pMb); + + if ((Para.pParaPtr = SkRlmtBuildPacket(pAC, IoC, PortNumber, + SK_PACKET_ALIVE, &pAC->Addr.Port[PortNumber].CurrentMacAddress, + &SkRlmtMcAddr)) != NULL) { + SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para); + } + break; + + case SK_PACKET_ADDR_CHANGED: + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX, + ("SkRlmtPacketReceive: Address Change.\n")) + + /* Build the check chain. */ + SkRlmtBuildCheckChain(pAC, pRPort->Net->NetNumber); + SkDrvFreeRlmtMbuf(pAC, IoC, pMb); + break; + + default: + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX, + ("SkRlmtPacketReceive: Unknown RLMT packet.\n")) + + /* RA;:;: ??? */ + SkDrvFreeRlmtMbuf(pAC, IoC, pMb); + } + } + else if (pSPacket->DSap == SK_RLMT_SPT_DSAP && + pSPacket->Ctrl == SK_RLMT_SPT_CTRL && + (pSPacket->SSap & ~LLC_COMMAND_RESPONSE_BIT) == SK_RLMT_SPT_SSAP) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX, + ("SkRlmtPacketReceive: BPDU Packet.\n")) + + /* Spanning Tree packet. */ + pRPort->RxSpHelloCts++; + + if (!SK_ADDR_EQUAL(&pSPacket->RootId[2], &pAC->Addr.Net[pAC->Rlmt. + Port[PortNumber].Net->NetNumber].CurrentMacAddress.a[0])) { + /* + * Check segmentation if a new root bridge is set and + * the segmentation check is not currently running. + */ + if (!SK_ADDR_EQUAL(&pSPacket->RootId[2], &pRPort->Root.Id[2]) && + (pAC->Rlmt.Port[PortNumber].Net->LinksUp > 1) && + (pAC->Rlmt.Port[PortNumber].Net->RlmtMode & SK_RLMT_CHECK_SEG) + != 0 && (pAC->Rlmt.Port[PortNumber].Net->CheckingState & + SK_RLMT_RCS_SEG) == 0) { + pAC->Rlmt.Port[PortNumber].Net->CheckingState |= + SK_RLMT_RCS_START_SEG | SK_RLMT_RCS_SEND_SEG; + } + + /* Store tree view of this port. */ + for (i = 0; i < 8; i++) { + pRPort->Root.Id[i] = pSPacket->RootId[i]; + } + pRPort->RootIdSet = SK_TRUE; + + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_DUMP, + ("Root ID %d: %02x %02x %02x %02x %02x %02x %02x %02x.\n", + PortNumber, + pRPort->Root.Id[0], pRPort->Root.Id[1], + pRPort->Root.Id[2], pRPort->Root.Id[3], + pRPort->Root.Id[4], pRPort->Root.Id[5], + pRPort->Root.Id[6], pRPort->Root.Id[7])) + } + + SkDrvFreeRlmtMbuf(pAC, IoC, pMb); + if ((pAC->Rlmt.Port[PortNumber].Net->CheckingState & + SK_RLMT_RCS_REPORT_SEG) != 0) { + SkRlmtCheckSeg(pAC, IoC, pAC->Rlmt.Port[PortNumber].Net->NetNumber); + } + } + else { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX, + ("SkRlmtPacketReceive: Unknown Packet Type.\n")) + + /* Unknown packet. */ + SkDrvFreeRlmtMbuf(pAC, IoC, pMb); + } + return; +} /* SkRlmtPacketReceive */ + + +/****************************************************************************** + * + * SkRlmtCheckPort - check if a port works + * + * Description: + * This routine checks if a port whose link is up received something + * and if it seems to transmit successfully. + * + * # PortState: PsInit, PsLinkDown, PsDown, PsGoingUp, PsUp + * # PortCheckingState (Bitfield): ChkTx, ChkRx, ChkSeg + * # RlmtCheckingState (Bitfield): ChkSeg, StartChkSeg, ReportSeg + * + * if (Rx - RxBpdu == 0) { # No rx. + * if (state == PsUp) { + * PortCheckingState |= ChkRx + * } + * if (ModeCheckSeg && (Timeout == + * TO_SHORTEN(RLMT_DEFAULT_TIMEOUT))) { + * RlmtCheckingState |= ChkSeg) + * PortCheckingState |= ChkSeg + * } + * NewTimeout = TO_SHORTEN(Timeout) + * if (NewTimeout < RLMT_MIN_TIMEOUT) { + * NewTimeout = RLMT_MIN_TIMEOUT + * PortState = PsDown + * ... + * } + * } + * else { # something was received + * # Set counter to 0 at LinkDown? + * # No - rx may be reported after LinkDown ??? + * PortCheckingState &= ~ChkRx + * NewTimeout = RLMT_DEFAULT_TIMEOUT + * if (RxAck == 0) { + * possible reasons: + * is my tx line bad? -- + * send RLMT multicast and report + * back internally? (only possible + * between ports on same adapter) + * } + * if (RxChk == 0) { + * possible reasons: + * - tx line of port set to check me + * maybe bad + * - no other port/adapter available or set + * to check me + * - adapter checking me has a longer + * timeout + * ??? anything that can be done here? + * } + * } + * + * Context: + * runtime, pageable? + * + * Returns: + * New timeout value. + */ +RLMT_STATIC SK_U32 SkRlmtCheckPort( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_U32 PortNumber) /* Port to check */ +{ + unsigned i; + SK_U32 NewTimeout; + SK_RLMT_PORT *pRPort; + SK_EVPARA Para; + + pRPort = &pAC->Rlmt.Port[PortNumber]; + + if ((pRPort->PacketsPerTimeSlot - pRPort->BpduPacketsPerTimeSlot) == 0) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SkRlmtCheckPort %d: No (%d) receives in last time slot.\n", + PortNumber, pRPort->PacketsPerTimeSlot)) + + /* + * Check segmentation if there was no receive at least twice + * in a row (PortNoRx is already set) and the segmentation + * check is not currently running. + */ + + if (pRPort->PortNoRx && (pAC->Rlmt.Port[PortNumber].Net->LinksUp > 1) && + (pAC->Rlmt.Port[PortNumber].Net->RlmtMode & SK_RLMT_CHECK_SEG) && + !(pAC->Rlmt.Port[PortNumber].Net->CheckingState & SK_RLMT_RCS_SEG)) { + pAC->Rlmt.Port[PortNumber].Net->CheckingState |= + SK_RLMT_RCS_START_SEG | SK_RLMT_RCS_SEND_SEG; + } + + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SkRlmtCheckPort: PortsSuspect %d, PcsRx %d.\n", + pRPort->PortsSuspect, pRPort->CheckingState & SK_RLMT_PCS_RX)) + + if (pRPort->PortState != SK_RLMT_PS_DOWN) { + NewTimeout = TO_SHORTEN(pAC->Rlmt.Port[PortNumber].Net->TimeoutValue); + if (NewTimeout < SK_RLMT_MIN_TO_VAL) { + NewTimeout = SK_RLMT_MIN_TO_VAL; + } + + if (!(pRPort->CheckingState & SK_RLMT_PCS_RX)) { + Para.Para32[0] = PortNumber; + pRPort->CheckingState |= SK_RLMT_PCS_RX; + + /* + * What shall we do if the port checked by this one receives + * our request frames? What's bad - our rx line or his tx line? + */ + Para.Para32[1] = (SK_U32)-1; + SkTimerStart(pAC, IoC, &pRPort->DownRxTimer, + SK_RLMT_PORTDOWN_TIM_VAL, SKGE_RLMT, + SK_RLMT_PORTDOWN_RX_TIM, Para); + + for (i = 0; i < pRPort->PortsChecked; i++) { + if (pRPort->PortCheck[i].SuspectTx) { + continue; + } + pRPort->PortCheck[i].SuspectTx = SK_TRUE; + pRPort->PortsSuspect++; + if ((Para.pParaPtr = + SkRlmtBuildPacket(pAC, IoC, PortNumber, SK_PACKET_CHECK_TX, + &pAC->Addr.Port[PortNumber].CurrentMacAddress, + &pRPort->PortCheck[i].CheckAddr)) != NULL) { + SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para); + } + } + } + } + else { /* PortDown -- or all partners suspect. */ + NewTimeout = SK_RLMT_DEF_TO_VAL; + } + pRPort->PortNoRx = SK_TRUE; + } + else { /* A non-BPDU packet was received. */ + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SkRlmtCheckPort %d: %d (%d) receives in last time slot.\n", + PortNumber, + pRPort->PacketsPerTimeSlot - pRPort->BpduPacketsPerTimeSlot, + pRPort->PacketsPerTimeSlot)) + + SkRlmtPortReceives(pAC, IoC, PortNumber); + if (pAC->Rlmt.CheckSwitch) { + SkRlmtCheckSwitch(pAC, IoC, pRPort->Net->NetNumber); + } + + NewTimeout = SK_RLMT_DEF_TO_VAL; + } + + return (NewTimeout); +} /* SkRlmtCheckPort */ + + +/****************************************************************************** + * + * SkRlmtSelectBcRx - select new active port, criteria 1 (CLP) + * + * Description: + * This routine selects the port that received a broadcast frame + * substantially later than all other ports. + * + * Context: + * runtime, pageable? + * + * Returns: + * SK_BOOL + */ +RLMT_STATIC SK_BOOL SkRlmtSelectBcRx( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_U32 Active, /* Active port */ +SK_U32 PrefPort, /* Preferred port */ +SK_U32 *pSelect) /* New active port */ +{ + SK_U64 BcTimeStamp; + SK_U32 i; + SK_BOOL PortFound; + + BcTimeStamp = 0; /* Not totally necessary, but feeling better. */ + PortFound = SK_FALSE; + + /* Select port with the latest TimeStamp. */ + for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) { + + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("TimeStamp Port %d (Down: %d, NoRx: %d): %08x %08x.\n", + i, + pAC->Rlmt.Port[i].PortDown, pAC->Rlmt.Port[i].PortNoRx, + *((SK_U32*)(&pAC->Rlmt.Port[i].BcTimeStamp) + OFFS_HI32), + *((SK_U32*)(&pAC->Rlmt.Port[i].BcTimeStamp) + OFFS_LO32))) + + if (!pAC->Rlmt.Port[i].PortDown && !pAC->Rlmt.Port[i].PortNoRx) { + if (!PortFound || pAC->Rlmt.Port[i].BcTimeStamp > BcTimeStamp) { + BcTimeStamp = pAC->Rlmt.Port[i].BcTimeStamp; + *pSelect = i; + PortFound = SK_TRUE; + } + } + } + + if (PortFound) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("Port %d received the last broadcast.\n", *pSelect)) + + /* Look if another port's time stamp is similar. */ + for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) { + if (i == *pSelect) { + continue; + } + if (!pAC->Rlmt.Port[i].PortDown && !pAC->Rlmt.Port[i].PortNoRx && + (pAC->Rlmt.Port[i].BcTimeStamp > + BcTimeStamp - SK_RLMT_BC_DELTA || + pAC->Rlmt.Port[i].BcTimeStamp + + SK_RLMT_BC_DELTA > BcTimeStamp)) { + PortFound = SK_FALSE; + + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("Port %d received a broadcast at a similar time.\n", i)) + break; + } + } + } + +#ifdef DEBUG + if (PortFound) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_SELECT_BCRX found Port %d receiving the substantially " + "latest broadcast (%u).\n", + *pSelect, + BcTimeStamp - pAC->Rlmt.Port[1 - *pSelect].BcTimeStamp)) + } +#endif /* DEBUG */ + + return (PortFound); +} /* SkRlmtSelectBcRx */ + + +/****************************************************************************** + * + * SkRlmtSelectNotSuspect - select new active port, criteria 2 (CLP) + * + * Description: + * This routine selects a good port (it is PortUp && !SuspectRx). + * + * Context: + * runtime, pageable? + * + * Returns: + * SK_BOOL + */ +RLMT_STATIC SK_BOOL SkRlmtSelectNotSuspect( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_U32 Active, /* Active port */ +SK_U32 PrefPort, /* Preferred port */ +SK_U32 *pSelect) /* New active port */ +{ + SK_U32 i; + SK_BOOL PortFound; + + PortFound = SK_FALSE; + + /* Select first port that is PortUp && !SuspectRx. */ + for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) { + if (!pAC->Rlmt.Port[i].PortDown && + !(pAC->Rlmt.Port[i].CheckingState & SK_RLMT_PCS_RX)) { + *pSelect = i; + if (!pAC->Rlmt.Port[Active].PortDown && + !(pAC->Rlmt.Port[Active].CheckingState & SK_RLMT_PCS_RX)) { + *pSelect = Active; + } + if (!pAC->Rlmt.Port[PrefPort].PortDown && + !(pAC->Rlmt.Port[PrefPort].CheckingState & SK_RLMT_PCS_RX)) { + *pSelect = PrefPort; + } + PortFound = SK_TRUE; + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_SELECT_NOTSUSPECT found Port %d up and not check RX.\n", + *pSelect)) + break; + } + } + return (PortFound); +} /* SkRlmtSelectNotSuspect */ + + +/****************************************************************************** + * + * SkRlmtSelectUp - select new active port, criteria 3, 4 (CLP) + * + * Description: + * This routine selects a port that is up. + * + * Context: + * runtime, pageable? + * + * Returns: + * SK_BOOL + */ +RLMT_STATIC SK_BOOL SkRlmtSelectUp( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_U32 Active, /* Active port */ +SK_U32 PrefPort, /* Preferred port */ +SK_U32 *pSelect, /* New active port */ +SK_BOOL AutoNegDone) /* Successfully auto-negotiated? */ +{ + SK_U32 i; + SK_BOOL PortFound; + + PortFound = SK_FALSE; + + /* Select first port that is PortUp. */ + for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) { + if (pAC->Rlmt.Port[i].PortState == SK_RLMT_PS_UP && + pAC->GIni.GP[i].PAutoNegFail != AutoNegDone) { + *pSelect = i; + if (pAC->Rlmt.Port[Active].PortState == SK_RLMT_PS_UP && + pAC->GIni.GP[Active].PAutoNegFail != AutoNegDone) { + *pSelect = Active; + } + if (pAC->Rlmt.Port[PrefPort].PortState == SK_RLMT_PS_UP && + pAC->GIni.GP[PrefPort].PAutoNegFail != AutoNegDone) { + *pSelect = PrefPort; + } + PortFound = SK_TRUE; + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_SELECT_UP found Port %d up.\n", *pSelect)) + break; + } + } + return (PortFound); +} /* SkRlmtSelectUp */ + + +/****************************************************************************** + * + * SkRlmtSelectGoingUp - select new active port, criteria 5, 6 (CLP) + * + * Description: + * This routine selects the port that is going up for the longest time. + * + * Context: + * runtime, pageable? + * + * Returns: + * SK_BOOL + */ +RLMT_STATIC SK_BOOL SkRlmtSelectGoingUp( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_U32 Active, /* Active port */ +SK_U32 PrefPort, /* Preferred port */ +SK_U32 *pSelect, /* New active port */ +SK_BOOL AutoNegDone) /* Successfully auto-negotiated? */ +{ + SK_U64 GuTimeStamp; + SK_U32 i; + SK_BOOL PortFound; + + GuTimeStamp = 0; + PortFound = SK_FALSE; + + /* Select port that is PortGoingUp for the longest time. */ + for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) { + if (pAC->Rlmt.Port[i].PortState == SK_RLMT_PS_GOING_UP && + pAC->GIni.GP[i].PAutoNegFail != AutoNegDone) { + GuTimeStamp = pAC->Rlmt.Port[i].GuTimeStamp; + *pSelect = i; + PortFound = SK_TRUE; + break; + } + } + + if (!PortFound) { + return (SK_FALSE); + } + + for (i = *pSelect + 1; i < (SK_U32)pAC->GIni.GIMacsFound; i++) { + if (pAC->Rlmt.Port[i].PortState == SK_RLMT_PS_GOING_UP && + pAC->Rlmt.Port[i].GuTimeStamp < GuTimeStamp && + pAC->GIni.GP[i].PAutoNegFail != AutoNegDone) { + GuTimeStamp = pAC->Rlmt.Port[i].GuTimeStamp; + *pSelect = i; + } + } + + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_SELECT_GOINGUP found Port %d going up.\n", *pSelect)) + return (SK_TRUE); +} /* SkRlmtSelectGoingUp */ + + +/****************************************************************************** + * + * SkRlmtSelectDown - select new active port, criteria 7, 8 (CLP) + * + * Description: + * This routine selects a port that is down. + * + * Context: + * runtime, pageable? + * + * Returns: + * SK_BOOL + */ +RLMT_STATIC SK_BOOL SkRlmtSelectDown( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_U32 Active, /* Active port */ +SK_U32 PrefPort, /* Preferred port */ +SK_U32 *pSelect, /* New active port */ +SK_BOOL AutoNegDone) /* Successfully auto-negotiated? */ +{ + SK_U32 i; + SK_BOOL PortFound; + + PortFound = SK_FALSE; + + /* Select first port that is PortDown. */ + for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) { + if (pAC->Rlmt.Port[i].PortState == SK_RLMT_PS_DOWN && + pAC->GIni.GP[i].PAutoNegFail != AutoNegDone) { + *pSelect = i; + if (pAC->Rlmt.Port[Active].PortState == SK_RLMT_PS_DOWN && + pAC->GIni.GP[Active].PAutoNegFail != AutoNegDone) { + *pSelect = Active; + } + if (pAC->Rlmt.Port[PrefPort].PortState == SK_RLMT_PS_DOWN && + pAC->GIni.GP[PrefPort].PAutoNegFail != AutoNegDone) { + *pSelect = PrefPort; + } + PortFound = SK_TRUE; + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_SELECT_DOWN found Port %d down.\n", *pSelect)) + break; + } + } + return (PortFound); +} /* SkRlmtSelectDown */ + + +/****************************************************************************** + * + * SkRlmtCheckSwitch - select new active port and switch to it + * + * Description: + * This routine decides which port should be the active one and queues + * port switching if necessary. + * + * Context: + * runtime, pageable? + * + * Returns: + * Nothing. + */ +RLMT_STATIC void SkRlmtCheckSwitch( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_U32 NetIdx) /* Net index */ +{ + SK_EVPARA Para; + SK_U32 Active; + SK_U32 PrefPort; + SK_U32 i; + SK_BOOL PortFound; + + Active = pAC->Rlmt.Net[NetIdx].ActivePort; /* Index of active port. */ + PrefPort = pAC->Rlmt.Net[NetIdx].PrefPort; /* Index of preferred port. */ + PortFound = SK_FALSE; + pAC->Rlmt.CheckSwitch = SK_FALSE; + +#if 0 /* RW 2001/10/18 - active port becomes always prefered one */ + if (pAC->Rlmt.Net[NetIdx].Preference == 0xFFFFFFFF) { /* Automatic */ + /* disable auto-fail back */ + PrefPort = Active; + } +#endif + + if (pAC->Rlmt.Net[NetIdx].LinksUp == 0) { + /* Last link went down - shut down the net. */ + pAC->Rlmt.Net[NetIdx].RlmtState = SK_RLMT_RS_NET_DOWN; + Para.Para32[0] = SK_RLMT_NET_DOWN_TEMP; + Para.Para32[1] = NetIdx; + SkEventQueue(pAC, SKGE_DRV, SK_DRV_NET_DOWN, Para); + + Para.Para32[0] = pAC->Rlmt.Net[NetIdx]. + Port[pAC->Rlmt.Net[NetIdx].ActivePort]->PortNumber; + Para.Para32[1] = NetIdx; + SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_ACTIVE_DOWN, Para); + return; + } /* pAC->Rlmt.LinksUp == 0 */ + else if (pAC->Rlmt.Net[NetIdx].LinksUp == 1 && + pAC->Rlmt.Net[NetIdx].RlmtState == SK_RLMT_RS_NET_DOWN) { + /* First link came up - get the net up. */ + pAC->Rlmt.Net[NetIdx].RlmtState = SK_RLMT_RS_NET_UP; + + /* + * If pAC->Rlmt.ActivePort != Para.Para32[0], + * the DRV switches to the port that came up. + */ + for (i = 0; i < pAC->Rlmt.Net[NetIdx].NumPorts; i++) { + if (!pAC->Rlmt.Net[NetIdx].Port[i]->LinkDown) { + if (!pAC->Rlmt.Net[NetIdx].Port[Active]->LinkDown) { + i = Active; + } + if (!pAC->Rlmt.Net[NetIdx].Port[PrefPort]->LinkDown) { + i = PrefPort; + } + PortFound = SK_TRUE; + break; + } + } + + if (PortFound) { + Para.Para32[0] = pAC->Rlmt.Net[NetIdx].Port[i]->PortNumber; + Para.Para32[1] = NetIdx; + SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_ACTIVE_UP, Para); + + pAC->Rlmt.Net[NetIdx].ActivePort = i; + Para.Para32[0] = pAC->Rlmt.Net[NetIdx].Port[i]->PortNumber; + Para.Para32[1] = NetIdx; + SkEventQueue(pAC, SKGE_DRV, SK_DRV_NET_UP, Para); + + if ((pAC->Rlmt.Net[NetIdx].RlmtMode & SK_RLMT_TRANSPARENT) == 0 && + (Para.pParaPtr = SkRlmtBuildPacket(pAC, IoC, + pAC->Rlmt.Net[NetIdx].Port[i]->PortNumber, + SK_PACKET_ANNOUNCE, &pAC->Addr.Net[NetIdx]. + CurrentMacAddress, &SkRlmtMcAddr)) != NULL) { + /* + * Send announce packet to RLMT multicast address to force + * switches to learn the new location of the logical MAC address. + */ + SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para); + } + } + else { + SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_RLMT_E007, SKERR_RLMT_E007_MSG); + } + + return; + } /* LinksUp == 1 && RlmtState == SK_RLMT_RS_NET_DOWN */ + else { /* Cannot be reached in dual-net mode. */ + Para.Para32[0] = Active; + + /* + * Preselection: + * If RLMT Mode != CheckLinkState + * select port that received a broadcast frame substantially later + * than all other ports + * else select first port that is not SuspectRx + * else select first port that is PortUp + * else select port that is PortGoingUp for the longest time + * else select first port that is PortDown + * else stop. + * + * For the preselected port: + * If ActivePort is equal in quality, select ActivePort. + * + * If PrefPort is equal in quality, select PrefPort. + * + * If ActivePort != SelectedPort, + * If old ActivePort is LinkDown, + * SwitchHard + * else + * SwitchSoft + */ + /* check of ChgBcPrio flag added */ + if ((pAC->Rlmt.Net[0].RlmtMode != SK_RLMT_MODE_CLS) && + (!pAC->Rlmt.Net[0].ChgBcPrio)) { + + if (!PortFound) { + PortFound = SkRlmtSelectBcRx( + pAC, IoC, Active, PrefPort, &Para.Para32[1]); + } + + if (!PortFound) { + PortFound = SkRlmtSelectNotSuspect( + pAC, IoC, Active, PrefPort, &Para.Para32[1]); + } + } /* pAC->Rlmt.RlmtMode != SK_RLMT_MODE_CLS */ + + /* with changed priority for last broadcast received */ + if ((pAC->Rlmt.Net[0].RlmtMode != SK_RLMT_MODE_CLS) && + (pAC->Rlmt.Net[0].ChgBcPrio)) { + if (!PortFound) { + PortFound = SkRlmtSelectNotSuspect( + pAC, IoC, Active, PrefPort, &Para.Para32[1]); + } + + if (!PortFound) { + PortFound = SkRlmtSelectBcRx( + pAC, IoC, Active, PrefPort, &Para.Para32[1]); + } + } /* pAC->Rlmt.RlmtMode != SK_RLMT_MODE_CLS */ + + if (!PortFound) { + PortFound = SkRlmtSelectUp( + pAC, IoC, Active, PrefPort, &Para.Para32[1], AUTONEG_SUCCESS); + } + + if (!PortFound) { + PortFound = SkRlmtSelectUp( + pAC, IoC, Active, PrefPort, &Para.Para32[1], AUTONEG_FAILED); + } + + if (!PortFound) { + PortFound = SkRlmtSelectGoingUp( + pAC, IoC, Active, PrefPort, &Para.Para32[1], AUTONEG_SUCCESS); + } + + if (!PortFound) { + PortFound = SkRlmtSelectGoingUp( + pAC, IoC, Active, PrefPort, &Para.Para32[1], AUTONEG_FAILED); + } + + if (pAC->Rlmt.Net[0].RlmtMode != SK_RLMT_MODE_CLS) { + if (!PortFound) { + PortFound = SkRlmtSelectDown(pAC, IoC, + Active, PrefPort, &Para.Para32[1], AUTONEG_SUCCESS); + } + + if (!PortFound) { + PortFound = SkRlmtSelectDown(pAC, IoC, + Active, PrefPort, &Para.Para32[1], AUTONEG_FAILED); + } + } /* pAC->Rlmt.RlmtMode != SK_RLMT_MODE_CLS */ + + if (PortFound) { + + if (Para.Para32[1] != Active) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("Active: %d, Para1: %d.\n", Active, Para.Para32[1])) + pAC->Rlmt.Net[NetIdx].ActivePort = Para.Para32[1]; + Para.Para32[0] = pAC->Rlmt.Net[NetIdx]. + Port[Para.Para32[0]]->PortNumber; + Para.Para32[1] = pAC->Rlmt.Net[NetIdx]. + Port[Para.Para32[1]]->PortNumber; + SK_HWAC_LINK_LED(pAC, IoC, Para.Para32[1], SK_LED_ACTIVE); + if (pAC->Rlmt.Port[Active].LinkDown) { + SkEventQueue(pAC, SKGE_DRV, SK_DRV_SWITCH_HARD, Para); + } + else { + SK_HWAC_LINK_LED(pAC, IoC, Para.Para32[0], SK_LED_STANDBY); + SkEventQueue(pAC, SKGE_DRV, SK_DRV_SWITCH_SOFT, Para); + } + Para.Para32[1] = NetIdx; + Para.Para32[0] = + pAC->Rlmt.Net[NetIdx].Port[Para.Para32[0]]->PortNumber; + SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_ACTIVE_DOWN, Para); + Para.Para32[0] = pAC->Rlmt.Net[NetIdx]. + Port[pAC->Rlmt.Net[NetIdx].ActivePort]->PortNumber; + SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_ACTIVE_UP, Para); + if ((pAC->Rlmt.Net[NetIdx].RlmtMode & SK_RLMT_TRANSPARENT) == 0 && + (Para.pParaPtr = SkRlmtBuildPacket(pAC, IoC, Para.Para32[0], + SK_PACKET_ANNOUNCE, &pAC->Addr.Net[NetIdx].CurrentMacAddress, + &SkRlmtMcAddr)) != NULL) { + /* + * Send announce packet to RLMT multicast address to force + * switches to learn the new location of the logical + * MAC address. + */ + SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para); + } /* (Para.pParaPtr = SkRlmtBuildPacket(...)) != NULL */ + } /* Para.Para32[1] != Active */ + } /* PortFound */ + else { + SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_RLMT_E004, SKERR_RLMT_E004_MSG); + } + } /* LinksUp > 1 || LinksUp == 1 && RlmtState != SK_RLMT_RS_NET_DOWN */ + return; +} /* SkRlmtCheckSwitch */ + + +/****************************************************************************** + * + * SkRlmtCheckSeg - Report if segmentation is detected + * + * Description: + * This routine checks if the ports see different root bridges and reports + * segmentation in such a case. + * + * Context: + * runtime, pageable? + * + * Returns: + * Nothing. + */ +RLMT_STATIC void SkRlmtCheckSeg( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_U32 NetIdx) /* Net number */ +{ + SK_EVPARA Para; + SK_RLMT_NET *pNet; + SK_U32 i, j; + SK_BOOL Equal; + + pNet = &pAC->Rlmt.Net[NetIdx]; + pNet->RootIdSet = SK_FALSE; + Equal = SK_TRUE; + + for (i = 0; i < pNet->NumPorts; i++) { + if (pNet->Port[i]->LinkDown || !pNet->Port[i]->RootIdSet) { + continue; + } + + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_DUMP, + ("Root ID %d: %02x %02x %02x %02x %02x %02x %02x %02x.\n", i, + pNet->Port[i]->Root.Id[0], pNet->Port[i]->Root.Id[1], + pNet->Port[i]->Root.Id[2], pNet->Port[i]->Root.Id[3], + pNet->Port[i]->Root.Id[4], pNet->Port[i]->Root.Id[5], + pNet->Port[i]->Root.Id[6], pNet->Port[i]->Root.Id[7])) + + if (!pNet->RootIdSet) { + pNet->Root = pNet->Port[i]->Root; + pNet->RootIdSet = SK_TRUE; + continue; + } + + for (j = 0; j < 8; j ++) { + Equal &= pNet->Port[i]->Root.Id[j] == pNet->Root.Id[j]; + if (!Equal) { + break; + } + } + + if (!Equal) { + SK_ERR_LOG(pAC, SK_ERRCL_COMM, SKERR_RLMT_E005, SKERR_RLMT_E005_MSG); + Para.Para32[0] = NetIdx; + Para.Para32[1] = (SK_U32)-1; + SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_SEGMENTATION, Para); + + pNet->CheckingState &= ~SK_RLMT_RCS_REPORT_SEG; + + /* 2000-03-06 RA: New. */ + Para.Para32[0] = NetIdx; + Para.Para32[1] = (SK_U32)-1; + SkTimerStart(pAC, IoC, &pNet->SegTimer, SK_RLMT_SEG_TO_VAL, + SKGE_RLMT, SK_RLMT_SEG_TIM, Para); + break; + } + } /* for (i = 0; i < pNet->NumPorts; i++) */ + + /* 2000-03-06 RA: Moved here. */ + /* Segmentation check not running anymore. */ + pNet->CheckingState &= ~SK_RLMT_RCS_SEG; + +} /* SkRlmtCheckSeg */ + + +/****************************************************************************** + * + * SkRlmtPortStart - initialize port variables and start port + * + * Description: + * This routine initializes a port's variables and issues a PORT_START + * to the HWAC module. This handles retries if the start fails or the + * link eventually goes down. + * + * Context: + * runtime, pageable? + * + * Returns: + * Nothing + */ +RLMT_STATIC void SkRlmtPortStart( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_U32 PortNumber) /* Port number */ +{ + SK_EVPARA Para; + + pAC->Rlmt.Port[PortNumber].PortState = SK_RLMT_PS_LINK_DOWN; + pAC->Rlmt.Port[PortNumber].PortStarted = SK_TRUE; + pAC->Rlmt.Port[PortNumber].LinkDown = SK_TRUE; + pAC->Rlmt.Port[PortNumber].PortDown = SK_TRUE; + pAC->Rlmt.Port[PortNumber].CheckingState = 0; + pAC->Rlmt.Port[PortNumber].RootIdSet = SK_FALSE; + Para.Para32[0] = PortNumber; + Para.Para32[1] = (SK_U32)-1; + SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_START, Para); +} /* SkRlmtPortStart */ + + +/****************************************************************************** + * + * SkRlmtEvtPortStartTim - PORT_START_TIM + * + * Description: + * This routine handles PORT_START_TIM events. + * + * Context: + * runtime, pageable? + * may be called after SK_INIT_IO + * + * Returns: + * Nothing + */ +RLMT_STATIC void SkRlmtEvtPortStartTim( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_EVPARA Para) /* SK_U32 PortNumber; SK_U32 -1 */ +{ + SK_U32 i; + + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_PORTSTART_TIMEOUT Port %d Event BEGIN.\n", Para.Para32[0])) + + if (Para.Para32[1] != (SK_U32)-1) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("Bad Parameter.\n")) + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_PORTSTART_TIMEOUT Event EMPTY.\n")) + return; + } + + /* + * Used to start non-preferred ports if the preferred one + * does not come up. + * This timeout needs only be set when starting the first + * (preferred) port. + */ + if (pAC->Rlmt.Port[Para.Para32[0]].LinkDown) { + /* PORT_START failed. */ + for (i = 0; i < pAC->Rlmt.Port[Para.Para32[0]].Net->NumPorts; i++) { + if (!pAC->Rlmt.Port[Para.Para32[0]].Net->Port[i]->PortStarted) { + SkRlmtPortStart(pAC, IoC, + pAC->Rlmt.Port[Para.Para32[0]].Net->Port[i]->PortNumber); + } + } + } + + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_PORTSTART_TIMEOUT Event END.\n")) +} /* SkRlmtEvtPortStartTim */ + + +/****************************************************************************** + * + * SkRlmtEvtLinkUp - LINK_UP + * + * Description: + * This routine handles LLINK_UP events. + * + * Context: + * runtime, pageable? + * may be called after SK_INIT_IO + * + * Returns: + * Nothing + */ +RLMT_STATIC void SkRlmtEvtLinkUp( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_EVPARA Para) /* SK_U32 PortNumber; SK_U32 Undefined */ +{ + SK_U32 i; + SK_RLMT_PORT *pRPort; + SK_EVPARA Para2; + + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_LINK_UP Port %d Event BEGIN.\n", Para.Para32[0])) + + pRPort = &pAC->Rlmt.Port[Para.Para32[0]]; + if (!pRPort->PortStarted) { + SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_RLMT_E008, SKERR_RLMT_E008_MSG); + + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_LINK_UP Event EMPTY.\n")) + return; + } + + if (!pRPort->LinkDown) { + /* RA;:;: Any better solution? */ + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_LINK_UP Event EMPTY.\n")) + return; + } + + SkTimerStop(pAC, IoC, &pRPort->UpTimer); + SkTimerStop(pAC, IoC, &pRPort->DownRxTimer); + SkTimerStop(pAC, IoC, &pRPort->DownTxTimer); + + /* Do something if timer already fired? */ + + pRPort->LinkDown = SK_FALSE; + pRPort->PortState = SK_RLMT_PS_GOING_UP; + pRPort->GuTimeStamp = SkOsGetTime(pAC); + pRPort->BcTimeStamp = 0; + pRPort->Net->LinksUp++; + if (pRPort->Net->LinksUp == 1) { + SK_HWAC_LINK_LED(pAC, IoC, Para.Para32[0], SK_LED_ACTIVE); + } + else { + SK_HWAC_LINK_LED(pAC, IoC, Para.Para32[0], SK_LED_STANDBY); + } + + for (i = 0; i < pRPort->Net->NumPorts; i++) { + if (!pRPort->Net->Port[i]->PortStarted) { + SkRlmtPortStart(pAC, IoC, pRPort->Net->Port[i]->PortNumber); + } + } + + SkRlmtCheckSwitch(pAC, IoC, pRPort->Net->NetNumber); + + if (pRPort->Net->LinksUp >= 2) { + if (pRPort->Net->RlmtMode & SK_RLMT_CHECK_LOC_LINK) { + /* Build the check chain. */ + SkRlmtBuildCheckChain(pAC, pRPort->Net->NetNumber); + } + } + + /* If the first link comes up, start the periodical RLMT timeout. */ + if (pRPort->Net->NumPorts > 1 && pRPort->Net->LinksUp == 1 && + (pRPort->Net->RlmtMode & SK_RLMT_CHECK_OTHERS) != 0) { + Para2.Para32[0] = pRPort->Net->NetNumber; + Para2.Para32[1] = (SK_U32)-1; + SkTimerStart(pAC, IoC, &pRPort->Net->LocTimer, + pRPort->Net->TimeoutValue, SKGE_RLMT, SK_RLMT_TIM, Para2); + } + + Para2 = Para; + Para2.Para32[1] = (SK_U32)-1; + SkTimerStart(pAC, IoC, &pRPort->UpTimer, SK_RLMT_PORTUP_TIM_VAL, + SKGE_RLMT, SK_RLMT_PORTUP_TIM, Para2); + + /* Later: if (pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_LOC_LINK) && */ + if ((pRPort->Net->RlmtMode & SK_RLMT_TRANSPARENT) == 0 && + (pRPort->Net->RlmtMode & SK_RLMT_CHECK_LINK) != 0 && + (Para2.pParaPtr = + SkRlmtBuildPacket(pAC, IoC, Para.Para32[0], SK_PACKET_ANNOUNCE, + &pAC->Addr.Port[Para.Para32[0]].CurrentMacAddress, &SkRlmtMcAddr) + ) != NULL) { + /* Send "new" packet to RLMT multicast address. */ + SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para2); + } + + if (pRPort->Net->RlmtMode & SK_RLMT_CHECK_SEG) { + if ((Para2.pParaPtr = + SkRlmtBuildSpanningTreePacket(pAC, IoC, Para.Para32[0])) != NULL) { + pAC->Rlmt.Port[Para.Para32[0]].RootIdSet = SK_FALSE; + pRPort->Net->CheckingState |= + SK_RLMT_RCS_SEG | SK_RLMT_RCS_REPORT_SEG; + + SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para2); + + Para.Para32[1] = (SK_U32)-1; + SkTimerStart(pAC, IoC, &pRPort->Net->SegTimer, + SK_RLMT_SEG_TO_VAL, SKGE_RLMT, SK_RLMT_SEG_TIM, Para); + } + } + + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_LINK_UP Event END.\n")) +} /* SkRlmtEvtLinkUp */ + + +/****************************************************************************** + * + * SkRlmtEvtPortUpTim - PORT_UP_TIM + * + * Description: + * This routine handles PORT_UP_TIM events. + * + * Context: + * runtime, pageable? + * may be called after SK_INIT_IO + * + * Returns: + * Nothing + */ +RLMT_STATIC void SkRlmtEvtPortUpTim( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_EVPARA Para) /* SK_U32 PortNumber; SK_U32 -1 */ +{ + SK_RLMT_PORT *pRPort; + + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_PORTUP_TIM Port %d Event BEGIN.\n", Para.Para32[0])) + + if (Para.Para32[1] != (SK_U32)-1) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("Bad Parameter.\n")) + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_PORTUP_TIM Event EMPTY.\n")) + return; + } + + pRPort = &pAC->Rlmt.Port[Para.Para32[0]]; + if (pRPort->LinkDown || (pRPort->PortState == SK_RLMT_PS_UP)) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_PORTUP_TIM Port %d Event EMPTY.\n", Para.Para32[0])) + return; + } + + pRPort->PortDown = SK_FALSE; + pRPort->PortState = SK_RLMT_PS_UP; + pRPort->Net->PortsUp++; + if (pRPort->Net->RlmtState != SK_RLMT_RS_INIT) { + if (pAC->Rlmt.NumNets <= 1) { + SkRlmtCheckSwitch(pAC, IoC, pRPort->Net->NetNumber); + } + SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_PORT_UP, Para); + } + + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_PORTUP_TIM Event END.\n")) +} /* SkRlmtEvtPortUpTim */ + + +/****************************************************************************** + * + * SkRlmtEvtPortDownTim - PORT_DOWN_* + * + * Description: + * This routine handles PORT_DOWN_* events. + * + * Context: + * runtime, pageable? + * may be called after SK_INIT_IO + * + * Returns: + * Nothing + */ +RLMT_STATIC void SkRlmtEvtPortDownX( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_U32 Event, /* Event code */ +SK_EVPARA Para) /* SK_U32 PortNumber; SK_U32 -1 */ +{ + SK_RLMT_PORT *pRPort; + + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_PORTDOWN* Port %d Event (%d) BEGIN.\n", + Para.Para32[0], Event)) + + if (Para.Para32[1] != (SK_U32)-1) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("Bad Parameter.\n")) + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_PORTDOWN* Event EMPTY.\n")) + return; + } + + pRPort = &pAC->Rlmt.Port[Para.Para32[0]]; + if (!pRPort->PortStarted || (Event == SK_RLMT_PORTDOWN_TX_TIM && + !(pRPort->CheckingState & SK_RLMT_PCS_TX))) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_PORTDOWN* Event (%d) EMPTY.\n", Event)) + return; + } + + /* Stop port's timers. */ + SkTimerStop(pAC, IoC, &pRPort->UpTimer); + SkTimerStop(pAC, IoC, &pRPort->DownRxTimer); + SkTimerStop(pAC, IoC, &pRPort->DownTxTimer); + + if (pRPort->PortState != SK_RLMT_PS_LINK_DOWN) { + pRPort->PortState = SK_RLMT_PS_DOWN; + } + + if (!pRPort->PortDown) { + pRPort->Net->PortsUp--; + pRPort->PortDown = SK_TRUE; + SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_PORT_DOWN, Para); + } + + pRPort->PacketsPerTimeSlot = 0; + /* pRPort->DataPacketsPerTimeSlot = 0; */ + pRPort->BpduPacketsPerTimeSlot = 0; + pRPort->BcTimeStamp = 0; + + /* + * RA;:;: To be checked: + * - actions at RLMT_STOP: We should not switch anymore. + */ + if (pRPort->Net->RlmtState != SK_RLMT_RS_INIT) { + if (Para.Para32[0] == + pRPort->Net->Port[pRPort->Net->ActivePort]->PortNumber) { + /* Active Port went down. */ + SkRlmtCheckSwitch(pAC, IoC, pRPort->Net->NetNumber); + } + } + + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_PORTDOWN* Event (%d) END.\n", Event)) +} /* SkRlmtEvtPortDownX */ + + +/****************************************************************************** + * + * SkRlmtEvtLinkDown - LINK_DOWN + * + * Description: + * This routine handles LINK_DOWN events. + * + * Context: + * runtime, pageable? + * may be called after SK_INIT_IO + * + * Returns: + * Nothing + */ +RLMT_STATIC void SkRlmtEvtLinkDown( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_EVPARA Para) /* SK_U32 PortNumber; SK_U32 Undefined */ +{ + SK_RLMT_PORT *pRPort; + + pRPort = &pAC->Rlmt.Port[Para.Para32[0]]; + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_LINK_DOWN Port %d Event BEGIN.\n", Para.Para32[0])) + + if (!pAC->Rlmt.Port[Para.Para32[0]].LinkDown) { + pRPort->Net->LinksUp--; + pRPort->LinkDown = SK_TRUE; + pRPort->PortState = SK_RLMT_PS_LINK_DOWN; + SK_HWAC_LINK_LED(pAC, IoC, Para.Para32[0], SK_LED_OFF); + + if ((pRPort->Net->RlmtMode & SK_RLMT_CHECK_LOC_LINK) != 0) { + /* Build the check chain. */ + SkRlmtBuildCheckChain(pAC, pRPort->Net->NetNumber); + } + + /* Ensure that port is marked down. */ + Para.Para32[1] = -1; + (void)SkRlmtEvent(pAC, IoC, SK_RLMT_PORTDOWN, Para); + } + + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_LINK_DOWN Event END.\n")) +} /* SkRlmtEvtLinkDown */ + + +/****************************************************************************** + * + * SkRlmtEvtPortAddr - PORT_ADDR + * + * Description: + * This routine handles PORT_ADDR events. + * + * Context: + * runtime, pageable? + * may be called after SK_INIT_IO + * + * Returns: + * Nothing + */ +RLMT_STATIC void SkRlmtEvtPortAddr( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_EVPARA Para) /* SK_U32 PortNumber; SK_U32 -1 */ +{ + SK_U32 i, j; + SK_RLMT_PORT *pRPort; + SK_MAC_ADDR *pOldMacAddr; + SK_MAC_ADDR *pNewMacAddr; + + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_PORT_ADDR Port %d Event BEGIN.\n", Para.Para32[0])) + + if (Para.Para32[1] != (SK_U32)-1) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("Bad Parameter.\n")) + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_PORT_ADDR Event EMPTY.\n")) + return; + } + + /* Port's physical MAC address changed. */ + pOldMacAddr = &pAC->Addr.Port[Para.Para32[0]].PreviousMacAddress; + pNewMacAddr = &pAC->Addr.Port[Para.Para32[0]].CurrentMacAddress; + + /* + * NOTE: This is not scalable for solutions where ports are + * checked remotely. There, we need to send an RLMT + * address change packet - and how do we ensure delivery? + */ + for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) { + pRPort = &pAC->Rlmt.Port[i]; + for (j = 0; j < pRPort->PortsChecked; j++) { + if (SK_ADDR_EQUAL( + pRPort->PortCheck[j].CheckAddr.a, pOldMacAddr->a)) { + pRPort->PortCheck[j].CheckAddr = *pNewMacAddr; + } + } + } + + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_PORT_ADDR Event END.\n")) +} /* SkRlmtEvtPortAddr */ + + +/****************************************************************************** + * + * SkRlmtEvtStart - START + * + * Description: + * This routine handles START events. + * + * Context: + * runtime, pageable? + * may be called after SK_INIT_IO + * + * Returns: + * Nothing + */ +RLMT_STATIC void SkRlmtEvtStart( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_EVPARA Para) /* SK_U32 NetNumber; SK_U32 -1 */ +{ + SK_EVPARA Para2; + SK_U32 PortIdx; + SK_U32 PortNumber; + + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_START Net %d Event BEGIN.\n", Para.Para32[0])) + + if (Para.Para32[1] != (SK_U32)-1) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("Bad Parameter.\n")) + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_START Event EMPTY.\n")) + return; + } + + if (Para.Para32[0] >= pAC->Rlmt.NumNets) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("Bad NetNumber %d.\n", Para.Para32[0])) + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_START Event EMPTY.\n")) + return; + } + + if (pAC->Rlmt.Net[Para.Para32[0]].RlmtState != SK_RLMT_RS_INIT) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_START Event EMPTY.\n")) + return; + } + + if (pAC->Rlmt.NetsStarted >= pAC->Rlmt.NumNets) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("All nets should have been started.\n")) + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_START Event EMPTY.\n")) + return; + } + + if (pAC->Rlmt.Net[Para.Para32[0]].PrefPort >= + pAC->Rlmt.Net[Para.Para32[0]].NumPorts) { + SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_RLMT_E009, SKERR_RLMT_E009_MSG); + + /* Change PrefPort to internal default. */ + Para2.Para32[0] = 0xFFFFFFFF; + Para2.Para32[1] = Para.Para32[0]; + (void)SkRlmtEvent(pAC, IoC, SK_RLMT_PREFPORT_CHANGE, Para2); + } + + PortIdx = pAC->Rlmt.Net[Para.Para32[0]].PrefPort; + PortNumber = pAC->Rlmt.Net[Para.Para32[0]].Port[PortIdx]->PortNumber; + + pAC->Rlmt.Net[Para.Para32[0]].LinksUp = 0; + pAC->Rlmt.Net[Para.Para32[0]].PortsUp = 0; + pAC->Rlmt.Net[Para.Para32[0]].CheckingState = 0; + pAC->Rlmt.Net[Para.Para32[0]].RlmtState = SK_RLMT_RS_NET_DOWN; + + /* Start preferred port. */ + SkRlmtPortStart(pAC, IoC, PortNumber); + + /* Start Timer (for first port only). */ + Para2.Para32[0] = PortNumber; + Para2.Para32[1] = (SK_U32)-1; + SkTimerStart(pAC, IoC, &pAC->Rlmt.Port[PortNumber].UpTimer, + SK_RLMT_PORTSTART_TIM_VAL, SKGE_RLMT, SK_RLMT_PORTSTART_TIM, Para2); + + pAC->Rlmt.NetsStarted++; + + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_START Event END.\n")) +} /* SkRlmtEvtStart */ + + +/****************************************************************************** + * + * SkRlmtEvtStop - STOP + * + * Description: + * This routine handles STOP events. + * + * Context: + * runtime, pageable? + * may be called after SK_INIT_IO + * + * Returns: + * Nothing + */ +RLMT_STATIC void SkRlmtEvtStop( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_EVPARA Para) /* SK_U32 NetNumber; SK_U32 -1 */ +{ + SK_EVPARA Para2; + SK_U32 PortNumber; + SK_U32 i; + + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_STOP Net %d Event BEGIN.\n", Para.Para32[0])) + + if (Para.Para32[1] != (SK_U32)-1) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("Bad Parameter.\n")) + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_STOP Event EMPTY.\n")) + return; + } + + if (Para.Para32[0] >= pAC->Rlmt.NumNets) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("Bad NetNumber %d.\n", Para.Para32[0])) + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_STOP Event EMPTY.\n")) + return; + } + + if (pAC->Rlmt.Net[Para.Para32[0]].RlmtState == SK_RLMT_RS_INIT) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_STOP Event EMPTY.\n")) + return; + } + + if (pAC->Rlmt.NetsStarted == 0) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("All nets are stopped.\n")) + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_STOP Event EMPTY.\n")) + return; + } + + /* Stop RLMT timers. */ + SkTimerStop(pAC, IoC, &pAC->Rlmt.Net[Para.Para32[0]].LocTimer); + SkTimerStop(pAC, IoC, &pAC->Rlmt.Net[Para.Para32[0]].SegTimer); + + /* Stop net. */ + pAC->Rlmt.Net[Para.Para32[0]].RlmtState = SK_RLMT_RS_INIT; + pAC->Rlmt.Net[Para.Para32[0]].RootIdSet = SK_FALSE; + Para2.Para32[0] = SK_RLMT_NET_DOWN_FINAL; + Para2.Para32[1] = Para.Para32[0]; /* Net# */ + SkEventQueue(pAC, SKGE_DRV, SK_DRV_NET_DOWN, Para2); + + /* Stop ports. */ + for (i = 0; i < pAC->Rlmt.Net[Para.Para32[0]].NumPorts; i++) { + PortNumber = pAC->Rlmt.Net[Para.Para32[0]].Port[i]->PortNumber; + if (pAC->Rlmt.Port[PortNumber].PortState != SK_RLMT_PS_INIT) { + SkTimerStop(pAC, IoC, &pAC->Rlmt.Port[PortNumber].UpTimer); + SkTimerStop(pAC, IoC, &pAC->Rlmt.Port[PortNumber].DownRxTimer); + SkTimerStop(pAC, IoC, &pAC->Rlmt.Port[PortNumber].DownTxTimer); + + pAC->Rlmt.Port[PortNumber].PortState = SK_RLMT_PS_INIT; + pAC->Rlmt.Port[PortNumber].RootIdSet = SK_FALSE; + pAC->Rlmt.Port[PortNumber].PortStarted = SK_FALSE; + Para2.Para32[0] = PortNumber; + Para2.Para32[1] = (SK_U32)-1; + SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_STOP, Para2); + } + } + + pAC->Rlmt.NetsStarted--; + + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_STOP Event END.\n")) +} /* SkRlmtEvtStop */ + + +/****************************************************************************** + * + * SkRlmtEvtTim - TIM + * + * Description: + * This routine handles TIM events. + * + * Context: + * runtime, pageable? + * may be called after SK_INIT_IO + * + * Returns: + * Nothing + */ +RLMT_STATIC void SkRlmtEvtTim( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_EVPARA Para) /* SK_U32 NetNumber; SK_U32 -1 */ +{ + SK_RLMT_PORT *pRPort; + SK_U32 Timeout; + SK_U32 NewTimeout; + SK_U32 PortNumber; + SK_U32 i; + + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_TIM Event BEGIN.\n")) + + if (Para.Para32[1] != (SK_U32)-1) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("Bad Parameter.\n")) + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_TIM Event EMPTY.\n")) + return; + } + + if ((pAC->Rlmt.Net[Para.Para32[0]].RlmtMode & SK_RLMT_CHECK_OTHERS) == 0 || + pAC->Rlmt.Net[Para.Para32[0]].LinksUp == 0) { + /* Mode changed or all links down: No more link checking. */ + return; + } + +#if 0 + pAC->Rlmt.SwitchCheckCounter--; + if (pAC->Rlmt.SwitchCheckCounter == 0) { + pAC->Rlmt.SwitchCheckCounter; + } +#endif /* 0 */ + + NewTimeout = SK_RLMT_DEF_TO_VAL; + for (i = 0; i < pAC->Rlmt.Net[Para.Para32[0]].NumPorts; i++) { + PortNumber = pAC->Rlmt.Net[Para.Para32[0]].Port[i]->PortNumber; + pRPort = &pAC->Rlmt.Port[PortNumber]; + if (!pRPort->LinkDown) { + Timeout = SkRlmtCheckPort(pAC, IoC, PortNumber); + if (Timeout < NewTimeout) { + NewTimeout = Timeout; + } + + /* + * These counters should be set to 0 for all ports before the + * first frame is sent in the next loop. + */ + pRPort->PacketsPerTimeSlot = 0; + /* pRPort->DataPacketsPerTimeSlot = 0; */ + pRPort->BpduPacketsPerTimeSlot = 0; + } + } + pAC->Rlmt.Net[Para.Para32[0]].TimeoutValue = NewTimeout; + + if (pAC->Rlmt.Net[Para.Para32[0]].LinksUp > 1) { + /* + * If checking remote ports, also send packets if + * (LinksUp == 1) && + * this port checks at least one (remote) port. + */ + + /* + * Must be new loop, as SkRlmtCheckPort can request to + * check segmentation when e.g. checking the last port. + */ + for (i = 0; i < pAC->Rlmt.Net[Para.Para32[0]].NumPorts; i++) { + if (!pAC->Rlmt.Net[Para.Para32[0]].Port[i]->LinkDown) { + SkRlmtSend(pAC, IoC, + pAC->Rlmt.Net[Para.Para32[0]].Port[i]->PortNumber); + } + } + } + + SkTimerStart(pAC, IoC, &pAC->Rlmt.Net[Para.Para32[0]].LocTimer, + pAC->Rlmt.Net[Para.Para32[0]].TimeoutValue, SKGE_RLMT, SK_RLMT_TIM, + Para); + + if (pAC->Rlmt.Net[Para.Para32[0]].LinksUp > 1 && + (pAC->Rlmt.Net[Para.Para32[0]].RlmtMode & SK_RLMT_CHECK_SEG) && + (pAC->Rlmt.Net[Para.Para32[0]].CheckingState & SK_RLMT_RCS_START_SEG)) { + SkTimerStart(pAC, IoC, &pAC->Rlmt.Net[Para.Para32[0]].SegTimer, + SK_RLMT_SEG_TO_VAL, SKGE_RLMT, SK_RLMT_SEG_TIM, Para); + pAC->Rlmt.Net[Para.Para32[0]].CheckingState &= ~SK_RLMT_RCS_START_SEG; + pAC->Rlmt.Net[Para.Para32[0]].CheckingState |= + SK_RLMT_RCS_SEG | SK_RLMT_RCS_REPORT_SEG; + } + + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_TIM Event END.\n")) +} /* SkRlmtEvtTim */ + + +/****************************************************************************** + * + * SkRlmtEvtSegTim - SEG_TIM + * + * Description: + * This routine handles SEG_TIM events. + * + * Context: + * runtime, pageable? + * may be called after SK_INIT_IO + * + * Returns: + * Nothing + */ +RLMT_STATIC void SkRlmtEvtSegTim( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_EVPARA Para) /* SK_U32 NetNumber; SK_U32 -1 */ +{ +#ifdef xDEBUG + int j; +#endif /* DEBUG */ + + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_SEG_TIM Event BEGIN.\n")) + + if (Para.Para32[1] != (SK_U32)-1) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("Bad Parameter.\n")) + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_SEG_TIM Event EMPTY.\n")) + return; + } + +#ifdef xDEBUG + for (j = 0; j < pAC->Rlmt.Net[Para.Para32[0]].NumPorts; j++) { + SK_ADDR_PORT *pAPort; + SK_U32 k; + SK_U16 *InAddr; + SK_U8 InAddr8[6]; + + InAddr = (SK_U16 *)&InAddr8[0]; + pAPort = pAC->Rlmt.Net[Para.Para32[0]].Port[j]->AddrPort; + for (k = 0; k < pAPort->NextExactMatchRlmt; k++) { + /* Get exact match address k from port j. */ + XM_INADDR(IoC, pAC->Rlmt.Net[Para.Para32[0]].Port[j]->PortNumber, + XM_EXM(k), InAddr); + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("MC address %d on Port %u: %02x %02x %02x %02x %02x %02x -- %02x %02x %02x %02x %02x %02x.\n", + k, pAC->Rlmt.Net[Para.Para32[0]].Port[j]->PortNumber, + InAddr8[0], InAddr8[1], InAddr8[2], + InAddr8[3], InAddr8[4], InAddr8[5], + pAPort->Exact[k].a[0], pAPort->Exact[k].a[1], + pAPort->Exact[k].a[2], pAPort->Exact[k].a[3], + pAPort->Exact[k].a[4], pAPort->Exact[k].a[5])) + } + } +#endif /* xDEBUG */ + + SkRlmtCheckSeg(pAC, IoC, Para.Para32[0]); + + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_SEG_TIM Event END.\n")) +} /* SkRlmtEvtSegTim */ + + +/****************************************************************************** + * + * SkRlmtEvtPacketRx - PACKET_RECEIVED + * + * Description: + * This routine handles PACKET_RECEIVED events. + * + * Context: + * runtime, pageable? + * may be called after SK_INIT_IO + * + * Returns: + * Nothing + */ +RLMT_STATIC void SkRlmtEvtPacketRx( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_EVPARA Para) /* SK_MBUF *pMb */ +{ + SK_MBUF *pMb; + SK_MBUF *pNextMb; + SK_U32 NetNumber; + + + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_PACKET_RECEIVED Event BEGIN.\n")) + + /* Should we ignore frames during port switching? */ + +#ifdef DEBUG + pMb = Para.pParaPtr; + if (pMb == NULL) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("No mbuf.\n")) + } + else if (pMb->pNext != NULL) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("More than one mbuf or pMb->pNext not set.\n")) + } +#endif /* DEBUG */ + + for (pMb = Para.pParaPtr; pMb != NULL; pMb = pNextMb) { + pNextMb = pMb->pNext; + pMb->pNext = NULL; + + NetNumber = pAC->Rlmt.Port[pMb->PortIdx].Net->NetNumber; + if (pAC->Rlmt.Net[NetNumber].RlmtState == SK_RLMT_RS_INIT) { + SkDrvFreeRlmtMbuf(pAC, IoC, pMb); + } + else { + SkRlmtPacketReceive(pAC, IoC, pMb); + } + } + + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_PACKET_RECEIVED Event END.\n")) +} /* SkRlmtEvtPacketRx */ + + +/****************************************************************************** + * + * SkRlmtEvtStatsClear - STATS_CLEAR + * + * Description: + * This routine handles STATS_CLEAR events. + * + * Context: + * runtime, pageable? + * may be called after SK_INIT_IO + * + * Returns: + * Nothing + */ +RLMT_STATIC void SkRlmtEvtStatsClear( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_EVPARA Para) /* SK_U32 NetNumber; SK_U32 -1 */ +{ + SK_U32 i; + SK_RLMT_PORT *pRPort; + + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_STATS_CLEAR Event BEGIN.\n")) + + if (Para.Para32[1] != (SK_U32)-1) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("Bad Parameter.\n")) + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_STATS_CLEAR Event EMPTY.\n")) + return; + } + + if (Para.Para32[0] >= pAC->Rlmt.NumNets) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("Bad NetNumber %d.\n", Para.Para32[0])) + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_STATS_CLEAR Event EMPTY.\n")) + return; + } + + /* Clear statistics for logical and physical ports. */ + for (i = 0; i < pAC->Rlmt.Net[Para.Para32[0]].NumPorts; i++) { + pRPort = + &pAC->Rlmt.Port[pAC->Rlmt.Net[Para.Para32[0]].Port[i]->PortNumber]; + pRPort->TxHelloCts = 0; + pRPort->RxHelloCts = 0; + pRPort->TxSpHelloReqCts = 0; + pRPort->RxSpHelloCts = 0; + } + + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_STATS_CLEAR Event END.\n")) +} /* SkRlmtEvtStatsClear */ + + +/****************************************************************************** + * + * SkRlmtEvtStatsUpdate - STATS_UPDATE + * + * Description: + * This routine handles STATS_UPDATE events. + * + * Context: + * runtime, pageable? + * may be called after SK_INIT_IO + * + * Returns: + * Nothing + */ +RLMT_STATIC void SkRlmtEvtStatsUpdate( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_EVPARA Para) /* SK_U32 NetNumber; SK_U32 -1 */ +{ + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_STATS_UPDATE Event BEGIN.\n")) + + if (Para.Para32[1] != (SK_U32)-1) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("Bad Parameter.\n")) + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_STATS_UPDATE Event EMPTY.\n")) + return; + } + + if (Para.Para32[0] >= pAC->Rlmt.NumNets) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("Bad NetNumber %d.\n", Para.Para32[0])) + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_STATS_UPDATE Event EMPTY.\n")) + return; + } + + /* Update statistics - currently always up-to-date. */ + + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_STATS_UPDATE Event END.\n")) +} /* SkRlmtEvtStatsUpdate */ + + +/****************************************************************************** + * + * SkRlmtEvtPrefportChange - PREFPORT_CHANGE + * + * Description: + * This routine handles PREFPORT_CHANGE events. + * + * Context: + * runtime, pageable? + * may be called after SK_INIT_IO + * + * Returns: + * Nothing + */ +RLMT_STATIC void SkRlmtEvtPrefportChange( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_EVPARA Para) /* SK_U32 PortIndex; SK_U32 NetNumber */ +{ + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_PREFPORT_CHANGE to Port %d Event BEGIN.\n", Para.Para32[0])) + + if (Para.Para32[1] >= pAC->Rlmt.NumNets) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("Bad NetNumber %d.\n", Para.Para32[1])) + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_PREFPORT_CHANGE Event EMPTY.\n")) + return; + } + + /* 0xFFFFFFFF == auto-mode. */ + if (Para.Para32[0] == 0xFFFFFFFF) { + pAC->Rlmt.Net[Para.Para32[1]].PrefPort = SK_RLMT_DEF_PREF_PORT; + } + else { + if (Para.Para32[0] >= pAC->Rlmt.Net[Para.Para32[1]].NumPorts) { + SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_RLMT_E010, SKERR_RLMT_E010_MSG); + + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_PREFPORT_CHANGE Event EMPTY.\n")) + return; + } + + pAC->Rlmt.Net[Para.Para32[1]].PrefPort = Para.Para32[0]; + } + + pAC->Rlmt.Net[Para.Para32[1]].Preference = Para.Para32[0]; + + if (pAC->Rlmt.Net[Para.Para32[1]].RlmtState != SK_RLMT_RS_INIT) { + SkRlmtCheckSwitch(pAC, IoC, Para.Para32[1]); + } + + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_PREFPORT_CHANGE Event END.\n")) +} /* SkRlmtEvtPrefportChange */ + + +/****************************************************************************** + * + * SkRlmtEvtSetNets - SET_NETS + * + * Description: + * This routine handles SET_NETS events. + * + * Context: + * runtime, pageable? + * may be called after SK_INIT_IO + * + * Returns: + * Nothing + */ +RLMT_STATIC void SkRlmtEvtSetNets( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_EVPARA Para) /* SK_U32 NumNets; SK_U32 -1 */ +{ + int i; + + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_SET_NETS Event BEGIN.\n")) + + if (Para.Para32[1] != (SK_U32)-1) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("Bad Parameter.\n")) + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_SET_NETS Event EMPTY.\n")) + return; + } + + if (Para.Para32[0] == 0 || Para.Para32[0] > SK_MAX_NETS || + Para.Para32[0] > (SK_U32)pAC->GIni.GIMacsFound) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("Bad number of nets: %d.\n", Para.Para32[0])) + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_SET_NETS Event EMPTY.\n")) + return; + } + + if (Para.Para32[0] == pAC->Rlmt.NumNets) { /* No change. */ + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_SET_NETS Event EMPTY.\n")) + return; + } + + /* Entering and leaving dual mode only allowed while nets are stopped. */ + if (pAC->Rlmt.NetsStarted > 0) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("Changing dual mode only allowed while all nets are stopped.\n")) + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_SET_NETS Event EMPTY.\n")) + return; + } + + if (Para.Para32[0] == 1) { + if (pAC->Rlmt.NumNets > 1) { + /* Clear logical MAC addr from second net's active port. */ + (void)SkAddrOverride(pAC, IoC, pAC->Rlmt.Net[1].Port[pAC->Addr. + Net[1].ActivePort]->PortNumber, NULL, SK_ADDR_CLEAR_LOGICAL); + pAC->Rlmt.Net[1].NumPorts = 0; + } + + pAC->Rlmt.NumNets = Para.Para32[0]; + for (i = 0; (SK_U32)i < pAC->Rlmt.NumNets; i++) { + pAC->Rlmt.Net[i].RlmtState = SK_RLMT_RS_INIT; + pAC->Rlmt.Net[i].RootIdSet = SK_FALSE; + pAC->Rlmt.Net[i].Preference = 0xFFFFFFFF; /* "Automatic" */ + pAC->Rlmt.Net[i].PrefPort = SK_RLMT_DEF_PREF_PORT; + /* Just assuming. */ + pAC->Rlmt.Net[i].ActivePort = pAC->Rlmt.Net[i].PrefPort; + pAC->Rlmt.Net[i].RlmtMode = SK_RLMT_DEF_MODE; + pAC->Rlmt.Net[i].TimeoutValue = SK_RLMT_DEF_TO_VAL; + pAC->Rlmt.Net[i].NetNumber = i; + } + + pAC->Rlmt.Port[1].Net= &pAC->Rlmt.Net[0]; + pAC->Rlmt.Net[0].NumPorts = pAC->GIni.GIMacsFound; + + SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_SET_NETS, Para); + + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("RLMT: Changed to one net with two ports.\n")) + } + else if (Para.Para32[0] == 2) { + pAC->Rlmt.Port[1].Net= &pAC->Rlmt.Net[1]; + pAC->Rlmt.Net[1].NumPorts = pAC->GIni.GIMacsFound - 1; + pAC->Rlmt.Net[0].NumPorts = + pAC->GIni.GIMacsFound - pAC->Rlmt.Net[1].NumPorts; + + pAC->Rlmt.NumNets = Para.Para32[0]; + for (i = 0; (SK_U32)i < pAC->Rlmt.NumNets; i++) { + pAC->Rlmt.Net[i].RlmtState = SK_RLMT_RS_INIT; + pAC->Rlmt.Net[i].RootIdSet = SK_FALSE; + pAC->Rlmt.Net[i].Preference = 0xFFFFFFFF; /* "Automatic" */ + pAC->Rlmt.Net[i].PrefPort = SK_RLMT_DEF_PREF_PORT; + /* Just assuming. */ + pAC->Rlmt.Net[i].ActivePort = pAC->Rlmt.Net[i].PrefPort; + pAC->Rlmt.Net[i].RlmtMode = SK_RLMT_DEF_MODE; + pAC->Rlmt.Net[i].TimeoutValue = SK_RLMT_DEF_TO_VAL; + + pAC->Rlmt.Net[i].NetNumber = i; + } + + /* Set logical MAC addr on second net's active port. */ + (void)SkAddrOverride(pAC, IoC, pAC->Rlmt.Net[1].Port[pAC->Addr. + Net[1].ActivePort]->PortNumber, NULL, SK_ADDR_SET_LOGICAL); + + SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_SET_NETS, Para); + + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("RLMT: Changed to two nets with one port each.\n")) + } + else { + /* Not implemented for more than two nets. */ + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SetNets not implemented for more than two nets.\n")) + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_SET_NETS Event EMPTY.\n")) + return; + } + + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_SET_NETS Event END.\n")) +} /* SkRlmtSetNets */ + + +/****************************************************************************** + * + * SkRlmtEvtModeChange - MODE_CHANGE + * + * Description: + * This routine handles MODE_CHANGE events. + * + * Context: + * runtime, pageable? + * may be called after SK_INIT_IO + * + * Returns: + * Nothing + */ +RLMT_STATIC void SkRlmtEvtModeChange( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_EVPARA Para) /* SK_U32 NewMode; SK_U32 NetNumber */ +{ + SK_EVPARA Para2; + SK_U32 i; + SK_U32 PrevRlmtMode; + + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_MODE_CHANGE Event BEGIN.\n")) + + if (Para.Para32[1] >= pAC->Rlmt.NumNets) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("Bad NetNumber %d.\n", Para.Para32[1])) + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_MODE_CHANGE Event EMPTY.\n")) + return; + } + + Para.Para32[0] |= SK_RLMT_CHECK_LINK; + + if ((pAC->Rlmt.Net[Para.Para32[1]].NumPorts == 1) && + Para.Para32[0] != SK_RLMT_MODE_CLS) { + pAC->Rlmt.Net[Para.Para32[1]].RlmtMode = SK_RLMT_MODE_CLS; + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("Forced RLMT mode to CLS on single port net.\n")) + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_MODE_CHANGE Event EMPTY.\n")) + return; + } + + /* Update RLMT mode. */ + PrevRlmtMode = pAC->Rlmt.Net[Para.Para32[1]].RlmtMode; + pAC->Rlmt.Net[Para.Para32[1]].RlmtMode = Para.Para32[0]; + + if ((PrevRlmtMode & SK_RLMT_CHECK_LOC_LINK) != + (pAC->Rlmt.Net[Para.Para32[1]].RlmtMode & SK_RLMT_CHECK_LOC_LINK)) { + /* SK_RLMT_CHECK_LOC_LINK bit changed. */ + if ((PrevRlmtMode & SK_RLMT_CHECK_OTHERS) == 0 && + pAC->Rlmt.Net[Para.Para32[1]].NumPorts > 1 && + pAC->Rlmt.Net[Para.Para32[1]].PortsUp >= 1) { + /* 20001207 RA: Was "PortsUp == 1". */ + Para2.Para32[0] = Para.Para32[1]; + Para2.Para32[1] = (SK_U32)-1; + SkTimerStart(pAC, IoC, &pAC->Rlmt.Net[Para.Para32[1]].LocTimer, + pAC->Rlmt.Net[Para.Para32[1]].TimeoutValue, + SKGE_RLMT, SK_RLMT_TIM, Para2); + } + } + + if ((PrevRlmtMode & SK_RLMT_CHECK_SEG) != + (pAC->Rlmt.Net[Para.Para32[1]].RlmtMode & SK_RLMT_CHECK_SEG)) { + /* SK_RLMT_CHECK_SEG bit changed. */ + for (i = 0; i < pAC->Rlmt.Net[Para.Para32[1]].NumPorts; i++) { + (void)SkAddrMcClear(pAC, IoC, + pAC->Rlmt.Net[Para.Para32[1]].Port[i]->PortNumber, + SK_ADDR_PERMANENT | SK_MC_SW_ONLY); + + /* Add RLMT MC address. */ + (void)SkAddrMcAdd(pAC, IoC, + pAC->Rlmt.Net[Para.Para32[1]].Port[i]->PortNumber, + &SkRlmtMcAddr, SK_ADDR_PERMANENT); + + if ((pAC->Rlmt.Net[Para.Para32[1]].RlmtMode & + SK_RLMT_CHECK_SEG) != 0) { + /* Add BPDU MC address. */ + (void)SkAddrMcAdd(pAC, IoC, + pAC->Rlmt.Net[Para.Para32[1]].Port[i]->PortNumber, + &BridgeMcAddr, SK_ADDR_PERMANENT); + + if (pAC->Rlmt.Net[Para.Para32[1]].RlmtState != SK_RLMT_RS_INIT) { + if (!pAC->Rlmt.Net[Para.Para32[1]].Port[i]->LinkDown && + (Para2.pParaPtr = SkRlmtBuildSpanningTreePacket( + pAC, IoC, i)) != NULL) { + pAC->Rlmt.Net[Para.Para32[1]].Port[i]->RootIdSet = + SK_FALSE; + SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para2); + } + } + } + (void)SkAddrMcUpdate(pAC, IoC, + pAC->Rlmt.Net[Para.Para32[1]].Port[i]->PortNumber); + } /* for ... */ + + if ((pAC->Rlmt.Net[Para.Para32[1]].RlmtMode & SK_RLMT_CHECK_SEG) != 0) { + Para2.Para32[0] = Para.Para32[1]; + Para2.Para32[1] = (SK_U32)-1; + SkTimerStart(pAC, IoC, &pAC->Rlmt.Net[Para.Para32[1]].SegTimer, + SK_RLMT_SEG_TO_VAL, SKGE_RLMT, SK_RLMT_SEG_TIM, Para2); + } + } /* SK_RLMT_CHECK_SEG bit changed. */ + + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_MODE_CHANGE Event END.\n")) +} /* SkRlmtEvtModeChange */ + + +/****************************************************************************** + * + * SkRlmtEvent - a PORT- or an RLMT-specific event happened + * + * Description: + * This routine calls subroutines to handle PORT- and RLMT-specific events. + * + * Context: + * runtime, pageable? + * may be called after SK_INIT_IO + * + * Returns: + * 0 + */ +int SkRlmtEvent( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_U32 Event, /* Event code */ +SK_EVPARA Para) /* Event-specific parameter */ +{ + switch (Event) { + + /* ----- PORT events ----- */ + + case SK_RLMT_PORTSTART_TIM: /* From RLMT via TIME. */ + SkRlmtEvtPortStartTim(pAC, IoC, Para); + break; + case SK_RLMT_LINK_UP: /* From SIRQ. */ + SkRlmtEvtLinkUp(pAC, IoC, Para); + break; + case SK_RLMT_PORTUP_TIM: /* From RLMT via TIME. */ + SkRlmtEvtPortUpTim(pAC, IoC, Para); + break; + case SK_RLMT_PORTDOWN: /* From RLMT. */ + case SK_RLMT_PORTDOWN_RX_TIM: /* From RLMT via TIME. */ + case SK_RLMT_PORTDOWN_TX_TIM: /* From RLMT via TIME. */ + SkRlmtEvtPortDownX(pAC, IoC, Event, Para); + break; + case SK_RLMT_LINK_DOWN: /* From SIRQ. */ + SkRlmtEvtLinkDown(pAC, IoC, Para); + break; + case SK_RLMT_PORT_ADDR: /* From ADDR. */ + SkRlmtEvtPortAddr(pAC, IoC, Para); + break; + + /* ----- RLMT events ----- */ + + case SK_RLMT_START: /* From DRV. */ + SkRlmtEvtStart(pAC, IoC, Para); + break; + case SK_RLMT_STOP: /* From DRV. */ + SkRlmtEvtStop(pAC, IoC, Para); + break; + case SK_RLMT_TIM: /* From RLMT via TIME. */ + SkRlmtEvtTim(pAC, IoC, Para); + break; + case SK_RLMT_SEG_TIM: + SkRlmtEvtSegTim(pAC, IoC, Para); + break; + case SK_RLMT_PACKET_RECEIVED: /* From DRV. */ + SkRlmtEvtPacketRx(pAC, IoC, Para); + break; + case SK_RLMT_STATS_CLEAR: /* From PNMI. */ + SkRlmtEvtStatsClear(pAC, IoC, Para); + break; + case SK_RLMT_STATS_UPDATE: /* From PNMI. */ + SkRlmtEvtStatsUpdate(pAC, IoC, Para); + break; + case SK_RLMT_PREFPORT_CHANGE: /* From PNMI. */ + SkRlmtEvtPrefportChange(pAC, IoC, Para); + break; + case SK_RLMT_MODE_CHANGE: /* From PNMI. */ + SkRlmtEvtModeChange(pAC, IoC, Para); + break; + case SK_RLMT_SET_NETS: /* From DRV. */ + SkRlmtEvtSetNets(pAC, IoC, Para); + break; + + /* ----- Unknown events ----- */ + + default: /* Create error log entry. */ + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("Unknown RLMT Event %d.\n", Event)) + SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_RLMT_E003, SKERR_RLMT_E003_MSG); + break; + } /* switch() */ + + return (0); +} /* SkRlmtEvent */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ diff --git a/drivers/net/sk98lin/sktimer.c b/drivers/net/sk98lin/sktimer.c new file mode 100644 index 000000000000..4e462955ecd8 --- /dev/null +++ b/drivers/net/sk98lin/sktimer.c @@ -0,0 +1,250 @@ +/****************************************************************************** + * + * Name: sktimer.c + * Project: Gigabit Ethernet Adapters, Event Scheduler Module + * Version: $Revision: 1.14 $ + * Date: $Date: 2003/09/16 13:46:51 $ + * Purpose: High level timer functions. + * + ******************************************************************************/ + +/****************************************************************************** + * + * (C)Copyright 1998-2002 SysKonnect GmbH. + * (C)Copyright 2002-2003 Marvell. + * + * 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. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + + +/* + * Event queue and dispatcher + */ +#if (defined(DEBUG) || ((!defined(LINT)) && (!defined(SK_SLIM)))) +static const char SysKonnectFileId[] = + "@(#) $Id: sktimer.c,v 1.14 2003/09/16 13:46:51 rschmidt Exp $ (C) Marvell."; +#endif + +#include "h/skdrv1st.h" /* Driver Specific Definitions */ +#include "h/skdrv2nd.h" /* Adapter Control- and Driver specific Def. */ + +#ifdef __C2MAN__ +/* + Event queue management. + + General Description: + + */ +intro() +{} +#endif + + +/* Forward declaration */ +static void timer_done(SK_AC *pAC,SK_IOC Ioc,int Restart); + + +/* + * Inits the software timer + * + * needs to be called during Init level 1. + */ +void SkTimerInit( +SK_AC *pAC, /* Adapters context */ +SK_IOC Ioc, /* IoContext */ +int Level) /* Init Level */ +{ + switch (Level) { + case SK_INIT_DATA: + pAC->Tim.StQueue = NULL; + break; + case SK_INIT_IO: + SkHwtInit(pAC, Ioc); + SkTimerDone(pAC, Ioc); + break; + default: + break; + } +} + +/* + * Stops a high level timer + * - If a timer is not in the queue the function returns normally, too. + */ +void SkTimerStop( +SK_AC *pAC, /* Adapters context */ +SK_IOC Ioc, /* IoContext */ +SK_TIMER *pTimer) /* Timer Pointer to be started */ +{ + SK_TIMER **ppTimPrev; + SK_TIMER *pTm; + + /* + * remove timer from queue + */ + pTimer->TmActive = SK_FALSE; + + if (pAC->Tim.StQueue == pTimer && !pTimer->TmNext) { + SkHwtStop(pAC, Ioc); + } + + for (ppTimPrev = &pAC->Tim.StQueue; (pTm = *ppTimPrev); + ppTimPrev = &pTm->TmNext ) { + + if (pTm == pTimer) { + /* + * Timer found in queue + * - dequeue it and + * - correct delta of the next timer + */ + *ppTimPrev = pTm->TmNext; + + if (pTm->TmNext) { + /* correct delta of next timer in queue */ + pTm->TmNext->TmDelta += pTm->TmDelta; + } + return; + } + } +} + +/* + * Start a high level software timer + */ +void SkTimerStart( +SK_AC *pAC, /* Adapters context */ +SK_IOC Ioc, /* IoContext */ +SK_TIMER *pTimer, /* Timer Pointer to be started */ +SK_U32 Time, /* Time value */ +SK_U32 Class, /* Event Class for this timer */ +SK_U32 Event, /* Event Value for this timer */ +SK_EVPARA Para) /* Event Parameter for this timer */ +{ + SK_TIMER **ppTimPrev; + SK_TIMER *pTm; + SK_U32 Delta; + + Time /= 16; /* input is uS, clock ticks are 16uS */ + + if (!Time) + Time = 1; + + SkTimerStop(pAC, Ioc, pTimer); + + pTimer->TmClass = Class; + pTimer->TmEvent = Event; + pTimer->TmPara = Para; + pTimer->TmActive = SK_TRUE; + + if (!pAC->Tim.StQueue) { + /* First Timer to be started */ + pAC->Tim.StQueue = pTimer; + pTimer->TmNext = NULL; + pTimer->TmDelta = Time; + + SkHwtStart(pAC, Ioc, Time); + + return; + } + + /* + * timer correction + */ + timer_done(pAC, Ioc, 0); + + /* + * find position in queue + */ + Delta = 0; + for (ppTimPrev = &pAC->Tim.StQueue; (pTm = *ppTimPrev); + ppTimPrev = &pTm->TmNext ) { + + if (Delta + pTm->TmDelta > Time) { + /* Position found */ + /* Here the timer needs to be inserted. */ + break; + } + Delta += pTm->TmDelta; + } + + /* insert in queue */ + *ppTimPrev = pTimer; + pTimer->TmNext = pTm; + pTimer->TmDelta = Time - Delta; + + if (pTm) { + /* There is a next timer + * -> correct its Delta value. + */ + pTm->TmDelta -= pTimer->TmDelta; + } + + /* restart with first */ + SkHwtStart(pAC, Ioc, pAC->Tim.StQueue->TmDelta); +} + + +void SkTimerDone( +SK_AC *pAC, /* Adapters context */ +SK_IOC Ioc) /* IoContext */ +{ + timer_done(pAC, Ioc, 1); +} + + +static void timer_done( +SK_AC *pAC, /* Adapters context */ +SK_IOC Ioc, /* IoContext */ +int Restart) /* Do we need to restart the Hardware timer ? */ +{ + SK_U32 Delta; + SK_TIMER *pTm; + SK_TIMER *pTComp; /* Timer completed now now */ + SK_TIMER **ppLast; /* Next field of Last timer to be deq */ + int Done = 0; + + Delta = SkHwtRead(pAC, Ioc); + + ppLast = &pAC->Tim.StQueue; + pTm = pAC->Tim.StQueue; + while (pTm && !Done) { + if (Delta >= pTm->TmDelta) { + /* Timer ran out */ + pTm->TmActive = SK_FALSE; + Delta -= pTm->TmDelta; + ppLast = &pTm->TmNext; + pTm = pTm->TmNext; + } + else { + /* We found the first timer that did not run out */ + pTm->TmDelta -= Delta; + Delta = 0; + Done = 1; + } + } + *ppLast = NULL; + /* + * pTm points to the first Timer that did not run out. + * StQueue points to the first Timer that run out. + */ + + for ( pTComp = pAC->Tim.StQueue; pTComp; pTComp = pTComp->TmNext) { + SkEventQueue(pAC,pTComp->TmClass, pTComp->TmEvent, pTComp->TmPara); + } + + /* Set head of timer queue to the first timer that did not run out */ + pAC->Tim.StQueue = pTm; + + if (Restart && pAC->Tim.StQueue) { + /* Restart HW timer */ + SkHwtStart(pAC, Ioc, pAC->Tim.StQueue->TmDelta); + } +} + +/* End of file */ diff --git a/drivers/net/sk98lin/skvpd.c b/drivers/net/sk98lin/skvpd.c new file mode 100644 index 000000000000..1e662aaebf84 --- /dev/null +++ b/drivers/net/sk98lin/skvpd.c @@ -0,0 +1,1091 @@ +/****************************************************************************** + * + * Name: skvpd.c + * Project: GEnesis, PCI Gigabit Ethernet Adapter + * Version: $Revision: 1.37 $ + * Date: $Date: 2003/01/13 10:42:45 $ + * Purpose: Shared software to read and write VPD data + * + ******************************************************************************/ + +/****************************************************************************** + * + * (C)Copyright 1998-2003 SysKonnect GmbH. + * + * 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. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/* + Please refer skvpd.txt for information how to include this module + */ +static const char SysKonnectFileId[] = + "@(#)$Id: skvpd.c,v 1.37 2003/01/13 10:42:45 rschmidt Exp $ (C) SK"; + +#include "h/skdrv1st.h" +#include "h/sktypes.h" +#include "h/skdebug.h" +#include "h/skdrv2nd.h" + +/* + * Static functions + */ +#ifndef SK_KR_PROTO +static SK_VPD_PARA *vpd_find_para( + SK_AC *pAC, + const char *key, + SK_VPD_PARA *p); +#else /* SK_KR_PROTO */ +static SK_VPD_PARA *vpd_find_para(); +#endif /* SK_KR_PROTO */ + +/* + * waits for a completion of a VPD transfer + * The VPD transfer must complete within SK_TICKS_PER_SEC/16 + * + * returns 0: success, transfer completes + * error exit(9) with a error message + */ +static int VpdWait( +SK_AC *pAC, /* Adapters context */ +SK_IOC IoC, /* IO Context */ +int event) /* event to wait for (VPD_READ / VPD_write) completion*/ +{ + SK_U64 start_time; + SK_U16 state; + + SK_DBG_MSG(pAC,SK_DBGMOD_VPD, SK_DBGCAT_CTRL, + ("VPD wait for %s\n", event?"Write":"Read")); + start_time = SkOsGetTime(pAC); + do { + if (SkOsGetTime(pAC) - start_time > SK_TICKS_PER_SEC) { + + /* Bug fix AF: Thu Mar 28 2002 + * Do not call: VPD_STOP(pAC, IoC); + * A pending VPD read cycle can not be aborted by writing + * VPD_WRITE to the PCI_VPD_ADR_REG (VPD address register). + * Although the write threshold in the OUR-register protects + * VPD read only space from being overwritten this does not + * protect a VPD read from being `converted` into a VPD write + * operation (on the fly). As a consequence the VPD_STOP would + * delete VPD read only data. In case of any problems with the + * I2C bus we exit the loop here. The I2C read operation can + * not be aborted except by a reset (->LR). + */ + SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_FATAL | SK_DBGCAT_ERR, + ("ERROR:VPD wait timeout\n")); + return(1); + } + + VPD_IN16(pAC, IoC, PCI_VPD_ADR_REG, &state); + + SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL, + ("state = %x, event %x\n",state,event)); + } while((int)(state & PCI_VPD_FLAG) == event); + + return(0); +} + +#ifdef SKDIAG + +/* + * Read the dword at address 'addr' from the VPD EEPROM. + * + * Needed Time: MIN 1,3 ms MAX 2,6 ms + * + * Note: The DWord is returned in the endianess of the machine the routine + * is running on. + * + * Returns the data read. + */ +SK_U32 VpdReadDWord( +SK_AC *pAC, /* Adapters context */ +SK_IOC IoC, /* IO Context */ +int addr) /* VPD address */ +{ + SK_U32 Rtv; + + /* start VPD read */ + SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL, + ("VPD read dword at 0x%x\n",addr)); + addr &= ~VPD_WRITE; /* ensure the R/W bit is set to read */ + + VPD_OUT16(pAC, IoC, PCI_VPD_ADR_REG, (SK_U16)addr); + + /* ignore return code here */ + (void)VpdWait(pAC, IoC, VPD_READ); + + /* Don't swap here, it's a data stream of bytes */ + Rtv = 0; + + VPD_IN32(pAC, IoC, PCI_VPD_DAT_REG, &Rtv); + + SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL, + ("VPD read dword data = 0x%x\n",Rtv)); + return(Rtv); +} + +#endif /* SKDIAG */ + +/* + * Read one Stream of 'len' bytes of VPD data, starting at 'addr' from + * or to the I2C EEPROM. + * + * Returns number of bytes read / written. + */ +static int VpdWriteStream( +SK_AC *pAC, /* Adapters context */ +SK_IOC IoC, /* IO Context */ +char *buf, /* data buffer */ +int Addr, /* VPD start address */ +int Len) /* number of bytes to read / to write */ +{ + int i; + int j; + SK_U16 AdrReg; + int Rtv; + SK_U8 * pComp; /* Compare pointer */ + SK_U8 Data; /* Input Data for Compare */ + + /* Init Compare Pointer */ + pComp = (SK_U8 *) buf; + + for (i = 0; i < Len; i++, buf++) { + if ((i%sizeof(SK_U32)) == 0) { + /* + * At the begin of each cycle read the Data Reg + * So it is initialized even if only a few bytes + * are written. + */ + AdrReg = (SK_U16) Addr; + AdrReg &= ~VPD_WRITE; /* READ operation */ + + VPD_OUT16(pAC, IoC, PCI_VPD_ADR_REG, AdrReg); + + /* Wait for termination */ + Rtv = VpdWait(pAC, IoC, VPD_READ); + if (Rtv != 0) { + return(i); + } + } + + /* Write current Byte */ + VPD_OUT8(pAC, IoC, PCI_VPD_DAT_REG + (i%sizeof(SK_U32)), + *(SK_U8*)buf); + + if (((i%sizeof(SK_U32)) == 3) || (i == (Len - 1))) { + /* New Address needs to be written to VPD_ADDR reg */ + AdrReg = (SK_U16) Addr; + Addr += sizeof(SK_U32); + AdrReg |= VPD_WRITE; /* WRITE operation */ + + VPD_OUT16(pAC, IoC, PCI_VPD_ADR_REG, AdrReg); + + /* Wait for termination */ + Rtv = VpdWait(pAC, IoC, VPD_WRITE); + if (Rtv != 0) { + SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR, + ("Write Timed Out\n")); + return(i - (i%sizeof(SK_U32))); + } + + /* + * Now re-read to verify + */ + AdrReg &= ~VPD_WRITE; /* READ operation */ + + VPD_OUT16(pAC, IoC, PCI_VPD_ADR_REG, AdrReg); + + /* Wait for termination */ + Rtv = VpdWait(pAC, IoC, VPD_READ); + if (Rtv != 0) { + SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR, + ("Verify Timed Out\n")); + return(i - (i%sizeof(SK_U32))); + } + + for (j = 0; j <= (int)(i%sizeof(SK_U32)); j++, pComp++) { + + VPD_IN8(pAC, IoC, PCI_VPD_DAT_REG + j, &Data); + + if (Data != *pComp) { + /* Verify Error */ + SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR, + ("WriteStream Verify Error\n")); + return(i - (i%sizeof(SK_U32)) + j); + } + } + } + } + + return(Len); +} + + +/* + * Read one Stream of 'len' bytes of VPD data, starting at 'addr' from + * or to the I2C EEPROM. + * + * Returns number of bytes read / written. + */ +static int VpdReadStream( +SK_AC *pAC, /* Adapters context */ +SK_IOC IoC, /* IO Context */ +char *buf, /* data buffer */ +int Addr, /* VPD start address */ +int Len) /* number of bytes to read / to write */ +{ + int i; + SK_U16 AdrReg; + int Rtv; + + for (i = 0; i < Len; i++, buf++) { + if ((i%sizeof(SK_U32)) == 0) { + /* New Address needs to be written to VPD_ADDR reg */ + AdrReg = (SK_U16) Addr; + Addr += sizeof(SK_U32); + AdrReg &= ~VPD_WRITE; /* READ operation */ + + VPD_OUT16(pAC, IoC, PCI_VPD_ADR_REG, AdrReg); + + /* Wait for termination */ + Rtv = VpdWait(pAC, IoC, VPD_READ); + if (Rtv != 0) { + return(i); + } + } + VPD_IN8(pAC, IoC, PCI_VPD_DAT_REG + (i%sizeof(SK_U32)), + (SK_U8 *)buf); + } + + return(Len); +} + +/* + * Read ore writes 'len' bytes of VPD data, starting at 'addr' from + * or to the I2C EEPROM. + * + * Returns number of bytes read / written. + */ +static int VpdTransferBlock( +SK_AC *pAC, /* Adapters context */ +SK_IOC IoC, /* IO Context */ +char *buf, /* data buffer */ +int addr, /* VPD start address */ +int len, /* number of bytes to read / to write */ +int dir) /* transfer direction may be VPD_READ or VPD_WRITE */ +{ + int Rtv; /* Return value */ + int vpd_rom_size; + + SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL, + ("VPD %s block, addr = 0x%x, len = %d\n", + dir ? "write" : "read", addr, len)); + + if (len == 0) + return(0); + + vpd_rom_size = pAC->vpd.rom_size; + + if (addr > vpd_rom_size - 4) { + SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR | SK_DBGCAT_FATAL, + ("Address error: 0x%x, exp. < 0x%x\n", + addr, vpd_rom_size - 4)); + return(0); + } + + if (addr + len > vpd_rom_size) { + len = vpd_rom_size - addr; + SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR, + ("Warning: len was cut to %d\n", len)); + } + + if (dir == VPD_READ) { + Rtv = VpdReadStream(pAC, IoC, buf, addr, len); + } + else { + Rtv = VpdWriteStream(pAC, IoC, buf, addr, len); + } + + return(Rtv); +} + +#ifdef SKDIAG + +/* + * Read 'len' bytes of VPD data, starting at 'addr'. + * + * Returns number of bytes read. + */ +int VpdReadBlock( +SK_AC *pAC, /* pAC pointer */ +SK_IOC IoC, /* IO Context */ +char *buf, /* buffer were the data should be stored */ +int addr, /* start reading at the VPD address */ +int len) /* number of bytes to read */ +{ + return(VpdTransferBlock(pAC, IoC, buf, addr, len, VPD_READ)); +} + +/* + * Write 'len' bytes of *but to the VPD EEPROM, starting at 'addr'. + * + * Returns number of bytes writes. + */ +int VpdWriteBlock( +SK_AC *pAC, /* pAC pointer */ +SK_IOC IoC, /* IO Context */ +char *buf, /* buffer, holds the data to write */ +int addr, /* start writing at the VPD address */ +int len) /* number of bytes to write */ +{ + return(VpdTransferBlock(pAC, IoC, buf, addr, len, VPD_WRITE)); +} +#endif /* SKDIAG */ + +/* + * (re)initialize the VPD buffer + * + * Reads the VPD data from the EEPROM into the VPD buffer. + * Get the remaining read only and read / write space. + * + * return 0: success + * 1: fatal VPD error + */ +static int VpdInit( +SK_AC *pAC, /* Adapters context */ +SK_IOC IoC) /* IO Context */ +{ + SK_VPD_PARA *r, rp; /* RW or RV */ + int i; + unsigned char x; + int vpd_size; + SK_U16 dev_id; + SK_U32 our_reg2; + + SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_INIT, ("VpdInit .. ")); + + VPD_IN16(pAC, IoC, PCI_DEVICE_ID, &dev_id); + + VPD_IN32(pAC, IoC, PCI_OUR_REG_2, &our_reg2); + + pAC->vpd.rom_size = 256 << ((our_reg2 & PCI_VPD_ROM_SZ) >> 14); + + /* + * this function might get used before the hardware is initialized + * therefore we cannot always trust in GIChipId + */ + if (((pAC->vpd.v.vpd_status & VPD_VALID) == 0 && + dev_id != VPD_DEV_ID_GENESIS) || + ((pAC->vpd.v.vpd_status & VPD_VALID) != 0 && + !pAC->GIni.GIGenesis)) { + + /* for Yukon the VPD size is always 256 */ + vpd_size = VPD_SIZE_YUKON; + } + else { + /* Genesis uses the maximum ROM size up to 512 for VPD */ + if (pAC->vpd.rom_size > VPD_SIZE_GENESIS) { + vpd_size = VPD_SIZE_GENESIS; + } + else { + vpd_size = pAC->vpd.rom_size; + } + } + + /* read the VPD data into the VPD buffer */ + if (VpdTransferBlock(pAC, IoC, pAC->vpd.vpd_buf, 0, vpd_size, VPD_READ) + != vpd_size) { + + SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR, + ("Block Read Error\n")); + return(1); + } + + pAC->vpd.vpd_size = vpd_size; + + /* Asus K8V Se Deluxe bugfix. Correct VPD content */ + /* MBo April 2004 */ + if (((unsigned char)pAC->vpd.vpd_buf[0x3f] == 0x38) && + ((unsigned char)pAC->vpd.vpd_buf[0x40] == 0x3c) && + ((unsigned char)pAC->vpd.vpd_buf[0x41] == 0x45)) { + printk("sk98lin: Asus mainboard with buggy VPD? " + "Correcting data.\n"); + pAC->vpd.vpd_buf[0x40] = 0x38; + } + + + /* find the end tag of the RO area */ + if (!(r = vpd_find_para(pAC, VPD_RV, &rp))) { + SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR | SK_DBGCAT_FATAL, + ("Encoding Error: RV Tag not found\n")); + return(1); + } + + if (r->p_val + r->p_len > pAC->vpd.vpd_buf + vpd_size/2) { + SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR | SK_DBGCAT_FATAL, + ("Encoding Error: Invalid VPD struct size\n")); + return(1); + } + pAC->vpd.v.vpd_free_ro = r->p_len - 1; + + /* test the checksum */ + for (i = 0, x = 0; (unsigned)i <= (unsigned)vpd_size/2 - r->p_len; i++) { + x += pAC->vpd.vpd_buf[i]; + } + + if (x != 0) { + /* checksum error */ + SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR | SK_DBGCAT_FATAL, + ("VPD Checksum Error\n")); + return(1); + } + + /* find and check the end tag of the RW area */ + if (!(r = vpd_find_para(pAC, VPD_RW, &rp))) { + SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR | SK_DBGCAT_FATAL, + ("Encoding Error: RV Tag not found\n")); + return(1); + } + + if (r->p_val < pAC->vpd.vpd_buf + vpd_size/2) { + SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR | SK_DBGCAT_FATAL, + ("Encoding Error: Invalid VPD struct size\n")); + return(1); + } + pAC->vpd.v.vpd_free_rw = r->p_len; + + /* everything seems to be ok */ + if (pAC->GIni.GIChipId != 0) { + pAC->vpd.v.vpd_status |= VPD_VALID; + } + + SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_INIT, + ("done. Free RO = %d, Free RW = %d\n", + pAC->vpd.v.vpd_free_ro, pAC->vpd.v.vpd_free_rw)); + + return(0); +} + +/* + * find the Keyword 'key' in the VPD buffer and fills the + * parameter struct 'p' with it's values + * + * returns *p success + * 0: parameter was not found or VPD encoding error + */ +static SK_VPD_PARA *vpd_find_para( +SK_AC *pAC, /* common data base */ +const char *key, /* keyword to find (e.g. "MN") */ +SK_VPD_PARA *p) /* parameter description struct */ +{ + char *v ; /* points to VPD buffer */ + int max; /* Maximum Number of Iterations */ + + v = pAC->vpd.vpd_buf; + max = 128; + + SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL, + ("VPD find para %s .. ",key)); + + /* check mandatory resource type ID string (Product Name) */ + if (*v != (char)RES_ID) { + SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR | SK_DBGCAT_FATAL, + ("Error: 0x%x missing\n", RES_ID)); + return NULL; + } + + if (strcmp(key, VPD_NAME) == 0) { + p->p_len = VPD_GET_RES_LEN(v); + p->p_val = VPD_GET_VAL(v); + SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL, + ("found, len = %d\n", p->p_len)); + return(p); + } + + v += 3 + VPD_GET_RES_LEN(v) + 3; + for (;; ) { + if (SK_MEMCMP(key,v,2) == 0) { + p->p_len = VPD_GET_VPD_LEN(v); + p->p_val = VPD_GET_VAL(v); + SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL, + ("found, len = %d\n",p->p_len)); + return(p); + } + + /* exit when reaching the "RW" Tag or the maximum of itera. */ + max--; + if (SK_MEMCMP(VPD_RW,v,2) == 0 || max == 0) { + break; + } + + if (SK_MEMCMP(VPD_RV,v,2) == 0) { + v += 3 + VPD_GET_VPD_LEN(v) + 3; /* skip VPD-W */ + } + else { + v += 3 + VPD_GET_VPD_LEN(v); + } + SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL, + ("scanning '%c%c' len = %d\n",v[0],v[1],v[2])); + } + +#ifdef DEBUG + SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL, ("not found\n")); + if (max == 0) { + SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR | SK_DBGCAT_FATAL, + ("Key/Len Encoding error\n")); + } +#endif /* DEBUG */ + return NULL; +} + +/* + * Move 'n' bytes. Begin with the last byte if 'n' is > 0, + * Start with the last byte if n is < 0. + * + * returns nothing + */ +static void vpd_move_para( +char *start, /* start of memory block */ +char *end, /* end of memory block to move */ +int n) /* number of bytes the memory block has to be moved */ +{ + char *p; + int i; /* number of byte copied */ + + if (n == 0) + return; + + i = (int) (end - start + 1); + if (n < 0) { + p = start + n; + while (i != 0) { + *p++ = *start++; + i--; + } + } + else { + p = end + n; + while (i != 0) { + *p-- = *end--; + i--; + } + } +} + +/* + * setup the VPD keyword 'key' at 'ip'. + * + * returns nothing + */ +static void vpd_insert_key( +const char *key, /* keyword to insert */ +const char *buf, /* buffer with the keyword value */ +int len, /* length of the value string */ +char *ip) /* inseration point */ +{ + SK_VPD_KEY *p; + + p = (SK_VPD_KEY *) ip; + p->p_key[0] = key[0]; + p->p_key[1] = key[1]; + p->p_len = (unsigned char) len; + SK_MEMCPY(&p->p_val,buf,len); +} + +/* + * Setup the VPD end tag "RV" / "RW". + * Also correct the remaining space variables vpd_free_ro / vpd_free_rw. + * + * returns 0: success + * 1: encoding error + */ +static int vpd_mod_endtag( +SK_AC *pAC, /* common data base */ +char *etp) /* end pointer input position */ +{ + SK_VPD_KEY *p; + unsigned char x; + int i; + int vpd_size; + + SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL, + ("VPD modify endtag at 0x%x = '%c%c'\n",etp,etp[0],etp[1])); + + vpd_size = pAC->vpd.vpd_size; + + p = (SK_VPD_KEY *) etp; + + if (p->p_key[0] != 'R' || (p->p_key[1] != 'V' && p->p_key[1] != 'W')) { + /* something wrong here, encoding error */ + SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR | SK_DBGCAT_FATAL, + ("Encoding Error: invalid end tag\n")); + return(1); + } + if (etp > pAC->vpd.vpd_buf + vpd_size/2) { + /* create "RW" tag */ + p->p_len = (unsigned char)(pAC->vpd.vpd_buf+vpd_size-etp-3-1); + pAC->vpd.v.vpd_free_rw = (int) p->p_len; + i = pAC->vpd.v.vpd_free_rw; + etp += 3; + } + else { + /* create "RV" tag */ + p->p_len = (unsigned char)(pAC->vpd.vpd_buf+vpd_size/2-etp-3); + pAC->vpd.v.vpd_free_ro = (int) p->p_len - 1; + + /* setup checksum */ + for (i = 0, x = 0; i < vpd_size/2 - p->p_len; i++) { + x += pAC->vpd.vpd_buf[i]; + } + p->p_val = (char) 0 - x; + i = pAC->vpd.v.vpd_free_ro; + etp += 4; + } + while (i) { + *etp++ = 0x00; + i--; + } + + return(0); +} + +/* + * Insert a VPD keyword into the VPD buffer. + * + * The keyword 'key' is inserted at the position 'ip' in the + * VPD buffer. + * The keywords behind the input position will + * be moved. The VPD end tag "RV" or "RW" is generated again. + * + * returns 0: success + * 2: value string was cut + * 4: VPD full, keyword was not written + * 6: fatal VPD error + * + */ +static int VpdSetupPara( +SK_AC *pAC, /* common data base */ +const char *key, /* keyword to insert */ +const char *buf, /* buffer with the keyword value */ +int len, /* length of the keyword value */ +int type, /* VPD_RO_KEY or VPD_RW_KEY */ +int op) /* operation to do: ADD_KEY or OWR_KEY */ +{ + SK_VPD_PARA vp; + char *etp; /* end tag position */ + int free; /* remaining space in selected area */ + char *ip; /* input position inside the VPD buffer */ + int rtv; /* return code */ + int head; /* additional haeder bytes to move */ + int found; /* additinoal bytes if the keyword was found */ + int vpd_size; + + SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL, + ("VPD setup para key = %s, val = %s\n",key,buf)); + + vpd_size = pAC->vpd.vpd_size; + + rtv = 0; + ip = NULL; + if (type == VPD_RW_KEY) { + /* end tag is "RW" */ + free = pAC->vpd.v.vpd_free_rw; + etp = pAC->vpd.vpd_buf + (vpd_size - free - 1 - 3); + } + else { + /* end tag is "RV" */ + free = pAC->vpd.v.vpd_free_ro; + etp = pAC->vpd.vpd_buf + (vpd_size/2 - free - 4); + } + SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL, + ("Free RO = %d, Free RW = %d\n", + pAC->vpd.v.vpd_free_ro, pAC->vpd.v.vpd_free_rw)); + + head = 0; + found = 0; + if (op == OWR_KEY) { + if (vpd_find_para(pAC, key, &vp)) { + found = 3; + ip = vp.p_val - 3; + free += vp.p_len + 3; + SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL, + ("Overwrite Key\n")); + } + else { + op = ADD_KEY; + SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL, + ("Add Key\n")); + } + } + if (op == ADD_KEY) { + ip = etp; + vp.p_len = 0; + head = 3; + } + + if (len + 3 > free) { + if (free < 7) { + SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR, + ("VPD Buffer Overflow, keyword not written\n")); + return(4); + } + /* cut it again */ + len = free - 3; + rtv = 2; + SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR, + ("VPD Buffer Full, Keyword was cut\n")); + } + + vpd_move_para(ip + vp.p_len + found, etp+2, len-vp.p_len+head); + vpd_insert_key(key, buf, len, ip); + if (vpd_mod_endtag(pAC, etp + len - vp.p_len + head)) { + pAC->vpd.v.vpd_status &= ~VPD_VALID; + SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR, + ("VPD Encoding Error\n")); + return(6); + } + + return(rtv); +} + + +/* + * Read the contents of the VPD EEPROM and copy it to the + * VPD buffer if not already done. + * + * return: A pointer to the vpd_status structure. The structure contains + * this fields. + */ +SK_VPD_STATUS *VpdStat( +SK_AC *pAC, /* Adapters context */ +SK_IOC IoC) /* IO Context */ +{ + if ((pAC->vpd.v.vpd_status & VPD_VALID) == 0) { + (void)VpdInit(pAC, IoC); + } + return(&pAC->vpd.v); +} + + +/* + * Read the contents of the VPD EEPROM and copy it to the VPD + * buffer if not already done. + * Scan the VPD buffer for VPD keywords and create the VPD + * keyword list by copying the keywords to 'buf', all after + * each other and terminated with a '\0'. + * + * Exceptions: o The Resource Type ID String (product name) is called "Name" + * o The VPD end tags 'RV' and 'RW' are not listed + * + * The number of copied keywords is counted in 'elements'. + * + * returns 0: success + * 2: buffer overfull, one or more keywords are missing + * 6: fatal VPD error + * + * example values after returning: + * + * buf = "Name\0PN\0EC\0MN\0SN\0CP\0VF\0VL\0YA\0" + * *len = 30 + * *elements = 9 + */ +int VpdKeys( +SK_AC *pAC, /* common data base */ +SK_IOC IoC, /* IO Context */ +char *buf, /* buffer where to copy the keywords */ +int *len, /* buffer length */ +int *elements) /* number of keywords returned */ +{ + char *v; + int n; + + SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_RX, ("list VPD keys .. ")); + *elements = 0; + if ((pAC->vpd.v.vpd_status & VPD_VALID) == 0) { + if (VpdInit(pAC, IoC) != 0) { + *len = 0; + SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR, + ("VPD Init Error, terminated\n")); + return(6); + } + } + + if ((signed)strlen(VPD_NAME) + 1 <= *len) { + v = pAC->vpd.vpd_buf; + strcpy(buf,VPD_NAME); + n = strlen(VPD_NAME) + 1; + buf += n; + *elements = 1; + SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_RX, + ("'%c%c' ",v[0],v[1])); + } + else { + *len = 0; + SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, + ("buffer overflow\n")); + return(2); + } + + v += 3 + VPD_GET_RES_LEN(v) + 3; + for (;; ) { + /* exit when reaching the "RW" Tag */ + if (SK_MEMCMP(VPD_RW,v,2) == 0) { + break; + } + + if (SK_MEMCMP(VPD_RV,v,2) == 0) { + v += 3 + VPD_GET_VPD_LEN(v) + 3; /* skip VPD-W */ + continue; + } + + if (n+3 <= *len) { + SK_MEMCPY(buf,v,2); + buf += 2; + *buf++ = '\0'; + n += 3; + v += 3 + VPD_GET_VPD_LEN(v); + *elements += 1; + SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_RX, + ("'%c%c' ",v[0],v[1])); + } + else { + *len = n; + SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR, + ("buffer overflow\n")); + return(2); + } + } + + SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_RX, ("\n")); + *len = n; + return(0); +} + + +/* + * Read the contents of the VPD EEPROM and copy it to the + * VPD buffer if not already done. Search for the VPD keyword + * 'key' and copy its value to 'buf'. Add a terminating '\0'. + * If the value does not fit into the buffer cut it after + * 'len' - 1 bytes. + * + * returns 0: success + * 1: keyword not found + * 2: value string was cut + * 3: VPD transfer timeout + * 6: fatal VPD error + */ +int VpdRead( +SK_AC *pAC, /* common data base */ +SK_IOC IoC, /* IO Context */ +const char *key, /* keyword to read (e.g. "MN") */ +char *buf, /* buffer where to copy the keyword value */ +int *len) /* buffer length */ +{ + SK_VPD_PARA *p, vp; + + SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_RX, ("VPD read %s .. ", key)); + if ((pAC->vpd.v.vpd_status & VPD_VALID) == 0) { + if (VpdInit(pAC, IoC) != 0) { + *len = 0; + SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR, + ("VPD init error\n")); + return(6); + } + } + + if ((p = vpd_find_para(pAC, key, &vp)) != NULL) { + if (p->p_len > (*(unsigned *)len)-1) { + p->p_len = *len - 1; + } + SK_MEMCPY(buf, p->p_val, p->p_len); + buf[p->p_len] = '\0'; + *len = p->p_len; + SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_RX, + ("%c%c%c%c.., len = %d\n", + buf[0],buf[1],buf[2],buf[3],*len)); + } + else { + *len = 0; + SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR, ("not found\n")); + return(1); + } + return(0); +} + + +/* + * Check whether a given key may be written + * + * returns + * SK_TRUE Yes it may be written + * SK_FALSE No it may be written + */ +SK_BOOL VpdMayWrite( +char *key) /* keyword to write (allowed values "Yx", "Vx") */ +{ + if ((*key != 'Y' && *key != 'V') || + key[1] < '0' || key[1] > 'Z' || + (key[1] > '9' && key[1] < 'A') || strlen(key) != 2) { + + return(SK_FALSE); + } + return(SK_TRUE); +} + +/* + * Read the contents of the VPD EEPROM and copy it to the VPD + * buffer if not already done. Insert/overwrite the keyword 'key' + * in the VPD buffer. Cut the keyword value if it does not fit + * into the VPD read / write area. + * + * returns 0: success + * 2: value string was cut + * 3: VPD transfer timeout + * 4: VPD full, keyword was not written + * 5: keyword cannot be written + * 6: fatal VPD error + */ +int VpdWrite( +SK_AC *pAC, /* common data base */ +SK_IOC IoC, /* IO Context */ +const char *key, /* keyword to write (allowed values "Yx", "Vx") */ +const char *buf) /* buffer where the keyword value can be read from */ +{ + int len; /* length of the keyword to write */ + int rtv; /* return code */ + int rtv2; + + SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_TX, + ("VPD write %s = %s\n",key,buf)); + + if ((*key != 'Y' && *key != 'V') || + key[1] < '0' || key[1] > 'Z' || + (key[1] > '9' && key[1] < 'A') || strlen(key) != 2) { + + SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR, + ("illegal key tag, keyword not written\n")); + return(5); + } + + if ((pAC->vpd.v.vpd_status & VPD_VALID) == 0) { + if (VpdInit(pAC, IoC) != 0) { + SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR, + ("VPD init error\n")); + return(6); + } + } + + rtv = 0; + len = strlen(buf); + if (len > VPD_MAX_LEN) { + /* cut it */ + len = VPD_MAX_LEN; + rtv = 2; + SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR, + ("keyword too long, cut after %d bytes\n",VPD_MAX_LEN)); + } + if ((rtv2 = VpdSetupPara(pAC, key, buf, len, VPD_RW_KEY, OWR_KEY)) != 0) { + SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR, + ("VPD write error\n")); + return(rtv2); + } + + return(rtv); +} + +/* + * Read the contents of the VPD EEPROM and copy it to the + * VPD buffer if not already done. Remove the VPD keyword + * 'key' from the VPD buffer. + * Only the keywords in the read/write area can be deleted. + * Keywords in the read only area cannot be deleted. + * + * returns 0: success, keyword was removed + * 1: keyword not found + * 5: keyword cannot be deleted + * 6: fatal VPD error + */ +int VpdDelete( +SK_AC *pAC, /* common data base */ +SK_IOC IoC, /* IO Context */ +char *key) /* keyword to read (e.g. "MN") */ +{ + SK_VPD_PARA *p, vp; + char *etp; + int vpd_size; + + vpd_size = pAC->vpd.vpd_size; + + SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX,("VPD delete key %s\n",key)); + if ((pAC->vpd.v.vpd_status & VPD_VALID) == 0) { + if (VpdInit(pAC, IoC) != 0) { + SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR, + ("VPD init error\n")); + return(6); + } + } + + if ((p = vpd_find_para(pAC, key, &vp)) != NULL) { + if (p->p_val < pAC->vpd.vpd_buf + vpd_size/2) { + /* try to delete read only keyword */ + SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR, + ("cannot delete RO keyword\n")); + return(5); + } + + etp = pAC->vpd.vpd_buf + (vpd_size-pAC->vpd.v.vpd_free_rw-1-3); + + vpd_move_para(vp.p_val+vp.p_len, etp+2, + - ((int)(vp.p_len + 3))); + if (vpd_mod_endtag(pAC, etp - vp.p_len - 3)) { + pAC->vpd.v.vpd_status &= ~VPD_VALID; + SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR, + ("VPD encoding error\n")); + return(6); + } + } + else { + SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR, + ("keyword not found\n")); + return(1); + } + + return(0); +} + +/* + * If the VPD buffer contains valid data write the VPD + * read/write area back to the VPD EEPROM. + * + * returns 0: success + * 3: VPD transfer timeout + */ +int VpdUpdate( +SK_AC *pAC, /* Adapters context */ +SK_IOC IoC) /* IO Context */ +{ + int vpd_size; + + vpd_size = pAC->vpd.vpd_size; + + SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_TX, ("VPD update .. ")); + if ((pAC->vpd.v.vpd_status & VPD_VALID) != 0) { + if (VpdTransferBlock(pAC, IoC, pAC->vpd.vpd_buf + vpd_size/2, + vpd_size/2, vpd_size/2, VPD_WRITE) != vpd_size/2) { + + SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR, + ("transfer timed out\n")); + return(3); + } + } + SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_TX, ("done\n")); + return(0); +} + diff --git a/drivers/net/sk98lin/skxmac2.c b/drivers/net/sk98lin/skxmac2.c new file mode 100644 index 000000000000..b4e75022a657 --- /dev/null +++ b/drivers/net/sk98lin/skxmac2.c @@ -0,0 +1,4160 @@ +/****************************************************************************** + * + * Name: skxmac2.c + * Project: Gigabit Ethernet Adapters, Common Modules + * Version: $Revision: 1.102 $ + * Date: $Date: 2003/10/02 16:53:58 $ + * Purpose: Contains functions to initialize the MACs and PHYs + * + ******************************************************************************/ + +/****************************************************************************** + * + * (C)Copyright 1998-2002 SysKonnect. + * (C)Copyright 2002-2003 Marvell. + * + * 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. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +#include "h/skdrv1st.h" +#include "h/skdrv2nd.h" + +/* typedefs *******************************************************************/ + +/* BCOM PHY magic pattern list */ +typedef struct s_PhyHack { + int PhyReg; /* Phy register */ + SK_U16 PhyVal; /* Value to write */ +} BCOM_HACK; + +/* local variables ************************************************************/ + +#if (defined(DEBUG) || ((!defined(LINT)) && (!defined(SK_SLIM)))) +static const char SysKonnectFileId[] = + "@(#) $Id: skxmac2.c,v 1.102 2003/10/02 16:53:58 rschmidt Exp $ (C) Marvell."; +#endif + +#ifdef GENESIS +static BCOM_HACK BcomRegA1Hack[] = { + { 0x18, 0x0c20 }, { 0x17, 0x0012 }, { 0x15, 0x1104 }, { 0x17, 0x0013 }, + { 0x15, 0x0404 }, { 0x17, 0x8006 }, { 0x15, 0x0132 }, { 0x17, 0x8006 }, + { 0x15, 0x0232 }, { 0x17, 0x800D }, { 0x15, 0x000F }, { 0x18, 0x0420 }, + { 0, 0 } +}; +static BCOM_HACK BcomRegC0Hack[] = { + { 0x18, 0x0c20 }, { 0x17, 0x0012 }, { 0x15, 0x1204 }, { 0x17, 0x0013 }, + { 0x15, 0x0A04 }, { 0x18, 0x0420 }, + { 0, 0 } +}; +#endif + +/* function prototypes ********************************************************/ +#ifdef GENESIS +static void SkXmInitPhyXmac(SK_AC*, SK_IOC, int, SK_BOOL); +static void SkXmInitPhyBcom(SK_AC*, SK_IOC, int, SK_BOOL); +static int SkXmAutoNegDoneXmac(SK_AC*, SK_IOC, int); +static int SkXmAutoNegDoneBcom(SK_AC*, SK_IOC, int); +#endif /* GENESIS */ +#ifdef YUKON +static void SkGmInitPhyMarv(SK_AC*, SK_IOC, int, SK_BOOL); +static int SkGmAutoNegDoneMarv(SK_AC*, SK_IOC, int); +#endif /* YUKON */ +#ifdef OTHER_PHY +static void SkXmInitPhyLone(SK_AC*, SK_IOC, int, SK_BOOL); +static void SkXmInitPhyNat (SK_AC*, SK_IOC, int, SK_BOOL); +static int SkXmAutoNegDoneLone(SK_AC*, SK_IOC, int); +static int SkXmAutoNegDoneNat (SK_AC*, SK_IOC, int); +#endif /* OTHER_PHY */ + + +#ifdef GENESIS +/****************************************************************************** + * + * SkXmPhyRead() - Read from XMAC PHY register + * + * Description: reads a 16-bit word from XMAC PHY or ext. PHY + * + * Returns: + * nothing + */ +void SkXmPhyRead( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +int Port, /* Port Index (MAC_1 + n) */ +int PhyReg, /* Register Address (Offset) */ +SK_U16 SK_FAR *pVal) /* Pointer to Value */ +{ + SK_U16 Mmu; + SK_GEPORT *pPrt; + + pPrt = &pAC->GIni.GP[Port]; + + /* write the PHY register's address */ + XM_OUT16(IoC, Port, XM_PHY_ADDR, PhyReg | pPrt->PhyAddr); + + /* get the PHY register's value */ + XM_IN16(IoC, Port, XM_PHY_DATA, pVal); + + if (pPrt->PhyType != SK_PHY_XMAC) { + do { + XM_IN16(IoC, Port, XM_MMU_CMD, &Mmu); + /* wait until 'Ready' is set */ + } while ((Mmu & XM_MMU_PHY_RDY) == 0); + + /* get the PHY register's value */ + XM_IN16(IoC, Port, XM_PHY_DATA, pVal); + } +} /* SkXmPhyRead */ + + +/****************************************************************************** + * + * SkXmPhyWrite() - Write to XMAC PHY register + * + * Description: writes a 16-bit word to XMAC PHY or ext. PHY + * + * Returns: + * nothing + */ +void SkXmPhyWrite( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +int Port, /* Port Index (MAC_1 + n) */ +int PhyReg, /* Register Address (Offset) */ +SK_U16 Val) /* Value */ +{ + SK_U16 Mmu; + SK_GEPORT *pPrt; + + pPrt = &pAC->GIni.GP[Port]; + + if (pPrt->PhyType != SK_PHY_XMAC) { + do { + XM_IN16(IoC, Port, XM_MMU_CMD, &Mmu); + /* wait until 'Busy' is cleared */ + } while ((Mmu & XM_MMU_PHY_BUSY) != 0); + } + + /* write the PHY register's address */ + XM_OUT16(IoC, Port, XM_PHY_ADDR, PhyReg | pPrt->PhyAddr); + + /* write the PHY register's value */ + XM_OUT16(IoC, Port, XM_PHY_DATA, Val); + + if (pPrt->PhyType != SK_PHY_XMAC) { + do { + XM_IN16(IoC, Port, XM_MMU_CMD, &Mmu); + /* wait until 'Busy' is cleared */ + } while ((Mmu & XM_MMU_PHY_BUSY) != 0); + } +} /* SkXmPhyWrite */ +#endif /* GENESIS */ + + +#ifdef YUKON +/****************************************************************************** + * + * SkGmPhyRead() - Read from GPHY register + * + * Description: reads a 16-bit word from GPHY through MDIO + * + * Returns: + * nothing + */ +void SkGmPhyRead( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +int Port, /* Port Index (MAC_1 + n) */ +int PhyReg, /* Register Address (Offset) */ +SK_U16 SK_FAR *pVal) /* Pointer to Value */ +{ + SK_U16 Ctrl; + SK_GEPORT *pPrt; +#ifdef VCPU + u_long SimCyle; + u_long SimLowTime; + + VCPUgetTime(&SimCyle, &SimLowTime); + VCPUprintf(0, "SkGmPhyRead(%u), SimCyle=%u, SimLowTime=%u\n", + PhyReg, SimCyle, SimLowTime); +#endif /* VCPU */ + + pPrt = &pAC->GIni.GP[Port]; + + /* set PHY-Register offset and 'Read' OpCode (= 1) */ + *pVal = (SK_U16)(GM_SMI_CT_PHY_AD(pPrt->PhyAddr) | + GM_SMI_CT_REG_AD(PhyReg) | GM_SMI_CT_OP_RD); + + GM_OUT16(IoC, Port, GM_SMI_CTRL, *pVal); + + GM_IN16(IoC, Port, GM_SMI_CTRL, &Ctrl); + + /* additional check for MDC/MDIO activity */ + if ((Ctrl & GM_SMI_CT_BUSY) == 0) { + *pVal = 0; + return; + } + + *pVal |= GM_SMI_CT_BUSY; + + do { +#ifdef VCPU + VCPUwaitTime(1000); +#endif /* VCPU */ + + GM_IN16(IoC, Port, GM_SMI_CTRL, &Ctrl); + + /* wait until 'ReadValid' is set */ + } while (Ctrl == *pVal); + + /* get the PHY register's value */ + GM_IN16(IoC, Port, GM_SMI_DATA, pVal); + +#ifdef VCPU + VCPUgetTime(&SimCyle, &SimLowTime); + VCPUprintf(0, "VCPUgetTime(), SimCyle=%u, SimLowTime=%u\n", + SimCyle, SimLowTime); +#endif /* VCPU */ + +} /* SkGmPhyRead */ + + +/****************************************************************************** + * + * SkGmPhyWrite() - Write to GPHY register + * + * Description: writes a 16-bit word to GPHY through MDIO + * + * Returns: + * nothing + */ +void SkGmPhyWrite( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +int Port, /* Port Index (MAC_1 + n) */ +int PhyReg, /* Register Address (Offset) */ +SK_U16 Val) /* Value */ +{ + SK_U16 Ctrl; + SK_GEPORT *pPrt; +#ifdef VCPU + SK_U32 DWord; + u_long SimCyle; + u_long SimLowTime; + + VCPUgetTime(&SimCyle, &SimLowTime); + VCPUprintf(0, "SkGmPhyWrite(Reg=%u, Val=0x%04x), SimCyle=%u, SimLowTime=%u\n", + PhyReg, Val, SimCyle, SimLowTime); +#endif /* VCPU */ + + pPrt = &pAC->GIni.GP[Port]; + + /* write the PHY register's value */ + GM_OUT16(IoC, Port, GM_SMI_DATA, Val); + + /* set PHY-Register offset and 'Write' OpCode (= 0) */ + Val = GM_SMI_CT_PHY_AD(pPrt->PhyAddr) | GM_SMI_CT_REG_AD(PhyReg); + + GM_OUT16(IoC, Port, GM_SMI_CTRL, Val); + + GM_IN16(IoC, Port, GM_SMI_CTRL, &Ctrl); + + /* additional check for MDC/MDIO activity */ + if ((Ctrl & GM_SMI_CT_BUSY) == 0) { + return; + } + + Val |= GM_SMI_CT_BUSY; + + do { +#ifdef VCPU + /* read Timer value */ + SK_IN32(IoC, B2_TI_VAL, &DWord); + + VCPUwaitTime(1000); +#endif /* VCPU */ + + GM_IN16(IoC, Port, GM_SMI_CTRL, &Ctrl); + + /* wait until 'Busy' is cleared */ + } while (Ctrl == Val); + +#ifdef VCPU + VCPUgetTime(&SimCyle, &SimLowTime); + VCPUprintf(0, "VCPUgetTime(), SimCyle=%u, SimLowTime=%u\n", + SimCyle, SimLowTime); +#endif /* VCPU */ + +} /* SkGmPhyWrite */ +#endif /* YUKON */ + + +#ifdef SK_DIAG +/****************************************************************************** + * + * SkGePhyRead() - Read from PHY register + * + * Description: calls a read PHY routine dep. on board type + * + * Returns: + * nothing + */ +void SkGePhyRead( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +int Port, /* Port Index (MAC_1 + n) */ +int PhyReg, /* Register Address (Offset) */ +SK_U16 *pVal) /* Pointer to Value */ +{ + void (*r_func)(SK_AC *pAC, SK_IOC IoC, int Port, int Reg, SK_U16 *pVal); + + if (pAC->GIni.GIGenesis) { + r_func = SkXmPhyRead; + } + else { + r_func = SkGmPhyRead; + } + + r_func(pAC, IoC, Port, PhyReg, pVal); +} /* SkGePhyRead */ + + +/****************************************************************************** + * + * SkGePhyWrite() - Write to PHY register + * + * Description: calls a write PHY routine dep. on board type + * + * Returns: + * nothing + */ +void SkGePhyWrite( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +int Port, /* Port Index (MAC_1 + n) */ +int PhyReg, /* Register Address (Offset) */ +SK_U16 Val) /* Value */ +{ + void (*w_func)(SK_AC *pAC, SK_IOC IoC, int Port, int Reg, SK_U16 Val); + + if (pAC->GIni.GIGenesis) { + w_func = SkXmPhyWrite; + } + else { + w_func = SkGmPhyWrite; + } + + w_func(pAC, IoC, Port, PhyReg, Val); +} /* SkGePhyWrite */ +#endif /* SK_DIAG */ + + +/****************************************************************************** + * + * SkMacPromiscMode() - Enable / Disable Promiscuous Mode + * + * Description: + * enables / disables promiscuous mode by setting Mode Register (XMAC) or + * Receive Control Register (GMAC) dep. on board type + * + * Returns: + * nothing + */ +void SkMacPromiscMode( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port, /* Port Index (MAC_1 + n) */ +SK_BOOL Enable) /* Enable / Disable */ +{ +#ifdef YUKON + SK_U16 RcReg; +#endif +#ifdef GENESIS + SK_U32 MdReg; +#endif + +#ifdef GENESIS + if (pAC->GIni.GIGenesis) { + + XM_IN32(IoC, Port, XM_MODE, &MdReg); + /* enable or disable promiscuous mode */ + if (Enable) { + MdReg |= XM_MD_ENA_PROM; + } + else { + MdReg &= ~XM_MD_ENA_PROM; + } + /* setup Mode Register */ + XM_OUT32(IoC, Port, XM_MODE, MdReg); + } +#endif /* GENESIS */ + +#ifdef YUKON + if (pAC->GIni.GIYukon) { + + GM_IN16(IoC, Port, GM_RX_CTRL, &RcReg); + + /* enable or disable unicast and multicast filtering */ + if (Enable) { + RcReg &= ~(GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA); + } + else { + RcReg |= (GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA); + } + /* setup Receive Control Register */ + GM_OUT16(IoC, Port, GM_RX_CTRL, RcReg); + } +#endif /* YUKON */ + +} /* SkMacPromiscMode*/ + + +/****************************************************************************** + * + * SkMacHashing() - Enable / Disable Hashing + * + * Description: + * enables / disables hashing by setting Mode Register (XMAC) or + * Receive Control Register (GMAC) dep. on board type + * + * Returns: + * nothing + */ +void SkMacHashing( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port, /* Port Index (MAC_1 + n) */ +SK_BOOL Enable) /* Enable / Disable */ +{ +#ifdef YUKON + SK_U16 RcReg; +#endif +#ifdef GENESIS + SK_U32 MdReg; +#endif + +#ifdef GENESIS + if (pAC->GIni.GIGenesis) { + + XM_IN32(IoC, Port, XM_MODE, &MdReg); + /* enable or disable hashing */ + if (Enable) { + MdReg |= XM_MD_ENA_HASH; + } + else { + MdReg &= ~XM_MD_ENA_HASH; + } + /* setup Mode Register */ + XM_OUT32(IoC, Port, XM_MODE, MdReg); + } +#endif /* GENESIS */ + +#ifdef YUKON + if (pAC->GIni.GIYukon) { + + GM_IN16(IoC, Port, GM_RX_CTRL, &RcReg); + + /* enable or disable multicast filtering */ + if (Enable) { + RcReg |= GM_RXCR_MCF_ENA; + } + else { + RcReg &= ~GM_RXCR_MCF_ENA; + } + /* setup Receive Control Register */ + GM_OUT16(IoC, Port, GM_RX_CTRL, RcReg); + } +#endif /* YUKON */ + +} /* SkMacHashing*/ + + +#ifdef SK_DIAG +/****************************************************************************** + * + * SkXmSetRxCmd() - Modify the value of the XMAC's Rx Command Register + * + * Description: + * The features + * - FCS stripping, SK_STRIP_FCS_ON/OFF + * - pad byte stripping, SK_STRIP_PAD_ON/OFF + * - don't set XMR_FS_ERR in status SK_LENERR_OK_ON/OFF + * for inrange length error frames + * - don't set XMR_FS_ERR in status SK_BIG_PK_OK_ON/OFF + * for frames > 1514 bytes + * - enable Rx of own packets SK_SELF_RX_ON/OFF + * + * for incoming packets may be enabled/disabled by this function. + * Additional modes may be added later. + * Multiple modes can be enabled/disabled at the same time. + * The new configuration is written to the Rx Command register immediately. + * + * Returns: + * nothing + */ +static void SkXmSetRxCmd( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port, /* Port Index (MAC_1 + n) */ +int Mode) /* Mode is SK_STRIP_FCS_ON/OFF, SK_STRIP_PAD_ON/OFF, + SK_LENERR_OK_ON/OFF, or SK_BIG_PK_OK_ON/OFF */ +{ + SK_U16 OldRxCmd; + SK_U16 RxCmd; + + XM_IN16(IoC, Port, XM_RX_CMD, &OldRxCmd); + + RxCmd = OldRxCmd; + + switch (Mode & (SK_STRIP_FCS_ON | SK_STRIP_FCS_OFF)) { + case SK_STRIP_FCS_ON: + RxCmd |= XM_RX_STRIP_FCS; + break; + case SK_STRIP_FCS_OFF: + RxCmd &= ~XM_RX_STRIP_FCS; + break; + } + + switch (Mode & (SK_STRIP_PAD_ON | SK_STRIP_PAD_OFF)) { + case SK_STRIP_PAD_ON: + RxCmd |= XM_RX_STRIP_PAD; + break; + case SK_STRIP_PAD_OFF: + RxCmd &= ~XM_RX_STRIP_PAD; + break; + } + + switch (Mode & (SK_LENERR_OK_ON | SK_LENERR_OK_OFF)) { + case SK_LENERR_OK_ON: + RxCmd |= XM_RX_LENERR_OK; + break; + case SK_LENERR_OK_OFF: + RxCmd &= ~XM_RX_LENERR_OK; + break; + } + + switch (Mode & (SK_BIG_PK_OK_ON | SK_BIG_PK_OK_OFF)) { + case SK_BIG_PK_OK_ON: + RxCmd |= XM_RX_BIG_PK_OK; + break; + case SK_BIG_PK_OK_OFF: + RxCmd &= ~XM_RX_BIG_PK_OK; + break; + } + + switch (Mode & (SK_SELF_RX_ON | SK_SELF_RX_OFF)) { + case SK_SELF_RX_ON: + RxCmd |= XM_RX_SELF_RX; + break; + case SK_SELF_RX_OFF: + RxCmd &= ~XM_RX_SELF_RX; + break; + } + + /* Write the new mode to the Rx command register if required */ + if (OldRxCmd != RxCmd) { + XM_OUT16(IoC, Port, XM_RX_CMD, RxCmd); + } +} /* SkXmSetRxCmd */ + + +/****************************************************************************** + * + * SkGmSetRxCmd() - Modify the value of the GMAC's Rx Control Register + * + * Description: + * The features + * - FCS (CRC) stripping, SK_STRIP_FCS_ON/OFF + * - don't set GMR_FS_LONG_ERR SK_BIG_PK_OK_ON/OFF + * for frames > 1514 bytes + * - enable Rx of own packets SK_SELF_RX_ON/OFF + * + * for incoming packets may be enabled/disabled by this function. + * Additional modes may be added later. + * Multiple modes can be enabled/disabled at the same time. + * The new configuration is written to the Rx Command register immediately. + * + * Returns: + * nothing + */ +static void SkGmSetRxCmd( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port, /* Port Index (MAC_1 + n) */ +int Mode) /* Mode is SK_STRIP_FCS_ON/OFF, SK_STRIP_PAD_ON/OFF, + SK_LENERR_OK_ON/OFF, or SK_BIG_PK_OK_ON/OFF */ +{ + SK_U16 OldRxCmd; + SK_U16 RxCmd; + + if ((Mode & (SK_STRIP_FCS_ON | SK_STRIP_FCS_OFF)) != 0) { + + GM_IN16(IoC, Port, GM_RX_CTRL, &OldRxCmd); + + RxCmd = OldRxCmd; + + if ((Mode & SK_STRIP_FCS_ON) != 0) { + RxCmd |= GM_RXCR_CRC_DIS; + } + else { + RxCmd &= ~GM_RXCR_CRC_DIS; + } + /* Write the new mode to the Rx control register if required */ + if (OldRxCmd != RxCmd) { + GM_OUT16(IoC, Port, GM_RX_CTRL, RxCmd); + } + } + + if ((Mode & (SK_BIG_PK_OK_ON | SK_BIG_PK_OK_OFF)) != 0) { + + GM_IN16(IoC, Port, GM_SERIAL_MODE, &OldRxCmd); + + RxCmd = OldRxCmd; + + if ((Mode & SK_BIG_PK_OK_ON) != 0) { + RxCmd |= GM_SMOD_JUMBO_ENA; + } + else { + RxCmd &= ~GM_SMOD_JUMBO_ENA; + } + /* Write the new mode to the Rx control register if required */ + if (OldRxCmd != RxCmd) { + GM_OUT16(IoC, Port, GM_SERIAL_MODE, RxCmd); + } + } +} /* SkGmSetRxCmd */ + + +/****************************************************************************** + * + * SkMacSetRxCmd() - Modify the value of the MAC's Rx Control Register + * + * Description: modifies the MAC's Rx Control reg. dep. on board type + * + * Returns: + * nothing + */ +void SkMacSetRxCmd( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port, /* Port Index (MAC_1 + n) */ +int Mode) /* Rx Mode */ +{ + if (pAC->GIni.GIGenesis) { + + SkXmSetRxCmd(pAC, IoC, Port, Mode); + } + else { + + SkGmSetRxCmd(pAC, IoC, Port, Mode); + } + +} /* SkMacSetRxCmd */ + + +/****************************************************************************** + * + * SkMacCrcGener() - Enable / Disable CRC Generation + * + * Description: enables / disables CRC generation dep. on board type + * + * Returns: + * nothing + */ +void SkMacCrcGener( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port, /* Port Index (MAC_1 + n) */ +SK_BOOL Enable) /* Enable / Disable */ +{ + SK_U16 Word; + + if (pAC->GIni.GIGenesis) { + + XM_IN16(IoC, Port, XM_TX_CMD, &Word); + + if (Enable) { + Word &= ~XM_TX_NO_CRC; + } + else { + Word |= XM_TX_NO_CRC; + } + /* setup Tx Command Register */ + XM_OUT16(IoC, Port, XM_TX_CMD, Word); + } + else { + + GM_IN16(IoC, Port, GM_TX_CTRL, &Word); + + if (Enable) { + Word &= ~GM_TXCR_CRC_DIS; + } + else { + Word |= GM_TXCR_CRC_DIS; + } + /* setup Tx Control Register */ + GM_OUT16(IoC, Port, GM_TX_CTRL, Word); + } + +} /* SkMacCrcGener*/ + +#endif /* SK_DIAG */ + + +#ifdef GENESIS +/****************************************************************************** + * + * SkXmClrExactAddr() - Clear Exact Match Address Registers + * + * Description: + * All Exact Match Address registers of the XMAC 'Port' will be + * cleared starting with 'StartNum' up to (and including) the + * Exact Match address number of 'StopNum'. + * + * Returns: + * nothing + */ +void SkXmClrExactAddr( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port, /* Port Index (MAC_1 + n) */ +int StartNum, /* Begin with this Address Register Index (0..15) */ +int StopNum) /* Stop after finished with this Register Idx (0..15) */ +{ + int i; + SK_U16 ZeroAddr[3] = {0x0000, 0x0000, 0x0000}; + + if ((unsigned)StartNum > 15 || (unsigned)StopNum > 15 || + StartNum > StopNum) { + + SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E001, SKERR_HWI_E001MSG); + return; + } + + for (i = StartNum; i <= StopNum; i++) { + XM_OUTADDR(IoC, Port, XM_EXM(i), &ZeroAddr[0]); + } +} /* SkXmClrExactAddr */ +#endif /* GENESIS */ + + +/****************************************************************************** + * + * SkMacFlushTxFifo() - Flush the MAC's transmit FIFO + * + * Description: + * Flush the transmit FIFO of the MAC specified by the index 'Port' + * + * Returns: + * nothing + */ +void SkMacFlushTxFifo( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port) /* Port Index (MAC_1 + n) */ +{ +#ifdef GENESIS + SK_U32 MdReg; + + if (pAC->GIni.GIGenesis) { + + XM_IN32(IoC, Port, XM_MODE, &MdReg); + + XM_OUT32(IoC, Port, XM_MODE, MdReg | XM_MD_FTF); + } +#endif /* GENESIS */ + +#ifdef YUKON + if (pAC->GIni.GIYukon) { + /* no way to flush the FIFO we have to issue a reset */ + /* TBD */ + } +#endif /* YUKON */ + +} /* SkMacFlushTxFifo */ + + +/****************************************************************************** + * + * SkMacFlushRxFifo() - Flush the MAC's receive FIFO + * + * Description: + * Flush the receive FIFO of the MAC specified by the index 'Port' + * + * Returns: + * nothing + */ +static void SkMacFlushRxFifo( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port) /* Port Index (MAC_1 + n) */ +{ +#ifdef GENESIS + SK_U32 MdReg; + + if (pAC->GIni.GIGenesis) { + + XM_IN32(IoC, Port, XM_MODE, &MdReg); + + XM_OUT32(IoC, Port, XM_MODE, MdReg | XM_MD_FRF); + } +#endif /* GENESIS */ + +#ifdef YUKON + if (pAC->GIni.GIYukon) { + /* no way to flush the FIFO we have to issue a reset */ + /* TBD */ + } +#endif /* YUKON */ + +} /* SkMacFlushRxFifo */ + + +#ifdef GENESIS +/****************************************************************************** + * + * SkXmSoftRst() - Do a XMAC software reset + * + * Description: + * The PHY registers should not be destroyed during this + * kind of software reset. Therefore the XMAC Software Reset + * (XM_GP_RES_MAC bit in XM_GP_PORT) must not be used! + * + * The software reset is done by + * - disabling the Rx and Tx state machine, + * - resetting the statistics module, + * - clear all other significant XMAC Mode, + * Command, and Control Registers + * - clearing the Hash Register and the + * Exact Match Address registers, and + * - flushing the XMAC's Rx and Tx FIFOs. + * + * Note: + * Another requirement when stopping the XMAC is to + * avoid sending corrupted frames on the network. + * Disabling the Tx state machine will NOT interrupt + * the currently transmitted frame. But we must take care + * that the Tx FIFO is cleared AFTER the current frame + * is complete sent to the network. + * + * It takes about 12ns to send a frame with 1538 bytes. + * One PCI clock goes at least 15ns (66MHz). Therefore + * after reading XM_GP_PORT back, we are sure that the + * transmitter is disabled AND idle. And this means + * we may flush the transmit FIFO now. + * + * Returns: + * nothing + */ +static void SkXmSoftRst( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port) /* Port Index (MAC_1 + n) */ +{ + SK_U16 ZeroAddr[4] = {0x0000, 0x0000, 0x0000, 0x0000}; + + /* reset the statistics module */ + XM_OUT32(IoC, Port, XM_GP_PORT, XM_GP_RES_STAT); + + /* disable all XMAC IRQs */ + XM_OUT16(IoC, Port, XM_IMSK, 0xffff); + + XM_OUT32(IoC, Port, XM_MODE, 0); /* clear Mode Reg */ + + XM_OUT16(IoC, Port, XM_TX_CMD, 0); /* reset TX CMD Reg */ + XM_OUT16(IoC, Port, XM_RX_CMD, 0); /* reset RX CMD Reg */ + + /* disable all PHY IRQs */ + switch (pAC->GIni.GP[Port].PhyType) { + case SK_PHY_BCOM: + SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_INT_MASK, 0xffff); + break; +#ifdef OTHER_PHY + case SK_PHY_LONE: + SkXmPhyWrite(pAC, IoC, Port, PHY_LONE_INT_ENAB, 0); + break; + case SK_PHY_NAT: + /* todo: National + SkXmPhyWrite(pAC, IoC, Port, PHY_NAT_INT_MASK, 0xffff); */ + break; +#endif /* OTHER_PHY */ + } + + /* clear the Hash Register */ + XM_OUTHASH(IoC, Port, XM_HSM, &ZeroAddr); + + /* clear the Exact Match Address registers */ + SkXmClrExactAddr(pAC, IoC, Port, 0, 15); + + /* clear the Source Check Address registers */ + XM_OUTHASH(IoC, Port, XM_SRC_CHK, &ZeroAddr); + +} /* SkXmSoftRst */ + + +/****************************************************************************** + * + * SkXmHardRst() - Do a XMAC hardware reset + * + * Description: + * The XMAC of the specified 'Port' and all connected devices + * (PHY and SERDES) will receive a reset signal on its *Reset pins. + * External PHYs must be reset by clearing a bit in the GPIO register + * (Timing requirements: Broadcom: 400ns, Level One: none, National: 80ns). + * + * ATTENTION: + * It is absolutely necessary to reset the SW_RST Bit first + * before calling this function. + * + * Returns: + * nothing + */ +static void SkXmHardRst( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port) /* Port Index (MAC_1 + n) */ +{ + SK_U32 Reg; + int i; + int TOut; + SK_U16 Word; + + for (i = 0; i < 4; i++) { + /* TX_MFF_CTRL1 has 32 bits, but only the lowest 16 bits are used */ + SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), MFF_CLR_MAC_RST); + + TOut = 0; + do { + if (TOut++ > 10000) { + /* + * Adapter seems to be in RESET state. + * Registers cannot be written. + */ + return; + } + + SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), MFF_SET_MAC_RST); + + SK_IN16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), &Word); + + } while ((Word & MFF_SET_MAC_RST) == 0); + } + + /* For external PHYs there must be special handling */ + if (pAC->GIni.GP[Port].PhyType != SK_PHY_XMAC) { + + SK_IN32(IoC, B2_GP_IO, &Reg); + + if (Port == 0) { + Reg |= GP_DIR_0; /* set to output */ + Reg &= ~GP_IO_0; /* set PHY reset (active low) */ + } + else { + Reg |= GP_DIR_2; /* set to output */ + Reg &= ~GP_IO_2; /* set PHY reset (active low) */ + } + /* reset external PHY */ + SK_OUT32(IoC, B2_GP_IO, Reg); + + /* short delay */ + SK_IN32(IoC, B2_GP_IO, &Reg); + } +} /* SkXmHardRst */ + + +/****************************************************************************** + * + * SkXmClearRst() - Release the PHY & XMAC reset + * + * Description: + * + * Returns: + * nothing + */ +static void SkXmClearRst( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port) /* Port Index (MAC_1 + n) */ +{ + SK_U32 DWord; + + /* clear HW reset */ + SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), MFF_CLR_MAC_RST); + + if (pAC->GIni.GP[Port].PhyType != SK_PHY_XMAC) { + + SK_IN32(IoC, B2_GP_IO, &DWord); + + if (Port == 0) { + DWord |= (GP_DIR_0 | GP_IO_0); /* set to output */ + } + else { + DWord |= (GP_DIR_2 | GP_IO_2); /* set to output */ + } + /* Clear PHY reset */ + SK_OUT32(IoC, B2_GP_IO, DWord); + + /* Enable GMII interface */ + XM_OUT16(IoC, Port, XM_HW_CFG, XM_HW_GMII_MD); + } +} /* SkXmClearRst */ +#endif /* GENESIS */ + + +#ifdef YUKON +/****************************************************************************** + * + * SkGmSoftRst() - Do a GMAC software reset + * + * Description: + * The GPHY registers should not be destroyed during this + * kind of software reset. + * + * Returns: + * nothing + */ +static void SkGmSoftRst( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port) /* Port Index (MAC_1 + n) */ +{ + SK_U16 EmptyHash[4] = {0x0000, 0x0000, 0x0000, 0x0000}; + SK_U16 RxCtrl; + + /* reset the statistics module */ + + /* disable all GMAC IRQs */ + SK_OUT8(IoC, GMAC_IRQ_MSK, 0); + + /* disable all PHY IRQs */ + SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_INT_MASK, 0); + + /* clear the Hash Register */ + GM_OUTHASH(IoC, Port, GM_MC_ADDR_H1, EmptyHash); + + /* Enable Unicast and Multicast filtering */ + GM_IN16(IoC, Port, GM_RX_CTRL, &RxCtrl); + + GM_OUT16(IoC, Port, GM_RX_CTRL, + (SK_U16)(RxCtrl | GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA)); + +} /* SkGmSoftRst */ + + +/****************************************************************************** + * + * SkGmHardRst() - Do a GMAC hardware reset + * + * Description: + * + * Returns: + * nothing + */ +static void SkGmHardRst( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port) /* Port Index (MAC_1 + n) */ +{ + SK_U32 DWord; + + /* WA code for COMA mode */ + if (pAC->GIni.GIYukonLite && + pAC->GIni.GIChipRev >= CHIP_REV_YU_LITE_A3) { + + SK_IN32(IoC, B2_GP_IO, &DWord); + + DWord |= (GP_DIR_9 | GP_IO_9); + + /* set PHY reset */ + SK_OUT32(IoC, B2_GP_IO, DWord); + } + + /* set GPHY Control reset */ + SK_OUT32(IoC, MR_ADDR(Port, GPHY_CTRL), GPC_RST_SET); + + /* set GMAC Control reset */ + SK_OUT32(IoC, MR_ADDR(Port, GMAC_CTRL), GMC_RST_SET); + +} /* SkGmHardRst */ + + +/****************************************************************************** + * + * SkGmClearRst() - Release the GPHY & GMAC reset + * + * Description: + * + * Returns: + * nothing + */ +static void SkGmClearRst( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port) /* Port Index (MAC_1 + n) */ +{ + SK_U32 DWord; + +#ifdef XXX + /* clear GMAC Control reset */ + SK_OUT32(IoC, MR_ADDR(Port, GMAC_CTRL), GMC_RST_CLR); + + /* set GMAC Control reset */ + SK_OUT32(IoC, MR_ADDR(Port, GMAC_CTRL), GMC_RST_SET); +#endif /* XXX */ + + /* WA code for COMA mode */ + if (pAC->GIni.GIYukonLite && + pAC->GIni.GIChipRev >= CHIP_REV_YU_LITE_A3) { + + SK_IN32(IoC, B2_GP_IO, &DWord); + + DWord |= GP_DIR_9; /* set to output */ + DWord &= ~GP_IO_9; /* clear PHY reset (active high) */ + + /* clear PHY reset */ + SK_OUT32(IoC, B2_GP_IO, DWord); + } + + /* set HWCFG_MODE */ + DWord = GPC_INT_POL_HI | GPC_DIS_FC | GPC_DIS_SLEEP | + GPC_ENA_XC | GPC_ANEG_ADV_ALL_M | GPC_ENA_PAUSE | + (pAC->GIni.GICopperType ? GPC_HWCFG_GMII_COP : + GPC_HWCFG_GMII_FIB); + + /* set GPHY Control reset */ + SK_OUT32(IoC, MR_ADDR(Port, GPHY_CTRL), DWord | GPC_RST_SET); + + /* release GPHY Control reset */ + SK_OUT32(IoC, MR_ADDR(Port, GPHY_CTRL), DWord | GPC_RST_CLR); + +#ifdef VCPU + VCpuWait(9000); +#endif /* VCPU */ + + /* clear GMAC Control reset */ + SK_OUT32(IoC, MR_ADDR(Port, GMAC_CTRL), GMC_PAUSE_ON | GMC_RST_CLR); + +#ifdef VCPU + VCpuWait(2000); + + SK_IN32(IoC, MR_ADDR(Port, GPHY_CTRL), &DWord); + + SK_IN32(IoC, B0_ISRC, &DWord); +#endif /* VCPU */ + +} /* SkGmClearRst */ +#endif /* YUKON */ + + +/****************************************************************************** + * + * SkMacSoftRst() - Do a MAC software reset + * + * Description: calls a MAC software reset routine dep. on board type + * + * Returns: + * nothing + */ +void SkMacSoftRst( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port) /* Port Index (MAC_1 + n) */ +{ + SK_GEPORT *pPrt; + + pPrt = &pAC->GIni.GP[Port]; + + /* disable receiver and transmitter */ + SkMacRxTxDisable(pAC, IoC, Port); + +#ifdef GENESIS + if (pAC->GIni.GIGenesis) { + + SkXmSoftRst(pAC, IoC, Port); + } +#endif /* GENESIS */ + +#ifdef YUKON + if (pAC->GIni.GIYukon) { + + SkGmSoftRst(pAC, IoC, Port); + } +#endif /* YUKON */ + + /* flush the MAC's Rx and Tx FIFOs */ + SkMacFlushTxFifo(pAC, IoC, Port); + + SkMacFlushRxFifo(pAC, IoC, Port); + + pPrt->PState = SK_PRT_STOP; + +} /* SkMacSoftRst */ + + +/****************************************************************************** + * + * SkMacHardRst() - Do a MAC hardware reset + * + * Description: calls a MAC hardware reset routine dep. on board type + * + * Returns: + * nothing + */ +void SkMacHardRst( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port) /* Port Index (MAC_1 + n) */ +{ + +#ifdef GENESIS + if (pAC->GIni.GIGenesis) { + + SkXmHardRst(pAC, IoC, Port); + } +#endif /* GENESIS */ + +#ifdef YUKON + if (pAC->GIni.GIYukon) { + + SkGmHardRst(pAC, IoC, Port); + } +#endif /* YUKON */ + + pAC->GIni.GP[Port].PState = SK_PRT_RESET; + +} /* SkMacHardRst */ + + +#ifdef GENESIS +/****************************************************************************** + * + * SkXmInitMac() - Initialize the XMAC II + * + * Description: + * Initialize the XMAC of the specified port. + * The XMAC must be reset or stopped before calling this function. + * + * Note: + * The XMAC's Rx and Tx state machine is still disabled when returning. + * + * Returns: + * nothing + */ +void SkXmInitMac( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port) /* Port Index (MAC_1 + n) */ +{ + SK_GEPORT *pPrt; + int i; + SK_U16 SWord; + + pPrt = &pAC->GIni.GP[Port]; + + if (pPrt->PState == SK_PRT_STOP) { + /* Port State: SK_PRT_STOP */ + /* Verify that the reset bit is cleared */ + SK_IN16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), &SWord); + + if ((SWord & MFF_SET_MAC_RST) != 0) { + /* PState does not match HW state */ + SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E006, SKERR_HWI_E006MSG); + /* Correct it */ + pPrt->PState = SK_PRT_RESET; + } + } + + if (pPrt->PState == SK_PRT_RESET) { + + SkXmClearRst(pAC, IoC, Port); + + if (pPrt->PhyType != SK_PHY_XMAC) { + /* read Id from external PHY (all have the same address) */ + SkXmPhyRead(pAC, IoC, Port, PHY_XMAC_ID1, &pPrt->PhyId1); + + /* + * Optimize MDIO transfer by suppressing preamble. + * Must be done AFTER first access to BCOM chip. + */ + XM_IN16(IoC, Port, XM_MMU_CMD, &SWord); + + XM_OUT16(IoC, Port, XM_MMU_CMD, SWord | XM_MMU_NO_PRE); + + if (pPrt->PhyId1 == PHY_BCOM_ID1_C0) { + /* + * Workaround BCOM Errata for the C0 type. + * Write magic patterns to reserved registers. + */ + i = 0; + while (BcomRegC0Hack[i].PhyReg != 0) { + SkXmPhyWrite(pAC, IoC, Port, BcomRegC0Hack[i].PhyReg, + BcomRegC0Hack[i].PhyVal); + i++; + } + } + else if (pPrt->PhyId1 == PHY_BCOM_ID1_A1) { + /* + * Workaround BCOM Errata for the A1 type. + * Write magic patterns to reserved registers. + */ + i = 0; + while (BcomRegA1Hack[i].PhyReg != 0) { + SkXmPhyWrite(pAC, IoC, Port, BcomRegA1Hack[i].PhyReg, + BcomRegA1Hack[i].PhyVal); + i++; + } + } + + /* + * Workaround BCOM Errata (#10523) for all BCom PHYs. + * Disable Power Management after reset. + */ + SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUX_CTRL, &SWord); + + SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_AUX_CTRL, + (SK_U16)(SWord | PHY_B_AC_DIS_PM)); + + /* PHY LED initialization is done in SkGeXmitLED() */ + } + + /* Dummy read the Interrupt source register */ + XM_IN16(IoC, Port, XM_ISRC, &SWord); + + /* + * The auto-negotiation process starts immediately after + * clearing the reset. The auto-negotiation process should be + * started by the SIRQ, therefore stop it here immediately. + */ + SkMacInitPhy(pAC, IoC, Port, SK_FALSE); + +#ifdef TEST_ONLY + /* temp. code: enable signal detect */ + /* WARNING: do not override GMII setting above */ + XM_OUT16(IoC, Port, XM_HW_CFG, XM_HW_COM4SIG); +#endif + } + + /* + * configure the XMACs Station Address + * B2_MAC_2 = xx xx xx xx xx x1 is programmed to XMAC A + * B2_MAC_3 = xx xx xx xx xx x2 is programmed to XMAC B + */ + for (i = 0; i < 3; i++) { + /* + * The following 2 statements are together endianess + * independent. Remember this when changing. + */ + SK_IN16(IoC, (B2_MAC_2 + Port * 8 + i * 2), &SWord); + + XM_OUT16(IoC, Port, (XM_SA + i * 2), SWord); + } + + /* Tx Inter Packet Gap (XM_TX_IPG): use default */ + /* Tx High Water Mark (XM_TX_HI_WM): use default */ + /* Tx Low Water Mark (XM_TX_LO_WM): use default */ + /* Host Request Threshold (XM_HT_THR): use default */ + /* Rx Request Threshold (XM_RX_THR): use default */ + /* Rx Low Water Mark (XM_RX_LO_WM): use default */ + + /* configure Rx High Water Mark (XM_RX_HI_WM) */ + XM_OUT16(IoC, Port, XM_RX_HI_WM, SK_XM_RX_HI_WM); + + /* Configure Tx Request Threshold */ + SWord = SK_XM_THR_SL; /* for single port */ + + if (pAC->GIni.GIMacsFound > 1) { + switch (pAC->GIni.GIPortUsage) { + case SK_RED_LINK: + SWord = SK_XM_THR_REDL; /* redundant link */ + break; + case SK_MUL_LINK: + SWord = SK_XM_THR_MULL; /* load balancing */ + break; + case SK_JUMBO_LINK: + SWord = SK_XM_THR_JUMBO; /* jumbo frames */ + break; + default: + SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E014, SKERR_HWI_E014MSG); + break; + } + } + XM_OUT16(IoC, Port, XM_TX_THR, SWord); + + /* setup register defaults for the Tx Command Register */ + XM_OUT16(IoC, Port, XM_TX_CMD, XM_TX_AUTO_PAD); + + /* setup register defaults for the Rx Command Register */ + SWord = XM_RX_STRIP_FCS | XM_RX_LENERR_OK; + + if (pAC->GIni.GIPortUsage == SK_JUMBO_LINK) { + SWord |= XM_RX_BIG_PK_OK; + } + + if (pPrt->PLinkMode == SK_LMODE_HALF) { + /* + * If in manual half duplex mode the other side might be in + * full duplex mode, so ignore if a carrier extension is not seen + * on frames received + */ + SWord |= XM_RX_DIS_CEXT; + } + + XM_OUT16(IoC, Port, XM_RX_CMD, SWord); + + /* + * setup register defaults for the Mode Register + * - Don't strip error frames to avoid Store & Forward + * on the Rx side. + * - Enable 'Check Station Address' bit + * - Enable 'Check Address Array' bit + */ + XM_OUT32(IoC, Port, XM_MODE, XM_DEF_MODE); + + /* + * Initialize the Receive Counter Event Mask (XM_RX_EV_MSK) + * - Enable all bits excepting 'Octets Rx OK Low CntOv' + * and 'Octets Rx OK Hi Cnt Ov'. + */ + XM_OUT32(IoC, Port, XM_RX_EV_MSK, XMR_DEF_MSK); + + /* + * Initialize the Transmit Counter Event Mask (XM_TX_EV_MSK) + * - Enable all bits excepting 'Octets Tx OK Low CntOv' + * and 'Octets Tx OK Hi Cnt Ov'. + */ + XM_OUT32(IoC, Port, XM_TX_EV_MSK, XMT_DEF_MSK); + + /* + * Do NOT init XMAC interrupt mask here. + * All interrupts remain disable until link comes up! + */ + + /* + * Any additional configuration changes may be done now. + * The last action is to enable the Rx and Tx state machine. + * This should be done after the auto-negotiation process + * has been completed successfully. + */ +} /* SkXmInitMac */ +#endif /* GENESIS */ + + +#ifdef YUKON +/****************************************************************************** + * + * SkGmInitMac() - Initialize the GMAC + * + * Description: + * Initialize the GMAC of the specified port. + * The GMAC must be reset or stopped before calling this function. + * + * Note: + * The GMAC's Rx and Tx state machine is still disabled when returning. + * + * Returns: + * nothing + */ +void SkGmInitMac( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port) /* Port Index (MAC_1 + n) */ +{ + SK_GEPORT *pPrt; + int i; + SK_U16 SWord; + SK_U32 DWord; + + pPrt = &pAC->GIni.GP[Port]; + + if (pPrt->PState == SK_PRT_STOP) { + /* Port State: SK_PRT_STOP */ + /* Verify that the reset bit is cleared */ + SK_IN32(IoC, MR_ADDR(Port, GMAC_CTRL), &DWord); + + if ((DWord & GMC_RST_SET) != 0) { + /* PState does not match HW state */ + SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E006, SKERR_HWI_E006MSG); + /* Correct it */ + pPrt->PState = SK_PRT_RESET; + } + } + + if (pPrt->PState == SK_PRT_RESET) { + + SkGmHardRst(pAC, IoC, Port); + + SkGmClearRst(pAC, IoC, Port); + + /* Auto-negotiation ? */ + if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) { + /* Auto-negotiation disabled */ + + /* get General Purpose Control */ + GM_IN16(IoC, Port, GM_GP_CTRL, &SWord); + + /* disable auto-update for speed, duplex and flow-control */ + SWord |= GM_GPCR_AU_ALL_DIS; + + /* setup General Purpose Control Register */ + GM_OUT16(IoC, Port, GM_GP_CTRL, SWord); + + SWord = GM_GPCR_AU_ALL_DIS; + } + else { + SWord = 0; + } + + /* speed settings */ + switch (pPrt->PLinkSpeed) { + case SK_LSPEED_AUTO: + case SK_LSPEED_1000MBPS: + SWord |= GM_GPCR_SPEED_1000 | GM_GPCR_SPEED_100; + break; + case SK_LSPEED_100MBPS: + SWord |= GM_GPCR_SPEED_100; + break; + case SK_LSPEED_10MBPS: + break; + } + + /* duplex settings */ + if (pPrt->PLinkMode != SK_LMODE_HALF) { + /* set full duplex */ + SWord |= GM_GPCR_DUP_FULL; + } + + /* flow-control settings */ + switch (pPrt->PFlowCtrlMode) { + case SK_FLOW_MODE_NONE: + /* set Pause Off */ + SK_OUT32(IoC, MR_ADDR(Port, GMAC_CTRL), GMC_PAUSE_OFF); + /* disable Tx & Rx flow-control */ + SWord |= GM_GPCR_FC_TX_DIS | GM_GPCR_FC_RX_DIS | GM_GPCR_AU_FCT_DIS; + break; + case SK_FLOW_MODE_LOC_SEND: + /* disable Rx flow-control */ + SWord |= GM_GPCR_FC_RX_DIS | GM_GPCR_AU_FCT_DIS; + break; + case SK_FLOW_MODE_SYMMETRIC: + case SK_FLOW_MODE_SYM_OR_REM: + /* enable Tx & Rx flow-control */ + break; + } + + /* setup General Purpose Control Register */ + GM_OUT16(IoC, Port, GM_GP_CTRL, SWord); + + /* dummy read the Interrupt Source Register */ + SK_IN16(IoC, GMAC_IRQ_SRC, &SWord); + +#ifndef VCPU + /* read Id from PHY */ + SkGmPhyRead(pAC, IoC, Port, PHY_MARV_ID1, &pPrt->PhyId1); + + SkGmInitPhyMarv(pAC, IoC, Port, SK_FALSE); +#endif /* VCPU */ + } + + (void)SkGmResetCounter(pAC, IoC, Port); + + /* setup Transmit Control Register */ + GM_OUT16(IoC, Port, GM_TX_CTRL, TX_COL_THR(pPrt->PMacColThres)); + + /* setup Receive Control Register */ + GM_OUT16(IoC, Port, GM_RX_CTRL, GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA | + GM_RXCR_CRC_DIS); + + /* setup Transmit Flow Control Register */ + GM_OUT16(IoC, Port, GM_TX_FLOW_CTRL, 0xffff); + + /* setup Transmit Parameter Register */ +#ifdef VCPU + GM_IN16(IoC, Port, GM_TX_PARAM, &SWord); +#endif /* VCPU */ + + SWord = TX_JAM_LEN_VAL(pPrt->PMacJamLen) | + TX_JAM_IPG_VAL(pPrt->PMacJamIpgVal) | + TX_IPG_JAM_DATA(pPrt->PMacJamIpgData); + + GM_OUT16(IoC, Port, GM_TX_PARAM, SWord); + + /* configure the Serial Mode Register */ +#ifdef VCPU + GM_IN16(IoC, Port, GM_SERIAL_MODE, &SWord); +#endif /* VCPU */ + + SWord = GM_SMOD_VLAN_ENA | IPG_DATA_VAL(pPrt->PMacIpgData); + + if (pPrt->PMacLimit4) { + /* reset of collision counter after 4 consecutive collisions */ + SWord |= GM_SMOD_LIMIT_4; + } + + if (pAC->GIni.GIPortUsage == SK_JUMBO_LINK) { + /* enable jumbo mode (Max. Frame Length = 9018) */ + SWord |= GM_SMOD_JUMBO_ENA; + } + + GM_OUT16(IoC, Port, GM_SERIAL_MODE, SWord); + + /* + * configure the GMACs Station Addresses + * in PROM you can find our addresses at: + * B2_MAC_1 = xx xx xx xx xx x0 virtual address + * B2_MAC_2 = xx xx xx xx xx x1 is programmed to GMAC A + * B2_MAC_3 = xx xx xx xx xx x2 is reserved for DualPort + */ + + for (i = 0; i < 3; i++) { + /* + * The following 2 statements are together endianess + * independent. Remember this when changing. + */ + /* physical address: will be used for pause frames */ + SK_IN16(IoC, (B2_MAC_2 + Port * 8 + i * 2), &SWord); + +#ifdef WA_DEV_16 + /* WA for deviation #16 */ + if (pAC->GIni.GIChipId == CHIP_ID_YUKON && pAC->GIni.GIChipRev == 0) { + /* swap the address bytes */ + SWord = ((SWord & 0xff00) >> 8) | ((SWord & 0x00ff) << 8); + + /* write to register in reversed order */ + GM_OUT16(IoC, Port, (GM_SRC_ADDR_1L + (2 - i) * 4), SWord); + } + else { + GM_OUT16(IoC, Port, (GM_SRC_ADDR_1L + i * 4), SWord); + } +#else + GM_OUT16(IoC, Port, (GM_SRC_ADDR_1L + i * 4), SWord); +#endif /* WA_DEV_16 */ + + /* virtual address: will be used for data */ + SK_IN16(IoC, (B2_MAC_1 + Port * 8 + i * 2), &SWord); + + GM_OUT16(IoC, Port, (GM_SRC_ADDR_2L + i * 4), SWord); + + /* reset Multicast filtering Hash registers 1-3 */ + GM_OUT16(IoC, Port, GM_MC_ADDR_H1 + 4*i, 0); + } + + /* reset Multicast filtering Hash register 4 */ + GM_OUT16(IoC, Port, GM_MC_ADDR_H4, 0); + + /* enable interrupt mask for counter overflows */ + GM_OUT16(IoC, Port, GM_TX_IRQ_MSK, 0); + GM_OUT16(IoC, Port, GM_RX_IRQ_MSK, 0); + GM_OUT16(IoC, Port, GM_TR_IRQ_MSK, 0); + +#if defined(SK_DIAG) || defined(DEBUG) + /* read General Purpose Status */ + GM_IN16(IoC, Port, GM_GP_STAT, &SWord); + + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("MAC Stat Reg.=0x%04X\n", SWord)); +#endif /* SK_DIAG || DEBUG */ + +#ifdef SK_DIAG + c_print("MAC Stat Reg=0x%04X\n", SWord); +#endif /* SK_DIAG */ + +} /* SkGmInitMac */ +#endif /* YUKON */ + + +#ifdef GENESIS +/****************************************************************************** + * + * SkXmInitDupMd() - Initialize the XMACs Duplex Mode + * + * Description: + * This function initializes the XMACs Duplex Mode. + * It should be called after successfully finishing + * the Auto-negotiation Process + * + * Returns: + * nothing + */ +static void SkXmInitDupMd( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port) /* Port Index (MAC_1 + n) */ +{ + switch (pAC->GIni.GP[Port].PLinkModeStatus) { + case SK_LMODE_STAT_AUTOHALF: + case SK_LMODE_STAT_HALF: + /* Configuration Actions for Half Duplex Mode */ + /* + * XM_BURST = default value. We are probable not quick + * enough at the 'XMAC' bus to burst 8kB. + * The XMAC stops bursting if no transmit frames + * are available or the burst limit is exceeded. + */ + /* XM_TX_RT_LIM = default value (15) */ + /* XM_TX_STIME = default value (0xff = 4096 bit times) */ + break; + case SK_LMODE_STAT_AUTOFULL: + case SK_LMODE_STAT_FULL: + /* Configuration Actions for Full Duplex Mode */ + /* + * The duplex mode is configured by the PHY, + * therefore it seems to be that there is nothing + * to do here. + */ + break; + case SK_LMODE_STAT_UNKNOWN: + default: + SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E007, SKERR_HWI_E007MSG); + break; + } +} /* SkXmInitDupMd */ + + +/****************************************************************************** + * + * SkXmInitPauseMd() - initialize the Pause Mode to be used for this port + * + * Description: + * This function initializes the Pause Mode which should + * be used for this port. + * It should be called after successfully finishing + * the Auto-negotiation Process + * + * Returns: + * nothing + */ +static void SkXmInitPauseMd( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port) /* Port Index (MAC_1 + n) */ +{ + SK_GEPORT *pPrt; + SK_U32 DWord; + SK_U16 Word; + + pPrt = &pAC->GIni.GP[Port]; + + XM_IN16(IoC, Port, XM_MMU_CMD, &Word); + + if (pPrt->PFlowCtrlStatus == SK_FLOW_STAT_NONE || + pPrt->PFlowCtrlStatus == SK_FLOW_STAT_LOC_SEND) { + + /* Disable Pause Frame Reception */ + Word |= XM_MMU_IGN_PF; + } + else { + /* + * enabling pause frame reception is required for 1000BT + * because the XMAC is not reset if the link is going down + */ + /* Enable Pause Frame Reception */ + Word &= ~XM_MMU_IGN_PF; + } + + XM_OUT16(IoC, Port, XM_MMU_CMD, Word); + + XM_IN32(IoC, Port, XM_MODE, &DWord); + + if (pPrt->PFlowCtrlStatus == SK_FLOW_STAT_SYMMETRIC || + pPrt->PFlowCtrlStatus == SK_FLOW_STAT_LOC_SEND) { + + /* + * Configure Pause Frame Generation + * Use internal and external Pause Frame Generation. + * Sending pause frames is edge triggered. + * Send a Pause frame with the maximum pause time if + * internal oder external FIFO full condition occurs. + * Send a zero pause time frame to re-start transmission. + */ + + /* XM_PAUSE_DA = '010000C28001' (default) */ + + /* XM_MAC_PTIME = 0xffff (maximum) */ + /* remember this value is defined in big endian (!) */ + XM_OUT16(IoC, Port, XM_MAC_PTIME, 0xffff); + + /* Set Pause Mode in Mode Register */ + DWord |= XM_PAUSE_MODE; + + /* Set Pause Mode in MAC Rx FIFO */ + SK_OUT16(IoC, MR_ADDR(Port, RX_MFF_CTRL1), MFF_ENA_PAUSE); + } + else { + /* + * disable pause frame generation is required for 1000BT + * because the XMAC is not reset if the link is going down + */ + /* Disable Pause Mode in Mode Register */ + DWord &= ~XM_PAUSE_MODE; + + /* Disable Pause Mode in MAC Rx FIFO */ + SK_OUT16(IoC, MR_ADDR(Port, RX_MFF_CTRL1), MFF_DIS_PAUSE); + } + + XM_OUT32(IoC, Port, XM_MODE, DWord); +} /* SkXmInitPauseMd*/ + + +/****************************************************************************** + * + * SkXmInitPhyXmac() - Initialize the XMAC Phy registers + * + * Description: initializes all the XMACs Phy registers + * + * Note: + * + * Returns: + * nothing + */ +static void SkXmInitPhyXmac( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port, /* Port Index (MAC_1 + n) */ +SK_BOOL DoLoop) /* Should a Phy LoopBack be set-up? */ +{ + SK_GEPORT *pPrt; + SK_U16 Ctrl; + + pPrt = &pAC->GIni.GP[Port]; + Ctrl = 0; + + /* Auto-negotiation ? */ + if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) { + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("InitPhyXmac: no auto-negotiation Port %d\n", Port)); + /* Set DuplexMode in Config register */ + if (pPrt->PLinkMode == SK_LMODE_FULL) { + Ctrl |= PHY_CT_DUP_MD; + } + + /* + * Do NOT enable Auto-negotiation here. This would hold + * the link down because no IDLEs are transmitted + */ + } + else { + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("InitPhyXmac: with auto-negotiation Port %d\n", Port)); + /* Set Auto-negotiation advertisement */ + + /* Set Full/half duplex capabilities */ + switch (pPrt->PLinkMode) { + case SK_LMODE_AUTOHALF: + Ctrl |= PHY_X_AN_HD; + break; + case SK_LMODE_AUTOFULL: + Ctrl |= PHY_X_AN_FD; + break; + case SK_LMODE_AUTOBOTH: + Ctrl |= PHY_X_AN_FD | PHY_X_AN_HD; + break; + default: + SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E015, + SKERR_HWI_E015MSG); + } + + /* Set Flow-control capabilities */ + switch (pPrt->PFlowCtrlMode) { + case SK_FLOW_MODE_NONE: + Ctrl |= PHY_X_P_NO_PAUSE; + break; + case SK_FLOW_MODE_LOC_SEND: + Ctrl |= PHY_X_P_ASYM_MD; + break; + case SK_FLOW_MODE_SYMMETRIC: + Ctrl |= PHY_X_P_SYM_MD; + break; + case SK_FLOW_MODE_SYM_OR_REM: + Ctrl |= PHY_X_P_BOTH_MD; + break; + default: + SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E016, + SKERR_HWI_E016MSG); + } + + /* Write AutoNeg Advertisement Register */ + SkXmPhyWrite(pAC, IoC, Port, PHY_XMAC_AUNE_ADV, Ctrl); + + /* Restart Auto-negotiation */ + Ctrl = PHY_CT_ANE | PHY_CT_RE_CFG; + } + + if (DoLoop) { + /* Set the Phy Loopback bit, too */ + Ctrl |= PHY_CT_LOOP; + } + + /* Write to the Phy control register */ + SkXmPhyWrite(pAC, IoC, Port, PHY_XMAC_CTRL, Ctrl); +} /* SkXmInitPhyXmac */ + + +/****************************************************************************** + * + * SkXmInitPhyBcom() - Initialize the Broadcom Phy registers + * + * Description: initializes all the Broadcom Phy registers + * + * Note: + * + * Returns: + * nothing + */ +static void SkXmInitPhyBcom( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port, /* Port Index (MAC_1 + n) */ +SK_BOOL DoLoop) /* Should a Phy LoopBack be set-up? */ +{ + SK_GEPORT *pPrt; + SK_U16 Ctrl1; + SK_U16 Ctrl2; + SK_U16 Ctrl3; + SK_U16 Ctrl4; + SK_U16 Ctrl5; + + Ctrl1 = PHY_CT_SP1000; + Ctrl2 = 0; + Ctrl3 = PHY_SEL_TYPE; + Ctrl4 = PHY_B_PEC_EN_LTR; + Ctrl5 = PHY_B_AC_TX_TST; + + pPrt = &pAC->GIni.GP[Port]; + + /* manually Master/Slave ? */ + if (pPrt->PMSMode != SK_MS_MODE_AUTO) { + Ctrl2 |= PHY_B_1000C_MSE; + + if (pPrt->PMSMode == SK_MS_MODE_MASTER) { + Ctrl2 |= PHY_B_1000C_MSC; + } + } + /* Auto-negotiation ? */ + if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) { + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("InitPhyBcom: no auto-negotiation Port %d\n", Port)); + /* Set DuplexMode in Config register */ + if (pPrt->PLinkMode == SK_LMODE_FULL) { + Ctrl1 |= PHY_CT_DUP_MD; + } + + /* Determine Master/Slave manually if not already done */ + if (pPrt->PMSMode == SK_MS_MODE_AUTO) { + Ctrl2 |= PHY_B_1000C_MSE; /* set it to Slave */ + } + + /* + * Do NOT enable Auto-negotiation here. This would hold + * the link down because no IDLES are transmitted + */ + } + else { + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("InitPhyBcom: with auto-negotiation Port %d\n", Port)); + /* Set Auto-negotiation advertisement */ + + /* + * Workaround BCOM Errata #1 for the C5 type. + * 1000Base-T Link Acquisition Failure in Slave Mode + * Set Repeater/DTE bit 10 of the 1000Base-T Control Register + */ + Ctrl2 |= PHY_B_1000C_RD; + + /* Set Full/half duplex capabilities */ + switch (pPrt->PLinkMode) { + case SK_LMODE_AUTOHALF: + Ctrl2 |= PHY_B_1000C_AHD; + break; + case SK_LMODE_AUTOFULL: + Ctrl2 |= PHY_B_1000C_AFD; + break; + case SK_LMODE_AUTOBOTH: + Ctrl2 |= PHY_B_1000C_AFD | PHY_B_1000C_AHD; + break; + default: + SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E015, + SKERR_HWI_E015MSG); + } + + /* Set Flow-control capabilities */ + switch (pPrt->PFlowCtrlMode) { + case SK_FLOW_MODE_NONE: + Ctrl3 |= PHY_B_P_NO_PAUSE; + break; + case SK_FLOW_MODE_LOC_SEND: + Ctrl3 |= PHY_B_P_ASYM_MD; + break; + case SK_FLOW_MODE_SYMMETRIC: + Ctrl3 |= PHY_B_P_SYM_MD; + break; + case SK_FLOW_MODE_SYM_OR_REM: + Ctrl3 |= PHY_B_P_BOTH_MD; + break; + default: + SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E016, + SKERR_HWI_E016MSG); + } + + /* Restart Auto-negotiation */ + Ctrl1 |= PHY_CT_ANE | PHY_CT_RE_CFG; + } + + /* Initialize LED register here? */ + /* No. Please do it in SkDgXmitLed() (if required) and swap + init order of LEDs and XMAC. (MAl) */ + + /* Write 1000Base-T Control Register */ + SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_1000T_CTRL, Ctrl2); + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("Set 1000B-T Ctrl Reg=0x%04X\n", Ctrl2)); + + /* Write AutoNeg Advertisement Register */ + SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_AUNE_ADV, Ctrl3); + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("Set Auto-Neg.Adv.Reg=0x%04X\n", Ctrl3)); + + if (DoLoop) { + /* Set the Phy Loopback bit, too */ + Ctrl1 |= PHY_CT_LOOP; + } + + if (pAC->GIni.GIPortUsage == SK_JUMBO_LINK) { + /* configure FIFO to high latency for transmission of ext. packets */ + Ctrl4 |= PHY_B_PEC_HIGH_LA; + + /* configure reception of extended packets */ + Ctrl5 |= PHY_B_AC_LONG_PACK; + + SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_AUX_CTRL, Ctrl5); + } + + /* Configure LED Traffic Mode and Jumbo Frame usage if specified */ + SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_P_EXT_CTRL, Ctrl4); + + /* Write to the Phy control register */ + SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_CTRL, Ctrl1); + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("PHY Control Reg=0x%04X\n", Ctrl1)); +} /* SkXmInitPhyBcom */ +#endif /* GENESIS */ + +#ifdef YUKON +/****************************************************************************** + * + * SkGmInitPhyMarv() - Initialize the Marvell Phy registers + * + * Description: initializes all the Marvell Phy registers + * + * Note: + * + * Returns: + * nothing + */ +static void SkGmInitPhyMarv( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port, /* Port Index (MAC_1 + n) */ +SK_BOOL DoLoop) /* Should a Phy LoopBack be set-up? */ +{ + SK_GEPORT *pPrt; + SK_U16 PhyCtrl; + SK_U16 C1000BaseT; + SK_U16 AutoNegAdv; + SK_U16 ExtPhyCtrl; + SK_U16 LedCtrl; + SK_BOOL AutoNeg; +#if defined(SK_DIAG) || defined(DEBUG) + SK_U16 PhyStat; + SK_U16 PhyStat1; + SK_U16 PhySpecStat; +#endif /* SK_DIAG || DEBUG */ + + pPrt = &pAC->GIni.GP[Port]; + + /* Auto-negotiation ? */ + if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) { + AutoNeg = SK_FALSE; + } + else { + AutoNeg = SK_TRUE; + } + + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("InitPhyMarv: Port %d, auto-negotiation %s\n", + Port, AutoNeg ? "ON" : "OFF")); + +#ifdef VCPU + VCPUprintf(0, "SkGmInitPhyMarv(), Port=%u, DoLoop=%u\n", + Port, DoLoop); +#else /* VCPU */ + if (DoLoop) { + /* Set 'MAC Power up'-bit, set Manual MDI configuration */ + SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_CTRL, + PHY_M_PC_MAC_POW_UP); + } + else if (AutoNeg && pPrt->PLinkSpeed == SK_LSPEED_AUTO) { + /* Read Ext. PHY Specific Control */ + SkGmPhyRead(pAC, IoC, Port, PHY_MARV_EXT_CTRL, &ExtPhyCtrl); + + ExtPhyCtrl &= ~(PHY_M_EC_M_DSC_MSK | PHY_M_EC_S_DSC_MSK | + PHY_M_EC_MAC_S_MSK); + + ExtPhyCtrl |= PHY_M_EC_MAC_S(MAC_TX_CLK_25_MHZ) | + PHY_M_EC_M_DSC(0) | PHY_M_EC_S_DSC(1); + + SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_EXT_CTRL, ExtPhyCtrl); + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("Set Ext. PHY Ctrl=0x%04X\n", ExtPhyCtrl)); + } + + /* Read PHY Control */ + SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CTRL, &PhyCtrl); + + if (!AutoNeg) { + /* Disable Auto-negotiation */ + PhyCtrl &= ~PHY_CT_ANE; + } + + PhyCtrl |= PHY_CT_RESET; + /* Assert software reset */ + SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_CTRL, PhyCtrl); +#endif /* VCPU */ + + PhyCtrl = 0 /* PHY_CT_COL_TST */; + C1000BaseT = 0; + AutoNegAdv = PHY_SEL_TYPE; + + /* manually Master/Slave ? */ + if (pPrt->PMSMode != SK_MS_MODE_AUTO) { + /* enable Manual Master/Slave */ + C1000BaseT |= PHY_M_1000C_MSE; + + if (pPrt->PMSMode == SK_MS_MODE_MASTER) { + C1000BaseT |= PHY_M_1000C_MSC; /* set it to Master */ + } + } + + /* Auto-negotiation ? */ + if (!AutoNeg) { + + if (pPrt->PLinkMode == SK_LMODE_FULL) { + /* Set Full Duplex Mode */ + PhyCtrl |= PHY_CT_DUP_MD; + } + + /* Set Master/Slave manually if not already done */ + if (pPrt->PMSMode == SK_MS_MODE_AUTO) { + C1000BaseT |= PHY_M_1000C_MSE; /* set it to Slave */ + } + + /* Set Speed */ + switch (pPrt->PLinkSpeed) { + case SK_LSPEED_AUTO: + case SK_LSPEED_1000MBPS: + PhyCtrl |= PHY_CT_SP1000; + break; + case SK_LSPEED_100MBPS: + PhyCtrl |= PHY_CT_SP100; + break; + case SK_LSPEED_10MBPS: + break; + default: + SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E019, + SKERR_HWI_E019MSG); + } + + if (!DoLoop) { + PhyCtrl |= PHY_CT_RESET; + } + } + else { + /* Set Auto-negotiation advertisement */ + + if (pAC->GIni.GICopperType) { + /* Set Speed capabilities */ + switch (pPrt->PLinkSpeed) { + case SK_LSPEED_AUTO: + C1000BaseT |= PHY_M_1000C_AHD | PHY_M_1000C_AFD; + AutoNegAdv |= PHY_M_AN_100_FD | PHY_M_AN_100_HD | + PHY_M_AN_10_FD | PHY_M_AN_10_HD; + break; + case SK_LSPEED_1000MBPS: + C1000BaseT |= PHY_M_1000C_AHD | PHY_M_1000C_AFD; + break; + case SK_LSPEED_100MBPS: + AutoNegAdv |= PHY_M_AN_100_FD | PHY_M_AN_100_HD | + /* advertise 10Base-T also */ + PHY_M_AN_10_FD | PHY_M_AN_10_HD; + break; + case SK_LSPEED_10MBPS: + AutoNegAdv |= PHY_M_AN_10_FD | PHY_M_AN_10_HD; + break; + default: + SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E019, + SKERR_HWI_E019MSG); + } + + /* Set Full/half duplex capabilities */ + switch (pPrt->PLinkMode) { + case SK_LMODE_AUTOHALF: + C1000BaseT &= ~PHY_M_1000C_AFD; + AutoNegAdv &= ~(PHY_M_AN_100_FD | PHY_M_AN_10_FD); + break; + case SK_LMODE_AUTOFULL: + C1000BaseT &= ~PHY_M_1000C_AHD; + AutoNegAdv &= ~(PHY_M_AN_100_HD | PHY_M_AN_10_HD); + break; + case SK_LMODE_AUTOBOTH: + break; + default: + SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E015, + SKERR_HWI_E015MSG); + } + + /* Set Flow-control capabilities */ + switch (pPrt->PFlowCtrlMode) { + case SK_FLOW_MODE_NONE: + AutoNegAdv |= PHY_B_P_NO_PAUSE; + break; + case SK_FLOW_MODE_LOC_SEND: + AutoNegAdv |= PHY_B_P_ASYM_MD; + break; + case SK_FLOW_MODE_SYMMETRIC: + AutoNegAdv |= PHY_B_P_SYM_MD; + break; + case SK_FLOW_MODE_SYM_OR_REM: + AutoNegAdv |= PHY_B_P_BOTH_MD; + break; + default: + SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E016, + SKERR_HWI_E016MSG); + } + } + else { /* special defines for FIBER (88E1011S only) */ + + /* Set Full/half duplex capabilities */ + switch (pPrt->PLinkMode) { + case SK_LMODE_AUTOHALF: + AutoNegAdv |= PHY_M_AN_1000X_AHD; + break; + case SK_LMODE_AUTOFULL: + AutoNegAdv |= PHY_M_AN_1000X_AFD; + break; + case SK_LMODE_AUTOBOTH: + AutoNegAdv |= PHY_M_AN_1000X_AHD | PHY_M_AN_1000X_AFD; + break; + default: + SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E015, + SKERR_HWI_E015MSG); + } + + /* Set Flow-control capabilities */ + switch (pPrt->PFlowCtrlMode) { + case SK_FLOW_MODE_NONE: + AutoNegAdv |= PHY_M_P_NO_PAUSE_X; + break; + case SK_FLOW_MODE_LOC_SEND: + AutoNegAdv |= PHY_M_P_ASYM_MD_X; + break; + case SK_FLOW_MODE_SYMMETRIC: + AutoNegAdv |= PHY_M_P_SYM_MD_X; + break; + case SK_FLOW_MODE_SYM_OR_REM: + AutoNegAdv |= PHY_M_P_BOTH_MD_X; + break; + default: + SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E016, + SKERR_HWI_E016MSG); + } + } + + if (!DoLoop) { + /* Restart Auto-negotiation */ + PhyCtrl |= PHY_CT_ANE | PHY_CT_RE_CFG; + } + } + +#ifdef VCPU + /* + * E-mail from Gu Lin (08-03-2002): + */ + + /* Program PHY register 30 as 16'h0708 for simulation speed up */ + SkGmPhyWrite(pAC, IoC, Port, 30, 0x0700 /* 0x0708 */); + + VCpuWait(2000); + +#else /* VCPU */ + + /* Write 1000Base-T Control Register */ + SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_1000T_CTRL, C1000BaseT); + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("Set 1000B-T Ctrl =0x%04X\n", C1000BaseT)); + + /* Write AutoNeg Advertisement Register */ + SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_AUNE_ADV, AutoNegAdv); + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("Set Auto-Neg.Adv.=0x%04X\n", AutoNegAdv)); +#endif /* VCPU */ + + if (DoLoop) { + /* Set the PHY Loopback bit */ + PhyCtrl |= PHY_CT_LOOP; + +#ifdef XXX + /* Program PHY register 16 as 16'h0400 to force link good */ + SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_CTRL, PHY_M_PC_FL_GOOD); +#endif /* XXX */ + +#ifndef VCPU + if (pPrt->PLinkSpeed != SK_LSPEED_AUTO) { + /* Write Ext. PHY Specific Control */ + SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_EXT_CTRL, + (SK_U16)((pPrt->PLinkSpeed + 2) << 4)); + } +#endif /* VCPU */ + } +#ifdef TEST_ONLY + else if (pPrt->PLinkSpeed == SK_LSPEED_10MBPS) { + /* Write PHY Specific Control */ + SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_CTRL, + PHY_M_PC_EN_DET_MSK); + } +#endif + + /* Write to the PHY Control register */ + SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_CTRL, PhyCtrl); + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("Set PHY Ctrl Reg.=0x%04X\n", PhyCtrl)); + +#ifdef VCPU + VCpuWait(2000); +#else + + LedCtrl = PHY_M_LED_PULS_DUR(PULS_170MS) | PHY_M_LED_BLINK_RT(BLINK_84MS); + + if ((pAC->GIni.GILedBlinkCtrl & SK_ACT_LED_BLINK) != 0) { + LedCtrl |= PHY_M_LEDC_RX_CTRL | PHY_M_LEDC_TX_CTRL; + } + + if ((pAC->GIni.GILedBlinkCtrl & SK_DUP_LED_NORMAL) != 0) { + LedCtrl |= PHY_M_LEDC_DP_CTRL; + } + + SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_LED_CTRL, LedCtrl); + + if ((pAC->GIni.GILedBlinkCtrl & SK_LED_LINK100_ON) != 0) { + /* only in forced 100 Mbps mode */ + if (!AutoNeg && pPrt->PLinkSpeed == SK_LSPEED_100MBPS) { + + SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_LED_OVER, + PHY_M_LED_MO_100(MO_LED_ON)); + } + } + +#ifdef SK_DIAG + c_print("Set PHY Ctrl=0x%04X\n", PhyCtrl); + c_print("Set 1000 B-T=0x%04X\n", C1000BaseT); + c_print("Set Auto-Neg=0x%04X\n", AutoNegAdv); + c_print("Set Ext Ctrl=0x%04X\n", ExtPhyCtrl); +#endif /* SK_DIAG */ + +#if defined(SK_DIAG) || defined(DEBUG) + /* Read PHY Control */ + SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CTRL, &PhyCtrl); + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("PHY Ctrl Reg.=0x%04X\n", PhyCtrl)); + + /* Read 1000Base-T Control Register */ + SkGmPhyRead(pAC, IoC, Port, PHY_MARV_1000T_CTRL, &C1000BaseT); + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("1000B-T Ctrl =0x%04X\n", C1000BaseT)); + + /* Read AutoNeg Advertisement Register */ + SkGmPhyRead(pAC, IoC, Port, PHY_MARV_AUNE_ADV, &AutoNegAdv); + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("Auto-Neg.Adv.=0x%04X\n", AutoNegAdv)); + + /* Read Ext. PHY Specific Control */ + SkGmPhyRead(pAC, IoC, Port, PHY_MARV_EXT_CTRL, &ExtPhyCtrl); + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("Ext. PHY Ctrl=0x%04X\n", ExtPhyCtrl)); + + /* Read PHY Status */ + SkGmPhyRead(pAC, IoC, Port, PHY_MARV_STAT, &PhyStat); + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("PHY Stat Reg.=0x%04X\n", PhyStat)); + SkGmPhyRead(pAC, IoC, Port, PHY_MARV_STAT, &PhyStat1); + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("PHY Stat Reg.=0x%04X\n", PhyStat1)); + + /* Read PHY Specific Status */ + SkGmPhyRead(pAC, IoC, Port, PHY_MARV_PHY_STAT, &PhySpecStat); + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("PHY Spec Stat=0x%04X\n", PhySpecStat)); +#endif /* SK_DIAG || DEBUG */ + +#ifdef SK_DIAG + c_print("PHY Ctrl Reg=0x%04X\n", PhyCtrl); + c_print("PHY 1000 Reg=0x%04X\n", C1000BaseT); + c_print("PHY AnAd Reg=0x%04X\n", AutoNegAdv); + c_print("Ext Ctrl Reg=0x%04X\n", ExtPhyCtrl); + c_print("PHY Stat Reg=0x%04X\n", PhyStat); + c_print("PHY Stat Reg=0x%04X\n", PhyStat1); + c_print("PHY Spec Reg=0x%04X\n", PhySpecStat); +#endif /* SK_DIAG */ + +#endif /* VCPU */ + +} /* SkGmInitPhyMarv */ +#endif /* YUKON */ + + +#ifdef OTHER_PHY +/****************************************************************************** + * + * SkXmInitPhyLone() - Initialize the Level One Phy registers + * + * Description: initializes all the Level One Phy registers + * + * Note: + * + * Returns: + * nothing + */ +static void SkXmInitPhyLone( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port, /* Port Index (MAC_1 + n) */ +SK_BOOL DoLoop) /* Should a Phy LoopBack be set-up? */ +{ + SK_GEPORT *pPrt; + SK_U16 Ctrl1; + SK_U16 Ctrl2; + SK_U16 Ctrl3; + + Ctrl1 = PHY_CT_SP1000; + Ctrl2 = 0; + Ctrl3 = PHY_SEL_TYPE; + + pPrt = &pAC->GIni.GP[Port]; + + /* manually Master/Slave ? */ + if (pPrt->PMSMode != SK_MS_MODE_AUTO) { + Ctrl2 |= PHY_L_1000C_MSE; + + if (pPrt->PMSMode == SK_MS_MODE_MASTER) { + Ctrl2 |= PHY_L_1000C_MSC; + } + } + /* Auto-negotiation ? */ + if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) { + /* + * level one spec say: "1000 Mbps: manual mode not allowed" + * but lets see what happens... + */ + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("InitPhyLone: no auto-negotiation Port %d\n", Port)); + /* Set DuplexMode in Config register */ + if (pPrt->PLinkMode == SK_LMODE_FULL) { + Ctrl1 |= PHY_CT_DUP_MD; + } + + /* Determine Master/Slave manually if not already done */ + if (pPrt->PMSMode == SK_MS_MODE_AUTO) { + Ctrl2 |= PHY_L_1000C_MSE; /* set it to Slave */ + } + + /* + * Do NOT enable Auto-negotiation here. This would hold + * the link down because no IDLES are transmitted + */ + } + else { + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("InitPhyLone: with auto-negotiation Port %d\n", Port)); + /* Set Auto-negotiation advertisement */ + + /* Set Full/half duplex capabilities */ + switch (pPrt->PLinkMode) { + case SK_LMODE_AUTOHALF: + Ctrl2 |= PHY_L_1000C_AHD; + break; + case SK_LMODE_AUTOFULL: + Ctrl2 |= PHY_L_1000C_AFD; + break; + case SK_LMODE_AUTOBOTH: + Ctrl2 |= PHY_L_1000C_AFD | PHY_L_1000C_AHD; + break; + default: + SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E015, + SKERR_HWI_E015MSG); + } + + /* Set Flow-control capabilities */ + switch (pPrt->PFlowCtrlMode) { + case SK_FLOW_MODE_NONE: + Ctrl3 |= PHY_L_P_NO_PAUSE; + break; + case SK_FLOW_MODE_LOC_SEND: + Ctrl3 |= PHY_L_P_ASYM_MD; + break; + case SK_FLOW_MODE_SYMMETRIC: + Ctrl3 |= PHY_L_P_SYM_MD; + break; + case SK_FLOW_MODE_SYM_OR_REM: + Ctrl3 |= PHY_L_P_BOTH_MD; + break; + default: + SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E016, + SKERR_HWI_E016MSG); + } + + /* Restart Auto-negotiation */ + Ctrl1 = PHY_CT_ANE | PHY_CT_RE_CFG; + } + + /* Write 1000Base-T Control Register */ + SkXmPhyWrite(pAC, IoC, Port, PHY_LONE_1000T_CTRL, Ctrl2); + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("1000B-T Ctrl Reg=0x%04X\n", Ctrl2)); + + /* Write AutoNeg Advertisement Register */ + SkXmPhyWrite(pAC, IoC, Port, PHY_LONE_AUNE_ADV, Ctrl3); + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("Auto-Neg.Adv.Reg=0x%04X\n", Ctrl3)); + + if (DoLoop) { + /* Set the Phy Loopback bit, too */ + Ctrl1 |= PHY_CT_LOOP; + } + + /* Write to the Phy control register */ + SkXmPhyWrite(pAC, IoC, Port, PHY_LONE_CTRL, Ctrl1); + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("PHY Control Reg=0x%04X\n", Ctrl1)); +} /* SkXmInitPhyLone */ + + +/****************************************************************************** + * + * SkXmInitPhyNat() - Initialize the National Phy registers + * + * Description: initializes all the National Phy registers + * + * Note: + * + * Returns: + * nothing + */ +static void SkXmInitPhyNat( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port, /* Port Index (MAC_1 + n) */ +SK_BOOL DoLoop) /* Should a Phy LoopBack be set-up? */ +{ +/* todo: National */ +} /* SkXmInitPhyNat */ +#endif /* OTHER_PHY */ + + +/****************************************************************************** + * + * SkMacInitPhy() - Initialize the PHY registers + * + * Description: calls the Init PHY routines dep. on board type + * + * Note: + * + * Returns: + * nothing + */ +void SkMacInitPhy( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port, /* Port Index (MAC_1 + n) */ +SK_BOOL DoLoop) /* Should a Phy LoopBack be set-up? */ +{ + SK_GEPORT *pPrt; + + pPrt = &pAC->GIni.GP[Port]; + +#ifdef GENESIS + if (pAC->GIni.GIGenesis) { + + switch (pPrt->PhyType) { + case SK_PHY_XMAC: + SkXmInitPhyXmac(pAC, IoC, Port, DoLoop); + break; + case SK_PHY_BCOM: + SkXmInitPhyBcom(pAC, IoC, Port, DoLoop); + break; +#ifdef OTHER_PHY + case SK_PHY_LONE: + SkXmInitPhyLone(pAC, IoC, Port, DoLoop); + break; + case SK_PHY_NAT: + SkXmInitPhyNat(pAC, IoC, Port, DoLoop); + break; +#endif /* OTHER_PHY */ + } + } +#endif /* GENESIS */ + +#ifdef YUKON + if (pAC->GIni.GIYukon) { + + SkGmInitPhyMarv(pAC, IoC, Port, DoLoop); + } +#endif /* YUKON */ + +} /* SkMacInitPhy */ + + +#ifdef GENESIS +/****************************************************************************** + * + * SkXmAutoNegDoneXmac() - Auto-negotiation handling + * + * Description: + * This function handles the auto-negotiation if the Done bit is set. + * + * Returns: + * SK_AND_OK o.k. + * SK_AND_DUP_CAP Duplex capability error happened + * SK_AND_OTHER Other error happened + */ +static int SkXmAutoNegDoneXmac( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port) /* Port Index (MAC_1 + n) */ +{ + SK_GEPORT *pPrt; + SK_U16 ResAb; /* Resolved Ability */ + SK_U16 LPAb; /* Link Partner Ability */ + + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("AutoNegDoneXmac, Port %d\n", Port)); + + pPrt = &pAC->GIni.GP[Port]; + + /* Get PHY parameters */ + SkXmPhyRead(pAC, IoC, Port, PHY_XMAC_AUNE_LP, &LPAb); + SkXmPhyRead(pAC, IoC, Port, PHY_XMAC_RES_ABI, &ResAb); + + if ((LPAb & PHY_X_AN_RFB) != 0) { + /* At least one of the remote fault bit is set */ + /* Error */ + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("AutoNegFail: Remote fault bit set Port %d\n", Port)); + pPrt->PAutoNegFail = SK_TRUE; + return(SK_AND_OTHER); + } + + /* Check Duplex mismatch */ + if ((ResAb & (PHY_X_RS_HD | PHY_X_RS_FD)) == PHY_X_RS_FD) { + pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOFULL; + } + else if ((ResAb & (PHY_X_RS_HD | PHY_X_RS_FD)) == PHY_X_RS_HD) { + pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOHALF; + } + else { + /* Error */ + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("AutoNegFail: Duplex mode mismatch Port %d\n", Port)); + pPrt->PAutoNegFail = SK_TRUE; + return(SK_AND_DUP_CAP); + } + + /* Check PAUSE mismatch */ + /* We are NOT using chapter 4.23 of the Xaqti manual */ + /* We are using IEEE 802.3z/D5.0 Table 37-4 */ + if ((pPrt->PFlowCtrlMode == SK_FLOW_MODE_SYMMETRIC || + pPrt->PFlowCtrlMode == SK_FLOW_MODE_SYM_OR_REM) && + (LPAb & PHY_X_P_SYM_MD) != 0) { + /* Symmetric PAUSE */ + pPrt->PFlowCtrlStatus = SK_FLOW_STAT_SYMMETRIC; + } + else if (pPrt->PFlowCtrlMode == SK_FLOW_MODE_SYM_OR_REM && + (LPAb & PHY_X_RS_PAUSE) == PHY_X_P_ASYM_MD) { + /* Enable PAUSE receive, disable PAUSE transmit */ + pPrt->PFlowCtrlStatus = SK_FLOW_STAT_REM_SEND; + } + else if (pPrt->PFlowCtrlMode == SK_FLOW_MODE_LOC_SEND && + (LPAb & PHY_X_RS_PAUSE) == PHY_X_P_BOTH_MD) { + /* Disable PAUSE receive, enable PAUSE transmit */ + pPrt->PFlowCtrlStatus = SK_FLOW_STAT_LOC_SEND; + } + else { + /* PAUSE mismatch -> no PAUSE */ + pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE; + } + pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_1000MBPS; + + return(SK_AND_OK); +} /* SkXmAutoNegDoneXmac */ + + +/****************************************************************************** + * + * SkXmAutoNegDoneBcom() - Auto-negotiation handling + * + * Description: + * This function handles the auto-negotiation if the Done bit is set. + * + * Returns: + * SK_AND_OK o.k. + * SK_AND_DUP_CAP Duplex capability error happened + * SK_AND_OTHER Other error happened + */ +static int SkXmAutoNegDoneBcom( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port) /* Port Index (MAC_1 + n) */ +{ + SK_GEPORT *pPrt; + SK_U16 LPAb; /* Link Partner Ability */ + SK_U16 AuxStat; /* Auxiliary Status */ + +#ifdef TEST_ONLY +01-Sep-2000 RA;:;: + SK_U16 ResAb; /* Resolved Ability */ +#endif /* 0 */ + + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("AutoNegDoneBcom, Port %d\n", Port)); + pPrt = &pAC->GIni.GP[Port]; + + /* Get PHY parameters */ + SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUNE_LP, &LPAb); +#ifdef TEST_ONLY +01-Sep-2000 RA;:;: + SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_1000T_STAT, &ResAb); +#endif /* 0 */ + + SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUX_STAT, &AuxStat); + + if ((LPAb & PHY_B_AN_RF) != 0) { + /* Remote fault bit is set: Error */ + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("AutoNegFail: Remote fault bit set Port %d\n", Port)); + pPrt->PAutoNegFail = SK_TRUE; + return(SK_AND_OTHER); + } + + /* Check Duplex mismatch */ + if ((AuxStat & PHY_B_AS_AN_RES_MSK) == PHY_B_RES_1000FD) { + pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOFULL; + } + else if ((AuxStat & PHY_B_AS_AN_RES_MSK) == PHY_B_RES_1000HD) { + pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOHALF; + } + else { + /* Error */ + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("AutoNegFail: Duplex mode mismatch Port %d\n", Port)); + pPrt->PAutoNegFail = SK_TRUE; + return(SK_AND_DUP_CAP); + } + +#ifdef TEST_ONLY +01-Sep-2000 RA;:;: + /* Check Master/Slave resolution */ + if ((ResAb & PHY_B_1000S_MSF) != 0) { + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("Master/Slave Fault Port %d\n", Port)); + pPrt->PAutoNegFail = SK_TRUE; + pPrt->PMSStatus = SK_MS_STAT_FAULT; + return(SK_AND_OTHER); + } + + pPrt->PMSStatus = ((ResAb & PHY_B_1000S_MSR) != 0) ? + SK_MS_STAT_MASTER : SK_MS_STAT_SLAVE; +#endif /* 0 */ + + /* Check PAUSE mismatch ??? */ + /* We are using IEEE 802.3z/D5.0 Table 37-4 */ + if ((AuxStat & PHY_B_AS_PAUSE_MSK) == PHY_B_AS_PAUSE_MSK) { + /* Symmetric PAUSE */ + pPrt->PFlowCtrlStatus = SK_FLOW_STAT_SYMMETRIC; + } + else if ((AuxStat & PHY_B_AS_PAUSE_MSK) == PHY_B_AS_PRR) { + /* Enable PAUSE receive, disable PAUSE transmit */ + pPrt->PFlowCtrlStatus = SK_FLOW_STAT_REM_SEND; + } + else if ((AuxStat & PHY_B_AS_PAUSE_MSK) == PHY_B_AS_PRT) { + /* Disable PAUSE receive, enable PAUSE transmit */ + pPrt->PFlowCtrlStatus = SK_FLOW_STAT_LOC_SEND; + } + else { + /* PAUSE mismatch -> no PAUSE */ + pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE; + } + pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_1000MBPS; + + return(SK_AND_OK); +} /* SkXmAutoNegDoneBcom */ +#endif /* GENESIS */ + + +#ifdef YUKON +/****************************************************************************** + * + * SkGmAutoNegDoneMarv() - Auto-negotiation handling + * + * Description: + * This function handles the auto-negotiation if the Done bit is set. + * + * Returns: + * SK_AND_OK o.k. + * SK_AND_DUP_CAP Duplex capability error happened + * SK_AND_OTHER Other error happened + */ +static int SkGmAutoNegDoneMarv( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port) /* Port Index (MAC_1 + n) */ +{ + SK_GEPORT *pPrt; + SK_U16 LPAb; /* Link Partner Ability */ + SK_U16 ResAb; /* Resolved Ability */ + SK_U16 AuxStat; /* Auxiliary Status */ + + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("AutoNegDoneMarv, Port %d\n", Port)); + pPrt = &pAC->GIni.GP[Port]; + + /* Get PHY parameters */ + SkGmPhyRead(pAC, IoC, Port, PHY_MARV_AUNE_LP, &LPAb); + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("Link P.Abil.=0x%04X\n", LPAb)); + + if ((LPAb & PHY_M_AN_RF) != 0) { + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("AutoNegFail: Remote fault bit set Port %d\n", Port)); + pPrt->PAutoNegFail = SK_TRUE; + return(SK_AND_OTHER); + } + + SkGmPhyRead(pAC, IoC, Port, PHY_MARV_1000T_STAT, &ResAb); + + /* Check Master/Slave resolution */ + if ((ResAb & PHY_B_1000S_MSF) != 0) { + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("Master/Slave Fault Port %d\n", Port)); + pPrt->PAutoNegFail = SK_TRUE; + pPrt->PMSStatus = SK_MS_STAT_FAULT; + return(SK_AND_OTHER); + } + + pPrt->PMSStatus = ((ResAb & PHY_B_1000S_MSR) != 0) ? + (SK_U8)SK_MS_STAT_MASTER : (SK_U8)SK_MS_STAT_SLAVE; + + /* Read PHY Specific Status */ + SkGmPhyRead(pAC, IoC, Port, PHY_MARV_PHY_STAT, &AuxStat); + + /* Check Speed & Duplex resolved */ + if ((AuxStat & PHY_M_PS_SPDUP_RES) == 0) { + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("AutoNegFail: Speed & Duplex not resolved, Port %d\n", Port)); + pPrt->PAutoNegFail = SK_TRUE; + pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_UNKNOWN; + return(SK_AND_DUP_CAP); + } + + if ((AuxStat & PHY_M_PS_FULL_DUP) != 0) { + pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOFULL; + } + else { + pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOHALF; + } + + /* Check PAUSE mismatch ??? */ + /* We are using IEEE 802.3z/D5.0 Table 37-4 */ + if ((AuxStat & PHY_M_PS_PAUSE_MSK) == PHY_M_PS_PAUSE_MSK) { + /* Symmetric PAUSE */ + pPrt->PFlowCtrlStatus = SK_FLOW_STAT_SYMMETRIC; + } + else if ((AuxStat & PHY_M_PS_PAUSE_MSK) == PHY_M_PS_RX_P_EN) { + /* Enable PAUSE receive, disable PAUSE transmit */ + pPrt->PFlowCtrlStatus = SK_FLOW_STAT_REM_SEND; + } + else if ((AuxStat & PHY_M_PS_PAUSE_MSK) == PHY_M_PS_TX_P_EN) { + /* Disable PAUSE receive, enable PAUSE transmit */ + pPrt->PFlowCtrlStatus = SK_FLOW_STAT_LOC_SEND; + } + else { + /* PAUSE mismatch -> no PAUSE */ + pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE; + } + + /* set used link speed */ + switch ((unsigned)(AuxStat & PHY_M_PS_SPEED_MSK)) { + case (unsigned)PHY_M_PS_SPEED_1000: + pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_1000MBPS; + break; + case PHY_M_PS_SPEED_100: + pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_100MBPS; + break; + default: + pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_10MBPS; + } + + return(SK_AND_OK); +} /* SkGmAutoNegDoneMarv */ +#endif /* YUKON */ + + +#ifdef OTHER_PHY +/****************************************************************************** + * + * SkXmAutoNegDoneLone() - Auto-negotiation handling + * + * Description: + * This function handles the auto-negotiation if the Done bit is set. + * + * Returns: + * SK_AND_OK o.k. + * SK_AND_DUP_CAP Duplex capability error happened + * SK_AND_OTHER Other error happened + */ +static int SkXmAutoNegDoneLone( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port) /* Port Index (MAC_1 + n) */ +{ + SK_GEPORT *pPrt; + SK_U16 ResAb; /* Resolved Ability */ + SK_U16 LPAb; /* Link Partner Ability */ + SK_U16 QuickStat; /* Auxiliary Status */ + + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("AutoNegDoneLone, Port %d\n", Port)); + pPrt = &pAC->GIni.GP[Port]; + + /* Get PHY parameters */ + SkXmPhyRead(pAC, IoC, Port, PHY_LONE_AUNE_LP, &LPAb); + SkXmPhyRead(pAC, IoC, Port, PHY_LONE_1000T_STAT, &ResAb); + SkXmPhyRead(pAC, IoC, Port, PHY_LONE_Q_STAT, &QuickStat); + + if ((LPAb & PHY_L_AN_RF) != 0) { + /* Remote fault bit is set */ + /* Error */ + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("AutoNegFail: Remote fault bit set Port %d\n", Port)); + pPrt->PAutoNegFail = SK_TRUE; + return(SK_AND_OTHER); + } + + /* Check Duplex mismatch */ + if ((QuickStat & PHY_L_QS_DUP_MOD) != 0) { + pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOFULL; + } + else { + pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOHALF; + } + + /* Check Master/Slave resolution */ + if ((ResAb & PHY_L_1000S_MSF) != 0) { + /* Error */ + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("Master/Slave Fault Port %d\n", Port)); + pPrt->PAutoNegFail = SK_TRUE; + pPrt->PMSStatus = SK_MS_STAT_FAULT; + return(SK_AND_OTHER); + } + else if (ResAb & PHY_L_1000S_MSR) { + pPrt->PMSStatus = SK_MS_STAT_MASTER; + } + else { + pPrt->PMSStatus = SK_MS_STAT_SLAVE; + } + + /* Check PAUSE mismatch */ + /* We are using IEEE 802.3z/D5.0 Table 37-4 */ + /* we must manually resolve the abilities here */ + pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE; + + switch (pPrt->PFlowCtrlMode) { + case SK_FLOW_MODE_NONE: + /* default */ + break; + case SK_FLOW_MODE_LOC_SEND: + if ((QuickStat & (PHY_L_QS_PAUSE | PHY_L_QS_AS_PAUSE)) == + (PHY_L_QS_PAUSE | PHY_L_QS_AS_PAUSE)) { + /* Disable PAUSE receive, enable PAUSE transmit */ + pPrt->PFlowCtrlStatus = SK_FLOW_STAT_LOC_SEND; + } + break; + case SK_FLOW_MODE_SYMMETRIC: + if ((QuickStat & PHY_L_QS_PAUSE) != 0) { + /* Symmetric PAUSE */ + pPrt->PFlowCtrlStatus = SK_FLOW_STAT_SYMMETRIC; + } + break; + case SK_FLOW_MODE_SYM_OR_REM: + if ((QuickStat & (PHY_L_QS_PAUSE | PHY_L_QS_AS_PAUSE)) == + PHY_L_QS_AS_PAUSE) { + /* Enable PAUSE receive, disable PAUSE transmit */ + pPrt->PFlowCtrlStatus = SK_FLOW_STAT_REM_SEND; + } + else if ((QuickStat & PHY_L_QS_PAUSE) != 0) { + /* Symmetric PAUSE */ + pPrt->PFlowCtrlStatus = SK_FLOW_STAT_SYMMETRIC; + } + break; + default: + SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E016, + SKERR_HWI_E016MSG); + } + + return(SK_AND_OK); +} /* SkXmAutoNegDoneLone */ + + +/****************************************************************************** + * + * SkXmAutoNegDoneNat() - Auto-negotiation handling + * + * Description: + * This function handles the auto-negotiation if the Done bit is set. + * + * Returns: + * SK_AND_OK o.k. + * SK_AND_DUP_CAP Duplex capability error happened + * SK_AND_OTHER Other error happened + */ +static int SkXmAutoNegDoneNat( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port) /* Port Index (MAC_1 + n) */ +{ +/* todo: National */ + return(SK_AND_OK); +} /* SkXmAutoNegDoneNat */ +#endif /* OTHER_PHY */ + + +/****************************************************************************** + * + * SkMacAutoNegDone() - Auto-negotiation handling + * + * Description: calls the auto-negotiation done routines dep. on board type + * + * Returns: + * SK_AND_OK o.k. + * SK_AND_DUP_CAP Duplex capability error happened + * SK_AND_OTHER Other error happened + */ +int SkMacAutoNegDone( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port) /* Port Index (MAC_1 + n) */ +{ + SK_GEPORT *pPrt; + int Rtv; + + Rtv = SK_AND_OK; + + pPrt = &pAC->GIni.GP[Port]; + +#ifdef GENESIS + if (pAC->GIni.GIGenesis) { + + switch (pPrt->PhyType) { + + case SK_PHY_XMAC: + Rtv = SkXmAutoNegDoneXmac(pAC, IoC, Port); + break; + case SK_PHY_BCOM: + Rtv = SkXmAutoNegDoneBcom(pAC, IoC, Port); + break; +#ifdef OTHER_PHY + case SK_PHY_LONE: + Rtv = SkXmAutoNegDoneLone(pAC, IoC, Port); + break; + case SK_PHY_NAT: + Rtv = SkXmAutoNegDoneNat(pAC, IoC, Port); + break; +#endif /* OTHER_PHY */ + default: + return(SK_AND_OTHER); + } + } +#endif /* GENESIS */ + +#ifdef YUKON + if (pAC->GIni.GIYukon) { + + Rtv = SkGmAutoNegDoneMarv(pAC, IoC, Port); + } +#endif /* YUKON */ + + if (Rtv != SK_AND_OK) { + return(Rtv); + } + + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("AutoNeg done Port %d\n", Port)); + + /* We checked everything and may now enable the link */ + pPrt->PAutoNegFail = SK_FALSE; + + SkMacRxTxEnable(pAC, IoC, Port); + + return(SK_AND_OK); +} /* SkMacAutoNegDone */ + + +/****************************************************************************** + * + * SkMacRxTxEnable() - Enable Rx/Tx activity if port is up + * + * Description: enables Rx/Tx dep. on board type + * + * Returns: + * 0 o.k. + * != 0 Error happened + */ +int SkMacRxTxEnable( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port) /* Port Index (MAC_1 + n) */ +{ + SK_GEPORT *pPrt; + SK_U16 Reg; /* 16-bit register value */ + SK_U16 IntMask; /* MAC interrupt mask */ +#ifdef GENESIS + SK_U16 SWord; +#endif + + pPrt = &pAC->GIni.GP[Port]; + + if (!pPrt->PHWLinkUp) { + /* The Hardware link is NOT up */ + return(0); + } + + if ((pPrt->PLinkMode == SK_LMODE_AUTOHALF || + pPrt->PLinkMode == SK_LMODE_AUTOFULL || + pPrt->PLinkMode == SK_LMODE_AUTOBOTH) && + pPrt->PAutoNegFail) { + /* Auto-negotiation is not done or failed */ + return(0); + } + +#ifdef GENESIS + if (pAC->GIni.GIGenesis) { + /* set Duplex Mode and Pause Mode */ + SkXmInitDupMd(pAC, IoC, Port); + + SkXmInitPauseMd(pAC, IoC, Port); + + /* + * Initialize the Interrupt Mask Register. Default IRQs are... + * - Link Asynchronous Event + * - Link Partner requests config + * - Auto Negotiation Done + * - Rx Counter Event Overflow + * - Tx Counter Event Overflow + * - Transmit FIFO Underrun + */ + IntMask = XM_DEF_MSK; + +#ifdef DEBUG + /* add IRQ for Receive FIFO Overflow */ + IntMask &= ~XM_IS_RXF_OV; +#endif /* DEBUG */ + + if (pPrt->PhyType != SK_PHY_XMAC) { + /* disable GP0 interrupt bit */ + IntMask |= XM_IS_INP_ASS; + } + XM_OUT16(IoC, Port, XM_IMSK, IntMask); + + /* get MMU Command Reg. */ + XM_IN16(IoC, Port, XM_MMU_CMD, &Reg); + + if (pPrt->PhyType != SK_PHY_XMAC && + (pPrt->PLinkModeStatus == SK_LMODE_STAT_FULL || + pPrt->PLinkModeStatus == SK_LMODE_STAT_AUTOFULL)) { + /* set to Full Duplex */ + Reg |= XM_MMU_GMII_FD; + } + + switch (pPrt->PhyType) { + case SK_PHY_BCOM: + /* + * Workaround BCOM Errata (#10523) for all BCom Phys + * Enable Power Management after link up + */ + SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUX_CTRL, &SWord); + SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_AUX_CTRL, + (SK_U16)(SWord & ~PHY_B_AC_DIS_PM)); + SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_INT_MASK, + (SK_U16)PHY_B_DEF_MSK); + break; +#ifdef OTHER_PHY + case SK_PHY_LONE: + SkXmPhyWrite(pAC, IoC, Port, PHY_LONE_INT_ENAB, PHY_L_DEF_MSK); + break; + case SK_PHY_NAT: + /* todo National: + SkXmPhyWrite(pAC, IoC, Port, PHY_NAT_INT_MASK, PHY_N_DEF_MSK); */ + /* no interrupts possible from National ??? */ + break; +#endif /* OTHER_PHY */ + } + + /* enable Rx/Tx */ + XM_OUT16(IoC, Port, XM_MMU_CMD, Reg | XM_MMU_ENA_RX | XM_MMU_ENA_TX); + } +#endif /* GENESIS */ + +#ifdef YUKON + if (pAC->GIni.GIYukon) { + /* + * Initialize the Interrupt Mask Register. Default IRQs are... + * - Rx Counter Event Overflow + * - Tx Counter Event Overflow + * - Transmit FIFO Underrun + */ + IntMask = GMAC_DEF_MSK; + +#ifdef DEBUG + /* add IRQ for Receive FIFO Overrun */ + IntMask |= GM_IS_RX_FF_OR; +#endif /* DEBUG */ + + SK_OUT8(IoC, GMAC_IRQ_MSK, (SK_U8)IntMask); + + /* get General Purpose Control */ + GM_IN16(IoC, Port, GM_GP_CTRL, &Reg); + + if (pPrt->PLinkModeStatus == SK_LMODE_STAT_FULL || + pPrt->PLinkModeStatus == SK_LMODE_STAT_AUTOFULL) { + /* set to Full Duplex */ + Reg |= GM_GPCR_DUP_FULL; + } + + /* enable Rx/Tx */ + GM_OUT16(IoC, Port, GM_GP_CTRL, (SK_U16)(Reg | GM_GPCR_RX_ENA | + GM_GPCR_TX_ENA)); + +#ifndef VCPU + /* Enable all PHY interrupts */ + SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_INT_MASK, + (SK_U16)PHY_M_DEF_MSK); +#endif /* VCPU */ + } +#endif /* YUKON */ + + return(0); + +} /* SkMacRxTxEnable */ + + +/****************************************************************************** + * + * SkMacRxTxDisable() - Disable Receiver and Transmitter + * + * Description: disables Rx/Tx dep. on board type + * + * Returns: N/A + */ +void SkMacRxTxDisable( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* IO context */ +int Port) /* Port Index (MAC_1 + n) */ +{ + SK_U16 Word; + +#ifdef GENESIS + if (pAC->GIni.GIGenesis) { + + XM_IN16(IoC, Port, XM_MMU_CMD, &Word); + + XM_OUT16(IoC, Port, XM_MMU_CMD, Word & ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX)); + + /* dummy read to ensure writing */ + XM_IN16(IoC, Port, XM_MMU_CMD, &Word); + } +#endif /* GENESIS */ + +#ifdef YUKON + if (pAC->GIni.GIYukon) { + + GM_IN16(IoC, Port, GM_GP_CTRL, &Word); + + GM_OUT16(IoC, Port, GM_GP_CTRL, (SK_U16)(Word & ~(GM_GPCR_RX_ENA | + GM_GPCR_TX_ENA))); + + /* dummy read to ensure writing */ + GM_IN16(IoC, Port, GM_GP_CTRL, &Word); + } +#endif /* YUKON */ + +} /* SkMacRxTxDisable */ + + +/****************************************************************************** + * + * SkMacIrqDisable() - Disable IRQ from MAC + * + * Description: sets the IRQ-mask to disable IRQ dep. on board type + * + * Returns: N/A + */ +void SkMacIrqDisable( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* IO context */ +int Port) /* Port Index (MAC_1 + n) */ +{ + SK_GEPORT *pPrt; +#ifdef GENESIS + SK_U16 Word; +#endif + + pPrt = &pAC->GIni.GP[Port]; + +#ifdef GENESIS + if (pAC->GIni.GIGenesis) { + + /* disable all XMAC IRQs */ + XM_OUT16(IoC, Port, XM_IMSK, 0xffff); + + /* Disable all PHY interrupts */ + switch (pPrt->PhyType) { + case SK_PHY_BCOM: + /* Make sure that PHY is initialized */ + if (pPrt->PState != SK_PRT_RESET) { + /* NOT allowed if BCOM is in RESET state */ + /* Workaround BCOM Errata (#10523) all BCom */ + /* Disable Power Management if link is down */ + SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUX_CTRL, &Word); + SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_AUX_CTRL, + (SK_U16)(Word | PHY_B_AC_DIS_PM)); + SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_INT_MASK, 0xffff); + } + break; +#ifdef OTHER_PHY + case SK_PHY_LONE: + SkXmPhyWrite(pAC, IoC, Port, PHY_LONE_INT_ENAB, 0); + break; + case SK_PHY_NAT: + /* todo: National + SkXmPhyWrite(pAC, IoC, Port, PHY_NAT_INT_MASK, 0xffff); */ + break; +#endif /* OTHER_PHY */ + } + } +#endif /* GENESIS */ + +#ifdef YUKON + if (pAC->GIni.GIYukon) { + /* disable all GMAC IRQs */ + SK_OUT8(IoC, GMAC_IRQ_MSK, 0); + +#ifndef VCPU + /* Disable all PHY interrupts */ + SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_INT_MASK, 0); +#endif /* VCPU */ + } +#endif /* YUKON */ + +} /* SkMacIrqDisable */ + + +#ifdef SK_DIAG +/****************************************************************************** + * + * SkXmSendCont() - Enable / Disable Send Continuous Mode + * + * Description: enable / disable Send Continuous Mode on XMAC + * + * Returns: + * nothing + */ +void SkXmSendCont( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port, /* Port Index (MAC_1 + n) */ +SK_BOOL Enable) /* Enable / Disable */ +{ + SK_U32 MdReg; + + XM_IN32(IoC, Port, XM_MODE, &MdReg); + + if (Enable) { + MdReg |= XM_MD_TX_CONT; + } + else { + MdReg &= ~XM_MD_TX_CONT; + } + /* setup Mode Register */ + XM_OUT32(IoC, Port, XM_MODE, MdReg); + +} /* SkXmSendCont */ + + +/****************************************************************************** + * + * SkMacTimeStamp() - Enable / Disable Time Stamp + * + * Description: enable / disable Time Stamp generation for Rx packets + * + * Returns: + * nothing + */ +void SkMacTimeStamp( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port, /* Port Index (MAC_1 + n) */ +SK_BOOL Enable) /* Enable / Disable */ +{ + SK_U32 MdReg; + SK_U8 TimeCtrl; + + if (pAC->GIni.GIGenesis) { + + XM_IN32(IoC, Port, XM_MODE, &MdReg); + + if (Enable) { + MdReg |= XM_MD_ATS; + } + else { + MdReg &= ~XM_MD_ATS; + } + /* setup Mode Register */ + XM_OUT32(IoC, Port, XM_MODE, MdReg); + } + else { + if (Enable) { + TimeCtrl = GMT_ST_START | GMT_ST_CLR_IRQ; + } + else { + TimeCtrl = GMT_ST_STOP | GMT_ST_CLR_IRQ; + } + /* Start/Stop Time Stamp Timer */ + SK_OUT8(IoC, GMAC_TI_ST_CTRL, TimeCtrl); + } + +} /* SkMacTimeStamp*/ + +#else /* !SK_DIAG */ + +#ifdef GENESIS +/****************************************************************************** + * + * SkXmAutoNegLipaXmac() - Decides whether Link Partner could do auto-neg + * + * This function analyses the Interrupt status word. If any of the + * Auto-negotiating interrupt bits are set, the PLipaAutoNeg variable + * is set true. + */ +void SkXmAutoNegLipaXmac( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port, /* Port Index (MAC_1 + n) */ +SK_U16 IStatus) /* Interrupt Status word to analyse */ +{ + SK_GEPORT *pPrt; + + pPrt = &pAC->GIni.GP[Port]; + + if (pPrt->PLipaAutoNeg != SK_LIPA_AUTO && + (IStatus & (XM_IS_LIPA_RC | XM_IS_RX_PAGE | XM_IS_AND)) != 0) { + + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("AutoNegLipa: AutoNeg detected on Port %d, IStatus=0x%04X\n", + Port, IStatus)); + pPrt->PLipaAutoNeg = SK_LIPA_AUTO; + } +} /* SkXmAutoNegLipaXmac */ +#endif /* GENESIS */ + + +/****************************************************************************** + * + * SkMacAutoNegLipaPhy() - Decides whether Link Partner could do auto-neg + * + * This function analyses the PHY status word. + * If any of the Auto-negotiating bits are set, the PLipaAutoNeg variable + * is set true. + */ +void SkMacAutoNegLipaPhy( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port, /* Port Index (MAC_1 + n) */ +SK_U16 PhyStat) /* PHY Status word to analyse */ +{ + SK_GEPORT *pPrt; + + pPrt = &pAC->GIni.GP[Port]; + + if (pPrt->PLipaAutoNeg != SK_LIPA_AUTO && + (PhyStat & PHY_ST_AN_OVER) != 0) { + + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("AutoNegLipa: AutoNeg detected on Port %d, PhyStat=0x%04X\n", + Port, PhyStat)); + pPrt->PLipaAutoNeg = SK_LIPA_AUTO; + } +} /* SkMacAutoNegLipaPhy */ + + +#ifdef GENESIS +/****************************************************************************** + * + * SkXmIrq() - Interrupt Service Routine + * + * Description: services an Interrupt Request of the XMAC + * + * Note: + * With an external PHY, some interrupt bits are not meaningfull any more: + * - LinkAsyncEvent (bit #14) XM_IS_LNK_AE + * - LinkPartnerReqConfig (bit #10) XM_IS_LIPA_RC + * - Page Received (bit #9) XM_IS_RX_PAGE + * - NextPageLoadedForXmt (bit #8) XM_IS_TX_PAGE + * - AutoNegDone (bit #7) XM_IS_AND + * Also probably not valid any more is the GP0 input bit: + * - GPRegisterBit0set XM_IS_INP_ASS + * + * Returns: + * nothing + */ +static void SkXmIrq( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port) /* Port Index (MAC_1 + n) */ +{ + SK_GEPORT *pPrt; + SK_EVPARA Para; + SK_U16 IStatus; /* Interrupt status read from the XMAC */ + SK_U16 IStatus2; +#ifdef SK_SLIM + SK_U64 OverflowStatus; +#endif + + pPrt = &pAC->GIni.GP[Port]; + + XM_IN16(IoC, Port, XM_ISRC, &IStatus); + + /* LinkPartner Auto-negable? */ + if (pPrt->PhyType == SK_PHY_XMAC) { + SkXmAutoNegLipaXmac(pAC, IoC, Port, IStatus); + } + else { + /* mask bits that are not used with ext. PHY */ + IStatus &= ~(XM_IS_LNK_AE | XM_IS_LIPA_RC | + XM_IS_RX_PAGE | XM_IS_TX_PAGE | + XM_IS_AND | XM_IS_INP_ASS); + } + + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ, + ("XmacIrq Port %d Isr 0x%04X\n", Port, IStatus)); + + if (!pPrt->PHWLinkUp) { + /* Spurious XMAC interrupt */ + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ, + ("SkXmIrq: spurious interrupt on Port %d\n", Port)); + return; + } + + if ((IStatus & XM_IS_INP_ASS) != 0) { + /* Reread ISR Register if link is not in sync */ + XM_IN16(IoC, Port, XM_ISRC, &IStatus2); + + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ, + ("SkXmIrq: Link async. Double check Port %d 0x%04X 0x%04X\n", + Port, IStatus, IStatus2)); + IStatus &= ~XM_IS_INP_ASS; + IStatus |= IStatus2; + } + + if ((IStatus & XM_IS_LNK_AE) != 0) { + /* not used, GP0 is used instead */ + } + + if ((IStatus & XM_IS_TX_ABORT) != 0) { + /* not used */ + } + + if ((IStatus & XM_IS_FRC_INT) != 0) { + /* not used, use ASIC IRQ instead if needed */ + } + + if ((IStatus & (XM_IS_INP_ASS | XM_IS_LIPA_RC | XM_IS_RX_PAGE)) != 0) { + SkHWLinkDown(pAC, IoC, Port); + + /* Signal to RLMT */ + Para.Para32[0] = (SK_U32)Port; + SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para); + + /* Start workaround Errata #2 timer */ + SkTimerStart(pAC, IoC, &pPrt->PWaTimer, SK_WA_INA_TIME, + SKGE_HWAC, SK_HWEV_WATIM, Para); + } + + if ((IStatus & XM_IS_RX_PAGE) != 0) { + /* not used */ + } + + if ((IStatus & XM_IS_TX_PAGE) != 0) { + /* not used */ + } + + if ((IStatus & XM_IS_AND) != 0) { + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ, + ("SkXmIrq: AND on link that is up Port %d\n", Port)); + } + + if ((IStatus & XM_IS_TSC_OV) != 0) { + /* not used */ + } + + /* Combined Tx & Rx Counter Overflow SIRQ Event */ + if ((IStatus & (XM_IS_RXC_OV | XM_IS_TXC_OV)) != 0) { +#ifdef SK_SLIM + SkXmOverflowStatus(pAC, IoC, Port, IStatus, &OverflowStatus); +#else + Para.Para32[0] = (SK_U32)Port; + Para.Para32[1] = (SK_U32)IStatus; + SkPnmiEvent(pAC, IoC, SK_PNMI_EVT_SIRQ_OVERFLOW, Para); +#endif /* SK_SLIM */ + } + + if ((IStatus & XM_IS_RXF_OV) != 0) { + /* normal situation -> no effect */ +#ifdef DEBUG + pPrt->PRxOverCnt++; +#endif /* DEBUG */ + } + + if ((IStatus & XM_IS_TXF_UR) != 0) { + /* may NOT happen -> error log */ + SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E020, SKERR_SIRQ_E020MSG); + } + + if ((IStatus & XM_IS_TX_COMP) != 0) { + /* not served here */ + } + + if ((IStatus & XM_IS_RX_COMP) != 0) { + /* not served here */ + } +} /* SkXmIrq */ +#endif /* GENESIS */ + + +#ifdef YUKON +/****************************************************************************** + * + * SkGmIrq() - Interrupt Service Routine + * + * Description: services an Interrupt Request of the GMAC + * + * Note: + * + * Returns: + * nothing + */ +static void SkGmIrq( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port) /* Port Index (MAC_1 + n) */ +{ + SK_GEPORT *pPrt; + SK_U8 IStatus; /* Interrupt status */ +#ifdef SK_SLIM + SK_U64 OverflowStatus; +#else + SK_EVPARA Para; +#endif + + pPrt = &pAC->GIni.GP[Port]; + + SK_IN8(IoC, GMAC_IRQ_SRC, &IStatus); + +#ifdef XXX + /* LinkPartner Auto-negable? */ + SkMacAutoNegLipaPhy(pAC, IoC, Port, IStatus); +#endif /* XXX */ + + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ, + ("GmacIrq Port %d Isr 0x%04X\n", Port, IStatus)); + + /* Combined Tx & Rx Counter Overflow SIRQ Event */ + if (IStatus & (GM_IS_RX_CO_OV | GM_IS_TX_CO_OV)) { + /* these IRQs will be cleared by reading GMACs register */ +#ifdef SK_SLIM + SkGmOverflowStatus(pAC, IoC, Port, IStatus, &OverflowStatus); +#else + Para.Para32[0] = (SK_U32)Port; + Para.Para32[1] = (SK_U32)IStatus; + SkPnmiEvent(pAC, IoC, SK_PNMI_EVT_SIRQ_OVERFLOW, Para); +#endif + } + + if (IStatus & GM_IS_RX_FF_OR) { + /* clear GMAC Rx FIFO Overrun IRQ */ + SK_OUT8(IoC, MR_ADDR(Port, RX_GMF_CTRL_T), (SK_U8)GMF_CLI_RX_FO); +#ifdef DEBUG + pPrt->PRxOverCnt++; +#endif /* DEBUG */ + } + + if (IStatus & GM_IS_TX_FF_UR) { + /* clear GMAC Tx FIFO Underrun IRQ */ + SK_OUT8(IoC, MR_ADDR(Port, TX_GMF_CTRL_T), (SK_U8)GMF_CLI_TX_FU); + /* may NOT happen -> error log */ + SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E020, SKERR_SIRQ_E020MSG); + } + + if (IStatus & GM_IS_TX_COMPL) { + /* not served here */ + } + + if (IStatus & GM_IS_RX_COMPL) { + /* not served here */ + } +} /* SkGmIrq */ +#endif /* YUKON */ + + +/****************************************************************************** + * + * SkMacIrq() - Interrupt Service Routine for MAC + * + * Description: calls the Interrupt Service Routine dep. on board type + * + * Returns: + * nothing + */ +void SkMacIrq( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port) /* Port Index (MAC_1 + n) */ +{ +#ifdef GENESIS + if (pAC->GIni.GIGenesis) { + /* IRQ from XMAC */ + SkXmIrq(pAC, IoC, Port); + } +#endif /* GENESIS */ + +#ifdef YUKON + if (pAC->GIni.GIYukon) { + /* IRQ from GMAC */ + SkGmIrq(pAC, IoC, Port); + } +#endif /* YUKON */ + +} /* SkMacIrq */ + +#endif /* !SK_DIAG */ + +#ifdef GENESIS +/****************************************************************************** + * + * SkXmUpdateStats() - Force the XMAC to output the current statistic + * + * Description: + * The XMAC holds its statistic internally. To obtain the current + * values a command must be sent so that the statistic data will + * be written to a predefined memory area on the adapter. + * + * Returns: + * 0: success + * 1: something went wrong + */ +int SkXmUpdateStats( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +unsigned int Port) /* Port Index (MAC_1 + n) */ +{ + SK_GEPORT *pPrt; + SK_U16 StatReg; + int WaitIndex; + + pPrt = &pAC->GIni.GP[Port]; + WaitIndex = 0; + + /* Send an update command to XMAC specified */ + XM_OUT16(IoC, Port, XM_STAT_CMD, XM_SC_SNP_TXC | XM_SC_SNP_RXC); + + /* + * It is an auto-clearing register. If the command bits + * went to zero again, the statistics are transferred. + * Normally the command should be executed immediately. + * But just to be sure we execute a loop. + */ + do { + + XM_IN16(IoC, Port, XM_STAT_CMD, &StatReg); + + if (++WaitIndex > 10) { + + SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_HWI_E021, SKERR_HWI_E021MSG); + + return(1); + } + } while ((StatReg & (XM_SC_SNP_TXC | XM_SC_SNP_RXC)) != 0); + + return(0); +} /* SkXmUpdateStats */ + + +/****************************************************************************** + * + * SkXmMacStatistic() - Get XMAC counter value + * + * Description: + * Gets the 32bit counter value. Except for the octet counters + * the lower 32bit are counted in hardware and the upper 32bit + * must be counted in software by monitoring counter overflow interrupts. + * + * Returns: + * 0: success + * 1: something went wrong + */ +int SkXmMacStatistic( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +unsigned int Port, /* Port Index (MAC_1 + n) */ +SK_U16 StatAddr, /* MIB counter base address */ +SK_U32 SK_FAR *pVal) /* ptr to return statistic value */ +{ + if ((StatAddr < XM_TXF_OK) || (StatAddr > XM_RXF_MAX_SZ)) { + + SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E022, SKERR_HWI_E022MSG); + + return(1); + } + + XM_IN32(IoC, Port, StatAddr, pVal); + + return(0); +} /* SkXmMacStatistic */ + + +/****************************************************************************** + * + * SkXmResetCounter() - Clear MAC statistic counter + * + * Description: + * Force the XMAC to clear its statistic counter. + * + * Returns: + * 0: success + * 1: something went wrong + */ +int SkXmResetCounter( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +unsigned int Port) /* Port Index (MAC_1 + n) */ +{ + XM_OUT16(IoC, Port, XM_STAT_CMD, XM_SC_CLR_RXC | XM_SC_CLR_TXC); + /* Clear two times according to Errata #3 */ + XM_OUT16(IoC, Port, XM_STAT_CMD, XM_SC_CLR_RXC | XM_SC_CLR_TXC); + + return(0); +} /* SkXmResetCounter */ + + +/****************************************************************************** + * + * SkXmOverflowStatus() - Gets the status of counter overflow interrupt + * + * Description: + * Checks the source causing an counter overflow interrupt. On success the + * resulting counter overflow status is written to <pStatus>, whereas the + * upper dword stores the XMAC ReceiveCounterEvent register and the lower + * dword the XMAC TransmitCounterEvent register. + * + * Note: + * For XMAC the interrupt source is a self-clearing register, so the source + * must be checked only once. SIRQ module does another check to be sure + * that no interrupt get lost during process time. + * + * Returns: + * 0: success + * 1: something went wrong + */ +int SkXmOverflowStatus( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +unsigned int Port, /* Port Index (MAC_1 + n) */ +SK_U16 IStatus, /* Interupt Status from MAC */ +SK_U64 SK_FAR *pStatus) /* ptr for return overflow status value */ +{ + SK_U64 Status; /* Overflow status */ + SK_U32 RegVal; + + Status = 0; + + if ((IStatus & XM_IS_RXC_OV) != 0) { + + XM_IN32(IoC, Port, XM_RX_CNT_EV, &RegVal); + Status |= (SK_U64)RegVal << 32; + } + + if ((IStatus & XM_IS_TXC_OV) != 0) { + + XM_IN32(IoC, Port, XM_TX_CNT_EV, &RegVal); + Status |= (SK_U64)RegVal; + } + + *pStatus = Status; + + return(0); +} /* SkXmOverflowStatus */ +#endif /* GENESIS */ + + +#ifdef YUKON +/****************************************************************************** + * + * SkGmUpdateStats() - Force the GMAC to output the current statistic + * + * Description: + * Empty function for GMAC. Statistic data is accessible in direct way. + * + * Returns: + * 0: success + * 1: something went wrong + */ +int SkGmUpdateStats( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +unsigned int Port) /* Port Index (MAC_1 + n) */ +{ + return(0); +} + + +/****************************************************************************** + * + * SkGmMacStatistic() - Get GMAC counter value + * + * Description: + * Gets the 32bit counter value. Except for the octet counters + * the lower 32bit are counted in hardware and the upper 32bit + * must be counted in software by monitoring counter overflow interrupts. + * + * Returns: + * 0: success + * 1: something went wrong + */ +int SkGmMacStatistic( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +unsigned int Port, /* Port Index (MAC_1 + n) */ +SK_U16 StatAddr, /* MIB counter base address */ +SK_U32 SK_FAR *pVal) /* ptr to return statistic value */ +{ + + if ((StatAddr < GM_RXF_UC_OK) || (StatAddr > GM_TXE_FIFO_UR)) { + + SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E022, SKERR_HWI_E022MSG); + + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("SkGmMacStat: wrong MIB counter 0x%04X\n", StatAddr)); + return(1); + } + + GM_IN32(IoC, Port, StatAddr, pVal); + + return(0); +} /* SkGmMacStatistic */ + + +/****************************************************************************** + * + * SkGmResetCounter() - Clear MAC statistic counter + * + * Description: + * Force GMAC to clear its statistic counter. + * + * Returns: + * 0: success + * 1: something went wrong + */ +int SkGmResetCounter( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +unsigned int Port) /* Port Index (MAC_1 + n) */ +{ + SK_U16 Reg; /* Phy Address Register */ + SK_U16 Word; + int i; + + GM_IN16(IoC, Port, GM_PHY_ADDR, &Reg); + + /* set MIB Clear Counter Mode */ + GM_OUT16(IoC, Port, GM_PHY_ADDR, Reg | GM_PAR_MIB_CLR); + + /* read all MIB Counters with Clear Mode set */ + for (i = 0; i < GM_MIB_CNT_SIZE; i++) { + /* the reset is performed only when the lower 16 bits are read */ + GM_IN16(IoC, Port, GM_MIB_CNT_BASE + 8*i, &Word); + } + + /* clear MIB Clear Counter Mode */ + GM_OUT16(IoC, Port, GM_PHY_ADDR, Reg); + + return(0); +} /* SkGmResetCounter */ + + +/****************************************************************************** + * + * SkGmOverflowStatus() - Gets the status of counter overflow interrupt + * + * Description: + * Checks the source causing an counter overflow interrupt. On success the + * resulting counter overflow status is written to <pStatus>, whereas the + * the following bit coding is used: + * 63:56 - unused + * 55:48 - TxRx interrupt register bit7:0 + * 32:47 - Rx interrupt register + * 31:24 - unused + * 23:16 - TxRx interrupt register bit15:8 + * 15:0 - Tx interrupt register + * + * Returns: + * 0: success + * 1: something went wrong + */ +int SkGmOverflowStatus( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +unsigned int Port, /* Port Index (MAC_1 + n) */ +SK_U16 IStatus, /* Interupt Status from MAC */ +SK_U64 SK_FAR *pStatus) /* ptr for return overflow status value */ +{ + SK_U64 Status; /* Overflow status */ + SK_U16 RegVal; + + Status = 0; + + if ((IStatus & GM_IS_RX_CO_OV) != 0) { + /* this register is self-clearing after read */ + GM_IN16(IoC, Port, GM_RX_IRQ_SRC, &RegVal); + Status |= (SK_U64)RegVal << 32; + } + + if ((IStatus & GM_IS_TX_CO_OV) != 0) { + /* this register is self-clearing after read */ + GM_IN16(IoC, Port, GM_TX_IRQ_SRC, &RegVal); + Status |= (SK_U64)RegVal; + } + + /* this register is self-clearing after read */ + GM_IN16(IoC, Port, GM_TR_IRQ_SRC, &RegVal); + /* Rx overflow interrupt register bits (LoByte)*/ + Status |= (SK_U64)((SK_U8)RegVal) << 48; + /* Tx overflow interrupt register bits (HiByte)*/ + Status |= (SK_U64)(RegVal >> 8) << 16; + + *pStatus = Status; + + return(0); +} /* SkGmOverflowStatus */ + + +#ifndef SK_SLIM +/****************************************************************************** + * + * SkGmCableDiagStatus() - Starts / Gets status of cable diagnostic test + * + * Description: + * starts the cable diagnostic test if 'StartTest' is true + * gets the results if 'StartTest' is true + * + * NOTE: this test is meaningful only when link is down + * + * Returns: + * 0: success + * 1: no YUKON copper + * 2: test in progress + */ +int SkGmCableDiagStatus( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int Port, /* Port Index (MAC_1 + n) */ +SK_BOOL StartTest) /* flag for start / get result */ +{ + int i; + SK_U16 RegVal; + SK_GEPORT *pPrt; + + pPrt = &pAC->GIni.GP[Port]; + + if (pPrt->PhyType != SK_PHY_MARV_COPPER) { + + return(1); + } + + if (StartTest) { + /* only start the cable test */ + if ((pPrt->PhyId1 & PHY_I1_REV_MSK) < 4) { + /* apply TDR workaround from Marvell */ + SkGmPhyWrite(pAC, IoC, Port, 29, 0x001e); + + SkGmPhyWrite(pAC, IoC, Port, 30, 0xcc00); + SkGmPhyWrite(pAC, IoC, Port, 30, 0xc800); + SkGmPhyWrite(pAC, IoC, Port, 30, 0xc400); + SkGmPhyWrite(pAC, IoC, Port, 30, 0xc000); + SkGmPhyWrite(pAC, IoC, Port, 30, 0xc100); + } + + /* set address to 0 for MDI[0] */ + SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_EXT_ADR, 0); + + /* Read Cable Diagnostic Reg */ + SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CABLE_DIAG, &RegVal); + + /* start Cable Diagnostic Test */ + SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_CABLE_DIAG, + (SK_U16)(RegVal | PHY_M_CABD_ENA_TEST)); + + return(0); + } + + /* Read Cable Diagnostic Reg */ + SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CABLE_DIAG, &RegVal); + + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("PHY Cable Diag.=0x%04X\n", RegVal)); + + if ((RegVal & PHY_M_CABD_ENA_TEST) != 0) { + /* test is running */ + return(2); + } + + /* get the test results */ + for (i = 0; i < 4; i++) { + /* set address to i for MDI[i] */ + SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_EXT_ADR, (SK_U16)i); + + /* get Cable Diagnostic values */ + SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CABLE_DIAG, &RegVal); + + pPrt->PMdiPairLen[i] = (SK_U8)(RegVal & PHY_M_CABD_DIST_MSK); + + pPrt->PMdiPairSts[i] = (SK_U8)((RegVal & PHY_M_CABD_STAT_MSK) >> 13); + } + + return(0); +} /* SkGmCableDiagStatus */ +#endif /* !SK_SLIM */ +#endif /* YUKON */ + +/* End of file */ diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index e6d937ec6886..ea117fc3d5e3 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -51,7 +51,7 @@ #include "sky2.h" #define DRV_NAME "sky2" -#define DRV_VERSION "1.17" +#define DRV_VERSION "1.18" #define PFX DRV_NAME " " /* @@ -118,12 +118,15 @@ static const struct pci_device_id sky2_id_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4351) }, /* 88E8036 */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4352) }, /* 88E8038 */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4353) }, /* 88E8039 */ + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4354) }, /* 88E8040 */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4356) }, /* 88EC033 */ + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x435A) }, /* 88E8048 */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4360) }, /* 88E8052 */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4361) }, /* 88E8050 */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4362) }, /* 88E8053 */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4363) }, /* 88E8055 */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4364) }, /* 88E8056 */ + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4365) }, /* 88E8070 */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4366) }, /* 88EC036 */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4367) }, /* 88EC032 */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4368) }, /* 88EC034 */ @@ -147,8 +150,11 @@ static const char *yukon2_name[] = { "Extreme", /* 0xb5 */ "EC", /* 0xb6 */ "FE", /* 0xb7 */ + "FE+", /* 0xb8 */ }; +static void sky2_set_multicast(struct net_device *dev); + /* Access to external PHY */ static int gm_phy_write(struct sky2_hw *hw, unsigned port, u16 reg, u16 val) { @@ -215,8 +221,7 @@ static void sky2_power_on(struct sky2_hw *hw) else sky2_write8(hw, B2_Y2_CLK_GATE, 0); - if (hw->chip_id == CHIP_ID_YUKON_EC_U || - hw->chip_id == CHIP_ID_YUKON_EX) { + if (hw->flags & SKY2_HW_ADV_POWER_CTL) { u32 reg; sky2_pci_write32(hw, PCI_DEV_REG3, 0); @@ -309,10 +314,8 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) struct sky2_port *sky2 = netdev_priv(hw->dev[port]); u16 ctrl, ct1000, adv, pg, ledctrl, ledover, reg; - if (sky2->autoneg == AUTONEG_ENABLE - && !(hw->chip_id == CHIP_ID_YUKON_XL - || hw->chip_id == CHIP_ID_YUKON_EC_U - || hw->chip_id == CHIP_ID_YUKON_EX)) { + if (sky2->autoneg == AUTONEG_ENABLE && + !(hw->flags & SKY2_HW_NEWER_PHY)) { u16 ectrl = gm_phy_read(hw, port, PHY_MARV_EXT_CTRL); ectrl &= ~(PHY_M_EC_M_DSC_MSK | PHY_M_EC_S_DSC_MSK | @@ -332,9 +335,19 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) ctrl = gm_phy_read(hw, port, PHY_MARV_PHY_CTRL); if (sky2_is_copper(hw)) { - if (hw->chip_id == CHIP_ID_YUKON_FE) { + if (!(hw->flags & SKY2_HW_GIGABIT)) { /* enable automatic crossover */ ctrl |= PHY_M_PC_MDI_XMODE(PHY_M_PC_ENA_AUTO) >> 1; + + if (hw->chip_id == CHIP_ID_YUKON_FE_P && + hw->chip_rev == CHIP_REV_YU_FE2_A0) { + u16 spec; + + /* Enable Class A driver for FE+ A0 */ + spec = gm_phy_read(hw, port, PHY_MARV_FE_SPEC_2); + spec |= PHY_M_FESC_SEL_CL_A; + gm_phy_write(hw, port, PHY_MARV_FE_SPEC_2, spec); + } } else { /* disable energy detect */ ctrl &= ~PHY_M_PC_EN_DET_MSK; @@ -344,9 +357,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) /* downshift on PHY 88E1112 and 88E1149 is changed */ if (sky2->autoneg == AUTONEG_ENABLE - && (hw->chip_id == CHIP_ID_YUKON_XL - || hw->chip_id == CHIP_ID_YUKON_EC_U - || hw->chip_id == CHIP_ID_YUKON_EX)) { + && (hw->flags & SKY2_HW_NEWER_PHY)) { /* set downshift counter to 3x and enable downshift */ ctrl &= ~PHY_M_PC_DSC_MSK; ctrl |= PHY_M_PC_DSC(2) | PHY_M_PC_DOWN_S_ENA; @@ -362,7 +373,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, ctrl); /* special setup for PHY 88E1112 Fiber */ - if (hw->chip_id == CHIP_ID_YUKON_XL && !sky2_is_copper(hw)) { + if (hw->chip_id == CHIP_ID_YUKON_XL && (hw->flags & SKY2_HW_FIBRE_PHY)) { pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR); /* Fiber: select 1000BASE-X only mode MAC Specific Ctrl Reg. */ @@ -453,7 +464,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) gma_write16(hw, port, GM_GP_CTRL, reg); - if (hw->chip_id != CHIP_ID_YUKON_FE) + if (hw->flags & SKY2_HW_GIGABIT) gm_phy_write(hw, port, PHY_MARV_1000T_CTRL, ct1000); gm_phy_write(hw, port, PHY_MARV_AUNE_ADV, adv); @@ -477,6 +488,23 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) gm_phy_write(hw, port, PHY_MARV_FE_LED_PAR, ctrl); break; + case CHIP_ID_YUKON_FE_P: + /* Enable Link Partner Next Page */ + ctrl = gm_phy_read(hw, port, PHY_MARV_PHY_CTRL); + ctrl |= PHY_M_PC_ENA_LIP_NP; + + /* disable Energy Detect and enable scrambler */ + ctrl &= ~(PHY_M_PC_ENA_ENE_DT | PHY_M_PC_DIS_SCRAMB); + gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, ctrl); + + /* set LED2 -> ACT, LED1 -> LINK, LED0 -> SPEED */ + ctrl = PHY_M_FELP_LED2_CTRL(LED_PAR_CTRL_ACT_BL) | + PHY_M_FELP_LED1_CTRL(LED_PAR_CTRL_LINK) | + PHY_M_FELP_LED0_CTRL(LED_PAR_CTRL_SPEED); + + gm_phy_write(hw, port, PHY_MARV_FE_LED_PAR, ctrl); + break; + case CHIP_ID_YUKON_XL: pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR); @@ -546,7 +574,13 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) /* set page register to 0 */ gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 0); + } else if (hw->chip_id == CHIP_ID_YUKON_FE_P && + hw->chip_rev == CHIP_REV_YU_FE2_A0) { + /* apply workaround for integrated resistors calibration */ + gm_phy_write(hw, port, PHY_MARV_PAGE_ADDR, 17); + gm_phy_write(hw, port, PHY_MARV_PAGE_DATA, 0x3f60); } else if (hw->chip_id != CHIP_ID_YUKON_EX) { + /* no effect on Yukon-XL */ gm_phy_write(hw, port, PHY_MARV_LED_CTRL, ledctrl); if (sky2->autoneg == AUTONEG_DISABLE || sky2->speed == SPEED_100) { @@ -667,25 +701,25 @@ static void sky2_wol_init(struct sky2_port *sky2) static void sky2_set_tx_stfwd(struct sky2_hw *hw, unsigned port) { - if (hw->chip_id == CHIP_ID_YUKON_EX && hw->chip_rev != CHIP_REV_YU_EX_A0) { + struct net_device *dev = hw->dev[port]; + + if (dev->mtu <= ETH_DATA_LEN) sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), - TX_STFW_ENA | - (hw->dev[port]->mtu > ETH_DATA_LEN) ? TX_JUMBO_ENA : TX_JUMBO_DIS); - } else { - if (hw->dev[port]->mtu > ETH_DATA_LEN) { - /* set Tx GMAC FIFO Almost Empty Threshold */ - sky2_write32(hw, SK_REG(port, TX_GMF_AE_THR), - (ECU_JUMBO_WM << 16) | ECU_AE_THR); + TX_JUMBO_DIS | TX_STFW_ENA); - sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), - TX_JUMBO_ENA | TX_STFW_DIS); + else if (hw->chip_id != CHIP_ID_YUKON_EC_U) + sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), + TX_STFW_ENA | TX_JUMBO_ENA); + else { + /* set Tx GMAC FIFO Almost Empty Threshold */ + sky2_write32(hw, SK_REG(port, TX_GMF_AE_THR), + (ECU_JUMBO_WM << 16) | ECU_AE_THR); - /* Can't do offload because of lack of store/forward */ - hw->dev[port]->features &= ~(NETIF_F_TSO | NETIF_F_SG - | NETIF_F_ALL_CSUM); - } else - sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), - TX_JUMBO_DIS | TX_STFW_ENA); + sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), + TX_JUMBO_ENA | TX_STFW_DIS); + + /* Can't do offload because of lack of store/forward */ + dev->features &= ~(NETIF_F_TSO | NETIF_F_SG | NETIF_F_ALL_CSUM); } } @@ -771,7 +805,8 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port) /* Configure Rx MAC FIFO */ sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_CLR); rx_reg = GMF_OPER_ON | GMF_RX_F_FL_ON; - if (hw->chip_id == CHIP_ID_YUKON_EX) + if (hw->chip_id == CHIP_ID_YUKON_EX || + hw->chip_id == CHIP_ID_YUKON_FE_P) rx_reg |= GMF_RX_OVER_ON; sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T), rx_reg); @@ -780,13 +815,19 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port) sky2_write16(hw, SK_REG(port, RX_GMF_FL_MSK), GMR_FS_ANY_ERR); /* Set threshold to 0xa (64 bytes) + 1 to workaround pause bug */ - sky2_write16(hw, SK_REG(port, RX_GMF_FL_THR), RX_GMF_FL_THR_DEF+1); + reg = RX_GMF_FL_THR_DEF + 1; + /* Another magic mystery workaround from sk98lin */ + if (hw->chip_id == CHIP_ID_YUKON_FE_P && + hw->chip_rev == CHIP_REV_YU_FE2_A0) + reg = 0x178; + sky2_write16(hw, SK_REG(port, RX_GMF_FL_THR), reg); /* Configure Tx MAC FIFO */ sky2_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_RST_CLR); sky2_write16(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_OPER_ON); - if (hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX) { + /* On chips without ram buffer, pause is controled by MAC level */ + if (sky2_read8(hw, B2_E_0) == 0) { sky2_write8(hw, SK_REG(port, RX_GMF_LP_THR), 768/8); sky2_write8(hw, SK_REG(port, RX_GMF_UP_THR), 1024/8); @@ -869,6 +910,20 @@ static inline struct sky2_tx_le *get_tx_le(struct sky2_port *sky2) return le; } +static void tx_init(struct sky2_port *sky2) +{ + struct sky2_tx_le *le; + + sky2->tx_prod = sky2->tx_cons = 0; + sky2->tx_tcpsum = 0; + sky2->tx_last_mss = 0; + + le = get_tx_le(sky2); + le->addr = 0; + le->opcode = OP_ADDR64 | HW_OWNER; + sky2->tx_addr64 = 0; +} + static inline struct tx_ring_info *tx_le_re(struct sky2_port *sky2, struct sky2_tx_le *le) { @@ -965,19 +1020,15 @@ static void sky2_rx_unmap_skb(struct pci_dev *pdev, struct rx_ring_info *re) */ static void rx_set_checksum(struct sky2_port *sky2) { - struct sky2_rx_le *le; - - if (sky2->hw->chip_id != CHIP_ID_YUKON_EX) { - le = sky2_next_rx(sky2); - le->addr = cpu_to_le32((ETH_HLEN << 16) | ETH_HLEN); - le->ctrl = 0; - le->opcode = OP_TCPSTART | HW_OWNER; + struct sky2_rx_le *le = sky2_next_rx(sky2); - sky2_write32(sky2->hw, - Q_ADDR(rxqaddr[sky2->port], Q_CSR), - sky2->rx_csum ? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM); - } + le->addr = cpu_to_le32((ETH_HLEN << 16) | ETH_HLEN); + le->ctrl = 0; + le->opcode = OP_TCPSTART | HW_OWNER; + sky2_write32(sky2->hw, + Q_ADDR(rxqaddr[sky2->port], Q_CSR), + sky2->rx_csum ? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM); } /* @@ -1173,7 +1224,8 @@ static int sky2_rx_start(struct sky2_port *sky2) sky2_prefetch_init(hw, rxq, sky2->rx_le_map, RX_LE_SIZE - 1); - rx_set_checksum(sky2); + if (!(hw->flags & SKY2_HW_NEW_LE)) + rx_set_checksum(sky2); /* Space needed for frame data + headers rounded up */ size = roundup(sky2->netdev->mtu + ETH_HLEN + VLAN_HLEN, 8); @@ -1244,7 +1296,7 @@ static int sky2_up(struct net_device *dev) struct sky2_port *sky2 = netdev_priv(dev); struct sky2_hw *hw = sky2->hw; unsigned port = sky2->port; - u32 ramsize, imask; + u32 imask, ramsize; int cap, err = -ENOMEM; struct net_device *otherdev = hw->dev[sky2->port^1]; @@ -1282,7 +1334,8 @@ static int sky2_up(struct net_device *dev) GFP_KERNEL); if (!sky2->tx_ring) goto err_out; - sky2->tx_prod = sky2->tx_cons = 0; + + tx_init(sky2); sky2->rx_le = pci_alloc_consistent(hw->pdev, RX_LE_BYTES, &sky2->rx_le_map); @@ -1301,11 +1354,10 @@ static int sky2_up(struct net_device *dev) /* Register is number of 4K blocks on internal RAM buffer. */ ramsize = sky2_read8(hw, B2_E_0) * 4; - printk(KERN_INFO PFX "%s: ram buffer %dK\n", dev->name, ramsize); - if (ramsize > 0) { u32 rxspace; + pr_debug(PFX "%s: ram buffer %dK\n", dev->name, ramsize); if (ramsize < 16) rxspace = ramsize / 2; else @@ -1434,13 +1486,15 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) /* Check for TCP Segmentation Offload */ mss = skb_shinfo(skb)->gso_size; if (mss != 0) { - if (hw->chip_id != CHIP_ID_YUKON_EX) + + if (!(hw->flags & SKY2_HW_NEW_LE)) mss += ETH_HLEN + ip_hdrlen(skb) + tcp_hdrlen(skb); if (mss != sky2->tx_last_mss) { le = get_tx_le(sky2); le->addr = cpu_to_le32(mss); - if (hw->chip_id == CHIP_ID_YUKON_EX) + + if (hw->flags & SKY2_HW_NEW_LE) le->opcode = OP_MSS | HW_OWNER; else le->opcode = OP_LRGLEN | HW_OWNER; @@ -1466,8 +1520,7 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) /* Handle TCP checksum offload */ if (skb->ip_summed == CHECKSUM_PARTIAL) { /* On Yukon EX (some versions) encoding change. */ - if (hw->chip_id == CHIP_ID_YUKON_EX - && hw->chip_rev != CHIP_REV_YU_EX_B0) + if (hw->flags & SKY2_HW_AUTO_TX_SUM) ctrl |= CALSUM; /* auto checksum */ else { const unsigned offset = skb_transport_offset(skb); @@ -1620,9 +1673,6 @@ static int sky2_down(struct net_device *dev) if (netif_msg_ifdown(sky2)) printk(KERN_INFO PFX "%s: disabling interface\n", dev->name); - if (netif_carrier_ok(dev) && --hw->active == 0) - del_timer(&hw->watchdog_timer); - /* Stop more packets from being queued */ netif_stop_queue(dev); @@ -1706,11 +1756,15 @@ static int sky2_down(struct net_device *dev) static u16 sky2_phy_speed(const struct sky2_hw *hw, u16 aux) { - if (!sky2_is_copper(hw)) + if (hw->flags & SKY2_HW_FIBRE_PHY) return SPEED_1000; - if (hw->chip_id == CHIP_ID_YUKON_FE) - return (aux & PHY_M_PS_SPEED_100) ? SPEED_100 : SPEED_10; + if (!(hw->flags & SKY2_HW_GIGABIT)) { + if (aux & PHY_M_PS_SPEED_100) + return SPEED_100; + else + return SPEED_10; + } switch (aux & PHY_M_PS_SPEED_MSK) { case PHY_M_PS_SPEED_1000: @@ -1743,17 +1797,13 @@ static void sky2_link_up(struct sky2_port *sky2) netif_carrier_on(sky2->netdev); - if (hw->active++ == 0) - mod_timer(&hw->watchdog_timer, jiffies + 1); - + mod_timer(&hw->watchdog_timer, jiffies + 1); /* Turn on link LED */ sky2_write8(hw, SK_REG(port, LNK_LED_REG), LINKLED_ON | LINKLED_BLINK_OFF | LINKLED_LINKSYNC_OFF); - if (hw->chip_id == CHIP_ID_YUKON_XL - || hw->chip_id == CHIP_ID_YUKON_EC_U - || hw->chip_id == CHIP_ID_YUKON_EX) { + if (hw->flags & SKY2_HW_NEWER_PHY) { u16 pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR); u16 led = PHY_M_LEDC_LOS_CTRL(1); /* link active */ @@ -1798,11 +1848,6 @@ static void sky2_link_down(struct sky2_port *sky2) netif_carrier_off(sky2->netdev); - /* Stop watchdog if both ports are not active */ - if (--hw->active == 0) - del_timer(&hw->watchdog_timer); - - /* Turn on link LED */ sky2_write8(hw, SK_REG(port, LNK_LED_REG), LINKLED_OFF); @@ -1845,7 +1890,7 @@ static int sky2_autoneg_done(struct sky2_port *sky2, u16 aux) /* Since the pause result bits seem to in different positions on * different chips. look at registers. */ - if (!sky2_is_copper(hw)) { + if (hw->flags & SKY2_HW_FIBRE_PHY) { /* Shift for bits in fiber PHY */ advert &= ~(ADVERTISE_PAUSE_CAP|ADVERTISE_PAUSE_ASYM); lpa &= ~(LPA_PAUSE_CAP|LPA_PAUSE_ASYM); @@ -1956,7 +2001,9 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu) if (new_mtu < ETH_ZLEN || new_mtu > ETH_JUMBO_MTU) return -EINVAL; - if (new_mtu > ETH_DATA_LEN && hw->chip_id == CHIP_ID_YUKON_FE) + if (new_mtu > ETH_DATA_LEN && + (hw->chip_id == CHIP_ID_YUKON_FE || + hw->chip_id == CHIP_ID_YUKON_FE_P)) return -EINVAL; if (!netif_running(dev)) { @@ -1973,7 +2020,7 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu) synchronize_irq(hw->pdev->irq); - if (hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX) + if (sky2_read8(hw, B2_E_0) == 0) sky2_set_tx_stfwd(hw, port); ctl = gma_read16(hw, port, GM_GP_CTRL); @@ -2101,6 +2148,13 @@ static struct sk_buff *sky2_receive(struct net_device *dev, struct sky2_port *sky2 = netdev_priv(dev); struct rx_ring_info *re = sky2->rx_ring + sky2->rx_next; struct sk_buff *skb = NULL; + u16 count = (status & GMR_FS_LEN) >> 16; + +#ifdef SKY2_VLAN_TAG_USED + /* Account for vlan tag */ + if (sky2->vlgrp && (status & GMR_FS_VLAN)) + count -= VLAN_HLEN; +#endif if (unlikely(netif_msg_rx_status(sky2))) printk(KERN_DEBUG PFX "%s: rx slot %u status 0x%x len %d\n", @@ -2109,15 +2163,26 @@ static struct sk_buff *sky2_receive(struct net_device *dev, sky2->rx_next = (sky2->rx_next + 1) % sky2->rx_pending; prefetch(sky2->rx_ring + sky2->rx_next); + /* This chip has hardware problems that generates bogus status. + * So do only marginal checking and expect higher level protocols + * to handle crap frames. + */ + if (sky2->hw->chip_id == CHIP_ID_YUKON_FE_P && + sky2->hw->chip_rev == CHIP_REV_YU_FE2_A0 && + length != count) + goto okay; + if (status & GMR_FS_ANY_ERR) goto error; if (!(status & GMR_FS_RX_OK)) goto resubmit; - if (status >> 16 != length) - goto len_mismatch; + /* if length reported by DMA does not match PHY, packet was truncated */ + if (length != count) + goto len_error; +okay: if (length < copybreak) skb = receive_copy(sky2, re, length); else @@ -2127,10 +2192,14 @@ resubmit: return skb; -len_mismatch: +len_error: /* Truncation of overlength packets causes PHY length to not match MAC length */ ++sky2->net_stats.rx_length_errors; + if (netif_msg_rx_err(sky2) && net_ratelimit()) + pr_info(PFX "%s: rx length error: status %#x length %d\n", + dev->name, status, length); + goto resubmit; error: ++sky2->net_stats.rx_errors; @@ -2200,7 +2269,7 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do) } /* This chip reports checksum status differently */ - if (hw->chip_id == CHIP_ID_YUKON_EX) { + if (hw->flags & SKY2_HW_NEW_LE) { if (sky2->rx_csum && (le->css & (CSS_ISIPV4 | CSS_ISIPV6)) && (le->css & CSS_TCPUDPCSOK)) @@ -2241,8 +2310,14 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do) if (!sky2->rx_csum) break; - if (hw->chip_id == CHIP_ID_YUKON_EX) + /* If this happens then driver assuming wrong format */ + if (unlikely(hw->flags & SKY2_HW_NEW_LE)) { + if (net_ratelimit()) + printk(KERN_NOTICE "%s: unexpected" + " checksum status\n", + dev->name); break; + } /* Both checksum counters are programmed to start at * the same offset, so unless there is a problem they @@ -2434,20 +2509,72 @@ static void sky2_le_error(struct sky2_hw *hw, unsigned port, sky2_write32(hw, Q_ADDR(q, Q_CSR), BMU_CLR_IRQ_CHK); } -/* Check for lost IRQ once a second */ +static int sky2_rx_hung(struct net_device *dev) +{ + struct sky2_port *sky2 = netdev_priv(dev); + struct sky2_hw *hw = sky2->hw; + unsigned port = sky2->port; + unsigned rxq = rxqaddr[port]; + u32 mac_rp = sky2_read32(hw, SK_REG(port, RX_GMF_RP)); + u8 mac_lev = sky2_read8(hw, SK_REG(port, RX_GMF_RLEV)); + u8 fifo_rp = sky2_read8(hw, Q_ADDR(rxq, Q_RP)); + u8 fifo_lev = sky2_read8(hw, Q_ADDR(rxq, Q_RL)); + + /* If idle and MAC or PCI is stuck */ + if (sky2->check.last == dev->last_rx && + ((mac_rp == sky2->check.mac_rp && + mac_lev != 0 && mac_lev >= sky2->check.mac_lev) || + /* Check if the PCI RX hang */ + (fifo_rp == sky2->check.fifo_rp && + fifo_lev != 0 && fifo_lev >= sky2->check.fifo_lev))) { + printk(KERN_DEBUG PFX "%s: hung mac %d:%d fifo %d (%d:%d)\n", + dev->name, mac_lev, mac_rp, fifo_lev, fifo_rp, + sky2_read8(hw, Q_ADDR(rxq, Q_WP))); + return 1; + } else { + sky2->check.last = dev->last_rx; + sky2->check.mac_rp = mac_rp; + sky2->check.mac_lev = mac_lev; + sky2->check.fifo_rp = fifo_rp; + sky2->check.fifo_lev = fifo_lev; + return 0; + } +} + static void sky2_watchdog(unsigned long arg) { struct sky2_hw *hw = (struct sky2_hw *) arg; + struct net_device *dev; + /* Check for lost IRQ once a second */ if (sky2_read32(hw, B0_ISRC)) { - struct net_device *dev = hw->dev[0]; - + dev = hw->dev[0]; if (__netif_rx_schedule_prep(dev)) __netif_rx_schedule(dev); + } else { + int i, active = 0; + + for (i = 0; i < hw->ports; i++) { + dev = hw->dev[i]; + if (!netif_running(dev)) + continue; + ++active; + + /* For chips with Rx FIFO, check if stuck */ + if ((hw->flags & SKY2_HW_FIFO_HANG_CHECK) && + sky2_rx_hung(dev)) { + pr_info(PFX "%s: receiver hang detected\n", + dev->name); + schedule_work(&hw->restart_work); + return; + } + } + + if (active == 0) + return; } - if (hw->active > 0) - mod_timer(&hw->watchdog_timer, round_jiffies(jiffies + HZ)); + mod_timer(&hw->watchdog_timer, round_jiffies(jiffies + HZ)); } /* Hardware/software error handling */ @@ -2544,17 +2671,25 @@ static void sky2_netpoll(struct net_device *dev) #endif /* Chip internal frequency for clock calculations */ -static inline u32 sky2_mhz(const struct sky2_hw *hw) +static u32 sky2_mhz(const struct sky2_hw *hw) { switch (hw->chip_id) { case CHIP_ID_YUKON_EC: case CHIP_ID_YUKON_EC_U: case CHIP_ID_YUKON_EX: - return 125; /* 125 Mhz */ + return 125; + case CHIP_ID_YUKON_FE: - return 100; /* 100 Mhz */ - default: /* YUKON_XL */ - return 156; /* 156 Mhz */ + return 100; + + case CHIP_ID_YUKON_FE_P: + return 50; + + case CHIP_ID_YUKON_XL: + return 156; + + default: + BUG(); } } @@ -2579,23 +2714,63 @@ static int __devinit sky2_init(struct sky2_hw *hw) sky2_write8(hw, B0_CTST, CS_RST_CLR); hw->chip_id = sky2_read8(hw, B2_CHIP_ID); - if (hw->chip_id < CHIP_ID_YUKON_XL || hw->chip_id > CHIP_ID_YUKON_FE) { + hw->chip_rev = (sky2_read8(hw, B2_MAC_CFG) & CFG_CHIP_R_MSK) >> 4; + + switch(hw->chip_id) { + case CHIP_ID_YUKON_XL: + hw->flags = SKY2_HW_GIGABIT + | SKY2_HW_NEWER_PHY; + if (hw->chip_rev < 3) + hw->flags |= SKY2_HW_FIFO_HANG_CHECK; + + break; + + case CHIP_ID_YUKON_EC_U: + hw->flags = SKY2_HW_GIGABIT + | SKY2_HW_NEWER_PHY + | SKY2_HW_ADV_POWER_CTL; + break; + + case CHIP_ID_YUKON_EX: + hw->flags = SKY2_HW_GIGABIT + | SKY2_HW_NEWER_PHY + | SKY2_HW_NEW_LE + | SKY2_HW_ADV_POWER_CTL; + + /* New transmit checksum */ + if (hw->chip_rev != CHIP_REV_YU_EX_B0) + hw->flags |= SKY2_HW_AUTO_TX_SUM; + break; + + case CHIP_ID_YUKON_EC: + /* This rev is really old, and requires untested workarounds */ + if (hw->chip_rev == CHIP_REV_YU_EC_A1) { + dev_err(&hw->pdev->dev, "unsupported revision Yukon-EC rev A1\n"); + return -EOPNOTSUPP; + } + hw->flags = SKY2_HW_GIGABIT | SKY2_HW_FIFO_HANG_CHECK; + break; + + case CHIP_ID_YUKON_FE: + break; + + case CHIP_ID_YUKON_FE_P: + hw->flags = SKY2_HW_NEWER_PHY + | SKY2_HW_NEW_LE + | SKY2_HW_AUTO_TX_SUM + | SKY2_HW_ADV_POWER_CTL; + break; + default: dev_err(&hw->pdev->dev, "unsupported chip type 0x%x\n", hw->chip_id); return -EOPNOTSUPP; } - hw->chip_rev = (sky2_read8(hw, B2_MAC_CFG) & CFG_CHIP_R_MSK) >> 4; + hw->pmd_type = sky2_read8(hw, B2_PMD_TYP); + if (hw->pmd_type == 'L' || hw->pmd_type == 'S' || hw->pmd_type == 'P') + hw->flags |= SKY2_HW_FIBRE_PHY; - /* This rev is really old, and requires untested workarounds */ - if (hw->chip_id == CHIP_ID_YUKON_EC && hw->chip_rev == CHIP_REV_YU_EC_A1) { - dev_err(&hw->pdev->dev, "unsupported revision Yukon-%s (0x%x) rev %d\n", - yukon2_name[hw->chip_id - CHIP_ID_YUKON_XL], - hw->chip_id, hw->chip_rev); - return -EOPNOTSUPP; - } - hw->pmd_type = sky2_read8(hw, B2_PMD_TYP); hw->ports = 1; t8 = sky2_read8(hw, B2_Y2_HW_RES); if ((t8 & CFG_DUAL_MAC_MSK) == CFG_DUAL_MAC_MSK) { @@ -2789,7 +2964,9 @@ static int sky2_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) sky2->wol = wol->wolopts; - if (hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX) + if (hw->chip_id == CHIP_ID_YUKON_EC_U || + hw->chip_id == CHIP_ID_YUKON_EX || + hw->chip_id == CHIP_ID_YUKON_FE_P) sky2_write32(hw, B0_CTST, sky2->wol ? Y2_HW_WOL_ON : Y2_HW_WOL_OFF); @@ -2807,7 +2984,7 @@ static u32 sky2_supported_modes(const struct sky2_hw *hw) | SUPPORTED_100baseT_Full | SUPPORTED_Autoneg | SUPPORTED_TP; - if (hw->chip_id != CHIP_ID_YUKON_FE) + if (hw->flags & SKY2_HW_GIGABIT) modes |= SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full; return modes; @@ -2827,13 +3004,6 @@ static int sky2_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) ecmd->supported = sky2_supported_modes(hw); ecmd->phy_address = PHY_ADDR_MARV; if (sky2_is_copper(hw)) { - ecmd->supported = SUPPORTED_10baseT_Half - | SUPPORTED_10baseT_Full - | SUPPORTED_100baseT_Half - | SUPPORTED_100baseT_Full - | SUPPORTED_1000baseT_Half - | SUPPORTED_1000baseT_Full - | SUPPORTED_Autoneg | SUPPORTED_TP; ecmd->port = PORT_TP; ecmd->speed = sky2->speed; } else { @@ -2900,8 +3070,10 @@ static int sky2_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) sky2->autoneg = ecmd->autoneg; sky2->advertising = ecmd->advertising; - if (netif_running(dev)) + if (netif_running(dev)) { sky2_phy_reinit(sky2); + sky2_set_multicast(dev); + } return 0; } @@ -2994,6 +3166,7 @@ static int sky2_nway_reset(struct net_device *dev) return -EINVAL; sky2_phy_reinit(sky2); + sky2_set_multicast(dev); return 0; } @@ -3809,8 +3982,12 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw, dev->features |= NETIF_F_HIGHDMA; #ifdef SKY2_VLAN_TAG_USED - dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; - dev->vlan_rx_register = sky2_vlan_rx_register; + /* The workaround for FE+ status conflicts with VLAN tag detection. */ + if (!(sky2->hw->chip_id == CHIP_ID_YUKON_FE_P && + sky2->hw->chip_rev == CHIP_REV_YU_FE2_A0)) { + dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; + dev->vlan_rx_register = sky2_vlan_rx_register; + } #endif /* read the mac address */ @@ -3841,7 +4018,7 @@ static irqreturn_t __devinit sky2_test_intr(int irq, void *dev_id) return IRQ_NONE; if (status & Y2_IS_IRQ_SW) { - hw->msi = 1; + hw->flags |= SKY2_HW_USE_MSI; wake_up(&hw->msi_wait); sky2_write8(hw, B0_CTST, CS_CL_SW_IRQ); } @@ -3869,9 +4046,9 @@ static int __devinit sky2_test_msi(struct sky2_hw *hw) sky2_write8(hw, B0_CTST, CS_ST_SW_IRQ); sky2_read8(hw, B0_CTST); - wait_event_timeout(hw->msi_wait, hw->msi, HZ/10); + wait_event_timeout(hw->msi_wait, (hw->flags & SKY2_HW_USE_MSI), HZ/10); - if (!hw->msi) { + if (!(hw->flags & SKY2_HW_USE_MSI)) { /* MSI test failed, go back to INTx mode */ dev_info(&pdev->dev, "No interrupt generated using MSI, " "switching to INTx mode.\n"); @@ -4004,7 +4181,8 @@ static int __devinit sky2_probe(struct pci_dev *pdev, goto err_out_free_netdev; } - err = request_irq(pdev->irq, sky2_intr, hw->msi ? 0 : IRQF_SHARED, + err = request_irq(pdev->irq, sky2_intr, + (hw->flags & SKY2_HW_USE_MSI) ? 0 : IRQF_SHARED, dev->name, hw); if (err) { dev_err(&pdev->dev, "cannot assign irq %d\n", pdev->irq); @@ -4037,7 +4215,7 @@ static int __devinit sky2_probe(struct pci_dev *pdev, return 0; err_out_unregister: - if (hw->msi) + if (hw->flags & SKY2_HW_USE_MSI) pci_disable_msi(pdev); unregister_netdev(dev); err_out_free_netdev: @@ -4086,7 +4264,7 @@ static void __devexit sky2_remove(struct pci_dev *pdev) sky2_read8(hw, B0_CTST); free_irq(pdev->irq, hw); - if (hw->msi) + if (hw->flags & SKY2_HW_USE_MSI) pci_disable_msi(pdev); pci_free_consistent(pdev, STATUS_LE_BYTES, hw->st_le, hw->st_dma); pci_release_regions(pdev); @@ -4154,7 +4332,9 @@ static int sky2_resume(struct pci_dev *pdev) pci_enable_wake(pdev, PCI_D0, 0); /* Re-enable all clocks */ - if (hw->chip_id == CHIP_ID_YUKON_EX || hw->chip_id == CHIP_ID_YUKON_EC_U) + if (hw->chip_id == CHIP_ID_YUKON_EX || + hw->chip_id == CHIP_ID_YUKON_EC_U || + hw->chip_id == CHIP_ID_YUKON_FE_P) sky2_pci_write32(hw, PCI_DEV_REG3, 0); sky2_reset(hw); @@ -4171,6 +4351,8 @@ static int sky2_resume(struct pci_dev *pdev) dev_close(dev); goto out; } + + sky2_set_multicast(dev); } } diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index 72e12b7cfa40..8bc5c54e3efa 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -470,18 +470,24 @@ enum { CHIP_ID_YUKON_EX = 0xb5, /* Chip ID for YUKON-2 Extreme */ CHIP_ID_YUKON_EC = 0xb6, /* Chip ID for YUKON-2 EC */ CHIP_ID_YUKON_FE = 0xb7, /* Chip ID for YUKON-2 FE */ - + CHIP_ID_YUKON_FE_P = 0xb8, /* Chip ID for YUKON-2 FE+ */ +}; +enum yukon_ec_rev { CHIP_REV_YU_EC_A1 = 0, /* Chip Rev. for Yukon-EC A1/A0 */ CHIP_REV_YU_EC_A2 = 1, /* Chip Rev. for Yukon-EC A2 */ CHIP_REV_YU_EC_A3 = 2, /* Chip Rev. for Yukon-EC A3 */ - +}; +enum yukon_ec_u_rev { CHIP_REV_YU_EC_U_A0 = 1, CHIP_REV_YU_EC_U_A1 = 2, CHIP_REV_YU_EC_U_B0 = 3, - +}; +enum yukon_fe_rev { CHIP_REV_YU_FE_A1 = 1, CHIP_REV_YU_FE_A2 = 2, - +}; +enum yukon_fe_p_rev { + CHIP_REV_YU_FE2_A0 = 0, }; enum yukon_ex_rev { CHIP_REV_YU_EX_A0 = 1, @@ -1668,7 +1674,7 @@ enum { /* Receive Frame Status Encoding */ enum { - GMR_FS_LEN = 0xffff<<16, /* Bit 31..16: Rx Frame Length */ + GMR_FS_LEN = 0x7fff<<16, /* Bit 30..16: Rx Frame Length */ GMR_FS_VLAN = 1<<13, /* VLAN Packet */ GMR_FS_JABBER = 1<<12, /* Jabber Packet */ GMR_FS_UN_SIZE = 1<<11, /* Undersize Packet */ @@ -1729,6 +1735,10 @@ enum { GMF_RX_CTRL_DEF = GMF_OPER_ON | GMF_RX_F_FL_ON, }; +/* TX_GMF_EA 32 bit Tx GMAC FIFO End Address */ +enum { + TX_DYN_WM_ENA = 3, /* Yukon-FE+ specific */ +}; /* TX_GMF_CTRL_T 32 bit Tx GMAC FIFO Control/Test */ enum { @@ -2017,6 +2027,14 @@ struct sky2_port { u16 rx_tag; struct vlan_group *vlgrp; #endif + struct { + unsigned long last; + u32 mac_rp; + u8 mac_lev; + u8 fifo_rp; + u8 fifo_lev; + } check; + dma_addr_t rx_le_map; dma_addr_t tx_le_map; @@ -2040,12 +2058,20 @@ struct sky2_hw { void __iomem *regs; struct pci_dev *pdev; struct net_device *dev[2]; + unsigned long flags; +#define SKY2_HW_USE_MSI 0x00000001 +#define SKY2_HW_FIBRE_PHY 0x00000002 +#define SKY2_HW_GIGABIT 0x00000004 +#define SKY2_HW_NEWER_PHY 0x00000008 +#define SKY2_HW_FIFO_HANG_CHECK 0x00000010 +#define SKY2_HW_NEW_LE 0x00000020 /* new LSOv2 format */ +#define SKY2_HW_AUTO_TX_SUM 0x00000040 /* new IP decode for Tx */ +#define SKY2_HW_ADV_POWER_CTL 0x00000080 /* additional PHY power regs */ u8 chip_id; u8 chip_rev; u8 pmd_type; u8 ports; - u8 active; struct sky2_status_le *st_le; u32 st_idx; @@ -2053,13 +2079,12 @@ struct sky2_hw { struct timer_list watchdog_timer; struct work_struct restart_work; - int msi; wait_queue_head_t msi_wait; }; static inline int sky2_is_copper(const struct sky2_hw *hw) { - return !(hw->pmd_type == 'L' || hw->pmd_type == 'S' || hw->pmd_type == 'P'); + return !(hw->flags & SKY2_HW_FIBRE_PHY); } /* Register accessor for memory mapped device */ diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index 590b12c7246c..82d837ab4db9 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -1441,17 +1441,14 @@ static void spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg) { u32 error_reg1, error_reg2; - u32 mask_reg1, mask_reg2; u32 i; int show_error = 1; error_reg1 = spider_net_read_reg(card, SPIDER_NET_GHIINT1STS); error_reg2 = spider_net_read_reg(card, SPIDER_NET_GHIINT2STS); - mask_reg1 = spider_net_read_reg(card, SPIDER_NET_GHIINT1MSK); - mask_reg2 = spider_net_read_reg(card,SPIDER_NET_GHIINT2MSK); - error_reg1 &= mask_reg1; - error_reg2 &= mask_reg2; + error_reg1 &= SPIDER_NET_INT1_MASK_VALUE; + error_reg2 &= SPIDER_NET_INT2_MASK_VALUE; /* check GHIINT0STS ************************************/ if (status_reg) @@ -1679,11 +1676,10 @@ spider_net_interrupt(int irq, void *ptr) { struct net_device *netdev = ptr; struct spider_net_card *card = netdev_priv(netdev); - u32 status_reg, mask_reg; + u32 status_reg; status_reg = spider_net_read_reg(card, SPIDER_NET_GHIINT0STS); - mask_reg = spider_net_read_reg(card, SPIDER_NET_GHIINT0MSK); - status_reg &= mask_reg; + status_reg &= SPIDER_NET_INT0_MASK_VALUE; if (!status_reg) return IRQ_NONE; diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 58740428dd07..9034a05734ef 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -64,8 +64,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.80" -#define DRV_MODULE_RELDATE "August 2, 2007" +#define DRV_MODULE_VERSION "3.81" +#define DRV_MODULE_RELDATE "September 5, 2007" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 @@ -7127,6 +7127,10 @@ static int tg3_open(struct net_device *dev) } else if (pci_enable_msi(tp->pdev) == 0) { u32 msi_mode; + /* Hardware bug - MSI won't work if INTX disabled. */ + if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) + pci_intx(tp->pdev, 1); + msi_mode = tr32(MSGINT_MODE); tw32(MSGINT_MODE, msi_mode | MSGINT_MODE_ENABLE); tp->tg3_flags2 |= TG3_FLG2_USING_MSI; @@ -12172,6 +12176,11 @@ static int tg3_resume(struct pci_dev *pdev) if (err) return err; + /* Hardware bug - MSI won't work if INTX disabled. */ + if ((tp->tg3_flags2 & TG3_FLG2_5780_CLASS) && + (tp->tg3_flags2 & TG3_FLG2_USING_MSI)) + pci_intx(tp->pdev, 1); + netif_device_attach(dev); tg3_full_lock(tp, 0); diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index 12e01b24105a..9a38dfe45f8f 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -2148,7 +2148,7 @@ static void ucc_geth_memclean(struct ucc_geth_private *ugeth) for (j = 0; j < ugeth->ug_info->bdRingLenTx[i]; j++) { if (ugeth->tx_skbuff[i][j]) { dma_unmap_single(NULL, - ((qe_bd_t *)bd)->buf, + ((struct qe_bd *)bd)->buf, (in_be32((u32 *)bd) & BD_LENGTH_MASK), DMA_TO_DEVICE); diff --git a/drivers/net/usb/dm9601.c b/drivers/net/usb/dm9601.c index 16c7a0e87850..a2de32fabc17 100644 --- a/drivers/net/usb/dm9601.c +++ b/drivers/net/usb/dm9601.c @@ -405,7 +405,7 @@ static int dm9601_bind(struct usbnet *dev, struct usb_interface *intf) dev->net->ethtool_ops = &dm9601_ethtool_ops; dev->net->hard_header_len += DM_TX_OVERHEAD; dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len; - dev->rx_urb_size = dev->net->mtu + DM_RX_OVERHEAD; + dev->rx_urb_size = dev->net->mtu + ETH_HLEN + DM_RX_OVERHEAD; dev->mii.dev = dev->net; dev->mii.mdio_read = dm9601_mdio_read; diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index ef35bc6c4a22..4eb6d9752881 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -43,7 +43,7 @@ obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o obj-$(CONFIG_PCMCIA_WL3501) += wl3501_cs.o obj-$(CONFIG_USB_ZD1201) += zd1201.o -obj-$(CONFIG_LIBERTAS_USB) += libertas/ +obj-$(CONFIG_LIBERTAS) += libertas/ rtl8187-objs := rtl8187_dev.o rtl8187_rtl8225.o obj-$(CONFIG_RTL8187) += rtl8187.o diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index c5d6753a55ea..dfbd01eaaf34 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -3183,6 +3183,9 @@ static void bcm43xx_periodic_work_handler(struct work_struct *work) unsigned long orig_trans_start = 0; mutex_lock(&bcm->mutex); + /* keep from doing and rearming periodic work if shutting down */ + if (bcm43xx_status(bcm) == BCM43xx_STAT_UNINIT) + goto unlock_mutex; if (unlikely(bcm->periodic_state % 60 == 0)) { /* Periodic work will take a long time, so we want it to * be preemtible. @@ -3228,14 +3231,10 @@ static void bcm43xx_periodic_work_handler(struct work_struct *work) mmiowb(); bcm->periodic_state++; spin_unlock_irqrestore(&bcm->irq_lock, flags); +unlock_mutex: mutex_unlock(&bcm->mutex); } -void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm) -{ - cancel_rearming_delayed_work(&bcm->periodic_work); -} - void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm) { struct delayed_work *work = &bcm->periodic_work; @@ -3285,6 +3284,14 @@ static int bcm43xx_rng_init(struct bcm43xx_private *bcm) return err; } +void bcm43xx_cancel_work(struct bcm43xx_private *bcm) +{ + /* The system must be unlocked when this routine is entered. + * If not, the next 2 steps may deadlock */ + cancel_work_sync(&bcm->restart_work); + cancel_delayed_work_sync(&bcm->periodic_work); +} + static int bcm43xx_shutdown_all_wireless_cores(struct bcm43xx_private *bcm) { int ret = 0; @@ -3321,7 +3328,12 @@ static void bcm43xx_free_board(struct bcm43xx_private *bcm) { bcm43xx_rng_exit(bcm); bcm43xx_sysfs_unregister(bcm); - bcm43xx_periodic_tasks_delete(bcm); + + mutex_lock(&(bcm)->mutex); + bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT); + mutex_unlock(&(bcm)->mutex); + + bcm43xx_cancel_work(bcm); mutex_lock(&(bcm)->mutex); bcm43xx_shutdown_all_wireless_cores(bcm); @@ -4016,7 +4028,7 @@ static int bcm43xx_net_stop(struct net_device *net_dev) err = bcm43xx_disable_interrupts_sync(bcm); assert(!err); bcm43xx_free_board(bcm); - flush_scheduled_work(); + bcm43xx_cancel_work(bcm); return 0; } @@ -4148,9 +4160,9 @@ static void bcm43xx_chip_reset(struct work_struct *work) struct bcm43xx_phyinfo *phy; int err = -ENODEV; + bcm43xx_cancel_work(bcm); mutex_lock(&(bcm)->mutex); if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) { - bcm43xx_periodic_tasks_delete(bcm); phy = bcm43xx_current_phy(bcm); err = bcm43xx_select_wireless_core(bcm, phy->type); if (!err) diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.h b/drivers/net/wireless/bcm43xx/bcm43xx_main.h index c8f3c532bab5..14cfbeb582ef 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.h @@ -122,7 +122,7 @@ void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy); void bcm43xx_mac_suspend(struct bcm43xx_private *bcm); void bcm43xx_mac_enable(struct bcm43xx_private *bcm); -void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm); +void bcm43xx_cancel_work(struct bcm43xx_private *bcm); void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm); void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason); diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c index c71b998a3694..8ab5f93d192a 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c @@ -327,7 +327,7 @@ static ssize_t bcm43xx_attr_phymode_store(struct device *dev, goto out; } - bcm43xx_periodic_tasks_delete(bcm); + bcm43xx_cancel_work(bcm); mutex_lock(&(bcm)->mutex); err = bcm43xx_select_wireless_core(bcm, phytype); if (!err) diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c index d6d9413d7f23..6acfdc49dccd 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c @@ -444,7 +444,7 @@ static int bcm43xx_wx_set_xmitpower(struct net_device *net_dev, u16 maxpower; if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) { - printk(PFX KERN_ERR "TX power not in dBm.\n"); + printk(KERN_ERR PFX "TX power not in dBm.\n"); return -EOPNOTSUPP; } diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 27e00b2d7b5b..171ca712e523 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -285,7 +285,7 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom) } } -void __devinit pci_read_bridge_bases(struct pci_bus *child) +void pci_read_bridge_bases(struct pci_bus *child) { struct pci_dev *dev = child->self; u8 io_base_lo, io_limit_lo; diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 2d40f437b9fc..50f2dd9e1bb2 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -972,8 +972,8 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, k8t_sound_ho * * The SMBus PCI Device can be activated by setting a bit in the ICH LPC * bridge. Unfortunately, this device has no subvendor/subdevice ID. So it - * becomes necessary to do this tweak in two steps -- I've chosen the Host - * bridge as trigger. + * becomes necessary to do this tweak in two steps -- the chosen trigger + * is either the Host bridge (preferred) or on-board VGA controller. * * Note that we used to unhide the SMBus that way on Toshiba laptops * (Satellite A40 and Tecra M2) but then found that the thermal management @@ -1070,6 +1070,14 @@ static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev) case 0x0058: /* Compaq Evo N620c */ asus_hides_smbus = 1; } + else if (dev->device == PCI_DEVICE_ID_INTEL_82810_IG3) + switch(dev->subsystem_device) { + case 0xB16C: /* Compaq Deskpro EP 401963-001 (PCA# 010174) */ + /* Motherboard doesn't have Host bridge + * subvendor/subdevice IDs, therefore checking + * its on-board VGA controller */ + asus_hides_smbus = 1; + } } } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82845_HB, asus_hides_smbus_hostbridge ); @@ -1082,6 +1090,8 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82855PM_HB, as DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82855GM_HB, asus_hides_smbus_hostbridge ); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82915GM_HB, asus_hides_smbus_hostbridge ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82810_IG3, asus_hides_smbus_hostbridge ); + static void asus_hides_smbus_lpc(struct pci_dev *dev) { u16 val; @@ -1099,12 +1109,14 @@ static void asus_hides_smbus_lpc(struct pci_dev *dev) printk(KERN_INFO "PCI: Enabled i801 SMBus device\n"); } } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, asus_hides_smbus_lpc ); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, asus_hides_smbus_lpc ); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, asus_hides_smbus_lpc ); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, asus_hides_smbus_lpc ); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, asus_hides_smbus_lpc ); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, asus_hides_smbus_lpc ); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, asus_hides_smbus_lpc ); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, asus_hides_smbus_lpc ); DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, asus_hides_smbus_lpc ); DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, asus_hides_smbus_lpc ); DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, asus_hides_smbus_lpc ); @@ -1432,7 +1444,6 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NETMOS, PCI_ANY_ID, quirk_netmos); static void __devinit quirk_e100_interrupt(struct pci_dev *dev) { u16 command; - u32 bar; u8 __iomem *csr; u8 cmd_hi; @@ -1464,12 +1475,12 @@ static void __devinit quirk_e100_interrupt(struct pci_dev *dev) * re-enable them when it's ready. */ pci_read_config_word(dev, PCI_COMMAND, &command); - pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &bar); - if (!(command & PCI_COMMAND_MEMORY) || !bar) + if (!(command & PCI_COMMAND_MEMORY) || !pci_resource_start(dev, 0)) return; - csr = ioremap(bar, 8); + /* Convert from PCI bus to resource space. */ + csr = ioremap(pci_resource_start(dev, 0), 8); if (!csr) { printk(KERN_WARNING "PCI: Can't map %s e100 registers\n", pci_name(dev)); diff --git a/drivers/pnp/quirks.c b/drivers/pnp/quirks.c index 90755d4cdb9f..6b0cf0c2a088 100644 --- a/drivers/pnp/quirks.c +++ b/drivers/pnp/quirks.c @@ -107,108 +107,6 @@ static void quirk_sb16audio_resources(struct pnp_dev *dev) "pnp: SB audio device quirk - increasing port range\n"); } -static int quirk_smc_fir_enabled(struct pnp_dev *dev) -{ - unsigned long firbase; - u8 bank, high, low, chip; - - if (!pnp_port_valid(dev, 1)) - return 0; - - firbase = pnp_port_start(dev, 1); - - /* Select register bank 3 */ - bank = inb(firbase + 7); - bank &= 0xf0; - bank |= 3; - outb(bank, firbase + 7); - - high = inb(firbase + 0); - low = inb(firbase + 1); - chip = inb(firbase + 2); - - /* This corresponds to the check in smsc_ircc_present() */ - if (high == 0x10 && low == 0xb8 && (chip == 0xf1 || chip == 0xf2)) - return 1; - - return 0; -} - -static void quirk_smc_enable(struct pnp_dev *dev) -{ - struct resource fir, sir, irq; - - pnp_activate_dev(dev); - if (quirk_smc_fir_enabled(dev)) - return; - - /* - * Sometimes the BIOS claims the device is enabled, but it reports - * the wrong FIR resources or doesn't properly configure ISA or LPC - * bridges on the way to the device. - * - * HP nc6000 and nc8000/nw8000 laptops have known problems like - * this. Fortunately, they do fix things up if we auto-configure - * the device using its _PRS and _SRS methods. - */ - dev_err(&dev->dev, "%s not responding at SIR 0x%lx, FIR 0x%lx; " - "auto-configuring\n", dev->id->id, - (unsigned long)pnp_port_start(dev, 0), - (unsigned long)pnp_port_start(dev, 1)); - - pnp_disable_dev(dev); - pnp_init_resource_table(&dev->res); - pnp_auto_config_dev(dev); - pnp_activate_dev(dev); - if (quirk_smc_fir_enabled(dev)) { - dev_err(&dev->dev, "responds at SIR 0x%lx, FIR 0x%lx\n", - (unsigned long)pnp_port_start(dev, 0), - (unsigned long)pnp_port_start(dev, 1)); - return; - } - - /* - * The Toshiba Portege 4000 _CRS reports the FIR region first, - * followed by the SIR region. The BIOS will configure the bridge, - * but only if we call _SRS with SIR first, then FIR. It also - * reports the IRQ as active high, when it is really active low. - */ - dev_err(&dev->dev, "not responding at SIR 0x%lx, FIR 0x%lx; " - "swapping SIR/FIR and reconfiguring\n", - (unsigned long)pnp_port_start(dev, 0), - (unsigned long)pnp_port_start(dev, 1)); - - /* - * Clear IORESOURCE_AUTO so pnp_activate_dev() doesn't reassign - * these resources any more. - */ - fir = dev->res.port_resource[0]; - sir = dev->res.port_resource[1]; - fir.flags &= ~IORESOURCE_AUTO; - sir.flags &= ~IORESOURCE_AUTO; - - irq = dev->res.irq_resource[0]; - irq.flags &= ~IORESOURCE_AUTO; - irq.flags &= ~IORESOURCE_BITS; - irq.flags |= IORESOURCE_IRQ_LOWEDGE; - - pnp_disable_dev(dev); - dev->res.port_resource[0] = sir; - dev->res.port_resource[1] = fir; - dev->res.irq_resource[0] = irq; - pnp_activate_dev(dev); - - if (quirk_smc_fir_enabled(dev)) { - dev_err(&dev->dev, "responds at SIR 0x%lx, FIR 0x%lx\n", - (unsigned long)pnp_port_start(dev, 0), - (unsigned long)pnp_port_start(dev, 1)); - return; - } - - dev_err(&dev->dev, "giving up; try \"smsc-ircc2.nopnp\" and " - "email bjorn.helgaas@hp.com\n"); -} - /* * PnP Quirks * Cards or devices that need some tweaking due to incomplete resource info @@ -229,7 +127,6 @@ static struct pnp_fixup pnp_fixups[] = { {"CTL0043", quirk_sb16audio_resources}, {"CTL0044", quirk_sb16audio_resources}, {"CTL0045", quirk_sb16audio_resources}, - {"SMCf010", quirk_smc_enable}, {""} }; diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c index c7c4574729b1..de3155b21285 100644 --- a/drivers/power/power_supply_sysfs.c +++ b/drivers/power/power_supply_sysfs.c @@ -289,6 +289,7 @@ int power_supply_uevent(struct device *dev, char **envp, int num_envp, if (ret) goto out; } + envp[i] = NULL; out: free_page((unsigned long)prop_buf); diff --git a/drivers/rtc/rtc-ds1553.c b/drivers/rtc/rtc-ds1553.c index 46da5714932c..5ab3492817d1 100644 --- a/drivers/rtc/rtc-ds1553.c +++ b/drivers/rtc/rtc-ds1553.c @@ -61,7 +61,7 @@ struct rtc_plat_data { struct rtc_device *rtc; void __iomem *ioaddr; - unsigned long baseaddr; + resource_size_t baseaddr; unsigned long last_jiffies; int irq; unsigned int irqen; diff --git a/drivers/rtc/rtc-ds1742.c b/drivers/rtc/rtc-ds1742.c index b2e5481ba3b6..67291b0f8283 100644 --- a/drivers/rtc/rtc-ds1742.c +++ b/drivers/rtc/rtc-ds1742.c @@ -55,7 +55,7 @@ struct rtc_plat_data { void __iomem *ioaddr_rtc; size_t size_nvram; size_t size; - unsigned long baseaddr; + resource_size_t baseaddr; unsigned long last_jiffies; }; diff --git a/drivers/rtc/rtc-v3020.c b/drivers/rtc/rtc-v3020.c index 3b58d3d5d38a..a6b572978dc0 100644 --- a/drivers/rtc/rtc-v3020.c +++ b/drivers/rtc/rtc-v3020.c @@ -26,6 +26,7 @@ #include <linux/types.h> #include <linux/bcd.h> #include <linux/rtc-v3020.h> +#include <linux/delay.h> #include <asm/io.h> @@ -47,6 +48,7 @@ static void v3020_set_reg(struct v3020 *chip, unsigned char address, for (i = 0; i < 4; i++) { writel((tmp & 1) << chip->leftshift, chip->ioaddress); tmp >>= 1; + udelay(1); } /* Commands dont have data */ @@ -54,6 +56,7 @@ static void v3020_set_reg(struct v3020 *chip, unsigned char address, for (i = 0; i < 8; i++) { writel((data & 1) << chip->leftshift, chip->ioaddress); data >>= 1; + udelay(1); } } } @@ -66,12 +69,14 @@ static unsigned char v3020_get_reg(struct v3020 *chip, unsigned char address) for (i = 0; i < 4; i++) { writel((address & 1) << chip->leftshift, chip->ioaddress); address >>= 1; + udelay(1); } for (i = 0; i < 8; i++) { data >>= 1; if (readl(chip->ioaddress) & (1 << chip->leftshift)) data |= 0x80; + udelay(1); } return data; @@ -95,7 +100,7 @@ static int v3020_read_time(struct device *dev, struct rtc_time *dt) tmp = v3020_get_reg(chip, V3020_MONTH_DAY); dt->tm_mday = BCD2BIN(tmp); tmp = v3020_get_reg(chip, V3020_MONTH); - dt->tm_mon = BCD2BIN(tmp); + dt->tm_mon = BCD2BIN(tmp) - 1; tmp = v3020_get_reg(chip, V3020_WEEK_DAY); dt->tm_wday = BCD2BIN(tmp); tmp = v3020_get_reg(chip, V3020_YEAR); @@ -135,7 +140,7 @@ static int v3020_set_time(struct device *dev, struct rtc_time *dt) v3020_set_reg(chip, V3020_MINUTES, BIN2BCD(dt->tm_min)); v3020_set_reg(chip, V3020_HOURS, BIN2BCD(dt->tm_hour)); v3020_set_reg(chip, V3020_MONTH_DAY, BIN2BCD(dt->tm_mday)); - v3020_set_reg(chip, V3020_MONTH, BIN2BCD(dt->tm_mon)); + v3020_set_reg(chip, V3020_MONTH, BIN2BCD(dt->tm_mon + 1)); v3020_set_reg(chip, V3020_WEEK_DAY, BIN2BCD(dt->tm_wday)); v3020_set_reg(chip, V3020_YEAR, BIN2BCD(dt->tm_year % 100)); diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index ab5ec1feaf4e..90aa53fc4f3e 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -1503,7 +1503,7 @@ zfcp_gid_pn_buffers_alloc(struct zfcp_gid_pn_data **gid_pn, mempool_t *pool) data->ct.pool = pool; } } else { - data = kmalloc(sizeof(struct zfcp_gid_pn_data), GFP_ATOMIC); + data = kmem_cache_alloc(zfcp_data.gid_pn_cache, GFP_ATOMIC); } if (NULL == data) @@ -1531,7 +1531,7 @@ static void zfcp_gid_pn_buffers_free(struct zfcp_gid_pn_data *gid_pn) if (gid_pn->ct.pool) mempool_free(gid_pn, gid_pn->ct.pool); else - kfree(gid_pn); + kmem_cache_free(zfcp_data.gid_pn_cache, gid_pn); } /** diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index 81daa8204bfe..c6899efdc8f6 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c @@ -640,13 +640,9 @@ int zfcp_qdio_sbals_from_scsicmnd(struct zfcp_fsf_req *fsf_req, unsigned long sbtype, struct scsi_cmnd *scsi_cmnd) { - if (scsi_sg_count(scsi_cmnd)) - return zfcp_qdio_sbals_from_sg(fsf_req, sbtype, - scsi_sglist(scsi_cmnd), - scsi_sg_count(scsi_cmnd), - ZFCP_MAX_SBALS_PER_REQ); - else - return 0; + return zfcp_qdio_sbals_from_sg(fsf_req, sbtype, scsi_sglist(scsi_cmnd), + scsi_sg_count(scsi_cmnd), + ZFCP_MAX_SBALS_PER_REQ); } /** diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 0acf6db0a08d..ad7eb4a9261c 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -764,7 +764,9 @@ zfcp_reset_fc_host_stats(struct Scsi_Host *shost) return; ret = zfcp_fsf_exchange_port_data(NULL, adapter, data); - if (ret == 0) { + if (ret) { + kfree(data); + } else { adapter->stats_reset = jiffies/HZ; old_data = adapter->stats_reset_data; adapter->stats_reset_data = data; /* finally freed in diff --git a/drivers/scsi/aic94xx/aic94xx_task.c b/drivers/scsi/aic94xx/aic94xx_task.c index d5d8caba3560..ab13824df856 100644 --- a/drivers/scsi/aic94xx/aic94xx_task.c +++ b/drivers/scsi/aic94xx/aic94xx_task.c @@ -451,7 +451,7 @@ static int asd_build_smp_ascb(struct asd_ascb *ascb, struct sas_task *task, struct scb *scb; pci_map_sg(asd_ha->pcidev, &task->smp_task.smp_req, 1, - PCI_DMA_FROMDEVICE); + PCI_DMA_TODEVICE); pci_map_sg(asd_ha->pcidev, &task->smp_task.smp_resp, 1, PCI_DMA_FROMDEVICE); @@ -486,7 +486,7 @@ static void asd_unbuild_smp_ascb(struct asd_ascb *a) BUG_ON(!task); pci_unmap_sg(a->ha->pcidev, &task->smp_task.smp_req, 1, - PCI_DMA_FROMDEVICE); + PCI_DMA_TODEVICE); pci_unmap_sg(a->ha->pcidev, &task->smp_task.smp_resp, 1, PCI_DMA_FROMDEVICE); } diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c index 77b06a983fa7..95cf7b6cd622 100644 --- a/drivers/scsi/esp_scsi.c +++ b/drivers/scsi/esp_scsi.c @@ -2314,6 +2314,7 @@ int __devinit scsi_esp_register(struct esp *esp, struct device *dev) esp->host->transportt = esp_transport_template; esp->host->max_lun = ESP_MAX_LUN; esp->host->cmd_per_lun = 2; + esp->host->unique_id = instance; esp_set_clock_params(esp); @@ -2337,7 +2338,7 @@ int __devinit scsi_esp_register(struct esp *esp, struct device *dev) if (err) return err; - esp->host->unique_id = instance++; + instance++; scsi_scan_host(esp->host); diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 5606d1e62978..efceed451b46 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -737,12 +737,19 @@ check_mgmt: */ conn->ctask = list_entry(conn->xmitqueue.next, struct iscsi_cmd_task, running); - if (conn->ctask->state == ISCSI_TASK_PENDING) { + switch (conn->ctask->state) { + case ISCSI_TASK_ABORTING: + break; + case ISCSI_TASK_PENDING: iscsi_prep_scsi_cmd_pdu(conn->ctask); conn->session->tt->init_cmd_task(conn->ctask); + /* fall through */ + default: + conn->ctask->state = ISCSI_TASK_RUNNING; + break; } - conn->ctask->state = ISCSI_TASK_RUNNING; list_move_tail(conn->xmitqueue.next, &conn->run_list); + rc = iscsi_xmit_ctask(conn); if (rc) goto again; @@ -1049,7 +1056,9 @@ static int iscsi_exec_abort_task(struct scsi_cmnd *sc, ctask->mtask = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)hdr, NULL, 0); if (!ctask->mtask) { + spin_unlock_bh(&session->lock); iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); + spin_lock_bh(&session->lock) debug_scsi("abort sent failure [itt 0x%x]\n", ctask->itt); return -EPERM; } @@ -1066,6 +1075,7 @@ static int iscsi_exec_abort_task(struct scsi_cmnd *sc, debug_scsi("abort set timeout [itt 0x%x]\n", ctask->itt); } spin_unlock_bh(&session->lock); + mutex_unlock(&session->eh_mutex); scsi_queue_work(session->host, &conn->xmitwork); /* @@ -1083,6 +1093,7 @@ static int iscsi_exec_abort_task(struct scsi_cmnd *sc, if (signal_pending(current)) flush_signals(current); del_timer_sync(&conn->tmabort_timer); + mutex_lock(&session->eh_mutex); spin_lock_bh(&session->lock); return 0; } @@ -1158,31 +1169,45 @@ static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, __iscsi_put_ctask(ctask); } +static void iscsi_suspend_tx(struct iscsi_conn *conn) +{ + set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); + scsi_flush_work(conn->session->host); +} + +static void iscsi_start_tx(struct iscsi_conn *conn) +{ + clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); + scsi_queue_work(conn->session->host, &conn->xmitwork); +} + int iscsi_eh_abort(struct scsi_cmnd *sc) { + struct Scsi_Host *host = sc->device->host; + struct iscsi_session *session = iscsi_hostdata(host->hostdata); struct iscsi_cmd_task *ctask; struct iscsi_conn *conn; - struct iscsi_session *session; int rc; + mutex_lock(&session->eh_mutex); + spin_lock_bh(&session->lock); /* * if session was ISCSI_STATE_IN_RECOVERY then we may not have * got the command. */ if (!sc->SCp.ptr) { debug_scsi("sc never reached iscsi layer or it completed.\n"); + spin_unlock_bh(&session->lock); + mutex_unlock(&session->eh_mutex); return SUCCESS; } ctask = (struct iscsi_cmd_task *)sc->SCp.ptr; conn = ctask->conn; - session = conn->session; conn->eh_abort_cnt++; debug_scsi("aborting [sc %p itt 0x%x]\n", sc, ctask->itt); - spin_lock_bh(&session->lock); - /* * If we are not logged in or we have started a new session * then let the host reset code handle this @@ -1219,6 +1244,7 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) switch (conn->tmabort_state) { case TMABORT_SUCCESS: spin_unlock_bh(&session->lock); + iscsi_suspend_tx(conn); /* * clean up task if aborted. grab the recv lock as a writer */ @@ -1227,11 +1253,7 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) fail_command(conn, ctask, DID_ABORT << 16); spin_unlock(&session->lock); write_unlock_bh(conn->recv_lock); - /* - * make sure xmit thread is not still touching the - * ctask/scsi_cmnd - */ - scsi_flush_work(session->host); + iscsi_start_tx(conn); goto success_unlocked; case TMABORT_NOT_FOUND: if (!ctask->sc) { @@ -1251,12 +1273,14 @@ success: spin_unlock_bh(&session->lock); success_unlocked: debug_scsi("abort success [sc %lx itt 0x%x]\n", (long)sc, ctask->itt); + mutex_unlock(&session->eh_mutex); return SUCCESS; failed: spin_unlock_bh(&session->lock); failed_unlocked: debug_scsi("abort failed [sc %lx itt 0x%x]\n", (long)sc, ctask->itt); + mutex_unlock(&session->eh_mutex); return FAILED; } EXPORT_SYMBOL_GPL(iscsi_eh_abort); @@ -1403,6 +1427,7 @@ iscsi_session_setup(struct iscsi_transport *iscsit, session->max_cmdsn = initial_cmdsn + 1; session->max_r2t = 1; session->tt = iscsit; + mutex_init(&session->eh_mutex); /* initialize SCSI PDU commands pool */ if (iscsi_pool_init(&session->cmdpool, session->cmds_max, @@ -1736,9 +1761,22 @@ static void iscsi_start_session_recovery(struct iscsi_session *session, { int old_stop_stage; + mutex_lock(&session->eh_mutex); spin_lock_bh(&session->lock); if (conn->stop_stage == STOP_CONN_TERM) { spin_unlock_bh(&session->lock); + mutex_unlock(&session->eh_mutex); + return; + } + + /* + * The LLD either freed/unset the lock on us, or userspace called + * stop but did not create a proper connection (connection was never + * bound or it was unbound then stop was called). + */ + if (!conn->recv_lock) { + spin_unlock_bh(&session->lock); + mutex_unlock(&session->eh_mutex); return; } @@ -1755,9 +1793,9 @@ static void iscsi_start_session_recovery(struct iscsi_session *session, old_stop_stage = conn->stop_stage; conn->stop_stage = flag; conn->c_stage = ISCSI_CONN_STOPPED; - set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); spin_unlock_bh(&session->lock); - scsi_flush_work(session->host); + + iscsi_suspend_tx(conn); write_lock_bh(conn->recv_lock); set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx); @@ -1786,6 +1824,7 @@ static void iscsi_start_session_recovery(struct iscsi_session *session, fail_all_commands(conn); flush_control_queues(session, conn); spin_unlock_bh(&session->lock); + mutex_unlock(&session->eh_mutex); } void iscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index 3907f6718ede..da56163c30a8 100644 --- a/drivers/scsi/megaraid.c +++ b/drivers/scsi/megaraid.c @@ -1753,6 +1753,14 @@ mega_build_sglist(adapter_t *adapter, scb_t *scb, u32 *buf, u32 *len) *len = 0; + if (scsi_sg_count(cmd) == 1 && !adapter->has_64bit_addr) { + sg = scsi_sglist(cmd); + scb->dma_h_bulkdata = sg_dma_address(sg); + *buf = (u32)scb->dma_h_bulkdata; + *len = sg_dma_len(sg); + return 0; + } + scsi_for_each_sg(cmd, sg, sgcnt, idx) { if (adapter->has_64bit_addr) { scb->sgl64[idx].address = sg_dma_address(sg); diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c index 563d18f4ff50..c6680348b648 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.c +++ b/drivers/scsi/qla2xxx/qla_dbg.c @@ -2050,21 +2050,18 @@ qla25xx_fw_dump_failed: void qla2x00_dump_regs(scsi_qla_host_t *ha) { + int i; struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; + struct device_reg_24xx __iomem *reg24 = &ha->iobase->isp24; + uint16_t __iomem *mbx_reg; + + mbx_reg = IS_FWI2_CAPABLE(ha) ? ®24->mailbox0: + MAILBOX_REG(ha, reg, 0); printk("Mailbox registers:\n"); - printk("scsi(%ld): mbox 0 0x%04x \n", - ha->host_no, RD_MAILBOX_REG(ha, reg, 0)); - printk("scsi(%ld): mbox 1 0x%04x \n", - ha->host_no, RD_MAILBOX_REG(ha, reg, 1)); - printk("scsi(%ld): mbox 2 0x%04x \n", - ha->host_no, RD_MAILBOX_REG(ha, reg, 2)); - printk("scsi(%ld): mbox 3 0x%04x \n", - ha->host_no, RD_MAILBOX_REG(ha, reg, 3)); - printk("scsi(%ld): mbox 4 0x%04x \n", - ha->host_no, RD_MAILBOX_REG(ha, reg, 4)); - printk("scsi(%ld): mbox 5 0x%04x \n", - ha->host_no, RD_MAILBOX_REG(ha, reg, 5)); + for (i = 0; i < 6; i++) + printk("scsi(%ld): mbox %d 0x%04x \n", ha->host_no, i, + RD_REG_WORD(mbx_reg++)); } diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 27ae3a532a55..c1964866a423 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -1502,7 +1502,6 @@ typedef struct { uint8_t node_name[WWN_SIZE]; uint8_t port_name[WWN_SIZE]; uint8_t fabric_port_name[WWN_SIZE]; - uint16_t fp_speeds; uint16_t fp_speed; } sw_info_t; diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index b06cbb8580d3..a7e23583f899 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -295,6 +295,8 @@ qla2x00_gid_pt(scsi_qla_host_t *ha, sw_info_t *list) list[i].d_id.b.domain = gid_data->port_id[0]; list[i].d_id.b.area = gid_data->port_id[1]; list[i].d_id.b.al_pa = gid_data->port_id[2]; + memset(list[i].fabric_port_name, 0, WWN_SIZE); + list[i].fp_speed = PORT_SPEED_UNKNOWN; /* Last one exit. */ if (gid_data->control_byte & BIT_7) { @@ -1707,8 +1709,6 @@ qla2x00_gfpn_id(scsi_qla_host_t *ha, sw_info_t *list) for (i = 0; i < MAX_FIBRE_DEVICES; i++) { /* Issue GFPN_ID */ - memset(list[i].fabric_port_name, 0, WWN_SIZE); - /* Prepare common MS IOCB */ ms_pkt = ha->isp_ops->prep_ms_iocb(ha, GFPN_ID_REQ_SIZE, GFPN_ID_RSP_SIZE); @@ -1821,8 +1821,6 @@ qla2x00_gpsc(scsi_qla_host_t *ha, sw_info_t *list) for (i = 0; i < MAX_FIBRE_DEVICES; i++) { /* Issue GFPN_ID */ - list[i].fp_speeds = list[i].fp_speed = 0; - /* Prepare common MS IOCB */ ms_pkt = qla24xx_prep_ms_fm_iocb(ha, GPSC_REQ_SIZE, GPSC_RSP_SIZE); @@ -1858,9 +1856,21 @@ qla2x00_gpsc(scsi_qla_host_t *ha, sw_info_t *list) } rval = QLA_FUNCTION_FAILED; } else { - /* Save portname */ - list[i].fp_speeds = ct_rsp->rsp.gpsc.speeds; - list[i].fp_speed = ct_rsp->rsp.gpsc.speed; + /* Save port-speed */ + switch (be16_to_cpu(ct_rsp->rsp.gpsc.speed)) { + case BIT_15: + list[i].fp_speed = PORT_SPEED_1GB; + break; + case BIT_14: + list[i].fp_speed = PORT_SPEED_2GB; + break; + case BIT_13: + list[i].fp_speed = PORT_SPEED_4GB; + break; + case BIT_11: + list[i].fp_speed = PORT_SPEED_8GB; + break; + } DEBUG2_3(printk("scsi(%ld): GPSC ext entry - " "fpn %02x%02x%02x%02x%02x%02x%02x%02x speeds=%04x " @@ -1873,8 +1883,8 @@ qla2x00_gpsc(scsi_qla_host_t *ha, sw_info_t *list) list[i].fabric_port_name[5], list[i].fabric_port_name[6], list[i].fabric_port_name[7], - be16_to_cpu(list[i].fp_speeds), - be16_to_cpu(list[i].fp_speed))); + be16_to_cpu(ct_rsp->rsp.gpsc.speeds), + be16_to_cpu(ct_rsp->rsp.gpsc.speed))); } /* Last device exit. */ diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 374abe19b547..1a058ec9bd0c 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -2079,17 +2079,7 @@ qla2x00_configure_local_loop(scsi_qla_host_t *ha) } /* Base iIDMA settings on HBA port speed. */ - switch (ha->link_data_rate) { - case PORT_SPEED_1GB: - fcport->fp_speed = cpu_to_be16(BIT_15); - break; - case PORT_SPEED_2GB: - fcport->fp_speed = cpu_to_be16(BIT_14); - break; - case PORT_SPEED_4GB: - fcport->fp_speed = cpu_to_be16(BIT_13); - break; - } + fcport->fp_speed = ha->link_data_rate; qla2x00_update_fcport(ha, fcport); @@ -2130,38 +2120,25 @@ static void qla2x00_iidma_fcport(scsi_qla_host_t *ha, fc_port_t *fcport) { #define LS_UNKNOWN 2 - static char *link_speeds[5] = { "1", "2", "?", "4" }; + static char *link_speeds[5] = { "1", "2", "?", "4", "8" }; int rval; - uint16_t port_speed, mb[6]; + uint16_t mb[6]; if (!IS_IIDMA_CAPABLE(ha)) return; - switch (be16_to_cpu(fcport->fp_speed)) { - case BIT_15: - port_speed = PORT_SPEED_1GB; - break; - case BIT_14: - port_speed = PORT_SPEED_2GB; - break; - case BIT_13: - port_speed = PORT_SPEED_4GB; - break; - default: + if (fcport->fp_speed == PORT_SPEED_UNKNOWN) { DEBUG2(printk("scsi(%ld): %02x%02x%02x%02x%02x%02x%02x%02x -- " - "unsupported FM port operating speed (%04x).\n", + "unsupported FM port operating speed.\n", ha->host_no, fcport->port_name[0], fcport->port_name[1], fcport->port_name[2], fcport->port_name[3], fcport->port_name[4], fcport->port_name[5], - fcport->port_name[6], fcport->port_name[7], - be16_to_cpu(fcport->fp_speed))); - port_speed = PORT_SPEED_UNKNOWN; - break; - } - if (port_speed == PORT_SPEED_UNKNOWN) + fcport->port_name[6], fcport->port_name[7])); return; + } - rval = qla2x00_set_idma_speed(ha, fcport->loop_id, port_speed, mb); + rval = qla2x00_set_idma_speed(ha, fcport->loop_id, fcport->fp_speed, + mb); if (rval != QLA_SUCCESS) { DEBUG2(printk("scsi(%ld): Unable to adjust iIDMA " "%02x%02x%02x%02x%02x%02x%02x%02x -- %04x %x %04x %04x.\n", @@ -2169,12 +2146,12 @@ qla2x00_iidma_fcport(scsi_qla_host_t *ha, fc_port_t *fcport) fcport->port_name[2], fcport->port_name[3], fcport->port_name[4], fcport->port_name[5], fcport->port_name[6], fcport->port_name[7], rval, - port_speed, mb[0], mb[1])); + fcport->fp_speed, mb[0], mb[1])); } else { DEBUG2(qla_printk(KERN_INFO, ha, "iIDMA adjusted to %s GB/s on " "%02x%02x%02x%02x%02x%02x%02x%02x.\n", - link_speeds[port_speed], fcport->port_name[0], + link_speeds[fcport->fp_speed], fcport->port_name[0], fcport->port_name[1], fcport->port_name[2], fcport->port_name[3], fcport->port_name[4], fcport->port_name[5], fcport->port_name[6], @@ -3354,7 +3331,8 @@ qla2x00_restart_isp(scsi_qla_host_t *ha) spin_lock_irqsave(&ha->hardware_lock, flags); - if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha)) { + if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha) && + !IS_QLA25XX(ha)) { /* * Disable SRAM, Instruction RAM and GP RAM * parity. @@ -3370,7 +3348,8 @@ qla2x00_restart_isp(scsi_qla_host_t *ha) spin_lock_irqsave(&ha->hardware_lock, flags); - if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha)) { + if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha) && + !IS_QLA25XX(ha)) { /* Enable proper parity */ if (IS_QLA2300(ha)) /* SRAM parity */ diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 50539da467bf..eecae9905ece 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -490,6 +490,7 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb) set_bit(REGISTER_FC4_NEEDED, &ha->dpc_flags); ha->flags.gpsc_supported = 1; + ha->flags.management_server_logged_in = 0; break; case MBA_CHG_IN_CONNECTION: /* Change in connection mode */ diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 93c0c7e4f08f..acca898ce0a2 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -1564,7 +1564,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) struct Scsi_Host *host; scsi_qla_host_t *ha; unsigned long flags = 0; - char pci_info[20]; + char pci_info[30]; char fw_str[30]; struct scsi_host_template *sht; diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index dd1f8ceb79c4..18095b9b76f4 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -7,7 +7,7 @@ /* * Driver version */ -#define QLA2XXX_VERSION "8.02.00-k2" +#define QLA2XXX_VERSION "8.02.00-k3" #define QLA_DRIVER_MAJOR_VER 8 #define QLA_DRIVER_MINOR_VER 2 diff --git a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c index 6f56f8750635..4df21c92ff1e 100644 --- a/drivers/scsi/scsi_transport_spi.c +++ b/drivers/scsi/scsi_transport_spi.c @@ -787,10 +787,12 @@ spi_dv_device_internal(struct scsi_device *sdev, u8 *buffer) struct scsi_target *starget = sdev->sdev_target; struct Scsi_Host *shost = sdev->host; int len = sdev->inquiry_len; + int min_period = spi_min_period(starget); + int max_width = spi_max_width(starget); /* first set us up for narrow async */ DV_SET(offset, 0); DV_SET(width, 0); - + if (spi_dv_device_compare_inquiry(sdev, buffer, buffer, DV_LOOPS) != SPI_COMPARE_SUCCESS) { starget_printk(KERN_ERR, starget, "Domain Validation Initial Inquiry Failed\n"); @@ -798,9 +800,13 @@ spi_dv_device_internal(struct scsi_device *sdev, u8 *buffer) return; } + if (!scsi_device_wide(sdev)) { + spi_max_width(starget) = 0; + max_width = 0; + } + /* test width */ - if (i->f->set_width && spi_max_width(starget) && - scsi_device_wide(sdev)) { + if (i->f->set_width && max_width) { i->f->set_width(starget, 1); if (spi_dv_device_compare_inquiry(sdev, buffer, @@ -809,6 +815,11 @@ spi_dv_device_internal(struct scsi_device *sdev, u8 *buffer) != SPI_COMPARE_SUCCESS) { starget_printk(KERN_ERR, starget, "Wide Transfers Fail\n"); i->f->set_width(starget, 0); + /* Make sure we don't force wide back on by asking + * for a transfer period that requires it */ + max_width = 0; + if (min_period < 10) + min_period = 10; } } @@ -828,7 +839,8 @@ spi_dv_device_internal(struct scsi_device *sdev, u8 *buffer) /* now set up to the maximum */ DV_SET(offset, spi_max_offset(starget)); - DV_SET(period, spi_min_period(starget)); + DV_SET(period, min_period); + /* try QAS requests; this should be harmless to set if the * target supports it */ if (scsi_device_qas(sdev)) { @@ -837,14 +849,14 @@ spi_dv_device_internal(struct scsi_device *sdev, u8 *buffer) DV_SET(qas, 0); } - if (scsi_device_ius(sdev) && spi_min_period(starget) < 9) { + if (scsi_device_ius(sdev) && min_period < 9) { /* This u320 (or u640). Set IU transfers */ DV_SET(iu, 1); /* Then set the optional parameters */ DV_SET(rd_strm, 1); DV_SET(wr_flow, 1); DV_SET(rti, 1); - if (spi_min_period(starget) == 8) + if (min_period == 8) DV_SET(pcomp_en, 1); } else { DV_SET(iu, 0); @@ -862,6 +874,10 @@ spi_dv_device_internal(struct scsi_device *sdev, u8 *buffer) } else { DV_SET(dt, 1); } + /* set width last because it will pull all the other + * parameters down to required values */ + DV_SET(width, max_width); + /* Do the read only INQUIRY tests */ spi_dv_retrain(sdev, buffer, buffer + sdev->inquiry_len, spi_dv_device_compare_inquiry); diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 64ff6a5f6afd..81b52b7cca21 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -611,7 +611,7 @@ config SERIAL_BFIN config SERIAL_BFIN_CONSOLE bool "Console on Blackfin serial port" - depends on SERIAL_BFIN + depends on SERIAL_BFIN=y select SERIAL_CORE_CONSOLE choice @@ -832,10 +832,10 @@ config SERIAL_MUX 4. Change the kernel command console parameter to: console=ttyB0 config SERIAL_MUX_CONSOLE - bool "Support for console on serial MUX" - depends on SERIAL_MUX + bool "Support for console on serial MUX" + depends on SERIAL_MUX=y select SERIAL_CORE_CONSOLE - default y + default y config PDC_CONSOLE bool "PDC software console support" diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.h b/drivers/serial/cpm_uart/cpm_uart_cpm1.h index a99e45e2b6d8..2a6477834c3e 100644 --- a/drivers/serial/cpm_uart/cpm_uart_cpm1.h +++ b/drivers/serial/cpm_uart/cpm_uart_cpm1.h @@ -37,6 +37,6 @@ static inline void cpm_set_smc_fcr(volatile smc_uart_t * up) up->smc_tfcr = SMC_EB; } -#define DPRAM_BASE ((unsigned char *)&cpmp->cp_dpmem[0]) +#define DPRAM_BASE ((unsigned char *)cpm_dpram_addr(0)) #endif diff --git a/drivers/serial/sb1250-duart.c b/drivers/serial/sb1250-duart.c index 201253755011..2d6c08b3dbcf 100644 --- a/drivers/serial/sb1250-duart.c +++ b/drivers/serial/sb1250-duart.c @@ -58,6 +58,12 @@ #define SBD_CTRLREGS(line) A_BCM1480_DUART_CTRLREG((line), 0) #define SBD_INT(line) (K_BCM1480_INT_UART_0 + (line)) +#define DUART_CHANREG_SPACING BCM1480_DUART_CHANREG_SPACING + +#define R_DUART_IMRREG(line) R_BCM1480_DUART_IMRREG(line) +#define R_DUART_INCHREG(line) R_BCM1480_DUART_INCHREG(line) +#define R_DUART_ISRREG(line) R_BCM1480_DUART_ISRREG(line) + #elif defined(CONFIG_SIBYTE_SB1250) || defined(CONFIG_SIBYTE_BCM112X) #include <asm/sibyte/sb1250_regs.h> #include <asm/sibyte/sb1250_int.h> diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c index a0ea43598515..7c8d78fbbbfb 100644 --- a/drivers/serial/serial_cs.c +++ b/drivers/serial/serial_cs.c @@ -943,6 +943,7 @@ static struct pcmcia_device_id serial_ids[] = { PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial Port: SL432",0x3beb8cf2,0x1cce7ac4), PCMCIA_MFC_DEVICE_PROD_ID12(2,"Elan","Serial Port: SL432",0x3beb8cf2,0x1cce7ac4), PCMCIA_MFC_DEVICE_PROD_ID12(3,"Elan","Serial Port: SL432",0x3beb8cf2,0x1cce7ac4), + PCMCIA_DEVICE_MANF_CARD(0x0279, 0x950b), /* too generic */ /* PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0160, 0x0002), */ /* PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x0160, 0x0002), */ diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c index bca57bb94939..ff610c23314b 100644 --- a/drivers/serial/sunsab.c +++ b/drivers/serial/sunsab.c @@ -38,7 +38,7 @@ #include <asm/prom.h> #include <asm/of_device.h> -#if defined(CONFIG_SERIAL_SUNZILOG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#if defined(CONFIG_SERIAL_SUNSAB_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) #define SUPPORT_SYSRQ #endif @@ -58,6 +58,7 @@ struct uart_sunsab_port { unsigned char interrupt_mask1;/* ISR1 masking */ unsigned char pvr_dtr_bit; /* Which PVR bit is DTR */ unsigned char pvr_dsr_bit; /* Which PVR bit is DSR */ + unsigned int gis_shift; int type; /* SAB82532 version */ /* Setting configuration bits while the transmitter is active @@ -305,13 +306,15 @@ static irqreturn_t sunsab_interrupt(int irq, void *dev_id) struct tty_struct *tty; union sab82532_irq_status status; unsigned long flags; + unsigned char gis; spin_lock_irqsave(&up->port.lock, flags); status.stat = 0; - if (readb(&up->regs->r.gis) & SAB82532_GIS_ISA0) + gis = readb(&up->regs->r.gis) >> up->gis_shift; + if (gis & 1) status.sreg.isr0 = readb(&up->regs->r.isr0); - if (readb(&up->regs->r.gis) & SAB82532_GIS_ISA1) + if (gis & 2) status.sreg.isr1 = readb(&up->regs->r.isr1); tty = NULL; @@ -327,35 +330,6 @@ static irqreturn_t sunsab_interrupt(int irq, void *dev_id) transmit_chars(up, &status); } - spin_unlock(&up->port.lock); - - if (tty) - tty_flip_buffer_push(tty); - - up++; - - spin_lock(&up->port.lock); - - status.stat = 0; - if (readb(&up->regs->r.gis) & SAB82532_GIS_ISB0) - status.sreg.isr0 = readb(&up->regs->r.isr0); - if (readb(&up->regs->r.gis) & SAB82532_GIS_ISB1) - status.sreg.isr1 = readb(&up->regs->r.isr1); - - tty = NULL; - if (status.stat) { - if ((status.sreg.isr0 & (SAB82532_ISR0_TCD | SAB82532_ISR0_TIME | - SAB82532_ISR0_RFO | SAB82532_ISR0_RPF)) || - (status.sreg.isr1 & SAB82532_ISR1_BRK)) - - tty = receive_chars(up, &status); - if ((status.sreg.isr0 & SAB82532_ISR0_CDSC) || - (status.sreg.isr1 & (SAB82532_ISR1_BRK | SAB82532_ISR1_CSC))) - check_status(up, &status); - if (status.sreg.isr1 & (SAB82532_ISR1_ALLS | SAB82532_ISR1_XPR)) - transmit_chars(up, &status); - } - spin_unlock_irqrestore(&up->port.lock, flags); if (tty) @@ -539,6 +513,10 @@ static int sunsab_startup(struct uart_port *port) struct uart_sunsab_port *up = (struct uart_sunsab_port *) port; unsigned long flags; unsigned char tmp; + int err = request_irq(up->port.irq, sunsab_interrupt, + IRQF_SHARED, "sab", up); + if (err) + return err; spin_lock_irqsave(&up->port.lock, flags); @@ -641,6 +619,7 @@ static void sunsab_shutdown(struct uart_port *port) #endif spin_unlock_irqrestore(&up->port.lock, flags); + free_irq(up->port.irq, up); } /* @@ -1008,9 +987,11 @@ static int __devinit sunsab_init_one(struct uart_sunsab_port *up, if ((up->port.line & 0x1) == 0) { up->pvr_dsr_bit = (1 << 0); up->pvr_dtr_bit = (1 << 1); + up->gis_shift = 2; } else { up->pvr_dsr_bit = (1 << 3); up->pvr_dtr_bit = (1 << 2); + up->gis_shift = 0; } up->cached_pvr = (1 << 1) | (1 << 2) | (1 << 4); writeb(up->cached_pvr, &up->regs->w.pvr); @@ -1023,19 +1004,6 @@ static int __devinit sunsab_init_one(struct uart_sunsab_port *up, up->tec_timeout = SAB82532_MAX_TEC_TIMEOUT; up->cec_timeout = SAB82532_MAX_CEC_TIMEOUT; - if (!(up->port.line & 0x01)) { - int err; - - err = request_irq(up->port.irq, sunsab_interrupt, - IRQF_SHARED, "sab", up); - if (err) { - of_iounmap(&op->resource[0], - up->port.membase, - sizeof(union sab82532_async_regs)); - return err; - } - } - return 0; } @@ -1051,52 +1019,60 @@ static int __devinit sab_probe(struct of_device *op, const struct of_device_id * 0, (inst * 2) + 0); if (err) - return err; + goto out; err = sunsab_init_one(&up[1], op, sizeof(union sab82532_async_regs), (inst * 2) + 1); - if (err) { - of_iounmap(&op->resource[0], - up[0].port.membase, - sizeof(union sab82532_async_regs)); - free_irq(up[0].port.irq, &up[0]); - return err; - } + if (err) + goto out1; sunserial_console_match(SUNSAB_CONSOLE(), op->node, &sunsab_reg, up[0].port.line); - uart_add_one_port(&sunsab_reg, &up[0].port); sunserial_console_match(SUNSAB_CONSOLE(), op->node, &sunsab_reg, up[1].port.line); - uart_add_one_port(&sunsab_reg, &up[1].port); + + err = uart_add_one_port(&sunsab_reg, &up[0].port); + if (err) + goto out2; + + err = uart_add_one_port(&sunsab_reg, &up[1].port); + if (err) + goto out3; dev_set_drvdata(&op->dev, &up[0]); inst++; return 0; -} - -static void __devexit sab_remove_one(struct uart_sunsab_port *up) -{ - struct of_device *op = to_of_device(up->port.dev); - uart_remove_one_port(&sunsab_reg, &up->port); - if (!(up->port.line & 1)) - free_irq(up->port.irq, up); +out3: + uart_remove_one_port(&sunsab_reg, &up[0].port); +out2: of_iounmap(&op->resource[0], - up->port.membase, + up[1].port.membase, sizeof(union sab82532_async_regs)); +out1: + of_iounmap(&op->resource[0], + up[0].port.membase, + sizeof(union sab82532_async_regs)); +out: + return err; } static int __devexit sab_remove(struct of_device *op) { struct uart_sunsab_port *up = dev_get_drvdata(&op->dev); - sab_remove_one(&up[0]); - sab_remove_one(&up[1]); + uart_remove_one_port(&sunsab_reg, &up[1].port); + uart_remove_one_port(&sunsab_reg, &up[0].port); + of_iounmap(&op->resource[0], + up[1].port.membase, + sizeof(union sab82532_async_regs)); + of_iounmap(&op->resource[0], + up[0].port.membase, + sizeof(union sab82532_async_regs)); dev_set_drvdata(&op->dev, NULL); @@ -1143,6 +1119,7 @@ static int __init sunsab_init(void) sunsab_reg.minor = sunserial_current_minor; sunsab_reg.nr = num_channels; + sunsab_reg.cons = SUNSAB_CONSOLE(); err = uart_register_driver(&sunsab_reg); if (err) { diff --git a/drivers/spi/spi_mpc83xx.c b/drivers/spi/spi_mpc83xx.c index fcbf1b8a5264..32cda77b31cd 100644 --- a/drivers/spi/spi_mpc83xx.c +++ b/drivers/spi/spi_mpc83xx.c @@ -384,11 +384,8 @@ irqreturn_t mpc83xx_spi_irq(s32 irq, void *context_data) mpc83xx_spi->count -= 1; if (mpc83xx_spi->count) { - if (mpc83xx_spi->tx) { - u32 word = mpc83xx_spi->get_tx(mpc83xx_spi); - mpc83xx_spi_write_reg(&mpc83xx_spi->base->transmit, - word); - } + u32 word = mpc83xx_spi->get_tx(mpc83xx_spi); + mpc83xx_spi_write_reg(&mpc83xx_spi->base->transmit, word); } else { complete(&mpc83xx_spi->done); } diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index a1ad11d0c47c..63b1243a9139 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -60,7 +60,7 @@ ssize_t usb_store_new_id(struct usb_dynids *dynids, dynid->id.match_flags = USB_DEVICE_ID_MATCH_DEVICE; spin_lock(&dynids->lock); - list_add_tail(&dynids->list, &dynid->node); + list_add_tail(&dynid->node, &dynids->list); spin_unlock(&dynids->lock); if (get_driver(driver)) { diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index 9e467118dc94..ebf3dc20110a 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -28,10 +28,16 @@ * devices is broken... */ static const struct usb_device_id usb_quirk_list[] = { + /* CBM - Flash disk */ + { USB_DEVICE(0x0204, 0x6025), .driver_info = USB_QUIRK_RESET_RESUME }, /* HP 5300/5370C scanner */ { USB_DEVICE(0x03f0, 0x0701), .driver_info = USB_QUIRK_STRING_FETCH_255 }, /* Hewlett-Packard PhotoSmart 720 / PhotoSmart 935 (storage) */ { USB_DEVICE(0x03f0, 0x4002), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, + + /* SGS Thomson Microelectronics 4in1 card reader */ + { USB_DEVICE(0x0483, 0x0321), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, + /* Acer Peripherals Inc. (now BenQ Corp.) Prisa 640BU */ { USB_DEVICE(0x04a5, 0x207e), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, /* Benq S2W 3300U */ @@ -66,6 +72,19 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x05cc, 0x2267), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, /* Ultima Electronics Corp.*/ { USB_DEVICE(0x05d8, 0x4005), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, + + /* Genesys USB-to-IDE */ + { USB_DEVICE(0x0503, 0x0702), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, + + /* USB Graphical LCD - EEH Datalink GmbH */ + { USB_DEVICE(0x060c, 0x04eb), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, + + /* INTEL VALUE SSD */ + { USB_DEVICE(0x8086, 0xf1a5), .driver_info = USB_QUIRK_RESET_RESUME }, + + /* M-Systems Flash Disk Pioneers */ + { USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME }, + /* Agfa Snapscan1212u */ { USB_DEVICE(0x06bd, 0x2061), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, /* Seagate RSS LLC */ @@ -87,6 +106,12 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x0fca, 0x0004), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, { USB_DEVICE(0x0fca, 0x0006), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, + /* Apple iPhone */ + { USB_DEVICE(0x05ac, 0x1290), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, + + /* SKYMEDI USB_DRIVE */ + { USB_DEVICE(0x1516, 0x8628), .driver_info = USB_QUIRK_RESET_RESUME }, + { } /* terminating entry must be last */ }; @@ -127,4 +152,10 @@ void usb_detect_quirks(struct usb_device *udev) /* do any special quirk handling here if needed */ if (udev->quirks & USB_QUIRK_NO_AUTOSUSPEND) usb_autosuspend_quirk(udev); + + /* By default, disable autosuspend for all non-hubs */ +#ifdef CONFIG_USB_SUSPEND + if (udev->descriptor.bDeviceClass != USB_CLASS_HUB) + udev->autosuspend_delay = -1; +#endif } diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c index 9cd98e73dc1d..ce4d2e09633d 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c @@ -1691,14 +1691,12 @@ static int gs_setup_class(struct usb_gadget *gadget, switch (ctrl->bRequest) { case USB_CDC_REQ_SET_LINE_CODING: - ret = min(wLength, - (u16)sizeof(struct usb_cdc_line_coding)); - if (port) { - spin_lock(&port->port_lock); - memcpy(&port->port_line_coding, req->buf, ret); - spin_unlock(&port->port_lock); - } - ret = 0; + /* FIXME Submit req to read the data; have its completion + * handler copy that data to port->port_line_coding (iff + * it's valid) and maybe pass it on. Until then, fail. + */ + printk(KERN_WARNING "gs_setup: set_line_coding " + "unuspported\n"); break; case USB_CDC_REQ_GET_LINE_CODING: @@ -1713,11 +1711,18 @@ static int gs_setup_class(struct usb_gadget *gadget, break; case USB_CDC_REQ_SET_CONTROL_LINE_STATE: - ret = 0; + /* FIXME Submit req to read the data; have its completion + * handler use that to set the state (iff it's valid) and + * maybe pass it on. Until then, fail. + */ + printk(KERN_WARNING "gs_setup: set_control_line_state " + "unuspported\n"); break; default: - printk(KERN_ERR "gs_setup: unknown class request, type=%02x, request=%02x, value=%04x, index=%04x, length=%d\n", + printk(KERN_ERR "gs_setup: unknown class request, " + "type=%02x, request=%02x, value=%04x, " + "index=%04x, length=%d\n", ctrl->bRequestType, ctrl->bRequest, wValue, wIndex, wLength); break; diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c index 9f37ba44c132..b64ca91d9b02 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.c +++ b/drivers/usb/misc/sisusbvga/sisusb.c @@ -3404,6 +3404,7 @@ static void sisusb_disconnect(struct usb_interface *intf) } static struct usb_device_id sisusb_table [] = { + { USB_DEVICE(0x0711, 0x0550) }, { USB_DEVICE(0x0711, 0x0900) }, { USB_DEVICE(0x0711, 0x0901) }, { USB_DEVICE(0x0711, 0x0902) }, diff --git a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c index c08a38402b93..a47a24f8820d 100644 --- a/drivers/usb/serial/bus.c +++ b/drivers/usb/serial/bus.c @@ -138,7 +138,7 @@ static void free_dynids(struct usb_serial_driver *drv) static struct driver_attribute drv_attrs[] = { __ATTR_NULL, }; -static inline void free_dynids(struct usb_driver *drv) +static inline void free_dynids(struct usb_serial_driver *drv) { } #endif diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 1370c423d7c2..2d045857b181 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -568,6 +568,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(ELEKTOR_VID, ELEKTOR_FT323R_PID) }, { USB_DEVICE(TELLDUS_VID, TELLDUS_TELLSTICK_PID) }, { USB_DEVICE(FTDI_VID, FTDI_MAXSTREAM_PID) }, + { USB_DEVICE(TML_VID, TML_USB_SERIAL_PID) }, { USB_DEVICE(OLIMEX_VID, OLIMEX_ARM_USB_OCD_PID), .driver_info = (kernel_ulong_t)&ftdi_olimex_quirk }, { }, /* Optional parameter entry */ diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index c70e1de6389e..b57b90ae9f9d 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h @@ -534,6 +534,14 @@ #define OLIMEX_VID 0x15BA #define OLIMEX_ARM_USB_OCD_PID 0x0003 + +/* + * The Mobility Lab (TML) + * Submitted by Pierre Castella + */ +#define TML_VID 0x1B91 /* Vendor ID */ +#define TML_USB_SERIAL_PID 0x0064 /* USB - Serial Converter */ + /* Commands */ #define FTDI_SIO_RESET 0 /* Reset the port */ #define FTDI_SIO_MODEM_CTRL 1 /* Set the modem control register */ diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 4cb3c165742b..a18659e0700c 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -108,6 +108,7 @@ static int option_send_setup(struct usb_serial_port *port); #define HUAWEI_VENDOR_ID 0x12D1 #define HUAWEI_PRODUCT_E600 0x1001 #define HUAWEI_PRODUCT_E220 0x1003 +#define HUAWEI_PRODUCT_E220BIS 0x1004 #define NOVATELWIRELESS_VENDOR_ID 0x1410 #define DELL_VENDOR_ID 0x413C @@ -158,6 +159,7 @@ static struct usb_device_id option_ids[] = { { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_KOI_NETWORK) }, { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) }, { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220) }, + { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220BIS) }, { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x1100) }, /* Novatel Merlin XS620/S640 */ { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x1110) }, /* Novatel Merlin S620 */ { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x1120) }, /* Novatel Merlin EX720 */ @@ -176,6 +178,7 @@ static struct usb_device_id option_ids[] = { { USB_DEVICE(DELL_VENDOR_ID, 0x8117) }, /* Dell Wireless 5700 Mobile Broadband CDMA/EVDO ExpressCard == Novatel Merlin XV620 CDMA/EV-DO */ { USB_DEVICE(DELL_VENDOR_ID, 0x8118) }, /* Dell Wireless 5510 Mobile Broadband HSDPA ExpressCard == Novatel Merlin XU870 HSDPA/3G */ { USB_DEVICE(DELL_VENDOR_ID, 0x8128) }, /* Dell Wireless 5700 Mobile Broadband CDMA/EVDO Mini-Card == Novatel Expedite E720 CDMA/EV-DO */ + { USB_DEVICE(DELL_VENDOR_ID, 0x8137) }, /* Dell Wireless HSDPA 5520 */ { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_E100A) }, { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_500A) }, { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_C100_1) }, diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c index 833ada47fc54..64f3f66a7a35 100644 --- a/drivers/usb/serial/oti6858.c +++ b/drivers/usb/serial/oti6858.c @@ -817,21 +817,6 @@ static int oti6858_ioctl(struct usb_serial_port *port, struct file *file, __FUNCTION__, port->number, cmd, arg); switch (cmd) { - case TCGETS: - if (kernel_termios_to_user_termios((struct ktermios __user *)arg, - port->tty->termios)) - return -EFAULT; - return 0; - - case TCSETS: - case TCSETSW: /* FIXME: this is not the same! */ - case TCSETSF: /* FIXME: this is not the same! */ - if (user_termios_to_kernel_termios(port->tty->termios, - (struct ktermios __user *)arg)) - return -EFAULT; - oti6858_set_termios(port, NULL); - return 0; - case TCFLSH: /* FIXME */ return 0; diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c index 47e56079925d..1ba19eaa1970 100644 --- a/drivers/usb/storage/scsiglue.c +++ b/drivers/usb/storage/scsiglue.c @@ -285,15 +285,10 @@ static int device_reset(struct scsi_cmnd *srb) US_DEBUGP("%s called\n", __FUNCTION__); - result = usb_autopm_get_interface(us->pusb_intf); - if (result == 0) { - - /* lock the device pointers and do the reset */ - mutex_lock(&(us->dev_mutex)); - result = us->transport_reset(us); - mutex_unlock(&us->dev_mutex); - usb_autopm_put_interface(us->pusb_intf); - } + /* lock the device pointers and do the reset */ + mutex_lock(&(us->dev_mutex)); + result = us->transport_reset(us); + mutex_unlock(&us->dev_mutex); return result < 0 ? FAILED : SUCCESS; } diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 2d92ce31018f..c6b78ba815ea 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -348,6 +348,13 @@ UNUSUAL_DEV( 0x04b0, 0x0411, 0x0100, 0x0101, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_CAPACITY), +/* Reported by Ortwin Glueck <odi@odi.ch> */ +UNUSUAL_DEV( 0x04b0, 0x0413, 0x0110, 0x0110, + "NIKON", + "NIKON DSC D40", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_FIX_CAPACITY), + /* BENQ DC5330 * Reported by Manuel Fombuena <mfombuena@ya.com> and * Frank Copeland <fjc@thingy.apana.org.au> */ @@ -897,6 +904,22 @@ UNUSUAL_DEV( 0x069b, 0x3004, 0x0001, 0x0001, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_CAPACITY ), +/* Reported by Massimiliano Ghilardi <massimiliano.ghilardi@gmail.com> + * This USB MP3/AVI player device fails and disconnects if more than 128 + * sectors (64kB) are read/written in a single command, and may be present + * at least in the following products: + * "Magnex Digital Video Panel DVP 1800" + * "MP4 AIGO 4GB SLOT SD" + * "Teclast TL-C260 MP3" + * "i.Meizu PMP MP3/MP4" + * "Speed MV8 MP4 Audio Player" + */ +UNUSUAL_DEV( 0x071b, 0x3203, 0x0100, 0x0100, + "RockChip", + "ROCK MP3", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_MAX_SECTORS_64), + /* Reported by Olivier Blondeau <zeitoun@gmail.com> */ UNUSUAL_DEV( 0x0727, 0x0306, 0x0100, 0x0100, "ATMEL", @@ -1393,6 +1416,13 @@ UNUSUAL_DEV( 0x0fce, 0xe030, 0x0000, 0x0000, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_CAPACITY | US_FL_IGNORE_RESIDUE ), +/* Reported by Ricardo Barberis <ricardo@dattatec.com> */ +UNUSUAL_DEV( 0x0fce, 0xe092, 0x0000, 0x0000, + "Sony Ericsson", + "P1i", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_IGNORE_RESIDUE ), + /* Reported by Emmanuel Vasilakis <evas@forthnet.gr> */ UNUSUAL_DEV( 0x0fce, 0xe031, 0x0000, 0x0000, "Sony Ericsson", diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index 25e557d4fe6b..59181667066c 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -184,14 +184,16 @@ static int storage_suspend(struct usb_interface *iface, pm_message_t message) { struct us_data *us = usb_get_intfdata(iface); - US_DEBUGP("%s\n", __FUNCTION__); - /* Wait until no command is running */ mutex_lock(&us->dev_mutex); + US_DEBUGP("%s\n", __FUNCTION__); if (us->suspend_resume_hook) (us->suspend_resume_hook)(us, US_SUSPEND); + /* When runtime PM is working, we'll set a flag to indicate + * whether we should autoresume when a SCSI request arrives. */ + mutex_unlock(&us->dev_mutex); return 0; } @@ -200,11 +202,13 @@ static int storage_resume(struct usb_interface *iface) { struct us_data *us = usb_get_intfdata(iface); - US_DEBUGP("%s\n", __FUNCTION__); + mutex_lock(&us->dev_mutex); + US_DEBUGP("%s\n", __FUNCTION__); if (us->suspend_resume_hook) (us->suspend_resume_hook)(us, US_RESUME); + mutex_unlock(&us->dev_mutex); return 0; } @@ -302,7 +306,6 @@ static int usb_stor_control_thread(void * __us) { struct us_data *us = (struct us_data *)__us; struct Scsi_Host *host = us_to_host(us); - int autopm_rc; for(;;) { US_DEBUGP("*** thread sleeping.\n"); @@ -311,9 +314,6 @@ static int usb_stor_control_thread(void * __us) US_DEBUGP("*** thread awakened.\n"); - /* Autoresume the device */ - autopm_rc = usb_autopm_get_interface(us->pusb_intf); - /* lock the device pointers */ mutex_lock(&(us->dev_mutex)); @@ -372,12 +372,6 @@ static int usb_stor_control_thread(void * __us) us->srb->result = SAM_STAT_GOOD; } - /* Did the autoresume fail? */ - else if (autopm_rc < 0) { - US_DEBUGP("Could not wake device\n"); - us->srb->result = DID_ERROR << 16; - } - /* we've got a command, let's do it! */ else { US_DEBUG(usb_stor_show_command(us->srb)); @@ -420,10 +414,6 @@ SkipForAbort: /* unlock the device pointers */ mutex_unlock(&us->dev_mutex); - - /* Start an autosuspend */ - if (autopm_rc == 0) - usb_autopm_put_interface(us->pusb_intf); } /* for (;;) */ /* Wait until we are told to stop */ @@ -941,7 +931,6 @@ retry: /* Should we unbind if no devices were detected? */ } - usb_autopm_put_interface(us->pusb_intf); complete_and_exit(&us->scanning_done, 0); } @@ -1027,7 +1016,6 @@ static int storage_probe(struct usb_interface *intf, goto BadDevice; } - usb_autopm_get_interface(intf); /* dropped in the scanning thread */ wake_up_process(th); return 0; @@ -1065,7 +1053,6 @@ static struct usb_driver usb_storage_driver = { .pre_reset = storage_pre_reset, .post_reset = storage_post_reset, .id_table = storage_usb_ids, - .supports_autosuspend = 1, }; static int __init usb_stor_init(void) diff --git a/drivers/video/aty/ati_ids.h b/drivers/video/aty/ati_ids.h index 685a754991c6..dca2eb8f2dde 100644 --- a/drivers/video/aty/ati_ids.h +++ b/drivers/video/aty/ati_ids.h @@ -192,6 +192,12 @@ #define PCI_CHIP_RS300_5835 0x5835 #define PCI_CHIP_RS300_5836 0x5836 #define PCI_CHIP_RS300_5837 0x5837 +#define PCI_CHIP_RS480_5955 0x5955 +#define PCI_CHIP_RV280_5960 0x5960 +#define PCI_CHIP_RV280_5961 0x5961 +#define PCI_CHIP_RV280_5962 0x5962 +#define PCI_CHIP_RV280_5964 0x5964 +#define PCI_CHIP_RS482_5975 0x5975 #define PCI_CHIP_RV370_5B60 0x5B60 #define PCI_CHIP_RV370_5B61 0x5B61 #define PCI_CHIP_RV370_5B62 0x5B62 @@ -200,14 +206,8 @@ #define PCI_CHIP_RV370_5B65 0x5B65 #define PCI_CHIP_RV370_5B66 0x5B66 #define PCI_CHIP_RV370_5B67 0x5B67 -#define PCI_CHIP_RV280_5960 0x5960 -#define PCI_CHIP_RV280_5961 0x5961 -#define PCI_CHIP_RV280_5962 0x5962 -#define PCI_CHIP_RV280_5964 0x5964 -#define PCI_CHIP_RS485_5975 0x5975 #define PCI_CHIP_RV280_5C61 0x5C61 #define PCI_CHIP_RV280_5C63 0x5C63 #define PCI_CHIP_R423_5D57 0x5D57 #define PCI_CHIP_RS350_7834 0x7834 #define PCI_CHIP_RS350_7835 0x7835 -#define PCI_CHIP_RS480_5955 0x5955 diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c index 47ca62fe7c3e..4b747bdaeea6 100644 --- a/drivers/video/aty/radeon_base.c +++ b/drivers/video/aty/radeon_base.c @@ -102,6 +102,7 @@ static struct pci_device_id radeonfb_pci_table[] = { /* Radeon Xpress 200m */ CHIP_DEF(PCI_CHIP_RS480_5955, RS480, CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY), + CHIP_DEF(PCI_CHIP_RS482_5975, RS480, CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY), /* Mobility M6 */ CHIP_DEF(PCI_CHIP_RADEON_LY, RV100, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), CHIP_DEF(PCI_CHIP_RADEON_LZ, RV100, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), @@ -153,8 +154,6 @@ static struct pci_device_id radeonfb_pci_table[] = { /* Mobility 9200 (M9+) */ CHIP_DEF(PCI_CHIP_RV280_5C61, RV280, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), CHIP_DEF(PCI_CHIP_RV280_5C63, RV280, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), - /*Mobility Xpress 200 */ - CHIP_DEF(PCI_CHIP_RS485_5975, R300, CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY), /* 9200 */ CHIP_DEF(PCI_CHIP_RV280_5960, RV280, CHIP_HAS_CRTC2), CHIP_DEF(PCI_CHIP_RV280_5961, RV280, CHIP_HAS_CRTC2), @@ -1285,7 +1284,8 @@ static void radeon_write_pll_regs(struct radeonfb_info *rinfo, struct radeon_reg if (rinfo->family == CHIP_FAMILY_R300 || rinfo->family == CHIP_FAMILY_RS300 || rinfo->family == CHIP_FAMILY_R350 || - rinfo->family == CHIP_FAMILY_RV350) { + rinfo->family == CHIP_FAMILY_RV350 || + rinfo->family == CHIP_FAMILY_RV380 ) { if (mode->ppll_ref_div & R300_PPLL_REF_DIV_ACC_MASK) { /* When restoring console mode, use saved PPLL_REF_DIV * setting. diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c index 16bc8d75e36e..6a47682d8614 100644 --- a/drivers/video/intelfb/intelfbhw.c +++ b/drivers/video/intelfb/intelfbhw.c @@ -924,10 +924,10 @@ calc_pll_params(int index, int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *re if (m > pll->max_m) m = pll->max_m - 1; for (testm = m - 1; testm <= m; testm++) { - f_out = calc_vclock3(index, m, n, p); + f_out = calc_vclock3(index, testm, n, p); if (splitm(index, testm, &m1, &m2)) { - WRN_MSG("cannot split m = %d\n", m); - n++; + WRN_MSG("cannot split m = %d\n", + testm); continue; } if (clock > f_out) @@ -1352,7 +1352,7 @@ intelfbhw_program_mode(struct intelfb_info *dinfo, /* turn off PLL */ tmp = INREG(dpll_reg); - dpll_reg &= ~DPLL_VCO_ENABLE; + tmp &= ~DPLL_VCO_ENABLE; OUTREG(dpll_reg, tmp); /* Set PLL parameters */ diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c index 8d7ab74170d5..a593f900eff4 100644 --- a/drivers/w1/w1.c +++ b/drivers/w1/w1.c @@ -431,6 +431,7 @@ static int w1_uevent(struct device *dev, char **envp, int num_envp, err = add_uevent_var(envp, num_envp, &cur_index, buffer, buffer_size, &cur_len, "W1_SLAVE_ID=%024LX", (unsigned long long)sl->reg_num.id); + envp[cur_index] = NULL; if (err) return err; |