From: Linus Torvalds Date: Thu, 2 May 2013 00:51:54 +0000 (-0700) Subject: Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs X-Git-Url: https://openfabrics.org/gitweb/?a=commitdiff_plain;h=20b4fb485227404329e41ad15588afad3df23050;p=~shefty%2Frdma-dev.git Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs Pull VFS updates from Al Viro, Misc cleanups all over the place, mainly wrt /proc interfaces (switch create_proc_entry to proc_create(), get rid of the deprecated create_proc_read_entry() in favor of using proc_create_data() and seq_file etc). 7kloc removed. * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (204 commits) don't bother with deferred freeing of fdtables proc: Move non-public stuff from linux/proc_fs.h to fs/proc/internal.h proc: Make the PROC_I() and PDE() macros internal to procfs proc: Supply a function to remove a proc entry by PDE take cgroup_open() and cpuset_open() to fs/proc/base.c ppc: Clean up scanlog ppc: Clean up rtas_flash driver somewhat hostap: proc: Use remove_proc_subtree() drm: proc: Use remove_proc_subtree() drm: proc: Use minor->index to label things, not PDE->name drm: Constify drm_proc_list[] zoran: Don't print proc_dir_entry data in debug reiserfs: Don't access the proc_dir_entry in r_open(), r_start() r_show() proc: Supply an accessor for getting the data from a PDE's parent airo: Use remove_proc_subtree() rtl8192u: Don't need to save device proc dir PDE rtl8187se: Use a dir under /proc/net/r8180/ proc: Add proc_mkdir_data() proc: Move some bits from linux/proc_fs.h to linux/{of.h,signal.h,tty.h} proc: Move PDE_NET() to fs/proc/proc_net.c ... --- 20b4fb485227404329e41ad15588afad3df23050 diff --cc drivers/firmware/efi/efi-pstore.c index 67615d6d038,00000000000..202d2c85ba2 mode 100644,000000..100644 --- a/drivers/firmware/efi/efi-pstore.c +++ b/drivers/firmware/efi/efi-pstore.c @@@ -1,251 -1,0 +1,252 @@@ +#include +#include +#include ++#include +#include + +#define DUMP_NAME_LEN 52 + +static bool efivars_pstore_disable = + IS_ENABLED(CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE); + +module_param_named(pstore_disable, efivars_pstore_disable, bool, 0644); + +#define PSTORE_EFI_ATTRIBUTES \ + (EFI_VARIABLE_NON_VOLATILE | \ + EFI_VARIABLE_BOOTSERVICE_ACCESS | \ + EFI_VARIABLE_RUNTIME_ACCESS) + +static int efi_pstore_open(struct pstore_info *psi) +{ + efivar_entry_iter_begin(); + psi->data = NULL; + return 0; +} + +static int efi_pstore_close(struct pstore_info *psi) +{ + efivar_entry_iter_end(); + psi->data = NULL; + return 0; +} + +struct pstore_read_data { + u64 *id; + enum pstore_type_id *type; + int *count; + struct timespec *timespec; + char **buf; +}; + +static int efi_pstore_read_func(struct efivar_entry *entry, void *data) +{ + efi_guid_t vendor = LINUX_EFI_CRASH_GUID; + struct pstore_read_data *cb_data = data; + char name[DUMP_NAME_LEN]; + int i; + int cnt; + unsigned int part; + unsigned long time, size; + + if (efi_guidcmp(entry->var.VendorGuid, vendor)) + return 0; + + for (i = 0; i < DUMP_NAME_LEN; i++) + name[i] = entry->var.VariableName[i]; + + if (sscanf(name, "dump-type%u-%u-%d-%lu", + cb_data->type, &part, &cnt, &time) == 4) { + *cb_data->id = part; + *cb_data->count = cnt; + cb_data->timespec->tv_sec = time; + cb_data->timespec->tv_nsec = 0; + } else if (sscanf(name, "dump-type%u-%u-%lu", + cb_data->type, &part, &time) == 3) { + /* + * Check if an old format, + * which doesn't support holding + * multiple logs, remains. + */ + *cb_data->id = part; + *cb_data->count = 0; + cb_data->timespec->tv_sec = time; + cb_data->timespec->tv_nsec = 0; + } else + return 0; + + entry->var.DataSize = 1024; + __efivar_entry_get(entry, &entry->var.Attributes, + &entry->var.DataSize, entry->var.Data); + size = entry->var.DataSize; + + *cb_data->buf = kmalloc(size, GFP_KERNEL); + if (*cb_data->buf == NULL) + return -ENOMEM; + memcpy(*cb_data->buf, entry->var.Data, size); + return size; +} + +static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type, + int *count, struct timespec *timespec, + char **buf, struct pstore_info *psi) +{ + struct pstore_read_data data; + + data.id = id; + data.type = type; + data.count = count; + data.timespec = timespec; + data.buf = buf; + + return __efivar_entry_iter(efi_pstore_read_func, &efivar_sysfs_list, &data, + (struct efivar_entry **)&psi->data); +} + +static int efi_pstore_write(enum pstore_type_id type, + enum kmsg_dump_reason reason, u64 *id, + unsigned int part, int count, size_t size, + struct pstore_info *psi) +{ + char name[DUMP_NAME_LEN]; + efi_char16_t efi_name[DUMP_NAME_LEN]; + efi_guid_t vendor = LINUX_EFI_CRASH_GUID; + int i, ret = 0; + + sprintf(name, "dump-type%u-%u-%d-%lu", type, part, count, + get_seconds()); + + for (i = 0; i < DUMP_NAME_LEN; i++) + efi_name[i] = name[i]; + + efivar_entry_set_safe(efi_name, vendor, PSTORE_EFI_ATTRIBUTES, + !pstore_cannot_block_path(reason), + size, psi->buf); + + if (reason == KMSG_DUMP_OOPS) + efivar_run_worker(); + + *id = part; + return ret; +}; + +struct pstore_erase_data { + u64 id; + enum pstore_type_id type; + int count; + struct timespec time; + efi_char16_t *name; +}; + +/* + * Clean up an entry with the same name + */ +static int efi_pstore_erase_func(struct efivar_entry *entry, void *data) +{ + struct pstore_erase_data *ed = data; + efi_guid_t vendor = LINUX_EFI_CRASH_GUID; + efi_char16_t efi_name_old[DUMP_NAME_LEN]; + efi_char16_t *efi_name = ed->name; + unsigned long ucs2_len = ucs2_strlen(ed->name); + char name_old[DUMP_NAME_LEN]; + int i; + + if (efi_guidcmp(entry->var.VendorGuid, vendor)) + return 0; + + if (ucs2_strncmp(entry->var.VariableName, + efi_name, (size_t)ucs2_len)) { + /* + * Check if an old format, which doesn't support + * holding multiple logs, remains. + */ + sprintf(name_old, "dump-type%u-%u-%lu", ed->type, + (unsigned int)ed->id, ed->time.tv_sec); + + for (i = 0; i < DUMP_NAME_LEN; i++) + efi_name_old[i] = name_old[i]; + + if (ucs2_strncmp(entry->var.VariableName, efi_name_old, + ucs2_strlen(efi_name_old))) + return 0; + } + + /* found */ + __efivar_entry_delete(entry); + list_del(&entry->list); + + return 1; +} + +static int efi_pstore_erase(enum pstore_type_id type, u64 id, int count, + struct timespec time, struct pstore_info *psi) +{ + struct pstore_erase_data edata; + struct efivar_entry *entry = NULL; + char name[DUMP_NAME_LEN]; + efi_char16_t efi_name[DUMP_NAME_LEN]; + int found, i; + + sprintf(name, "dump-type%u-%u-%d-%lu", type, (unsigned int)id, count, + time.tv_sec); + + for (i = 0; i < DUMP_NAME_LEN; i++) + efi_name[i] = name[i]; + + edata.id = id; + edata.type = type; + edata.count = count; + edata.time = time; + edata.name = efi_name; + + efivar_entry_iter_begin(); + found = __efivar_entry_iter(efi_pstore_erase_func, &efivar_sysfs_list, &edata, &entry); + efivar_entry_iter_end(); + + if (found) + efivar_unregister(entry); + + return 0; +} + +static struct pstore_info efi_pstore_info = { + .owner = THIS_MODULE, + .name = "efi", + .open = efi_pstore_open, + .close = efi_pstore_close, + .read = efi_pstore_read, + .write = efi_pstore_write, + .erase = efi_pstore_erase, +}; + +static __init int efivars_pstore_init(void) +{ + if (!efi_enabled(EFI_RUNTIME_SERVICES)) + return 0; + + if (!efivars_kobject()) + return 0; + + if (efivars_pstore_disable) + return 0; + + efi_pstore_info.buf = kmalloc(4096, GFP_KERNEL); + if (!efi_pstore_info.buf) + return -ENOMEM; + + efi_pstore_info.bufsize = 1024; + spin_lock_init(&efi_pstore_info.buf_lock); + + pstore_register(&efi_pstore_info); + + return 0; +} + +static __exit void efivars_pstore_exit(void) +{ +} + +module_init(efivars_pstore_init); +module_exit(efivars_pstore_exit); + +MODULE_DESCRIPTION("EFI variable backend for pstore"); +MODULE_LICENSE("GPL"); diff --cc drivers/firmware/efi/efivars.c index 5e94897244c,00000000000..b623c599e57 mode 100644,000000..100644 --- a/drivers/firmware/efi/efivars.c +++ b/drivers/firmware/efi/efivars.c @@@ -1,616 -1,0 +1,617 @@@ +/* + * Originally from efivars.c, + * + * Copyright (C) 2001,2003,2004 Dell + * Copyright (C) 2004 Intel Corporation + * + * This code takes all variables accessible from EFI runtime and + * exports them via sysfs + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Changelog: + * + * 17 May 2004 - Matt Domsch + * remove check for efi_enabled in exit + * add MODULE_VERSION + * + * 26 Apr 2004 - Matt Domsch + * minor bug fixes + * + * 21 Apr 2004 - Matt Tolentino + * fix locking per Peter Chubb's findings + * + * 25 Mar 2002 - Matt Domsch + * move uuid_unparse() to include/asm-ia64/efi.h:efi_guid_unparse() + * + * 12 Feb 2002 - Matt Domsch + * use list_for_each_safe when deleting vars. + * remove ifdef CONFIG_SMP around include + * v0.04 release to linux-ia64@linuxia64.org + * + * 20 April 2001 - Matt Domsch + * Moved vars from /proc/efi to /proc/efi/vars, and made + * efi.c own the /proc/efi directory. + * v0.03 release to linux-ia64@linuxia64.org + * + * 26 March 2001 - Matt Domsch + * At the request of Stephane, moved ownership of /proc/efi + * to efi.c, and now efivars lives under /proc/efi/vars. + * + * 12 March 2001 - Matt Domsch + * Feedback received from Stephane Eranian incorporated. + * efivar_write() checks copy_from_user() return value. + * efivar_read/write() returns proper errno. + * v0.02 release to linux-ia64@linuxia64.org + * + * 26 February 2001 - Matt Domsch + * v0.01 release to linux-ia64@linuxia64.org + */ + +#include +#include ++#include +#include + +#define EFIVARS_VERSION "0.08" +#define EFIVARS_DATE "2004-May-17" + +MODULE_AUTHOR("Matt Domsch "); +MODULE_DESCRIPTION("sysfs interface to EFI Variables"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(EFIVARS_VERSION); + +LIST_HEAD(efivar_sysfs_list); +EXPORT_SYMBOL_GPL(efivar_sysfs_list); + +static struct kset *efivars_kset; + +static struct bin_attribute *efivars_new_var; +static struct bin_attribute *efivars_del_var; + +struct efivar_attribute { + struct attribute attr; + ssize_t (*show) (struct efivar_entry *entry, char *buf); + ssize_t (*store)(struct efivar_entry *entry, const char *buf, size_t count); +}; + +#define EFIVAR_ATTR(_name, _mode, _show, _store) \ +struct efivar_attribute efivar_attr_##_name = { \ + .attr = {.name = __stringify(_name), .mode = _mode}, \ + .show = _show, \ + .store = _store, \ +}; + +#define to_efivar_attr(_attr) container_of(_attr, struct efivar_attribute, attr) +#define to_efivar_entry(obj) container_of(obj, struct efivar_entry, kobj) + +/* + * Prototype for sysfs creation function + */ +static int +efivar_create_sysfs_entry(struct efivar_entry *new_var); + +static ssize_t +efivar_guid_read(struct efivar_entry *entry, char *buf) +{ + struct efi_variable *var = &entry->var; + char *str = buf; + + if (!entry || !buf) + return 0; + + efi_guid_unparse(&var->VendorGuid, str); + str += strlen(str); + str += sprintf(str, "\n"); + + return str - buf; +} + +static ssize_t +efivar_attr_read(struct efivar_entry *entry, char *buf) +{ + struct efi_variable *var = &entry->var; + char *str = buf; + + if (!entry || !buf) + return -EINVAL; + + var->DataSize = 1024; + if (efivar_entry_get(entry, &var->Attributes, &var->DataSize, var->Data)) + return -EIO; + + if (var->Attributes & EFI_VARIABLE_NON_VOLATILE) + str += sprintf(str, "EFI_VARIABLE_NON_VOLATILE\n"); + if (var->Attributes & EFI_VARIABLE_BOOTSERVICE_ACCESS) + str += sprintf(str, "EFI_VARIABLE_BOOTSERVICE_ACCESS\n"); + if (var->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) + str += sprintf(str, "EFI_VARIABLE_RUNTIME_ACCESS\n"); + if (var->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) + str += sprintf(str, "EFI_VARIABLE_HARDWARE_ERROR_RECORD\n"); + if (var->Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) + str += sprintf(str, + "EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS\n"); + if (var->Attributes & + EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) + str += sprintf(str, + "EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS\n"); + if (var->Attributes & EFI_VARIABLE_APPEND_WRITE) + str += sprintf(str, "EFI_VARIABLE_APPEND_WRITE\n"); + return str - buf; +} + +static ssize_t +efivar_size_read(struct efivar_entry *entry, char *buf) +{ + struct efi_variable *var = &entry->var; + char *str = buf; + + if (!entry || !buf) + return -EINVAL; + + var->DataSize = 1024; + if (efivar_entry_get(entry, &var->Attributes, &var->DataSize, var->Data)) + return -EIO; + + str += sprintf(str, "0x%lx\n", var->DataSize); + return str - buf; +} + +static ssize_t +efivar_data_read(struct efivar_entry *entry, char *buf) +{ + struct efi_variable *var = &entry->var; + + if (!entry || !buf) + return -EINVAL; + + var->DataSize = 1024; + if (efivar_entry_get(entry, &var->Attributes, &var->DataSize, var->Data)) + return -EIO; + + memcpy(buf, var->Data, var->DataSize); + return var->DataSize; +} +/* + * We allow each variable to be edited via rewriting the + * entire efi variable structure. + */ +static ssize_t +efivar_store_raw(struct efivar_entry *entry, const char *buf, size_t count) +{ + struct efi_variable *new_var, *var = &entry->var; + int err; + + if (count != sizeof(struct efi_variable)) + return -EINVAL; + + new_var = (struct efi_variable *)buf; + /* + * If only updating the variable data, then the name + * and guid should remain the same + */ + if (memcmp(new_var->VariableName, var->VariableName, sizeof(var->VariableName)) || + efi_guidcmp(new_var->VendorGuid, var->VendorGuid)) { + printk(KERN_ERR "efivars: Cannot edit the wrong variable!\n"); + return -EINVAL; + } + + if ((new_var->DataSize <= 0) || (new_var->Attributes == 0)){ + printk(KERN_ERR "efivars: DataSize & Attributes must be valid!\n"); + return -EINVAL; + } + + if ((new_var->Attributes & ~EFI_VARIABLE_MASK) != 0 || + efivar_validate(new_var, new_var->Data, new_var->DataSize) == false) { + printk(KERN_ERR "efivars: Malformed variable content\n"); + return -EINVAL; + } + + memcpy(&entry->var, new_var, count); + + err = efivar_entry_set(entry, new_var->Attributes, + new_var->DataSize, new_var->Data, false); + if (err) { + printk(KERN_WARNING "efivars: set_variable() failed: status=%d\n", err); + return -EIO; + } + + return count; +} + +static ssize_t +efivar_show_raw(struct efivar_entry *entry, char *buf) +{ + struct efi_variable *var = &entry->var; + + if (!entry || !buf) + return 0; + + var->DataSize = 1024; + if (efivar_entry_get(entry, &entry->var.Attributes, + &entry->var.DataSize, entry->var.Data)) + return -EIO; + + memcpy(buf, var, sizeof(*var)); + + return sizeof(*var); +} + +/* + * Generic read/write functions that call the specific functions of + * the attributes... + */ +static ssize_t efivar_attr_show(struct kobject *kobj, struct attribute *attr, + char *buf) +{ + struct efivar_entry *var = to_efivar_entry(kobj); + struct efivar_attribute *efivar_attr = to_efivar_attr(attr); + ssize_t ret = -EIO; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + if (efivar_attr->show) { + ret = efivar_attr->show(var, buf); + } + return ret; +} + +static ssize_t efivar_attr_store(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t count) +{ + struct efivar_entry *var = to_efivar_entry(kobj); + struct efivar_attribute *efivar_attr = to_efivar_attr(attr); + ssize_t ret = -EIO; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + if (efivar_attr->store) + ret = efivar_attr->store(var, buf, count); + + return ret; +} + +static const struct sysfs_ops efivar_attr_ops = { + .show = efivar_attr_show, + .store = efivar_attr_store, +}; + +static void efivar_release(struct kobject *kobj) +{ + struct efivar_entry *var = container_of(kobj, struct efivar_entry, kobj); + kfree(var); +} + +static EFIVAR_ATTR(guid, 0400, efivar_guid_read, NULL); +static EFIVAR_ATTR(attributes, 0400, efivar_attr_read, NULL); +static EFIVAR_ATTR(size, 0400, efivar_size_read, NULL); +static EFIVAR_ATTR(data, 0400, efivar_data_read, NULL); +static EFIVAR_ATTR(raw_var, 0600, efivar_show_raw, efivar_store_raw); + +static struct attribute *def_attrs[] = { + &efivar_attr_guid.attr, + &efivar_attr_size.attr, + &efivar_attr_attributes.attr, + &efivar_attr_data.attr, + &efivar_attr_raw_var.attr, + NULL, +}; + +static struct kobj_type efivar_ktype = { + .release = efivar_release, + .sysfs_ops = &efivar_attr_ops, + .default_attrs = def_attrs, +}; + +static ssize_t efivar_create(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t pos, size_t count) +{ + struct efi_variable *new_var = (struct efi_variable *)buf; + struct efivar_entry *new_entry; + int err; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + if ((new_var->Attributes & ~EFI_VARIABLE_MASK) != 0 || + efivar_validate(new_var, new_var->Data, new_var->DataSize) == false) { + printk(KERN_ERR "efivars: Malformed variable content\n"); + return -EINVAL; + } + + new_entry = kzalloc(sizeof(*new_entry), GFP_KERNEL); + if (!new_entry) + return -ENOMEM; + + memcpy(&new_entry->var, new_var, sizeof(*new_var)); + + err = efivar_entry_set(new_entry, new_var->Attributes, new_var->DataSize, + new_var->Data, &efivar_sysfs_list); + if (err) { + if (err == -EEXIST) + err = -EINVAL; + goto out; + } + + if (efivar_create_sysfs_entry(new_entry)) { + printk(KERN_WARNING "efivars: failed to create sysfs entry.\n"); + kfree(new_entry); + } + return count; + +out: + kfree(new_entry); + return err; +} + +static ssize_t efivar_delete(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t pos, size_t count) +{ + struct efi_variable *del_var = (struct efi_variable *)buf; + struct efivar_entry *entry; + int err = 0; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + efivar_entry_iter_begin(); + entry = efivar_entry_find(del_var->VariableName, del_var->VendorGuid, + &efivar_sysfs_list, true); + if (!entry) + err = -EINVAL; + else if (__efivar_entry_delete(entry)) + err = -EIO; + + efivar_entry_iter_end(); + + if (err) + return err; + + efivar_unregister(entry); + + /* It's dead Jim.... */ + return count; +} + +/** + * efivar_create_sysfs_entry - create a new entry in sysfs + * @new_var: efivar entry to create + * + * Returns 1 on failure, 0 on success + */ +static int +efivar_create_sysfs_entry(struct efivar_entry *new_var) +{ + int i, short_name_size; + char *short_name; + unsigned long variable_name_size; + efi_char16_t *variable_name; + + variable_name = new_var->var.VariableName; + variable_name_size = ucs2_strlen(variable_name) * sizeof(efi_char16_t); + + /* + * Length of the variable bytes in ASCII, plus the '-' separator, + * plus the GUID, plus trailing NUL + */ + short_name_size = variable_name_size / sizeof(efi_char16_t) + + 1 + EFI_VARIABLE_GUID_LEN + 1; + + short_name = kzalloc(short_name_size, GFP_KERNEL); + + if (!short_name) + return 1; + + /* Convert Unicode to normal chars (assume top bits are 0), + ala UTF-8 */ + for (i=0; i < (int)(variable_name_size / sizeof(efi_char16_t)); i++) { + short_name[i] = variable_name[i] & 0xFF; + } + /* This is ugly, but necessary to separate one vendor's + private variables from another's. */ + + *(short_name + strlen(short_name)) = '-'; + efi_guid_unparse(&new_var->var.VendorGuid, + short_name + strlen(short_name)); + + new_var->kobj.kset = efivars_kset; + + i = kobject_init_and_add(&new_var->kobj, &efivar_ktype, + NULL, "%s", short_name); + kfree(short_name); + if (i) + return 1; + + kobject_uevent(&new_var->kobj, KOBJ_ADD); + efivar_entry_add(new_var, &efivar_sysfs_list); + + return 0; +} + +static int +create_efivars_bin_attributes(void) +{ + struct bin_attribute *attr; + int error; + + /* new_var */ + attr = kzalloc(sizeof(*attr), GFP_KERNEL); + if (!attr) + return -ENOMEM; + + attr->attr.name = "new_var"; + attr->attr.mode = 0200; + attr->write = efivar_create; + efivars_new_var = attr; + + /* del_var */ + attr = kzalloc(sizeof(*attr), GFP_KERNEL); + if (!attr) { + error = -ENOMEM; + goto out_free; + } + attr->attr.name = "del_var"; + attr->attr.mode = 0200; + attr->write = efivar_delete; + efivars_del_var = attr; + + sysfs_bin_attr_init(efivars_new_var); + sysfs_bin_attr_init(efivars_del_var); + + /* Register */ + error = sysfs_create_bin_file(&efivars_kset->kobj, efivars_new_var); + if (error) { + printk(KERN_ERR "efivars: unable to create new_var sysfs file" + " due to error %d\n", error); + goto out_free; + } + + error = sysfs_create_bin_file(&efivars_kset->kobj, efivars_del_var); + if (error) { + printk(KERN_ERR "efivars: unable to create del_var sysfs file" + " due to error %d\n", error); + sysfs_remove_bin_file(&efivars_kset->kobj, efivars_new_var); + goto out_free; + } + + return 0; +out_free: + kfree(efivars_del_var); + efivars_del_var = NULL; + kfree(efivars_new_var); + efivars_new_var = NULL; + return error; +} + +static int efivar_update_sysfs_entry(efi_char16_t *name, efi_guid_t vendor, + unsigned long name_size, void *data) +{ + struct efivar_entry *entry = data; + + if (efivar_entry_find(name, vendor, &efivar_sysfs_list, false)) + return 0; + + memcpy(entry->var.VariableName, name, name_size); + memcpy(&(entry->var.VendorGuid), &vendor, sizeof(efi_guid_t)); + + return 1; +} + +static void efivar_update_sysfs_entries(struct work_struct *work) +{ + struct efivar_entry *entry; + int err; + + entry = kzalloc(sizeof(*entry), GFP_KERNEL); + if (!entry) + return; + + /* Add new sysfs entries */ + while (1) { + memset(entry, 0, sizeof(*entry)); + + err = efivar_init(efivar_update_sysfs_entry, entry, + true, false, &efivar_sysfs_list); + if (!err) + break; + + efivar_create_sysfs_entry(entry); + } + + kfree(entry); +} + +static int efivars_sysfs_callback(efi_char16_t *name, efi_guid_t vendor, + unsigned long name_size, void *data) +{ + struct efivar_entry *entry; + + entry = kzalloc(sizeof(*entry), GFP_KERNEL); + if (!entry) + return -ENOMEM; + + memcpy(entry->var.VariableName, name, name_size); + memcpy(&(entry->var.VendorGuid), &vendor, sizeof(efi_guid_t)); + + efivar_create_sysfs_entry(entry); + + return 0; +} + +static int efivar_sysfs_destroy(struct efivar_entry *entry, void *data) +{ + efivar_entry_remove(entry); + efivar_unregister(entry); + return 0; +} + +void efivars_sysfs_exit(void) +{ + /* Remove all entries and destroy */ + __efivar_entry_iter(efivar_sysfs_destroy, &efivar_sysfs_list, NULL, NULL); + + if (efivars_new_var) + sysfs_remove_bin_file(&efivars_kset->kobj, efivars_new_var); + if (efivars_del_var) + sysfs_remove_bin_file(&efivars_kset->kobj, efivars_del_var); + kfree(efivars_new_var); + kfree(efivars_del_var); + kset_unregister(efivars_kset); +} + +int efivars_sysfs_init(void) +{ + struct kobject *parent_kobj = efivars_kobject(); + int error = 0; + + /* No efivars has been registered yet */ + if (!parent_kobj) + return 0; + + printk(KERN_INFO "EFI Variables Facility v%s %s\n", EFIVARS_VERSION, + EFIVARS_DATE); + + efivars_kset = kset_create_and_add("vars", NULL, parent_kobj); + if (!efivars_kset) { + printk(KERN_ERR "efivars: Subsystem registration failed.\n"); + return -ENOMEM; + } + + efivar_init(efivars_sysfs_callback, NULL, false, + true, &efivar_sysfs_list); + + error = create_efivars_bin_attributes(); + if (error) { + efivars_sysfs_exit(); + return error; + } + + INIT_WORK(&efivar_work, efivar_update_sysfs_entries); + + return 0; +} +EXPORT_SYMBOL_GPL(efivars_sysfs_init); + +module_init(efivars_sysfs_init); +module_exit(efivars_sysfs_exit); diff --cc drivers/media/pci/cx25821/cx25821-audio-upstream.c index b9be535e32b,d6dfb5765d0..68dbc2dbc98 --- a/drivers/media/pci/cx25821/cx25821-audio-upstream.c +++ b/drivers/media/pci/cx25821/cx25821-audio-upstream.c @@@ -257,19 -257,16 +257,16 @@@ void cx25821_free_mem_upstream_audio(st } static int cx25821_get_audio_data(struct cx25821_dev *dev, - struct sram_channel *sram_ch) + const struct sram_channel *sram_ch) { - struct file *myfile; + struct file *file; int frame_index_temp = dev->_audioframe_index; int i = 0; - int line_size = AUDIO_LINE_SIZE; int frame_size = AUDIO_DATA_BUF_SZ; int frame_offset = frame_size * frame_index_temp; - ssize_t vfs_read_retval = 0; - char mybuf[line_size]; + char mybuf[AUDIO_LINE_SIZE]; loff_t file_offset = dev->_audioframe_count * frame_size; - loff_t pos; - mm_segment_t old_fs; + char *p = NULL; if (dev->_audiofile_status == END_OF_FILE) return 0; @@@ -352,83 -319,43 +319,43 @@@ static void cx25821_audioups_handler(st } static int cx25821_openfile_audio(struct cx25821_dev *dev, - struct sram_channel *sram_ch) + const struct sram_channel *sram_ch) { - struct file *myfile; - int i = 0, j = 0; - int line_size = AUDIO_LINE_SIZE; - ssize_t vfs_read_retval = 0; - char mybuf[line_size]; - loff_t pos; - loff_t offset = (unsigned long)0; - mm_segment_t old_fs; - - myfile = filp_open(dev->_audiofilename, O_RDONLY | O_LARGEFILE, 0); - - if (IS_ERR(myfile)) { - const int open_errno = -PTR_ERR(myfile); - pr_err("%s(): ERROR opening file(%s) with errno = %d!\n", - __func__, dev->_audiofilename, open_errno); - return PTR_ERR(myfile); - } else { - if (!(myfile->f_op)) { - pr_err("%s(): File has no file operations registered!\n", - __func__); - filp_close(myfile, NULL); - return -EIO; - } + char *p = (void *)dev->_audiodata_buf_virt_addr; + struct file *file; + loff_t offset; + int i, j; + + file = filp_open(dev->_audiofilename, O_RDONLY | O_LARGEFILE, 0); + if (IS_ERR(file)) { + pr_err("%s(): ERROR opening file(%s) with errno = %ld!\n", + __func__, dev->_audiofilename, PTR_ERR(file)); + return PTR_ERR(file); + } - if (!myfile->f_op->read) { - pr_err("%s(): File has no READ operations registered!\n", - __func__); - filp_close(myfile, NULL); - return -EIO; - } + for (j = 0, offset = 0; j < NUM_AUDIO_FRAMES; j++) { + for (i = 0; i < dev->_audio_lines_count; i++) { + char buf[AUDIO_LINE_SIZE]; + int n = kernel_read(file, offset, buf, + AUDIO_LINE_SIZE); - pos = myfile->f_pos; - old_fs = get_fs(); - set_fs(KERNEL_DS); - - for (j = 0; j < NUM_AUDIO_FRAMES; j++) { - for (i = 0; i < dev->_audio_lines_count; i++) { - pos = offset; - - vfs_read_retval = vfs_read(myfile, mybuf, - line_size, &pos); - - if (vfs_read_retval > 0 && - vfs_read_retval == line_size && - dev->_audiodata_buf_virt_addr != NULL) { - memcpy((void *)(dev-> - _audiodata_buf_virt_addr - + offset / 4), mybuf, - vfs_read_retval); - } - - offset += vfs_read_retval; - - if (vfs_read_retval < line_size) { - pr_info("Done: exit %s() since no more bytes to read from Audio file\n", - __func__); - break; - } + if (n < AUDIO_LINE_SIZE) { + pr_info("Done: exit %s() since no more bytes to read from Audio file\n", + __func__); + dev->_audiofile_status = END_OF_FILE; + fput(file); + return 0; } - if (i > 0) - dev->_audioframe_count++; + if (p) + memcpy(p + offset, buf, n); - if (vfs_read_retval < line_size) - break; + offset += n; } - - dev->_audiofile_status = (vfs_read_retval == line_size) ? - IN_PROGRESS : END_OF_FILE; - - set_fs(old_fs); - myfile->f_pos = 0; - filp_close(myfile, NULL); + dev->_audioframe_count++; } - + dev->_audiofile_status = IN_PROGRESS; + fput(file); return 0; } diff --cc drivers/staging/rts5139/rts51x_scsi.h index 3a5213611d2,c2446d02d32..1a0d7056618 --- a/drivers/staging/rts5139/rts51x_scsi.h +++ b/drivers/staging/rts5139/rts51x_scsi.h @@@ -147,10 -147,9 +147,8 @@@ struct scsi_cmnd int slave_alloc(struct scsi_device *sdev); int slave_configure(struct scsi_device *sdev); - int proc_info(struct Scsi_Host *host, char *buffer, - char **start, off_t offset, int length, int inout); int queuecommand(struct Scsi_Host *, struct scsi_cmnd *); int command_abort(struct scsi_cmnd *srb); -int device_reset(struct scsi_cmnd *srb); int bus_reset(struct scsi_cmnd *srb); #endif /* __RTS51X_SCSI_H */ diff --cc drivers/staging/silicom/bpctl_mod.c index 00000000000,3117559c041..b7e570ccb75 mode 000000,100644..100644 --- a/drivers/staging/silicom/bpctl_mod.c +++ b/drivers/staging/silicom/bpctl_mod.c @@@ -1,0 -1,7909 +1,7907 @@@ + /******************************************************************************/ + /* */ + /* Bypass Control utility, Copyright (c) 2005-20011 Silicom */ + /* */ + /* 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, located in the file LICENSE. */ + /* Copyright(c) 2007 - 2009 Intel Corporation. All rights reserved. */ + /* */ + /* */ + /******************************************************************************/ + + #include /* We're doing kernel work */ + #include /* Specifically, a module */ + #include + #include + #include + #include + #include + #include + #include + + #include /* for get_user and put_user */ + #include + #include + #include + + #include "bp_ioctl.h" + #include "bp_mod.h" + #include "bypass.h" + #include "libbp_sd.h" + + #define SUCCESS 0 + #define BP_MOD_VER "9.0.4" + #define BP_MOD_DESCR "Silicom Bypass-SD Control driver" + #define BP_SYNC_FLAG 1 + + static int major_num = 0; + + MODULE_AUTHOR("Anna Lukin, annal@silicom.co.il"); + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION(BP_MOD_DESCR); + MODULE_VERSION(BP_MOD_VER); + spinlock_t bpvm_lock; + + #define lock_bpctl() \ + if (down_interruptible(&bpctl_sema)) { \ + return -ERESTARTSYS; \ + } \ + + #define unlock_bpctl() \ + up(&bpctl_sema); + + /* Media Types */ + typedef enum { + bp_copper = 0, + bp_fiber, + bp_cx4, + bp_none, + } bp_media_type; + + struct bypass_pfs_sd { + char dir_name[32]; + struct proc_dir_entry *bypass_entry; + }; + + typedef struct _bpctl_dev { + char *name; + char *desc; + struct pci_dev *pdev; /* PCI device */ + struct net_device *ndev; /* net device */ + unsigned long mem_map; + uint8_t bus; + uint8_t slot; + uint8_t func; + u_int32_t device; + u_int32_t vendor; + u_int32_t subvendor; + u_int32_t subdevice; + int ifindex; + uint32_t bp_caps; + uint32_t bp_caps_ex; + uint8_t bp_fw_ver; + int bp_ext_ver; + int wdt_status; + unsigned long bypass_wdt_on_time; + uint32_t bypass_timer_interval; + struct timer_list bp_timer; + uint32_t reset_time; + uint8_t bp_status_un; + atomic_t wdt_busy; + bp_media_type media_type; + int bp_tpl_flag; + struct timer_list bp_tpl_timer; + spinlock_t bypass_wr_lock; + int bp_10g; + int bp_10gb; + int bp_fiber5; + int bp_10g9; + int bp_i80; + int bp_540; + int (*hard_start_xmit_save) (struct sk_buff *skb, + struct net_device *dev); + const struct net_device_ops *old_ops; + struct net_device_ops new_ops; + int bp_self_test_flag; + char *bp_tx_data; + struct bypass_pfs_sd bypass_pfs_set; + + } bpctl_dev_t; + + static bpctl_dev_t *bpctl_dev_arr; + + static struct semaphore bpctl_sema; + static int device_num = 0; + + static int get_dev_idx(int ifindex); + static bpctl_dev_t *get_master_port_fn(bpctl_dev_t *pbpctl_dev); + static int disc_status(bpctl_dev_t *pbpctl_dev); + static int bypass_status(bpctl_dev_t *pbpctl_dev); + static int wdt_timer(bpctl_dev_t *pbpctl_dev, int *time_left); + static bpctl_dev_t *get_status_port_fn(bpctl_dev_t *pbpctl_dev); + static void if_scan_init(void); + + int bypass_proc_create_dev_sd(bpctl_dev_t *pbp_device_block); + int bypass_proc_remove_dev_sd(bpctl_dev_t *pbp_device_block); + int bp_proc_create(void); + + int is_bypass_fn(bpctl_dev_t *pbpctl_dev); + int get_dev_idx_bsf(int bus, int slot, int func); + + static unsigned long str_to_hex(char *p); + static int bp_device_event(struct notifier_block *unused, + unsigned long event, void *ptr) + { + struct net_device *dev = ptr; + static bpctl_dev_t *pbpctl_dev = NULL, *pbpctl_dev_m = NULL; + int dev_num = 0, ret = 0, ret_d = 0, time_left = 0; + /* printk("BP_PROC_SUPPORT event =%d %s %d\n", event,dev->name, dev->ifindex ); */ + /* return NOTIFY_DONE; */ + if (!dev) + return NOTIFY_DONE; + if (event == NETDEV_REGISTER) { + { + struct ethtool_drvinfo drvinfo; + char cbuf[32]; + char *buf = NULL; + char res[10]; + int i = 0, ifindex, idx_dev = 0; + int bus = 0, slot = 0, func = 0; + ifindex = dev->ifindex; + + memset(res, 0, 10); + memset(&drvinfo, 0, sizeof(struct ethtool_drvinfo)); + + if (dev->ethtool_ops && dev->ethtool_ops->get_drvinfo) { + memset(&drvinfo, 0, sizeof(drvinfo)); + dev->ethtool_ops->get_drvinfo(dev, &drvinfo); + } else + return NOTIFY_DONE; + if (!drvinfo.bus_info) + return NOTIFY_DONE; + if (!strcmp(drvinfo.bus_info, "N/A")) + return NOTIFY_DONE; + memcpy(&cbuf, drvinfo.bus_info, 32); + buf = &cbuf[0]; + + while (*buf++ != ':') ; + for (i = 0; i < 10; i++, buf++) { + if (*buf == ':') + break; + res[i] = *buf; + + } + buf++; + bus = str_to_hex(res); + memset(res, 0, 10); + + for (i = 0; i < 10; i++, buf++) { + if (*buf == '.') + break; + res[i] = *buf; + + } + buf++; + slot = str_to_hex(res); + func = str_to_hex(buf); + idx_dev = get_dev_idx_bsf(bus, slot, func); + + if (idx_dev != -1) { + + bpctl_dev_arr[idx_dev].ifindex = ifindex; + bpctl_dev_arr[idx_dev].ndev = dev; + + bypass_proc_remove_dev_sd(&bpctl_dev_arr + [idx_dev]); + bypass_proc_create_dev_sd(&bpctl_dev_arr + [idx_dev]); + + } + + } + return NOTIFY_DONE; + + } + if (event == NETDEV_UNREGISTER) { + int idx_dev = 0; + for (idx_dev = 0; + ((bpctl_dev_arr[idx_dev].pdev != NULL) + && (idx_dev < device_num)); idx_dev++) { + if (bpctl_dev_arr[idx_dev].ndev == dev) { + bypass_proc_remove_dev_sd(&bpctl_dev_arr + [idx_dev]); + bpctl_dev_arr[idx_dev].ndev = NULL; + + return NOTIFY_DONE; + + } + + } + return NOTIFY_DONE; + } + if (event == NETDEV_CHANGENAME) { + int idx_dev = 0; + for (idx_dev = 0; + ((bpctl_dev_arr[idx_dev].pdev != NULL) + && (idx_dev < device_num)); idx_dev++) { + if (bpctl_dev_arr[idx_dev].ndev == dev) { + bypass_proc_remove_dev_sd(&bpctl_dev_arr + [idx_dev]); + bypass_proc_create_dev_sd(&bpctl_dev_arr + [idx_dev]); + + return NOTIFY_DONE; + + } + + } + return NOTIFY_DONE; + + } + + switch (event) { + + case NETDEV_CHANGE:{ + if (netif_carrier_ok(dev)) + return NOTIFY_DONE; + + if (((dev_num = get_dev_idx(dev->ifindex)) == -1) || + (!(pbpctl_dev = &bpctl_dev_arr[dev_num]))) + return NOTIFY_DONE; + + if ((is_bypass_fn(pbpctl_dev)) == 1) + pbpctl_dev_m = pbpctl_dev; + else + pbpctl_dev_m = get_master_port_fn(pbpctl_dev); + if (!pbpctl_dev_m) + return NOTIFY_DONE; + ret = bypass_status(pbpctl_dev_m); + if (ret == 1) + printk("bpmod: %s is in the Bypass mode now", + dev->name); + ret_d = disc_status(pbpctl_dev_m); + if (ret_d == 1) + printk + ("bpmod: %s is in the Disconnect mode now", + dev->name); + if (ret || ret_d) { + wdt_timer(pbpctl_dev_m, &time_left); + if (time_left == -1) + printk("; WDT has expired"); + printk(".\n"); + + } + return NOTIFY_DONE; + + } + + default: + return NOTIFY_DONE; + + } + return NOTIFY_DONE; + + } + + static struct notifier_block bp_notifier_block = { + .notifier_call = bp_device_event, + }; + + int is_bypass_fn(bpctl_dev_t *pbpctl_dev); + int wdt_time_left(bpctl_dev_t *pbpctl_dev); + + static void write_pulse(bpctl_dev_t *pbpctl_dev, + unsigned int ctrl_ext, + unsigned char value, unsigned char len) + { + unsigned char ctrl_val = 0; + unsigned int i = len; + unsigned int ctrl = 0; + bpctl_dev_t *pbpctl_dev_c = NULL; + + if (pbpctl_dev->bp_i80) + ctrl = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT); + if (pbpctl_dev->bp_540) + ctrl = BP10G_READ_REG(pbpctl_dev, ESDP); + + if (pbpctl_dev->bp_10g9) { + if (!(pbpctl_dev_c = get_status_port_fn(pbpctl_dev))) + return; + ctrl = BP10G_READ_REG(pbpctl_dev_c, ESDP); + } + + while (i--) { + ctrl_val = (value >> i) & 0x1; + if (ctrl_val) { + if (pbpctl_dev->bp_10g9) { + + /* To start management : MCLK 1, MDIO 1, output */ + /* DATA 1 CLK 1 */ + /*BP10G_WRITE_REG(pbpctl_dev, I2CCTL, (ctrl_ext|BP10G_MCLK_DATA_OUT9|BP10G_MDIO_DATA_OUT9)); */ + BP10G_WRITE_REG(pbpctl_dev, I2CCTL, + ctrl_ext | + BP10G_MDIO_DATA_OUT9); + BP10G_WRITE_REG(pbpctl_dev_c, ESDP, + (ctrl | BP10G_MCLK_DATA_OUT9 | + BP10G_MCLK_DIR_OUT9)); + + } else if (pbpctl_dev->bp_fiber5) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, (ctrl_ext | + BPCTLI_CTRL_EXT_MCLK_DIR5 + | + BPCTLI_CTRL_EXT_MDIO_DIR5 + | + BPCTLI_CTRL_EXT_MDIO_DATA5 + | + BPCTLI_CTRL_EXT_MCLK_DATA5)); + + } else if (pbpctl_dev->bp_i80) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, (ctrl_ext | + BPCTLI_CTRL_EXT_MDIO_DIR80 + | + BPCTLI_CTRL_EXT_MDIO_DATA80)); + + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, (ctrl | + BPCTLI_CTRL_EXT_MCLK_DIR80 + | + BPCTLI_CTRL_EXT_MCLK_DATA80)); + + } else if (pbpctl_dev->bp_540) { + BP10G_WRITE_REG(pbpctl_dev, ESDP, (ctrl | + BP540_MDIO_DIR + | + BP540_MDIO_DATA + | + BP540_MCLK_DIR + | + BP540_MCLK_DATA)); + + } else if (pbpctl_dev->bp_10gb) { + BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO, + (ctrl_ext | BP10GB_MDIO_SET | + BP10GB_MCLK_SET) & + ~(BP10GB_MCLK_DIR | + BP10GB_MDIO_DIR | + BP10GB_MDIO_CLR | + BP10GB_MCLK_CLR)); + + } else if (!pbpctl_dev->bp_10g) + /* To start management : MCLK 1, MDIO 1, output */ + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, + (ctrl_ext | + BPCTLI_CTRL_EXT_MCLK_DIR | + BPCTLI_CTRL_EXT_MDIO_DIR | + BPCTLI_CTRL_EXT_MDIO_DATA | + BPCTLI_CTRL_EXT_MCLK_DATA)); + else { + + /* To start management : MCLK 1, MDIO 1, output*/ + BP10G_WRITE_REG(pbpctl_dev, EODSDP, + (ctrl_ext | BP10G_MCLK_DATA_OUT + | BP10G_MDIO_DATA_OUT)); + + } + + usec_delay(PULSE_TIME); + if (pbpctl_dev->bp_10g9) { + + /*BP10G_WRITE_REG(pbpctl_dev, I2CCTL, ((ctrl_ext|BP10G_MDIO_DATA_OUT9)&~(BP10G_MCLK_DATA_OUT9))); */ + /* DATA 1 CLK 0 */ + BP10G_WRITE_REG(pbpctl_dev, I2CCTL, + ctrl_ext | + BP10G_MDIO_DATA_OUT9); + BP10G_WRITE_REG(pbpctl_dev_c, ESDP, + (ctrl | BP10G_MCLK_DIR_OUT9) & + ~BP10G_MCLK_DATA_OUT9); + + } else if (pbpctl_dev->bp_fiber5) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, + ((ctrl_ext | + BPCTLI_CTRL_EXT_MCLK_DIR5 | + BPCTLI_CTRL_EXT_MDIO_DIR5 | + BPCTLI_CTRL_EXT_MDIO_DATA5) + & + ~ + (BPCTLI_CTRL_EXT_MCLK_DATA5))); + + } else if (pbpctl_dev->bp_i80) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, (ctrl_ext | + BPCTLI_CTRL_EXT_MDIO_DIR80 + | + BPCTLI_CTRL_EXT_MDIO_DATA80)); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, + ((ctrl | + BPCTLI_CTRL_EXT_MCLK_DIR80) + & + ~ + (BPCTLI_CTRL_EXT_MCLK_DATA80))); + + } else if (pbpctl_dev->bp_540) { + BP10G_WRITE_REG(pbpctl_dev, ESDP, + (ctrl | BP540_MDIO_DIR | + BP540_MDIO_DATA | + BP540_MCLK_DIR) & + ~(BP540_MCLK_DATA)); + + } else if (pbpctl_dev->bp_10gb) { + + BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO, + (ctrl_ext | BP10GB_MDIO_SET | + BP10GB_MCLK_CLR) & + ~(BP10GB_MCLK_DIR | + BP10GB_MDIO_DIR | + BP10GB_MDIO_CLR | + BP10GB_MCLK_SET)); + + } else if (!pbpctl_dev->bp_10g) + + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, + ((ctrl_ext | + BPCTLI_CTRL_EXT_MCLK_DIR | + BPCTLI_CTRL_EXT_MDIO_DIR | + BPCTLI_CTRL_EXT_MDIO_DATA) + & + ~ + (BPCTLI_CTRL_EXT_MCLK_DATA))); + else { + + BP10G_WRITE_REG(pbpctl_dev, EODSDP, + ((ctrl_ext | + BP10G_MDIO_DATA_OUT) & + ~(BP10G_MCLK_DATA_OUT))); + } + + usec_delay(PULSE_TIME); + + } else { + if (pbpctl_dev->bp_10g9) { + /* DATA 0 CLK 1 */ + /*BP10G_WRITE_REG(pbpctl_dev, I2CCTL, ((ctrl_ext|BP10G_MCLK_DATA_OUT9)&~BP10G_MDIO_DATA_OUT9)); */ + BP10G_WRITE_REG(pbpctl_dev, I2CCTL, + (ctrl_ext & + ~BP10G_MDIO_DATA_OUT9)); + BP10G_WRITE_REG(pbpctl_dev_c, ESDP, + (ctrl | BP10G_MCLK_DATA_OUT9 | + BP10G_MCLK_DIR_OUT9)); + + } else if (pbpctl_dev->bp_fiber5) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, + ((ctrl_ext | + BPCTLI_CTRL_EXT_MCLK_DIR5 | + BPCTLI_CTRL_EXT_MDIO_DIR5 | + BPCTLI_CTRL_EXT_MCLK_DATA5) + & + ~ + (BPCTLI_CTRL_EXT_MDIO_DATA5))); + + } else if (pbpctl_dev->bp_i80) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, + ((ctrl_ext | + BPCTLI_CTRL_EXT_MDIO_DIR80) + & + ~ + (BPCTLI_CTRL_EXT_MDIO_DATA80))); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, + (ctrl | + BPCTLI_CTRL_EXT_MCLK_DIR80 | + BPCTLI_CTRL_EXT_MCLK_DATA80)); + + } else if (pbpctl_dev->bp_540) { + BP10G_WRITE_REG(pbpctl_dev, ESDP, + ((ctrl | BP540_MCLK_DIR | + BP540_MCLK_DATA | + BP540_MDIO_DIR) & + ~(BP540_MDIO_DATA))); + + } else if (pbpctl_dev->bp_10gb) { + BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO, + (ctrl_ext | BP10GB_MDIO_CLR | + BP10GB_MCLK_SET) & + ~(BP10GB_MCLK_DIR | + BP10GB_MDIO_DIR | + BP10GB_MDIO_SET | + BP10GB_MCLK_CLR)); + + } else if (!pbpctl_dev->bp_10g) + + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, + ((ctrl_ext | + BPCTLI_CTRL_EXT_MCLK_DIR | + BPCTLI_CTRL_EXT_MDIO_DIR | + BPCTLI_CTRL_EXT_MCLK_DATA) + & + ~ + (BPCTLI_CTRL_EXT_MDIO_DATA))); + else { + + BP10G_WRITE_REG(pbpctl_dev, EODSDP, + ((ctrl_ext | + BP10G_MCLK_DATA_OUT) & + ~BP10G_MDIO_DATA_OUT)); + + } + usec_delay(PULSE_TIME); + if (pbpctl_dev->bp_10g9) { + /* DATA 0 CLK 0 */ + /*BP10G_WRITE_REG(pbpctl_dev, I2CCTL, (ctrl_ext&~(BP10G_MCLK_DATA_OUT9|BP10G_MDIO_DATA_OUT9))); */ + BP10G_WRITE_REG(pbpctl_dev, I2CCTL, + (ctrl_ext & + ~BP10G_MDIO_DATA_OUT9)); + BP10G_WRITE_REG(pbpctl_dev_c, ESDP, + ((ctrl | BP10G_MCLK_DIR_OUT9) & + ~(BP10G_MCLK_DATA_OUT9))); + + } else if (pbpctl_dev->bp_fiber5) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, + ((ctrl_ext | + BPCTLI_CTRL_EXT_MCLK_DIR5 | + BPCTLI_CTRL_EXT_MDIO_DIR5) + & + ~(BPCTLI_CTRL_EXT_MCLK_DATA5 + | + BPCTLI_CTRL_EXT_MDIO_DATA5))); + + } else if (pbpctl_dev->bp_i80) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, + ((ctrl_ext | + BPCTLI_CTRL_EXT_MDIO_DIR80) + & + ~BPCTLI_CTRL_EXT_MDIO_DATA80)); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, + ((ctrl | + BPCTLI_CTRL_EXT_MCLK_DIR80) + & + ~ + (BPCTLI_CTRL_EXT_MCLK_DATA80))); + + } else if (pbpctl_dev->bp_540) { + BP10G_WRITE_REG(pbpctl_dev, ESDP, + ((ctrl | BP540_MCLK_DIR | + BP540_MDIO_DIR) & + ~(BP540_MDIO_DATA | + BP540_MCLK_DATA))); + } else if (pbpctl_dev->bp_10gb) { + + BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO, + (ctrl_ext | BP10GB_MDIO_CLR | + BP10GB_MCLK_CLR) & + ~(BP10GB_MCLK_DIR | + BP10GB_MDIO_DIR | + BP10GB_MDIO_SET | + BP10GB_MCLK_SET)); + + } else if (!pbpctl_dev->bp_10g) + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, + ((ctrl_ext | + BPCTLI_CTRL_EXT_MCLK_DIR | + BPCTLI_CTRL_EXT_MDIO_DIR) & + ~(BPCTLI_CTRL_EXT_MCLK_DATA + | + BPCTLI_CTRL_EXT_MDIO_DATA))); + else { + + BP10G_WRITE_REG(pbpctl_dev, EODSDP, + (ctrl_ext & + ~(BP10G_MCLK_DATA_OUT | + BP10G_MDIO_DATA_OUT))); + } + + usec_delay(PULSE_TIME); + } + + } + } + + static int read_pulse(bpctl_dev_t *pbpctl_dev, unsigned int ctrl_ext, + unsigned char len) + { + unsigned char ctrl_val = 0; + unsigned int i = len; + unsigned int ctrl = 0; + bpctl_dev_t *pbpctl_dev_c = NULL; + + if (pbpctl_dev->bp_i80) + ctrl = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT); + if (pbpctl_dev->bp_540) + ctrl = BP10G_READ_REG(pbpctl_dev, ESDP); + if (pbpctl_dev->bp_10g9) { + if (!(pbpctl_dev_c = get_status_port_fn(pbpctl_dev))) + return -1; + ctrl = BP10G_READ_REG(pbpctl_dev_c, ESDP); + } + + + while (i--) { + if (pbpctl_dev->bp_10g9) { + /*BP10G_WRITE_REG(pbpctl_dev, I2CCTL, ((ctrl_ext|BP10G_MDIO_DATA_OUT9)&~BP10G_MCLK_DATA_OUT9)); */ + /* DATA ? CLK 0 */ + BP10G_WRITE_REG(pbpctl_dev_c, ESDP, + ((ctrl | BP10G_MCLK_DIR_OUT9) & + ~(BP10G_MCLK_DATA_OUT9))); + + } else if (pbpctl_dev->bp_fiber5) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext | + BPCTLI_CTRL_EXT_MCLK_DIR5) + & + ~ + (BPCTLI_CTRL_EXT_MDIO_DIR5 + | + BPCTLI_CTRL_EXT_MCLK_DATA5))); + + } else if (pbpctl_dev->bp_i80) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, + (ctrl_ext & + ~BPCTLI_CTRL_EXT_MDIO_DIR80)); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, + ((ctrl | BPCTLI_CTRL_EXT_MCLK_DIR80) + & ~(BPCTLI_CTRL_EXT_MCLK_DATA80))); + + } else if (pbpctl_dev->bp_540) { + BP10G_WRITE_REG(pbpctl_dev, ESDP, + ((ctrl | BP540_MCLK_DIR) & + ~(BP540_MDIO_DIR | BP540_MCLK_DATA))); + + } else if (pbpctl_dev->bp_10gb) { + + BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO, + (ctrl_ext | BP10GB_MDIO_DIR | + BP10GB_MCLK_CLR) & ~(BP10GB_MCLK_DIR | + BP10GB_MDIO_CLR | + BP10GB_MDIO_SET | + BP10GB_MCLK_SET)); + + } else if (!pbpctl_dev->bp_10g) + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext | + BPCTLI_CTRL_EXT_MCLK_DIR) + & + ~ + (BPCTLI_CTRL_EXT_MDIO_DIR + | + BPCTLI_CTRL_EXT_MCLK_DATA))); + else { + + BP10G_WRITE_REG(pbpctl_dev, EODSDP, ((ctrl_ext | BP10G_MDIO_DATA_OUT) & ~BP10G_MCLK_DATA_OUT)); /* ? */ + /* printk("0x28=0x%x\n",BP10G_READ_REG(pbpctl_dev,EODSDP);); */ + + } + + usec_delay(PULSE_TIME); + if (pbpctl_dev->bp_10g9) { + /*BP10G_WRITE_REG(pbpctl_dev, I2CCTL, (ctrl_ext|BP10G_MCLK_DATA_OUT9|BP10G_MDIO_DATA_OUT9)); */ + /* DATA ? CLK 1 */ + BP10G_WRITE_REG(pbpctl_dev_c, ESDP, + (ctrl | BP10G_MCLK_DATA_OUT9 | + BP10G_MCLK_DIR_OUT9)); + + } else if (pbpctl_dev->bp_fiber5) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext | + BPCTLI_CTRL_EXT_MCLK_DIR5 + | + BPCTLI_CTRL_EXT_MCLK_DATA5) + & + ~ + (BPCTLI_CTRL_EXT_MDIO_DIR5))); + + } else if (pbpctl_dev->bp_i80) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, + (ctrl_ext & + ~(BPCTLI_CTRL_EXT_MDIO_DIR80))); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, + (ctrl | BPCTLI_CTRL_EXT_MCLK_DIR80 | + BPCTLI_CTRL_EXT_MCLK_DATA80)); + + } else if (pbpctl_dev->bp_540) { + BP10G_WRITE_REG(pbpctl_dev, ESDP, + ((ctrl | BP540_MCLK_DIR | + BP540_MCLK_DATA) & + ~(BP540_MDIO_DIR))); + + } else if (pbpctl_dev->bp_10gb) { + BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO, + (ctrl_ext | BP10GB_MDIO_DIR | + BP10GB_MCLK_SET) & ~(BP10GB_MCLK_DIR | + BP10GB_MDIO_CLR | + BP10GB_MDIO_SET | + BP10GB_MCLK_CLR)); + + } else if (!pbpctl_dev->bp_10g) + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext | + BPCTLI_CTRL_EXT_MCLK_DIR + | + BPCTLI_CTRL_EXT_MCLK_DATA) + & + ~ + (BPCTLI_CTRL_EXT_MDIO_DIR))); + else { + + BP10G_WRITE_REG(pbpctl_dev, EODSDP, + (ctrl_ext | BP10G_MCLK_DATA_OUT | + BP10G_MDIO_DATA_OUT)); + + } + if (pbpctl_dev->bp_10g9) { + ctrl_ext = BP10G_READ_REG(pbpctl_dev, I2CCTL); + + } else if ((pbpctl_dev->bp_fiber5) || (pbpctl_dev->bp_i80)) { + ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL); + } else if (pbpctl_dev->bp_540) { + ctrl_ext = BP10G_READ_REG(pbpctl_dev, ESDP); + } else if (pbpctl_dev->bp_10gb) + ctrl_ext = BP10GB_READ_REG(pbpctl_dev, MISC_REG_SPIO); + + else if (!pbpctl_dev->bp_10g) + ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT); + else + ctrl_ext = BP10G_READ_REG(pbpctl_dev, EODSDP); + + usec_delay(PULSE_TIME); + if (pbpctl_dev->bp_10g9) { + if (ctrl_ext & BP10G_MDIO_DATA_IN9) + ctrl_val |= 1 << i; + + } else if (pbpctl_dev->bp_fiber5) { + if (ctrl_ext & BPCTLI_CTRL_EXT_MDIO_DATA5) + ctrl_val |= 1 << i; + } else if (pbpctl_dev->bp_i80) { + if (ctrl_ext & BPCTLI_CTRL_EXT_MDIO_DATA80) + ctrl_val |= 1 << i; + } else if (pbpctl_dev->bp_540) { + if (ctrl_ext & BP540_MDIO_DATA) + ctrl_val |= 1 << i; + } else if (pbpctl_dev->bp_10gb) { + if (ctrl_ext & BP10GB_MDIO_DATA) + ctrl_val |= 1 << i; + + } else if (!pbpctl_dev->bp_10g) { + + if (ctrl_ext & BPCTLI_CTRL_EXT_MDIO_DATA) + ctrl_val |= 1 << i; + } else { + + if (ctrl_ext & BP10G_MDIO_DATA_IN) + ctrl_val |= 1 << i; + } + + } + + return ctrl_val; + } + + static void write_reg(bpctl_dev_t *pbpctl_dev, unsigned char value, + unsigned char addr) + { + uint32_t ctrl_ext = 0, ctrl = 0; + bpctl_dev_t *pbpctl_dev_c = NULL; + unsigned long flags; + if (pbpctl_dev->bp_10g9) { + if (!(pbpctl_dev_c = get_status_port_fn(pbpctl_dev))) + return; + } + if ((pbpctl_dev->wdt_status == WDT_STATUS_EN) && + (pbpctl_dev->bp_ext_ver < PXG4BPFI_VER)) + wdt_time_left(pbpctl_dev); + + #ifdef BP_SYNC_FLAG + spin_lock_irqsave(&pbpctl_dev->bypass_wr_lock, flags); + #else + atomic_set(&pbpctl_dev->wdt_busy, 1); + #endif + if (pbpctl_dev->bp_10g9) { + + ctrl_ext = BP10G_READ_REG(pbpctl_dev, I2CCTL); + ctrl = BP10G_READ_REG(pbpctl_dev_c, ESDP); + /* DATA 0 CLK 0 */ + /* BP10G_WRITE_REG(pbpctl_dev, I2CCTL, (ctrl_ext&~(BP10G_MCLK_DATA_OUT9|BP10G_MDIO_DATA_OUT9))); */ + BP10G_WRITE_REG(pbpctl_dev, I2CCTL, + (ctrl_ext & ~BP10G_MDIO_DATA_OUT9)); + BP10G_WRITE_REG(pbpctl_dev_c, ESDP, + ((ctrl | BP10G_MCLK_DIR_OUT9) & + ~(BP10G_MCLK_DATA_OUT9))); + + } else if (pbpctl_dev->bp_fiber5) { + ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext | + BPCTLI_CTRL_EXT_MCLK_DIR5 + | + BPCTLI_CTRL_EXT_MDIO_DIR5) + & + ~ + (BPCTLI_CTRL_EXT_MDIO_DATA5 + | + BPCTLI_CTRL_EXT_MCLK_DATA5))); + } else if (pbpctl_dev->bp_i80) { + ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL); + ctrl = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext | + BPCTLI_CTRL_EXT_MDIO_DIR80) + & + ~BPCTLI_CTRL_EXT_MDIO_DATA80)); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, + ((ctrl | BPCTLI_CTRL_EXT_MCLK_DIR80) & + ~BPCTLI_CTRL_EXT_MCLK_DATA80)); + + } else if (pbpctl_dev->bp_540) { + ctrl = ctrl_ext = BP10G_READ_REG(pbpctl_dev, ESDP); + BP10G_WRITE_REG(pbpctl_dev, ESDP, ((ctrl | + BP540_MDIO_DIR | + BP540_MCLK_DIR) & + ~(BP540_MDIO_DATA | + BP540_MCLK_DATA))); + + } else if (pbpctl_dev->bp_10gb) { + ctrl_ext = BP10GB_READ_REG(pbpctl_dev, MISC_REG_SPIO); + + BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO, + (ctrl_ext | BP10GB_MDIO_CLR | BP10GB_MCLK_CLR) + & ~(BP10GB_MCLK_DIR | BP10GB_MDIO_DIR | + BP10GB_MDIO_SET | BP10GB_MCLK_SET)); + + } else if (!pbpctl_dev->bp_10g) { + + ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext | + BPCTLI_CTRL_EXT_MCLK_DIR + | + BPCTLI_CTRL_EXT_MDIO_DIR) + & + ~ + (BPCTLI_CTRL_EXT_MDIO_DATA + | + BPCTLI_CTRL_EXT_MCLK_DATA))); + } else { + ctrl = BP10G_READ_REG(pbpctl_dev, ESDP); + ctrl_ext = BP10G_READ_REG(pbpctl_dev, EODSDP); + BP10G_WRITE_REG(pbpctl_dev, EODSDP, + (ctrl_ext & + ~(BP10G_MCLK_DATA_OUT | BP10G_MDIO_DATA_OUT))); + } + usec_delay(CMND_INTERVAL); + + /*send sync cmd */ + write_pulse(pbpctl_dev, ctrl_ext, SYNC_CMD_VAL, SYNC_CMD_LEN); + /*send wr cmd */ + write_pulse(pbpctl_dev, ctrl_ext, WR_CMD_VAL, WR_CMD_LEN); + write_pulse(pbpctl_dev, ctrl_ext, addr, ADDR_CMD_LEN); + + /*write data */ + write_pulse(pbpctl_dev, ctrl_ext, value, WR_DATA_LEN); + if (pbpctl_dev->bp_10g9) { + /*BP10G_WRITE_REG(pbpctl_dev, I2CCTL, (ctrl_ext&~(BP10G_MCLK_DATA_OUT9|BP10G_MDIO_DATA_OUT9))); */ + /* DATA 0 CLK 0 */ + BP10G_WRITE_REG(pbpctl_dev, I2CCTL, + (ctrl_ext & ~BP10G_MDIO_DATA_OUT9)); + BP10G_WRITE_REG(pbpctl_dev_c, ESDP, + ((ctrl | BP10G_MCLK_DIR_OUT9) & + ~(BP10G_MCLK_DATA_OUT9))); + + } else if (pbpctl_dev->bp_fiber5) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext | + BPCTLI_CTRL_EXT_MCLK_DIR5 + | + BPCTLI_CTRL_EXT_MDIO_DIR5) + & + ~ + (BPCTLI_CTRL_EXT_MDIO_DATA5 + | + BPCTLI_CTRL_EXT_MCLK_DATA5))); + } else if (pbpctl_dev->bp_i80) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext | + BPCTLI_CTRL_EXT_MDIO_DIR80) + & + ~BPCTLI_CTRL_EXT_MDIO_DATA80)); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, + ((ctrl | BPCTLI_CTRL_EXT_MCLK_DIR80) & + ~BPCTLI_CTRL_EXT_MCLK_DATA80)); + } else if (pbpctl_dev->bp_540) { + BP10G_WRITE_REG(pbpctl_dev, ESDP, ((ctrl | + BP540_MDIO_DIR | + BP540_MCLK_DIR) & + ~(BP540_MDIO_DATA | + BP540_MCLK_DATA))); + } else if (pbpctl_dev->bp_10gb) { + BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO, + (ctrl_ext | BP10GB_MDIO_CLR | BP10GB_MCLK_CLR) + & ~(BP10GB_MCLK_DIR | BP10GB_MDIO_DIR | + BP10GB_MDIO_SET | BP10GB_MCLK_SET)); + + } else if (!pbpctl_dev->bp_10g) + + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext | + BPCTLI_CTRL_EXT_MCLK_DIR + | + BPCTLI_CTRL_EXT_MDIO_DIR) + & + ~ + (BPCTLI_CTRL_EXT_MDIO_DATA + | + BPCTLI_CTRL_EXT_MCLK_DATA))); + else { + BP10G_WRITE_REG(pbpctl_dev, EODSDP, + (ctrl_ext & + ~(BP10G_MCLK_DATA_OUT | BP10G_MDIO_DATA_OUT))); + + } + + usec_delay(CMND_INTERVAL * 4); + + if ((pbpctl_dev->wdt_status == WDT_STATUS_EN) && + (pbpctl_dev->bp_ext_ver < PXG4BPFI_VER) && (addr == CMND_REG_ADDR)) + pbpctl_dev->bypass_wdt_on_time = jiffies; + #ifdef BP_SYNC_FLAG + spin_unlock_irqrestore(&pbpctl_dev->bypass_wr_lock, flags); + #else + atomic_set(&pbpctl_dev->wdt_busy, 0); + #endif + + } + + static void write_data(bpctl_dev_t *pbpctl_dev, unsigned char value) + { + write_reg(pbpctl_dev, value, CMND_REG_ADDR); + } + + static int read_reg(bpctl_dev_t *pbpctl_dev, unsigned char addr) + { + uint32_t ctrl_ext = 0, ctrl = 0, ctrl_value = 0; + bpctl_dev_t *pbpctl_dev_c = NULL; + + #ifdef BP_SYNC_FLAG + unsigned long flags; + spin_lock_irqsave(&pbpctl_dev->bypass_wr_lock, flags); + #else + atomic_set(&pbpctl_dev->wdt_busy, 1); + #endif + if (pbpctl_dev->bp_10g9) { + if (!(pbpctl_dev_c = get_status_port_fn(pbpctl_dev))) + return -1; + } + + if (pbpctl_dev->bp_10g9) { + ctrl_ext = BP10G_READ_REG(pbpctl_dev, I2CCTL); + ctrl = BP10G_READ_REG(pbpctl_dev_c, ESDP); + + /* BP10G_WRITE_REG(pbpctl_dev, I2CCTL, (ctrl_ext&~(BP10G_MCLK_DATA_OUT9|BP10G_MDIO_DATA_OUT9))); */ + /* DATA 0 CLK 0 */ + BP10G_WRITE_REG(pbpctl_dev, I2CCTL, + (ctrl_ext & ~BP10G_MDIO_DATA_OUT9)); + BP10G_WRITE_REG(pbpctl_dev_c, ESDP, + ((ctrl | BP10G_MCLK_DIR_OUT9) & + ~(BP10G_MCLK_DATA_OUT9))); + + } else if (pbpctl_dev->bp_fiber5) { + ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL); + + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext | + BPCTLI_CTRL_EXT_MCLK_DIR5 + | + BPCTLI_CTRL_EXT_MDIO_DIR5) + & + ~ + (BPCTLI_CTRL_EXT_MDIO_DATA5 + | + BPCTLI_CTRL_EXT_MCLK_DATA5))); + } else if (pbpctl_dev->bp_i80) { + ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL); + ctrl = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT); + + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext | + BPCTLI_CTRL_EXT_MDIO_DIR80) + & + ~BPCTLI_CTRL_EXT_MDIO_DATA80)); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, + ((ctrl | BPCTLI_CTRL_EXT_MCLK_DIR80) & + ~BPCTLI_CTRL_EXT_MCLK_DATA80)); + } else if (pbpctl_dev->bp_540) { + ctrl_ext = BP10G_READ_REG(pbpctl_dev, ESDP); + ctrl = BP10G_READ_REG(pbpctl_dev, ESDP); + + BP10G_WRITE_REG(pbpctl_dev, ESDP, ((ctrl | BP540_MCLK_DIR | + BP540_MDIO_DIR) & + ~(BP540_MDIO_DATA | + BP540_MCLK_DATA))); + } else if (pbpctl_dev->bp_10gb) { + ctrl_ext = BP10GB_READ_REG(pbpctl_dev, MISC_REG_SPIO); + + BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO, + (ctrl_ext | BP10GB_MDIO_CLR | BP10GB_MCLK_CLR) + & ~(BP10GB_MCLK_DIR | BP10GB_MDIO_DIR | + BP10GB_MDIO_SET | BP10GB_MCLK_SET)); + #if 0 + + /*BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO, (ctrl_ext | BP10GB_MCLK_DIR | BP10GB_MDIO_DIR| + BP10GB_MCLK_CLR|BP10GB_MDIO_CLR)); + ctrl_ext = BP10GB_READ_REG(pbpctl_dev, MISC_REG_SPIO); + printk("1reg=%x\n", ctrl_ext); */ + + BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO, ((ctrl_ext | + BP10GB_MCLK_SET | + BP10GB_MDIO_CLR)) + & ~(BP10GB_MCLK_CLR | BP10GB_MDIO_SET | + BP10GB_MCLK_DIR | BP10GB_MDIO_DIR)); + + /* bnx2x_set_spio(pbpctl_dev, 5, MISC_REGISTERS_SPIO_OUTPUT_LOW); + bnx2x_set_spio(pbpctl_dev, 4, MISC_REGISTERS_SPIO_OUTPUT_LOW); + bnx2x_set_spio(pbpctl_dev, 4, MISC_REGISTERS_SPIO_INPUT_HI_Z); */ + + ctrl_ext = BP10GB_READ_REG(pbpctl_dev, MISC_REG_SPIO); + + printk("2reg=%x\n", ctrl_ext); + + #ifdef BP_SYNC_FLAG + spin_unlock_irqrestore(&pbpctl_dev->bypass_wr_lock, flags); + #else + atomic_set(&pbpctl_dev->wdt_busy, 0); + #endif + + return 0; + + #endif + + } else if (!pbpctl_dev->bp_10g) { + + ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT); + + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext | + BPCTLI_CTRL_EXT_MCLK_DIR + | + BPCTLI_CTRL_EXT_MDIO_DIR) + & + ~ + (BPCTLI_CTRL_EXT_MDIO_DATA + | + BPCTLI_CTRL_EXT_MCLK_DATA))); + } else { + + ctrl = BP10G_READ_REG(pbpctl_dev, ESDP); + ctrl_ext = BP10G_READ_REG(pbpctl_dev, EODSDP); + BP10G_WRITE_REG(pbpctl_dev, EODSDP, + (ctrl_ext & + ~(BP10G_MCLK_DATA_OUT | BP10G_MDIO_DATA_OUT))); + + } + + usec_delay(CMND_INTERVAL); + + /*send sync cmd */ + write_pulse(pbpctl_dev, ctrl_ext, SYNC_CMD_VAL, SYNC_CMD_LEN); + /*send rd cmd */ + write_pulse(pbpctl_dev, ctrl_ext, RD_CMD_VAL, RD_CMD_LEN); + /*send addr */ + write_pulse(pbpctl_dev, ctrl_ext, addr, ADDR_CMD_LEN); + /*read data */ + /* zero */ + if (pbpctl_dev->bp_10g9) { + /* DATA 0 CLK 1 */ + /*BP10G_WRITE_REG(pbpctl_dev, I2CCTL, (ctrl_ext|BP10G_MCLK_DATA_OUT9|BP10G_MDIO_DATA_OUT9)); */ + BP10G_WRITE_REG(pbpctl_dev, I2CCTL, + (ctrl_ext | BP10G_MDIO_DATA_OUT9)); + BP10G_WRITE_REG(pbpctl_dev_c, ESDP, + (ctrl | BP10G_MCLK_DATA_OUT9 | + BP10G_MCLK_DIR_OUT9)); + + } else if (pbpctl_dev->bp_fiber5) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext | + BPCTLI_CTRL_EXT_MCLK_DIR5 + | + BPCTLI_CTRL_EXT_MCLK_DATA5) + & + ~ + (BPCTLI_CTRL_EXT_MDIO_DIR5 + | + BPCTLI_CTRL_EXT_MDIO_DATA5))); + + } else if (pbpctl_dev->bp_i80) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, + (ctrl_ext & + ~(BPCTLI_CTRL_EXT_MDIO_DATA80 | + BPCTLI_CTRL_EXT_MDIO_DIR80))); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, + (ctrl | BPCTLI_CTRL_EXT_MCLK_DIR80 | + BPCTLI_CTRL_EXT_MCLK_DATA80)); + + } else if (pbpctl_dev->bp_540) { + BP10G_WRITE_REG(pbpctl_dev, ESDP, + (((ctrl | BP540_MDIO_DIR | BP540_MCLK_DIR | + BP540_MCLK_DATA) & ~BP540_MDIO_DATA))); + + } else if (pbpctl_dev->bp_10gb) { + + BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO, + (ctrl_ext | BP10GB_MDIO_DIR | BP10GB_MCLK_SET) + & ~(BP10GB_MCLK_DIR | BP10GB_MDIO_SET | + BP10GB_MDIO_CLR | BP10GB_MCLK_CLR)); + + } else if (!pbpctl_dev->bp_10g) + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext | + BPCTLI_CTRL_EXT_MCLK_DIR + | + BPCTLI_CTRL_EXT_MCLK_DATA) + & + ~ + (BPCTLI_CTRL_EXT_MDIO_DIR + | + BPCTLI_CTRL_EXT_MDIO_DATA))); + else { + + BP10G_WRITE_REG(pbpctl_dev, EODSDP, + (ctrl_ext | BP10G_MCLK_DATA_OUT | + BP10G_MDIO_DATA_OUT)); + + + } + usec_delay(PULSE_TIME); + + ctrl_value = read_pulse(pbpctl_dev, ctrl_ext, RD_DATA_LEN); + + if (pbpctl_dev->bp_10g9) { + ctrl_ext = BP10G_READ_REG(pbpctl_dev, I2CCTL); + ctrl = BP10G_READ_REG(pbpctl_dev_c, ESDP); + + /* BP10G_WRITE_REG(pbpctl_dev, I2CCTL, (ctrl_ext&~(BP10G_MCLK_DATA_OUT9|BP10G_MDIO_DATA_OUT9))); */ + /* DATA 0 CLK 0 */ + BP10G_WRITE_REG(pbpctl_dev, I2CCTL, + (ctrl_ext & ~BP10G_MDIO_DATA_OUT9)); + BP10G_WRITE_REG(pbpctl_dev_c, ESDP, + ((ctrl | BP10G_MCLK_DIR_OUT9) & + ~(BP10G_MCLK_DATA_OUT9))); + + } else if (pbpctl_dev->bp_fiber5) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext | + BPCTLI_CTRL_EXT_MCLK_DIR5 + | + BPCTLI_CTRL_EXT_MDIO_DIR5) + & + ~ + (BPCTLI_CTRL_EXT_MDIO_DATA5 + | + BPCTLI_CTRL_EXT_MCLK_DATA5))); + } else if (pbpctl_dev->bp_i80) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext | + BPCTLI_CTRL_EXT_MDIO_DIR80) + & + ~BPCTLI_CTRL_EXT_MDIO_DATA80)); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, + ((ctrl | BPCTLI_CTRL_EXT_MCLK_DIR80) & + ~BPCTLI_CTRL_EXT_MCLK_DATA80)); + + } else if (pbpctl_dev->bp_540) { + ctrl = BP10G_READ_REG(pbpctl_dev, ESDP); + BP10G_WRITE_REG(pbpctl_dev, ESDP, ((ctrl | BP540_MCLK_DIR | + BP540_MDIO_DIR) & + ~(BP540_MDIO_DATA | + BP540_MCLK_DATA))); + + } else if (pbpctl_dev->bp_10gb) { + ctrl_ext = BP10GB_READ_REG(pbpctl_dev, MISC_REG_SPIO); + BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO, + (ctrl_ext | BP10GB_MDIO_CLR | BP10GB_MCLK_CLR) + & ~(BP10GB_MCLK_DIR | BP10GB_MDIO_DIR | + BP10GB_MDIO_SET | BP10GB_MCLK_SET)); + + } else if (!pbpctl_dev->bp_10g) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext | + BPCTLI_CTRL_EXT_MCLK_DIR + | + BPCTLI_CTRL_EXT_MDIO_DIR) + & + ~ + (BPCTLI_CTRL_EXT_MDIO_DATA + | + BPCTLI_CTRL_EXT_MCLK_DATA))); + } else { + + ctrl = BP10G_READ_REG(pbpctl_dev, ESDP); + ctrl_ext = BP10G_READ_REG(pbpctl_dev, EODSDP); + BP10G_WRITE_REG(pbpctl_dev, EODSDP, + (ctrl_ext & + ~(BP10G_MCLK_DATA_OUT | BP10G_MDIO_DATA_OUT))); + + } + + usec_delay(CMND_INTERVAL * 4); + #ifdef BP_SYNC_FLAG + spin_unlock_irqrestore(&pbpctl_dev->bypass_wr_lock, flags); + #else + atomic_set(&pbpctl_dev->wdt_busy, 0); + #endif + + return ctrl_value; + } + + static int wdt_pulse(bpctl_dev_t *pbpctl_dev) + { + uint32_t ctrl_ext = 0, ctrl = 0; + bpctl_dev_t *pbpctl_dev_c = NULL; + + #ifdef BP_SYNC_FLAG + unsigned long flags; + + spin_lock_irqsave(&pbpctl_dev->bypass_wr_lock, flags); + #else + + if ((atomic_read(&pbpctl_dev->wdt_busy)) == 1) + return -1; + #endif + if (pbpctl_dev->bp_10g9) { + if (!(pbpctl_dev_c = get_status_port_fn(pbpctl_dev))) + return -1; + } + + if (pbpctl_dev->bp_10g9) { + ctrl_ext = BP10G_READ_REG(pbpctl_dev, I2CCTL); + ctrl = BP10G_READ_REG(pbpctl_dev_c, ESDP); + + /* BP10G_WRITE_REG(pbpctl_dev, I2CCTL, (ctrl_ext&~(BP10G_MCLK_DATA_OUT9|BP10G_MDIO_DATA_OUT9))); */ + /* DATA 0 CLK 0 */ + BP10G_WRITE_REG(pbpctl_dev, I2CCTL, + (ctrl_ext & ~BP10G_MDIO_DATA_OUT9)); + BP10G_WRITE_REG(pbpctl_dev_c, ESDP, + ((ctrl | BP10G_MCLK_DIR_OUT9) & + ~(BP10G_MCLK_DATA_OUT9))); + + } else if (pbpctl_dev->bp_fiber5) { + ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext | + BPCTLI_CTRL_EXT_MCLK_DIR5 + | + BPCTLI_CTRL_EXT_MDIO_DIR5) + & + ~ + (BPCTLI_CTRL_EXT_MDIO_DATA5 + | + BPCTLI_CTRL_EXT_MCLK_DATA5))); + } else if (pbpctl_dev->bp_i80) { + ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL); + ctrl = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext | + BPCTLI_CTRL_EXT_MDIO_DIR80) + & + ~BPCTLI_CTRL_EXT_MDIO_DATA80)); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, + ((ctrl | BPCTLI_CTRL_EXT_MCLK_DIR80) & + ~BPCTLI_CTRL_EXT_MCLK_DATA80)); + } else if (pbpctl_dev->bp_540) { + ctrl_ext = ctrl = BP10G_READ_REG(pbpctl_dev, ESDP); + BP10G_WRITE_REG(pbpctl_dev, ESDP, ((ctrl | BP540_MCLK_DIR | + BP540_MDIO_DIR) & + ~(BP540_MDIO_DATA | + BP540_MCLK_DATA))); + } else if (pbpctl_dev->bp_10gb) { + ctrl_ext = BP10GB_READ_REG(pbpctl_dev, MISC_REG_SPIO); + BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO, + (ctrl_ext | BP10GB_MDIO_CLR | BP10GB_MCLK_CLR) + & ~(BP10GB_MCLK_DIR | BP10GB_MDIO_DIR | + BP10GB_MDIO_SET | BP10GB_MCLK_SET)); + + } else if (!pbpctl_dev->bp_10g) { + + ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext | + BPCTLI_CTRL_EXT_MCLK_DIR + | + BPCTLI_CTRL_EXT_MDIO_DIR) + & + ~ + (BPCTLI_CTRL_EXT_MDIO_DATA + | + BPCTLI_CTRL_EXT_MCLK_DATA))); + } else { + + ctrl = BP10G_READ_REG(pbpctl_dev, ESDP); + ctrl_ext = BP10G_READ_REG(pbpctl_dev, EODSDP); + BP10G_WRITE_REG(pbpctl_dev, EODSDP, + (ctrl_ext & + ~(BP10G_MCLK_DATA_OUT | BP10G_MDIO_DATA_OUT))); + + } + if (pbpctl_dev->bp_10g9) { + /* BP10G_WRITE_REG(pbpctl_dev, I2CCTL, ((ctrl_ext|BP10G_MCLK_DATA_OUT9)&~BP10G_MDIO_DATA_OUT9)); */ + /* DATA 0 CLK 1 */ + BP10G_WRITE_REG(pbpctl_dev, I2CCTL, + (ctrl_ext & ~BP10G_MDIO_DATA_OUT9)); + BP10G_WRITE_REG(pbpctl_dev_c, ESDP, + (ctrl | BP10G_MCLK_DATA_OUT9 | + BP10G_MCLK_DIR_OUT9)); + + } else if (pbpctl_dev->bp_fiber5) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext | + BPCTLI_CTRL_EXT_MCLK_DIR5 + | + BPCTLI_CTRL_EXT_MDIO_DIR5 + | + BPCTLI_CTRL_EXT_MCLK_DATA5) + & + ~ + (BPCTLI_CTRL_EXT_MDIO_DATA5))); + } else if (pbpctl_dev->bp_i80) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext | + BPCTLI_CTRL_EXT_MDIO_DIR80) + & + ~BPCTLI_CTRL_EXT_MDIO_DATA80)); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, + (ctrl | BPCTLI_CTRL_EXT_MCLK_DIR80 | + BPCTLI_CTRL_EXT_MCLK_DATA80)); + + } else if (pbpctl_dev->bp_540) { + BP10G_WRITE_REG(pbpctl_dev, ESDP, ((ctrl | + BP540_MDIO_DIR | + BP540_MCLK_DIR | + BP540_MCLK_DATA) & + ~BP540_MDIO_DATA)); + + } else if (pbpctl_dev->bp_10gb) { + ctrl_ext = BP10GB_READ_REG(pbpctl_dev, MISC_REG_SPIO); + + BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO, + (ctrl_ext | BP10GB_MDIO_CLR | BP10GB_MCLK_SET) + & ~(BP10GB_MCLK_DIR | BP10GB_MDIO_DIR | + BP10GB_MDIO_SET | BP10GB_MCLK_CLR)); + + } else if (!pbpctl_dev->bp_10g) + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext | + BPCTLI_CTRL_EXT_MCLK_DIR + | + BPCTLI_CTRL_EXT_MDIO_DIR + | + BPCTLI_CTRL_EXT_MCLK_DATA) + & + ~ + (BPCTLI_CTRL_EXT_MDIO_DATA))); + else { + + BP10G_WRITE_REG(pbpctl_dev, EODSDP, + ((ctrl_ext | BP10G_MCLK_DATA_OUT) & + ~BP10G_MDIO_DATA_OUT)); + + } + + usec_delay(WDT_INTERVAL); + if (pbpctl_dev->bp_10g9) { + /* BP10G_WRITE_REG(pbpctl_dev, I2CCTL, (ctrl_ext&~(BP10G_MCLK_DATA_OUT9|BP10G_MDIO_DATA_OUT9))); */ + /* DATA 0 CLK 0 */ + BP10G_WRITE_REG(pbpctl_dev, I2CCTL, + (ctrl_ext & ~BP10G_MDIO_DATA_OUT9)); + BP10G_WRITE_REG(pbpctl_dev_c, ESDP, + ((ctrl | BP10G_MCLK_DIR_OUT9) & + ~(BP10G_MCLK_DATA_OUT9))); + + } else if (pbpctl_dev->bp_fiber5) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext | + BPCTLI_CTRL_EXT_MCLK_DIR5 + | + BPCTLI_CTRL_EXT_MDIO_DIR5) + & + ~ + (BPCTLI_CTRL_EXT_MCLK_DATA5 + | + BPCTLI_CTRL_EXT_MDIO_DATA5))); + } else if (pbpctl_dev->bp_i80) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext | + BPCTLI_CTRL_EXT_MDIO_DIR80) + & + ~BPCTLI_CTRL_EXT_MDIO_DATA80)); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, + ((ctrl | BPCTLI_CTRL_EXT_MCLK_DIR80) & + ~BPCTLI_CTRL_EXT_MCLK_DATA80)); + + } else if (pbpctl_dev->bp_540) { + BP10G_WRITE_REG(pbpctl_dev, ESDP, ((ctrl | BP540_MCLK_DIR | + BP540_MDIO_DIR) & + ~(BP540_MDIO_DATA | + BP540_MCLK_DATA))); + + } else if (pbpctl_dev->bp_10gb) { + ctrl_ext = BP10GB_READ_REG(pbpctl_dev, MISC_REG_SPIO); + BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO, + (ctrl_ext | BP10GB_MDIO_CLR | BP10GB_MCLK_CLR) + & ~(BP10GB_MCLK_DIR | BP10GB_MDIO_DIR | + BP10GB_MDIO_SET | BP10GB_MCLK_SET)); + + } else if (!pbpctl_dev->bp_10g) + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext | + BPCTLI_CTRL_EXT_MCLK_DIR + | + BPCTLI_CTRL_EXT_MDIO_DIR) + & + ~ + (BPCTLI_CTRL_EXT_MCLK_DATA + | + BPCTLI_CTRL_EXT_MDIO_DATA))); + else { + + BP10G_WRITE_REG(pbpctl_dev, EODSDP, + (ctrl_ext & + ~(BP10G_MCLK_DATA_OUT | BP10G_MDIO_DATA_OUT))); + } + if ((pbpctl_dev->wdt_status == WDT_STATUS_EN) /*&& + (pbpctl_dev->bp_ext_verbypass_wdt_on_time = jiffies; + #ifdef BP_SYNC_FLAG + spin_unlock_irqrestore(&pbpctl_dev->bypass_wr_lock, flags); + #endif + usec_delay(CMND_INTERVAL * 4); + return 0; + } + + static void data_pulse(bpctl_dev_t *pbpctl_dev, unsigned char value) + { + + uint32_t ctrl_ext = 0; + #ifdef BP_SYNC_FLAG + unsigned long flags; + #endif + wdt_time_left(pbpctl_dev); + #ifdef BP_SYNC_FLAG + spin_lock_irqsave(&pbpctl_dev->bypass_wr_lock, flags); + #else + atomic_set(&pbpctl_dev->wdt_busy, 1); + #endif + + ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext | + BPCTLI_CTRL_EXT_SDP6_DIR | + BPCTLI_CTRL_EXT_SDP7_DIR) & + ~(BPCTLI_CTRL_EXT_SDP6_DATA | + BPCTLI_CTRL_EXT_SDP7_DATA))); + + usec_delay(INIT_CMND_INTERVAL); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext | + BPCTLI_CTRL_EXT_SDP6_DIR | + BPCTLI_CTRL_EXT_SDP7_DIR | + BPCTLI_CTRL_EXT_SDP6_DATA) & + ~ + (BPCTLI_CTRL_EXT_SDP7_DATA))); + usec_delay(INIT_CMND_INTERVAL); + + while (value) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ctrl_ext | + BPCTLI_CTRL_EXT_SDP6_DIR | + BPCTLI_CTRL_EXT_SDP7_DIR | + BPCTLI_CTRL_EXT_SDP6_DATA | + BPCTLI_CTRL_EXT_SDP7_DATA); + usec_delay(PULSE_INTERVAL); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext | + BPCTLI_CTRL_EXT_SDP6_DIR + | + BPCTLI_CTRL_EXT_SDP7_DIR + | + BPCTLI_CTRL_EXT_SDP6_DATA) + & + ~BPCTLI_CTRL_EXT_SDP7_DATA)); + usec_delay(PULSE_INTERVAL); + value--; + + } + usec_delay(INIT_CMND_INTERVAL - PULSE_INTERVAL); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext | + BPCTLI_CTRL_EXT_SDP6_DIR | + BPCTLI_CTRL_EXT_SDP7_DIR) & + ~(BPCTLI_CTRL_EXT_SDP6_DATA | + BPCTLI_CTRL_EXT_SDP7_DATA))); + usec_delay(WDT_TIME_CNT); + if (pbpctl_dev->wdt_status == WDT_STATUS_EN) + pbpctl_dev->bypass_wdt_on_time = jiffies; + #ifdef BP_SYNC_FLAG + spin_unlock_irqrestore(&pbpctl_dev->bypass_wr_lock, flags); + #else + atomic_set(&pbpctl_dev->wdt_busy, 0); + #endif + + } + + static int send_wdt_pulse(bpctl_dev_t *pbpctl_dev) + { + uint32_t ctrl_ext = 0; + + #ifdef BP_SYNC_FLAG + unsigned long flags; + + spin_lock_irqsave(&pbpctl_dev->bypass_wr_lock, flags); + #else + + if ((atomic_read(&pbpctl_dev->wdt_busy)) == 1) + return -1; + #endif + wdt_time_left(pbpctl_dev); + ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT); + + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ctrl_ext | /* 1 */ + BPCTLI_CTRL_EXT_SDP7_DIR | + BPCTLI_CTRL_EXT_SDP7_DATA); + usec_delay(PULSE_INTERVAL); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext | /* 0 */ + BPCTLI_CTRL_EXT_SDP7_DIR) & + ~BPCTLI_CTRL_EXT_SDP7_DATA)); + + usec_delay(PULSE_INTERVAL); + if (pbpctl_dev->wdt_status == WDT_STATUS_EN) + pbpctl_dev->bypass_wdt_on_time = jiffies; + #ifdef BP_SYNC_FLAG + spin_unlock_irqrestore(&pbpctl_dev->bypass_wr_lock, flags); + #endif + + return 0; + } + + void send_bypass_clear_pulse(bpctl_dev_t *pbpctl_dev, unsigned int value) + { + uint32_t ctrl_ext = 0; + + ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext | /* 0 */ + BPCTLI_CTRL_EXT_SDP6_DIR) & + ~BPCTLI_CTRL_EXT_SDP6_DATA)); + + usec_delay(PULSE_INTERVAL); + while (value) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ctrl_ext | /* 1 */ + BPCTLI_CTRL_EXT_SDP6_DIR | + BPCTLI_CTRL_EXT_SDP6_DATA); + usec_delay(PULSE_INTERVAL); + value--; + } + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext | /* 0 */ + BPCTLI_CTRL_EXT_SDP6_DIR) & + ~BPCTLI_CTRL_EXT_SDP6_DATA)); + usec_delay(PULSE_INTERVAL); + } + + /* #endif OLD_FW */ + #ifdef BYPASS_DEBUG + + int pulse_set_fn(bpctl_dev_t *pbpctl_dev, unsigned int counter) + { + uint32_t ctrl_ext = 0; + + if (!pbpctl_dev) + return -1; + + ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT); + write_pulse_1(pbpctl_dev, ctrl_ext, counter, counter); + + pbpctl_dev->bypass_wdt_status = 0; + if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) { + write_pulse_1(pbpctl_dev, ctrl_ext, counter, counter); + } else { + wdt_time_left(pbpctl_dev); + if (pbpctl_dev->wdt_status == WDT_STATUS_EN) { + pbpctl_dev->wdt_status = 0; + data_pulse(pbpctl_dev, counter); + pbpctl_dev->wdt_status = WDT_STATUS_EN; + pbpctl_dev->bypass_wdt_on_time = jiffies; + + } else + data_pulse(pbpctl_dev, counter); + } + + return 0; + } + + int zero_set_fn(bpctl_dev_t *pbpctl_dev) + { + uint32_t ctrl_ext = 0, ctrl_value = 0; + if (!pbpctl_dev) + return -1; + + if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) { + printk("zero_set"); + + ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT); + + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext | + BPCTLI_CTRL_EXT_MCLK_DIR) + & + ~ + (BPCTLI_CTRL_EXT_MCLK_DATA + | + BPCTLI_CTRL_EXT_MDIO_DIR + | + BPCTLI_CTRL_EXT_MDIO_DATA))); + + } + return ctrl_value; + } + + int pulse_get2_fn(bpctl_dev_t *pbpctl_dev) + { + uint32_t ctrl_ext = 0, ctrl_value = 0; + if (!pbpctl_dev) + return -1; + + if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) { + printk("pulse_get_fn\n"); + ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT); + ctrl_value = read_pulse_2(pbpctl_dev, ctrl_ext); + printk("read:%d\n", ctrl_value); + } + return ctrl_value; + } + + int pulse_get1_fn(bpctl_dev_t *pbpctl_dev) + { + uint32_t ctrl_ext = 0, ctrl_value = 0; + if (!pbpctl_dev) + return -1; + + if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) { + + printk("pulse_get_fn\n"); + + ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT); + ctrl_value = read_pulse_1(pbpctl_dev, ctrl_ext); + printk("read:%d\n", ctrl_value); + } + return ctrl_value; + } + + int gpio6_set_fn(bpctl_dev_t *pbpctl_dev) + { + uint32_t ctrl_ext = 0; + + ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ctrl_ext | + BPCTLI_CTRL_EXT_SDP6_DIR | + BPCTLI_CTRL_EXT_SDP6_DATA); + return 0; + } + + int gpio7_set_fn(bpctl_dev_t *pbpctl_dev) + { + uint32_t ctrl_ext = 0; + + ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ctrl_ext | + BPCTLI_CTRL_EXT_SDP7_DIR | + BPCTLI_CTRL_EXT_SDP7_DATA); + return 0; + } + + int gpio7_clear_fn(bpctl_dev_t *pbpctl_dev) + { + uint32_t ctrl_ext = 0; + + ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext | + BPCTLI_CTRL_EXT_SDP7_DIR) & + ~BPCTLI_CTRL_EXT_SDP7_DATA)); + return 0; + } + + int gpio6_clear_fn(bpctl_dev_t *pbpctl_dev) + { + uint32_t ctrl_ext = 0; + + ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext | + BPCTLI_CTRL_EXT_SDP6_DIR) & + ~BPCTLI_CTRL_EXT_SDP6_DATA)); + return 0; + } + #endif /*BYPASS_DEBUG */ + + static bpctl_dev_t *lookup_port(bpctl_dev_t *dev) + { + bpctl_dev_t *p; + int n; + for (n = 0, p = bpctl_dev_arr; n < device_num && p->pdev; n++) { + if (p->bus == dev->bus + && p->slot == dev->slot + && p->func == (dev->func ^ 1)) + return p; + } + return NULL; + } + + static bpctl_dev_t *get_status_port_fn(bpctl_dev_t *pbpctl_dev) + { + if (pbpctl_dev) { + if (pbpctl_dev->func == 0 || pbpctl_dev->func == 2) + return lookup_port(pbpctl_dev); + } + return NULL; + } + + static bpctl_dev_t *get_master_port_fn(bpctl_dev_t *pbpctl_dev) + { + if (pbpctl_dev) { + if (pbpctl_dev->func == 1 || pbpctl_dev->func == 3) + return lookup_port(pbpctl_dev); + } + return NULL; + } + + /**************************************/ + /**************INTEL API***************/ + /**************************************/ + + static void write_data_port_int(bpctl_dev_t *pbpctl_dev, + unsigned char ctrl_value) + { + uint32_t value; + + value = BPCTL_READ_REG(pbpctl_dev, CTRL); + /* Make SDP0 Pin Directonality to Output */ + value |= BPCTLI_CTRL_SDP0_DIR; + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, value); + + value &= ~BPCTLI_CTRL_SDP0_DATA; + value |= ((ctrl_value & 0x1) << BPCTLI_CTRL_SDP0_SHIFT); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, value); + + value = (BPCTL_READ_REG(pbpctl_dev, CTRL_EXT)); + /* Make SDP2 Pin Directonality to Output */ + value |= BPCTLI_CTRL_EXT_SDP6_DIR; + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, value); + + value &= ~BPCTLI_CTRL_EXT_SDP6_DATA; + value |= (((ctrl_value & 0x2) >> 1) << BPCTLI_CTRL_EXT_SDP6_SHIFT); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, value); + + } + + static int write_data_int(bpctl_dev_t *pbpctl_dev, unsigned char value) + { + bpctl_dev_t *pbpctl_dev_b = NULL; + + if (!(pbpctl_dev_b = get_status_port_fn(pbpctl_dev))) + return -1; + atomic_set(&pbpctl_dev->wdt_busy, 1); + write_data_port_int(pbpctl_dev, value & 0x3); + write_data_port_int(pbpctl_dev_b, ((value & 0xc) >> 2)); + atomic_set(&pbpctl_dev->wdt_busy, 0); + + return 0; + } + + static int wdt_pulse_int(bpctl_dev_t *pbpctl_dev) + { + + if ((atomic_read(&pbpctl_dev->wdt_busy)) == 1) + return -1; + + if ((write_data_int(pbpctl_dev, RESET_WDT_INT)) < 0) + return -1; + msec_delay_bp(CMND_INTERVAL_INT); + if ((write_data_int(pbpctl_dev, CMND_OFF_INT)) < 0) + return -1; + msec_delay_bp(CMND_INTERVAL_INT); + + if (pbpctl_dev->wdt_status == WDT_STATUS_EN) + pbpctl_dev->bypass_wdt_on_time = jiffies; + + return 0; + } + + /*************************************/ + /************* COMMANDS **************/ + /*************************************/ + + /* CMND_ON 0x4 (100)*/ + int cmnd_on(bpctl_dev_t *pbpctl_dev) + { + int ret = BP_NOT_CAP; + + if (pbpctl_dev->bp_caps & SW_CTL_CAP) { + if (INTEL_IF_SERIES(pbpctl_dev->subdevice)) + return 0; + if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) + write_data(pbpctl_dev, CMND_ON); + else + data_pulse(pbpctl_dev, CMND_ON); + ret = 0; + } + return ret; + } + + /* CMND_OFF 0x2 (10)*/ + int cmnd_off(bpctl_dev_t *pbpctl_dev) + { + int ret = BP_NOT_CAP; + + if (pbpctl_dev->bp_caps & SW_CTL_CAP) { + if (INTEL_IF_SERIES(pbpctl_dev->subdevice)) { + write_data_int(pbpctl_dev, CMND_OFF_INT); + msec_delay_bp(CMND_INTERVAL_INT); + } else if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) + write_data(pbpctl_dev, CMND_OFF); + else + data_pulse(pbpctl_dev, CMND_OFF); + ret = 0; + }; + return ret; + } + + /* BYPASS_ON (0xa)*/ + int bypass_on(bpctl_dev_t *pbpctl_dev) + { + int ret = BP_NOT_CAP; + + if (pbpctl_dev->bp_caps & BP_CAP) { + if (INTEL_IF_SERIES(pbpctl_dev->subdevice)) { + write_data_int(pbpctl_dev, BYPASS_ON_INT); + msec_delay_bp(BYPASS_DELAY_INT); + pbpctl_dev->bp_status_un = 0; + } else if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) { + write_data(pbpctl_dev, BYPASS_ON); + if (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER) + msec_delay_bp(LATCH_DELAY); + } else + data_pulse(pbpctl_dev, BYPASS_ON); + ret = 0; + }; + return ret; + } + + /* BYPASS_OFF (0x8 111)*/ + int bypass_off(bpctl_dev_t *pbpctl_dev) + { + int ret = BP_NOT_CAP; + + if (pbpctl_dev->bp_caps & BP_CAP) { + if (INTEL_IF_SERIES(pbpctl_dev->subdevice)) { + write_data_int(pbpctl_dev, DIS_BYPASS_CAP_INT); + msec_delay_bp(BYPASS_DELAY_INT); + write_data_int(pbpctl_dev, PWROFF_BYPASS_ON_INT); + msec_delay_bp(BYPASS_DELAY_INT); + pbpctl_dev->bp_status_un = 0; + } else if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) { + write_data(pbpctl_dev, BYPASS_OFF); + if (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER) + msec_delay_bp(LATCH_DELAY); + } else + data_pulse(pbpctl_dev, BYPASS_OFF); + ret = 0; + } + return ret; + } + + /* TAP_OFF (0x9)*/ + int tap_off(bpctl_dev_t *pbpctl_dev) + { + int ret = BP_NOT_CAP; + if ((pbpctl_dev->bp_caps & TAP_CAP) + && (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER)) { + write_data(pbpctl_dev, TAP_OFF); + msec_delay_bp(LATCH_DELAY); + ret = 0; + }; + return ret; + } + + /* TAP_ON (0xb)*/ + int tap_on(bpctl_dev_t *pbpctl_dev) + { + int ret = BP_NOT_CAP; + if ((pbpctl_dev->bp_caps & TAP_CAP) + && (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER)) { + write_data(pbpctl_dev, TAP_ON); + msec_delay_bp(LATCH_DELAY); + ret = 0; + }; + return ret; + } + + /* DISC_OFF (0x9)*/ + int disc_off(bpctl_dev_t *pbpctl_dev) + { + int ret = 0; + if ((pbpctl_dev->bp_caps & DISC_CAP) && (pbpctl_dev->bp_ext_ver >= 0x8)) { + write_data(pbpctl_dev, DISC_OFF); + msec_delay_bp(LATCH_DELAY); + } else + ret = BP_NOT_CAP; + return ret; + } + + /* DISC_ON (0xb)*/ + int disc_on(bpctl_dev_t *pbpctl_dev) + { + int ret = 0; + if ((pbpctl_dev->bp_caps & DISC_CAP) && (pbpctl_dev->bp_ext_ver >= 0x8)) { + write_data(pbpctl_dev, /*DISC_ON */ 0x85); + msec_delay_bp(LATCH_DELAY); + } else + ret = BP_NOT_CAP; + return ret; + } + + /* DISC_PORT_ON */ + int disc_port_on(bpctl_dev_t *pbpctl_dev) + { + int ret = 0; + bpctl_dev_t *pbpctl_dev_m; + + if ((is_bypass_fn(pbpctl_dev)) == 1) + pbpctl_dev_m = pbpctl_dev; + else + pbpctl_dev_m = get_master_port_fn(pbpctl_dev); + if (pbpctl_dev_m == NULL) + return BP_NOT_CAP; + + if (pbpctl_dev_m->bp_caps_ex & DISC_PORT_CAP_EX) { + if (is_bypass_fn(pbpctl_dev) == 1) { + + write_data(pbpctl_dev_m, TX_DISA); + } else { + + write_data(pbpctl_dev_m, TX_DISB); + } + + msec_delay_bp(LATCH_DELAY); + + } + return ret; + } + + /* DISC_PORT_OFF */ + int disc_port_off(bpctl_dev_t *pbpctl_dev) + { + int ret = 0; + bpctl_dev_t *pbpctl_dev_m; + + if ((is_bypass_fn(pbpctl_dev)) == 1) + pbpctl_dev_m = pbpctl_dev; + else + pbpctl_dev_m = get_master_port_fn(pbpctl_dev); + if (pbpctl_dev_m == NULL) + return BP_NOT_CAP; + + if (pbpctl_dev_m->bp_caps_ex & DISC_PORT_CAP_EX) { + if (is_bypass_fn(pbpctl_dev) == 1) + write_data(pbpctl_dev_m, TX_ENA); + else + write_data(pbpctl_dev_m, TX_ENB); + + msec_delay_bp(LATCH_DELAY); + + } + return ret; + } + + /*TWO_PORT_LINK_HW_EN (0xe)*/ + int tpl_hw_on(bpctl_dev_t *pbpctl_dev) + { + int ret = 0, ctrl = 0; + bpctl_dev_t *pbpctl_dev_b = NULL; + + if (!(pbpctl_dev_b = get_status_port_fn(pbpctl_dev))) + return BP_NOT_CAP; + + if (pbpctl_dev->bp_caps_ex & TPL2_CAP_EX) { + cmnd_on(pbpctl_dev); + write_data(pbpctl_dev, TPL2_ON); + msec_delay_bp(LATCH_DELAY + EEPROM_WR_DELAY); + cmnd_off(pbpctl_dev); + return ret; + } + + if (TPL_IF_SERIES(pbpctl_dev->subdevice)) { + ctrl = BPCTL_READ_REG(pbpctl_dev_b, CTRL); + BPCTL_BP_WRITE_REG(pbpctl_dev_b, CTRL, + ((ctrl | BPCTLI_CTRL_SWDPIO0) & + ~BPCTLI_CTRL_SWDPIN0)); + } else + ret = BP_NOT_CAP; + return ret; + } + + /*TWO_PORT_LINK_HW_DIS (0xc)*/ + int tpl_hw_off(bpctl_dev_t *pbpctl_dev) + { + int ret = 0, ctrl = 0; + bpctl_dev_t *pbpctl_dev_b = NULL; + + if (!(pbpctl_dev_b = get_status_port_fn(pbpctl_dev))) + return BP_NOT_CAP; + if (pbpctl_dev->bp_caps_ex & TPL2_CAP_EX) { + cmnd_on(pbpctl_dev); + write_data(pbpctl_dev, TPL2_OFF); + msec_delay_bp(LATCH_DELAY + EEPROM_WR_DELAY); + cmnd_off(pbpctl_dev); + return ret; + } + if (TPL_IF_SERIES(pbpctl_dev->subdevice)) { + ctrl = BPCTL_READ_REG(pbpctl_dev_b, CTRL); + BPCTL_BP_WRITE_REG(pbpctl_dev_b, CTRL, + (ctrl | BPCTLI_CTRL_SWDPIO0 | + BPCTLI_CTRL_SWDPIN0)); + } else + ret = BP_NOT_CAP; + return ret; + } + + /* WDT_OFF (0x6 110)*/ + int wdt_off(bpctl_dev_t *pbpctl_dev) + { + int ret = BP_NOT_CAP; + + if (pbpctl_dev->bp_caps & WD_CTL_CAP) { + if (INTEL_IF_SERIES(pbpctl_dev->subdevice)) { + bypass_off(pbpctl_dev); + } else if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) + write_data(pbpctl_dev, WDT_OFF); + else + data_pulse(pbpctl_dev, WDT_OFF); + pbpctl_dev->wdt_status = WDT_STATUS_DIS; + ret = 0; + }; + return ret; + } + + /* WDT_ON (0x10)*/ + + /***Global***/ + static unsigned int + wdt_val_array[] = { 1000, 1500, 2000, 3000, 4000, 8000, 16000, 32000, 0 }; + + int wdt_on(bpctl_dev_t *pbpctl_dev, unsigned int timeout) + { + + if (pbpctl_dev->bp_caps & WD_CTL_CAP) { + unsigned int pulse = 0, temp_value = 0, temp_cnt = 0; + pbpctl_dev->wdt_status = 0; + + if (INTEL_IF_SERIES(pbpctl_dev->subdevice)) { + for (; wdt_val_array[temp_cnt]; temp_cnt++) + if (timeout <= wdt_val_array[temp_cnt]) + break; + + if (!wdt_val_array[temp_cnt]) + temp_cnt--; + + timeout = wdt_val_array[temp_cnt]; + temp_cnt += 0x7; + + write_data_int(pbpctl_dev, DIS_BYPASS_CAP_INT); + msec_delay_bp(BYPASS_DELAY_INT); + pbpctl_dev->bp_status_un = 0; + write_data_int(pbpctl_dev, temp_cnt); + pbpctl_dev->bypass_wdt_on_time = jiffies; + msec_delay_bp(CMND_INTERVAL_INT); + pbpctl_dev->bypass_timer_interval = timeout; + } else { + timeout = + (timeout < + TIMEOUT_UNIT ? TIMEOUT_UNIT : (timeout > + WDT_TIMEOUT_MAX ? + WDT_TIMEOUT_MAX : + timeout)); + temp_value = timeout / 100; + while ((temp_value >>= 1)) + temp_cnt++; + if (timeout > ((1 << temp_cnt) * 100)) + temp_cnt++; + pbpctl_dev->bypass_wdt_on_time = jiffies; + pulse = (WDT_ON | temp_cnt); + if (pbpctl_dev->bp_ext_ver == OLD_IF_VER) + data_pulse(pbpctl_dev, pulse); + else + write_data(pbpctl_dev, pulse); + pbpctl_dev->bypass_timer_interval = + (1 << temp_cnt) * 100; + } + pbpctl_dev->wdt_status = WDT_STATUS_EN; + return 0; + } + return BP_NOT_CAP; + } + + void bp75_put_hw_semaphore_generic(bpctl_dev_t *pbpctl_dev) + { + u32 swsm; + + swsm = BPCTL_READ_REG(pbpctl_dev, SWSM); + + swsm &= ~(BPCTLI_SWSM_SMBI | BPCTLI_SWSM_SWESMBI); + + BPCTL_WRITE_REG(pbpctl_dev, SWSM, swsm); + } + + s32 bp75_get_hw_semaphore_generic(bpctl_dev_t *pbpctl_dev) + { + u32 swsm; + s32 ret_val = 0; + s32 timeout = 8192 + 1; + s32 i = 0; + + /* Get the SW semaphore */ + while (i < timeout) { + swsm = BPCTL_READ_REG(pbpctl_dev, SWSM); + if (!(swsm & BPCTLI_SWSM_SMBI)) + break; + + usec_delay(50); + i++; + } + + if (i == timeout) { + printk + ("bpctl_mod: Driver can't access device - SMBI bit is set.\n"); + ret_val = -1; + goto out; + } + + /* Get the FW semaphore. */ + for (i = 0; i < timeout; i++) { + swsm = BPCTL_READ_REG(pbpctl_dev, SWSM); + BPCTL_WRITE_REG(pbpctl_dev, SWSM, swsm | BPCTLI_SWSM_SWESMBI); + + /* Semaphore acquired if bit latched */ + if (BPCTL_READ_REG(pbpctl_dev, SWSM) & BPCTLI_SWSM_SWESMBI) + break; + + usec_delay(50); + } + + if (i == timeout) { + /* Release semaphores */ + bp75_put_hw_semaphore_generic(pbpctl_dev); + printk("bpctl_mod: Driver can't access the NVM\n"); + ret_val = -1; + goto out; + } + + out: + return ret_val; + } + + static void bp75_release_phy(bpctl_dev_t *pbpctl_dev) + { + u16 mask = BPCTLI_SWFW_PHY0_SM; + u32 swfw_sync; + + if ((pbpctl_dev->func == 1) || (pbpctl_dev->func == 3)) + mask = BPCTLI_SWFW_PHY1_SM; + + while (bp75_get_hw_semaphore_generic(pbpctl_dev) != 0) ; + /* Empty */ + + swfw_sync = BPCTL_READ_REG(pbpctl_dev, SW_FW_SYNC); + swfw_sync &= ~mask; + BPCTL_WRITE_REG(pbpctl_dev, SW_FW_SYNC, swfw_sync); + + bp75_put_hw_semaphore_generic(pbpctl_dev); + } + + static s32 bp75_acquire_phy(bpctl_dev_t *pbpctl_dev) + { + u16 mask = BPCTLI_SWFW_PHY0_SM; + u32 swfw_sync; + u32 swmask; + u32 fwmask; + s32 ret_val = 0; + s32 i = 0, timeout = 200; + + if ((pbpctl_dev->func == 1) || (pbpctl_dev->func == 3)) + mask = BPCTLI_SWFW_PHY1_SM; + + swmask = mask; + fwmask = mask << 16; + + while (i < timeout) { + if (bp75_get_hw_semaphore_generic(pbpctl_dev)) { + ret_val = -1; + goto out; + } + + swfw_sync = BPCTL_READ_REG(pbpctl_dev, SW_FW_SYNC); + if (!(swfw_sync & (fwmask | swmask))) + break; + + bp75_put_hw_semaphore_generic(pbpctl_dev); + mdelay(5); + i++; + } + + if (i == timeout) { + printk + ("bpctl_mod: Driver can't access resource, SW_FW_SYNC timeout.\n"); + ret_val = -1; + goto out; + } + + swfw_sync |= swmask; + BPCTL_WRITE_REG(pbpctl_dev, SW_FW_SYNC, swfw_sync); + + bp75_put_hw_semaphore_generic(pbpctl_dev); + + out: + return ret_val; + } + + s32 bp75_read_phy_reg_mdic(bpctl_dev_t *pbpctl_dev, u32 offset, u16 *data) + { + u32 i, mdic = 0; + s32 ret_val = 0; + u32 phy_addr = 1; + + mdic = ((offset << BPCTLI_MDIC_REG_SHIFT) | + (phy_addr << BPCTLI_MDIC_PHY_SHIFT) | (BPCTLI_MDIC_OP_READ)); + + BPCTL_WRITE_REG(pbpctl_dev, MDIC, mdic); + + for (i = 0; i < (BPCTLI_GEN_POLL_TIMEOUT * 3); i++) { + usec_delay(50); + mdic = BPCTL_READ_REG(pbpctl_dev, MDIC); + if (mdic & BPCTLI_MDIC_READY) + break; + } + if (!(mdic & BPCTLI_MDIC_READY)) { + printk("bpctl_mod: MDI Read did not complete\n"); + ret_val = -1; + goto out; + } + if (mdic & BPCTLI_MDIC_ERROR) { + printk("bpctl_mod: MDI Error\n"); + ret_val = -1; + goto out; + } + *data = (u16) mdic; + + out: + return ret_val; + } + + s32 bp75_write_phy_reg_mdic(bpctl_dev_t *pbpctl_dev, u32 offset, u16 data) + { + u32 i, mdic = 0; + s32 ret_val = 0; + u32 phy_addr = 1; + + mdic = (((u32) data) | + (offset << BPCTLI_MDIC_REG_SHIFT) | + (phy_addr << BPCTLI_MDIC_PHY_SHIFT) | (BPCTLI_MDIC_OP_WRITE)); + + BPCTL_WRITE_REG(pbpctl_dev, MDIC, mdic); + + for (i = 0; i < (BPCTLI_GEN_POLL_TIMEOUT * 3); i++) { + usec_delay(50); + mdic = BPCTL_READ_REG(pbpctl_dev, MDIC); + if (mdic & BPCTLI_MDIC_READY) + break; + } + if (!(mdic & BPCTLI_MDIC_READY)) { + printk("bpctl_mod: MDI Write did not complete\n"); + ret_val = -1; + goto out; + } + if (mdic & BPCTLI_MDIC_ERROR) { + printk("bpctl_mod: MDI Error\n"); + ret_val = -1; + goto out; + } + + out: + return ret_val; + } + + static s32 bp75_read_phy_reg(bpctl_dev_t *pbpctl_dev, u32 offset, u16 *data) + { + s32 ret_val = 0; + + ret_val = bp75_acquire_phy(pbpctl_dev); + if (ret_val) + goto out; + + if (offset > BPCTLI_MAX_PHY_MULTI_PAGE_REG) { + ret_val = bp75_write_phy_reg_mdic(pbpctl_dev, + BPCTLI_IGP01E1000_PHY_PAGE_SELECT, + (u16) offset); + if (ret_val) + goto release; + } + + ret_val = + bp75_read_phy_reg_mdic(pbpctl_dev, + BPCTLI_MAX_PHY_REG_ADDRESS & offset, data); + + release: + bp75_release_phy(pbpctl_dev); + out: + return ret_val; + } + + static s32 bp75_write_phy_reg(bpctl_dev_t *pbpctl_dev, u32 offset, u16 data) + { + s32 ret_val = 0; + + ret_val = bp75_acquire_phy(pbpctl_dev); + if (ret_val) + goto out; + + if (offset > BPCTLI_MAX_PHY_MULTI_PAGE_REG) { + ret_val = bp75_write_phy_reg_mdic(pbpctl_dev, + BPCTLI_IGP01E1000_PHY_PAGE_SELECT, + (u16) offset); + if (ret_val) + goto release; + } + + ret_val = + bp75_write_phy_reg_mdic(pbpctl_dev, + BPCTLI_MAX_PHY_REG_ADDRESS & offset, data); + + release: + bp75_release_phy(pbpctl_dev); + + out: + return ret_val; + } + + /* SET_TX (non-Bypass command :)) */ + static int set_tx(bpctl_dev_t *pbpctl_dev, int tx_state) + { + int ret = 0, ctrl = 0; + bpctl_dev_t *pbpctl_dev_m; + if ((is_bypass_fn(pbpctl_dev)) == 1) + pbpctl_dev_m = pbpctl_dev; + else + pbpctl_dev_m = get_master_port_fn(pbpctl_dev); + if (pbpctl_dev_m == NULL) + return BP_NOT_CAP; + if (pbpctl_dev_m->bp_caps_ex & DISC_PORT_CAP_EX) { + ctrl = BPCTL_READ_REG(pbpctl_dev, CTRL); + if (!tx_state) { + if (pbpctl_dev->bp_540) { + ctrl = BP10G_READ_REG(pbpctl_dev, ESDP); + BP10G_WRITE_REG(pbpctl_dev, ESDP, + (ctrl | BP10G_SDP1_DIR | + BP10G_SDP1_DATA)); + + } else { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, + (ctrl | BPCTLI_CTRL_SDP1_DIR + | BPCTLI_CTRL_SWDPIN1)); + } + } else { + if (pbpctl_dev->bp_540) { + ctrl = BP10G_READ_REG(pbpctl_dev, ESDP); + BP10G_WRITE_REG(pbpctl_dev, ESDP, + ((ctrl | BP10G_SDP1_DIR) & + ~BP10G_SDP1_DATA)); + } else { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, + ((ctrl | + BPCTLI_CTRL_SDP1_DIR) & + ~BPCTLI_CTRL_SWDPIN1)); + } + return ret; + + } + } else if (pbpctl_dev->bp_caps & TX_CTL_CAP) { + if (PEG5_IF_SERIES(pbpctl_dev->subdevice)) { + if (tx_state) { + uint16_t mii_reg; + if (! + (ret = + bp75_read_phy_reg(pbpctl_dev, + BPCTLI_PHY_CONTROL, + &mii_reg))) { + if (mii_reg & BPCTLI_MII_CR_POWER_DOWN) { + ret = + bp75_write_phy_reg + (pbpctl_dev, + BPCTLI_PHY_CONTROL, + mii_reg & + ~BPCTLI_MII_CR_POWER_DOWN); + } + } + } else { + uint16_t mii_reg; + if (! + (ret = + bp75_read_phy_reg(pbpctl_dev, + BPCTLI_PHY_CONTROL, + &mii_reg))) { + + mii_reg |= BPCTLI_MII_CR_POWER_DOWN; + ret = + bp75_write_phy_reg(pbpctl_dev, + BPCTLI_PHY_CONTROL, + mii_reg); + } + } + + } + if (pbpctl_dev->bp_fiber5) { + ctrl = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT); + + } else if (pbpctl_dev->bp_10gb) + ctrl = BP10GB_READ_REG(pbpctl_dev, MISC_REG_GPIO); + + else if (!pbpctl_dev->bp_10g) + ctrl = BPCTL_READ_REG(pbpctl_dev, CTRL); + else + ctrl = BP10G_READ_REG(pbpctl_dev, ESDP); + + if (!tx_state) + if (pbpctl_dev->bp_10g9) { + BP10G_WRITE_REG(pbpctl_dev, ESDP, + (ctrl | BP10G_SDP3_DATA | + BP10G_SDP3_DIR)); + + } else if (pbpctl_dev->bp_fiber5) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, + (ctrl | + BPCTLI_CTRL_EXT_SDP6_DIR | + BPCTLI_CTRL_EXT_SDP6_DATA)); + + } else if (pbpctl_dev->bp_10gb) { + if ((pbpctl_dev->func == 1) + || (pbpctl_dev->func == 3)) + BP10GB_WRITE_REG(pbpctl_dev, + MISC_REG_GPIO, + (ctrl | + BP10GB_GPIO0_SET_P1) & + ~(BP10GB_GPIO0_CLR_P1 | + BP10GB_GPIO0_OE_P1)); + else + BP10GB_WRITE_REG(pbpctl_dev, + MISC_REG_GPIO, + (ctrl | + BP10GB_GPIO0_OE_P0 | + BP10GB_GPIO0_SET_P0)); + + } else if (pbpctl_dev->bp_i80) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, + (ctrl | BPCTLI_CTRL_SDP1_DIR + | BPCTLI_CTRL_SWDPIN1)); + + } else if (pbpctl_dev->bp_540) { + ctrl = BP10G_READ_REG(pbpctl_dev, ESDP); + BP10G_WRITE_REG(pbpctl_dev, ESDP, + (ctrl | BP10G_SDP1_DIR | + BP10G_SDP1_DATA)); + + } + + else if (!pbpctl_dev->bp_10g) + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, + (ctrl | BPCTLI_CTRL_SWDPIO0 | + BPCTLI_CTRL_SWDPIN0)); + + else + BP10G_WRITE_REG(pbpctl_dev, ESDP, + (ctrl | BP10G_SDP0_DATA | + BP10G_SDP0_DIR)); + + else { + if (pbpctl_dev->bp_10g9) { + BP10G_WRITE_REG(pbpctl_dev, ESDP, + ((ctrl | BP10G_SDP3_DIR) & + ~BP10G_SDP3_DATA)); + + } else if (pbpctl_dev->bp_fiber5) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, + ((ctrl | + BPCTLI_CTRL_EXT_SDP6_DIR) & + ~BPCTLI_CTRL_EXT_SDP6_DATA)); + + } else if (pbpctl_dev->bp_10gb) { + if ((bpctl_dev_arr->func == 1) + || (bpctl_dev_arr->func == 3)) + BP10GB_WRITE_REG(pbpctl_dev, + MISC_REG_GPIO, + (ctrl | + BP10GB_GPIO0_CLR_P1) & + ~(BP10GB_GPIO0_SET_P1 | + BP10GB_GPIO0_OE_P1)); + else + BP10GB_WRITE_REG(pbpctl_dev, + MISC_REG_GPIO, + (ctrl | + BP10GB_GPIO0_OE_P0 | + BP10GB_GPIO0_CLR_P0)); + + } else if (pbpctl_dev->bp_i80) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, + ((ctrl | + BPCTLI_CTRL_SDP1_DIR) & + ~BPCTLI_CTRL_SWDPIN1)); + } else if (pbpctl_dev->bp_540) { + ctrl = BP10G_READ_REG(pbpctl_dev, ESDP); + BP10G_WRITE_REG(pbpctl_dev, ESDP, + ((ctrl | BP10G_SDP1_DIR) & + ~BP10G_SDP1_DATA)); + } + + else if (!pbpctl_dev->bp_10g) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, + ((ctrl | BPCTLI_CTRL_SWDPIO0) + & ~BPCTLI_CTRL_SWDPIN0)); + if (!PEGF_IF_SERIES(pbpctl_dev->subdevice)) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, + (ctrl & + ~ + (BPCTLI_CTRL_SDP0_DATA + | + BPCTLI_CTRL_SDP0_DIR))); + } + } else + BP10G_WRITE_REG(pbpctl_dev, ESDP, + ((ctrl | BP10G_SDP0_DIR) & + ~BP10G_SDP0_DATA)); + + } + + } else + ret = BP_NOT_CAP; + return ret; + + } + + /* SET_FORCE_LINK (non-Bypass command :)) */ + static int set_bp_force_link(bpctl_dev_t *pbpctl_dev, int tx_state) + { + int ret = 0, ctrl = 0; + + if (DBI_IF_SERIES(pbpctl_dev->subdevice)) { + + if ((pbpctl_dev->bp_10g) || (pbpctl_dev->bp_10g9)) { + + ctrl = BPCTL_READ_REG(pbpctl_dev, CTRL); + if (!tx_state) + BP10G_WRITE_REG(pbpctl_dev, ESDP, + ctrl & ~BP10G_SDP1_DIR); + else + BP10G_WRITE_REG(pbpctl_dev, ESDP, + ((ctrl | BP10G_SDP1_DIR) & + ~BP10G_SDP1_DATA)); + return ret; + } + + } + return BP_NOT_CAP; + } + + /*RESET_CONT 0x20 */ + int reset_cont(bpctl_dev_t *pbpctl_dev) + { + int ret = BP_NOT_CAP; + + if (pbpctl_dev->bp_caps & SW_CTL_CAP) { + if (INTEL_IF_SERIES(pbpctl_dev->subdevice)) + return BP_NOT_CAP; + if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) + write_data(pbpctl_dev, RESET_CONT); + else + data_pulse(pbpctl_dev, RESET_CONT); + ret = 0; + }; + return ret; + } + + /*DIS_BYPASS_CAP 0x22 */ + int dis_bypass_cap(bpctl_dev_t *pbpctl_dev) + { + + if (pbpctl_dev->bp_caps & BP_DIS_CAP) { + if (INTEL_IF_SERIES(pbpctl_dev->subdevice)) { + write_data_int(pbpctl_dev, DIS_BYPASS_CAP_INT); + msec_delay_bp(BYPASS_DELAY_INT); + } else { + write_data(pbpctl_dev, BYPASS_OFF); + msec_delay_bp(LATCH_DELAY); + write_data(pbpctl_dev, DIS_BYPASS_CAP); + msec_delay_bp(BYPASS_CAP_DELAY); + } + return 0; + } + return BP_NOT_CAP; + } + + /*EN_BYPASS_CAP 0x24 */ + int en_bypass_cap(bpctl_dev_t *pbpctl_dev) + { + if (pbpctl_dev->bp_caps & BP_DIS_CAP) { + if (INTEL_IF_SERIES(pbpctl_dev->subdevice)) { + write_data_int(pbpctl_dev, PWROFF_BYPASS_ON_INT); + msec_delay_bp(BYPASS_DELAY_INT); + } else { + write_data(pbpctl_dev, EN_BYPASS_CAP); + msec_delay_bp(BYPASS_CAP_DELAY); + } + return 0; + } + return BP_NOT_CAP; + } + + /* BYPASS_STATE_PWRON 0x26*/ + int bypass_state_pwron(bpctl_dev_t *pbpctl_dev) + { + if (pbpctl_dev->bp_caps & BP_PWUP_CTL_CAP) { + write_data(pbpctl_dev, BYPASS_STATE_PWRON); + if (pbpctl_dev->bp_ext_ver == PXG2BPI_VER) + msec_delay_bp(DFLT_PWRON_DELAY); + else + msec_delay_bp(LATCH_DELAY + EEPROM_WR_DELAY); + return 0; + } + return BP_NOT_CAP; + } + + /* NORMAL_STATE_PWRON 0x28*/ + int normal_state_pwron(bpctl_dev_t *pbpctl_dev) + { + if ((pbpctl_dev->bp_caps & BP_PWUP_CTL_CAP) + || (pbpctl_dev->bp_caps & TAP_PWUP_CTL_CAP)) { + write_data(pbpctl_dev, NORMAL_STATE_PWRON); + if (pbpctl_dev->bp_ext_ver == PXG2BPI_VER) + msec_delay_bp(DFLT_PWRON_DELAY); + else + msec_delay_bp(LATCH_DELAY + EEPROM_WR_DELAY); + return 0; + } + return BP_NOT_CAP; + } + + /* BYPASS_STATE_PWROFF 0x27*/ + int bypass_state_pwroff(bpctl_dev_t *pbpctl_dev) + { + if (pbpctl_dev->bp_caps & BP_PWOFF_CTL_CAP) { + write_data(pbpctl_dev, BYPASS_STATE_PWROFF); + msec_delay_bp(LATCH_DELAY + EEPROM_WR_DELAY); + return 0; + } + return BP_NOT_CAP; + } + + /* NORMAL_STATE_PWROFF 0x29*/ + int normal_state_pwroff(bpctl_dev_t *pbpctl_dev) + { + if ((pbpctl_dev->bp_caps & BP_PWOFF_CTL_CAP)) { + write_data(pbpctl_dev, NORMAL_STATE_PWROFF); + msec_delay_bp(LATCH_DELAY + EEPROM_WR_DELAY); + return 0; + } + return BP_NOT_CAP; + } + + /*TAP_STATE_PWRON 0x2a*/ + int tap_state_pwron(bpctl_dev_t *pbpctl_dev) + { + if (pbpctl_dev->bp_caps & TAP_PWUP_CTL_CAP) { + write_data(pbpctl_dev, TAP_STATE_PWRON); + msec_delay_bp(LATCH_DELAY + EEPROM_WR_DELAY); + return 0; + } + return BP_NOT_CAP; + } + + /*DIS_TAP_CAP 0x2c*/ + int dis_tap_cap(bpctl_dev_t *pbpctl_dev) + { + if (pbpctl_dev->bp_caps & TAP_DIS_CAP) { + write_data(pbpctl_dev, DIS_TAP_CAP); + msec_delay_bp(BYPASS_CAP_DELAY); + return 0; + } + return BP_NOT_CAP; + } + + /*EN_TAP_CAP 0x2e*/ + int en_tap_cap(bpctl_dev_t *pbpctl_dev) + { + if (pbpctl_dev->bp_caps & TAP_DIS_CAP) { + write_data(pbpctl_dev, EN_TAP_CAP); + msec_delay_bp(BYPASS_CAP_DELAY); + return 0; + } + return BP_NOT_CAP; + } + + /*DISC_STATE_PWRON 0x2a*/ + int disc_state_pwron(bpctl_dev_t *pbpctl_dev) + { + if (pbpctl_dev->bp_caps & DISC_PWUP_CTL_CAP) { + if (pbpctl_dev->bp_ext_ver >= 0x8) { + write_data(pbpctl_dev, DISC_STATE_PWRON); + msec_delay_bp(LATCH_DELAY + EEPROM_WR_DELAY); + return BP_OK; + } + } + return BP_NOT_CAP; + } + + /*DIS_DISC_CAP 0x2c*/ + int dis_disc_cap(bpctl_dev_t *pbpctl_dev) + { + if (pbpctl_dev->bp_caps & DISC_DIS_CAP) { + if (pbpctl_dev->bp_ext_ver >= 0x8) { + write_data(pbpctl_dev, DIS_DISC_CAP); + msec_delay_bp(BYPASS_CAP_DELAY); + return BP_OK; + } + } + return BP_NOT_CAP; + } + + /*DISC_STATE_PWRON 0x2a*/ + int disc_port_state_pwron(bpctl_dev_t *pbpctl_dev) + { + int ret = 0; + bpctl_dev_t *pbpctl_dev_m; + + return BP_NOT_CAP; + + if ((is_bypass_fn(pbpctl_dev)) == 1) + pbpctl_dev_m = pbpctl_dev; + else + pbpctl_dev_m = get_master_port_fn(pbpctl_dev); + if (pbpctl_dev_m == NULL) + return BP_NOT_CAP; + + if (pbpctl_dev_m->bp_caps_ex & DISC_PORT_CAP_EX) { + if (is_bypass_fn(pbpctl_dev) == 1) + write_data(pbpctl_dev_m, TX_DISA_PWRUP); + else + write_data(pbpctl_dev_m, TX_DISB_PWRUP); + + msec_delay_bp(LATCH_DELAY); + + } + return ret; + } + + int normal_port_state_pwron(bpctl_dev_t *pbpctl_dev) + { + int ret = 0; + bpctl_dev_t *pbpctl_dev_m; + return BP_NOT_CAP; + + if ((is_bypass_fn(pbpctl_dev)) == 1) + pbpctl_dev_m = pbpctl_dev; + else + pbpctl_dev_m = get_master_port_fn(pbpctl_dev); + if (pbpctl_dev_m == NULL) + return BP_NOT_CAP; + + if (pbpctl_dev_m->bp_caps_ex & DISC_PORT_CAP_EX) { + if (is_bypass_fn(pbpctl_dev) == 1) + write_data(pbpctl_dev_m, TX_ENA_PWRUP); + else + write_data(pbpctl_dev_m, TX_ENB_PWRUP); + + msec_delay_bp(LATCH_DELAY); + + } + return ret; + } + + /*EN_TAP_CAP 0x2e*/ + int en_disc_cap(bpctl_dev_t *pbpctl_dev) + { + if (pbpctl_dev->bp_caps & DISC_DIS_CAP) { + if (pbpctl_dev->bp_ext_ver >= 0x8) { + write_data(pbpctl_dev, EN_DISC_CAP); + msec_delay_bp(BYPASS_CAP_DELAY); + return BP_OK; + } + } + return BP_NOT_CAP; + } + + int std_nic_on(bpctl_dev_t *pbpctl_dev) + { + + if (pbpctl_dev->bp_caps & STD_NIC_CAP) { + + if (INTEL_IF_SERIES(pbpctl_dev->subdevice)) { + write_data_int(pbpctl_dev, DIS_BYPASS_CAP_INT); + msec_delay_bp(BYPASS_DELAY_INT); + pbpctl_dev->bp_status_un = 0; + return BP_OK; + } + + if (pbpctl_dev->bp_ext_ver >= 0x8) { + write_data(pbpctl_dev, STD_NIC_ON); + msec_delay_bp(BYPASS_CAP_DELAY); + return BP_OK; + + } + + if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) { + wdt_off(pbpctl_dev); + + if (pbpctl_dev->bp_caps & BP_CAP) { + write_data(pbpctl_dev, BYPASS_OFF); + msec_delay_bp(LATCH_DELAY); + } + + if (pbpctl_dev->bp_caps & TAP_CAP) { + write_data(pbpctl_dev, TAP_OFF); + msec_delay_bp(LATCH_DELAY); + } + + write_data(pbpctl_dev, NORMAL_STATE_PWRON); + if (pbpctl_dev->bp_ext_ver == PXG2BPI_VER) + msec_delay_bp(DFLT_PWRON_DELAY); + else + msec_delay_bp(LATCH_DELAY + EEPROM_WR_DELAY); + + if (pbpctl_dev->bp_caps & BP_DIS_CAP) { + write_data(pbpctl_dev, DIS_BYPASS_CAP); + msec_delay_bp(BYPASS_CAP_DELAY); + } + + if (pbpctl_dev->bp_caps & TAP_DIS_CAP) { + write_data(pbpctl_dev, DIS_TAP_CAP); + msec_delay_bp(BYPASS_CAP_DELAY); + + } + return 0; + } + } + return BP_NOT_CAP; + } + + int std_nic_off(bpctl_dev_t *pbpctl_dev) + { + + if (pbpctl_dev->bp_caps & STD_NIC_CAP) { + if (INTEL_IF_SERIES(pbpctl_dev->subdevice)) { + write_data_int(pbpctl_dev, PWROFF_BYPASS_ON_INT); + msec_delay_bp(BYPASS_DELAY_INT); + return BP_OK; + } + if (pbpctl_dev->bp_ext_ver >= 0x8) { + write_data(pbpctl_dev, STD_NIC_OFF); + msec_delay_bp(BYPASS_CAP_DELAY); + return BP_OK; + + } + + if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) { + + if (pbpctl_dev->bp_caps & TAP_PWUP_CTL_CAP) { + write_data(pbpctl_dev, TAP_STATE_PWRON); + msec_delay_bp(LATCH_DELAY + EEPROM_WR_DELAY); + } + + if (pbpctl_dev->bp_caps & BP_PWUP_CTL_CAP) { + write_data(pbpctl_dev, BYPASS_STATE_PWRON); + if (pbpctl_dev->bp_ext_ver > PXG2BPI_VER) + msec_delay_bp(LATCH_DELAY + + EEPROM_WR_DELAY); + else + msec_delay_bp(DFLT_PWRON_DELAY); + } + + if (pbpctl_dev->bp_caps & TAP_DIS_CAP) { + write_data(pbpctl_dev, EN_TAP_CAP); + msec_delay_bp(BYPASS_CAP_DELAY); + } + if (pbpctl_dev->bp_caps & DISC_DIS_CAP) { + write_data(pbpctl_dev, EN_DISC_CAP); + msec_delay_bp(BYPASS_CAP_DELAY); + } + + if (pbpctl_dev->bp_caps & BP_DIS_CAP) { + write_data(pbpctl_dev, EN_BYPASS_CAP); + msec_delay_bp(BYPASS_CAP_DELAY); + } + + return 0; + } + } + return BP_NOT_CAP; + } + + int wdt_time_left(bpctl_dev_t *pbpctl_dev) + { + + /* unsigned long curr_time=((long long)(jiffies*1000))/HZ, delta_time=0,wdt_on_time=((long long)(pbpctl_dev->bypass_wdt_on_time*1000))/HZ; */ + unsigned long curr_time = jiffies, delta_time = 0, wdt_on_time = + pbpctl_dev->bypass_wdt_on_time, delta_time_msec = 0; + int time_left = 0; + + switch (pbpctl_dev->wdt_status) { + case WDT_STATUS_DIS: + time_left = 0; + break; + case WDT_STATUS_EN: + delta_time = + (curr_time >= + wdt_on_time) ? (curr_time - wdt_on_time) : (~wdt_on_time + + curr_time); + delta_time_msec = jiffies_to_msecs(delta_time); + time_left = pbpctl_dev->bypass_timer_interval - delta_time_msec; + if (time_left < 0) { + time_left = -1; + pbpctl_dev->wdt_status = WDT_STATUS_EXP; + } + break; + case WDT_STATUS_EXP: + time_left = -1; + break; + } + + return time_left; + } + + static int wdt_timer(bpctl_dev_t *pbpctl_dev, int *time_left) + { + int ret = 0; + if (pbpctl_dev->bp_caps & WD_CTL_CAP) { + { + if (pbpctl_dev->wdt_status == WDT_STATUS_UNKNOWN) + ret = BP_NOT_CAP; + else + *time_left = wdt_time_left(pbpctl_dev); + } + + } else + ret = BP_NOT_CAP; + return ret; + } + + static int wdt_timer_reload(bpctl_dev_t *pbpctl_dev) + { + + int ret = 0; + + if ((pbpctl_dev->bp_caps & WD_CTL_CAP) && + (pbpctl_dev->wdt_status != WDT_STATUS_UNKNOWN)) { + if (pbpctl_dev->wdt_status == WDT_STATUS_DIS) + return 0; + if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) + ret = wdt_pulse(pbpctl_dev); + else if (INTEL_IF_SERIES(pbpctl_dev->subdevice)) + ret = wdt_pulse_int(pbpctl_dev); + else + ret = send_wdt_pulse(pbpctl_dev); + /* if (ret==-1) + mod_timer(&pbpctl_dev->bp_timer, jiffies+1);*/ + return 1; + } + return BP_NOT_CAP; + } + + static void wd_reset_timer(unsigned long param) + { + bpctl_dev_t *pbpctl_dev = (bpctl_dev_t *) param; + #ifdef BP_SELF_TEST + struct sk_buff *skb_tmp; + #endif + + if ((pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) && + ((atomic_read(&pbpctl_dev->wdt_busy)) == 1)) { + mod_timer(&pbpctl_dev->bp_timer, jiffies + 1); + return; + } + #ifdef BP_SELF_TEST + + if (pbpctl_dev->bp_self_test_flag == 1) { + skb_tmp = dev_alloc_skb(BPTEST_DATA_LEN + 2); + if ((skb_tmp) && (pbpctl_dev->ndev) && (pbpctl_dev->bp_tx_data)) { + memcpy(skb_put(skb_tmp, BPTEST_DATA_LEN), + pbpctl_dev->bp_tx_data, BPTEST_DATA_LEN); + skb_tmp->dev = pbpctl_dev->ndev; + skb_tmp->protocol = + eth_type_trans(skb_tmp, pbpctl_dev->ndev); + skb_tmp->ip_summed = CHECKSUM_UNNECESSARY; + netif_receive_skb(skb_tmp); + goto bp_timer_reload; + return; + } + } + #endif + + wdt_timer_reload(pbpctl_dev); + #ifdef BP_SELF_TEST + bp_timer_reload: + #endif + if (pbpctl_dev->reset_time) { + mod_timer(&pbpctl_dev->bp_timer, + jiffies + (HZ * pbpctl_dev->reset_time) / 1000); + } + } + + /*WAIT_AT_PWRUP 0x80 */ + int bp_wait_at_pwup_en(bpctl_dev_t *pbpctl_dev) + { + + if (pbpctl_dev->bp_caps & SW_CTL_CAP) { + if (pbpctl_dev->bp_ext_ver >= BP_FW_EXT_VER8) { + write_data(pbpctl_dev, BP_WAIT_AT_PWUP_EN); + msec_delay_bp(LATCH_DELAY + EEPROM_WR_DELAY); + + return BP_OK; + } + } + return BP_NOT_CAP; + } + + /*DIS_WAIT_AT_PWRUP 0x81 */ + int bp_wait_at_pwup_dis(bpctl_dev_t *pbpctl_dev) + { + + if (pbpctl_dev->bp_caps & SW_CTL_CAP) { + + if (pbpctl_dev->bp_ext_ver >= BP_FW_EXT_VER8) { + write_data(pbpctl_dev, BP_WAIT_AT_PWUP_DIS); + msec_delay_bp(LATCH_DELAY + EEPROM_WR_DELAY); + + return BP_OK; + } + } + return BP_NOT_CAP; + } + + /*EN_HW_RESET 0x82 */ + + int bp_hw_reset_en(bpctl_dev_t *pbpctl_dev) + { + + if (pbpctl_dev->bp_caps & SW_CTL_CAP) { + if (pbpctl_dev->bp_ext_ver >= BP_FW_EXT_VER8) { + write_data(pbpctl_dev, BP_HW_RESET_EN); + msec_delay_bp(LATCH_DELAY + EEPROM_WR_DELAY); + + return BP_OK; + } + } + return BP_NOT_CAP; + } + + /*DIS_HW_RESET 0x83 */ + + int bp_hw_reset_dis(bpctl_dev_t *pbpctl_dev) + { + + if (pbpctl_dev->bp_caps & SW_CTL_CAP) { + if (pbpctl_dev->bp_ext_ver >= BP_FW_EXT_VER8) { + write_data(pbpctl_dev, BP_HW_RESET_DIS); + msec_delay_bp(LATCH_DELAY + EEPROM_WR_DELAY); + + return BP_OK; + } + } + return BP_NOT_CAP; + } + + + int wdt_exp_mode(bpctl_dev_t *pbpctl_dev, int mode) + { + uint32_t status_reg = 0, status_reg1 = 0; + + if ((pbpctl_dev->bp_caps & (TAP_STATUS_CAP | DISC_CAP)) && + (pbpctl_dev->bp_caps & BP_CAP)) { + if (pbpctl_dev->bp_ext_ver >= PXE2TBPI_VER) { + + if ((pbpctl_dev->bp_ext_ver >= 0x8) && + (mode == 2) && (pbpctl_dev->bp_caps & DISC_CAP)) { + status_reg1 = + read_reg(pbpctl_dev, STATUS_DISC_REG_ADDR); + if (!(status_reg1 & WDTE_DISC_BPN_MASK)) + write_reg(pbpctl_dev, + status_reg1 | + WDTE_DISC_BPN_MASK, + STATUS_DISC_REG_ADDR); + return BP_OK; + } + } + status_reg = read_reg(pbpctl_dev, STATUS_TAP_REG_ADDR); + + if ((mode == 0) && (pbpctl_dev->bp_caps & BP_CAP)) { + if (pbpctl_dev->bp_ext_ver >= 0x8) { + status_reg1 = + read_reg(pbpctl_dev, STATUS_DISC_REG_ADDR); + if (status_reg1 & WDTE_DISC_BPN_MASK) + write_reg(pbpctl_dev, + status_reg1 & + ~WDTE_DISC_BPN_MASK, + STATUS_DISC_REG_ADDR); + } + if (status_reg & WDTE_TAP_BPN_MASK) + write_reg(pbpctl_dev, + status_reg & ~WDTE_TAP_BPN_MASK, + STATUS_TAP_REG_ADDR); + return BP_OK; + + } else if ((mode == 1) && (pbpctl_dev->bp_caps & TAP_CAP)) { + if (!(status_reg & WDTE_TAP_BPN_MASK)) + write_reg(pbpctl_dev, + status_reg | WDTE_TAP_BPN_MASK, + STATUS_TAP_REG_ADDR); + /*else return BP_NOT_CAP; */ + return BP_OK; + } + + } + return BP_NOT_CAP; + } + + int bypass_fw_ver(bpctl_dev_t *pbpctl_dev) + { + if (is_bypass_fn(pbpctl_dev)) + return read_reg(pbpctl_dev, VER_REG_ADDR); + else + return BP_NOT_CAP; + } + + int bypass_sign_check(bpctl_dev_t *pbpctl_dev) + { + + if (is_bypass_fn(pbpctl_dev)) + return (((read_reg(pbpctl_dev, PIC_SIGN_REG_ADDR)) == + PIC_SIGN_VALUE) ? 1 : 0); + else + return BP_NOT_CAP; + } + + static int tx_status(bpctl_dev_t *pbpctl_dev) + { + uint32_t ctrl = 0; + bpctl_dev_t *pbpctl_dev_m; + if ((is_bypass_fn(pbpctl_dev)) == 1) + pbpctl_dev_m = pbpctl_dev; + else + pbpctl_dev_m = get_master_port_fn(pbpctl_dev); + if (pbpctl_dev_m == NULL) + return BP_NOT_CAP; + if (pbpctl_dev_m->bp_caps_ex & DISC_PORT_CAP_EX) { + + ctrl = BPCTL_READ_REG(pbpctl_dev, CTRL); + if (pbpctl_dev->bp_i80) + return ((ctrl & BPCTLI_CTRL_SWDPIN1) != 0 ? 0 : 1); + if (pbpctl_dev->bp_540) { + ctrl = BP10G_READ_REG(pbpctl_dev, ESDP); + + return ((ctrl & BP10G_SDP1_DATA) != 0 ? 0 : 1); + } + + } + + if (pbpctl_dev->bp_caps & TX_CTL_CAP) { + if (PEG5_IF_SERIES(pbpctl_dev->subdevice)) { + uint16_t mii_reg; + if (! + (bp75_read_phy_reg + (pbpctl_dev, BPCTLI_PHY_CONTROL, &mii_reg))) { + if (mii_reg & BPCTLI_MII_CR_POWER_DOWN) + return 0; + + else + return 1; + } + return -1; + } + + if (pbpctl_dev->bp_10g9) { + return ((BP10G_READ_REG(pbpctl_dev, ESDP) & + BP10G_SDP3_DATA) != 0 ? 0 : 1); + + } else if (pbpctl_dev->bp_fiber5) { + ctrl = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT); + if (ctrl & BPCTLI_CTRL_EXT_SDP6_DATA) + return 0; + return 1; + } else if (pbpctl_dev->bp_10gb) { + ctrl = BP10GB_READ_REG(pbpctl_dev, MISC_REG_GPIO); + BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_GPIO, + (ctrl | BP10GB_GPIO0_OE_P1) & + ~(BP10GB_GPIO0_SET_P1 | + BP10GB_GPIO0_CLR_P1)); + + if ((pbpctl_dev->func == 1) || (pbpctl_dev->func == 3)) + return (((BP10GB_READ_REG + (pbpctl_dev, + MISC_REG_GPIO)) & BP10GB_GPIO0_P1) != + 0 ? 0 : 1); + else + return (((BP10GB_READ_REG + (pbpctl_dev, + MISC_REG_GPIO)) & BP10GB_GPIO0_P0) != + 0 ? 0 : 1); + } + + if (!pbpctl_dev->bp_10g) { + + ctrl = BPCTL_READ_REG(pbpctl_dev, CTRL); + if (pbpctl_dev->bp_i80) + return ((ctrl & BPCTLI_CTRL_SWDPIN1) != + 0 ? 0 : 1); + if (pbpctl_dev->bp_540) { + ctrl = BP10G_READ_REG(pbpctl_dev, ESDP); + + return ((ctrl & BP10G_SDP1_DATA) != 0 ? 0 : 1); + } + + return ((ctrl & BPCTLI_CTRL_SWDPIN0) != 0 ? 0 : 1); + } else + return ((BP10G_READ_REG(pbpctl_dev, ESDP) & + BP10G_SDP0_DATA) != 0 ? 0 : 1); + + } + return BP_NOT_CAP; + } + + static int bp_force_link_status(bpctl_dev_t *pbpctl_dev) + { + + if (DBI_IF_SERIES(pbpctl_dev->subdevice)) { + + if ((pbpctl_dev->bp_10g) || (pbpctl_dev->bp_10g9)) { + return ((BP10G_READ_REG(pbpctl_dev, ESDP) & + BP10G_SDP1_DIR) != 0 ? 1 : 0); + + } + } + return BP_NOT_CAP; + } + + int bypass_from_last_read(bpctl_dev_t *pbpctl_dev) + { + uint32_t ctrl_ext = 0; + bpctl_dev_t *pbpctl_dev_b = NULL; + + if ((pbpctl_dev->bp_caps & SW_CTL_CAP) + && (pbpctl_dev_b = get_status_port_fn(pbpctl_dev))) { + ctrl_ext = BPCTL_READ_REG(pbpctl_dev_b, CTRL_EXT); + BPCTL_BP_WRITE_REG(pbpctl_dev_b, CTRL_EXT, + (ctrl_ext & ~BPCTLI_CTRL_EXT_SDP7_DIR)); + ctrl_ext = BPCTL_READ_REG(pbpctl_dev_b, CTRL_EXT); + if (ctrl_ext & BPCTLI_CTRL_EXT_SDP7_DATA) + return 0; + return 1; + } else + return BP_NOT_CAP; + } + + int bypass_status_clear(bpctl_dev_t *pbpctl_dev) + { + bpctl_dev_t *pbpctl_dev_b = NULL; + + if ((pbpctl_dev->bp_caps & SW_CTL_CAP) + && (pbpctl_dev_b = get_status_port_fn(pbpctl_dev))) { + + send_bypass_clear_pulse(pbpctl_dev_b, 1); + return 0; + } else + return BP_NOT_CAP; + } + + int bypass_flag_status(bpctl_dev_t *pbpctl_dev) + { + + if ((pbpctl_dev->bp_caps & BP_CAP)) { + if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) { + return ((((read_reg(pbpctl_dev, STATUS_REG_ADDR)) & + BYPASS_FLAG_MASK) == + BYPASS_FLAG_MASK) ? 1 : 0); + } + } + return BP_NOT_CAP; + } + + int bypass_flag_status_clear(bpctl_dev_t *pbpctl_dev) + { + + if (pbpctl_dev->bp_caps & BP_CAP) { + if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) { + uint32_t status_reg = 0; + status_reg = read_reg(pbpctl_dev, STATUS_REG_ADDR); + write_reg(pbpctl_dev, status_reg & ~BYPASS_FLAG_MASK, + STATUS_REG_ADDR); + return 0; + } + } + return BP_NOT_CAP; + } + + int bypass_change_status(bpctl_dev_t *pbpctl_dev) + { + int ret = BP_NOT_CAP; + + if (pbpctl_dev->bp_caps & BP_STATUS_CHANGE_CAP) { + if (pbpctl_dev->bp_ext_ver >= 0x8) { + ret = bypass_flag_status(pbpctl_dev); + bypass_flag_status_clear(pbpctl_dev); + } else if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) { + ret = bypass_flag_status(pbpctl_dev); + bypass_flag_status_clear(pbpctl_dev); + } else { + ret = bypass_from_last_read(pbpctl_dev); + bypass_status_clear(pbpctl_dev); + } + } + return ret; + } + + int bypass_off_status(bpctl_dev_t *pbpctl_dev) + { + + if (pbpctl_dev->bp_caps & BP_CAP) { + if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) { + return ((((read_reg(pbpctl_dev, STATUS_REG_ADDR)) & + BYPASS_OFF_MASK) == BYPASS_OFF_MASK) ? 1 : 0); + } + } + return BP_NOT_CAP; + } + + static int bypass_status(bpctl_dev_t *pbpctl_dev) + { + u32 ctrl_ext = 0; + if (pbpctl_dev->bp_caps & BP_CAP) { + + bpctl_dev_t *pbpctl_dev_b = NULL; + + if (!(pbpctl_dev_b = get_status_port_fn(pbpctl_dev))) + return BP_NOT_CAP; + + if (INTEL_IF_SERIES(pbpctl_dev->subdevice)) { + + if (!pbpctl_dev->bp_status_un) + return (((BPCTL_READ_REG + (pbpctl_dev_b, + CTRL_EXT)) & + BPCTLI_CTRL_EXT_SDP7_DATA) != + 0 ? 1 : 0); + else + return BP_NOT_CAP; + } + if (pbpctl_dev->bp_ext_ver >= 0x8) { + + if (pbpctl_dev->bp_10g9) { + ctrl_ext = BP10G_READ_REG(pbpctl_dev_b, I2CCTL); + BP10G_WRITE_REG(pbpctl_dev_b, I2CCTL, + (ctrl_ext | BP10G_I2C_CLK_OUT)); + return ((BP10G_READ_REG(pbpctl_dev_b, I2CCTL) & + BP10G_I2C_CLK_IN) != 0 ? 0 : 1); + + } else if (pbpctl_dev->bp_540) { + return (((BP10G_READ_REG(pbpctl_dev_b, ESDP)) & + BP10G_SDP0_DATA) != 0 ? 0 : 1); + } + + else if ((pbpctl_dev->bp_fiber5) + || (pbpctl_dev->bp_i80)) { + return (((BPCTL_READ_REG(pbpctl_dev_b, CTRL)) & + BPCTLI_CTRL_SWDPIN0) != 0 ? 0 : 1); + } else if (pbpctl_dev->bp_10gb) { + ctrl_ext = + BP10GB_READ_REG(pbpctl_dev, MISC_REG_GPIO); + BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_GPIO, + (ctrl_ext | BP10GB_GPIO3_OE_P0) + & ~(BP10GB_GPIO3_SET_P0 | + BP10GB_GPIO3_CLR_P0)); + + return (((BP10GB_READ_REG + (pbpctl_dev, + MISC_REG_GPIO)) & BP10GB_GPIO3_P0) != + 0 ? 0 : 1); + } + + else if (!pbpctl_dev->bp_10g) + return (((BPCTL_READ_REG + (pbpctl_dev_b, + CTRL_EXT)) & + BPCTLI_CTRL_EXT_SDP7_DATA) != + 0 ? 0 : 1); + + else { + ctrl_ext = BP10G_READ_REG(pbpctl_dev_b, EODSDP); + BP10G_WRITE_REG(pbpctl_dev_b, EODSDP, + (ctrl_ext | + BP10G_SDP7_DATA_OUT)); + return ((BP10G_READ_REG(pbpctl_dev_b, EODSDP) & + BP10G_SDP7_DATA_IN) != 0 ? 0 : 1); + } + + } else if (pbpctl_dev->media_type == bp_copper) { + + return (((BPCTL_READ_REG(pbpctl_dev_b, CTRL)) & + BPCTLI_CTRL_SWDPIN1) != 0 ? 1 : 0); + } else { + if ((bypass_status_clear(pbpctl_dev)) >= 0) + return bypass_from_last_read(pbpctl_dev); + } + + } + return BP_NOT_CAP; + } + + int default_pwron_status(bpctl_dev_t *pbpctl_dev) + { + + if (pbpctl_dev->bp_caps & SW_CTL_CAP) { + if (pbpctl_dev->bp_caps & BP_PWUP_CTL_CAP) { + if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) { + return ((((read_reg + (pbpctl_dev, + STATUS_REG_ADDR)) & DFLT_PWRON_MASK) + == DFLT_PWRON_MASK) ? 0 : 1); + } + } /*else if ((!pbpctl_dev->bp_caps&BP_DIS_CAP)&& + (pbpctl_dev->bp_caps&BP_PWUP_ON_CAP)) + return 1; */ + } + return BP_NOT_CAP; + } + + static int default_pwroff_status(bpctl_dev_t *pbpctl_dev) + { + + /*if ((!pbpctl_dev->bp_caps&BP_DIS_CAP)&& + (pbpctl_dev->bp_caps&BP_PWOFF_ON_CAP)) + return 1; */ + if ((pbpctl_dev->bp_caps & SW_CTL_CAP) + && (pbpctl_dev->bp_caps & BP_PWOFF_CTL_CAP)) { + return ((((read_reg(pbpctl_dev, STATUS_REG_ADDR)) & + DFLT_PWROFF_MASK) == DFLT_PWROFF_MASK) ? 0 : 1); + } + return BP_NOT_CAP; + } + + int dis_bypass_cap_status(bpctl_dev_t *pbpctl_dev) + { + + if (pbpctl_dev->bp_caps & BP_DIS_CAP) { + if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) { + return ((((read_reg(pbpctl_dev, STATUS_REG_ADDR)) & + DIS_BYPASS_CAP_MASK) == + DIS_BYPASS_CAP_MASK) ? 1 : 0); + } + } + return BP_NOT_CAP; + } + + int cmd_en_status(bpctl_dev_t *pbpctl_dev) + { + + if (pbpctl_dev->bp_caps & SW_CTL_CAP) { + if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) { + return ((((read_reg(pbpctl_dev, STATUS_REG_ADDR)) & + CMND_EN_MASK) == CMND_EN_MASK) ? 1 : 0); + } + } + return BP_NOT_CAP; + } + + int wdt_en_status(bpctl_dev_t *pbpctl_dev) + { + + if (pbpctl_dev->bp_caps & WD_CTL_CAP) { + if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) { + return ((((read_reg(pbpctl_dev, STATUS_REG_ADDR)) & + WDT_EN_MASK) == WDT_EN_MASK) ? 1 : 0); + } + } + return BP_NOT_CAP; + } + + int wdt_programmed(bpctl_dev_t *pbpctl_dev, int *timeout) + { + int ret = 0; + if (pbpctl_dev->bp_caps & WD_CTL_CAP) { + if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) { + if ((read_reg(pbpctl_dev, STATUS_REG_ADDR)) & + WDT_EN_MASK) { + u8 wdt_val; + wdt_val = read_reg(pbpctl_dev, WDT_REG_ADDR); + *timeout = (1 << wdt_val) * 100; + } else + *timeout = 0; + } else { + int curr_wdt_status = pbpctl_dev->wdt_status; + if (curr_wdt_status == WDT_STATUS_UNKNOWN) + *timeout = -1; + else + *timeout = + curr_wdt_status == + 0 ? 0 : pbpctl_dev->bypass_timer_interval; + }; + } else + ret = BP_NOT_CAP; + return ret; + } + + int bypass_support(bpctl_dev_t *pbpctl_dev) + { + int ret = 0; + + if (pbpctl_dev->bp_caps & SW_CTL_CAP) { + if (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER) { + ret = + ((((read_reg(pbpctl_dev, PRODUCT_CAP_REG_ADDR)) & + BYPASS_SUPPORT_MASK) == + BYPASS_SUPPORT_MASK) ? 1 : 0); + } else if (pbpctl_dev->bp_ext_ver == PXG2BPI_VER) + ret = 1; + } else + ret = BP_NOT_CAP; + return ret; + } + + int tap_support(bpctl_dev_t *pbpctl_dev) + { + int ret = 0; + + if (pbpctl_dev->bp_caps & SW_CTL_CAP) { + if (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER) { + ret = + ((((read_reg(pbpctl_dev, PRODUCT_CAP_REG_ADDR)) & + TAP_SUPPORT_MASK) == TAP_SUPPORT_MASK) ? 1 : 0); + } else if (pbpctl_dev->bp_ext_ver == PXG2BPI_VER) + ret = 0; + } else + ret = BP_NOT_CAP; + return ret; + } + + int normal_support(bpctl_dev_t *pbpctl_dev) + { + int ret = BP_NOT_CAP; + + if (pbpctl_dev->bp_caps & SW_CTL_CAP) { + if (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER) { + ret = + ((((read_reg(pbpctl_dev, PRODUCT_CAP_REG_ADDR)) & + NORMAL_UNSUPPORT_MASK) == + NORMAL_UNSUPPORT_MASK) ? 0 : 1); + } else + ret = 1; + }; + return ret; + } + + int get_bp_prod_caps(bpctl_dev_t *pbpctl_dev) + { + if ((pbpctl_dev->bp_caps & SW_CTL_CAP) && + (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER)) + return read_reg(pbpctl_dev, PRODUCT_CAP_REG_ADDR); + return BP_NOT_CAP; + + } + + int tap_flag_status(bpctl_dev_t *pbpctl_dev) + { + + if (pbpctl_dev->bp_caps & TAP_STATUS_CAP) { + if (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER) + return ((((read_reg(pbpctl_dev, STATUS_TAP_REG_ADDR)) & + TAP_FLAG_MASK) == TAP_FLAG_MASK) ? 1 : 0); + + } + return BP_NOT_CAP; + } + + int tap_flag_status_clear(bpctl_dev_t *pbpctl_dev) + { + uint32_t status_reg = 0; + if (pbpctl_dev->bp_caps & TAP_STATUS_CAP) { + if (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER) { + status_reg = read_reg(pbpctl_dev, STATUS_TAP_REG_ADDR); + write_reg(pbpctl_dev, status_reg & ~TAP_FLAG_MASK, + STATUS_TAP_REG_ADDR); + return 0; + } + } + return BP_NOT_CAP; + } + + int tap_change_status(bpctl_dev_t *pbpctl_dev) + { + int ret = BP_NOT_CAP; + if (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER) { + if (pbpctl_dev->bp_caps & TAP_CAP) { + if (pbpctl_dev->bp_caps & BP_CAP) { + ret = tap_flag_status(pbpctl_dev); + tap_flag_status_clear(pbpctl_dev); + } else { + ret = bypass_from_last_read(pbpctl_dev); + bypass_status_clear(pbpctl_dev); + } + } + } + return ret; + } + + int tap_off_status(bpctl_dev_t *pbpctl_dev) + { + if (pbpctl_dev->bp_caps & TAP_CAP) { + if (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER) + return ((((read_reg(pbpctl_dev, STATUS_TAP_REG_ADDR)) & + TAP_OFF_MASK) == TAP_OFF_MASK) ? 1 : 0); + } + return BP_NOT_CAP; + } + + int tap_status(bpctl_dev_t *pbpctl_dev) + { + u32 ctrl_ext = 0; + + if (pbpctl_dev->bp_caps & TAP_CAP) { + bpctl_dev_t *pbpctl_dev_b = NULL; + + if (!(pbpctl_dev_b = get_status_port_fn(pbpctl_dev))) + return BP_NOT_CAP; + + if (pbpctl_dev->bp_ext_ver >= 0x8) { + if (!pbpctl_dev->bp_10g) + return (((BPCTL_READ_REG + (pbpctl_dev_b, + CTRL_EXT)) & + BPCTLI_CTRL_EXT_SDP6_DATA) != + 0 ? 0 : 1); + else { + ctrl_ext = BP10G_READ_REG(pbpctl_dev_b, EODSDP); + BP10G_WRITE_REG(pbpctl_dev_b, EODSDP, + (ctrl_ext | + BP10G_SDP6_DATA_OUT)); + return ((BP10G_READ_REG(pbpctl_dev_b, EODSDP) & + BP10G_SDP6_DATA_IN) != 0 ? 0 : 1); + } + + } else if (pbpctl_dev->media_type == bp_copper) + return (((BPCTL_READ_REG(pbpctl_dev, CTRL)) & + BPCTLI_CTRL_SWDPIN0) != 0 ? 1 : 0); + else { + if ((bypass_status_clear(pbpctl_dev)) >= 0) + return bypass_from_last_read(pbpctl_dev); + } + + } + return BP_NOT_CAP; + } + + int default_pwron_tap_status(bpctl_dev_t *pbpctl_dev) + { + if (pbpctl_dev->bp_caps & TAP_PWUP_CTL_CAP) { + if (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER) + return ((((read_reg(pbpctl_dev, STATUS_TAP_REG_ADDR)) & + DFLT_PWRON_TAP_MASK) == + DFLT_PWRON_TAP_MASK) ? 1 : 0); + } + return BP_NOT_CAP; + } + + int dis_tap_cap_status(bpctl_dev_t *pbpctl_dev) + { + if (pbpctl_dev->bp_caps & TAP_PWUP_CTL_CAP) { + if (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER) + return ((((read_reg(pbpctl_dev, STATUS_TAP_REG_ADDR)) & + DIS_TAP_CAP_MASK) == + DIS_TAP_CAP_MASK) ? 1 : 0); + } + return BP_NOT_CAP; + } + + int disc_flag_status(bpctl_dev_t *pbpctl_dev) + { + + if (pbpctl_dev->bp_caps & DISC_CAP) { + if (pbpctl_dev->bp_ext_ver >= 0x8) + return ((((read_reg(pbpctl_dev, STATUS_DISC_REG_ADDR)) & + DISC_FLAG_MASK) == DISC_FLAG_MASK) ? 1 : 0); + + } + return BP_NOT_CAP; + } + + int disc_flag_status_clear(bpctl_dev_t *pbpctl_dev) + { + uint32_t status_reg = 0; + if (pbpctl_dev->bp_caps & DISC_CAP) { + if (pbpctl_dev->bp_ext_ver >= 0x8) { + status_reg = read_reg(pbpctl_dev, STATUS_DISC_REG_ADDR); + write_reg(pbpctl_dev, status_reg & ~DISC_FLAG_MASK, + STATUS_DISC_REG_ADDR); + return BP_OK; + } + } + return BP_NOT_CAP; + } + + int disc_change_status(bpctl_dev_t *pbpctl_dev) + { + int ret = BP_NOT_CAP; + if (pbpctl_dev->bp_caps & DISC_CAP) { + ret = disc_flag_status(pbpctl_dev); + disc_flag_status_clear(pbpctl_dev); + return ret; + } + return BP_NOT_CAP; + } + + int disc_off_status(bpctl_dev_t *pbpctl_dev) + { + bpctl_dev_t *pbpctl_dev_b = NULL; + u32 ctrl_ext = 0; + + if (pbpctl_dev->bp_caps & DISC_CAP) { + if (!(pbpctl_dev_b = get_status_port_fn(pbpctl_dev))) + return BP_NOT_CAP; + if (DISCF_IF_SERIES(pbpctl_dev->subdevice)) + return ((((read_reg(pbpctl_dev, STATUS_DISC_REG_ADDR)) & + DISC_OFF_MASK) == DISC_OFF_MASK) ? 1 : 0); + + if (pbpctl_dev->bp_i80) { + return (((BPCTL_READ_REG(pbpctl_dev_b, CTRL_EXT)) & + BPCTLI_CTRL_EXT_SDP6_DATA) != 0 ? 1 : 0); + + } + if (pbpctl_dev->bp_540) { + ctrl_ext = BP10G_READ_REG(pbpctl_dev_b, ESDP); + return ((BP10G_READ_REG(pbpctl_dev_b, ESDP) & + BP10G_SDP2_DATA) != 0 ? 1 : 0); + + } + if (pbpctl_dev->media_type == bp_copper) { + + #if 0 + return ((((read_reg(pbpctl_dev, STATUS_DISC_REG_ADDR)) & + DISC_OFF_MASK) == DISC_OFF_MASK) ? 1 : 0); + #endif + if (!pbpctl_dev->bp_10g) + return (((BPCTL_READ_REG(pbpctl_dev_b, CTRL)) & + BPCTLI_CTRL_SWDPIN1) != 0 ? 1 : 0); + else + return ((BP10G_READ_REG(pbpctl_dev_b, ESDP) & + BP10G_SDP1_DATA) != 0 ? 1 : 0); + + } else { + + if (pbpctl_dev->bp_10g9) { + ctrl_ext = BP10G_READ_REG(pbpctl_dev_b, I2CCTL); + BP10G_WRITE_REG(pbpctl_dev_b, I2CCTL, + (ctrl_ext | + BP10G_I2C_DATA_OUT)); + return ((BP10G_READ_REG(pbpctl_dev_b, I2CCTL) & + BP10G_I2C_DATA_IN) != 0 ? 1 : 0); + + } else if (pbpctl_dev->bp_fiber5) { + return (((BPCTL_READ_REG(pbpctl_dev_b, CTRL)) & + BPCTLI_CTRL_SWDPIN1) != 0 ? 1 : 0); + } else if (pbpctl_dev->bp_10gb) { + ctrl_ext = + BP10GB_READ_REG(pbpctl_dev, MISC_REG_GPIO); + BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_GPIO, + (ctrl_ext | BP10GB_GPIO3_OE_P1) + & ~(BP10GB_GPIO3_SET_P1 | + BP10GB_GPIO3_CLR_P1)); + + return (((BP10GB_READ_REG + (pbpctl_dev, + MISC_REG_GPIO)) & BP10GB_GPIO3_P1) != + 0 ? 1 : 0); + } + if (!pbpctl_dev->bp_10g) { + + return (((BPCTL_READ_REG + (pbpctl_dev_b, + CTRL_EXT)) & + BPCTLI_CTRL_EXT_SDP6_DATA) != + 0 ? 1 : 0); + } else { + ctrl_ext = BP10G_READ_REG(pbpctl_dev_b, EODSDP); + BP10G_WRITE_REG(pbpctl_dev_b, EODSDP, + (ctrl_ext | + BP10G_SDP6_DATA_OUT)); + return (((BP10G_READ_REG(pbpctl_dev_b, EODSDP)) + & BP10G_SDP6_DATA_IN) != 0 ? 1 : 0); + } + + } + } + return BP_NOT_CAP; + } + + static int disc_status(bpctl_dev_t *pbpctl_dev) + { + int ctrl = 0; + if (pbpctl_dev->bp_caps & DISC_CAP) { + + if ((ctrl = disc_off_status(pbpctl_dev)) < 0) + return ctrl; + return ((ctrl == 0) ? 1 : 0); + + } + return BP_NOT_CAP; + } + + int default_pwron_disc_status(bpctl_dev_t *pbpctl_dev) + { + if (pbpctl_dev->bp_caps & DISC_PWUP_CTL_CAP) { + if (pbpctl_dev->bp_ext_ver >= 0x8) + return ((((read_reg(pbpctl_dev, STATUS_DISC_REG_ADDR)) & + DFLT_PWRON_DISC_MASK) == + DFLT_PWRON_DISC_MASK) ? 1 : 0); + } + return BP_NOT_CAP; + } + + int dis_disc_cap_status(bpctl_dev_t *pbpctl_dev) + { + if (pbpctl_dev->bp_caps & DIS_DISC_CAP) { + if (pbpctl_dev->bp_ext_ver >= 0x8) + return ((((read_reg(pbpctl_dev, STATUS_DISC_REG_ADDR)) & + DIS_DISC_CAP_MASK) == + DIS_DISC_CAP_MASK) ? 1 : 0); + } + return BP_NOT_CAP; + } + + int disc_port_status(bpctl_dev_t *pbpctl_dev) + { + int ret = BP_NOT_CAP; + bpctl_dev_t *pbpctl_dev_m; + + if ((is_bypass_fn(pbpctl_dev)) == 1) + pbpctl_dev_m = pbpctl_dev; + else + pbpctl_dev_m = get_master_port_fn(pbpctl_dev); + if (pbpctl_dev_m == NULL) + return BP_NOT_CAP; + + if (pbpctl_dev_m->bp_caps_ex & DISC_PORT_CAP_EX) { + if (is_bypass_fn(pbpctl_dev) == 1) { + return ((((read_reg(pbpctl_dev, STATUS_TAP_REG_ADDR)) & + TX_DISA_MASK) == TX_DISA_MASK) ? 1 : 0); + } else + return ((((read_reg(pbpctl_dev, STATUS_TAP_REG_ADDR)) & + TX_DISB_MASK) == TX_DISB_MASK) ? 1 : 0); + + } + return ret; + } + + int default_pwron_disc_port_status(bpctl_dev_t *pbpctl_dev) + { + int ret = BP_NOT_CAP; + bpctl_dev_t *pbpctl_dev_m; + + if ((is_bypass_fn(pbpctl_dev)) == 1) + pbpctl_dev_m = pbpctl_dev; + else + pbpctl_dev_m = get_master_port_fn(pbpctl_dev); + if (pbpctl_dev_m == NULL) + return BP_NOT_CAP; + + if (pbpctl_dev_m->bp_caps_ex & DISC_PORT_CAP_EX) { + if (is_bypass_fn(pbpctl_dev) == 1) + return ret; + /* return((((read_reg(pbpctl_dev,STATUS_TAP_REG_ADDR)) & TX_DISA_MASK)==TX_DISA_MASK)?1:0); */ + else + return ret; + /* return((((read_reg(pbpctl_dev,STATUS_TAP_REG_ADDR)) & TX_DISA_MASK)==TX_DISA_MASK)?1:0); */ + + } + return ret; + } + + int wdt_exp_mode_status(bpctl_dev_t *pbpctl_dev) + { + if (pbpctl_dev->bp_caps & WD_CTL_CAP) { + if (pbpctl_dev->bp_ext_ver <= PXG2BPI_VER) + return 0; /* bypass mode */ + else if (pbpctl_dev->bp_ext_ver == PXG2TBPI_VER) + return 1; /* tap mode */ + else if (pbpctl_dev->bp_ext_ver >= PXE2TBPI_VER) { + if (pbpctl_dev->bp_ext_ver >= 0x8) { + if (((read_reg + (pbpctl_dev, + STATUS_DISC_REG_ADDR)) & + WDTE_DISC_BPN_MASK) == WDTE_DISC_BPN_MASK) + return 2; + } + return ((((read_reg(pbpctl_dev, STATUS_TAP_REG_ADDR)) & + WDTE_TAP_BPN_MASK) == + WDTE_TAP_BPN_MASK) ? 1 : 0); + } + } + return BP_NOT_CAP; + } + + int tpl2_flag_status(bpctl_dev_t *pbpctl_dev) + { + + if (pbpctl_dev->bp_caps_ex & TPL2_CAP_EX) { + return ((((read_reg(pbpctl_dev, STATUS_DISC_REG_ADDR)) & + TPL2_FLAG_MASK) == TPL2_FLAG_MASK) ? 1 : 0); + + } + return BP_NOT_CAP; + } + + int tpl_hw_status(bpctl_dev_t *pbpctl_dev) + { + bpctl_dev_t *pbpctl_dev_b = NULL; + + if (!(pbpctl_dev_b = get_status_port_fn(pbpctl_dev))) + return BP_NOT_CAP; + + if (TPL_IF_SERIES(pbpctl_dev->subdevice)) + return (((BPCTL_READ_REG(pbpctl_dev, CTRL)) & + BPCTLI_CTRL_SWDPIN0) != 0 ? 1 : 0); + return BP_NOT_CAP; + } + + + int bp_wait_at_pwup_status(bpctl_dev_t *pbpctl_dev) + { + if (pbpctl_dev->bp_caps & SW_CTL_CAP) { + if (pbpctl_dev->bp_ext_ver >= 0x8) + return ((((read_reg(pbpctl_dev, CONT_CONFIG_REG_ADDR)) & + WAIT_AT_PWUP_MASK) == + WAIT_AT_PWUP_MASK) ? 1 : 0); + } + return BP_NOT_CAP; + } + + int bp_hw_reset_status(bpctl_dev_t *pbpctl_dev) + { + + if (pbpctl_dev->bp_caps & SW_CTL_CAP) { + + if (pbpctl_dev->bp_ext_ver >= 0x8) + return ((((read_reg(pbpctl_dev, CONT_CONFIG_REG_ADDR)) & + EN_HW_RESET_MASK) == + EN_HW_RESET_MASK) ? 1 : 0); + } + return BP_NOT_CAP; + } + + + int std_nic_status(bpctl_dev_t *pbpctl_dev) + { + int status_val = 0; + + if (pbpctl_dev->bp_caps & STD_NIC_CAP) { + if (INTEL_IF_SERIES(pbpctl_dev->subdevice)) + return BP_NOT_CAP; + if (pbpctl_dev->bp_ext_ver >= BP_FW_EXT_VER8) { + return ((((read_reg(pbpctl_dev, STATUS_DISC_REG_ADDR)) & + STD_NIC_ON_MASK) == STD_NIC_ON_MASK) ? 1 : 0); + } + + if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) { + if (pbpctl_dev->bp_caps & BP_CAP) { + status_val = + read_reg(pbpctl_dev, STATUS_REG_ADDR); + if (((!(status_val & WDT_EN_MASK)) + && ((status_val & STD_NIC_MASK) == + STD_NIC_MASK))) + status_val = 1; + else + return 0; + } + if (pbpctl_dev->bp_caps & TAP_CAP) { + status_val = + read_reg(pbpctl_dev, STATUS_TAP_REG_ADDR); + if ((status_val & STD_NIC_TAP_MASK) == + STD_NIC_TAP_MASK) + status_val = 1; + else + return 0; + } + if (pbpctl_dev->bp_caps & TAP_CAP) { + if ((disc_off_status(pbpctl_dev))) + status_val = 1; + else + return 0; + } + + return status_val; + } + } + return BP_NOT_CAP; + } + + /******************************************************/ + /**************SW_INIT*********************************/ + /******************************************************/ + void bypass_caps_init(bpctl_dev_t *pbpctl_dev) + { + u_int32_t ctrl_ext = 0; + bpctl_dev_t *pbpctl_dev_m = NULL; + + #ifdef BYPASS_DEBUG + int ret = 0; + if (!(INTEL_IF_SERIES(adapter->bp_device_block.subdevice))) { + ret = read_reg(pbpctl_dev, VER_REG_ADDR); + printk("VER_REG reg1=%x\n", ret); + ret = read_reg(pbpctl_dev, PRODUCT_CAP_REG_ADDR); + printk("PRODUCT_CAP reg=%x\n", ret); + ret = read_reg(pbpctl_dev, STATUS_TAP_REG_ADDR); + printk("STATUS_TAP reg1=%x\n", ret); + ret = read_reg(pbpctl_dev, 0x7); + printk("SIG_REG reg1=%x\n", ret); + ret = read_reg(pbpctl_dev, STATUS_REG_ADDR); + printk("STATUS_REG_ADDR=%x\n", ret); + ret = read_reg(pbpctl_dev, WDT_REG_ADDR); + printk("WDT_REG_ADDR=%x\n", ret); + ret = read_reg(pbpctl_dev, TMRL_REG_ADDR); + printk("TMRL_REG_ADDR=%x\n", ret); + ret = read_reg(pbpctl_dev, TMRH_REG_ADDR); + printk("TMRH_REG_ADDR=%x\n", ret); + } + #endif + if ((pbpctl_dev->bp_fiber5) || (pbpctl_dev->bp_10g9)) { + pbpctl_dev->media_type = bp_fiber; + } else if (pbpctl_dev->bp_10gb) { + if (BP10GB_CX4_SERIES(pbpctl_dev->subdevice)) + pbpctl_dev->media_type = bp_cx4; + else + pbpctl_dev->media_type = bp_fiber; + + } + + else if (pbpctl_dev->bp_540) + pbpctl_dev->media_type = bp_none; + else if (!pbpctl_dev->bp_10g) { + + ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT); + if ((ctrl_ext & BPCTLI_CTRL_EXT_LINK_MODE_MASK) == 0x0) + pbpctl_dev->media_type = bp_copper; + else + pbpctl_dev->media_type = bp_fiber; + + } else { + if (BP10G_CX4_SERIES(pbpctl_dev->subdevice)) + pbpctl_dev->media_type = bp_cx4; + else + pbpctl_dev->media_type = bp_fiber; + } + + if (is_bypass_fn(pbpctl_dev)) { + + pbpctl_dev->bp_caps |= BP_PWOFF_ON_CAP; + if (pbpctl_dev->media_type == bp_fiber) + pbpctl_dev->bp_caps |= + (TX_CTL_CAP | TX_STATUS_CAP | TPL_CAP); + + if (TPL_IF_SERIES(pbpctl_dev->subdevice)) { + pbpctl_dev->bp_caps |= TPL_CAP; + } + + if (INTEL_IF_SERIES(pbpctl_dev->subdevice)) { + pbpctl_dev->bp_caps |= + (BP_CAP | BP_STATUS_CAP | SW_CTL_CAP | + BP_PWUP_ON_CAP | BP_PWUP_OFF_CAP | BP_PWOFF_OFF_CAP + | WD_CTL_CAP | WD_STATUS_CAP | STD_NIC_CAP | + WD_TIMEOUT_CAP); + + pbpctl_dev->bp_ext_ver = OLD_IF_VER; + return; + } + + if ((pbpctl_dev->bp_fw_ver == 0xff) && + OLD_IF_SERIES(pbpctl_dev->subdevice)) { + + pbpctl_dev->bp_caps |= + (BP_CAP | BP_STATUS_CAP | BP_STATUS_CHANGE_CAP | + SW_CTL_CAP | BP_PWUP_ON_CAP | WD_CTL_CAP | + WD_STATUS_CAP | WD_TIMEOUT_CAP); + + pbpctl_dev->bp_ext_ver = OLD_IF_VER; + return; + } + + else { + switch (pbpctl_dev->bp_fw_ver) { + case BP_FW_VER_A0: + case BP_FW_VER_A1:{ + pbpctl_dev->bp_ext_ver = + (pbpctl_dev-> + bp_fw_ver & EXT_VER_MASK); + break; + } + default:{ + if ((bypass_sign_check(pbpctl_dev)) != + 1) { + pbpctl_dev->bp_caps = 0; + return; + } + pbpctl_dev->bp_ext_ver = + (pbpctl_dev-> + bp_fw_ver & EXT_VER_MASK); + } + } + } + + if (pbpctl_dev->bp_ext_ver == PXG2BPI_VER) + pbpctl_dev->bp_caps |= + (BP_CAP | BP_STATUS_CAP | BP_STATUS_CHANGE_CAP | + SW_CTL_CAP | BP_DIS_CAP | BP_DIS_STATUS_CAP | + BP_PWUP_ON_CAP | BP_PWUP_OFF_CAP | BP_PWUP_CTL_CAP + | WD_CTL_CAP | STD_NIC_CAP | WD_STATUS_CAP | + WD_TIMEOUT_CAP); + else if (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER) { + int cap_reg; + + pbpctl_dev->bp_caps |= + (SW_CTL_CAP | WD_CTL_CAP | WD_STATUS_CAP | + WD_TIMEOUT_CAP); + cap_reg = get_bp_prod_caps(pbpctl_dev); + + if ((cap_reg & NORMAL_UNSUPPORT_MASK) == + NORMAL_UNSUPPORT_MASK) + pbpctl_dev->bp_caps |= NIC_CAP_NEG; + else + pbpctl_dev->bp_caps |= STD_NIC_CAP; + + if ((normal_support(pbpctl_dev)) == 1) + + pbpctl_dev->bp_caps |= STD_NIC_CAP; + + else + pbpctl_dev->bp_caps |= NIC_CAP_NEG; + if ((cap_reg & BYPASS_SUPPORT_MASK) == + BYPASS_SUPPORT_MASK) { + pbpctl_dev->bp_caps |= + (BP_CAP | BP_STATUS_CAP | + BP_STATUS_CHANGE_CAP | BP_DIS_CAP | + BP_DIS_STATUS_CAP | BP_PWUP_ON_CAP | + BP_PWUP_OFF_CAP | BP_PWUP_CTL_CAP); + if (pbpctl_dev->bp_ext_ver >= BP_FW_EXT_VER7) + pbpctl_dev->bp_caps |= + BP_PWOFF_ON_CAP | BP_PWOFF_OFF_CAP | + BP_PWOFF_CTL_CAP; + } + if ((cap_reg & TAP_SUPPORT_MASK) == TAP_SUPPORT_MASK) { + pbpctl_dev->bp_caps |= + (TAP_CAP | TAP_STATUS_CAP | + TAP_STATUS_CHANGE_CAP | TAP_DIS_CAP | + TAP_DIS_STATUS_CAP | TAP_PWUP_ON_CAP | + TAP_PWUP_OFF_CAP | TAP_PWUP_CTL_CAP); + } + if (pbpctl_dev->bp_ext_ver >= BP_FW_EXT_VER8) { + if ((cap_reg & DISC_SUPPORT_MASK) == + DISC_SUPPORT_MASK) + pbpctl_dev->bp_caps |= + (DISC_CAP | DISC_DIS_CAP | + DISC_PWUP_CTL_CAP); + if ((cap_reg & TPL2_SUPPORT_MASK) == + TPL2_SUPPORT_MASK) { + pbpctl_dev->bp_caps_ex |= TPL2_CAP_EX; + pbpctl_dev->bp_caps |= TPL_CAP; + pbpctl_dev->bp_tpl_flag = + tpl2_flag_status(pbpctl_dev); + } + + } + + if (pbpctl_dev->bp_ext_ver >= BP_FW_EXT_VER9) { + if ((cap_reg & DISC_PORT_SUPPORT_MASK) == + DISC_PORT_SUPPORT_MASK) { + pbpctl_dev->bp_caps_ex |= + DISC_PORT_CAP_EX; + pbpctl_dev->bp_caps |= + (TX_CTL_CAP | TX_STATUS_CAP); + } + + } + + } + if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) { + if ((read_reg(pbpctl_dev, STATUS_REG_ADDR)) & + WDT_EN_MASK) + pbpctl_dev->wdt_status = WDT_STATUS_EN; + else + pbpctl_dev->wdt_status = WDT_STATUS_DIS; + } + + } else if ((P2BPFI_IF_SERIES(pbpctl_dev->subdevice)) || + (PEGF5_IF_SERIES(pbpctl_dev->subdevice)) || + (PEGF80_IF_SERIES(pbpctl_dev->subdevice)) || + (BP10G9_IF_SERIES(pbpctl_dev->subdevice))) { + pbpctl_dev->bp_caps |= (TX_CTL_CAP | TX_STATUS_CAP); + } + if ((pbpctl_dev->subdevice & 0xa00) == 0xa00) + pbpctl_dev->bp_caps |= (TX_CTL_CAP | TX_STATUS_CAP); + if (PEG5_IF_SERIES(pbpctl_dev->subdevice)) + pbpctl_dev->bp_caps |= (TX_CTL_CAP | TX_STATUS_CAP); + + if (BP10GB_IF_SERIES(pbpctl_dev->subdevice)) { + pbpctl_dev->bp_caps &= ~(TX_CTL_CAP | TX_STATUS_CAP); + } + pbpctl_dev_m = get_master_port_fn(pbpctl_dev); + if (pbpctl_dev_m != NULL) { + int cap_reg = 0; + if (pbpctl_dev_m->bp_ext_ver >= 0x9) { + cap_reg = get_bp_prod_caps(pbpctl_dev_m); + if ((cap_reg & DISC_PORT_SUPPORT_MASK) == + DISC_PORT_SUPPORT_MASK) + pbpctl_dev->bp_caps |= + (TX_CTL_CAP | TX_STATUS_CAP); + pbpctl_dev->bp_caps_ex |= DISC_PORT_CAP_EX; + } + } + } + + int bypass_off_init(bpctl_dev_t *pbpctl_dev) + { + int ret = 0; + + if ((ret = cmnd_on(pbpctl_dev)) < 0) + return ret; + if (INTEL_IF_SERIES(pbpctl_dev->subdevice)) + return dis_bypass_cap(pbpctl_dev); + wdt_off(pbpctl_dev); + if (pbpctl_dev->bp_caps & BP_CAP) + bypass_off(pbpctl_dev); + if (pbpctl_dev->bp_caps & TAP_CAP) + tap_off(pbpctl_dev); + cmnd_off(pbpctl_dev); + return 0; + } + + void remove_bypass_wd_auto(bpctl_dev_t *pbpctl_dev) + { + #ifdef BP_SELF_TEST + bpctl_dev_t *pbpctl_dev_sl = NULL; + #endif + + if (pbpctl_dev->bp_caps & WD_CTL_CAP) { + + del_timer_sync(&pbpctl_dev->bp_timer); + #ifdef BP_SELF_TEST + pbpctl_dev_sl = get_status_port_fn(pbpctl_dev); + if (pbpctl_dev_sl && (pbpctl_dev_sl->ndev)) { + if ((pbpctl_dev_sl->ndev->netdev_ops) + && (pbpctl_dev_sl->old_ops)) { + rtnl_lock(); + pbpctl_dev_sl->ndev->netdev_ops = + pbpctl_dev_sl->old_ops; + pbpctl_dev_sl->old_ops = NULL; + + rtnl_unlock(); + + } + + } + #endif + } + + } + + int init_bypass_wd_auto(bpctl_dev_t *pbpctl_dev) + { + if (pbpctl_dev->bp_caps & WD_CTL_CAP) { + init_timer(&pbpctl_dev->bp_timer); + pbpctl_dev->bp_timer.function = &wd_reset_timer; + pbpctl_dev->bp_timer.data = (unsigned long)pbpctl_dev; + return 1; + } + return BP_NOT_CAP; + } + + #ifdef BP_SELF_TEST + int bp_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) + { + bpctl_dev_t *pbpctl_dev = NULL, *pbpctl_dev_m = NULL; + int idx_dev = 0; + struct ethhdr *eth = (struct ethhdr *)skb->data; + + for (idx_dev = 0; + ((bpctl_dev_arr[idx_dev].ndev != NULL) && (idx_dev < device_num)); + idx_dev++) { + if (bpctl_dev_arr[idx_dev].ndev == dev) { + pbpctl_dev = &bpctl_dev_arr[idx_dev]; + break; + } + } + if (!pbpctl_dev) + return 1; + if ((htons(ETH_P_BPTEST) == eth->h_proto)) { + + pbpctl_dev_m = get_master_port_fn(pbpctl_dev); + if (pbpctl_dev_m) { + + if (bypass_status(pbpctl_dev_m)) { + cmnd_on(pbpctl_dev_m); + bypass_off(pbpctl_dev_m); + cmnd_off(pbpctl_dev_m); + } + wdt_timer_reload(pbpctl_dev_m); + } + dev_kfree_skb_irq(skb); + return 0; + } + return pbpctl_dev->hard_start_xmit_save(skb, dev); + } + #endif + + int set_bypass_wd_auto(bpctl_dev_t *pbpctl_dev, unsigned int param) + { + if (pbpctl_dev->bp_caps & WD_CTL_CAP) { + if (pbpctl_dev->reset_time != param) { + if (INTEL_IF_SERIES(pbpctl_dev->subdevice)) + pbpctl_dev->reset_time = + (param < + WDT_AUTO_MIN_INT) ? WDT_AUTO_MIN_INT : + param; + else + pbpctl_dev->reset_time = param; + if (param) + mod_timer(&pbpctl_dev->bp_timer, jiffies); + } + return 0; + } + return BP_NOT_CAP; + } + + int get_bypass_wd_auto(bpctl_dev_t *pbpctl_dev) + { + + if (pbpctl_dev->bp_caps & WD_CTL_CAP) { + return pbpctl_dev->reset_time; + } + return BP_NOT_CAP; + } + + #ifdef BP_SELF_TEST + + int set_bp_self_test(bpctl_dev_t *pbpctl_dev, unsigned int param) + { + bpctl_dev_t *pbpctl_dev_sl = NULL; + + if (pbpctl_dev->bp_caps & WD_CTL_CAP) { + pbpctl_dev->bp_self_test_flag = param == 0 ? 0 : 1; + pbpctl_dev_sl = get_status_port_fn(pbpctl_dev); + + if ((pbpctl_dev_sl->ndev) && (pbpctl_dev_sl->ndev->netdev_ops)) { + rtnl_lock(); + if (pbpctl_dev->bp_self_test_flag == 1) { + + pbpctl_dev_sl->old_ops = + pbpctl_dev_sl->ndev->netdev_ops; + pbpctl_dev_sl->new_ops = + *pbpctl_dev_sl->old_ops; + pbpctl_dev_sl->new_ops.ndo_start_xmit = + bp_hard_start_xmit; + pbpctl_dev_sl->ndev->netdev_ops = + &pbpctl_dev_sl->new_ops; + + } else if (pbpctl_dev_sl->old_ops) { + pbpctl_dev_sl->ndev->netdev_ops = + pbpctl_dev_sl->old_ops; + pbpctl_dev_sl->old_ops = NULL; + } + rtnl_unlock(); + } + + set_bypass_wd_auto(pbpctl_dev, param); + return 0; + } + return BP_NOT_CAP; + } + + int get_bp_self_test(bpctl_dev_t *pbpctl_dev) + { + + if (pbpctl_dev->bp_caps & WD_CTL_CAP) { + if (pbpctl_dev->bp_self_test_flag == 1) + return pbpctl_dev->reset_time; + else + return 0; + } + return BP_NOT_CAP; + } + + #endif + + /**************************************************************/ + /************************* API ********************************/ + /**************************************************************/ + + int is_bypass_fn(bpctl_dev_t *pbpctl_dev) + { + if (!pbpctl_dev) + return -1; + + return (((pbpctl_dev->func == 0) || (pbpctl_dev->func == 2)) ? 1 : 0); + } + + int set_bypass_fn(bpctl_dev_t *pbpctl_dev, int bypass_mode) + { + int ret = 0; + + if (!(pbpctl_dev->bp_caps & BP_CAP)) + return BP_NOT_CAP; + if ((ret = cmnd_on(pbpctl_dev)) < 0) + return ret; + if (!bypass_mode) + ret = bypass_off(pbpctl_dev); + else + ret = bypass_on(pbpctl_dev); + cmnd_off(pbpctl_dev); + + return ret; + } + + int get_bypass_fn(bpctl_dev_t *pbpctl_dev) + { + return bypass_status(pbpctl_dev); + } + + int get_bypass_change_fn(bpctl_dev_t *pbpctl_dev) + { + if (!pbpctl_dev) + return -1; + + return bypass_change_status(pbpctl_dev); + } + + int set_dis_bypass_fn(bpctl_dev_t *pbpctl_dev, int dis_param) + { + int ret = 0; + if (!pbpctl_dev) + return -1; + + if (!(pbpctl_dev->bp_caps & BP_DIS_CAP)) + return BP_NOT_CAP; + if ((ret = cmnd_on(pbpctl_dev)) < 0) + return ret; + if (dis_param) + ret = dis_bypass_cap(pbpctl_dev); + else + ret = en_bypass_cap(pbpctl_dev); + cmnd_off(pbpctl_dev); + return ret; + } + + int get_dis_bypass_fn(bpctl_dev_t *pbpctl_dev) + { + if (!pbpctl_dev) + return -1; + + return dis_bypass_cap_status(pbpctl_dev); + } + + int set_bypass_pwoff_fn(bpctl_dev_t *pbpctl_dev, int bypass_mode) + { + int ret = 0; + if (!pbpctl_dev) + return -1; + + if (!(pbpctl_dev->bp_caps & BP_PWOFF_CTL_CAP)) + return BP_NOT_CAP; + if ((ret = cmnd_on(pbpctl_dev)) < 0) + return ret; + if (bypass_mode) + ret = bypass_state_pwroff(pbpctl_dev); + else + ret = normal_state_pwroff(pbpctl_dev); + cmnd_off(pbpctl_dev); + return ret; + } + + int get_bypass_pwoff_fn(bpctl_dev_t *pbpctl_dev) + { + if (!pbpctl_dev) + return -1; + + return default_pwroff_status(pbpctl_dev); + } + + int set_bypass_pwup_fn(bpctl_dev_t *pbpctl_dev, int bypass_mode) + { + int ret = 0; + if (!pbpctl_dev) + return -1; + + if (!(pbpctl_dev->bp_caps & BP_PWUP_CTL_CAP)) + return BP_NOT_CAP; + if ((ret = cmnd_on(pbpctl_dev)) < 0) + return ret; + if (bypass_mode) + ret = bypass_state_pwron(pbpctl_dev); + else + ret = normal_state_pwron(pbpctl_dev); + cmnd_off(pbpctl_dev); + return ret; + } + + int get_bypass_pwup_fn(bpctl_dev_t *pbpctl_dev) + { + if (!pbpctl_dev) + return -1; + + return default_pwron_status(pbpctl_dev); + } + + int set_bypass_wd_fn(bpctl_dev_t *pbpctl_dev, int timeout) + { + int ret = 0; + if (!pbpctl_dev) + return -1; + + if (!(pbpctl_dev->bp_caps & WD_CTL_CAP)) + return BP_NOT_CAP; + + if ((ret = cmnd_on(pbpctl_dev)) < 0) + return ret; + if (!timeout) + ret = wdt_off(pbpctl_dev); + else { + wdt_on(pbpctl_dev, timeout); + ret = pbpctl_dev->bypass_timer_interval; + } + cmnd_off(pbpctl_dev); + return ret; + } + + int get_bypass_wd_fn(bpctl_dev_t *pbpctl_dev, int *timeout) + { + if (!pbpctl_dev) + return -1; + + return wdt_programmed(pbpctl_dev, timeout); + } + + int get_wd_expire_time_fn(bpctl_dev_t *pbpctl_dev, int *time_left) + { + if (!pbpctl_dev) + return -1; + + return wdt_timer(pbpctl_dev, time_left); + } + + int reset_bypass_wd_timer_fn(bpctl_dev_t *pbpctl_dev) + { + if (!pbpctl_dev) + return -1; + + return wdt_timer_reload(pbpctl_dev); + } + + int get_wd_set_caps_fn(bpctl_dev_t *pbpctl_dev) + { + int bp_status = 0; + + unsigned int step_value = TIMEOUT_MAX_STEP + 1, bit_cnt = 0; + if (!pbpctl_dev) + return -1; + + if (INTEL_IF_SERIES(pbpctl_dev->subdevice)) + return BP_NOT_CAP; + + while ((step_value >>= 1)) + bit_cnt++; + + if (is_bypass_fn(pbpctl_dev)) { + bp_status = + WD_STEP_COUNT_MASK(bit_cnt) | WDT_STEP_TIME | + WD_MIN_TIME_MASK(TIMEOUT_UNIT / 100); + } else + return -1; + + return bp_status; + } + + int set_std_nic_fn(bpctl_dev_t *pbpctl_dev, int nic_mode) + { + int ret = 0; + if (!pbpctl_dev) + return -1; + + if (!(pbpctl_dev->bp_caps & STD_NIC_CAP)) + return BP_NOT_CAP; + + if ((ret = cmnd_on(pbpctl_dev)) < 0) + return ret; + if (nic_mode) + ret = std_nic_on(pbpctl_dev); + else + ret = std_nic_off(pbpctl_dev); + cmnd_off(pbpctl_dev); + return ret; + } + + int get_std_nic_fn(bpctl_dev_t *pbpctl_dev) + { + if (!pbpctl_dev) + return -1; + + return std_nic_status(pbpctl_dev); + } + + int set_tap_fn(bpctl_dev_t *pbpctl_dev, int tap_mode) + { + if (!pbpctl_dev) + return -1; + + if ((pbpctl_dev->bp_caps & TAP_CAP) && ((cmnd_on(pbpctl_dev)) >= 0)) { + if (!tap_mode) + tap_off(pbpctl_dev); + else + tap_on(pbpctl_dev); + cmnd_off(pbpctl_dev); + return 0; + } + return BP_NOT_CAP; + } + + int get_tap_fn(bpctl_dev_t *pbpctl_dev) + { + if (!pbpctl_dev) + return -1; + + return tap_status(pbpctl_dev); + } + + int set_tap_pwup_fn(bpctl_dev_t *pbpctl_dev, int tap_mode) + { + int ret = 0; + if (!pbpctl_dev) + return -1; + + if ((pbpctl_dev->bp_caps & TAP_PWUP_CTL_CAP) + && ((cmnd_on(pbpctl_dev)) >= 0)) { + if (tap_mode) + ret = tap_state_pwron(pbpctl_dev); + else + ret = normal_state_pwron(pbpctl_dev); + cmnd_off(pbpctl_dev); + } else + ret = BP_NOT_CAP; + return ret; + } + + int get_tap_pwup_fn(bpctl_dev_t *pbpctl_dev) + { + int ret = 0; + if (!pbpctl_dev) + return -1; + + if ((ret = default_pwron_tap_status(pbpctl_dev)) < 0) + return ret; + return ((ret == 0) ? 1 : 0); + } + + int get_tap_change_fn(bpctl_dev_t *pbpctl_dev) + { + if (!pbpctl_dev) + return -1; + + return tap_change_status(pbpctl_dev); + } + + int set_dis_tap_fn(bpctl_dev_t *pbpctl_dev, int dis_param) + { + int ret = 0; + if (!pbpctl_dev) + return -1; + + if ((pbpctl_dev->bp_caps & TAP_DIS_CAP) && ((cmnd_on(pbpctl_dev)) >= 0)) { + if (dis_param) + ret = dis_tap_cap(pbpctl_dev); + else + ret = en_tap_cap(pbpctl_dev); + cmnd_off(pbpctl_dev); + return ret; + } else + return BP_NOT_CAP; + } + + int get_dis_tap_fn(bpctl_dev_t *pbpctl_dev) + { + if (!pbpctl_dev) + return -1; + + return dis_tap_cap_status(pbpctl_dev); + } + + int set_disc_fn(bpctl_dev_t *pbpctl_dev, int disc_mode) + { + if (!pbpctl_dev) + return -1; + + if ((pbpctl_dev->bp_caps & DISC_CAP) && ((cmnd_on(pbpctl_dev)) >= 0)) { + if (!disc_mode) + disc_off(pbpctl_dev); + else + disc_on(pbpctl_dev); + cmnd_off(pbpctl_dev); + + return BP_OK; + } + return BP_NOT_CAP; + } + + int get_disc_fn(bpctl_dev_t *pbpctl_dev) + { + int ret = 0; + if (!pbpctl_dev) + return -1; + + ret = disc_status(pbpctl_dev); + + return ret; + } + + int set_disc_pwup_fn(bpctl_dev_t *pbpctl_dev, int disc_mode) + { + int ret = 0; + if (!pbpctl_dev) + return -1; + + if ((pbpctl_dev->bp_caps & DISC_PWUP_CTL_CAP) + && ((cmnd_on(pbpctl_dev)) >= 0)) { + if (disc_mode) + ret = disc_state_pwron(pbpctl_dev); + else + ret = normal_state_pwron(pbpctl_dev); + cmnd_off(pbpctl_dev); + } else + ret = BP_NOT_CAP; + return ret; + } + + int get_disc_pwup_fn(bpctl_dev_t *pbpctl_dev) + { + int ret = 0; + if (!pbpctl_dev) + return -1; + + ret = default_pwron_disc_status(pbpctl_dev); + return (ret == 0 ? 1 : (ret < 0 ? BP_NOT_CAP : 0)); + } + + int get_disc_change_fn(bpctl_dev_t *pbpctl_dev) + { + int ret = 0; + if (!pbpctl_dev) + return -1; + + ret = disc_change_status(pbpctl_dev); + return ret; + } + + int set_dis_disc_fn(bpctl_dev_t *pbpctl_dev, int dis_param) + { + int ret = 0; + if (!pbpctl_dev) + return -1; + + if ((pbpctl_dev->bp_caps & DISC_DIS_CAP) + && ((cmnd_on(pbpctl_dev)) >= 0)) { + if (dis_param) + ret = dis_disc_cap(pbpctl_dev); + else + ret = en_disc_cap(pbpctl_dev); + cmnd_off(pbpctl_dev); + return ret; + } else + return BP_NOT_CAP; + } + + int get_dis_disc_fn(bpctl_dev_t *pbpctl_dev) + { + int ret = 0; + if (!pbpctl_dev) + return -1; + + ret = dis_disc_cap_status(pbpctl_dev); + + return ret; + } + + int set_disc_port_fn(bpctl_dev_t *pbpctl_dev, int disc_mode) + { + int ret = BP_NOT_CAP; + if (!pbpctl_dev) + return -1; + + if (!disc_mode) + ret = disc_port_off(pbpctl_dev); + else + ret = disc_port_on(pbpctl_dev); + + return ret; + } + + int get_disc_port_fn(bpctl_dev_t *pbpctl_dev) + { + if (!pbpctl_dev) + return -1; + + return disc_port_status(pbpctl_dev); + } + + int set_disc_port_pwup_fn(bpctl_dev_t *pbpctl_dev, int disc_mode) + { + int ret = BP_NOT_CAP; + if (!pbpctl_dev) + return -1; + + if (!disc_mode) + ret = normal_port_state_pwron(pbpctl_dev); + else + ret = disc_port_state_pwron(pbpctl_dev); + + return ret; + } + + int get_disc_port_pwup_fn(bpctl_dev_t *pbpctl_dev) + { + int ret = 0; + if (!pbpctl_dev) + return -1; + + if ((ret = default_pwron_disc_port_status(pbpctl_dev)) < 0) + return ret; + return ((ret == 0) ? 1 : 0); + } + + int get_wd_exp_mode_fn(bpctl_dev_t *pbpctl_dev) + { + if (!pbpctl_dev) + return -1; + + return wdt_exp_mode_status(pbpctl_dev); + } + + int set_wd_exp_mode_fn(bpctl_dev_t *pbpctl_dev, int param) + { + if (!pbpctl_dev) + return -1; + + return wdt_exp_mode(pbpctl_dev, param); + } + + int reset_cont_fn(bpctl_dev_t *pbpctl_dev) + { + int ret = 0; + if (!pbpctl_dev) + return -1; + + if ((ret = cmnd_on(pbpctl_dev)) < 0) + return ret; + return reset_cont(pbpctl_dev); + } + + int set_tx_fn(bpctl_dev_t *pbpctl_dev, int tx_state) + { + + bpctl_dev_t *pbpctl_dev_b = NULL; + if (!pbpctl_dev) + return -1; + + if ((pbpctl_dev->bp_caps & TPL_CAP) && + (pbpctl_dev->bp_caps & SW_CTL_CAP)) { + if ((pbpctl_dev->bp_tpl_flag)) + return BP_NOT_CAP; + } else if ((pbpctl_dev_b = get_master_port_fn(pbpctl_dev))) { + if ((pbpctl_dev_b->bp_caps & TPL_CAP) && + (pbpctl_dev_b->bp_tpl_flag)) + return BP_NOT_CAP; + } + return set_tx(pbpctl_dev, tx_state); + } + + int set_bp_force_link_fn(int dev_num, int tx_state) + { + static bpctl_dev_t *bpctl_dev_curr; + + if ((dev_num < 0) || (dev_num > device_num) + || (bpctl_dev_arr[dev_num].pdev == NULL)) + return -1; + bpctl_dev_curr = &bpctl_dev_arr[dev_num]; + + return set_bp_force_link(bpctl_dev_curr, tx_state); + } + + int set_wd_autoreset_fn(bpctl_dev_t *pbpctl_dev, int param) + { + if (!pbpctl_dev) + return -1; + + return set_bypass_wd_auto(pbpctl_dev, param); + } + + int get_wd_autoreset_fn(bpctl_dev_t *pbpctl_dev) + { + if (!pbpctl_dev) + return -1; + + return get_bypass_wd_auto(pbpctl_dev); + } + + #ifdef BP_SELF_TEST + int set_bp_self_test_fn(bpctl_dev_t *pbpctl_dev, int param) + { + if (!pbpctl_dev) + return -1; + + return set_bp_self_test(pbpctl_dev, param); + } + + int get_bp_self_test_fn(bpctl_dev_t *pbpctl_dev) + { + if (!pbpctl_dev) + return -1; + + return get_bp_self_test(pbpctl_dev); + } + + #endif + + int get_bypass_caps_fn(bpctl_dev_t *pbpctl_dev) + { + if (!pbpctl_dev) + return -1; + + return pbpctl_dev->bp_caps; + + } + + int get_bypass_slave_fn(bpctl_dev_t *pbpctl_dev, bpctl_dev_t **pbpctl_dev_out) + { + int idx_dev = 0; + if (!pbpctl_dev) + return -1; + + if ((pbpctl_dev->func == 0) || (pbpctl_dev->func == 2)) { + for (idx_dev = 0; + ((bpctl_dev_arr[idx_dev].pdev != NULL) + && (idx_dev < device_num)); idx_dev++) { + if ((bpctl_dev_arr[idx_dev].bus == pbpctl_dev->bus) + && (bpctl_dev_arr[idx_dev].slot == + pbpctl_dev->slot)) { + if ((pbpctl_dev->func == 0) + && (bpctl_dev_arr[idx_dev].func == 1)) { + *pbpctl_dev_out = + &bpctl_dev_arr[idx_dev]; + return 1; + } + if ((pbpctl_dev->func == 2) && + (bpctl_dev_arr[idx_dev].func == 3)) { + *pbpctl_dev_out = + &bpctl_dev_arr[idx_dev]; + return 1; + } + } + } + return -1; + } else + return 0; + } + + int is_bypass(bpctl_dev_t *pbpctl_dev) + { + if (!pbpctl_dev) + return -1; + + if ((pbpctl_dev->func == 0) || (pbpctl_dev->func == 2)) + return 1; + else + return 0; + } + + int get_tx_fn(bpctl_dev_t *pbpctl_dev) + { + bpctl_dev_t *pbpctl_dev_b = NULL; + if (!pbpctl_dev) + return -1; + + if ((pbpctl_dev->bp_caps & TPL_CAP) && + (pbpctl_dev->bp_caps & SW_CTL_CAP)) { + if ((pbpctl_dev->bp_tpl_flag)) + return BP_NOT_CAP; + } else if ((pbpctl_dev_b = get_master_port_fn(pbpctl_dev))) { + if ((pbpctl_dev_b->bp_caps & TPL_CAP) && + (pbpctl_dev_b->bp_tpl_flag)) + return BP_NOT_CAP; + } + return tx_status(pbpctl_dev); + } + + int get_bp_force_link_fn(int dev_num) + { + static bpctl_dev_t *bpctl_dev_curr; + + if ((dev_num < 0) || (dev_num > device_num) + || (bpctl_dev_arr[dev_num].pdev == NULL)) + return -1; + bpctl_dev_curr = &bpctl_dev_arr[dev_num]; + + return bp_force_link_status(bpctl_dev_curr); + } + + static int get_bypass_link_status(bpctl_dev_t *pbpctl_dev) + { + if (!pbpctl_dev) + return -1; + + if (pbpctl_dev->media_type == bp_fiber) + return ((BPCTL_READ_REG(pbpctl_dev, CTRL) & + BPCTLI_CTRL_SWDPIN1)); + else + return ((BPCTL_READ_REG(pbpctl_dev, STATUS) & + BPCTLI_STATUS_LU)); + + } + + static void bp_tpl_timer_fn(unsigned long param) + { + bpctl_dev_t *pbpctl_dev = (bpctl_dev_t *) param; + uint32_t link1, link2; + bpctl_dev_t *pbpctl_dev_b = NULL; + + if (!(pbpctl_dev_b = get_status_port_fn(pbpctl_dev))) + return; + + if (!pbpctl_dev->bp_tpl_flag) { + set_tx(pbpctl_dev_b, 1); + set_tx(pbpctl_dev, 1); + return; + } + link1 = get_bypass_link_status(pbpctl_dev); + + link2 = get_bypass_link_status(pbpctl_dev_b); + if ((link1) && (tx_status(pbpctl_dev))) { + if ((!link2) && (tx_status(pbpctl_dev_b))) { + set_tx(pbpctl_dev, 0); + } else if (!tx_status(pbpctl_dev_b)) { + set_tx(pbpctl_dev_b, 1); + } + } else if ((!link1) && (tx_status(pbpctl_dev))) { + if ((link2) && (tx_status(pbpctl_dev_b))) { + set_tx(pbpctl_dev_b, 0); + } + } else if ((link1) && (!tx_status(pbpctl_dev))) { + if ((link2) && (tx_status(pbpctl_dev_b))) { + set_tx(pbpctl_dev, 1); + } + } else if ((!link1) && (!tx_status(pbpctl_dev))) { + if ((link2) && (tx_status(pbpctl_dev_b))) { + set_tx(pbpctl_dev, 1); + } + } + + mod_timer(&pbpctl_dev->bp_tpl_timer, jiffies + BP_LINK_MON_DELAY * HZ); + } + + void remove_bypass_tpl_auto(bpctl_dev_t *pbpctl_dev) + { + bpctl_dev_t *pbpctl_dev_b = NULL; + if (!pbpctl_dev) + return; + pbpctl_dev_b = get_status_port_fn(pbpctl_dev); + + if (pbpctl_dev->bp_caps & TPL_CAP) { + del_timer_sync(&pbpctl_dev->bp_tpl_timer); + pbpctl_dev->bp_tpl_flag = 0; + pbpctl_dev_b = get_status_port_fn(pbpctl_dev); + if (pbpctl_dev_b) + set_tx(pbpctl_dev_b, 1); + set_tx(pbpctl_dev, 1); + } + return; + } + + int init_bypass_tpl_auto(bpctl_dev_t *pbpctl_dev) + { + if (!pbpctl_dev) + return -1; + if (pbpctl_dev->bp_caps & TPL_CAP) { + init_timer(&pbpctl_dev->bp_tpl_timer); + pbpctl_dev->bp_tpl_timer.function = &bp_tpl_timer_fn; + pbpctl_dev->bp_tpl_timer.data = (unsigned long)pbpctl_dev; + return BP_OK; + } + return BP_NOT_CAP; + } + + int set_bypass_tpl_auto(bpctl_dev_t *pbpctl_dev, unsigned int param) + { + if (!pbpctl_dev) + return -1; + if (pbpctl_dev->bp_caps & TPL_CAP) { + if ((param) && (!pbpctl_dev->bp_tpl_flag)) { + pbpctl_dev->bp_tpl_flag = param; + mod_timer(&pbpctl_dev->bp_tpl_timer, jiffies + 1); + return BP_OK; + }; + if ((!param) && (pbpctl_dev->bp_tpl_flag)) + remove_bypass_tpl_auto(pbpctl_dev); + + return BP_OK; + } + return BP_NOT_CAP; + } + + int get_bypass_tpl_auto(bpctl_dev_t *pbpctl_dev) + { + if (!pbpctl_dev) + return -1; + if (pbpctl_dev->bp_caps & TPL_CAP) { + return pbpctl_dev->bp_tpl_flag; + } + return BP_NOT_CAP; + } + + int set_tpl_fn(bpctl_dev_t *pbpctl_dev, int tpl_mode) + { + + bpctl_dev_t *pbpctl_dev_b = NULL; + if (!pbpctl_dev) + return -1; + + pbpctl_dev_b = get_status_port_fn(pbpctl_dev); + + if (pbpctl_dev->bp_caps & TPL_CAP) { + if (tpl_mode) { + if ((pbpctl_dev_b = get_status_port_fn(pbpctl_dev))) + set_tx(pbpctl_dev_b, 1); + set_tx(pbpctl_dev, 1); + } + if ((TPL_IF_SERIES(pbpctl_dev->subdevice)) || + (pbpctl_dev->bp_caps_ex & TPL2_CAP_EX)) { + pbpctl_dev->bp_tpl_flag = tpl_mode; + if (!tpl_mode) + tpl_hw_off(pbpctl_dev); + else + tpl_hw_on(pbpctl_dev); + } else + set_bypass_tpl_auto(pbpctl_dev, tpl_mode); + return 0; + } + return BP_NOT_CAP; + } + + int get_tpl_fn(bpctl_dev_t *pbpctl_dev) + { + int ret = BP_NOT_CAP; + if (!pbpctl_dev) + return -1; + + if (pbpctl_dev->bp_caps & TPL_CAP) { + if (pbpctl_dev->bp_caps_ex & TPL2_CAP_EX) + return tpl2_flag_status(pbpctl_dev); + ret = pbpctl_dev->bp_tpl_flag; + } + return ret; + } + + int set_bp_wait_at_pwup_fn(bpctl_dev_t *pbpctl_dev, int tap_mode) + { + if (!pbpctl_dev) + return -1; + + if (pbpctl_dev->bp_caps & SW_CTL_CAP) { + /* bp_lock(pbp_device_block); */ + cmnd_on(pbpctl_dev); + if (!tap_mode) + bp_wait_at_pwup_dis(pbpctl_dev); + else + bp_wait_at_pwup_en(pbpctl_dev); + cmnd_off(pbpctl_dev); + + /* bp_unlock(pbp_device_block); */ + return BP_OK; + } + return BP_NOT_CAP; + } + + int get_bp_wait_at_pwup_fn(bpctl_dev_t *pbpctl_dev) + { + int ret = 0; + if (!pbpctl_dev) + return -1; + + /* bp_lock(pbp_device_block); */ + ret = bp_wait_at_pwup_status(pbpctl_dev); + /* bp_unlock(pbp_device_block); */ + + return ret; + } + + int set_bp_hw_reset_fn(bpctl_dev_t *pbpctl_dev, int tap_mode) + { + if (!pbpctl_dev) + return -1; + + if (pbpctl_dev->bp_caps & SW_CTL_CAP) { + /* bp_lock(pbp_device_block); */ + cmnd_on(pbpctl_dev); + + if (!tap_mode) + bp_hw_reset_dis(pbpctl_dev); + else + bp_hw_reset_en(pbpctl_dev); + cmnd_off(pbpctl_dev); + /* bp_unlock(pbp_device_block); */ + return BP_OK; + } + return BP_NOT_CAP; + } + + int get_bp_hw_reset_fn(bpctl_dev_t *pbpctl_dev) + { + int ret = 0; + if (!pbpctl_dev) + return -1; + + /* bp_lock(pbp_device_block); */ + ret = bp_hw_reset_status(pbpctl_dev); + + /* bp_unlock(pbp_device_block); */ + + return ret; + } + + + int get_bypass_info_fn(bpctl_dev_t *pbpctl_dev, char *dev_name, + char *add_param) + { + if (!pbpctl_dev) + return -1; + if (!is_bypass_fn(pbpctl_dev)) + return -1; + strcpy(dev_name, pbpctl_dev->name); + *add_param = pbpctl_dev->bp_fw_ver; + return 0; + } + + int get_dev_idx_bsf(int bus, int slot, int func) + { + int idx_dev = 0; + for (idx_dev = 0; + ((bpctl_dev_arr[idx_dev].pdev != NULL) && (idx_dev < device_num)); + idx_dev++) { + if ((bus == bpctl_dev_arr[idx_dev].bus) + && (slot == bpctl_dev_arr[idx_dev].slot) + && (func == bpctl_dev_arr[idx_dev].func)) + + return idx_dev; + } + return -1; + } + + static void str_low(char *str) + { + int i; + + for (i = 0; i < strlen(str); i++) + if ((str[i] >= 65) && (str[i] <= 90)) + str[i] += 32; + } + + static unsigned long str_to_hex(char *p) + { + unsigned long hex = 0; + unsigned long length = strlen(p), shift = 0; + unsigned char dig = 0; + + str_low(p); + length = strlen(p); + + if (length == 0) + return 0; + + do { + dig = p[--length]; + dig = dig < 'a' ? (dig - '0') : (dig - 'a' + 0xa); + hex |= (dig << shift); + shift += 4; + } while (length); + return hex; + } + + static int get_dev_idx(int ifindex) + { + int idx_dev = 0; + + for (idx_dev = 0; + ((bpctl_dev_arr[idx_dev].pdev != NULL) && (idx_dev < device_num)); + idx_dev++) { + if (ifindex == bpctl_dev_arr[idx_dev].ifindex) + return idx_dev; + } + + return -1; + } + + static bpctl_dev_t *get_dev_idx_p(int ifindex) + { + int idx_dev = 0; + + for (idx_dev = 0; + ((bpctl_dev_arr[idx_dev].pdev != NULL) && (idx_dev < device_num)); + idx_dev++) { + if (ifindex == bpctl_dev_arr[idx_dev].ifindex) + return &bpctl_dev_arr[idx_dev]; + } + + return NULL; + } + + static void if_scan_init(void) + { + int idx_dev = 0; + struct net_device *dev; + int ifindex; + /* rcu_read_lock(); */ + /* rtnl_lock(); */ + /* rcu_read_lock(); */ + + for_each_netdev(&init_net, dev) { + + struct ethtool_drvinfo drvinfo; + char cbuf[32]; + char *buf = NULL; + char res[10]; + int i = 0; + int bus = 0, slot = 0, func = 0; + ifindex = dev->ifindex; + + memset(res, 0, 10); + memset(&drvinfo, 0, sizeof(struct ethtool_drvinfo)); + + if (dev->ethtool_ops && dev->ethtool_ops->get_drvinfo) { + memset(&drvinfo, 0, sizeof(drvinfo)); + dev->ethtool_ops->get_drvinfo(dev, &drvinfo); + } else + continue; + if (!strcmp(drvinfo.bus_info, "N/A")) + continue; + memcpy(&cbuf, drvinfo.bus_info, 32); + buf = &cbuf[0]; + + while (*buf++ != ':') ; + for (i = 0; i < 10; i++, buf++) { + if (*buf == ':') + break; + res[i] = *buf; + + } + buf++; + bus = str_to_hex(res); + memset(res, 0, 10); + + for (i = 0; i < 10; i++, buf++) { + if (*buf == '.') + break; + res[i] = *buf; + + } + buf++; + slot = str_to_hex(res); + func = str_to_hex(buf); + idx_dev = get_dev_idx_bsf(bus, slot, func); + + if (idx_dev != -1) { + + bpctl_dev_arr[idx_dev].ifindex = ifindex; + bpctl_dev_arr[idx_dev].ndev = dev; + + } + + } + /* rtnl_unlock(); */ + /* rcu_read_unlock(); */ + + } + + static long device_ioctl(struct file *file, /* see include/linux/fs.h */ + unsigned int ioctl_num, /* number and param for ioctl */ + unsigned long ioctl_param) + { + struct bpctl_cmd bpctl_cmd; + int dev_idx = 0; + bpctl_dev_t *pbpctl_dev_out; + void __user *argp = (void __user *)ioctl_param; + int ret = 0; + unsigned long flags; + + static bpctl_dev_t *pbpctl_dev; + + /* lock_kernel(); */ + lock_bpctl(); + /* local_irq_save(flags); */ + /* if(!spin_trylock_irqsave(&bpvm_lock)){ + local_irq_restore(flags); + unlock_bpctl(); + unlock_kernel(); + return -1; + } */ + /* spin_lock_irqsave(&bpvm_lock, flags); */ + + /* + * Switch according to the ioctl called + */ + if (ioctl_num == IOCTL_TX_MSG(IF_SCAN)) { + if_scan_init(); + ret = SUCCESS; + goto bp_exit; + } + if (copy_from_user(&bpctl_cmd, argp, sizeof(struct bpctl_cmd))) { + + ret = -EFAULT; + goto bp_exit; + } + + if (ioctl_num == IOCTL_TX_MSG(GET_DEV_NUM)) { + bpctl_cmd.out_param[0] = device_num; + if (copy_to_user + (argp, (void *)&bpctl_cmd, sizeof(struct bpctl_cmd))) { + ret = -EFAULT; + goto bp_exit; + } + ret = SUCCESS; + goto bp_exit; + + } + /* lock_bpctl(); */ + /* preempt_disable(); */ + local_irq_save(flags); + if (!spin_trylock(&bpvm_lock)) { + local_irq_restore(flags); + unlock_bpctl(); + return -1; + } + + /* preempt_disable(); + rcu_read_lock(); + spin_lock_irqsave(&bpvm_lock, flags); + */ + if ((bpctl_cmd.in_param[5]) || + (bpctl_cmd.in_param[6]) || (bpctl_cmd.in_param[7])) + dev_idx = get_dev_idx_bsf(bpctl_cmd.in_param[5], + bpctl_cmd.in_param[6], + bpctl_cmd.in_param[7]); + else if (bpctl_cmd.in_param[1] == 0) + dev_idx = bpctl_cmd.in_param[0]; + else + dev_idx = get_dev_idx(bpctl_cmd.in_param[1]); + + if (dev_idx < 0 || dev_idx > device_num) { + /* unlock_bpctl(); + preempt_enable(); */ + ret = -EOPNOTSUPP; + /* preempt_enable(); + rcu_read_unlock(); */ + spin_unlock_irqrestore(&bpvm_lock, flags); + goto bp_exit; + } + + bpctl_cmd.out_param[0] = bpctl_dev_arr[dev_idx].bus; + bpctl_cmd.out_param[1] = bpctl_dev_arr[dev_idx].slot; + bpctl_cmd.out_param[2] = bpctl_dev_arr[dev_idx].func; + bpctl_cmd.out_param[3] = bpctl_dev_arr[dev_idx].ifindex; + + if ((bpctl_dev_arr[dev_idx].bp_10gb) + && (!(bpctl_dev_arr[dev_idx].ifindex))) { + printk("Please load network driver for %s adapter!\n", + bpctl_dev_arr[dev_idx].name); + bpctl_cmd.status = -1; + ret = SUCCESS; + /* preempt_enable(); */ + /* rcu_read_unlock(); */ + spin_unlock_irqrestore(&bpvm_lock, flags); + goto bp_exit; + + } + if ((bpctl_dev_arr[dev_idx].bp_10gb) && (bpctl_dev_arr[dev_idx].ndev)) { + if (!(bpctl_dev_arr[dev_idx].ndev->flags & IFF_UP)) { + if (!(bpctl_dev_arr[dev_idx].ndev->flags & IFF_UP)) { + printk + ("Please bring up network interfaces for %s adapter!\n", + bpctl_dev_arr[dev_idx].name); + bpctl_cmd.status = -1; + ret = SUCCESS; + /* preempt_enable(); */ + /* rcu_read_unlock(); */ + spin_unlock_irqrestore(&bpvm_lock, flags); + goto bp_exit; + } + + } + } + + if ((dev_idx < 0) || (dev_idx > device_num) + || (bpctl_dev_arr[dev_idx].pdev == NULL)) { + bpctl_cmd.status = -1; + goto bpcmd_exit; + } + + pbpctl_dev = &bpctl_dev_arr[dev_idx]; + + switch (ioctl_num) { + case IOCTL_TX_MSG(SET_BYPASS_PWOFF): + bpctl_cmd.status = + set_bypass_pwoff_fn(pbpctl_dev, bpctl_cmd.in_param[2]); + break; + + case IOCTL_TX_MSG(GET_BYPASS_PWOFF): + bpctl_cmd.status = get_bypass_pwoff_fn(pbpctl_dev); + break; + + case IOCTL_TX_MSG(SET_BYPASS_PWUP): + bpctl_cmd.status = + set_bypass_pwup_fn(pbpctl_dev, bpctl_cmd.in_param[2]); + break; + + case IOCTL_TX_MSG(GET_BYPASS_PWUP): + bpctl_cmd.status = get_bypass_pwup_fn(pbpctl_dev); + break; + + case IOCTL_TX_MSG(SET_BYPASS_WD): + bpctl_cmd.status = + set_bypass_wd_fn(pbpctl_dev, bpctl_cmd.in_param[2]); + break; + + case IOCTL_TX_MSG(GET_BYPASS_WD): + bpctl_cmd.status = + get_bypass_wd_fn(pbpctl_dev, (int *)&(bpctl_cmd.data[0])); + break; + + case IOCTL_TX_MSG(GET_WD_EXPIRE_TIME): + bpctl_cmd.status = + get_wd_expire_time_fn(pbpctl_dev, + (int *)&(bpctl_cmd.data[0])); + break; + + case IOCTL_TX_MSG(RESET_BYPASS_WD_TIMER): + bpctl_cmd.status = reset_bypass_wd_timer_fn(pbpctl_dev); + break; + + case IOCTL_TX_MSG(GET_WD_SET_CAPS): + bpctl_cmd.status = get_wd_set_caps_fn(pbpctl_dev); + break; + + case IOCTL_TX_MSG(SET_STD_NIC): + bpctl_cmd.status = + set_std_nic_fn(pbpctl_dev, bpctl_cmd.in_param[2]); + break; + + case IOCTL_TX_MSG(GET_STD_NIC): + bpctl_cmd.status = get_std_nic_fn(pbpctl_dev); + break; + + case IOCTL_TX_MSG(SET_TAP): + bpctl_cmd.status = + set_tap_fn(pbpctl_dev, bpctl_cmd.in_param[2]); + break; + + case IOCTL_TX_MSG(GET_TAP): + bpctl_cmd.status = get_tap_fn(pbpctl_dev); + break; + + case IOCTL_TX_MSG(GET_TAP_CHANGE): + bpctl_cmd.status = get_tap_change_fn(pbpctl_dev); + break; + + case IOCTL_TX_MSG(SET_DIS_TAP): + bpctl_cmd.status = + set_dis_tap_fn(pbpctl_dev, bpctl_cmd.in_param[2]); + break; + + case IOCTL_TX_MSG(GET_DIS_TAP): + bpctl_cmd.status = get_dis_tap_fn(pbpctl_dev); + break; + + case IOCTL_TX_MSG(SET_TAP_PWUP): + bpctl_cmd.status = + set_tap_pwup_fn(pbpctl_dev, bpctl_cmd.in_param[2]); + break; + + case IOCTL_TX_MSG(GET_TAP_PWUP): + bpctl_cmd.status = get_tap_pwup_fn(pbpctl_dev); + break; + + case IOCTL_TX_MSG(SET_WD_EXP_MODE): + bpctl_cmd.status = + set_wd_exp_mode_fn(pbpctl_dev, bpctl_cmd.in_param[2]); + break; + + case IOCTL_TX_MSG(GET_WD_EXP_MODE): + bpctl_cmd.status = get_wd_exp_mode_fn(pbpctl_dev); + break; + + case IOCTL_TX_MSG(GET_DIS_BYPASS): + bpctl_cmd.status = get_dis_bypass_fn(pbpctl_dev); + break; + + case IOCTL_TX_MSG(SET_DIS_BYPASS): + bpctl_cmd.status = + set_dis_bypass_fn(pbpctl_dev, bpctl_cmd.in_param[2]); + break; + + case IOCTL_TX_MSG(GET_BYPASS_CHANGE): + bpctl_cmd.status = get_bypass_change_fn(pbpctl_dev); + break; + + case IOCTL_TX_MSG(GET_BYPASS): + bpctl_cmd.status = get_bypass_fn(pbpctl_dev); + break; + + case IOCTL_TX_MSG(SET_BYPASS): + bpctl_cmd.status = + set_bypass_fn(pbpctl_dev, bpctl_cmd.in_param[2]); + break; + + case IOCTL_TX_MSG(GET_BYPASS_CAPS): + bpctl_cmd.status = get_bypass_caps_fn(pbpctl_dev); + /*preempt_enable(); */ + /*rcu_read_unlock();*/ + spin_unlock_irqrestore(&bpvm_lock, flags); + if (copy_to_user + (argp, (void *)&bpctl_cmd, sizeof(struct bpctl_cmd))) { + /*unlock_bpctl(); */ + /*preempt_enable(); */ + ret = -EFAULT; + goto bp_exit; + } + goto bp_exit; + + case IOCTL_TX_MSG(GET_BYPASS_SLAVE): + bpctl_cmd.status = + get_bypass_slave_fn(pbpctl_dev, &pbpctl_dev_out); + if (bpctl_cmd.status == 1) { + bpctl_cmd.out_param[4] = pbpctl_dev_out->bus; + bpctl_cmd.out_param[5] = pbpctl_dev_out->slot; + bpctl_cmd.out_param[6] = pbpctl_dev_out->func; + bpctl_cmd.out_param[7] = pbpctl_dev_out->ifindex; + } + break; + + case IOCTL_TX_MSG(IS_BYPASS): + bpctl_cmd.status = is_bypass(pbpctl_dev); + break; + case IOCTL_TX_MSG(SET_TX): + bpctl_cmd.status = set_tx_fn(pbpctl_dev, bpctl_cmd.in_param[2]); + break; + case IOCTL_TX_MSG(GET_TX): + bpctl_cmd.status = get_tx_fn(pbpctl_dev); + break; + case IOCTL_TX_MSG(SET_WD_AUTORESET): + bpctl_cmd.status = + set_wd_autoreset_fn(pbpctl_dev, bpctl_cmd.in_param[2]); + + break; + case IOCTL_TX_MSG(GET_WD_AUTORESET): + + bpctl_cmd.status = get_wd_autoreset_fn(pbpctl_dev); + break; + case IOCTL_TX_MSG(SET_DISC): + bpctl_cmd.status = + set_disc_fn(pbpctl_dev, bpctl_cmd.in_param[2]); + break; + case IOCTL_TX_MSG(GET_DISC): + bpctl_cmd.status = get_disc_fn(pbpctl_dev); + break; + case IOCTL_TX_MSG(GET_DISC_CHANGE): + bpctl_cmd.status = get_disc_change_fn(pbpctl_dev); + break; + case IOCTL_TX_MSG(SET_DIS_DISC): + bpctl_cmd.status = + set_dis_disc_fn(pbpctl_dev, bpctl_cmd.in_param[2]); + break; + case IOCTL_TX_MSG(GET_DIS_DISC): + bpctl_cmd.status = get_dis_disc_fn(pbpctl_dev); + break; + case IOCTL_TX_MSG(SET_DISC_PWUP): + bpctl_cmd.status = + set_disc_pwup_fn(pbpctl_dev, bpctl_cmd.in_param[2]); + break; + case IOCTL_TX_MSG(GET_DISC_PWUP): + bpctl_cmd.status = get_disc_pwup_fn(pbpctl_dev); + break; + + case IOCTL_TX_MSG(GET_BYPASS_INFO): + + bpctl_cmd.status = + get_bypass_info_fn(pbpctl_dev, (char *)&bpctl_cmd.data, + (char *)&bpctl_cmd.out_param[4]); + break; + + case IOCTL_TX_MSG(SET_TPL): + bpctl_cmd.status = + set_tpl_fn(pbpctl_dev, bpctl_cmd.in_param[2]); + break; + + case IOCTL_TX_MSG(GET_TPL): + bpctl_cmd.status = get_tpl_fn(pbpctl_dev); + break; + case IOCTL_TX_MSG(SET_BP_WAIT_AT_PWUP): + bpctl_cmd.status = + set_bp_wait_at_pwup_fn(pbpctl_dev, bpctl_cmd.in_param[2]); + break; + + case IOCTL_TX_MSG(GET_BP_WAIT_AT_PWUP): + bpctl_cmd.status = get_bp_wait_at_pwup_fn(pbpctl_dev); + break; + case IOCTL_TX_MSG(SET_BP_HW_RESET): + bpctl_cmd.status = + set_bp_hw_reset_fn(pbpctl_dev, bpctl_cmd.in_param[2]); + break; + + case IOCTL_TX_MSG(GET_BP_HW_RESET): + bpctl_cmd.status = get_bp_hw_reset_fn(pbpctl_dev); + break; + #ifdef BP_SELF_TEST + case IOCTL_TX_MSG(SET_BP_SELF_TEST): + bpctl_cmd.status = + set_bp_self_test_fn(pbpctl_dev, bpctl_cmd.in_param[2]); + + break; + case IOCTL_TX_MSG(GET_BP_SELF_TEST): + bpctl_cmd.status = get_bp_self_test_fn(pbpctl_dev); + break; + + #endif + #if 0 + case IOCTL_TX_MSG(SET_DISC_PORT): + bpctl_cmd.status = + set_disc_port_fn(pbpctl_dev, bpctl_cmd.in_param[2]); + break; + + case IOCTL_TX_MSG(GET_DISC_PORT): + bpctl_cmd.status = get_disc_port_fn(pbpctl_dev); + break; + + case IOCTL_TX_MSG(SET_DISC_PORT_PWUP): + bpctl_cmd.status = + set_disc_port_pwup_fn(pbpctl_dev, bpctl_cmd.in_param[2]); + break; + + case IOCTL_TX_MSG(GET_DISC_PORT_PWUP): + bpctl_cmd.status = get_disc_port_pwup_fn(pbpctl_dev); + break; + #endif + case IOCTL_TX_MSG(SET_BP_FORCE_LINK): + bpctl_cmd.status = + set_bp_force_link_fn(dev_idx, bpctl_cmd.in_param[2]); + break; + + case IOCTL_TX_MSG(GET_BP_FORCE_LINK): + bpctl_cmd.status = get_bp_force_link_fn(dev_idx); + break; + + default: + /* unlock_bpctl(); */ + + ret = -EOPNOTSUPP; + /* preempt_enable(); */ + /* rcu_read_unlock();*/ + spin_unlock_irqrestore(&bpvm_lock, flags); + goto bp_exit; + } + /* unlock_bpctl(); */ + /* preempt_enable(); */ + bpcmd_exit: + /* rcu_read_unlock(); */ + spin_unlock_irqrestore(&bpvm_lock, flags); + if (copy_to_user(argp, (void *)&bpctl_cmd, sizeof(struct bpctl_cmd))) + ret = -EFAULT; + ret = SUCCESS; + bp_exit: + /* unlock_kernel(); */ + /* spin_unlock_irqrestore(&bpvm_lock, flags); */ + unlock_bpctl(); + /* unlock_kernel(); */ + return ret; + } + + static const struct file_operations Fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = device_ioctl, + }; + + #ifndef PCI_DEVICE + #define PCI_DEVICE(vend,dev) \ + .vendor = (vend), .device = (dev), \ + .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID + #endif + + #define SILICOM_E1000BP_ETHERNET_DEVICE(device_id) {\ + PCI_DEVICE(SILICOM_VID, device_id)} + + typedef enum { + PXG2BPFI, + PXG2BPFIL, + PXG2BPFILX, + PXG2BPFILLX, + PXGBPI, + PXGBPIG, + PXG2TBFI, + PXG4BPI, + PXG4BPFI, + PEG4BPI, + PEG2BPI, + PEG4BPIN, + PEG2BPFI, + PEG2BPFILX, + PMCXG2BPFI, + PMCXG2BPFIN, + PEG4BPII, + PEG4BPFII, + PXG4BPFILX, + PMCXG2BPIN, + PMCXG4BPIN, + PXG2BISC1, + PEG2TBFI, + PXG2TBI, + PXG4BPFID, + PEG4BPFI, + PEG4BPIPT, + PXG6BPI, + PEG4BPIL, + PMCXG2BPIN2, + PMCXG4BPIN2, + PMCX2BPI, + PEG2BPFID, + PEG2BPFIDLX, + PMCX4BPI, + MEG2BPFILN, + MEG2BPFINX, + PEG4BPFILX, + PE10G2BPISR, + PE10G2BPILR, + MHIO8AD, + PE10G2BPICX4, + PEG2BPI5, + PEG6BPI, + PEG4BPFI5, + PEG4BPFI5LX, + MEG2BPFILXLN, + PEG2BPIX1, + MEG2BPFILXNX, + XE10G2BPIT, + XE10G2BPICX4, + XE10G2BPISR, + XE10G2BPILR, + PEG4BPIIO, + XE10G2BPIXR, + PE10GDBISR, + PE10GDBILR, + PEG2BISC6, + PEG6BPIFC, + PE10G2BPTCX4, + PE10G2BPTSR, + PE10G2BPTLR, + PE10G2BPTT, + PEG4BPI6, + PEG4BPFI6, + PEG4BPFI6LX, + PEG4BPFI6ZX, + PEG2BPI6, + PEG2BPFI6, + PEG2BPFI6LX, + PEG2BPFI6ZX, + PEG2BPFI6FLXM, + PEG4BPI6FC, + PEG4BPFI6FC, + PEG4BPFI6FCLX, + PEG4BPFI6FCZX, + PEG6BPI6, + PEG2BPI6SC6, + MEG2BPI6, + XEG2BPI6, + MEG4BPI6, + PEG2BPFI5, + PEG2BPFI5LX, + PXEG4BPFI, + M1EG2BPI6, + M1EG2BPFI6, + M1EG2BPFI6LX, + M1EG2BPFI6ZX, + M1EG4BPI6, + M1EG4BPFI6, + M1EG4BPFI6LX, + M1EG4BPFI6ZX, + M1EG6BPI6, + M1E2G4BPi80, + M1E2G4BPFi80, + M1E2G4BPFi80LX, + M1E2G4BPFi80ZX, + PE210G2SPI9, + M1E10G2BPI9CX4, + M1E10G2BPI9SR, + M1E10G2BPI9LR, + M1E10G2BPI9T, + PE210G2BPI9CX4, + PE210G2BPI9SR, + PE210G2BPI9LR, + PE210G2BPI9T, + M2EG2BPFI6, + M2EG2BPFI6LX, + M2EG2BPFI6ZX, + M2EG4BPI6, + M2EG4BPFI6, + M2EG4BPFI6LX, + M2EG4BPFI6ZX, + M2EG6BPI6, + PEG2DBI6, + PEG2DBFI6, + PEG2DBFI6LX, + PEG2DBFI6ZX, + PE2G4BPi80, + PE2G4BPFi80, + PE2G4BPFi80LX, + PE2G4BPFi80ZX, + PE2G4BPi80L, + M6E2G8BPi80A, + + PE2G2BPi35, + PAC1200BPi35, + PE2G2BPFi35, + PE2G2BPFi35LX, + PE2G2BPFi35ZX, + PE2G4BPi35, + PE2G4BPi35L, + PE2G4BPFi35, + PE2G4BPFi35LX, + PE2G4BPFi35ZX, + + PE2G6BPi35, + PE2G6BPi35CX, + + PE2G2BPi80, + PE2G2BPFi80, + PE2G2BPFi80LX, + PE2G2BPFi80ZX, + M2E10G2BPI9CX4, + M2E10G2BPI9SR, + M2E10G2BPI9LR, + M2E10G2BPI9T, + M6E2G8BPi80, + PE210G2DBi9SR, + PE210G2DBi9SRRB, + PE210G2DBi9LR, + PE210G2DBi9LRRB, + PE310G4DBi940SR, + PE310G4BPi9T, + PE310G4BPi9SR, + PE310G4BPi9LR, + PE210G2BPi40, + } board_t; + + typedef struct _bpmod_info_t { + unsigned int vendor; + unsigned int device; + unsigned int subvendor; + unsigned int subdevice; + unsigned int index; + char *bp_name; + + } bpmod_info_t; + + typedef struct _dev_desc { + char *name; + } dev_desc_t; + + dev_desc_t dev_desc[] = { + {"Silicom Bypass PXG2BPFI-SD series adapter"}, + {"Silicom Bypass PXG2BPFIL-SD series adapter"}, + {"Silicom Bypass PXG2BPFILX-SD series adapter"}, + {"Silicom Bypass PXG2BPFILLX-SD series adapter"}, + {"Silicom Bypass PXG2BPI-SD series adapter"}, + {"Silicom Bypass PXG2BPIG-SD series adapter"}, + {"Silicom Bypass PXG2TBFI-SD series adapter"}, + {"Silicom Bypass PXG4BPI-SD series adapter"}, + {"Silicom Bypass PXG4BPFI-SD series adapter"}, + {"Silicom Bypass PEG4BPI-SD series adapter"}, + {"Silicom Bypass PEG2BPI-SD series adapter"}, + {"Silicom Bypass PEG4BPIN-SD series adapter"}, + {"Silicom Bypass PEG2BPFI-SD series adapter"}, + {"Silicom Bypass PEG2BPFI-LX-SD series adapter"}, + {"Silicom Bypass PMCX2BPFI-SD series adapter"}, + {"Silicom Bypass PMCX2BPFI-N series adapter"}, + {"Intel Bypass PEG2BPII series adapter"}, + {"Intel Bypass PEG2BPFII series adapter"}, + {"Silicom Bypass PXG4BPFILX-SD series adapter"}, + {"Silicom Bypass PMCX2BPI-N series adapter"}, + {"Silicom Bypass PMCX4BPI-N series adapter"}, + {"Silicom Bypass PXG2BISC1-SD series adapter"}, + {"Silicom Bypass PEG2TBFI-SD series adapter"}, + {"Silicom Bypass PXG2TBI-SD series adapter"}, + {"Silicom Bypass PXG4BPFID-SD series adapter"}, + {"Silicom Bypass PEG4BPFI-SD series adapter"}, + {"Silicom Bypass PEG4BPIPT-SD series adapter"}, + {"Silicom Bypass PXG6BPI-SD series adapter"}, + {"Silicom Bypass PEG4BPIL-SD series adapter"}, + {"Silicom Bypass PMCX2BPI-N2 series adapter"}, + {"Silicom Bypass PMCX4BPI-N2 series adapter"}, + {"Silicom Bypass PMCX2BPI-SD series adapter"}, + {"Silicom Bypass PEG2BPFID-SD series adapter"}, + {"Silicom Bypass PEG2BPFIDLX-SD series adapter"}, + {"Silicom Bypass PMCX4BPI-SD series adapter"}, + {"Silicom Bypass MEG2BPFILN-SD series adapter"}, + {"Silicom Bypass MEG2BPFINX-SD series adapter"}, + {"Silicom Bypass PEG4BPFILX-SD series adapter"}, + {"Silicom Bypass PE10G2BPISR-SD series adapter"}, + {"Silicom Bypass PE10G2BPILR-SD series adapter"}, + {"Silicom Bypass MHIO8AD-SD series adapter"}, + {"Silicom Bypass PE10G2BPICX4-SD series adapter"}, + {"Silicom Bypass PEG2BPI5-SD series adapter"}, + {"Silicom Bypass PEG6BPI5-SD series adapter"}, + {"Silicom Bypass PEG4BPFI5-SD series adapter"}, + {"Silicom Bypass PEG4BPFI5LX-SD series adapter"}, + {"Silicom Bypass MEG2BPFILXLN-SD series adapter"}, + {"Silicom Bypass PEG2BPIX1-SD series adapter"}, + {"Silicom Bypass MEG2BPFILXNX-SD series adapter"}, + {"Silicom Bypass XE10G2BPIT-SD series adapter"}, + {"Silicom Bypass XE10G2BPICX4-SD series adapter"}, + {"Silicom Bypass XE10G2BPISR-SD series adapter"}, + {"Silicom Bypass XE10G2BPILR-SD series adapter"}, + {"Intel Bypass PEG2BPFII0 series adapter"}, + {"Silicom Bypass XE10G2BPIXR series adapter"}, + {"Silicom Bypass PE10G2DBISR series adapter"}, + {"Silicom Bypass PEG2BI5SC6 series adapter"}, + {"Silicom Bypass PEG6BPI5FC series adapter"}, + + {"Silicom Bypass PE10G2BPTCX4 series adapter"}, + {"Silicom Bypass PE10G2BPTSR series adapter"}, + {"Silicom Bypass PE10G2BPTLR series adapter"}, + {"Silicom Bypass PE10G2BPTT series adapter"}, + {"Silicom Bypass PEG4BPI6 series adapter"}, + {"Silicom Bypass PEG4BPFI6 series adapter"}, + {"Silicom Bypass PEG4BPFI6LX series adapter"}, + {"Silicom Bypass PEG4BPFI6ZX series adapter"}, + {"Silicom Bypass PEG2BPI6 series adapter"}, + {"Silicom Bypass PEG2BPFI6 series adapter"}, + {"Silicom Bypass PEG2BPFI6LX series adapter"}, + {"Silicom Bypass PEG2BPFI6ZX series adapter"}, + {"Silicom Bypass PEG2BPFI6FLXM series adapter"}, + {"Silicom Bypass PEG4BPI6FC series adapter"}, + {"Silicom Bypass PEG4BPFI6FC series adapter"}, + {"Silicom Bypass PEG4BPFI6FCLX series adapter"}, + {"Silicom Bypass PEG4BPFI6FCZX series adapter"}, + {"Silicom Bypass PEG6BPI6 series adapter"}, + {"Silicom Bypass PEG2BPI6SC6 series adapter"}, + {"Silicom Bypass MEG2BPI6 series adapter"}, + {"Silicom Bypass XEG2BPI6 series adapter"}, + {"Silicom Bypass MEG4BPI6 series adapter"}, + {"Silicom Bypass PEG2BPFI5-SD series adapter"}, + {"Silicom Bypass PEG2BPFI5LX-SD series adapter"}, + {"Silicom Bypass PXEG4BPFI-SD series adapter"}, + {"Silicom Bypass MxEG2BPI6 series adapter"}, + {"Silicom Bypass MxEG2BPFI6 series adapter"}, + {"Silicom Bypass MxEG2BPFI6LX series adapter"}, + {"Silicom Bypass MxEG2BPFI6ZX series adapter"}, + {"Silicom Bypass MxEG4BPI6 series adapter"}, + {"Silicom Bypass MxEG4BPFI6 series adapter"}, + {"Silicom Bypass MxEG4BPFI6LX series adapter"}, + {"Silicom Bypass MxEG4BPFI6ZX series adapter"}, + {"Silicom Bypass MxEG6BPI6 series adapter"}, + {"Silicom Bypass MxE2G4BPi80 series adapter"}, + {"Silicom Bypass MxE2G4BPFi80 series adapter"}, + {"Silicom Bypass MxE2G4BPFi80LX series adapter"}, + {"Silicom Bypass MxE2G4BPFi80ZX series adapter"}, + + {"Silicom Bypass PE210G2SPI9 series adapter"}, + + {"Silicom Bypass MxE210G2BPI9CX4 series adapter"}, + {"Silicom Bypass MxE210G2BPI9SR series adapter"}, + {"Silicom Bypass MxE210G2BPI9LR series adapter"}, + {"Silicom Bypass MxE210G2BPI9T series adapter"}, + + {"Silicom Bypass PE210G2BPI9CX4 series adapter"}, + {"Silicom Bypass PE210G2BPI9SR series adapter"}, + {"Silicom Bypass PE210G2BPI9LR series adapter"}, + {"Silicom Bypass PE210G2BPI9T series adapter"}, + + {"Silicom Bypass M2EG2BPFI6 series adapter"}, + {"Silicom Bypass M2EG2BPFI6LX series adapter"}, + {"Silicom Bypass M2EG2BPFI6ZX series adapter"}, + {"Silicom Bypass M2EG4BPI6 series adapter"}, + {"Silicom Bypass M2EG4BPFI6 series adapter"}, + {"Silicom Bypass M2EG4BPFI6LX series adapter"}, + {"Silicom Bypass M2EG4BPFI6ZX series adapter"}, + {"Silicom Bypass M2EG6BPI6 series adapter"}, + + {"Silicom Bypass PEG2DBI6 series adapter"}, + {"Silicom Bypass PEG2DBFI6 series adapter"}, + {"Silicom Bypass PEG2DBFI6LX series adapter"}, + {"Silicom Bypass PEG2DBFI6ZX series adapter"}, + + {"Silicom Bypass PE2G4BPi80 series adapter"}, + {"Silicom Bypass PE2G4BPFi80 series adapter"}, + {"Silicom Bypass PE2G4BPFi80LX series adapter"}, + {"Silicom Bypass PE2G4BPFi80ZX series adapter"}, + + {"Silicom Bypass PE2G4BPi80L series adapter"}, + {"Silicom Bypass MxE2G8BPi80A series adapter"}, + + {"Silicom Bypass PE2G2BPi35 series adapter"}, + {"Silicom Bypass PAC1200BPi35 series adapter"}, + {"Silicom Bypass PE2G2BPFi35 series adapter"}, + {"Silicom Bypass PE2G2BPFi35LX series adapter"}, + {"Silicom Bypass PE2G2BPFi35ZX series adapter"}, + + {"Silicom Bypass PE2G4BPi35 series adapter"}, + {"Silicom Bypass PE2G4BPi35L series adapter"}, + {"Silicom Bypass PE2G4BPFi35 series adapter"}, + {"Silicom Bypass PE2G4BPFi35LX series adapter"}, + {"Silicom Bypass PE2G4BPFi35ZX series adapter"}, + + {"Silicom Bypass PE2G6BPi35 series adapter"}, + {"Silicom Bypass PE2G6BPi35CX series adapter"}, + + {"Silicom Bypass PE2G2BPi80 series adapter"}, + {"Silicom Bypass PE2G2BPFi80 series adapter"}, + {"Silicom Bypass PE2G2BPFi80LX series adapter"}, + {"Silicom Bypass PE2G2BPFi80ZX series adapter"}, + + {"Silicom Bypass M2E10G2BPI9CX4 series adapter"}, + {"Silicom Bypass M2E10G2BPI9SR series adapter"}, + {"Silicom Bypass M2E10G2BPI9LR series adapter"}, + {"Silicom Bypass M2E10G2BPI9T series adapter"}, + {"Silicom Bypass MxE2G8BPi80 series adapter"}, + {"Silicom Bypass PE210G2DBi9SR series adapter"}, + {"Silicom Bypass PE210G2DBi9SRRB series adapter"}, + {"Silicom Bypass PE210G2DBi9LR series adapter"}, + {"Silicom Bypass PE210G2DBi9LRRB series adapter"}, + {"Silicom Bypass PE310G4DBi9-SR series adapter"}, + {"Silicom Bypass PE310G4BPi9T series adapter"}, + {"Silicom Bypass PE310G4BPi9SR series adapter"}, + {"Silicom Bypass PE310G4BPi9LR series adapter"}, + {"Silicom Bypass PE210G2BPi40T series adapter"}, + {0}, + }; + + static bpmod_info_t tx_ctl_pci_tbl[] = { + {0x8086, 0x107a, SILICOM_SVID, SILICOM_PXG2BPFI_SSID, PXG2BPFI, + "PXG2BPFI-SD"}, + {0x8086, 0x107a, SILICOM_SVID, SILICOM_PXG2BPFIL_SSID, PXG2BPFIL, + "PXG2BPFIL-SD"}, + {0x8086, 0x107a, SILICOM_SVID, SILICOM_PXG2BPFILX_SSID, PXG2BPFILX, + "PXG2BPFILX-SD"}, + {0x8086, 0x107a, SILICOM_SVID, SILICOM_PXG2BPFILLX_SSID, PXG2BPFILLX, + "PXG2BPFILLXSD"}, + {0x8086, 0x1010, SILICOM_SVID, SILICOM_PXGBPI_SSID, PXGBPI, + "PXG2BPI-SD"}, + {0x8086, 0x1079, SILICOM_SVID, SILICOM_PXGBPIG_SSID, PXGBPIG, + "PXG2BPIG-SD"}, + {0x8086, 0x107a, SILICOM_SVID, SILICOM_PXG2TBFI_SSID, PXG2TBFI, + "PXG2TBFI-SD"}, + {0x8086, 0x1079, SILICOM_SVID, SILICOM_PXG4BPI_SSID, PXG4BPI, + "PXG4BPI-SD"}, + {0x8086, 0x107a, SILICOM_SVID, SILICOM_PXG4BPFI_SSID, PXG4BPFI, + "PXG4BPFI-SD"}, + {0x8086, 0x107a, SILICOM_SVID, SILICOM_PXG4BPFILX_SSID, PXG4BPFILX, + "PXG4BPFILX-SD"}, + {0x8086, 0x1079, SILICOM_SVID, SILICOM_PEG4BPI_SSID, PEG4BPI, + "PEXG4BPI-SD"}, + {0x8086, 0x105e, SILICOM_SVID, SILICOM_PEG2BPI_SSID, PEG2BPI, + "PEG2BPI-SD"}, + {0x8086, 0x105e, SILICOM_SVID, SILICOM_PEG4BPIN_SSID, PEG4BPIN, + "PEG4BPI-SD"}, + {0x8086, 0x105f, SILICOM_SVID, SILICOM_PEG2BPFI_SSID, PEG2BPFI, + "PEG2BPFI-SD"}, + {0x8086, 0x105f, SILICOM_SVID, SILICOM_PEG2BPFILX_SSID, PEG2BPFILX, + "PEG2BPFILX-SD"}, + {0x8086, 0x107a, SILICOM_SVID, SILICOM_PMCXG2BPFI_SSID, PMCXG2BPFI, + "PMCX2BPFI-SD"}, + {0x8086, 0x107a, NOKIA_PMCXG2BPFIN_SVID, NOKIA_PMCXG2BPFIN_SSID, + PMCXG2BPFIN, "PMCX2BPFI-N"}, + {0x8086, INTEL_PEG4BPII_PID, 0x8086, INTEL_PEG4BPII_SSID, PEG4BPII, + "PEG4BPII"}, + {0x8086, INTEL_PEG4BPIIO_PID, 0x8086, INTEL_PEG4BPIIO_SSID, PEG4BPIIO, + "PEG4BPII0"}, + {0x8086, INTEL_PEG4BPFII_PID, 0x8086, INTEL_PEG4BPFII_SSID, PEG4BPFII, + "PEG4BPFII"}, + {0x8086, 0x1079, NOKIA_PMCXG2BPFIN_SVID, NOKIA_PMCXG2BPIN_SSID, + PMCXG2BPIN, "PMCX2BPI-N"}, + {0x8086, 0x1079, NOKIA_PMCXG2BPFIN_SVID, NOKIA_PMCXG4BPIN_SSID, + PMCXG4BPIN, "PMCX4BPI-N"}, + {0x8086, 0x1079, SILICOM_SVID, SILICOM_PXG2BISC1_SSID, PXG2BISC1, + "PXG2BISC1-SD"}, + {0x8086, 0x105f, SILICOM_SVID, SILICOM_PEG2TBFI_SSID, PEG2TBFI, + "PEG2TBFI-SD"}, + {0x8086, 0x1079, SILICOM_SVID, SILICOM_PXG2TBI_SSID, PXG2TBI, + "PXG2TBI-SD"}, + {0x8086, 0x107a, SILICOM_SVID, SILICOM_PXG4BPFID_SSID, PXG4BPFID, + "PXG4BPFID-SD"}, + {0x8086, 0x105f, SILICOM_SVID, SILICOM_PEG4BPFI_SSID, PEG4BPFI, + "PEG4BPFI-SD"}, + {0x8086, 0x105e, SILICOM_SVID, SILICOM_PEG4BPIPT_SSID, PEG4BPIPT, + "PEG4BPIPT-SD"}, + {0x8086, 0x1079, SILICOM_SVID, SILICOM_PXG6BPI_SSID, PXG6BPI, + "PXG6BPI-SD"}, + {0x8086, 0x10a7, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PEG4BPIL_SSID /*PCI_ANY_ID */ , PEG4BPIL, "PEG4BPIL-SD"}, + {0x8086, 0x1079, NOKIA_PMCXG2BPFIN_SVID, NOKIA_PMCXG2BPIN2_SSID, + PMCXG2BPIN2, "PMCX2BPI-N2"}, + {0x8086, 0x1079, NOKIA_PMCXG2BPFIN_SVID, NOKIA_PMCXG4BPIN2_SSID, + PMCXG4BPIN2, "PMCX4BPI-N2"}, + {0x8086, 0x1079, SILICOM_SVID, SILICOM_PMCX2BPI_SSID, PMCX2BPI, + "PMCX2BPI-SD"}, + {0x8086, 0x1079, SILICOM_SVID, SILICOM_PMCX4BPI_SSID, PMCX4BPI, + "PMCX4BPI-SD"}, + {0x8086, 0x105f, SILICOM_SVID, SILICOM_PEG2BPFID_SSID, PEG2BPFID, + "PEG2BPFID-SD"}, + {0x8086, 0x105f, SILICOM_SVID, SILICOM_PEG2BPFIDLX_SSID, PEG2BPFIDLX, + "PEG2BPFIDLXSD"}, + {0x8086, 0x105f, SILICOM_SVID, SILICOM_MEG2BPFILN_SSID, MEG2BPFILN, + "MEG2BPFILN-SD"}, + {0x8086, 0x105f, SILICOM_SVID, SILICOM_MEG2BPFINX_SSID, MEG2BPFINX, + "MEG2BPFINX-SD"}, + {0x8086, 0x105f, SILICOM_SVID, SILICOM_PEG4BPFILX_SSID, PEG4BPFILX, + "PEG4BPFILX-SD"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID, SILICOM_PE10G2BPISR_SSID, + PE10G2BPISR, "PE10G2BPISR"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID, SILICOM_PE10G2BPILR_SSID, + PE10G2BPILR, "PE10G2BPILR"}, + {0x8086, 0x10a9, SILICOM_SVID, SILICOM_MHIO8AD_SSID, MHIO8AD, + "MHIO8AD-SD"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID, SILICOM_PE10G2BPICX4_SSID, + PE10G2BPISR, "PE10G2BPICX4"}, + {0x8086, 0x10a7, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PEG2BPI5_SSID /*PCI_ANY_ID */ , PEG2BPI5, "PEG2BPI5-SD"}, + {0x8086, 0x10a7, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PEG6BPI_SSID /*PCI_ANY_ID */ , PEG6BPI, "PEG6BPI5"}, + {0x8086, 0x10a9, SILICOM_SVID /*PCI_ANY_ID */ , SILICOM_PEG4BPFI5_SSID, + PEG4BPFI5, "PEG4BPFI5"}, + {0x8086, 0x10a9, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PEG4BPFI5LX_SSID, PEG4BPFI5LX, "PEG4BPFI5LX"}, + {0x8086, 0x105f, SILICOM_SVID, SILICOM_MEG2BPFILXLN_SSID, MEG2BPFILXLN, + "MEG2BPFILXLN"}, + {0x8086, 0x105e, SILICOM_SVID, SILICOM_PEG2BPIX1_SSID, PEG2BPIX1, + "PEG2BPIX1-SD"}, + {0x8086, 0x105f, SILICOM_SVID, SILICOM_MEG2BPFILXNX_SSID, MEG2BPFILXNX, + "MEG2BPFILXNX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID, SILICOM_XE10G2BPIT_SSID, XE10G2BPIT, + "XE10G2BPIT"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID, SILICOM_XE10G2BPICX4_SSID, + XE10G2BPICX4, "XE10G2BPICX4"}, + {0x8086, 0x10C6, SILICOM_SVID, SILICOM_XE10G2BPISR_SSID, XE10G2BPISR, + "XE10G2BPISR"}, + {0x8086, 0x10C6, SILICOM_SVID, SILICOM_XE10G2BPILR_SSID, XE10G2BPILR, + "XE10G2BPILR"}, + {0x8086, 0x10C6, NOKIA_XE10G2BPIXR_SVID, NOKIA_XE10G2BPIXR_SSID, + XE10G2BPIXR, "XE10G2BPIXR"}, + {0x8086, 0x10C6, SILICOM_SVID, SILICOM_PE10GDBISR_SSID, PE10GDBISR, + "PE10G2DBISR"}, + {0x8086, 0x10C6, SILICOM_SVID, SILICOM_PE10GDBILR_SSID, PE10GDBILR, + "PE10G2DBILR"}, + {0x8086, 0x10a7, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PEG2BISC6_SSID /*PCI_ANY_ID */ , PEG2BISC6, "PEG2BI5SC6"}, + {0x8086, 0x10a7, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PEG6BPIFC_SSID /*PCI_ANY_ID */ , PEG6BPIFC, "PEG6BPI5FC"}, + + {BROADCOM_VID, BROADCOM_PE10G2_PID, SILICOM_SVID, + SILICOM_PE10G2BPTCX4_SSID, PE10G2BPTCX4, "PE10G2BPTCX4"}, + {BROADCOM_VID, BROADCOM_PE10G2_PID, SILICOM_SVID, + SILICOM_PE10G2BPTSR_SSID, PE10G2BPTSR, "PE10G2BPTSR"}, + {BROADCOM_VID, BROADCOM_PE10G2_PID, SILICOM_SVID, + SILICOM_PE10G2BPTLR_SSID, PE10G2BPTLR, "PE10G2BPTLR"}, + {BROADCOM_VID, BROADCOM_PE10G2_PID, SILICOM_SVID, + SILICOM_PE10G2BPTT_SSID, PE10G2BPTT, "PE10G2BPTT"}, + + /* {BROADCOM_VID, BROADCOM_PE10G2_PID, PCI_ANY_ID, PCI_ANY_ID, PE10G2BPTCX4, "PE10G2BPTCX4"}, */ + + {0x8086, 0x10c9, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PEG4BPI6_SSID /*PCI_ANY_ID */ , PEG4BPI6, "PEG4BPI6"}, + {0x8086, 0x10e6, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PEG4BPFI6_SSID /*PCI_ANY_ID */ , PEG4BPFI6, "PEG4BPFI6"}, + {0x8086, 0x10e6, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PEG4BPFI6LX_SSID /*PCI_ANY_ID */ , PEG4BPFI6LX, "PEG4BPFI6LX"}, + {0x8086, 0x10e6, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PEG4BPFI6ZX_SSID /*PCI_ANY_ID */ , PEG4BPFI6ZX, "PEG4BPFI6ZX"}, + {0x8086, 0x10c9, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PEG2BPI6_SSID /*PCI_ANY_ID */ , PEG2BPI6, "PEG2BPI6"}, + {0x8086, 0x10e6, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PEG2BPFI6_SSID /*PCI_ANY_ID */ , PEG2BPFI6, "PEG2BPFI6"}, + {0x8086, 0x10e6, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PEG2BPFI6LX_SSID /*PCI_ANY_ID */ , PEG2BPFI6LX, "PEG2BPFI6LX"}, + {0x8086, 0x10e6, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PEG2BPFI6ZX_SSID /*PCI_ANY_ID */ , PEG2BPFI6ZX, "PEG2BPFI6ZX"}, + {0x8086, 0x10e7, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PEG2BPFI6FLXM_SSID /*PCI_ANY_ID */ , PEG2BPFI6FLXM, + "PEG2BPFI6FLXM"}, + {0x8086, 0x10c9, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PEG4BPI6FC_SSID /*PCI_ANY_ID */ , PEG4BPI6FC, "PEG4BPI6FC"}, + {0x8086, 0x10e6, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PEG4BPFI6FC_SSID /*PCI_ANY_ID */ , PEG4BPFI6FC, "PEG4BPFI6FC"}, + {0x8086, 0x10e6, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PEG4BPFI6FCLX_SSID /*PCI_ANY_ID */ , PEG4BPFI6FCLX, + "PEG4BPFI6FCLX"}, + {0x8086, 0x10e6, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PEG4BPFI6FCZX_SSID /*PCI_ANY_ID */ , PEG4BPFI6FCZX, + "PEG4BPFI6FCZX"}, + {0x8086, 0x10c9, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PEG6BPI6_SSID /*PCI_ANY_ID */ , PEG6BPI6, "PEG6BPI6"}, + {0x8086, 0x10c9, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PEG2BPI6SC6_SSID /*PCI_ANY_ID */ , PEG2BPI6SC6, + "PEG6BPI62SC6"}, + {0x8086, 0x10c9, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_MEG2BPI6_SSID /*PCI_ANY_ID */ , MEG2BPI6, "MEG2BPI6"}, + {0x8086, 0x10c9, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_XEG2BPI6_SSID /*PCI_ANY_ID */ , XEG2BPI6, "XEG2BPI6"}, + {0x8086, 0x10c9, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_MEG4BPI6_SSID /*PCI_ANY_ID */ , MEG4BPI6, "MEG4BPI6"}, + + {0x8086, 0x10a9, SILICOM_SVID /*PCI_ANY_ID */ , SILICOM_PEG2BPFI5_SSID, + PEG2BPFI5, "PEG2BPFI5"}, + {0x8086, 0x10a9, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PEG2BPFI5LX_SSID, PEG2BPFI5LX, "PEG2BPFI5LX"}, + + {0x8086, 0x105f, SILICOM_SVID, SILICOM_PXEG4BPFI_SSID, PXEG4BPFI, + "PXEG4BPFI-SD"}, + + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M1EG2BPI6_SSID /*PCI_ANY_ID */ , M1EG2BPI6, "MxEG2BPI6"}, + + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M1EG2BPFI6_SSID /*PCI_ANY_ID */ , M1EG2BPFI6, "MxEG2BPFI6"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M1EG2BPFI6LX_SSID /*PCI_ANY_ID */ , M1EG2BPFI6LX, + "MxEG2BPFI6LX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M1EG2BPFI6ZX_SSID /*PCI_ANY_ID */ , M1EG2BPFI6ZX, + "MxEG2BPFI6ZX"}, + + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M1EG4BPI6_SSID /*PCI_ANY_ID */ , M1EG4BPI6, "MxEG4BPI6"}, + + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M1EG4BPFI6_SSID /*PCI_ANY_ID */ , M1EG4BPFI6, "MxEG4BPFI6"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M1EG4BPFI6LX_SSID /*PCI_ANY_ID */ , M1EG4BPFI6LX, + "MxEG4BPFI6LX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M1EG4BPFI6ZX_SSID /*PCI_ANY_ID */ , M1EG4BPFI6ZX, + "MxEG4BPFI6ZX"}, + + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M1EG6BPI6_SSID /*PCI_ANY_ID */ , M1EG6BPI6, "MxEG6BPI6"}, + + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M1E2G4BPi80_SSID /*PCI_ANY_ID */ , M1E2G4BPi80, "MxE2G4BPi80"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M1E2G4BPFi80_SSID /*PCI_ANY_ID */ , M1E2G4BPFi80, + "MxE2G4BPFi80"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M1E2G4BPFi80LX_SSID /*PCI_ANY_ID */ , M1E2G4BPFi80LX, + "MxE2G4BPFi80LX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M1E2G4BPFi80ZX_SSID /*PCI_ANY_ID */ , M1E2G4BPFi80ZX, + "MxE2G4BPFi80ZX"}, + + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M2EG2BPFI6_SSID /*PCI_ANY_ID */ , M2EG2BPFI6, "M2EG2BPFI6"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M2EG2BPFI6LX_SSID /*PCI_ANY_ID */ , M2EG2BPFI6LX, + "M2EG2BPFI6LX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M2EG2BPFI6ZX_SSID /*PCI_ANY_ID */ , M2EG2BPFI6ZX, + "M2EG2BPFI6ZX"}, + + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M2EG4BPI6_SSID /*PCI_ANY_ID */ , M2EG4BPI6, "M2EG4BPI6"}, + + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M2EG4BPFI6_SSID /*PCI_ANY_ID */ , M2EG4BPFI6, "M2EG4BPFI6"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M2EG4BPFI6LX_SSID /*PCI_ANY_ID */ , M2EG4BPFI6LX, + "M2EG4BPFI6LX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M2EG4BPFI6ZX_SSID /*PCI_ANY_ID */ , M2EG4BPFI6ZX, + "M2EG4BPFI6ZX"}, + + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M2EG6BPI6_SSID /*PCI_ANY_ID */ , M2EG6BPI6, "M2EG6BPI6"}, + + {0x8086, 0x10c9, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PEG2DBI6_SSID /*PCI_ANY_ID */ , PEG2DBI6, "PEG2DBI6"}, + {0x8086, 0x10e6, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PEG2DBFI6_SSID /*PCI_ANY_ID */ , PEG2DBFI6, "PEG2DBFI6"}, + {0x8086, 0x10e6, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PEG2DBFI6LX_SSID /*PCI_ANY_ID */ , PEG2DBFI6LX, "PEG2DBFI6LX"}, + {0x8086, 0x10e6, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PEG2DBFI6ZX_SSID /*PCI_ANY_ID */ , PEG2DBFI6ZX, "PEG2DBFI6ZX"}, + + {0x8086, 0x10F9, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PE210G2DBi9SR_SSID, PE210G2DBi9SR, "PE210G2DBi9SR"}, + {0x8086, 0x10F9, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PE210G2DBi9LR_SSID, PE210G2DBi9LR, "PE210G2DBi9LR"}, + {0x8086, 0x10F9, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PE310G4DBi940SR_SSID, PE310G4DBi940SR, "PE310G4DBi9SR"}, + + {0x8086, 0x10Fb, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PE310G4BPi9T_SSID, PE310G4BPi9T, "PE310G4BPi9T"}, + {0x8086, 0x10Fb, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PE310G4BPi9SR_SSID, PE310G4BPi9SR, "PE310G4BPi9SR"}, + {0x8086, 0x10Fb, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PE310G4BPi9LR_SSID, PE310G4BPi9LR, "PE310G4BPi9LR"}, + + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PE2G4BPi80_SSID /*PCI_ANY_ID */ , PE2G4BPi80, "PE2G4BPi80"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PE2G4BPFi80_SSID /*PCI_ANY_ID */ , PE2G4BPFi80, "PE2G4BPFi80"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PE2G4BPFi80LX_SSID /*PCI_ANY_ID */ , PE2G4BPFi80LX, + "PE2G4BPFi80LX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PE2G4BPFi80ZX_SSID /*PCI_ANY_ID */ , PE2G4BPFi80ZX, + "PE2G4BPFi80ZX"}, + + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PE2G4BPi80L_SSID /*PCI_ANY_ID */ , PE2G4BPi80L, "PE2G4BPi80L"}, + + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M6E2G8BPi80A_SSID /*PCI_ANY_ID */ , M6E2G8BPi80A, + "MxE2G8BPi80A"}, + + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PE2G2BPi35_SSID /*PCI_ANY_ID */ , PE2G2BPi35, "PE2G2BPi35"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PAC1200BPi35_SSID /*PCI_ANY_ID */ , PAC1200BPi35, + "PAC1200BPi35"}, + + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PE2G2BPFi35_SSID /*PCI_ANY_ID */ , PE2G2BPFi35, "PE2G2BPFi35"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PE2G2BPFi35LX_SSID /*PCI_ANY_ID */ , PE2G2BPFi35LX, + "PE2G2BPFi35LX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PE2G2BPFi35ZX_SSID /*PCI_ANY_ID */ , PE2G2BPFi35ZX, + "PE2G2BPFi35ZX"}, + + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PE2G4BPi35_SSID /*PCI_ANY_ID */ , PE2G4BPi35, "PE2G4BPi35"}, + + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PE2G4BPi35L_SSID /*PCI_ANY_ID */ , PE2G4BPi35L, "PE2G4BPi35L"}, + + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PE2G4BPFi35_SSID /*PCI_ANY_ID */ , PE2G4BPFi35, "PE2G4BPFi35"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PE2G4BPFi35LX_SSID /*PCI_ANY_ID */ , PE2G4BPFi35LX, + "PE2G4BPFi35LX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PE2G4BPFi35ZX_SSID /*PCI_ANY_ID */ , PE2G4BPFi35ZX, + "PE2G4BPFi35ZX"}, + + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PE2G6BPi35_SSID /*PCI_ANY_ID */ , PE2G6BPi35, "PE2G6BPi35"}, + + + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xaa0, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xaa1, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xaa2, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xaa3, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xaa4, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xaa5, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xaa6, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xaa7, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xaa8, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xaa9, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xaaa, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xaab, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xaac, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xaad, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xaae, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xaaf, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xab0, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xab1, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xab2, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xab3, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xab4, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xab5, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xab6, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xab7, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xab8, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xab9, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xaba, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xabb, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xabc, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xabd, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xabe, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xabf, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PE2G2BPi80_SSID /*PCI_ANY_ID */ , PE2G2BPi80, "PE2G2BPi80"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PE2G2BPFi80_SSID /*PCI_ANY_ID */ , PE2G2BPFi80, "PE2G2BPFi80"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PE2G2BPFi80LX_SSID /*PCI_ANY_ID */ , PE2G2BPFi80LX, + "PE2G2BPFi80LX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PE2G2BPFi80ZX_SSID /*PCI_ANY_ID */ , PE2G2BPFi80ZX, + "PE2G2BPFi80ZX"}, + + {0x8086, 0x10c9, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_MEG2BPI6_SSID /*PCI_ANY_ID */ , MEG2BPI6, "MEG2BPI6"}, + {0x8086, 0x10c9, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_XEG2BPI6_SSID /*PCI_ANY_ID */ , XEG2BPI6, "XEG2BPI6"}, + + #if 0 + {0x8086, 0x10fb, 0x8086, INTEL_PE210G2SPI9_SSID, PE210G2SPI9, + "PE210G2SPI9"}, + #endif + {0x8086, 0x10fb, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M1E10G2BPI9CX4_SSID /*PCI_ANY_ID */ , M1E10G2BPI9CX4, + "MxE210G2BPI9CX4"}, + {0x8086, 0x10fb, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M1E10G2BPI9SR_SSID /*PCI_ANY_ID */ , M1E10G2BPI9SR, + "MxE210G2BPI9SR"}, + {0x8086, 0x10fb, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M1E10G2BPI9LR_SSID /*PCI_ANY_ID */ , M1E10G2BPI9LR, + "MxE210G2BPI9LR"}, + {0x8086, 0x10fb, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M1E10G2BPI9T_SSID /*PCI_ANY_ID */ , M1E10G2BPI9T, + "MxE210G2BPI9T"}, + + {0x8086, 0x10fb, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M2E10G2BPI9CX4_SSID /*PCI_ANY_ID */ , M2E10G2BPI9CX4, + "M2E10G2BPI9CX4"}, + {0x8086, 0x10fb, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M2E10G2BPI9SR_SSID /*PCI_ANY_ID */ , M2E10G2BPI9SR, + "M2E10G2BPI9SR"}, + {0x8086, 0x10fb, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M2E10G2BPI9LR_SSID /*PCI_ANY_ID */ , M2E10G2BPI9LR, + "M2E10G2BPI9LR"}, + {0x8086, 0x10fb, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M2E10G2BPI9T_SSID /*PCI_ANY_ID */ , M2E10G2BPI9T, + "M2E10G2BPI9T"}, + + {0x8086, 0x10fb, SILICOM_SVID, SILICOM_PE210G2BPI9CX4_SSID, + PE210G2BPI9CX4, "PE210G2BPI9CX4"}, + {0x8086, 0x10fb, SILICOM_SVID, SILICOM_PE210G2BPI9SR_SSID, + PE210G2BPI9SR, "PE210G2BPI9SR"}, + {0x8086, 0x10fb, SILICOM_SVID, SILICOM_PE210G2BPI9LR_SSID, + PE210G2BPI9LR, "PE210G2BPI9LR"}, + {0x8086, 0x10fb, SILICOM_SVID, SILICOM_PE210G2BPI9T_SSID, PE210G2BPI9T, + "PE210G2BPI9T"}, + + #if 0 + {0x1374, 0x2c, SILICOM_SVID, SILICOM_PXG4BPI_SSID, PXG4BPI, + "PXG4BPI-SD"}, + + {0x1374, 0x2d, SILICOM_SVID, SILICOM_PXG4BPFI_SSID, PXG4BPFI, + "PXG4BPFI-SD"}, + + {0x1374, 0x3f, SILICOM_SVID, SILICOM_PXG2TBI_SSID, PXG2TBI, + "PXG2TBI-SD"}, + + {0x1374, 0x3d, SILICOM_SVID, SILICOM_PXG2BISC1_SSID, PXG2BISC1, + "PXG2BISC1-SD"}, + + {0x1374, 0x40, SILICOM_SVID, SILICOM_PEG4BPFI_SSID, PEG4BPFI, + "PEG4BPFI-SD"}, + + #ifdef BP_SELF_TEST + {0x1374, 0x28, SILICOM_SVID, 0x28, PXGBPI, "PXG2BPI-SD"}, + #endif + #endif + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M6E2G8BPi80_SSID /*PCI_ANY_ID */ , M6E2G8BPi80, "MxE2G8BPi80"}, + {0x8086, 0x1528, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PE210G2BPi40_SSID /*PCI_ANY_ID */ , PE210G2BPi40, + "PE210G2BPi40T"}, + + /* required last entry */ + {0,} + }; + + static void find_fw(bpctl_dev_t *dev) + { + unsigned long mmio_start, mmio_len; + struct pci_dev *pdev1 = dev->pdev; + + if ((OLD_IF_SERIES(dev->subdevice)) || + (INTEL_IF_SERIES(dev->subdevice))) + dev->bp_fw_ver = 0xff; + else + dev->bp_fw_ver = bypass_fw_ver(dev); + + if (dev->bp_10gb == 1 && dev->bp_fw_ver == 0xff) { + int cnt = 100; + while (cnt--) { + iounmap((void *)dev->mem_map); + mmio_start = pci_resource_start(pdev1, 0); + mmio_len = pci_resource_len(pdev1, 0); + + dev->mem_map = (unsigned long) + ioremap(mmio_start, mmio_len); + + dev->bp_fw_ver = bypass_fw_ver(dev); + if (dev-> bp_fw_ver == 0xa8) + break; + } + } + /* dev->bp_fw_ver=0xa8; */ + printk("firmware version: 0x%x\n", dev->bp_fw_ver); + } + + static int init_one(bpctl_dev_t *dev, bpmod_info_t *info, struct pci_dev *pdev1) + { + unsigned long mmio_start, mmio_len; + + dev->pdev = pdev1; + mmio_start = pci_resource_start(pdev1, 0); + mmio_len = pci_resource_len(pdev1, 0); + + dev->desc = dev_desc[info->index].name; + dev->name = info->bp_name; + dev->device = info->device; + dev->vendor = info->vendor; + dev->subdevice = info->subdevice; + dev->subvendor = info->subvendor; + dev->func = PCI_FUNC(pdev1->devfn); + dev->slot = PCI_SLOT(pdev1->devfn); + dev->bus = pdev1->bus->number; + dev->mem_map = (unsigned long)ioremap(mmio_start, mmio_len); + #ifdef BP_SYNC_FLAG + spin_lock_init(&dev->bypass_wr_lock); + #endif + if (BP10G9_IF_SERIES(dev->subdevice)) + dev->bp_10g9 = 1; + if (BP10G_IF_SERIES(dev->subdevice)) + dev->bp_10g = 1; + if (PEG540_IF_SERIES(dev->subdevice)) + dev->bp_540 = 1; + if (PEGF5_IF_SERIES(dev->subdevice)) + dev->bp_fiber5 = 1; + if (PEG80_IF_SERIES(dev->subdevice)) + dev->bp_i80 = 1; + if (PEGF80_IF_SERIES(dev->subdevice)) + dev->bp_i80 = 1; + if ((dev->subdevice & 0xa00) == 0xa00) + dev->bp_i80 = 1; + if (BP10GB_IF_SERIES(dev->subdevice)) { + if (dev->ifindex == 0) { + unregister_chrdev(major_num, DEVICE_NAME); + printk("Please load network driver for %s adapter!\n", + dev->name); + return -1; + } + + if (dev->ndev && !(dev->ndev->flags & IFF_UP)) { + unregister_chrdev(major_num, DEVICE_NAME); + printk("Please bring up network interfaces for %s adapter!\n", + dev->name); + return -1; + } + dev->bp_10gb = 1; + } + + if (!dev->bp_10g9) { + if (is_bypass_fn(dev)) { + printk(KERN_INFO "%s found, ", + dev->name); + find_fw(dev); + } + dev->wdt_status = WDT_STATUS_UNKNOWN; + dev->reset_time = 0; + atomic_set(&dev->wdt_busy, 0); + dev->bp_status_un = 1; + + bypass_caps_init(dev); + + init_bypass_wd_auto(dev); + init_bypass_tpl_auto(dev); + if (NOKIA_SERIES(dev->subdevice)) + reset_cont(dev); + } + #ifdef BP_SELF_TEST + if ((dev->bp_tx_data = kzalloc(BPTEST_DATA_LEN, GFP_KERNEL))) { + memset(dev->bp_tx_data, 0xff, 6); + memset(dev->bp_tx_data + 6, 0x0, 1); + memset(dev->bp_tx_data + 7, 0xaa, 5); + *(__be16 *)(dev->bp_tx_data + 12) = htons(ETH_P_BPTEST); + } else + printk("bp_ctl: Memory allocation error!\n"); + #endif + return 0; + } + + /* + * Initialize the module - Register the character device + */ + + static int __init bypass_init_module(void) + { + int ret_val, idx, idx_dev = 0; + struct pci_dev *pdev1 = NULL; + bpctl_dev_t *dev; + + printk(BP_MOD_DESCR " v" BP_MOD_VER "\n"); + ret_val = register_chrdev(major_num, DEVICE_NAME, &Fops); + if (ret_val < 0) { + printk("%s failed with %d\n", DEVICE_NAME, ret_val); + return ret_val; + } + major_num = ret_val; /* dynamic */ + for (idx = 0; tx_ctl_pci_tbl[idx].vendor; idx++) { + while ((pdev1 = pci_get_subsys(tx_ctl_pci_tbl[idx].vendor, + tx_ctl_pci_tbl[idx].device, + tx_ctl_pci_tbl[idx].subvendor, + tx_ctl_pci_tbl[idx].subdevice, + pdev1))) { + + device_num++; + } + } + if (!device_num) { + printk("No such device\n"); + unregister_chrdev(major_num, DEVICE_NAME); + return -1; + } + + bpctl_dev_arr = kmalloc((device_num) * sizeof(bpctl_dev_t), GFP_KERNEL); + + if (!bpctl_dev_arr) { + printk("Allocation error\n"); + unregister_chrdev(major_num, DEVICE_NAME); + return -1; + } + memset(bpctl_dev_arr, 0, ((device_num) * sizeof(bpctl_dev_t))); + + pdev1 = NULL; + dev = bpctl_dev_arr; + for (idx = 0; tx_ctl_pci_tbl[idx].vendor; idx++) { + while ((pdev1 = pci_get_subsys(tx_ctl_pci_tbl[idx].vendor, + tx_ctl_pci_tbl[idx].device, + tx_ctl_pci_tbl[idx].subvendor, + tx_ctl_pci_tbl[idx].subdevice, + pdev1))) { + if (init_one(dev, &tx_ctl_pci_tbl[idx], pdev1) < 0) + return -1; + dev++; + } + } + if_scan_init(); + + sema_init(&bpctl_sema, 1); + spin_lock_init(&bpvm_lock); + { + + bpctl_dev_t *pbpctl_dev_c = NULL; + for (idx_dev = 0, dev = bpctl_dev_arr; + idx_dev < device_num && dev->pdev; + idx_dev++, dev++) { + if (dev->bp_10g9) { + pbpctl_dev_c = get_status_port_fn(dev); + if (is_bypass_fn(dev)) { + printk(KERN_INFO "%s found, ", + dev->name); + dev->bp_fw_ver = bypass_fw_ver(dev); + printk("firmware version: 0x%x\n", + dev->bp_fw_ver); + } + dev->wdt_status = WDT_STATUS_UNKNOWN; + dev->reset_time = 0; + atomic_set(&dev->wdt_busy, 0); + dev->bp_status_un = 1; + + bypass_caps_init(dev); + + init_bypass_wd_auto(dev); + init_bypass_tpl_auto(dev); + + } + + } + } + + register_netdevice_notifier(&bp_notifier_block); + #ifdef BP_PROC_SUPPORT + { + int i = 0; + /* unsigned long flags; */ + /* rcu_read_lock(); */ + bp_proc_create(); + for (i = 0; i < device_num; i++) { + if (bpctl_dev_arr[i].ifindex) { + /* spin_lock_irqsave(&bpvm_lock, flags); */ + bypass_proc_remove_dev_sd(&bpctl_dev_arr[i]); + bypass_proc_create_dev_sd(&bpctl_dev_arr[i]); + /* spin_unlock_irqrestore(&bpvm_lock, flags); */ + } + + } + /* rcu_read_unlock(); */ + } + #endif + + return 0; + } + + /* + * Cleanup - unregister the appropriate file from /proc + */ + static void __exit bypass_cleanup_module(void) + { + int i; + unregister_netdevice_notifier(&bp_notifier_block); + + for (i = 0; i < device_num; i++) { + /* unsigned long flags; */ + #ifdef BP_PROC_SUPPORT + /* spin_lock_irqsave(&bpvm_lock, flags); + rcu_read_lock(); */ + bypass_proc_remove_dev_sd(&bpctl_dev_arr[i]); -/* spin_unlock_irqrestore(&bpvm_lock, flags); ++/* spin_unlock_irqrestore(&bpvm_lock, flags); + rcu_read_unlock(); */ + #endif + remove_bypass_wd_auto(&bpctl_dev_arr[i]); + bpctl_dev_arr[i].reset_time = 0; + + remove_bypass_tpl_auto(&bpctl_dev_arr[i]); + } + + /* unmap all devices */ + for (i = 0; i < device_num; i++) { + #ifdef BP_SELF_TEST - if (bpctl_dev_arr[i].bp_tx_data) - kfree(bpctl_dev_arr[i].bp_tx_data); ++ kfree(bpctl_dev_arr[i].bp_tx_data); + #endif + iounmap((void *)(bpctl_dev_arr[i].mem_map)); + } + + /* free all devices space */ - if (bpctl_dev_arr) - kfree(bpctl_dev_arr); ++ kfree(bpctl_dev_arr); + + /* -* Unregister the device ++* Unregister the device + */ + unregister_chrdev(major_num, DEVICE_NAME); + } + + module_init(bypass_init_module); + module_exit(bypass_cleanup_module); + + int is_bypass_sd(int ifindex) + { + return is_bypass(get_dev_idx_p(ifindex)); + } + + int set_bypass_sd(int ifindex, int bypass_mode) + { + + return set_bypass_fn(get_dev_idx_p(ifindex), bypass_mode); + } + + int get_bypass_sd(int ifindex) + { + + return get_bypass_fn(get_dev_idx_p(ifindex)); + } + + int get_bypass_change_sd(int ifindex) + { + + return get_bypass_change_fn(get_dev_idx_p(ifindex)); + } + + int set_dis_bypass_sd(int ifindex, int dis_param) + { + return set_dis_bypass_fn(get_dev_idx_p(ifindex), dis_param); + } + + int get_dis_bypass_sd(int ifindex) + { + + return get_dis_bypass_fn(get_dev_idx_p(ifindex)); + } + + int set_bypass_pwoff_sd(int ifindex, int bypass_mode) + { + return set_bypass_pwoff_fn(get_dev_idx_p(ifindex), bypass_mode); + + } + + int get_bypass_pwoff_sd(int ifindex) + { + return get_bypass_pwoff_fn(get_dev_idx_p(ifindex)); + + } + + int set_bypass_pwup_sd(int ifindex, int bypass_mode) + { + return set_bypass_pwup_fn(get_dev_idx_p(ifindex), bypass_mode); + + } + + int get_bypass_pwup_sd(int ifindex) + { + return get_bypass_pwup_fn(get_dev_idx_p(ifindex)); + + } + + int set_bypass_wd_sd(int if_index, int ms_timeout, int *ms_timeout_set) + { + if ((is_bypass(get_dev_idx_p(if_index))) <= 0) + return BP_NOT_CAP; + *ms_timeout_set = set_bypass_wd_fn(get_dev_idx_p(if_index), ms_timeout); + return 0; + } + + int get_bypass_wd_sd(int ifindex, int *timeout) + { + return get_bypass_wd_fn(get_dev_idx_p(ifindex), timeout); + + } + + int get_wd_expire_time_sd(int ifindex, int *time_left) + { + return get_wd_expire_time_fn(get_dev_idx_p(ifindex), time_left); + } + + int reset_bypass_wd_timer_sd(int ifindex) + { + return reset_bypass_wd_timer_fn(get_dev_idx_p(ifindex)); + + } + + int get_wd_set_caps_sd(int ifindex) + { + return get_wd_set_caps_fn(get_dev_idx_p(ifindex)); + + } + + int set_std_nic_sd(int ifindex, int nic_mode) + { + return set_std_nic_fn(get_dev_idx_p(ifindex), nic_mode); + + } + + int get_std_nic_sd(int ifindex) + { + return get_std_nic_fn(get_dev_idx_p(ifindex)); + + } + + int set_tap_sd(int ifindex, int tap_mode) + { + return set_tap_fn(get_dev_idx_p(ifindex), tap_mode); + + } + + int get_tap_sd(int ifindex) + { + return get_tap_fn(get_dev_idx_p(ifindex)); + + } + + int set_tap_pwup_sd(int ifindex, int tap_mode) + { + return set_tap_pwup_fn(get_dev_idx_p(ifindex), tap_mode); + + } + + int get_tap_pwup_sd(int ifindex) + { + return get_tap_pwup_fn(get_dev_idx_p(ifindex)); + + } + + int get_tap_change_sd(int ifindex) + { + return get_tap_change_fn(get_dev_idx_p(ifindex)); + + } + + int set_dis_tap_sd(int ifindex, int dis_param) + { + return set_dis_tap_fn(get_dev_idx_p(ifindex), dis_param); + + } + + int get_dis_tap_sd(int ifindex) + { + return get_dis_tap_fn(get_dev_idx_p(ifindex)); + + } + + int set_bp_disc_sd(int ifindex, int disc_mode) + { + return set_disc_fn(get_dev_idx_p(ifindex), disc_mode); + + } + + int get_bp_disc_sd(int ifindex) + { + return get_disc_fn(get_dev_idx_p(ifindex)); + + } + + int set_bp_disc_pwup_sd(int ifindex, int disc_mode) + { + return set_disc_pwup_fn(get_dev_idx_p(ifindex), disc_mode); + + } + + int get_bp_disc_pwup_sd(int ifindex) + { + return get_disc_pwup_fn(get_dev_idx_p(ifindex)); + + } + + int get_bp_disc_change_sd(int ifindex) + { + return get_disc_change_fn(get_dev_idx_p(ifindex)); + + } + + int set_bp_dis_disc_sd(int ifindex, int dis_param) + { + return set_dis_disc_fn(get_dev_idx_p(ifindex), dis_param); + + } + + int get_bp_dis_disc_sd(int ifindex) + { + return get_dis_disc_fn(get_dev_idx_p(ifindex)); + + } + + int get_wd_exp_mode_sd(int ifindex) + { + return get_wd_exp_mode_fn(get_dev_idx_p(ifindex)); + } + + int set_wd_exp_mode_sd(int ifindex, int param) + { + return set_wd_exp_mode_fn(get_dev_idx_p(ifindex), param); + + } + + int reset_cont_sd(int ifindex) + { + return reset_cont_fn(get_dev_idx_p(ifindex)); + + } + + int set_tx_sd(int ifindex, int tx_state) + { + return set_tx_fn(get_dev_idx_p(ifindex), tx_state); + + } + + int set_tpl_sd(int ifindex, int tpl_state) + { + return set_tpl_fn(get_dev_idx_p(ifindex), tpl_state); + + } + + int set_bp_hw_reset_sd(int ifindex, int status) + { + return set_bp_hw_reset_fn(get_dev_idx_p(ifindex), status); + + } + + int set_wd_autoreset_sd(int ifindex, int param) + { + return set_wd_autoreset_fn(get_dev_idx_p(ifindex), param); + + } + + int get_wd_autoreset_sd(int ifindex) + { + return get_wd_autoreset_fn(get_dev_idx_p(ifindex)); + + } + + int get_bypass_caps_sd(int ifindex) + { + return get_bypass_caps_fn(get_dev_idx_p(ifindex)); + } + + int get_bypass_slave_sd(int ifindex) + { + bpctl_dev_t *pbpctl_dev_out; + int ret = get_bypass_slave_fn(get_dev_idx_p(ifindex), &pbpctl_dev_out); + if (ret == 1) + return pbpctl_dev_out->ifindex; + return -1; + + } + + int get_tx_sd(int ifindex) + { + return get_tx_fn(get_dev_idx_p(ifindex)); + + } + + int get_tpl_sd(int ifindex) + { + return get_tpl_fn(get_dev_idx_p(ifindex)); + + } + + int get_bp_hw_reset_sd(int ifindex) + { + return get_bp_hw_reset_fn(get_dev_idx_p(ifindex)); + + } + + int get_bypass_info_sd(int ifindex, struct bp_info *bp_info) + { + return get_bypass_info_fn(get_dev_idx_p(ifindex), bp_info->prod_name, &bp_info->fw_ver); + } + + int bp_if_scan_sd(void) + { + if_scan_init(); + return 0; + } + + EXPORT_SYMBOL_NOVERS(is_bypass_sd); + EXPORT_SYMBOL_NOVERS(get_bypass_slave_sd); + EXPORT_SYMBOL_NOVERS(get_bypass_caps_sd); + EXPORT_SYMBOL_NOVERS(get_wd_set_caps_sd); + EXPORT_SYMBOL_NOVERS(set_bypass_sd); + EXPORT_SYMBOL_NOVERS(get_bypass_sd); + EXPORT_SYMBOL_NOVERS(get_bypass_change_sd); + EXPORT_SYMBOL_NOVERS(set_dis_bypass_sd); + EXPORT_SYMBOL_NOVERS(get_dis_bypass_sd); + EXPORT_SYMBOL_NOVERS(set_bypass_pwoff_sd); + EXPORT_SYMBOL_NOVERS(get_bypass_pwoff_sd); + EXPORT_SYMBOL_NOVERS(set_bypass_pwup_sd); + EXPORT_SYMBOL_NOVERS(get_bypass_pwup_sd); + EXPORT_SYMBOL_NOVERS(set_bypass_wd_sd); + EXPORT_SYMBOL_NOVERS(get_bypass_wd_sd); + EXPORT_SYMBOL_NOVERS(get_wd_expire_time_sd); + EXPORT_SYMBOL_NOVERS(reset_bypass_wd_timer_sd); + EXPORT_SYMBOL_NOVERS(set_std_nic_sd); + EXPORT_SYMBOL_NOVERS(get_std_nic_sd); + EXPORT_SYMBOL_NOVERS(set_tx_sd); + EXPORT_SYMBOL_NOVERS(get_tx_sd); + EXPORT_SYMBOL_NOVERS(set_tpl_sd); + EXPORT_SYMBOL_NOVERS(get_tpl_sd); + EXPORT_SYMBOL_NOVERS(set_bp_hw_reset_sd); + EXPORT_SYMBOL_NOVERS(get_bp_hw_reset_sd); + EXPORT_SYMBOL_NOVERS(set_tap_sd); + EXPORT_SYMBOL_NOVERS(get_tap_sd); + EXPORT_SYMBOL_NOVERS(get_tap_change_sd); + EXPORT_SYMBOL_NOVERS(set_dis_tap_sd); + EXPORT_SYMBOL_NOVERS(get_dis_tap_sd); + EXPORT_SYMBOL_NOVERS(set_tap_pwup_sd); + EXPORT_SYMBOL_NOVERS(get_tap_pwup_sd); + EXPORT_SYMBOL_NOVERS(set_wd_exp_mode_sd); + EXPORT_SYMBOL_NOVERS(get_wd_exp_mode_sd); + EXPORT_SYMBOL_NOVERS(set_wd_autoreset_sd); + EXPORT_SYMBOL_NOVERS(get_wd_autoreset_sd); + EXPORT_SYMBOL_NOVERS(set_bp_disc_sd); + EXPORT_SYMBOL_NOVERS(get_bp_disc_sd); + EXPORT_SYMBOL_NOVERS(get_bp_disc_change_sd); + EXPORT_SYMBOL_NOVERS(set_bp_dis_disc_sd); + EXPORT_SYMBOL_NOVERS(get_bp_dis_disc_sd); + EXPORT_SYMBOL_NOVERS(set_bp_disc_pwup_sd); + EXPORT_SYMBOL_NOVERS(get_bp_disc_pwup_sd); + EXPORT_SYMBOL_NOVERS(get_bypass_info_sd); + EXPORT_SYMBOL_NOVERS(bp_if_scan_sd); + + #define BP_PROC_DIR "bypass" + + static struct proc_dir_entry *bp_procfs_dir; + + int bp_proc_create(void) + { + bp_procfs_dir = proc_mkdir(BP_PROC_DIR, init_net.proc_net); + if (bp_procfs_dir == (struct proc_dir_entry *)0) { + printk(KERN_DEBUG + "Could not create procfs nicinfo directory %s\n", + BP_PROC_DIR); + return -1; + } + return 0; + } + + static int procfs_add(char *proc_name, const struct file_operations *fops, + bpctl_dev_t *dev) + { + struct bypass_pfs_sd *pfs = &dev->bypass_pfs_set; + if (!proc_create_data(proc_name, 0644, pfs->bypass_entry, fops, dev)) + return -1; + return 0; + } + + #define RO_FOPS(name) \ + static int name##_open(struct inode *inode, struct file *file) \ + { \ + return single_open(file, show_##name, PDE_DATA(inode));\ + } \ + static const struct file_operations name##_ops = { \ + .open = name##_open, \ + .read = seq_read, \ + .llseek = seq_lseek, \ + .release = single_release, \ + }; + + #define RW_FOPS(name) \ + static int name##_open(struct inode *inode, struct file *file) \ + { \ + return single_open(file, show_##name, PDE_DATA(inode));\ + } \ + static const struct file_operations name##_ops = { \ + .open = name##_open, \ + .read = seq_read, \ + .write = name##_write, \ + .llseek = seq_lseek, \ + .release = single_release, \ + }; + + static int show_bypass_info(struct seq_file *m, void *v) + { + bpctl_dev_t *dev = m->private; + + seq_printf(m, "Name\t\t\t%s\n", dev->name); + seq_printf(m, "Firmware version\t0x%x\n", dev->bp_fw_ver); + return 0; + } + RO_FOPS(bypass_info) + + static int show_bypass_slave(struct seq_file *m, void *v) + { + bpctl_dev_t *dev = m->private; + bpctl_dev_t *slave = get_status_port_fn(dev); + if (!slave) + slave = dev; + if (!slave) + seq_printf(m, "fail\n"); + else if (slave->ndev) + seq_printf(m, "%s\n", slave->ndev->name); + return 0; + } + RO_FOPS(bypass_slave) + + static int show_bypass_caps(struct seq_file *m, void *v) + { + bpctl_dev_t *dev = m->private; + int ret = get_bypass_caps_fn(dev); + if (ret == BP_NOT_CAP) + seq_printf(m, "-1\n"); + else + seq_printf(m, "0x%x\n", ret); + return 0; + } + RO_FOPS(bypass_caps) + + static int show_wd_set_caps(struct seq_file *m, void *v) + { + bpctl_dev_t *dev = m->private; + int ret = get_wd_set_caps_fn(dev); + if (ret == BP_NOT_CAP) + seq_printf(m, "-1\n"); + else + seq_printf(m, "0x%x\n", ret); + return 0; + } + RO_FOPS(wd_set_caps) + + static int user_on_off(const void __user *buffer, size_t count) + { + + char kbuf[256]; + int length = 0; + + if (count > (sizeof(kbuf) - 1)) + return -1; + + if (copy_from_user(&kbuf, buffer, count)) + return -1; + + kbuf[count] = '\0'; + length = strlen(kbuf); + if (kbuf[length - 1] == '\n') + kbuf[--length] = '\0'; + + if (strcmp(kbuf, "on") == 0) + return 1; + if (strcmp(kbuf, "off") == 0) + return 0; + return 0; + } + + static ssize_t bypass_write(struct file *file, const char __user *buffer, + size_t count, loff_t *pos) + { + int bypass_param = user_on_off(buffer, count); + if (bypass_param < 0) + return -1; + + set_bypass_fn(PDE_DATA(file_inode(file)), bypass_param); + return count; + } + static int show_bypass(struct seq_file *m, void *v) + { + bpctl_dev_t *dev = m->private; + int ret = get_bypass_fn(dev); + if (ret == BP_NOT_CAP) + seq_printf(m, "fail\n"); + else if (ret == 1) + seq_printf(m, "on\n"); + else if (ret == 0) + seq_printf(m, "off\n"); + return 0; + } + RW_FOPS(bypass) + + static ssize_t tap_write(struct file *file, const char __user *buffer, + size_t count, loff_t *pos) + { + int tap_param = user_on_off(buffer, count); + if (tap_param < 0) + return -1; + + set_tap_fn(PDE_DATA(file_inode(file)), tap_param); + return count; + } + static int show_tap(struct seq_file *m, void *v) + { + bpctl_dev_t *dev = m->private; + int ret = get_tap_fn(dev); + if (ret == BP_NOT_CAP) + seq_printf(m, "fail\n"); + else if (ret == 1) + seq_printf(m, "on\n"); + else if (ret == 0) + seq_printf(m, "off\n"); + return 0; + } + RW_FOPS(tap) + + static ssize_t disc_write(struct file *file, const char __user *buffer, + size_t count, loff_t *pos) + { + int tap_param = user_on_off(buffer, count); + if (tap_param < 0) + return -1; + + set_disc_fn(PDE_DATA(file_inode(file)), tap_param); + return count; + } + static int show_disc(struct seq_file *m, void *v) + { + bpctl_dev_t *dev = m->private; + int ret = get_disc_fn(dev); + if (ret == BP_NOT_CAP) + seq_printf(m, "fail\n"); + else if (ret == 1) + seq_printf(m, "on\n"); + else if (ret == 0) + seq_printf(m, "off\n"); + return 0; + } + RW_FOPS(disc) + + static int show_bypass_change(struct seq_file *m, void *v) + { + bpctl_dev_t *dev = m->private; + int ret = get_bypass_change_fn(dev); + if (ret == 1) + seq_printf(m, "on\n"); + else if (ret == 0) + seq_printf(m, "off\n"); + else + seq_printf(m, "fail\n"); + return 0; + } + RO_FOPS(bypass_change) + + static int show_tap_change(struct seq_file *m, void *v) + { + bpctl_dev_t *dev = m->private; + int ret = get_tap_change_fn(dev); + if (ret == 1) + seq_printf(m, "on\n"); + else if (ret == 0) + seq_printf(m, "off\n"); + else + seq_printf(m, "fail\n"); + return 0; + } + RO_FOPS(tap_change) + + static int show_disc_change(struct seq_file *m, void *v) + { + bpctl_dev_t *dev = m->private; + int ret = get_disc_change_fn(dev); + if (ret == 1) + seq_printf(m, "on\n"); + else if (ret == 0) + seq_printf(m, "off\n"); + else + seq_printf(m, "fail\n"); + return 0; + } + RO_FOPS(disc_change) + + static ssize_t bypass_wd_write(struct file *file, const char __user *buffer, + size_t count, loff_t *pos) + { + bpctl_dev_t *dev = PDE_DATA(file_inode(file)); + int timeout; + int ret = kstrtoint_from_user(buffer, count, 10, &timeout); + if (ret) + return ret; + set_bypass_wd_fn(dev, timeout); + return count; + } + static int show_bypass_wd(struct seq_file *m, void *v) + { + bpctl_dev_t *dev = m->private; + int ret = 0, timeout = 0; + + ret = get_bypass_wd_fn(dev, &timeout); + if (ret == BP_NOT_CAP) + seq_printf(m, "fail\n"); + else if (timeout == -1) + seq_printf(m, "unknown\n"); + else if (timeout == 0) + seq_printf(m, "disable\n"); + else + seq_printf(m, "%d\n", timeout); + return 0; + } + RW_FOPS(bypass_wd) + + static int show_wd_expire_time(struct seq_file *m, void *v) + { + bpctl_dev_t *dev = m->private; + int ret = 0, timeout = 0; + ret = get_wd_expire_time_fn(dev, &timeout); + if (ret == BP_NOT_CAP) + seq_printf(m, "fail\n"); + else if (timeout == -1) + seq_printf(m, "expire\n"); + else if (timeout == 0) + seq_printf(m, "disable\n"); + else + seq_printf(m, "%d\n", timeout); + return 0; + } + RO_FOPS(wd_expire_time) + + static ssize_t tpl_write(struct file *file, const char __user *buffer, + size_t count, loff_t *pos) + { + bpctl_dev_t *dev = PDE_DATA(file_inode(file)); + int tpl_param = user_on_off(buffer, count); + if (tpl_param < 0) + return -1; + + set_tpl_fn(dev, tpl_param); + return count; + } + static int show_tpl(struct seq_file *m, void *v) + { + bpctl_dev_t *dev = m->private; + int ret = get_tpl_fn(dev); + if (ret == BP_NOT_CAP) + seq_printf(m, "fail\n"); + else if (ret == 1) + seq_printf(m, "on\n"); + else if (ret == 0) + seq_printf(m, "off\n"); + return 0; + } + RW_FOPS(tpl) + + #ifdef PMC_FIX_FLAG + static ssize_t wait_at_pwup_write(struct file *file, const char __user *buffer, + size_t count, loff_t *pos) + { + bpctl_dev_t *dev = PDE_DATA(file_inode(file)); + int tpl_param = user_on_off(buffer, count); + if (tpl_param < 0) + return -1; + + set_bp_wait_at_pwup_fn(dev, tpl_param); + return count; + } + static int show_wait_at_pwup(struct seq_file *m, void *v) + { + bpctl_dev_t *dev = m->private; + int ret = get_bp_wait_at_pwup_fn(dev); + if (ret == BP_NOT_CAP) + seq_printf(m, "fail\n"); + else if (ret == 1) + seq_printf(m, "on\n"); + else if (ret == 0) + seq_printf(m, "off\n"); + return 0; + } + RW_FOPS(wait_at_pwup) + + static ssize_t hw_reset_write(struct file *file, const char __user *buffer, + size_t count, loff_t *pos) + { + bpctl_dev_t *dev = PDE_DATA(file_inode(file)); + int tpl_param = user_on_off(buffer, count); + if (tpl_param < 0) + return -1; + + set_bp_hw_reset_fn(dev, tpl_param); + return count; + } + static int show_hw_reset(struct seq_file *m, void *v) + { + bpctl_dev_t *dev = m->private; + int ret = get_bp_hw_reset_fn(dev); + if (ret == BP_NOT_CAP) + seq_printf(m, "fail\n"); + else if (ret == 1) + seq_printf(m, "on\n"); + else if (ret == 0) + seq_printf(m, "off\n"); + return 0; + } + RW_FOPS(hw_reset) + + #endif /*PMC_WAIT_FLAG */ + + static int show_reset_bypass_wd(struct seq_file *m, void *v) + { + bpctl_dev_t *dev = m->private; + int ret = reset_bypass_wd_timer_fn(dev); + if (ret == BP_NOT_CAP) + seq_printf(m, "fail\n"); + else if (ret == 0) + seq_printf(m, "disable\n"); + else if (ret == 1) + seq_printf(m, "success\n"); + return 0; + } + RO_FOPS(reset_bypass_wd) + + static ssize_t dis_bypass_write(struct file *file, const char __user *buffer, + size_t count, loff_t *pos) + { + int bypass_param = user_on_off(buffer, count); + if (bypass_param < 0) + return -EINVAL; + + set_dis_bypass_fn(PDE_DATA(file_inode(file)), bypass_param); + return count; + } + static int show_dis_bypass(struct seq_file *m, void *v) + { + bpctl_dev_t *dev = m->private; + int ret = get_dis_bypass_fn(dev); + if (ret == BP_NOT_CAP) + seq_printf(m, "fail\n"); + else if (ret == 0) + seq_printf(m, "off\n"); + else + seq_printf(m, "on\n"); + return 0; + } + RW_FOPS(dis_bypass) + + static ssize_t dis_tap_write(struct file *file, const char __user *buffer, + size_t count, loff_t *pos) + { + int tap_param = user_on_off(buffer, count); + if (tap_param < 0) + return -EINVAL; + + set_dis_tap_fn(PDE_DATA(file_inode(file)), tap_param); + return count; + } + static int show_dis_tap(struct seq_file *m, void *v) + { + bpctl_dev_t *dev = m->private; + int ret = get_dis_tap_fn(dev); + if (ret == BP_NOT_CAP) + seq_printf(m, "fail\n"); + else if (ret == 0) + seq_printf(m, "off\n"); + else + seq_printf(m, "on\n"); + return 0; + } + RW_FOPS(dis_tap) + + static ssize_t dis_disc_write(struct file *file, const char __user *buffer, + size_t count, loff_t *pos) + { + int tap_param = user_on_off(buffer, count); + if (tap_param < 0) + return -EINVAL; + + set_dis_disc_fn(PDE_DATA(file_inode(file)), tap_param); + return count; + } + static int show_dis_disc(struct seq_file *m, void *v) + { + bpctl_dev_t *dev = m->private; + int ret = get_dis_disc_fn(dev); + if (ret == BP_NOT_CAP) + seq_printf(m, "fail\n"); + else if (ret == 0) + seq_printf(m, "off\n"); + else + seq_printf(m, "on\n"); + return 0; + } + RW_FOPS(dis_disc) + + static ssize_t bypass_pwup_write(struct file *file, const char __user *buffer, + size_t count, loff_t *pos) + { + int bypass_param = user_on_off(buffer, count); + if (bypass_param < 0) + return -EINVAL; + + set_bypass_pwup_fn(PDE_DATA(file_inode(file)), bypass_param); + return count; + } + static int show_bypass_pwup(struct seq_file *m, void *v) + { + bpctl_dev_t *dev = m->private; + int ret = get_bypass_pwup_fn(dev); + if (ret == BP_NOT_CAP) + seq_printf(m, "fail\n"); + else if (ret == 0) + seq_printf(m, "off\n"); + else + seq_printf(m, "on\n"); + return 0; + } + RW_FOPS(bypass_pwup) + + static ssize_t bypass_pwoff_write(struct file *file, const char __user *buffer, + size_t count, loff_t *pos) + { + int bypass_param = user_on_off(buffer, count); + if (bypass_param < 0) + return -EINVAL; + + set_bypass_pwoff_fn(PDE_DATA(file_inode(file)), bypass_param); + return count; + } + static int show_bypass_pwoff(struct seq_file *m, void *v) + { + bpctl_dev_t *dev = m->private; + int ret = get_bypass_pwoff_fn(dev); + if (ret == BP_NOT_CAP) + seq_printf(m, "fail\n"); + else if (ret == 0) + seq_printf(m, "off\n"); + else + seq_printf(m, "on\n"); + return 0; + } + RW_FOPS(bypass_pwoff) + + static ssize_t tap_pwup_write(struct file *file, const char __user *buffer, + size_t count, loff_t *pos) + { + int tap_param = user_on_off(buffer, count); + if (tap_param < 0) + return -EINVAL; + + set_tap_pwup_fn(PDE_DATA(file_inode(file)), tap_param); + return count; + } + static int show_tap_pwup(struct seq_file *m, void *v) + { + bpctl_dev_t *dev = m->private; + int ret = get_tap_pwup_fn(dev); + if (ret == BP_NOT_CAP) + seq_printf(m, "fail\n"); + else if (ret == 0) + seq_printf(m, "off\n"); + else + seq_printf(m, "on\n"); + return 0; + } + RW_FOPS(tap_pwup) + + static ssize_t disc_pwup_write(struct file *file, const char __user *buffer, + size_t count, loff_t *pos) + { + int tap_param = user_on_off(buffer, count); + if (tap_param < 0) + return -EINVAL; + + set_disc_pwup_fn(PDE_DATA(file_inode(file)), tap_param); + return count; + } + static int show_disc_pwup(struct seq_file *m, void *v) + { + bpctl_dev_t *dev = m->private; + int ret = get_disc_pwup_fn(dev); + if (ret == BP_NOT_CAP) + seq_printf(m, "fail\n"); + else if (ret == 0) + seq_printf(m, "off\n"); + else + seq_printf(m, "on\n"); + return 0; + } + RW_FOPS(disc_pwup) + + static ssize_t std_nic_write(struct file *file, const char __user *buffer, + size_t count, loff_t *pos) + { + int bypass_param = user_on_off(buffer, count); + if (bypass_param < 0) + return -EINVAL; + + set_std_nic_fn(PDE_DATA(file_inode(file)), bypass_param); + return count; + } + static int show_std_nic(struct seq_file *m, void *v) + { + bpctl_dev_t *dev = m->private; + int ret = get_std_nic_fn(dev); + if (ret == BP_NOT_CAP) + seq_printf(m, "fail\n"); + else if (ret == 0) + seq_printf(m, "off\n"); + else + seq_printf(m, "on\n"); + return 0; + } + RW_FOPS(std_nic) + + static ssize_t wd_exp_mode_write(struct file *file, const char __user *buffer, + size_t count, loff_t *pos) + { + char kbuf[256]; + int bypass_param = 0, length = 0; + + if (count > (sizeof(kbuf) - 1)) + return -1; + + if (copy_from_user(&kbuf, buffer, count)) + return -1; + + kbuf[count] = '\0'; + length = strlen(kbuf); + if (kbuf[length - 1] == '\n') + kbuf[--length] = '\0'; + + if (strcmp(kbuf, "tap") == 0) + bypass_param = 1; + else if (strcmp(kbuf, "bypass") == 0) + bypass_param = 0; + else if (strcmp(kbuf, "disc") == 0) + bypass_param = 2; + + set_wd_exp_mode_fn(PDE_DATA(file_inode(file)), bypass_param); + + return count; + } + static int show_wd_exp_mode(struct seq_file *m, void *v) + { + bpctl_dev_t *dev = m->private; + int ret = get_wd_exp_mode_fn(dev); + if (ret == 1) + seq_printf(m, "tap\n"); + else if (ret == 0) + seq_printf(m, "bypass\n"); + else if (ret == 2) + seq_printf(m, "disc\n"); + else + seq_printf(m, "fail\n"); + return 0; + } + RW_FOPS(wd_exp_mode) + + static ssize_t wd_autoreset_write(struct file *file, const char __user *buffer, + size_t count, loff_t *pos) + { + int timeout; + int ret = kstrtoint_from_user(buffer, count, 10, &timeout); + if (ret) + return ret; + set_wd_autoreset_fn(PDE_DATA(file_inode(file)), timeout); + return count; + } + static int show_wd_autoreset(struct seq_file *m, void *v) + { + bpctl_dev_t *dev = m->private; + int ret = get_wd_autoreset_fn(dev); + if (ret >= 0) + seq_printf(m, "%d\n", ret); + else + seq_printf(m, "fail\n"); + return 0; + } + RW_FOPS(wd_autoreset) + + int bypass_proc_create_dev_sd(bpctl_dev_t *pbp_device_block) + { + struct bypass_pfs_sd *current_pfs = &(pbp_device_block->bypass_pfs_set); + static struct proc_dir_entry *procfs_dir = NULL; + int ret = 0; + + if (!pbp_device_block->ndev) + return -1; + sprintf(current_pfs->dir_name, "bypass_%s", + pbp_device_block->ndev->name); + + if (!bp_procfs_dir) + return -1; + + /* create device proc dir */ + procfs_dir = proc_mkdir(current_pfs->dir_name, bp_procfs_dir); + if (!procfs_dir) { + printk(KERN_DEBUG "Could not create procfs directory %s\n", + current_pfs->dir_name); + return -1; + } + current_pfs->bypass_entry = procfs_dir; + + #define ENTRY(x) ret |= procfs_add(#x, &x##_ops, pbp_device_block) + ENTRY(bypass_info); + if (pbp_device_block->bp_caps & SW_CTL_CAP) { + /* Create set param proc's */ + ENTRY(bypass_slave); + ENTRY(bypass_caps); + ENTRY(wd_set_caps); + ENTRY(bypass_wd); + ENTRY(wd_expire_time); + ENTRY(reset_bypass_wd); + ENTRY(std_nic); + if (pbp_device_block->bp_caps & BP_CAP) { + ENTRY(bypass); + ENTRY(dis_bypass); + ENTRY(bypass_pwup); + ENTRY(bypass_pwoff); + ENTRY(bypass_change); + } + if (pbp_device_block->bp_caps & TAP_CAP) { + ENTRY(tap); + ENTRY(dis_tap); + ENTRY(tap_pwup); + ENTRY(tap_change); + } + if (pbp_device_block->bp_caps & DISC_CAP) { + ENTRY(disc); + ENTRY(dis_disc); + ENTRY(disc_pwup); + ENTRY(disc_change); + } + + ENTRY(wd_exp_mode); + ENTRY(wd_autoreset); + ENTRY(tpl); + #ifdef PMC_FIX_FLAG + ENTRY(wait_at_pwup); + ENTRY(hw_reset); + #endif + } + #undef ENTRY + if (ret < 0) + printk(KERN_DEBUG "Create proc entry failed\n"); + + return ret; + } + + int bypass_proc_remove_dev_sd(bpctl_dev_t *pbp_device_block) + { + + struct bypass_pfs_sd *current_pfs = &pbp_device_block->bypass_pfs_set; + remove_proc_subtree(current_pfs->dir_name, bp_procfs_dir); + current_pfs->bypass_entry = NULL; + return 0; + } diff --cc drivers/staging/vt6655/device_main.c index be4f6c2ca3f,a89ab9bf38e..08b250f01da --- a/drivers/staging/vt6655/device_main.c +++ b/drivers/staging/vt6655/device_main.c @@@ -2723,61 -2933,39 +2724,39 @@@ static inline u32 ether_crc(int length //2008-8-4 by chester static int Config_FileGetParameter(unsigned char *string, - unsigned char *dest, unsigned char *source) + unsigned char *dest, unsigned char *source) { - unsigned char buf1[100]; - int source_len = strlen(source); + unsigned char buf1[100]; + int source_len = strlen(source); - memset(buf1,0,100); - strcat(buf1, string); - strcat(buf1, "="); - source+=strlen(buf1); + memset(buf1, 0, 100); + strcat(buf1, string); + strcat(buf1, "="); + source += strlen(buf1); - memcpy(dest,source,source_len-strlen(buf1)); - return true; + memcpy(dest, source, source_len - strlen(buf1)); + return true; } - int Config_FileOperation(PSDevice pDevice, bool fwrite, unsigned char *Parameter) { - unsigned char *config_path = CONFIG_PATH; - unsigned char *buffer = NULL; + int Config_FileOperation(PSDevice pDevice,bool fwrite,unsigned char *Parameter) + { + unsigned char *buffer = kmalloc(1024, GFP_KERNEL); unsigned char tmpbuffer[20]; - struct file *filp = NULL; - mm_segment_t old_fs = get_fs(); - //int oldfsuid=0,oldfsgid=0; - int result = 0; - - set_fs(KERNEL_DS); - - /* Can't do this anymore, so we rely on correct filesystem permissions: - //Make sure a caller can read or write power as root - oldfsuid=current->cred->fsuid; - oldfsgid=current->cred->fsgid; - current->cred->fsuid = 0; - current->cred->fsgid = 0; - */ - - //open file - filp = filp_open(config_path, O_RDWR, 0); - if (IS_ERR(filp)) { - printk("Config_FileOperation:open file fail?\n"); - result = -1; - goto error2; - } + struct file *file; + int result=0; - if (!(filp->f_op) || !(filp->f_op->read) || !(filp->f_op->write)) { - printk("file %s cann't readable or writable?\n", config_path); - result = -1; - goto error1; - } - - buffer = kmalloc(1024, GFP_KERNEL); - if (buffer == NULL) { + if (!buffer) { printk("allocate mem for file fail?\n"); - result = -1; - goto error1; + return -1; + } + file = filp_open(CONFIG_PATH, O_RDONLY, 0); + if (IS_ERR(file)) { + kfree(buffer); + printk("Config_FileOperation:open file fail?\n"); + return -1; } - if (filp->f_op->read(filp, buffer, 1024, &filp->f_pos) < 0) { + if (kernel_read(file, 0, buffer, 1024) < 0) { printk("read file error?\n"); result = -1; goto error1; diff --cc drivers/usb/gadget/goku_udc.c index 991aba390d9,57a547049df..480eeb7cfd9 --- a/drivers/usb/gadget/goku_udc.c +++ b/drivers/usb/gadget/goku_udc.c @@@ -1796,11 -1796,16 +1785,11 @@@ static int goku_probe(struct pci_dev *p #ifdef CONFIG_USB_GADGET_DEBUG_FILES - create_proc_read_entry(proc_node_name, 0, NULL, udc_proc_read, dev); + proc_create_data(proc_node_name, 0, NULL, &udc_proc_fops, dev); #endif - retval = device_register(&dev->gadget.dev); - if (retval) { - put_device(&dev->gadget.dev); - goto err; - } - dev->registered = 1; - retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget); + retval = usb_add_gadget_udc_release(&pdev->dev, &dev->gadget, + gadget_release); if (retval) goto err; diff --cc fs/Makefile index f0db9c941a5,b691a965dc1..4fe6df3ec28 --- a/fs/Makefile +++ b/fs/Makefile @@@ -7,10 -7,10 +7,10 @@@ obj-y := open.o read_write.o file_table.o super.o \ char_dev.o stat.o exec.o pipe.o namei.o fcntl.o \ - ioctl.o readdir.o select.o fifo.o dcache.o inode.o \ + ioctl.o readdir.o select.o dcache.o inode.o \ attr.o bad_inode.o file.o filesystems.o namespace.o \ seq_file.o xattr.o libfs.o fs-writeback.o \ - pnode.o drop_caches.o splice.o sync.o utimes.o \ + pnode.o splice.o sync.o utimes.o \ stack.o fs_struct.o statfs.o ifeq ($(CONFIG_BLOCK),y) diff --cc fs/compat.c index 5f83ffa4211,5058345dc27..d0560c93973 --- a/fs/compat.c +++ b/fs/compat.c @@@ -1068,190 -1069,26 +1068,6 @@@ asmlinkage long compat_sys_getdents64(u } #endif /* ! __ARCH_OMIT_COMPAT_SYS_GETDENTS64 */ - static ssize_t compat_do_readv_writev(int type, struct file *file, - const struct compat_iovec __user *uvector, - unsigned long nr_segs, loff_t *pos) - { - compat_ssize_t tot_len; - struct iovec iovstack[UIO_FASTIOV]; - struct iovec *iov = iovstack; - ssize_t ret; - io_fn_t fn; - iov_fn_t fnv; - - ret = -EINVAL; - if (!file->f_op) - goto out; - - ret = compat_rw_copy_check_uvector(type, uvector, nr_segs, - UIO_FASTIOV, iovstack, &iov); - if (ret <= 0) - goto out; - - tot_len = ret; - ret = rw_verify_area(type, file, pos, tot_len); - if (ret < 0) - goto out; - - fnv = NULL; - if (type == READ) { - fn = file->f_op->read; - fnv = file->f_op->aio_read; - } else { - fn = (io_fn_t)file->f_op->write; - fnv = file->f_op->aio_write; - } - - if (fnv) - ret = do_sync_readv_writev(file, iov, nr_segs, tot_len, - pos, fnv); - else - ret = do_loop_readv_writev(file, iov, nr_segs, pos, fn); - - out: - if (iov != iovstack) - kfree(iov); - if ((ret + (type == READ)) > 0) { - if (type == READ) - fsnotify_access(file); - else - fsnotify_modify(file); - } - return ret; - } - - static size_t compat_readv(struct file *file, - const struct compat_iovec __user *vec, - unsigned long vlen, loff_t *pos) - { - ssize_t ret = -EBADF; - - if (!(file->f_mode & FMODE_READ)) - goto out; - - ret = -EINVAL; - if (!file->f_op || (!file->f_op->aio_read && !file->f_op->read)) - goto out; - - ret = compat_do_readv_writev(READ, file, vec, vlen, pos); - - out: - if (ret > 0) - add_rchar(current, ret); - inc_syscr(current); - return ret; - } - - asmlinkage ssize_t - compat_sys_readv(unsigned long fd, const struct compat_iovec __user *vec, - unsigned long vlen) - { - struct fd f = fdget(fd); - ssize_t ret; - loff_t pos; - - if (!f.file) - return -EBADF; - pos = f.file->f_pos; - ret = compat_readv(f.file, vec, vlen, &pos); - f.file->f_pos = pos; - fdput(f); - return ret; - } - - asmlinkage ssize_t - compat_sys_preadv64(unsigned long fd, const struct compat_iovec __user *vec, - unsigned long vlen, loff_t pos) - { - struct fd f; - ssize_t ret; - - if (pos < 0) - return -EINVAL; - f = fdget(fd); - if (!f.file) - return -EBADF; - ret = -ESPIPE; - if (f.file->f_mode & FMODE_PREAD) - ret = compat_readv(f.file, vec, vlen, &pos); - fdput(f); - return ret; - } - - asmlinkage ssize_t - compat_sys_preadv(unsigned long fd, const struct compat_iovec __user *vec, - unsigned long vlen, u32 pos_low, u32 pos_high) - { - loff_t pos = ((loff_t)pos_high << 32) | pos_low; - return compat_sys_preadv64(fd, vec, vlen, pos); - } - - static size_t compat_writev(struct file *file, - const struct compat_iovec __user *vec, - unsigned long vlen, loff_t *pos) - { - ssize_t ret = -EBADF; - - if (!(file->f_mode & FMODE_WRITE)) - goto out; - - ret = -EINVAL; - if (!file->f_op || (!file->f_op->aio_write && !file->f_op->write)) - goto out; - - ret = compat_do_readv_writev(WRITE, file, vec, vlen, pos); - - out: - if (ret > 0) - add_wchar(current, ret); - inc_syscw(current); - return ret; - } - - asmlinkage ssize_t - compat_sys_writev(unsigned long fd, const struct compat_iovec __user *vec, - unsigned long vlen) - { - struct fd f = fdget(fd); - ssize_t ret; - loff_t pos; - - if (!f.file) - return -EBADF; - pos = f.file->f_pos; - ret = compat_writev(f.file, vec, vlen, &pos); - f.file->f_pos = pos; - fdput(f); - return ret; - } - - asmlinkage ssize_t - compat_sys_pwritev64(unsigned long fd, const struct compat_iovec __user *vec, - unsigned long vlen, loff_t pos) -asmlinkage long -compat_sys_vmsplice(int fd, const struct compat_iovec __user *iov32, - unsigned int nr_segs, unsigned int flags) --{ - struct fd f; - ssize_t ret; - - if (pos < 0) - unsigned i; - struct iovec __user *iov; - if (nr_segs > UIO_MAXIOV) -- return -EINVAL; - f = fdget(fd); - if (!f.file) - return -EBADF; - ret = -ESPIPE; - if (f.file->f_mode & FMODE_PWRITE) - ret = compat_writev(f.file, vec, vlen, &pos); - fdput(f); - return ret; - } - - asmlinkage ssize_t - compat_sys_pwritev(unsigned long fd, const struct compat_iovec __user *vec, - unsigned long vlen, u32 pos_low, u32 pos_high) - { - loff_t pos = ((loff_t)pos_high << 32) | pos_low; - return compat_sys_pwritev64(fd, vec, vlen, pos); - iov = compat_alloc_user_space(nr_segs * sizeof(struct iovec)); - for (i = 0; i < nr_segs; i++) { - struct compat_iovec v; - if (get_user(v.iov_base, &iov32[i].iov_base) || - get_user(v.iov_len, &iov32[i].iov_len) || - put_user(compat_ptr(v.iov_base), &iov[i].iov_base) || - put_user(v.iov_len, &iov[i].iov_len)) - return -EFAULT; - } - return sys_vmsplice(fd, iov, nr_segs, flags); --} -- /* * Exactly like fs/open.c:sys_open(), except that it doesn't set the * O_LARGEFILE flag. diff --cc fs/coredump.c index ec306cc9a28,a987f3d39d9..a9abe313e8d --- a/fs/coredump.c +++ b/fs/coredump.c @@@ -419,22 -407,9 +419,20 @@@ static void coredump_finish(struct mm_s mm->core_state = NULL; } +static bool dump_interrupted(void) +{ + /* + * SIGKILL or freezing() interrupt the coredumping. Perhaps we + * can do try_to_freeze() and check __fatal_signal_pending(), + * but then we need to teach dump_write() to restart and clear + * TIF_SIGPENDING. + */ + return signal_pending(current); +} + static void wait_for_dump_helpers(struct file *file) { - struct pipe_inode_info *pipe; - - pipe = file_inode(file)->i_pipe; + struct pipe_inode_info *pipe = file->private_data; pipe_lock(pipe); pipe->readers++; @@@ -656,7 -627,11 +654,9 @@@ void do_coredump(siginfo_t *siginfo goto close_fail; if (displaced) put_files_struct(displaced); + file_start_write(cprm.file); - retval = binfmt->core_dump(&cprm); - if (retval) - current->signal->group_exit_code |= 0x80; + core_dumped = !dump_interrupted() && binfmt->core_dump(&cprm); + file_end_write(cprm.file); if (ispipe && core_pipe_limit) wait_for_dump_helpers(cprm.file); diff --cc fs/efivarfs/file.c index ede07fc7309,00000000000..bfb53156431 mode 100644,000000..100644 --- a/fs/efivarfs/file.c +++ b/fs/efivarfs/file.c @@@ -1,105 -1,0 +1,106 @@@ +/* + * Copyright (C) 2012 Red Hat, Inc. + * Copyright (C) 2012 Jeremy Kerr + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include ++#include + +#include "internal.h" + +static ssize_t efivarfs_file_write(struct file *file, + const char __user *userbuf, size_t count, loff_t *ppos) +{ + struct efivar_entry *var = file->private_data; + void *data; + u32 attributes; + struct inode *inode = file->f_mapping->host; + unsigned long datasize = count - sizeof(attributes); + ssize_t bytes = 0; + bool set = false; + + if (count < sizeof(attributes)) + return -EINVAL; + + if (copy_from_user(&attributes, userbuf, sizeof(attributes))) + return -EFAULT; + + if (attributes & ~(EFI_VARIABLE_MASK)) + return -EINVAL; + + data = kmalloc(datasize, GFP_KERNEL); + if (!data) + return -ENOMEM; + + if (copy_from_user(data, userbuf + sizeof(attributes), datasize)) { + bytes = -EFAULT; + goto out; + } + + bytes = efivar_entry_set_get_size(var, attributes, &datasize, + data, &set); + if (!set && bytes) + goto out; + + if (bytes == -ENOENT) { + drop_nlink(inode); + d_delete(file->f_dentry); + dput(file->f_dentry); + } else { + mutex_lock(&inode->i_mutex); + i_size_write(inode, datasize + sizeof(attributes)); + mutex_unlock(&inode->i_mutex); + } + + bytes = count; + +out: + kfree(data); + + return bytes; +} + +static ssize_t efivarfs_file_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct efivar_entry *var = file->private_data; + unsigned long datasize = 0; + u32 attributes; + void *data; + ssize_t size = 0; + int err; + + err = efivar_entry_size(var, &datasize); + if (err) + return err; + + data = kmalloc(datasize + sizeof(attributes), GFP_KERNEL); + + if (!data) + return -ENOMEM; + + size = efivar_entry_get(var, &attributes, &datasize, + data + sizeof(attributes)); + if (size) + goto out_free; + + memcpy(data, &attributes, sizeof(attributes)); + size = simple_read_from_buffer(userbuf, count, ppos, + data, datasize + sizeof(attributes)); +out_free: + kfree(data); + + return size; +} + +const struct file_operations efivarfs_file_operations = { + .open = simple_open, + .read = efivarfs_file_read, + .write = efivarfs_file_write, + .llseek = no_llseek, +}; diff --cc fs/efivarfs/inode.c index 640e289d522,00000000000..7e787fb9029 mode 100644,000000..100644 --- a/fs/efivarfs/inode.c +++ b/fs/efivarfs/inode.c @@@ -1,173 -1,0 +1,174 @@@ +/* + * Copyright (C) 2012 Red Hat, Inc. + * Copyright (C) 2012 Jeremy Kerr + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include ++#include + +#include "internal.h" + +struct inode *efivarfs_get_inode(struct super_block *sb, + const struct inode *dir, int mode, dev_t dev) +{ + struct inode *inode = new_inode(sb); + + if (inode) { + inode->i_ino = get_next_ino(); + inode->i_mode = mode; + inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; + switch (mode & S_IFMT) { + case S_IFREG: + inode->i_fop = &efivarfs_file_operations; + break; + case S_IFDIR: + inode->i_op = &efivarfs_dir_inode_operations; + inode->i_fop = &simple_dir_operations; + inc_nlink(inode); + break; + } + } + return inode; +} + +/* + * Return true if 'str' is a valid efivarfs filename of the form, + * + * VariableName-12345678-1234-1234-1234-1234567891bc + */ +bool efivarfs_valid_name(const char *str, int len) +{ + static const char dashes[EFI_VARIABLE_GUID_LEN] = { + [8] = 1, [13] = 1, [18] = 1, [23] = 1 + }; + const char *s = str + len - EFI_VARIABLE_GUID_LEN; + int i; + + /* + * We need a GUID, plus at least one letter for the variable name, + * plus the '-' separator + */ + if (len < EFI_VARIABLE_GUID_LEN + 2) + return false; + + /* GUID must be preceded by a '-' */ + if (*(s - 1) != '-') + return false; + + /* + * Validate that 's' is of the correct format, e.g. + * + * 12345678-1234-1234-1234-123456789abc + */ + for (i = 0; i < EFI_VARIABLE_GUID_LEN; i++) { + if (dashes[i]) { + if (*s++ != '-') + return false; + } else { + if (!isxdigit(*s++)) + return false; + } + } + + return true; +} + +static void efivarfs_hex_to_guid(const char *str, efi_guid_t *guid) +{ + guid->b[0] = hex_to_bin(str[6]) << 4 | hex_to_bin(str[7]); + guid->b[1] = hex_to_bin(str[4]) << 4 | hex_to_bin(str[5]); + guid->b[2] = hex_to_bin(str[2]) << 4 | hex_to_bin(str[3]); + guid->b[3] = hex_to_bin(str[0]) << 4 | hex_to_bin(str[1]); + guid->b[4] = hex_to_bin(str[11]) << 4 | hex_to_bin(str[12]); + guid->b[5] = hex_to_bin(str[9]) << 4 | hex_to_bin(str[10]); + guid->b[6] = hex_to_bin(str[16]) << 4 | hex_to_bin(str[17]); + guid->b[7] = hex_to_bin(str[14]) << 4 | hex_to_bin(str[15]); + guid->b[8] = hex_to_bin(str[19]) << 4 | hex_to_bin(str[20]); + guid->b[9] = hex_to_bin(str[21]) << 4 | hex_to_bin(str[22]); + guid->b[10] = hex_to_bin(str[24]) << 4 | hex_to_bin(str[25]); + guid->b[11] = hex_to_bin(str[26]) << 4 | hex_to_bin(str[27]); + guid->b[12] = hex_to_bin(str[28]) << 4 | hex_to_bin(str[29]); + guid->b[13] = hex_to_bin(str[30]) << 4 | hex_to_bin(str[31]); + guid->b[14] = hex_to_bin(str[32]) << 4 | hex_to_bin(str[33]); + guid->b[15] = hex_to_bin(str[34]) << 4 | hex_to_bin(str[35]); +} + +static int efivarfs_create(struct inode *dir, struct dentry *dentry, + umode_t mode, bool excl) +{ + struct inode *inode; + struct efivar_entry *var; + int namelen, i = 0, err = 0; + + if (!efivarfs_valid_name(dentry->d_name.name, dentry->d_name.len)) + return -EINVAL; + + inode = efivarfs_get_inode(dir->i_sb, dir, mode, 0); + if (!inode) + return -ENOMEM; + + var = kzalloc(sizeof(struct efivar_entry), GFP_KERNEL); + if (!var) { + err = -ENOMEM; + goto out; + } + + /* length of the variable name itself: remove GUID and separator */ + namelen = dentry->d_name.len - EFI_VARIABLE_GUID_LEN - 1; + + efivarfs_hex_to_guid(dentry->d_name.name + namelen + 1, + &var->var.VendorGuid); + + for (i = 0; i < namelen; i++) + var->var.VariableName[i] = dentry->d_name.name[i]; + + var->var.VariableName[i] = '\0'; + + inode->i_private = var; + + efivar_entry_add(var, &efivarfs_list); + d_instantiate(dentry, inode); + dget(dentry); +out: + if (err) { + kfree(var); + iput(inode); + } + return err; +} + +static int efivarfs_unlink(struct inode *dir, struct dentry *dentry) +{ + struct efivar_entry *var = dentry->d_inode->i_private; + + if (efivar_entry_delete(var)) + return -EINVAL; + + drop_nlink(dentry->d_inode); + dput(dentry); + return 0; +}; + +/* + * Handle negative dentry. + */ +static struct dentry *efivarfs_lookup(struct inode *dir, struct dentry *dentry, + unsigned int flags) +{ + if (dentry->d_name.len > NAME_MAX) + return ERR_PTR(-ENAMETOOLONG); + d_add(dentry, NULL); + return NULL; +} + +const struct inode_operations efivarfs_dir_inode_operations = { + .lookup = efivarfs_lookup, + .unlink = efivarfs_unlink, + .create = efivarfs_create, +}; diff --cc fs/efivarfs/super.c index 525a2a1ac16,00000000000..141aee31884 mode 100644,000000..100644 --- a/fs/efivarfs/super.c +++ b/fs/efivarfs/super.c @@@ -1,268 -1,0 +1,270 @@@ +/* + * Copyright (C) 2012 Red Hat, Inc. + * Copyright (C) 2012 Jeremy Kerr + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include ++#include ++#include + +#include "internal.h" + +LIST_HEAD(efivarfs_list); + +static void efivarfs_evict_inode(struct inode *inode) +{ + clear_inode(inode); +} + +static const struct super_operations efivarfs_ops = { + .statfs = simple_statfs, + .drop_inode = generic_delete_inode, + .evict_inode = efivarfs_evict_inode, + .show_options = generic_show_options, +}; + +static struct super_block *efivarfs_sb; + +/* + * Compare two efivarfs file names. + * + * An efivarfs filename is composed of two parts, + * + * 1. A case-sensitive variable name + * 2. A case-insensitive GUID + * + * So we need to perform a case-sensitive match on part 1 and a + * case-insensitive match on part 2. + */ +static int efivarfs_d_compare(const struct dentry *parent, const struct inode *pinode, + const struct dentry *dentry, const struct inode *inode, + unsigned int len, const char *str, + const struct qstr *name) +{ + int guid = len - EFI_VARIABLE_GUID_LEN; + + if (name->len != len) + return 1; + + /* Case-sensitive compare for the variable name */ + if (memcmp(str, name->name, guid)) + return 1; + + /* Case-insensitive compare for the GUID */ + return strncasecmp(name->name + guid, str + guid, EFI_VARIABLE_GUID_LEN); +} + +static int efivarfs_d_hash(const struct dentry *dentry, + const struct inode *inode, struct qstr *qstr) +{ + unsigned long hash = init_name_hash(); + const unsigned char *s = qstr->name; + unsigned int len = qstr->len; + + if (!efivarfs_valid_name(s, len)) + return -EINVAL; + + while (len-- > EFI_VARIABLE_GUID_LEN) + hash = partial_name_hash(*s++, hash); + + /* GUID is case-insensitive. */ + while (len--) + hash = partial_name_hash(tolower(*s++), hash); + + qstr->hash = end_name_hash(hash); + return 0; +} + +/* + * Retaining negative dentries for an in-memory filesystem just wastes + * memory and lookup time: arrange for them to be deleted immediately. + */ +static int efivarfs_delete_dentry(const struct dentry *dentry) +{ + return 1; +} + +static struct dentry_operations efivarfs_d_ops = { + .d_compare = efivarfs_d_compare, + .d_hash = efivarfs_d_hash, + .d_delete = efivarfs_delete_dentry, +}; + +static struct dentry *efivarfs_alloc_dentry(struct dentry *parent, char *name) +{ + struct dentry *d; + struct qstr q; + int err; + + q.name = name; + q.len = strlen(name); + + err = efivarfs_d_hash(NULL, NULL, &q); + if (err) + return ERR_PTR(err); + + d = d_alloc(parent, &q); + if (d) + return d; + + return ERR_PTR(-ENOMEM); +} + +static int efivarfs_callback(efi_char16_t *name16, efi_guid_t vendor, + unsigned long name_size, void *data) +{ + struct super_block *sb = (struct super_block *)data; + struct efivar_entry *entry; + struct inode *inode = NULL; + struct dentry *dentry, *root = sb->s_root; + unsigned long size = 0; + char *name; + int len, i; + int err = -ENOMEM; + + entry = kmalloc(sizeof(*entry), GFP_KERNEL); + if (!entry) + return err; + + memcpy(entry->var.VariableName, name16, name_size); + memcpy(&(entry->var.VendorGuid), &vendor, sizeof(efi_guid_t)); + + len = ucs2_strlen(entry->var.VariableName); + + /* name, plus '-', plus GUID, plus NUL*/ + name = kmalloc(len + 1 + EFI_VARIABLE_GUID_LEN + 1, GFP_KERNEL); + if (!name) + goto fail; + + for (i = 0; i < len; i++) + name[i] = entry->var.VariableName[i] & 0xFF; + + name[len] = '-'; + + efi_guid_unparse(&entry->var.VendorGuid, name + len + 1); + + name[len + EFI_VARIABLE_GUID_LEN+1] = '\0'; + + inode = efivarfs_get_inode(sb, root->d_inode, S_IFREG | 0644, 0); + if (!inode) + goto fail_name; + + dentry = efivarfs_alloc_dentry(root, name); + if (IS_ERR(dentry)) { + err = PTR_ERR(dentry); + goto fail_inode; + } + + /* copied by the above to local storage in the dentry. */ + kfree(name); + + efivar_entry_size(entry, &size); + efivar_entry_add(entry, &efivarfs_list); + + mutex_lock(&inode->i_mutex); + inode->i_private = entry; + i_size_write(inode, size + sizeof(entry->var.Attributes)); + mutex_unlock(&inode->i_mutex); + d_add(dentry, inode); + + return 0; + +fail_inode: + iput(inode); +fail_name: + kfree(name); +fail: + kfree(entry); + return err; +} + +static int efivarfs_destroy(struct efivar_entry *entry, void *data) +{ + efivar_entry_remove(entry); + kfree(entry); + return 0; +} + +static int efivarfs_fill_super(struct super_block *sb, void *data, int silent) +{ + struct inode *inode = NULL; + struct dentry *root; + int err; + + efivarfs_sb = sb; + + sb->s_maxbytes = MAX_LFS_FILESIZE; + sb->s_blocksize = PAGE_CACHE_SIZE; + sb->s_blocksize_bits = PAGE_CACHE_SHIFT; + sb->s_magic = EFIVARFS_MAGIC; + sb->s_op = &efivarfs_ops; + sb->s_d_op = &efivarfs_d_ops; + sb->s_time_gran = 1; + + inode = efivarfs_get_inode(sb, NULL, S_IFDIR | 0755, 0); + if (!inode) + return -ENOMEM; + inode->i_op = &efivarfs_dir_inode_operations; + + root = d_make_root(inode); + sb->s_root = root; + if (!root) + return -ENOMEM; + + INIT_LIST_HEAD(&efivarfs_list); + + err = efivar_init(efivarfs_callback, (void *)sb, false, + true, &efivarfs_list); + if (err) + __efivar_entry_iter(efivarfs_destroy, &efivarfs_list, NULL, NULL); + + return err; +} + +static struct dentry *efivarfs_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) +{ + return mount_single(fs_type, flags, data, efivarfs_fill_super); +} + +static void efivarfs_kill_sb(struct super_block *sb) +{ + kill_litter_super(sb); + efivarfs_sb = NULL; + + /* Remove all entries and destroy */ + __efivar_entry_iter(efivarfs_destroy, &efivarfs_list, NULL, NULL); +} + +static struct file_system_type efivarfs_type = { + .name = "efivarfs", + .mount = efivarfs_mount, + .kill_sb = efivarfs_kill_sb, +}; + +static __init int efivarfs_init(void) +{ + if (!efi_enabled(EFI_RUNTIME_SERVICES)) + return 0; + + if (!efivars_kobject()) + return 0; + + return register_filesystem(&efivarfs_type); +} + +MODULE_AUTHOR("Matthew Garrett, Jeremy Kerr"); +MODULE_DESCRIPTION("EFI Variable Filesystem"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_FS("efivarfs"); + +module_init(efivarfs_init); diff --cc fs/namespace.c index 341d3f56408,0f0cf9379c9..b4f96a5230a --- a/fs/namespace.c +++ b/fs/namespace.c @@@ -21,7 -21,7 +21,8 @@@ #include /* get_fs_root et.al. */ #include /* fsnotify_vfsmount_delete */ #include - #include + #include ++#include #include "pnode.h" #include "internal.h" @@@ -2346,10 -2384,10 +2392,10 @@@ static struct mnt_namespace *dup_mnt_ns /* First pass: copy the tree topology */ copy_flags = CL_COPY_ALL | CL_EXPIRE; if (user_ns != mnt_ns->user_ns) - copy_flags |= CL_SHARED_TO_SLAVE; + copy_flags |= CL_SHARED_TO_SLAVE | CL_UNPRIVILEGED; new = copy_tree(old, old->mnt.mnt_root, copy_flags); if (IS_ERR(new)) { - up_write(&namespace_sem); + namespace_unlock(); free_mnt_ns(new_ns); return ERR_CAST(new); } diff --cc fs/pnode.c index 8b29d2164da,43617258fa6..3d2a7141b87 --- a/fs/pnode.c +++ b/fs/pnode.c @@@ -218,10 -217,9 +218,10 @@@ static struct mount *get_source(struct * @source_mnt: source mount. * @tree_list : list of heads of trees to be attached. */ - int propagate_mnt(struct mount *dest_mnt, struct dentry *dest_dentry, + int propagate_mnt(struct mount *dest_mnt, struct mountpoint *dest_mp, struct mount *source_mnt, struct list_head *tree_list) { + struct user_namespace *user_ns = current->nsproxy->mnt_ns->user_ns; struct mount *m, *child; int ret = 0; struct mount *prev_dest_mnt = dest_mnt; diff --cc fs/proc/internal.h index 75710357a51,04255b6e96b..d600fb098b6 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h @@@ -154,36 -191,56 +191,35 @@@ static inline struct proc_dir_entry *pd atomic_inc(&pde->count); return pde; } - void pde_put(struct proc_dir_entry *pde); - - int proc_fill_super(struct super_block *); - struct inode *proc_get_inode(struct super_block *, struct proc_dir_entry *); - int proc_remount(struct super_block *sb, int *flags, char *data); + extern void pde_put(struct proc_dir_entry *); /* - * These are generic /proc routines that use the internal - * "struct proc_dir_entry" tree to traverse the filesystem. - * - * The /proc root directory has extended versions to take care - * of the /proc/ subdirectories. + * inode.c */ - int proc_readdir(struct file *, void *, filldir_t); - struct dentry *proc_lookup(struct inode *, struct dentry *, unsigned int); + struct pde_opener { + struct file *file; + struct list_head lh; + int closing; + struct completion *c; + }; + extern const struct inode_operations proc_pid_link_inode_operations; + extern void proc_init_inodecache(void); + extern struct inode *proc_get_inode(struct super_block *, struct proc_dir_entry *); + extern int proc_fill_super(struct super_block *); + extern void proc_entry_rundown(struct proc_dir_entry *); - /* Lookups */ - typedef struct dentry *instantiate_t(struct inode *, struct dentry *, - struct task_struct *, const void *); - int proc_fill_cache(struct file *filp, void *dirent, filldir_t filldir, - const char *name, int len, - instantiate_t instantiate, struct task_struct *task, const void *ptr); - int pid_revalidate(struct dentry *dentry, unsigned int flags); - struct inode *proc_pid_make_inode(struct super_block * sb, struct task_struct *task); - extern const struct dentry_operations pid_dentry_operations; - int pid_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat); - int proc_setattr(struct dentry *dentry, struct iattr *attr); -/* - * mmu.c - */ -struct vmalloc_info { - unsigned long used; - unsigned long largest_chunk; -}; - -#ifdef CONFIG_MMU -#define VMALLOC_TOTAL (VMALLOC_END - VMALLOC_START) -extern void get_vmalloc_info(struct vmalloc_info *); - -#else -#define VMALLOC_TOTAL 0UL -static inline void get_vmalloc_info(struct vmalloc_info *vmi) -{ - vmi->used = 0; - vmi->largest_chunk = 0; -} -#endif - + /* + * proc_devtree.c + */ + #ifdef CONFIG_PROC_DEVICETREE + extern void proc_device_tree_init(void); + #endif + /* + * proc_namespaces.c + */ extern const struct inode_operations proc_ns_dir_inode_operations; extern const struct file_operations proc_ns_dir_operations; diff --cc fs/read_write.c index 8274a794253,a1f4d44cbc0..605dbbcb197 --- a/fs/read_write.c +++ b/fs/read_write.c @@@ -881,8 -900,203 +887,203 @@@ SYSCALL_DEFINE5(pwritev, unsigned long return ret; } + #ifdef CONFIG_COMPAT + + static ssize_t compat_do_readv_writev(int type, struct file *file, + const struct compat_iovec __user *uvector, + unsigned long nr_segs, loff_t *pos) + { + compat_ssize_t tot_len; + struct iovec iovstack[UIO_FASTIOV]; + struct iovec *iov = iovstack; + ssize_t ret; + io_fn_t fn; + iov_fn_t fnv; + + ret = -EINVAL; + if (!file->f_op) + goto out; + + ret = -EFAULT; + if (!access_ok(VERIFY_READ, uvector, nr_segs*sizeof(*uvector))) + goto out; + + ret = compat_rw_copy_check_uvector(type, uvector, nr_segs, + UIO_FASTIOV, iovstack, &iov); + if (ret <= 0) + goto out; + + tot_len = ret; + ret = rw_verify_area(type, file, pos, tot_len); + if (ret < 0) + goto out; + + fnv = NULL; + if (type == READ) { + fn = file->f_op->read; + fnv = file->f_op->aio_read; + } else { + fn = (io_fn_t)file->f_op->write; + fnv = file->f_op->aio_write; + file_start_write(file); + } + + if (fnv) + ret = do_sync_readv_writev(file, iov, nr_segs, tot_len, + pos, fnv); + else + ret = do_loop_readv_writev(file, iov, nr_segs, pos, fn); + + if (type != READ) + file_end_write(file); + + out: + if (iov != iovstack) + kfree(iov); + if ((ret + (type == READ)) > 0) { + if (type == READ) + fsnotify_access(file); + else + fsnotify_modify(file); + } + return ret; + } + + static size_t compat_readv(struct file *file, + const struct compat_iovec __user *vec, + unsigned long vlen, loff_t *pos) + { + ssize_t ret = -EBADF; + + if (!(file->f_mode & FMODE_READ)) + goto out; + + ret = -EINVAL; + if (!file->f_op || (!file->f_op->aio_read && !file->f_op->read)) + goto out; + + ret = compat_do_readv_writev(READ, file, vec, vlen, pos); + + out: + if (ret > 0) + add_rchar(current, ret); + inc_syscr(current); + return ret; + } + + COMPAT_SYSCALL_DEFINE3(readv, unsigned long, fd, + const struct compat_iovec __user *,vec, + unsigned long, vlen) + { + struct fd f = fdget(fd); + ssize_t ret; + loff_t pos; + + if (!f.file) + return -EBADF; + pos = f.file->f_pos; + ret = compat_readv(f.file, vec, vlen, &pos); + f.file->f_pos = pos; + fdput(f); + return ret; + } + + COMPAT_SYSCALL_DEFINE4(preadv64, unsigned long, fd, + const struct compat_iovec __user *,vec, + unsigned long, vlen, loff_t, pos) + { + struct fd f; + ssize_t ret; + + if (pos < 0) + return -EINVAL; + f = fdget(fd); + if (!f.file) + return -EBADF; + ret = -ESPIPE; + if (f.file->f_mode & FMODE_PREAD) + ret = compat_readv(f.file, vec, vlen, &pos); + fdput(f); + return ret; + } + + COMPAT_SYSCALL_DEFINE5(preadv, unsigned long, fd, + const struct compat_iovec __user *,vec, + unsigned long, vlen, u32, pos_low, u32, pos_high) + { + loff_t pos = ((loff_t)pos_high << 32) | pos_low; + return compat_sys_preadv64(fd, vec, vlen, pos); + } + + static size_t compat_writev(struct file *file, + const struct compat_iovec __user *vec, + unsigned long vlen, loff_t *pos) + { + ssize_t ret = -EBADF; + + if (!(file->f_mode & FMODE_WRITE)) + goto out; + + ret = -EINVAL; + if (!file->f_op || (!file->f_op->aio_write && !file->f_op->write)) + goto out; + + ret = compat_do_readv_writev(WRITE, file, vec, vlen, pos); + + out: + if (ret > 0) + add_wchar(current, ret); + inc_syscw(current); + return ret; + } + + COMPAT_SYSCALL_DEFINE3(writev, unsigned long, fd, + const struct compat_iovec __user *, vec, + unsigned long, vlen) + { + struct fd f = fdget(fd); + ssize_t ret; + loff_t pos; + + if (!f.file) + return -EBADF; + pos = f.file->f_pos; + ret = compat_writev(f.file, vec, vlen, &pos); + f.file->f_pos = pos; + fdput(f); + return ret; + } + + COMPAT_SYSCALL_DEFINE4(pwritev64, unsigned long, fd, + const struct compat_iovec __user *,vec, + unsigned long, vlen, loff_t, pos) + { + struct fd f; + ssize_t ret; + + if (pos < 0) + return -EINVAL; + f = fdget(fd); + if (!f.file) + return -EBADF; + ret = -ESPIPE; + if (f.file->f_mode & FMODE_PWRITE) + ret = compat_writev(f.file, vec, vlen, &pos); + fdput(f); + return ret; + } + + COMPAT_SYSCALL_DEFINE5(pwritev, unsigned long, fd, + const struct compat_iovec __user *,vec, + unsigned long, vlen, u32, pos_low, u32, pos_high) + { + loff_t pos = ((loff_t)pos_high << 32) | pos_low; + return compat_sys_pwritev64(fd, vec, vlen, pos); + } + #endif + -ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos, size_t count, - loff_t max) +static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos, + size_t count, loff_t max) { struct fd in, out; struct inode *in_inode, *out_inode; diff --cc fs/read_write.h index d07b954c6e0,b98780664ff..0ec530d9305 --- a/fs/read_write.h +++ b/fs/read_write.h @@@ -7,8 -7,6 +7,3 @@@ typedef ssize_t (*io_fn_t)(struct file *, char __user *, size_t, loff_t *); typedef ssize_t (*iov_fn_t)(struct kiocb *, const struct iovec *, unsigned long, loff_t); -- - ssize_t do_sync_readv_writev(struct file *filp, const struct iovec *iov, - unsigned long nr_segs, size_t len, loff_t *ppos, iov_fn_t fn); - ssize_t do_loop_readv_writev(struct file *filp, struct iovec *iov, - unsigned long nr_segs, loff_t *ppos, io_fn_t fn); -ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos, size_t count, - loff_t max); diff --cc include/linux/cgroup.h index 646ab9d15e4,68f2157b71d..3bff9ce09cf --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h @@@ -39,27 -42,16 +39,27 @@@ extern int cgroupstats_build(struct cgr extern int cgroup_load_subsys(struct cgroup_subsys *ss); extern void cgroup_unload_subsys(struct cgroup_subsys *ss); - extern const struct file_operations proc_cgroup_operations; + extern int proc_cgroup_show(struct seq_file *, void *); -/* Define the enumeration of all builtin cgroup subsystems */ +/* + * Define the enumeration of all cgroup subsystems. + * + * We define ids for builtin subsystems and then modular ones. + */ #define SUBSYS(_x) _x ## _subsys_id, -#define IS_SUBSYS_ENABLED(option) IS_ENABLED(option) enum cgroup_subsys_id { +#define IS_SUBSYS_ENABLED(option) IS_BUILTIN(option) #include +#undef IS_SUBSYS_ENABLED + CGROUP_BUILTIN_SUBSYS_COUNT, + + __CGROUP_SUBSYS_TEMP_PLACEHOLDER = CGROUP_BUILTIN_SUBSYS_COUNT - 1, + +#define IS_SUBSYS_ENABLED(option) IS_MODULE(option) +#include +#undef IS_SUBSYS_ENABLED CGROUP_SUBSYS_COUNT, }; -#undef IS_SUBSYS_ENABLED #undef SUBSYS /* Per-subsystem/per-cgroup state maintained by the system. */ diff --cc ipc/msgutil.c index d43439e6eb4,8f0201735f1..491e71f2a1b --- a/ipc/msgutil.c +++ b/ipc/msgutil.c @@@ -16,8 -16,8 +16,8 @@@ #include #include #include - #include + #include -#include +#include #include "util.h"