diff options
author | Paul Mackerras <paulus@samba.org> | 2005-10-31 13:37:12 +1100 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2005-10-31 13:37:12 +1100 |
commit | 23fd07750a789a66fe88cf173d52a18f1a387da4 (patch) | |
tree | 06fdd6df35fdb835abdaa9b754d62f6b84b97250 /drivers | |
parent | bd787d438a59266af3c9f6351644c85ef1dd21fe (diff) | |
parent | ed28f96ac1960f30f818374d65be71d2fdf811b0 (diff) | |
download | lwn-23fd07750a789a66fe88cf173d52a18f1a387da4.tar.gz lwn-23fd07750a789a66fe88cf173d52a18f1a387da4.zip |
Merge ../linux-2.6 by hand
Diffstat (limited to 'drivers')
951 files changed, 42625 insertions, 29865 deletions
diff --git a/drivers/Makefile b/drivers/Makefile index 1a109a6dd953..65670be6ff1a 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -5,7 +5,7 @@ # Rewritten to use lists instead of if-statements. # -obj-$(CONFIG_PCI) += pci/ +obj-$(CONFIG_PCI) += pci/ usb/ obj-$(CONFIG_PARISC) += parisc/ obj-y += video/ obj-$(CONFIG_ACPI) += acpi/ diff --git a/drivers/acorn/char/pcf8583.c b/drivers/acorn/char/pcf8583.c index 2b850e5860a0..e26f007a1417 100644 --- a/drivers/acorn/char/pcf8583.c +++ b/drivers/acorn/char/pcf8583.c @@ -9,6 +9,7 @@ * * Driver for PCF8583 RTC & RAM chip */ +#include <linux/module.h> #include <linux/i2c.h> #include <linux/slab.h> #include <linux/string.h> @@ -32,7 +33,8 @@ static struct i2c_client_address_data addr_data = { .forces = forces, }; -#define DAT(x) ((unsigned int)(x->dev.driver_data)) +#define set_ctrl(x, v) i2c_set_clientdata(x, (void *)(unsigned int)(v)) +#define get_ctrl(x) ((unsigned int)i2c_get_clientdata(x)) static int pcf8583_attach(struct i2c_adapter *adap, int addr, int kind) @@ -40,8 +42,17 @@ pcf8583_attach(struct i2c_adapter *adap, int addr, int kind) struct i2c_client *c; unsigned char buf[1], ad[1] = { 0 }; struct i2c_msg msgs[2] = { - { addr, 0, 1, ad }, - { addr, I2C_M_RD, 1, buf } + { + .addr = addr, + .flags = 0, + .len = 1, + .buf = ad, + }, { + .addr = addr, + .flags = I2C_M_RD, + .len = 1, + .buf = buf, + } }; c = kmalloc(sizeof(*c), GFP_KERNEL); @@ -54,7 +65,7 @@ pcf8583_attach(struct i2c_adapter *adap, int addr, int kind) c->driver = &pcf8583_driver; if (i2c_transfer(c->adapter, msgs, 2) == 2) - DAT(c) = buf[0]; + set_ctrl(c, buf[0]); return i2c_attach_client(c); } @@ -78,8 +89,17 @@ pcf8583_get_datetime(struct i2c_client *client, struct rtc_tm *dt) { unsigned char buf[8], addr[1] = { 1 }; struct i2c_msg msgs[2] = { - { client->addr, 0, 1, addr }, - { client->addr, I2C_M_RD, 6, buf } + { + .addr = client->addr, + .flags = 0, + .len = 1, + .buf = addr, + }, { + .addr = client->addr, + .flags = I2C_M_RD, + .len = 6, + .buf = buf, + } }; int ret = -EIO; @@ -113,7 +133,7 @@ pcf8583_set_datetime(struct i2c_client *client, struct rtc_tm *dt, int datetoo) int ret, len = 6; buf[0] = 0; - buf[1] = DAT(client) | 0x80; + buf[1] = get_ctrl(client) | 0x80; buf[2] = BIN_TO_BCD(dt->cs); buf[3] = BIN_TO_BCD(dt->secs); buf[4] = BIN_TO_BCD(dt->mins); @@ -129,7 +149,7 @@ pcf8583_set_datetime(struct i2c_client *client, struct rtc_tm *dt, int datetoo) if (ret == len) ret = 0; - buf[1] = DAT(client); + buf[1] = get_ctrl(client); i2c_master_send(client, (char *)buf, 2); return ret; @@ -138,7 +158,7 @@ pcf8583_set_datetime(struct i2c_client *client, struct rtc_tm *dt, int datetoo) static int pcf8583_get_ctrl(struct i2c_client *client, unsigned char *ctrl) { - *ctrl = DAT(client); + *ctrl = get_ctrl(client); return 0; } @@ -149,7 +169,7 @@ pcf8583_set_ctrl(struct i2c_client *client, unsigned char *ctrl) buf[0] = 0; buf[1] = *ctrl; - DAT(client) = *ctrl; + set_ctrl(client, *ctrl); return i2c_master_send(client, (char *)buf, 2); } @@ -159,15 +179,23 @@ pcf8583_read_mem(struct i2c_client *client, struct mem *mem) { unsigned char addr[1]; struct i2c_msg msgs[2] = { - { client->addr, 0, 1, addr }, - { client->addr, I2C_M_RD, 0, mem->data } + { + .addr = client->addr, + .flags = 0, + .len = 1, + .buf = addr, + }, { + .addr = client->addr, + .flags = I2C_M_RD, + .len = mem->nr, + .buf = mem->data, + } }; if (mem->loc < 8) return -EINVAL; addr[0] = mem->loc; - msgs[1].len = mem->nr; return i2c_transfer(client->adapter, msgs, 2) == 2 ? 0 : -EIO; } @@ -177,15 +205,23 @@ pcf8583_write_mem(struct i2c_client *client, struct mem *mem) { unsigned char addr[1]; struct i2c_msg msgs[2] = { - { client->addr, 0, 1, addr }, - { client->addr, 0, 0, mem->data } + { + .addr = client->addr, + .flags = 0, + .len = 1, + .buf = addr, + }, { + .addr = client->addr, + .flags = I2C_M_NOSTART, + .len = mem->nr, + .buf = mem->data, + } }; if (mem->loc < 8) return -EINVAL; addr[0] = mem->loc; - msgs[1].len = mem->nr; return i2c_transfer(client->adapter, msgs, 2) == 2 ? 0 : -EIO; } @@ -234,4 +270,14 @@ static __init int pcf8583_init(void) return i2c_add_driver(&pcf8583_driver); } -__initcall(pcf8583_init); +static __exit void pcf8583_exit(void) +{ + i2c_del_driver(&pcf8583_driver); +} + +module_init(pcf8583_init); +module_exit(pcf8583_exit); + +MODULE_AUTHOR("Russell King"); +MODULE_DESCRIPTION("PCF8583 I2C RTC driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c index 01a1bd239263..2143609d2936 100644 --- a/drivers/acpi/acpi_memhotplug.c +++ b/drivers/acpi/acpi_memhotplug.c @@ -200,8 +200,7 @@ static int acpi_memory_enable_device(struct acpi_memory_device *mem_device) * Note: Assume that this function returns zero on success */ result = add_memory(mem_device->start_addr, - (mem_device->end_addr - mem_device->start_addr) + 1, - mem_device->read_write_attribute); + (mem_device->end_addr - mem_device->start_addr) + 1); if (result) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "\nadd_memory failed\n")); mem_device->state = MEMORY_INVALID_STATE; @@ -259,7 +258,7 @@ static int acpi_memory_disable_device(struct acpi_memory_device *mem_device) * Ask the VM to offline this memory range. * Note: Assume that this function returns zero on success */ - result = remove_memory(start, len, attr); + result = remove_memory(start, len); if (result) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Hot-Remove failed.\n")); return_VALUE(result); diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 26a3a4016115..161db4acfb91 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -37,6 +37,7 @@ #include <linux/acpi.h> #include <linux/dmi.h> #include <linux/moduleparam.h> +#include <linux/sched.h> /* need_resched() */ #include <asm/io.h> #include <asm/uaccess.h> diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c index aee50b453265..930427fc0c4b 100644 --- a/drivers/acpi/sleep/main.c +++ b/drivers/acpi/sleep/main.c @@ -158,7 +158,15 @@ int acpi_suspend(u32 acpi_state) return -EINVAL; } +static int acpi_pm_state_valid(suspend_state_t pm_state) +{ + u32 acpi_state = acpi_suspend_states[pm_state]; + + return sleep_states[acpi_state]; +} + static struct pm_ops acpi_pm_ops = { + .valid = acpi_pm_state_valid, .prepare = acpi_pm_prepare, .enter = acpi_pm_enter, .finish = acpi_pm_finish, diff --git a/drivers/base/Makefile b/drivers/base/Makefile index 66d9c4643fc1..f12898d53078 100644 --- a/drivers/base/Makefile +++ b/drivers/base/Makefile @@ -7,6 +7,7 @@ obj-y := core.o sys.o bus.o dd.o \ obj-y += power/ obj-$(CONFIG_FW_LOADER) += firmware_class.o obj-$(CONFIG_NUMA) += node.o +obj-$(CONFIG_MEMORY_HOTPLUG) += memory.o ifeq ($(CONFIG_DEBUG_DRIVER),y) EXTRA_CFLAGS += -DDEBUG diff --git a/drivers/base/attribute_container.c b/drivers/base/attribute_container.c index 6b2eb6f39b4d..2a7d7ae83e1e 100644 --- a/drivers/base/attribute_container.c +++ b/drivers/base/attribute_container.c @@ -19,6 +19,8 @@ #include <linux/list.h> #include <linux/module.h> +#include "base.h" + /* This is a private structure used to tie the classdev and the * container .. it should never be visible outside this file */ struct internal_container { diff --git a/drivers/base/base.h b/drivers/base/base.h index 783752b68a9a..e3b548d46cff 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -1,3 +1,15 @@ + +/* initialisation functions */ + +extern int devices_init(void); +extern int buses_init(void); +extern int classes_init(void); +extern int firmware_init(void); +extern int platform_bus_init(void); +extern int system_bus_init(void); +extern int cpu_dev_init(void); +extern int attribute_container_init(void); + extern int bus_add_device(struct device * dev); extern void bus_remove_device(struct device * dev); diff --git a/drivers/base/class.c b/drivers/base/class.c index ce23dc8c18c5..db65fd0babe9 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -17,6 +17,7 @@ #include <linux/string.h> #include <linux/kdev_t.h> #include <linux/err.h> +#include <linux/slab.h> #include "base.h" #define to_class_attr(_attr) container_of(_attr, struct class_attribute, attr) @@ -99,7 +100,8 @@ struct class * class_get(struct class * cls) void class_put(struct class * cls) { - subsys_put(&cls->subsys); + if (cls) + subsys_put(&cls->subsys); } @@ -165,14 +167,25 @@ void class_unregister(struct class * cls) static void class_create_release(struct class *cls) { + pr_debug("%s called for %s\n", __FUNCTION__, cls->name); kfree(cls); } static void class_device_create_release(struct class_device *class_dev) { + pr_debug("%s called for %s\n", __FUNCTION__, class_dev->class_id); kfree(class_dev); } +/* needed to allow these devices to have parent class devices */ +static int class_device_create_hotplug(struct class_device *class_dev, + char **envp, int num_envp, + char *buffer, int buffer_size) +{ + pr_debug("%s called for %s\n", __FUNCTION__, class_dev->class_id); + return 0; +} + /** * class_create - create a struct class structure * @owner: pointer to the module that is to "own" this struct class @@ -301,10 +314,12 @@ static void class_dev_release(struct kobject * kobj) kfree(cd->devt_attr); cd->devt_attr = NULL; - if (cls->release) + if (cd->release) + cd->release(cd); + else if (cls->release) cls->release(cd); else { - printk(KERN_ERR "Device class '%s' does not have a release() function, " + printk(KERN_ERR "Class Device '%s' does not have a release() function, " "it is broken and must be fixed.\n", cd->class_id); WARN_ON(1); @@ -382,14 +397,18 @@ static int class_hotplug(struct kset *kset, struct kobject *kobj, char **envp, buffer = &buffer[length]; buffer_size -= length; - if (class_dev->class->hotplug) { - /* have the bus specific function add its stuff */ - retval = class_dev->class->hotplug (class_dev, envp, num_envp, - buffer, buffer_size); - if (retval) { - pr_debug ("%s - hotplug() returned %d\n", - __FUNCTION__, retval); - } + if (class_dev->hotplug) { + /* have the class device specific function add its stuff */ + retval = class_dev->hotplug(class_dev, envp, num_envp, + buffer, buffer_size); + if (retval) + pr_debug("class_dev->hotplug() returned %d\n", retval); + } else if (class_dev->class->hotplug) { + /* have the class specific function add its stuff */ + retval = class_dev->class->hotplug(class_dev, envp, num_envp, + buffer, buffer_size); + if (retval) + pr_debug("class->hotplug() returned %d\n", retval); } return retval; @@ -442,6 +461,13 @@ static ssize_t show_dev(struct class_device *class_dev, char *buf) return print_dev_t(buf, class_dev->devt); } +static ssize_t store_uevent(struct class_device *class_dev, + const char *buf, size_t count) +{ + kobject_hotplug(&class_dev->kobj, KOBJ_ADD); + return count; +} + void class_device_initialize(struct class_device *class_dev) { kobj_set_kset_s(class_dev, class_obj_subsys); @@ -469,34 +495,45 @@ static char *make_class_name(struct class_device *class_dev) int class_device_add(struct class_device *class_dev) { - struct class * parent = NULL; - struct class_interface * class_intf; + struct class *parent_class = NULL; + struct class_device *parent_class_dev = NULL; + struct class_interface *class_intf; char *class_name = NULL; - int error; + int error = -EINVAL; class_dev = class_device_get(class_dev); if (!class_dev) return -EINVAL; - if (!strlen(class_dev->class_id)) { - error = -EINVAL; + if (!strlen(class_dev->class_id)) goto register_done; - } - parent = class_get(class_dev->class); + parent_class = class_get(class_dev->class); + if (!parent_class) + goto register_done; + parent_class_dev = class_device_get(class_dev->parent); pr_debug("CLASS: registering class device: ID = '%s'\n", class_dev->class_id); /* first, register with generic layer. */ kobject_set_name(&class_dev->kobj, "%s", class_dev->class_id); - if (parent) - class_dev->kobj.parent = &parent->subsys.kset.kobj; + if (parent_class_dev) + class_dev->kobj.parent = &parent_class_dev->kobj; + else + class_dev->kobj.parent = &parent_class->subsys.kset.kobj; - if ((error = kobject_add(&class_dev->kobj))) + error = kobject_add(&class_dev->kobj); + if (error) goto register_done; /* add the needed attributes to this device */ + class_dev->uevent_attr.attr.name = "uevent"; + class_dev->uevent_attr.attr.mode = S_IWUSR; + class_dev->uevent_attr.attr.owner = parent_class->owner; + class_dev->uevent_attr.store = store_uevent; + class_device_create_file(class_dev, &class_dev->uevent_attr); + if (MAJOR(class_dev->devt)) { struct class_device_attribute *attr; attr = kzalloc(sizeof(*attr), GFP_KERNEL); @@ -505,12 +542,10 @@ int class_device_add(struct class_device *class_dev) kobject_del(&class_dev->kobj); goto register_done; } - attr->attr.name = "dev"; attr->attr.mode = S_IRUGO; - attr->attr.owner = parent->owner; + attr->attr.owner = parent_class->owner; attr->show = show_dev; - attr->store = NULL; class_device_create_file(class_dev, attr); class_dev->devt_attr = attr; } @@ -524,20 +559,23 @@ int class_device_add(struct class_device *class_dev) class_name); } + kobject_hotplug(&class_dev->kobj, KOBJ_ADD); + /* notify any interfaces this device is now here */ - if (parent) { - down(&parent->sem); - list_add_tail(&class_dev->node, &parent->children); - list_for_each_entry(class_intf, &parent->interfaces, node) + if (parent_class) { + down(&parent_class->sem); + list_add_tail(&class_dev->node, &parent_class->children); + list_for_each_entry(class_intf, &parent_class->interfaces, node) if (class_intf->add) - class_intf->add(class_dev); - up(&parent->sem); + class_intf->add(class_dev, class_intf); + up(&parent_class->sem); } - kobject_hotplug(&class_dev->kobj, KOBJ_ADD); register_done: - if (error && parent) - class_put(parent); + if (error) { + class_put(parent_class); + class_device_put(parent_class_dev); + } class_device_put(class_dev); kfree(class_name); return error; @@ -552,21 +590,28 @@ int class_device_register(struct class_device *class_dev) /** * class_device_create - creates a class device and registers it with sysfs * @cs: pointer to the struct class that this device should be registered to. + * @parent: pointer to the parent struct class_device of this new device, if any. * @dev: the dev_t for the char device to be added. * @device: a pointer to a struct device that is assiociated with this class device. * @fmt: string for the class device's name * * This function can be used by char device classes. A struct * class_device will be created in sysfs, registered to the specified - * class. A "dev" file will be created, showing the dev_t for the - * device. The pointer to the struct class_device will be returned from - * the call. Any further sysfs files that might be required can be - * created using this pointer. + * class. + * A "dev" file will be created, showing the dev_t for the device, if + * the dev_t is not 0,0. + * If a pointer to a parent struct class_device is passed in, the newly + * created struct class_device will be a child of that device in sysfs. + * The pointer to the struct class_device will be returned from the + * call. Any further sysfs files that might be required can be created + * using this pointer. * * Note: the struct class passed to this function must have previously * been created with a call to class_create(). */ -struct class_device *class_device_create(struct class *cls, dev_t devt, +struct class_device *class_device_create(struct class *cls, + struct class_device *parent, + dev_t devt, struct device *device, char *fmt, ...) { va_list args; @@ -585,6 +630,9 @@ struct class_device *class_device_create(struct class *cls, dev_t devt, class_dev->devt = devt; class_dev->dev = device; class_dev->class = cls; + class_dev->parent = parent; + class_dev->release = class_device_create_release; + class_dev->hotplug = class_device_create_hotplug; va_start(args, fmt); vsnprintf(class_dev->class_id, BUS_ID_SIZE, fmt, args); @@ -602,17 +650,18 @@ error: void class_device_del(struct class_device *class_dev) { - struct class * parent = class_dev->class; - struct class_interface * class_intf; + struct class *parent_class = class_dev->class; + struct class_device *parent_device = class_dev->parent; + struct class_interface *class_intf; char *class_name = NULL; - if (parent) { - down(&parent->sem); + if (parent_class) { + down(&parent_class->sem); list_del_init(&class_dev->node); - list_for_each_entry(class_intf, &parent->interfaces, node) + list_for_each_entry(class_intf, &parent_class->interfaces, node) if (class_intf->remove) - class_intf->remove(class_dev); - up(&parent->sem); + class_intf->remove(class_dev, class_intf); + up(&parent_class->sem); } if (class_dev->dev) { @@ -620,6 +669,7 @@ void class_device_del(struct class_device *class_dev) sysfs_remove_link(&class_dev->kobj, "device"); sysfs_remove_link(&class_dev->dev->kobj, class_name); } + class_device_remove_file(class_dev, &class_dev->uevent_attr); if (class_dev->devt_attr) class_device_remove_file(class_dev, class_dev->devt_attr); class_device_remove_attrs(class_dev); @@ -627,8 +677,8 @@ void class_device_del(struct class_device *class_dev) kobject_hotplug(&class_dev->kobj, KOBJ_REMOVE); kobject_del(&class_dev->kobj); - if (parent) - class_put(parent); + class_device_put(parent_device); + class_put(parent_class); kfree(class_name); } @@ -708,7 +758,8 @@ struct class_device * class_device_get(struct class_device *class_dev) void class_device_put(struct class_device *class_dev) { - kobject_put(&class_dev->kobj); + if (class_dev) + kobject_put(&class_dev->kobj); } @@ -728,7 +779,7 @@ int class_interface_register(struct class_interface *class_intf) list_add_tail(&class_intf->node, &parent->interfaces); if (class_intf->add) { list_for_each_entry(class_dev, &parent->children, node) - class_intf->add(class_dev); + class_intf->add(class_dev, class_intf); } up(&parent->sem); @@ -747,7 +798,7 @@ void class_interface_unregister(struct class_interface *class_intf) list_del_init(&class_intf->node); if (class_intf->remove) { list_for_each_entry(class_dev, &parent->children, node) - class_intf->remove(class_dev); + class_intf->remove(class_dev, class_intf); } up(&parent->sem); diff --git a/drivers/base/core.c b/drivers/base/core.c index 6ab73f5c799a..8615b42b517a 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -154,6 +154,13 @@ static struct kset_hotplug_ops device_hotplug_ops = { .hotplug = dev_hotplug, }; +static ssize_t store_uevent(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + kobject_hotplug(&dev->kobj, KOBJ_ADD); + return count; +} + /** * device_subsys - structure to be registered with kobject core. */ @@ -225,6 +232,7 @@ void device_initialize(struct device *dev) klist_children_put); INIT_LIST_HEAD(&dev->dma_pools); init_MUTEX(&dev->sem); + device_init_wakeup(dev, 0); } /** @@ -258,6 +266,14 @@ int device_add(struct device *dev) if ((error = kobject_add(&dev->kobj))) goto Error; + + dev->uevent_attr.attr.name = "uevent"; + dev->uevent_attr.attr.mode = S_IWUSR; + if (dev->driver) + dev->uevent_attr.attr.owner = dev->driver->owner; + dev->uevent_attr.store = store_uevent; + device_create_file(dev, &dev->uevent_attr); + kobject_hotplug(&dev->kobj, KOBJ_ADD); if ((error = device_pm_add(dev))) goto PMError; @@ -349,6 +365,7 @@ void device_del(struct device * dev) if (parent) klist_del(&dev->knode_parent); + device_remove_file(dev, &dev->uevent_attr); /* Notify the platform of the removal, in case they * need to do anything... @@ -390,11 +407,11 @@ static struct device * next_device(struct klist_iter * i) /** * device_for_each_child - device child iterator. - * @dev: parent struct device. + * @parent: parent struct device. * @data: data for the callback. * @fn: function to be called for each device. * - * Iterate over @dev's child devices, and call @fn for each, + * Iterate over @parent's child devices, and call @fn for each, * passing it @data. * * We check the return of @fn each time. If it returns anything diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index b79badd0f158..a95844790f7b 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -9,12 +9,15 @@ #include <linux/topology.h> #include <linux/device.h> +#include "base.h" struct sysdev_class cpu_sysdev_class = { set_kset_name("cpu"), }; EXPORT_SYMBOL(cpu_sysdev_class); +static struct sys_device *cpu_sys_devices[NR_CPUS]; + #ifdef CONFIG_HOTPLUG_CPU int __attribute__((weak)) smp_prepare_cpu (int cpu) { @@ -63,6 +66,7 @@ static void __devinit register_cpu_control(struct cpu *cpu) } void unregister_cpu(struct cpu *cpu, struct node *root) { + int logical_cpu = cpu->sysdev.id; if (root) sysfs_remove_link(&root->sysdev.kobj, @@ -70,7 +74,7 @@ void unregister_cpu(struct cpu *cpu, struct node *root) sysdev_remove_file(&cpu->sysdev, &attr_online); sysdev_unregister(&cpu->sysdev); - + cpu_sys_devices[logical_cpu] = NULL; return; } #else /* ... !CONFIG_HOTPLUG_CPU */ @@ -102,10 +106,19 @@ int __devinit register_cpu(struct cpu *cpu, int num, struct node *root) kobject_name(&cpu->sysdev.kobj)); if (!error && !cpu->no_control) register_cpu_control(cpu); + if (!error) + cpu_sys_devices[num] = &cpu->sysdev; return error; } - +struct sys_device *get_cpu_sysdev(int cpu) +{ + if (cpu < NR_CPUS) + return cpu_sys_devices[cpu]; + else + return NULL; +} +EXPORT_SYMBOL_GPL(get_cpu_sysdev); int __init cpu_dev_init(void) { diff --git a/drivers/base/driver.c b/drivers/base/driver.c index ef3fe513e398..161f3a390d90 100644 --- a/drivers/base/driver.c +++ b/drivers/base/driver.c @@ -28,6 +28,7 @@ static struct device * next_device(struct klist_iter * i) /** * driver_for_each_device - Iterator for devices bound to a driver. * @drv: Driver we're iterating. + * @start: Device to begin with * @data: Data to pass to the callback. * @fn: Function to call for each device. * @@ -57,7 +58,7 @@ EXPORT_SYMBOL_GPL(driver_for_each_device); /** * driver_find_device - device iterator for locating a particular device. - * @driver: The device's driver + * @drv: The device's driver * @start: Device to begin with * @data: Data to pass to match function * @match: Callback function to check device diff --git a/drivers/base/firmware.c b/drivers/base/firmware.c index 88ab044932f2..cb1b98ae0d58 100644 --- a/drivers/base/firmware.c +++ b/drivers/base/firmware.c @@ -11,6 +11,9 @@ #include <linux/kobject.h> #include <linux/module.h> #include <linux/init.h> +#include <linux/device.h> + +#include "base.h" static decl_subsys(firmware, NULL, NULL); diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index 4acb2c5733c3..98f6c02d6790 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -62,14 +62,16 @@ firmware_timeout_show(struct class *class, char *buf) } /** - * firmware_timeout_store: - * Description: + * firmware_timeout_store - set number of seconds to wait for firmware + * @class: device class pointer + * @buf: buffer to scan for timeout value + * @count: number of bytes in @buf + * * Sets the number of seconds to wait for the firmware. Once - * this expires an error will be return to the driver and no + * this expires an error will be returned to the driver and no * firmware will be provided. * - * Note: zero means 'wait for ever' - * + * Note: zero means 'wait forever'. **/ static ssize_t firmware_timeout_store(struct class *class, const char *buf, size_t count) @@ -123,12 +125,15 @@ firmware_loading_show(struct class_device *class_dev, char *buf) } /** - * firmware_loading_store: - loading control file - * Description: + * firmware_loading_store - set value in the 'loading' control file + * @class_dev: class_device pointer + * @buf: buffer to scan for loading control value + * @count: number of bytes in @buf + * * The relevant values are: * * 1: Start a load, discarding any previous partial load. - * 0: Conclude the load and handle the data to the driver code. + * 0: Conclude the load and hand the data to the driver code. * -1: Conclude the load with an error and discard any written data. **/ static ssize_t @@ -201,6 +206,7 @@ out: up(&fw_lock); return ret_count; } + static int fw_realloc_buffer(struct firmware_priv *fw_priv, int min_size) { @@ -227,11 +233,13 @@ fw_realloc_buffer(struct firmware_priv *fw_priv, int min_size) } /** - * firmware_data_write: + * firmware_data_write - write method for firmware + * @kobj: kobject for the class_device + * @buffer: buffer being written + * @offset: buffer offset for write in total data store area + * @count: buffer size * - * Description: - * - * Data written to the 'data' attribute will be later handled to + * Data written to the 'data' attribute will be later handed to * the driver as a firmware image. **/ static ssize_t @@ -264,6 +272,7 @@ out: up(&fw_lock); return retval; } + static struct bin_attribute firmware_attr_data_tmpl = { .attr = {.name = "data", .mode = 0644, .owner = THIS_MODULE}, .size = 0, @@ -448,13 +457,16 @@ out: /** * request_firmware: - request firmware to hotplug and wait for it - * Description: - * @firmware will be used to return a firmware image by the name + * @firmware_p: pointer to firmware image + * @name: name of firmware file + * @device: device for which firmware is being loaded + * + * @firmware_p will be used to return a firmware image by the name * of @name for device @device. * * Should be called from user context where sleeping is allowed. * - * @name will be use as $FIRMWARE in the hotplug environment and + * @name will be used as $FIRMWARE in the hotplug environment and * should be distinctive enough not to be confused with any other * firmware image for this or any other device. **/ @@ -468,6 +480,7 @@ request_firmware(const struct firmware **firmware_p, const char *name, /** * release_firmware: - release the resource associated with a firmware image + * @fw: firmware resource to release **/ void release_firmware(const struct firmware *fw) @@ -480,8 +493,10 @@ release_firmware(const struct firmware *fw) /** * register_firmware: - provide a firmware image for later usage + * @name: name of firmware image file + * @data: buffer pointer for the firmware image + * @size: size of the data buffer area * - * Description: * Make sure that @data will be available by requesting firmware @name. * * Note: This will not be possible until some kind of persistence @@ -526,21 +541,19 @@ request_firmware_work_func(void *arg) } /** - * request_firmware_nowait: + * request_firmware_nowait: asynchronous version of request_firmware + * @module: module requesting the firmware + * @hotplug: invokes hotplug event to copy the firmware image if this flag + * is non-zero else the firmware copy must be done manually. + * @name: name of firmware file + * @device: device for which firmware is being loaded + * @context: will be passed over to @cont, and + * @fw may be %NULL if firmware request fails. + * @cont: function will be called asynchronously when the firmware + * request is over. * - * Description: * Asynchronous variant of request_firmware() for contexts where * it is not possible to sleep. - * - * @hotplug invokes hotplug event to copy the firmware image if this flag - * is non-zero else the firmware copy must be done manually. - * - * @cont will be called asynchronously when the firmware request is over. - * - * @context will be passed over to @cont. - * - * @fw may be %NULL if firmware request fails. - * **/ int request_firmware_nowait( diff --git a/drivers/base/init.c b/drivers/base/init.c index a76ae5a221f3..c648914b9cde 100644 --- a/drivers/base/init.c +++ b/drivers/base/init.c @@ -9,15 +9,10 @@ #include <linux/device.h> #include <linux/init.h> +#include <linux/memory.h> + +#include "base.h" -extern int devices_init(void); -extern int buses_init(void); -extern int classes_init(void); -extern int firmware_init(void); -extern int platform_bus_init(void); -extern int system_bus_init(void); -extern int cpu_dev_init(void); -extern int attribute_container_init(void); /** * driver_init - initialize driver model. * @@ -39,5 +34,6 @@ void __init driver_init(void) platform_bus_init(); system_bus_init(); cpu_dev_init(); + memory_dev_init(); attribute_container_init(); } diff --git a/drivers/base/memory.c b/drivers/base/memory.c new file mode 100644 index 000000000000..b7ddd651d664 --- /dev/null +++ b/drivers/base/memory.c @@ -0,0 +1,452 @@ +/* + * drivers/base/memory.c - basic Memory class support + * + * Written by Matt Tolentino <matthew.e.tolentino@intel.com> + * Dave Hansen <haveblue@us.ibm.com> + * + * This file provides the necessary infrastructure to represent + * a SPARSEMEM-memory-model system's physical memory in /sysfs. + * All arch-independent code that assumes MEMORY_HOTPLUG requires + * SPARSEMEM should be contained here, or in mm/memory_hotplug.c. + */ + +#include <linux/sysdev.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/sched.h> /* capable() */ +#include <linux/topology.h> +#include <linux/device.h> +#include <linux/memory.h> +#include <linux/kobject.h> +#include <linux/memory_hotplug.h> +#include <linux/mm.h> +#include <asm/atomic.h> +#include <asm/uaccess.h> + +#define MEMORY_CLASS_NAME "memory" + +static struct sysdev_class memory_sysdev_class = { + set_kset_name(MEMORY_CLASS_NAME), +}; +EXPORT_SYMBOL(memory_sysdev_class); + +static char *memory_hotplug_name(struct kset *kset, struct kobject *kobj) +{ + return MEMORY_CLASS_NAME; +} + +static int memory_hotplug(struct kset *kset, struct kobject *kobj, char **envp, + int num_envp, char *buffer, int buffer_size) +{ + int retval = 0; + + return retval; +} + +static struct kset_hotplug_ops memory_hotplug_ops = { + .name = memory_hotplug_name, + .hotplug = memory_hotplug, +}; + +static struct notifier_block *memory_chain; + +static int register_memory_notifier(struct notifier_block *nb) +{ + return notifier_chain_register(&memory_chain, nb); +} + +static void unregister_memory_notifier(struct notifier_block *nb) +{ + notifier_chain_unregister(&memory_chain, nb); +} + +/* + * register_memory - Setup a sysfs device for a memory block + */ +static int +register_memory(struct memory_block *memory, struct mem_section *section, + struct node *root) +{ + int error; + + memory->sysdev.cls = &memory_sysdev_class; + memory->sysdev.id = __section_nr(section); + + error = sysdev_register(&memory->sysdev); + + if (root && !error) + error = sysfs_create_link(&root->sysdev.kobj, + &memory->sysdev.kobj, + kobject_name(&memory->sysdev.kobj)); + + return error; +} + +static void +unregister_memory(struct memory_block *memory, struct mem_section *section, + struct node *root) +{ + BUG_ON(memory->sysdev.cls != &memory_sysdev_class); + BUG_ON(memory->sysdev.id != __section_nr(section)); + + sysdev_unregister(&memory->sysdev); + if (root) + sysfs_remove_link(&root->sysdev.kobj, + kobject_name(&memory->sysdev.kobj)); +} + +/* + * use this as the physical section index that this memsection + * uses. + */ + +static ssize_t show_mem_phys_index(struct sys_device *dev, char *buf) +{ + struct memory_block *mem = + container_of(dev, struct memory_block, sysdev); + return sprintf(buf, "%08lx\n", mem->phys_index); +} + +/* + * online, offline, going offline, etc. + */ +static ssize_t show_mem_state(struct sys_device *dev, char *buf) +{ + struct memory_block *mem = + container_of(dev, struct memory_block, sysdev); + ssize_t len = 0; + + /* + * We can probably put these states in a nice little array + * so that they're not open-coded + */ + switch (mem->state) { + case MEM_ONLINE: + len = sprintf(buf, "online\n"); + break; + case MEM_OFFLINE: + len = sprintf(buf, "offline\n"); + break; + case MEM_GOING_OFFLINE: + len = sprintf(buf, "going-offline\n"); + break; + default: + len = sprintf(buf, "ERROR-UNKNOWN-%ld\n", + mem->state); + WARN_ON(1); + break; + } + + return len; +} + +static inline int memory_notify(unsigned long val, void *v) +{ + return notifier_call_chain(&memory_chain, val, v); +} + +/* + * MEMORY_HOTPLUG depends on SPARSEMEM in mm/Kconfig, so it is + * OK to have direct references to sparsemem variables in here. + */ +static int +memory_block_action(struct memory_block *mem, unsigned long action) +{ + int i; + unsigned long psection; + unsigned long start_pfn, start_paddr; + struct page *first_page; + int ret; + int old_state = mem->state; + + psection = mem->phys_index; + first_page = pfn_to_page(psection << PFN_SECTION_SHIFT); + + /* + * The probe routines leave the pages reserved, just + * as the bootmem code does. Make sure they're still + * that way. + */ + if (action == MEM_ONLINE) { + for (i = 0; i < PAGES_PER_SECTION; i++) { + if (PageReserved(first_page+i)) + continue; + + printk(KERN_WARNING "section number %ld page number %d " + "not reserved, was it already online? \n", + psection, i); + return -EBUSY; + } + } + + switch (action) { + case MEM_ONLINE: + start_pfn = page_to_pfn(first_page); + ret = online_pages(start_pfn, PAGES_PER_SECTION); + break; + case MEM_OFFLINE: + mem->state = MEM_GOING_OFFLINE; + memory_notify(MEM_GOING_OFFLINE, NULL); + start_paddr = page_to_pfn(first_page) << PAGE_SHIFT; + ret = remove_memory(start_paddr, + PAGES_PER_SECTION << PAGE_SHIFT); + if (ret) { + mem->state = old_state; + break; + } + memory_notify(MEM_MAPPING_INVALID, NULL); + break; + default: + printk(KERN_WARNING "%s(%p, %ld) unknown action: %ld\n", + __FUNCTION__, mem, action, action); + WARN_ON(1); + ret = -EINVAL; + } + /* + * For now, only notify on successful memory operations + */ + if (!ret) + memory_notify(action, NULL); + + return ret; +} + +static int memory_block_change_state(struct memory_block *mem, + unsigned long to_state, unsigned long from_state_req) +{ + int ret = 0; + down(&mem->state_sem); + + if (mem->state != from_state_req) { + ret = -EINVAL; + goto out; + } + + ret = memory_block_action(mem, to_state); + if (!ret) + mem->state = to_state; + +out: + up(&mem->state_sem); + return ret; +} + +static ssize_t +store_mem_state(struct sys_device *dev, const char *buf, size_t count) +{ + struct memory_block *mem; + unsigned int phys_section_nr; + int ret = -EINVAL; + + mem = container_of(dev, struct memory_block, sysdev); + phys_section_nr = mem->phys_index; + + if (!valid_section_nr(phys_section_nr)) + goto out; + + if (!strncmp(buf, "online", min((int)count, 6))) + ret = memory_block_change_state(mem, MEM_ONLINE, MEM_OFFLINE); + else if(!strncmp(buf, "offline", min((int)count, 7))) + ret = memory_block_change_state(mem, MEM_OFFLINE, MEM_ONLINE); +out: + if (ret) + return ret; + return count; +} + +/* + * phys_device is a bad name for this. What I really want + * is a way to differentiate between memory ranges that + * are part of physical devices that constitute + * a complete removable unit or fru. + * i.e. do these ranges belong to the same physical device, + * s.t. if I offline all of these sections I can then + * remove the physical device? + */ +static ssize_t show_phys_device(struct sys_device *dev, char *buf) +{ + struct memory_block *mem = + container_of(dev, struct memory_block, sysdev); + return sprintf(buf, "%d\n", mem->phys_device); +} + +static SYSDEV_ATTR(phys_index, 0444, show_mem_phys_index, NULL); +static SYSDEV_ATTR(state, 0644, show_mem_state, store_mem_state); +static SYSDEV_ATTR(phys_device, 0444, show_phys_device, NULL); + +#define mem_create_simple_file(mem, attr_name) \ + sysdev_create_file(&mem->sysdev, &attr_##attr_name) +#define mem_remove_simple_file(mem, attr_name) \ + sysdev_remove_file(&mem->sysdev, &attr_##attr_name) + +/* + * Block size attribute stuff + */ +static ssize_t +print_block_size(struct class *class, char *buf) +{ + return sprintf(buf, "%lx\n", (unsigned long)PAGES_PER_SECTION * PAGE_SIZE); +} + +static CLASS_ATTR(block_size_bytes, 0444, print_block_size, NULL); + +static int block_size_init(void) +{ + sysfs_create_file(&memory_sysdev_class.kset.kobj, + &class_attr_block_size_bytes.attr); + return 0; +} + +/* + * Some architectures will have custom drivers to do this, and + * will not need to do it from userspace. The fake hot-add code + * as well as ppc64 will do all of their discovery in userspace + * and will require this interface. + */ +#ifdef CONFIG_ARCH_MEMORY_PROBE +static ssize_t +memory_probe_store(struct class *class, const char __user *buf, size_t count) +{ + u64 phys_addr; + int ret; + + phys_addr = simple_strtoull(buf, NULL, 0); + + ret = add_memory(phys_addr, PAGES_PER_SECTION << PAGE_SHIFT); + + if (ret) + count = ret; + + return count; +} +static CLASS_ATTR(probe, 0700, NULL, memory_probe_store); + +static int memory_probe_init(void) +{ + sysfs_create_file(&memory_sysdev_class.kset.kobj, + &class_attr_probe.attr); + return 0; +} +#else +#define memory_probe_init(...) do {} while (0) +#endif + +/* + * Note that phys_device is optional. It is here to allow for + * differentiation between which *physical* devices each + * section belongs to... + */ + +static int add_memory_block(unsigned long node_id, struct mem_section *section, + unsigned long state, int phys_device) +{ + struct memory_block *mem = kzalloc(sizeof(*mem), GFP_KERNEL); + int ret = 0; + + if (!mem) + return -ENOMEM; + + mem->phys_index = __section_nr(section); + mem->state = state; + init_MUTEX(&mem->state_sem); + mem->phys_device = phys_device; + + ret = register_memory(mem, section, NULL); + if (!ret) + ret = mem_create_simple_file(mem, phys_index); + if (!ret) + ret = mem_create_simple_file(mem, state); + if (!ret) + ret = mem_create_simple_file(mem, phys_device); + + return ret; +} + +/* + * For now, we have a linear search to go find the appropriate + * memory_block corresponding to a particular phys_index. If + * this gets to be a real problem, we can always use a radix + * tree or something here. + * + * This could be made generic for all sysdev classes. + */ +static struct memory_block *find_memory_block(struct mem_section *section) +{ + struct kobject *kobj; + struct sys_device *sysdev; + struct memory_block *mem; + char name[sizeof(MEMORY_CLASS_NAME) + 9 + 1]; + + /* + * This only works because we know that section == sysdev->id + * slightly redundant with sysdev_register() + */ + sprintf(&name[0], "%s%d", MEMORY_CLASS_NAME, __section_nr(section)); + + kobj = kset_find_obj(&memory_sysdev_class.kset, name); + if (!kobj) + return NULL; + + sysdev = container_of(kobj, struct sys_device, kobj); + mem = container_of(sysdev, struct memory_block, sysdev); + + return mem; +} + +int remove_memory_block(unsigned long node_id, struct mem_section *section, + int phys_device) +{ + struct memory_block *mem; + + mem = find_memory_block(section); + mem_remove_simple_file(mem, phys_index); + mem_remove_simple_file(mem, state); + mem_remove_simple_file(mem, phys_device); + unregister_memory(mem, section, NULL); + + return 0; +} + +/* + * need an interface for the VM to add new memory regions, + * but without onlining it. + */ +int register_new_memory(struct mem_section *section) +{ + return add_memory_block(0, section, MEM_OFFLINE, 0); +} + +int unregister_memory_section(struct mem_section *section) +{ + if (!valid_section(section)) + return -EINVAL; + + return remove_memory_block(0, section, 0); +} + +/* + * Initialize the sysfs support for memory devices... + */ +int __init memory_dev_init(void) +{ + unsigned int i; + int ret; + + memory_sysdev_class.kset.hotplug_ops = &memory_hotplug_ops; + ret = sysdev_class_register(&memory_sysdev_class); + + /* + * Create entries for memory sections that were found + * during boot and have been initialized + */ + for (i = 0; i < NR_MEM_SECTIONS; i++) { + if (!valid_section_nr(i)) + continue; + add_memory_block(0, __nr_to_section(i), MEM_ONLINE, 0); + } + + memory_probe_init(); + block_size_init(); + + return ret; +} diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 361e204209eb..08d9cc99c7de 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -16,6 +16,9 @@ #include <linux/dma-mapping.h> #include <linux/bootmem.h> #include <linux/err.h> +#include <linux/slab.h> + +#include "base.h" struct device platform_bus = { .bus_id = "platform", @@ -279,13 +282,9 @@ static int platform_suspend(struct device * dev, pm_message_t state) { int ret = 0; - if (dev->driver && dev->driver->suspend) { - ret = dev->driver->suspend(dev, state, SUSPEND_DISABLE); - if (ret == 0) - ret = dev->driver->suspend(dev, state, SUSPEND_SAVE_STATE); - if (ret == 0) - ret = dev->driver->suspend(dev, state, SUSPEND_POWER_DOWN); - } + if (dev->driver && dev->driver->suspend) + ret = dev->driver->suspend(dev, state); + return ret; } @@ -293,13 +292,9 @@ static int platform_resume(struct device * dev) { int ret = 0; - if (dev->driver && dev->driver->resume) { - ret = dev->driver->resume(dev, RESUME_POWER_ON); - if (ret == 0) - ret = dev->driver->resume(dev, RESUME_RESTORE_STATE); - if (ret == 0) - ret = dev->driver->resume(dev, RESUME_ENABLE); - } + if (dev->driver && dev->driver->resume) + ret = dev->driver->resume(dev); + return ret; } diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 15e6a8f951f1..0d2e101e4f15 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -30,23 +30,6 @@ LIST_HEAD(dpm_off_irq); DECLARE_MUTEX(dpm_sem); DECLARE_MUTEX(dpm_list_sem); -/* - * PM Reference Counting. - */ - -static inline void device_pm_hold(struct device * dev) -{ - if (dev) - atomic_inc(&dev->power.pm_users); -} - -static inline void device_pm_release(struct device * dev) -{ - if (dev) - atomic_dec(&dev->power.pm_users); -} - - /** * device_pm_set_parent - Specify power dependency. * @dev: Device who needs power. @@ -62,10 +45,8 @@ static inline void device_pm_release(struct device * dev) void device_pm_set_parent(struct device * dev, struct device * parent) { - struct device * old_parent = dev->power.pm_parent; - device_pm_release(old_parent); - dev->power.pm_parent = parent; - device_pm_hold(parent); + put_device(dev->power.pm_parent); + dev->power.pm_parent = get_device(parent); } EXPORT_SYMBOL_GPL(device_pm_set_parent); @@ -75,7 +56,6 @@ int device_pm_add(struct device * dev) pr_debug("PM: Adding info for %s:%s\n", dev->bus ? dev->bus->name : "No Bus", dev->kobj.name); - atomic_set(&dev->power.pm_users, 0); down(&dpm_list_sem); list_add_tail(&dev->power.entry, &dpm_active); device_pm_set_parent(dev, dev->parent); @@ -91,7 +71,7 @@ void device_pm_remove(struct device * dev) dev->bus ? dev->bus->name : "No Bus", dev->kobj.name); down(&dpm_list_sem); dpm_sysfs_remove(dev); - device_pm_release(dev->power.pm_parent); + put_device(dev->power.pm_parent); list_del_init(&dev->power.entry); up(&dpm_list_sem); } diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h index 2e700d795cf1..fb3d35a9e101 100644 --- a/drivers/base/power/power.h +++ b/drivers/base/power/power.h @@ -67,9 +67,6 @@ extern int suspend_device(struct device *, pm_message_t); * runtime.c */ -extern int dpm_runtime_suspend(struct device *, pm_message_t); -extern void dpm_runtime_resume(struct device *); - #else /* CONFIG_PM */ @@ -82,14 +79,4 @@ static inline void device_pm_remove(struct device * dev) } -static inline int dpm_runtime_suspend(struct device * dev, pm_message_t state) -{ - return 0; -} - -static inline void dpm_runtime_resume(struct device * dev) -{ - -} - #endif diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index e8f0519f5dfa..adbc3148c039 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -36,6 +36,7 @@ void dpm_runtime_resume(struct device * dev) runtime_resume(dev); up(&dpm_sem); } +EXPORT_SYMBOL(dpm_runtime_resume); /** diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c index 8d04fb435c17..89c57875f3e5 100644 --- a/drivers/base/power/sysfs.c +++ b/drivers/base/power/sysfs.c @@ -48,8 +48,81 @@ static ssize_t state_store(struct device * dev, struct device_attribute *attr, c static DEVICE_ATTR(state, 0644, state_show, state_store); +/* + * wakeup - Report/change current wakeup option for device + * + * Some devices support "wakeup" events, which are hardware signals + * used to activate devices from suspended or low power states. Such + * devices have one of three values for the sysfs power/wakeup file: + * + * + "enabled\n" to issue the events; + * + "disabled\n" not to do so; or + * + "\n" for temporary or permanent inability to issue wakeup. + * + * (For example, unconfigured USB devices can't issue wakeups.) + * + * Familiar examples of devices that can issue wakeup events include + * keyboards and mice (both PS2 and USB styles), power buttons, modems, + * "Wake-On-LAN" Ethernet links, GPIO lines, and more. Some events + * will wake the entire system from a suspend state; others may just + * wake up the device (if the system as a whole is already active). + * Some wakeup events use normal IRQ lines; other use special out + * of band signaling. + * + * It is the responsibility of device drivers to enable (or disable) + * wakeup signaling as part of changing device power states, respecting + * the policy choices provided through the driver model. + * + * Devices may not be able to generate wakeup events from all power + * states. Also, the events may be ignored in some configurations; + * for example, they might need help from other devices that aren't + * active, or which may have wakeup disabled. Some drivers rely on + * wakeup events internally (unless they are disabled), keeping + * their hardware in low power modes whenever they're unused. This + * saves runtime power, without requiring system-wide sleep states. + */ + +static const char enabled[] = "enabled"; +static const char disabled[] = "disabled"; + +static ssize_t +wake_show(struct device * dev, struct device_attribute *attr, char * buf) +{ + return sprintf(buf, "%s\n", device_can_wakeup(dev) + ? (device_may_wakeup(dev) ? enabled : disabled) + : ""); +} + +static ssize_t +wake_store(struct device * dev, struct device_attribute *attr, + const char * buf, size_t n) +{ + char *cp; + int len = n; + + if (!device_can_wakeup(dev)) + return -EINVAL; + + cp = memchr(buf, '\n', n); + if (cp) + len = cp - buf; + if (len == sizeof enabled - 1 + && strncmp(buf, enabled, sizeof enabled - 1) == 0) + device_set_wakeup_enable(dev, 1); + else if (len == sizeof disabled - 1 + && strncmp(buf, disabled, sizeof disabled - 1) == 0) + device_set_wakeup_enable(dev, 0); + else + return -EINVAL; + return n; +} + +static DEVICE_ATTR(wakeup, 0644, wake_show, wake_store); + + static struct attribute * power_attrs[] = { &dev_attr_state.attr, + &dev_attr_wakeup.attr, NULL, }; static struct attribute_group pm_attr_group = { diff --git a/drivers/base/sys.c b/drivers/base/sys.c index 3431eb6004c3..66ed8f2fece5 100644 --- a/drivers/base/sys.c +++ b/drivers/base/sys.c @@ -21,6 +21,7 @@ #include <linux/slab.h> #include <linux/string.h> #include <linux/pm.h> +#include <asm/semaphore.h> extern struct subsystem devices_subsys; diff --git a/drivers/block/Kconfig.iosched b/drivers/block/Kconfig.iosched index 6070a480600b..5b90d2fa63b8 100644 --- a/drivers/block/Kconfig.iosched +++ b/drivers/block/Kconfig.iosched @@ -38,4 +38,32 @@ config IOSCHED_CFQ among all processes in the system. It should provide a fair working environment, suitable for desktop systems. +choice + prompt "Default I/O scheduler" + default DEFAULT_AS + help + Select the I/O scheduler which will be used by default for all + block devices. + + config DEFAULT_AS + bool "Anticipatory" if IOSCHED_AS + + config DEFAULT_DEADLINE + bool "Deadline" if IOSCHED_DEADLINE + + config DEFAULT_CFQ + bool "CFQ" if IOSCHED_CFQ + + config DEFAULT_NOOP + bool "No-op" + +endchoice + +config DEFAULT_IOSCHED + string + default "anticipatory" if DEFAULT_AS + default "deadline" if DEFAULT_DEADLINE + default "cfq" if DEFAULT_CFQ + default "noop" if DEFAULT_NOOP + endmenu diff --git a/drivers/block/aoe/aoe.h b/drivers/block/aoe/aoe.h index 0e9e586e9ba3..881c48d941b7 100644 --- a/drivers/block/aoe/aoe.h +++ b/drivers/block/aoe/aoe.h @@ -1,5 +1,5 @@ /* Copyright (c) 2004 Coraid, Inc. See COPYING for GPL terms. */ -#define VERSION "12" +#define VERSION "14" #define AOE_MAJOR 152 #define DEVICE_NAME "aoe" diff --git a/drivers/block/aoe/aoechr.c b/drivers/block/aoe/aoechr.c index 45a243096187..41ae0ede619a 100644 --- a/drivers/block/aoe/aoechr.c +++ b/drivers/block/aoe/aoechr.c @@ -224,7 +224,7 @@ aoechr_init(void) return PTR_ERR(aoe_class); } for (i = 0; i < ARRAY_SIZE(chardevs); ++i) - class_device_create(aoe_class, + class_device_create(aoe_class, NULL, MKDEV(AOE_MAJOR, chardevs[i].minor), NULL, chardevs[i].name); diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index b5be4b7d7b5b..5c9c7c1a3d4c 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c @@ -8,6 +8,7 @@ #include <linux/blkdev.h> #include <linux/skbuff.h> #include <linux/netdevice.h> +#include <asm/unaligned.h> #include "aoe.h" #define TIMERTICK (HZ / 10) @@ -311,16 +312,16 @@ ataid_complete(struct aoedev *d, unsigned char *id) u16 n; /* word 83: command set supported */ - n = le16_to_cpup((__le16 *) &id[83<<1]); + n = le16_to_cpu(get_unaligned((__le16 *) &id[83<<1])); /* word 86: command set/feature enabled */ - n |= le16_to_cpup((__le16 *) &id[86<<1]); + n |= le16_to_cpu(get_unaligned((__le16 *) &id[86<<1])); if (n & (1<<10)) { /* bit 10: LBA 48 */ d->flags |= DEVFL_EXT; /* word 100: number lba48 sectors */ - ssize = le64_to_cpup((__le64 *) &id[100<<1]); + ssize = le64_to_cpu(get_unaligned((__le64 *) &id[100<<1])); /* set as in ide-disk.c:init_idedisk_capacity */ d->geo.cylinders = ssize; @@ -331,12 +332,12 @@ ataid_complete(struct aoedev *d, unsigned char *id) d->flags &= ~DEVFL_EXT; /* number lba28 sectors */ - ssize = le32_to_cpup((__le32 *) &id[60<<1]); + ssize = le32_to_cpu(get_unaligned((__le32 *) &id[60<<1])); /* NOTE: obsolete in ATA 6 */ - d->geo.cylinders = le16_to_cpup((__le16 *) &id[54<<1]); - d->geo.heads = le16_to_cpup((__le16 *) &id[55<<1]); - d->geo.sectors = le16_to_cpup((__le16 *) &id[56<<1]); + d->geo.cylinders = le16_to_cpu(get_unaligned((__le16 *) &id[54<<1])); + d->geo.heads = le16_to_cpu(get_unaligned((__le16 *) &id[55<<1])); + d->geo.sectors = le16_to_cpu(get_unaligned((__le16 *) &id[56<<1])); } d->ssize = ssize; d->geo.start = 0; diff --git a/drivers/block/as-iosched.c b/drivers/block/as-iosched.c index 95c0a3690b0f..c6744ff38294 100644 --- a/drivers/block/as-iosched.c +++ b/drivers/block/as-iosched.c @@ -98,7 +98,6 @@ struct as_data { struct as_rq *next_arq[2]; /* next in sort order */ sector_t last_sector[2]; /* last REQ_SYNC & REQ_ASYNC sectors */ - struct list_head *dispatch; /* driver dispatch queue */ struct list_head *hash; /* request hash */ unsigned long exit_prob; /* probability a task will exit while @@ -239,6 +238,25 @@ static struct io_context *as_get_io_context(void) return ioc; } +static void as_put_io_context(struct as_rq *arq) +{ + struct as_io_context *aic; + + if (unlikely(!arq->io_context)) + return; + + aic = arq->io_context->aic; + + if (arq->is_sync == REQ_SYNC && aic) { + spin_lock(&aic->lock); + set_bit(AS_TASK_IORUNNING, &aic->state); + aic->last_end_request = jiffies; + spin_unlock(&aic->lock); + } + + put_io_context(arq->io_context); +} + /* * the back merge hash support functions */ @@ -261,14 +279,6 @@ static inline void as_del_arq_hash(struct as_rq *arq) __as_del_arq_hash(arq); } -static void as_remove_merge_hints(request_queue_t *q, struct as_rq *arq) -{ - as_del_arq_hash(arq); - - if (q->last_merge == arq->request) - q->last_merge = NULL; -} - static void as_add_arq_hash(struct as_data *ad, struct as_rq *arq) { struct request *rq = arq->request; @@ -312,7 +322,7 @@ static struct request *as_find_arq_hash(struct as_data *ad, sector_t offset) BUG_ON(!arq->on_hash); if (!rq_mergeable(__rq)) { - as_remove_merge_hints(ad->q, arq); + as_del_arq_hash(arq); continue; } @@ -950,23 +960,12 @@ static void as_completed_request(request_queue_t *q, struct request *rq) WARN_ON(!list_empty(&rq->queuelist)); - if (arq->state == AS_RQ_PRESCHED) { - WARN_ON(arq->io_context); - goto out; - } - - if (arq->state == AS_RQ_MERGED) - goto out_ioc; - if (arq->state != AS_RQ_REMOVED) { printk("arq->state %d\n", arq->state); WARN_ON(1); goto out; } - if (!blk_fs_request(rq)) - goto out; - if (ad->changed_batch && ad->nr_dispatched == 1) { kblockd_schedule_work(&ad->antic_work); ad->changed_batch = 0; @@ -1001,21 +1000,7 @@ static void as_completed_request(request_queue_t *q, struct request *rq) } } -out_ioc: - if (!arq->io_context) - goto out; - - if (arq->is_sync == REQ_SYNC) { - struct as_io_context *aic = arq->io_context->aic; - if (aic) { - spin_lock(&aic->lock); - set_bit(AS_TASK_IORUNNING, &aic->state); - aic->last_end_request = jiffies; - spin_unlock(&aic->lock); - } - } - - put_io_context(arq->io_context); + as_put_io_context(arq); out: arq->state = AS_RQ_POSTSCHED; } @@ -1047,73 +1032,11 @@ static void as_remove_queued_request(request_queue_t *q, struct request *rq) ad->next_arq[data_dir] = as_find_next_arq(ad, arq); list_del_init(&arq->fifo); - as_remove_merge_hints(q, arq); + as_del_arq_hash(arq); as_del_arq_rb(ad, arq); } /* - * as_remove_dispatched_request is called to remove a request which has gone - * to the dispatch list. - */ -static void as_remove_dispatched_request(request_queue_t *q, struct request *rq) -{ - struct as_rq *arq = RQ_DATA(rq); - struct as_io_context *aic; - - if (!arq) { - WARN_ON(1); - return; - } - - WARN_ON(arq->state != AS_RQ_DISPATCHED); - WARN_ON(ON_RB(&arq->rb_node)); - if (arq->io_context && arq->io_context->aic) { - aic = arq->io_context->aic; - if (aic) { - WARN_ON(!atomic_read(&aic->nr_dispatched)); - atomic_dec(&aic->nr_dispatched); - } - } -} - -/* - * as_remove_request is called when a driver has finished with a request. - * This should be only called for dispatched requests, but for some reason - * a POWER4 box running hwscan it does not. - */ -static void as_remove_request(request_queue_t *q, struct request *rq) -{ - struct as_rq *arq = RQ_DATA(rq); - - if (unlikely(arq->state == AS_RQ_NEW)) - goto out; - - if (ON_RB(&arq->rb_node)) { - if (arq->state != AS_RQ_QUEUED) { - printk("arq->state %d\n", arq->state); - WARN_ON(1); - goto out; - } - /* - * We'll lose the aliased request(s) here. I don't think this - * will ever happen, but if it does, hopefully someone will - * report it. - */ - WARN_ON(!list_empty(&rq->queuelist)); - as_remove_queued_request(q, rq); - } else { - if (arq->state != AS_RQ_DISPATCHED) { - printk("arq->state %d\n", arq->state); - WARN_ON(1); - goto out; - } - as_remove_dispatched_request(q, rq); - } -out: - arq->state = AS_RQ_REMOVED; -} - -/* * as_fifo_expired returns 0 if there are no expired reads on the fifo, * 1 otherwise. It is ratelimited so that we only perform the check once per * `fifo_expire' interval. Otherwise a large number of expired requests @@ -1165,7 +1088,6 @@ static inline int as_batch_expired(struct as_data *ad) static void as_move_to_dispatch(struct as_data *ad, struct as_rq *arq) { struct request *rq = arq->request; - struct list_head *insert; const int data_dir = arq->is_sync; BUG_ON(!ON_RB(&arq->rb_node)); @@ -1198,13 +1120,13 @@ static void as_move_to_dispatch(struct as_data *ad, struct as_rq *arq) /* * take it off the sort and fifo list, add to dispatch queue */ - insert = ad->dispatch->prev; - while (!list_empty(&rq->queuelist)) { struct request *__rq = list_entry_rq(rq->queuelist.next); struct as_rq *__arq = RQ_DATA(__rq); - list_move_tail(&__rq->queuelist, ad->dispatch); + list_del(&__rq->queuelist); + + elv_dispatch_add_tail(ad->q, __rq); if (__arq->io_context && __arq->io_context->aic) atomic_inc(&__arq->io_context->aic->nr_dispatched); @@ -1218,7 +1140,8 @@ static void as_move_to_dispatch(struct as_data *ad, struct as_rq *arq) as_remove_queued_request(ad->q, rq); WARN_ON(arq->state != AS_RQ_QUEUED); - list_add(&rq->queuelist, insert); + elv_dispatch_sort(ad->q, rq); + arq->state = AS_RQ_DISPATCHED; if (arq->io_context && arq->io_context->aic) atomic_inc(&arq->io_context->aic->nr_dispatched); @@ -1230,12 +1153,42 @@ static void as_move_to_dispatch(struct as_data *ad, struct as_rq *arq) * read/write expire, batch expire, etc, and moves it to the dispatch * queue. Returns 1 if a request was found, 0 otherwise. */ -static int as_dispatch_request(struct as_data *ad) +static int as_dispatch_request(request_queue_t *q, int force) { + struct as_data *ad = q->elevator->elevator_data; struct as_rq *arq; const int reads = !list_empty(&ad->fifo_list[REQ_SYNC]); const int writes = !list_empty(&ad->fifo_list[REQ_ASYNC]); + if (unlikely(force)) { + /* + * Forced dispatch, accounting is useless. Reset + * accounting states and dump fifo_lists. Note that + * batch_data_dir is reset to REQ_SYNC to avoid + * screwing write batch accounting as write batch + * accounting occurs on W->R transition. + */ + int dispatched = 0; + + ad->batch_data_dir = REQ_SYNC; + ad->changed_batch = 0; + ad->new_batch = 0; + + while (ad->next_arq[REQ_SYNC]) { + as_move_to_dispatch(ad, ad->next_arq[REQ_SYNC]); + dispatched++; + } + ad->last_check_fifo[REQ_SYNC] = jiffies; + + while (ad->next_arq[REQ_ASYNC]) { + as_move_to_dispatch(ad, ad->next_arq[REQ_ASYNC]); + dispatched++; + } + ad->last_check_fifo[REQ_ASYNC] = jiffies; + + return dispatched; + } + /* Signal that the write batch was uncontended, so we can't time it */ if (ad->batch_data_dir == REQ_ASYNC && !reads) { if (ad->current_write_count == 0 || !writes) @@ -1359,20 +1312,6 @@ fifo_expired: return 1; } -static struct request *as_next_request(request_queue_t *q) -{ - struct as_data *ad = q->elevator->elevator_data; - struct request *rq = NULL; - - /* - * if there are still requests on the dispatch queue, grab the first - */ - if (!list_empty(ad->dispatch) || as_dispatch_request(ad)) - rq = list_entry_rq(ad->dispatch->next); - - return rq; -} - /* * Add arq to a list behind alias */ @@ -1404,17 +1343,26 @@ as_add_aliased_request(struct as_data *ad, struct as_rq *arq, struct as_rq *alia /* * Don't want to have to handle merges. */ - as_remove_merge_hints(ad->q, arq); + as_del_arq_hash(arq); + arq->request->flags |= REQ_NOMERGE; } /* * add arq to rbtree and fifo */ -static void as_add_request(struct as_data *ad, struct as_rq *arq) +static void as_add_request(request_queue_t *q, struct request *rq) { + struct as_data *ad = q->elevator->elevator_data; + struct as_rq *arq = RQ_DATA(rq); struct as_rq *alias; int data_dir; + if (arq->state != AS_RQ_PRESCHED) { + printk("arq->state: %d\n", arq->state); + WARN_ON(1); + } + arq->state = AS_RQ_NEW; + if (rq_data_dir(arq->request) == READ || current->flags&PF_SYNCWRITE) arq->is_sync = 1; @@ -1437,12 +1385,8 @@ static void as_add_request(struct as_data *ad, struct as_rq *arq) arq->expires = jiffies + ad->fifo_expire[data_dir]; list_add_tail(&arq->fifo, &ad->fifo_list[data_dir]); - if (rq_mergeable(arq->request)) { + if (rq_mergeable(arq->request)) as_add_arq_hash(ad, arq); - - if (!ad->q->last_merge) - ad->q->last_merge = arq->request; - } as_update_arq(ad, arq); /* keep state machine up to date */ } else { @@ -1463,96 +1407,24 @@ static void as_add_request(struct as_data *ad, struct as_rq *arq) arq->state = AS_RQ_QUEUED; } -static void as_deactivate_request(request_queue_t *q, struct request *rq) +static void as_activate_request(request_queue_t *q, struct request *rq) { - struct as_data *ad = q->elevator->elevator_data; struct as_rq *arq = RQ_DATA(rq); - if (arq) { - if (arq->state == AS_RQ_REMOVED) { - arq->state = AS_RQ_DISPATCHED; - if (arq->io_context && arq->io_context->aic) - atomic_inc(&arq->io_context->aic->nr_dispatched); - } - } else - WARN_ON(blk_fs_request(rq) - && (!(rq->flags & (REQ_HARDBARRIER|REQ_SOFTBARRIER))) ); - - /* Stop anticipating - let this request get through */ - as_antic_stop(ad); -} - -/* - * requeue the request. The request has not been completed, nor is it a - * new request, so don't touch accounting. - */ -static void as_requeue_request(request_queue_t *q, struct request *rq) -{ - as_deactivate_request(q, rq); - list_add(&rq->queuelist, &q->queue_head); -} - -/* - * Account a request that is inserted directly onto the dispatch queue. - * arq->io_context->aic->nr_dispatched should not need to be incremented - * because only new requests should come through here: requeues go through - * our explicit requeue handler. - */ -static void as_account_queued_request(struct as_data *ad, struct request *rq) -{ - if (blk_fs_request(rq)) { - struct as_rq *arq = RQ_DATA(rq); - arq->state = AS_RQ_DISPATCHED; - ad->nr_dispatched++; - } + WARN_ON(arq->state != AS_RQ_DISPATCHED); + arq->state = AS_RQ_REMOVED; + if (arq->io_context && arq->io_context->aic) + atomic_dec(&arq->io_context->aic->nr_dispatched); } -static void -as_insert_request(request_queue_t *q, struct request *rq, int where) +static void as_deactivate_request(request_queue_t *q, struct request *rq) { - struct as_data *ad = q->elevator->elevator_data; struct as_rq *arq = RQ_DATA(rq); - if (arq) { - if (arq->state != AS_RQ_PRESCHED) { - printk("arq->state: %d\n", arq->state); - WARN_ON(1); - } - arq->state = AS_RQ_NEW; - } - - /* barriers must flush the reorder queue */ - if (unlikely(rq->flags & (REQ_SOFTBARRIER | REQ_HARDBARRIER) - && where == ELEVATOR_INSERT_SORT)) { - WARN_ON(1); - where = ELEVATOR_INSERT_BACK; - } - - switch (where) { - case ELEVATOR_INSERT_BACK: - while (ad->next_arq[REQ_SYNC]) - as_move_to_dispatch(ad, ad->next_arq[REQ_SYNC]); - - while (ad->next_arq[REQ_ASYNC]) - as_move_to_dispatch(ad, ad->next_arq[REQ_ASYNC]); - - list_add_tail(&rq->queuelist, ad->dispatch); - as_account_queued_request(ad, rq); - as_antic_stop(ad); - break; - case ELEVATOR_INSERT_FRONT: - list_add(&rq->queuelist, ad->dispatch); - as_account_queued_request(ad, rq); - as_antic_stop(ad); - break; - case ELEVATOR_INSERT_SORT: - BUG_ON(!blk_fs_request(rq)); - as_add_request(ad, arq); - break; - default: - BUG(); - return; - } + WARN_ON(arq->state != AS_RQ_REMOVED); + arq->state = AS_RQ_DISPATCHED; + if (arq->io_context && arq->io_context->aic) + atomic_inc(&arq->io_context->aic->nr_dispatched); } /* @@ -1565,12 +1437,8 @@ static int as_queue_empty(request_queue_t *q) { struct as_data *ad = q->elevator->elevator_data; - if (!list_empty(&ad->fifo_list[REQ_ASYNC]) - || !list_empty(&ad->fifo_list[REQ_SYNC]) - || !list_empty(ad->dispatch)) - return 0; - - return 1; + return list_empty(&ad->fifo_list[REQ_ASYNC]) + && list_empty(&ad->fifo_list[REQ_SYNC]); } static struct request * @@ -1608,15 +1476,6 @@ as_merge(request_queue_t *q, struct request **req, struct bio *bio) int ret; /* - * try last_merge to avoid going to hash - */ - ret = elv_try_last_merge(q, bio); - if (ret != ELEVATOR_NO_MERGE) { - __rq = q->last_merge; - goto out_insert; - } - - /* * see if the merge hash can satisfy a back merge */ __rq = as_find_arq_hash(ad, bio->bi_sector); @@ -1644,9 +1503,6 @@ as_merge(request_queue_t *q, struct request **req, struct bio *bio) return ELEVATOR_NO_MERGE; out: - if (rq_mergeable(__rq)) - q->last_merge = __rq; -out_insert: if (ret) { if (rq_mergeable(__rq)) as_hot_arq_hash(ad, RQ_DATA(__rq)); @@ -1693,9 +1549,6 @@ static void as_merged_request(request_queue_t *q, struct request *req) * behind the disk head. We currently don't bother adjusting. */ } - - if (arq->on_hash) - q->last_merge = req; } static void @@ -1763,6 +1616,7 @@ as_merged_requests(request_queue_t *q, struct request *req, * kill knowledge of next, this one is a goner */ as_remove_queued_request(q, next); + as_put_io_context(anext); anext->state = AS_RQ_MERGED; } @@ -1782,7 +1636,7 @@ static void as_work_handler(void *data) unsigned long flags; spin_lock_irqsave(q->queue_lock, flags); - if (as_next_request(q)) + if (!as_queue_empty(q)) q->request_fn(q); spin_unlock_irqrestore(q->queue_lock, flags); } @@ -1797,7 +1651,9 @@ static void as_put_request(request_queue_t *q, struct request *rq) return; } - if (arq->state != AS_RQ_POSTSCHED && arq->state != AS_RQ_PRESCHED) { + if (unlikely(arq->state != AS_RQ_POSTSCHED && + arq->state != AS_RQ_PRESCHED && + arq->state != AS_RQ_MERGED)) { printk("arq->state %d\n", arq->state); WARN_ON(1); } @@ -1807,7 +1663,7 @@ static void as_put_request(request_queue_t *q, struct request *rq) } static int as_set_request(request_queue_t *q, struct request *rq, - struct bio *bio, int gfp_mask) + struct bio *bio, gfp_t gfp_mask) { struct as_data *ad = q->elevator->elevator_data; struct as_rq *arq = mempool_alloc(ad->arq_pool, gfp_mask); @@ -1907,7 +1763,6 @@ static int as_init_queue(request_queue_t *q, elevator_t *e) INIT_LIST_HEAD(&ad->fifo_list[REQ_ASYNC]); ad->sort_list[REQ_SYNC] = RB_ROOT; ad->sort_list[REQ_ASYNC] = RB_ROOT; - ad->dispatch = &q->queue_head; ad->fifo_expire[REQ_SYNC] = default_read_expire; ad->fifo_expire[REQ_ASYNC] = default_write_expire; ad->antic_expire = default_antic_expire; @@ -2072,10 +1927,9 @@ static struct elevator_type iosched_as = { .elevator_merge_fn = as_merge, .elevator_merged_fn = as_merged_request, .elevator_merge_req_fn = as_merged_requests, - .elevator_next_req_fn = as_next_request, - .elevator_add_req_fn = as_insert_request, - .elevator_remove_req_fn = as_remove_request, - .elevator_requeue_req_fn = as_requeue_request, + .elevator_dispatch_fn = as_dispatch_request, + .elevator_add_req_fn = as_add_request, + .elevator_activate_req_fn = as_activate_request, .elevator_deactivate_req_fn = as_deactivate_request, .elevator_queue_empty_fn = as_queue_empty, .elevator_completed_req_fn = as_completed_request, @@ -2119,8 +1973,8 @@ static int __init as_init(void) static void __exit as_exit(void) { - kmem_cache_destroy(arq_pool); elv_unregister(&iosched_as); + kmem_cache_destroy(arq_pool); } module_init(as_init); diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c index e183a3ef7839..ec27976a57da 100644 --- a/drivers/block/cciss_scsi.c +++ b/drivers/block/cciss_scsi.c @@ -28,13 +28,17 @@ through the array controller. Note in particular, neither physical nor logical disks are presented through the scsi layer. */ +#include <linux/timer.h> +#include <linux/completion.h> +#include <linux/slab.h> +#include <linux/string.h> + +#include <asm/atomic.h> + #include <scsi/scsi.h> #include <scsi/scsi_cmnd.h> #include <scsi/scsi_device.h> #include <scsi/scsi_host.h> -#include <asm/atomic.h> -#include <linux/timer.h> -#include <linux/completion.h> #include "cciss_scsi.h" diff --git a/drivers/block/cfq-iosched.c b/drivers/block/cfq-iosched.c index cd056e7e64ec..5281f8e70510 100644 --- a/drivers/block/cfq-iosched.c +++ b/drivers/block/cfq-iosched.c @@ -84,7 +84,6 @@ static int cfq_max_depth = 2; (node)->rb_left = NULL; \ } while (0) #define RB_CLEAR_ROOT(root) ((root)->rb_node = NULL) -#define ON_RB(node) ((node)->rb_color != RB_NONE) #define rb_entry_crq(node) rb_entry((node), struct cfq_rq, rb_node) #define rq_rb_key(rq) (rq)->sector @@ -271,10 +270,7 @@ CFQ_CFQQ_FNS(expired); #undef CFQ_CFQQ_FNS enum cfq_rq_state_flags { - CFQ_CRQ_FLAG_in_flight = 0, - CFQ_CRQ_FLAG_in_driver, - CFQ_CRQ_FLAG_is_sync, - CFQ_CRQ_FLAG_requeued, + CFQ_CRQ_FLAG_is_sync = 0, }; #define CFQ_CRQ_FNS(name) \ @@ -291,14 +287,11 @@ static inline int cfq_crq_##name(const struct cfq_rq *crq) \ return (crq->crq_flags & (1 << CFQ_CRQ_FLAG_##name)) != 0; \ } -CFQ_CRQ_FNS(in_flight); -CFQ_CRQ_FNS(in_driver); CFQ_CRQ_FNS(is_sync); -CFQ_CRQ_FNS(requeued); #undef CFQ_CRQ_FNS static struct cfq_queue *cfq_find_cfq_hash(struct cfq_data *, unsigned int, unsigned short); -static void cfq_dispatch_sort(request_queue_t *, struct cfq_rq *); +static void cfq_dispatch_insert(request_queue_t *, struct cfq_rq *); static void cfq_put_cfqd(struct cfq_data *cfqd); #define process_sync(tsk) ((tsk)->flags & PF_SYNCWRITE) @@ -311,14 +304,6 @@ static inline void cfq_del_crq_hash(struct cfq_rq *crq) hlist_del_init(&crq->hash); } -static void cfq_remove_merge_hints(request_queue_t *q, struct cfq_rq *crq) -{ - cfq_del_crq_hash(crq); - - if (q->last_merge == crq->request) - q->last_merge = NULL; -} - static inline void cfq_add_crq_hash(struct cfq_data *cfqd, struct cfq_rq *crq) { const int hash_idx = CFQ_MHASH_FN(rq_hash_key(crq->request)); @@ -347,18 +332,13 @@ static struct request *cfq_find_rq_hash(struct cfq_data *cfqd, sector_t offset) return NULL; } -static inline int cfq_pending_requests(struct cfq_data *cfqd) -{ - return !list_empty(&cfqd->queue->queue_head) || cfqd->busy_queues; -} - /* * scheduler run of queue, if there are requests pending and no one in the * driver that will restart queueing */ static inline void cfq_schedule_dispatch(struct cfq_data *cfqd) { - if (!cfqd->rq_in_driver && cfq_pending_requests(cfqd)) + if (!cfqd->rq_in_driver && cfqd->busy_queues) kblockd_schedule_work(&cfqd->unplug_work); } @@ -366,7 +346,7 @@ static int cfq_queue_empty(request_queue_t *q) { struct cfq_data *cfqd = q->elevator->elevator_data; - return !cfq_pending_requests(cfqd); + return !cfqd->busy_queues; } /* @@ -386,11 +366,6 @@ cfq_choose_req(struct cfq_data *cfqd, struct cfq_rq *crq1, struct cfq_rq *crq2) if (crq2 == NULL) return crq1; - if (cfq_crq_requeued(crq1) && !cfq_crq_requeued(crq2)) - return crq1; - else if (cfq_crq_requeued(crq2) && !cfq_crq_requeued(crq1)) - return crq2; - if (cfq_crq_is_sync(crq1) && !cfq_crq_is_sync(crq2)) return crq1; else if (cfq_crq_is_sync(crq2) && !cfq_crq_is_sync(crq1)) @@ -461,10 +436,7 @@ cfq_find_next_crq(struct cfq_data *cfqd, struct cfq_queue *cfqq, struct cfq_rq *crq_next = NULL, *crq_prev = NULL; struct rb_node *rbnext, *rbprev; - rbnext = NULL; - if (ON_RB(&last->rb_node)) - rbnext = rb_next(&last->rb_node); - if (!rbnext) { + if (!(rbnext = rb_next(&last->rb_node))) { rbnext = rb_first(&cfqq->sort_list); if (rbnext == &last->rb_node) rbnext = NULL; @@ -545,13 +517,13 @@ static void cfq_resort_rr_list(struct cfq_queue *cfqq, int preempted) * the pending list according to last request service */ static inline void -cfq_add_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq, int requeue) +cfq_add_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq) { BUG_ON(cfq_cfqq_on_rr(cfqq)); cfq_mark_cfqq_on_rr(cfqq); cfqd->busy_queues++; - cfq_resort_rr_list(cfqq, requeue); + cfq_resort_rr_list(cfqq, 0); } static inline void @@ -571,22 +543,19 @@ cfq_del_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq) static inline void cfq_del_crq_rb(struct cfq_rq *crq) { struct cfq_queue *cfqq = crq->cfq_queue; + struct cfq_data *cfqd = cfqq->cfqd; + const int sync = cfq_crq_is_sync(crq); - if (ON_RB(&crq->rb_node)) { - struct cfq_data *cfqd = cfqq->cfqd; - const int sync = cfq_crq_is_sync(crq); - - BUG_ON(!cfqq->queued[sync]); - cfqq->queued[sync]--; + BUG_ON(!cfqq->queued[sync]); + cfqq->queued[sync]--; - cfq_update_next_crq(crq); + cfq_update_next_crq(crq); - rb_erase(&crq->rb_node, &cfqq->sort_list); - RB_CLEAR_COLOR(&crq->rb_node); + rb_erase(&crq->rb_node, &cfqq->sort_list); + RB_CLEAR_COLOR(&crq->rb_node); - if (cfq_cfqq_on_rr(cfqq) && RB_EMPTY(&cfqq->sort_list)) - cfq_del_cfqq_rr(cfqd, cfqq); - } + if (cfq_cfqq_on_rr(cfqq) && RB_EMPTY(&cfqq->sort_list)) + cfq_del_cfqq_rr(cfqd, cfqq); } static struct cfq_rq * @@ -627,12 +596,12 @@ static void cfq_add_crq_rb(struct cfq_rq *crq) * if that happens, put the alias on the dispatch list */ while ((__alias = __cfq_add_crq_rb(crq)) != NULL) - cfq_dispatch_sort(cfqd->queue, __alias); + cfq_dispatch_insert(cfqd->queue, __alias); rb_insert_color(&crq->rb_node, &cfqq->sort_list); if (!cfq_cfqq_on_rr(cfqq)) - cfq_add_cfqq_rr(cfqd, cfqq, cfq_crq_requeued(crq)); + cfq_add_cfqq_rr(cfqd, cfqq); /* * check if this request is a better next-serve candidate @@ -643,10 +612,8 @@ static void cfq_add_crq_rb(struct cfq_rq *crq) static inline void cfq_reposition_crq_rb(struct cfq_queue *cfqq, struct cfq_rq *crq) { - if (ON_RB(&crq->rb_node)) { - rb_erase(&crq->rb_node, &cfqq->sort_list); - cfqq->queued[cfq_crq_is_sync(crq)]--; - } + rb_erase(&crq->rb_node, &cfqq->sort_list); + cfqq->queued[cfq_crq_is_sync(crq)]--; cfq_add_crq_rb(crq); } @@ -676,49 +643,28 @@ out: return NULL; } -static void cfq_deactivate_request(request_queue_t *q, struct request *rq) +static void cfq_activate_request(request_queue_t *q, struct request *rq) { struct cfq_data *cfqd = q->elevator->elevator_data; - struct cfq_rq *crq = RQ_DATA(rq); - - if (crq) { - struct cfq_queue *cfqq = crq->cfq_queue; - if (cfq_crq_in_driver(crq)) { - cfq_clear_crq_in_driver(crq); - WARN_ON(!cfqd->rq_in_driver); - cfqd->rq_in_driver--; - } - if (cfq_crq_in_flight(crq)) { - const int sync = cfq_crq_is_sync(crq); - - cfq_clear_crq_in_flight(crq); - WARN_ON(!cfqq->on_dispatch[sync]); - cfqq->on_dispatch[sync]--; - } - cfq_mark_crq_requeued(crq); - } + cfqd->rq_in_driver++; } -/* - * make sure the service time gets corrected on reissue of this request - */ -static void cfq_requeue_request(request_queue_t *q, struct request *rq) +static void cfq_deactivate_request(request_queue_t *q, struct request *rq) { - cfq_deactivate_request(q, rq); - list_add(&rq->queuelist, &q->queue_head); + struct cfq_data *cfqd = q->elevator->elevator_data; + + WARN_ON(!cfqd->rq_in_driver); + cfqd->rq_in_driver--; } -static void cfq_remove_request(request_queue_t *q, struct request *rq) +static void cfq_remove_request(struct request *rq) { struct cfq_rq *crq = RQ_DATA(rq); - if (crq) { - list_del_init(&rq->queuelist); - cfq_del_crq_rb(crq); - cfq_remove_merge_hints(q, crq); - - } + list_del_init(&rq->queuelist); + cfq_del_crq_rb(crq); + cfq_del_crq_hash(crq); } static int @@ -728,12 +674,6 @@ cfq_merge(request_queue_t *q, struct request **req, struct bio *bio) struct request *__rq; int ret; - ret = elv_try_last_merge(q, bio); - if (ret != ELEVATOR_NO_MERGE) { - __rq = q->last_merge; - goto out_insert; - } - __rq = cfq_find_rq_hash(cfqd, bio->bi_sector); if (__rq && elv_rq_merge_ok(__rq, bio)) { ret = ELEVATOR_BACK_MERGE; @@ -748,8 +688,6 @@ cfq_merge(request_queue_t *q, struct request **req, struct bio *bio) return ELEVATOR_NO_MERGE; out: - q->last_merge = __rq; -out_insert: *req = __rq; return ret; } @@ -762,14 +700,12 @@ static void cfq_merged_request(request_queue_t *q, struct request *req) cfq_del_crq_hash(crq); cfq_add_crq_hash(cfqd, crq); - if (ON_RB(&crq->rb_node) && (rq_rb_key(req) != crq->rb_key)) { + if (rq_rb_key(req) != crq->rb_key) { struct cfq_queue *cfqq = crq->cfq_queue; cfq_update_next_crq(crq); cfq_reposition_crq_rb(cfqq, crq); } - - q->last_merge = req; } static void @@ -785,7 +721,7 @@ cfq_merged_requests(request_queue_t *q, struct request *rq, time_before(next->start_time, rq->start_time)) list_move(&rq->queuelist, &next->queuelist); - cfq_remove_request(q, next); + cfq_remove_request(next); } static inline void @@ -992,53 +928,15 @@ static int cfq_arm_slice_timer(struct cfq_data *cfqd, struct cfq_queue *cfqq) return 1; } -/* - * we dispatch cfqd->cfq_quantum requests in total from the rr_list queues, - * this function sector sorts the selected request to minimize seeks. we start - * at cfqd->last_sector, not 0. - */ -static void cfq_dispatch_sort(request_queue_t *q, struct cfq_rq *crq) +static void cfq_dispatch_insert(request_queue_t *q, struct cfq_rq *crq) { struct cfq_data *cfqd = q->elevator->elevator_data; struct cfq_queue *cfqq = crq->cfq_queue; - struct list_head *head = &q->queue_head, *entry = head; - struct request *__rq; - sector_t last; - - list_del(&crq->request->queuelist); - - last = cfqd->last_sector; - list_for_each_entry_reverse(__rq, head, queuelist) { - struct cfq_rq *__crq = RQ_DATA(__rq); - - if (blk_barrier_rq(__rq)) - break; - if (!blk_fs_request(__rq)) - break; - if (cfq_crq_requeued(__crq)) - break; - - if (__rq->sector <= crq->request->sector) - break; - if (__rq->sector > last && crq->request->sector < last) { - last = crq->request->sector + crq->request->nr_sectors; - break; - } - entry = &__rq->queuelist; - } - - cfqd->last_sector = last; cfqq->next_crq = cfq_find_next_crq(cfqd, cfqq, crq); - - cfq_del_crq_rb(crq); - cfq_remove_merge_hints(q, crq); - - cfq_mark_crq_in_flight(crq); - cfq_clear_crq_requeued(crq); - + cfq_remove_request(crq->request); cfqq->on_dispatch[cfq_crq_is_sync(crq)]++; - list_add_tail(&crq->request->queuelist, entry); + elv_dispatch_sort(q, crq->request); } /* @@ -1159,7 +1057,7 @@ __cfq_dispatch_requests(struct cfq_data *cfqd, struct cfq_queue *cfqq, /* * finally, insert request into driver dispatch list */ - cfq_dispatch_sort(cfqd->queue, crq); + cfq_dispatch_insert(cfqd->queue, crq); cfqd->dispatch_slice++; dispatched++; @@ -1194,7 +1092,7 @@ __cfq_dispatch_requests(struct cfq_data *cfqd, struct cfq_queue *cfqq, } static int -cfq_dispatch_requests(request_queue_t *q, int max_dispatch, int force) +cfq_dispatch_requests(request_queue_t *q, int force) { struct cfq_data *cfqd = q->elevator->elevator_data; struct cfq_queue *cfqq; @@ -1204,12 +1102,25 @@ cfq_dispatch_requests(request_queue_t *q, int max_dispatch, int force) cfqq = cfq_select_queue(cfqd, force); if (cfqq) { + int max_dispatch; + + /* + * if idle window is disabled, allow queue buildup + */ + if (!cfq_cfqq_idle_window(cfqq) && + cfqd->rq_in_driver >= cfqd->cfq_max_depth) + return 0; + cfq_clear_cfqq_must_dispatch(cfqq); cfq_clear_cfqq_wait_request(cfqq); del_timer(&cfqd->idle_slice_timer); - if (cfq_class_idle(cfqq)) - max_dispatch = 1; + if (!force) { + max_dispatch = cfqd->cfq_quantum; + if (cfq_class_idle(cfqq)) + max_dispatch = 1; + } else + max_dispatch = INT_MAX; return __cfq_dispatch_requests(cfqd, cfqq, max_dispatch); } @@ -1217,93 +1128,6 @@ cfq_dispatch_requests(request_queue_t *q, int max_dispatch, int force) return 0; } -static inline void cfq_account_dispatch(struct cfq_rq *crq) -{ - struct cfq_queue *cfqq = crq->cfq_queue; - struct cfq_data *cfqd = cfqq->cfqd; - - if (unlikely(!blk_fs_request(crq->request))) - return; - - /* - * accounted bit is necessary since some drivers will call - * elv_next_request() many times for the same request (eg ide) - */ - if (cfq_crq_in_driver(crq)) - return; - - cfq_mark_crq_in_driver(crq); - cfqd->rq_in_driver++; -} - -static inline void -cfq_account_completion(struct cfq_queue *cfqq, struct cfq_rq *crq) -{ - struct cfq_data *cfqd = cfqq->cfqd; - unsigned long now; - - if (!cfq_crq_in_driver(crq)) - return; - - now = jiffies; - - WARN_ON(!cfqd->rq_in_driver); - cfqd->rq_in_driver--; - - if (!cfq_class_idle(cfqq)) - cfqd->last_end_request = now; - - if (!cfq_cfqq_dispatched(cfqq)) { - if (cfq_cfqq_on_rr(cfqq)) { - cfqq->service_last = now; - cfq_resort_rr_list(cfqq, 0); - } - if (cfq_cfqq_expired(cfqq)) { - __cfq_slice_expired(cfqd, cfqq, 0); - cfq_schedule_dispatch(cfqd); - } - } - - if (cfq_crq_is_sync(crq)) - crq->io_context->last_end_request = now; -} - -static struct request *cfq_next_request(request_queue_t *q) -{ - struct cfq_data *cfqd = q->elevator->elevator_data; - struct request *rq; - - if (!list_empty(&q->queue_head)) { - struct cfq_rq *crq; -dispatch: - rq = list_entry_rq(q->queue_head.next); - - crq = RQ_DATA(rq); - if (crq) { - struct cfq_queue *cfqq = crq->cfq_queue; - - /* - * if idle window is disabled, allow queue buildup - */ - if (!cfq_crq_in_driver(crq) && - !cfq_cfqq_idle_window(cfqq) && - !blk_barrier_rq(rq) && - cfqd->rq_in_driver >= cfqd->cfq_max_depth) - return NULL; - - cfq_remove_merge_hints(q, crq); - cfq_account_dispatch(crq); - } - - return rq; - } - - if (cfq_dispatch_requests(q, cfqd->cfq_quantum, 0)) - goto dispatch; - - return NULL; -} - /* * task holds one reference to the queue, dropped when task exits. each crq * in-flight on this queue also holds a reference, dropped when crq is freed. @@ -1422,7 +1246,7 @@ static void cfq_exit_io_context(struct cfq_io_context *cic) } static struct cfq_io_context * -cfq_alloc_io_context(struct cfq_data *cfqd, int gfp_mask) +cfq_alloc_io_context(struct cfq_data *cfqd, gfp_t gfp_mask) { struct cfq_io_context *cic = kmem_cache_alloc(cfq_ioc_pool, gfp_mask); @@ -1517,7 +1341,7 @@ static int cfq_ioc_set_ioprio(struct io_context *ioc, unsigned int ioprio) static struct cfq_queue * cfq_get_queue(struct cfq_data *cfqd, unsigned int key, unsigned short ioprio, - int gfp_mask) + gfp_t gfp_mask) { const int hashval = hash_long(key, CFQ_QHASH_SHIFT); struct cfq_queue *cfqq, *new_cfqq = NULL; @@ -1578,7 +1402,7 @@ out: * cfqq, so we don't need to worry about it disappearing */ static struct cfq_io_context * -cfq_get_io_context(struct cfq_data *cfqd, pid_t pid, int gfp_mask) +cfq_get_io_context(struct cfq_data *cfqd, pid_t pid, gfp_t gfp_mask) { struct io_context *ioc = NULL; struct cfq_io_context *cic; @@ -1816,8 +1640,9 @@ cfq_crq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq, } } -static void cfq_enqueue(struct cfq_data *cfqd, struct request *rq) +static void cfq_insert_request(request_queue_t *q, struct request *rq) { + struct cfq_data *cfqd = q->elevator->elevator_data; struct cfq_rq *crq = RQ_DATA(rq); struct cfq_queue *cfqq = crq->cfq_queue; @@ -1827,66 +1652,43 @@ static void cfq_enqueue(struct cfq_data *cfqd, struct request *rq) list_add_tail(&rq->queuelist, &cfqq->fifo); - if (rq_mergeable(rq)) { + if (rq_mergeable(rq)) cfq_add_crq_hash(cfqd, crq); - if (!cfqd->queue->last_merge) - cfqd->queue->last_merge = rq; - } - cfq_crq_enqueued(cfqd, cfqq, crq); } -static void -cfq_insert_request(request_queue_t *q, struct request *rq, int where) -{ - struct cfq_data *cfqd = q->elevator->elevator_data; - - switch (where) { - case ELEVATOR_INSERT_BACK: - while (cfq_dispatch_requests(q, INT_MAX, 1)) - ; - list_add_tail(&rq->queuelist, &q->queue_head); - /* - * If we were idling with pending requests on - * inactive cfqqs, force dispatching will - * remove the idle timer and the queue won't - * be kicked by __make_request() afterward. - * Kick it here. - */ - cfq_schedule_dispatch(cfqd); - break; - case ELEVATOR_INSERT_FRONT: - list_add(&rq->queuelist, &q->queue_head); - break; - case ELEVATOR_INSERT_SORT: - BUG_ON(!blk_fs_request(rq)); - cfq_enqueue(cfqd, rq); - break; - default: - printk("%s: bad insert point %d\n", __FUNCTION__,where); - return; - } -} - static void cfq_completed_request(request_queue_t *q, struct request *rq) { struct cfq_rq *crq = RQ_DATA(rq); - struct cfq_queue *cfqq; + struct cfq_queue *cfqq = crq->cfq_queue; + struct cfq_data *cfqd = cfqq->cfqd; + const int sync = cfq_crq_is_sync(crq); + unsigned long now; - if (unlikely(!blk_fs_request(rq))) - return; + now = jiffies; - cfqq = crq->cfq_queue; + WARN_ON(!cfqd->rq_in_driver); + WARN_ON(!cfqq->on_dispatch[sync]); + cfqd->rq_in_driver--; + cfqq->on_dispatch[sync]--; - if (cfq_crq_in_flight(crq)) { - const int sync = cfq_crq_is_sync(crq); + if (!cfq_class_idle(cfqq)) + cfqd->last_end_request = now; - WARN_ON(!cfqq->on_dispatch[sync]); - cfqq->on_dispatch[sync]--; + if (!cfq_cfqq_dispatched(cfqq)) { + if (cfq_cfqq_on_rr(cfqq)) { + cfqq->service_last = now; + cfq_resort_rr_list(cfqq, 0); + } + if (cfq_cfqq_expired(cfqq)) { + __cfq_slice_expired(cfqd, cfqq, 0); + cfq_schedule_dispatch(cfqd); + } } - cfq_account_completion(cfqq, crq); + if (cfq_crq_is_sync(crq)) + crq->io_context->last_end_request = now; } static struct request * @@ -2075,7 +1877,7 @@ static void cfq_put_request(request_queue_t *q, struct request *rq) */ static int cfq_set_request(request_queue_t *q, struct request *rq, struct bio *bio, - int gfp_mask) + gfp_t gfp_mask) { struct cfq_data *cfqd = q->elevator->elevator_data; struct task_struct *tsk = current; @@ -2118,9 +1920,6 @@ cfq_set_request(request_queue_t *q, struct request *rq, struct bio *bio, INIT_HLIST_NODE(&crq->hash); crq->cfq_queue = cfqq; crq->io_context = cic; - cfq_clear_crq_in_flight(crq); - cfq_clear_crq_in_driver(crq); - cfq_clear_crq_requeued(crq); if (rw == READ || process_sync(tsk)) cfq_mark_crq_is_sync(crq); @@ -2201,7 +2000,7 @@ static void cfq_idle_slice_timer(unsigned long data) * only expire and reinvoke request handler, if there are * other queues with pending requests */ - if (!cfq_pending_requests(cfqd)) { + if (!cfqd->busy_queues) { cfqd->idle_slice_timer.expires = min(now + cfqd->cfq_slice_idle, cfqq->slice_end); add_timer(&cfqd->idle_slice_timer); goto out_cont; @@ -2576,10 +2375,9 @@ static struct elevator_type iosched_cfq = { .elevator_merge_fn = cfq_merge, .elevator_merged_fn = cfq_merged_request, .elevator_merge_req_fn = cfq_merged_requests, - .elevator_next_req_fn = cfq_next_request, + .elevator_dispatch_fn = cfq_dispatch_requests, .elevator_add_req_fn = cfq_insert_request, - .elevator_remove_req_fn = cfq_remove_request, - .elevator_requeue_req_fn = cfq_requeue_request, + .elevator_activate_req_fn = cfq_activate_request, .elevator_deactivate_req_fn = cfq_deactivate_request, .elevator_queue_empty_fn = cfq_queue_empty, .elevator_completed_req_fn = cfq_completed_request, @@ -2620,28 +2418,8 @@ static int __init cfq_init(void) static void __exit cfq_exit(void) { - struct task_struct *g, *p; - unsigned long flags; - - read_lock_irqsave(&tasklist_lock, flags); - - /* - * iterate each process in the system, removing our io_context - */ - do_each_thread(g, p) { - struct io_context *ioc = p->io_context; - - if (ioc && ioc->cic) { - ioc->cic->exit(ioc->cic); - cfq_free_io_context(ioc->cic); - ioc->cic = NULL; - } - } while_each_thread(g, p); - - read_unlock_irqrestore(&tasklist_lock, flags); - - cfq_slab_kill(); elv_unregister(&iosched_cfq); + cfq_slab_kill(); } module_init(cfq_init); diff --git a/drivers/block/deadline-iosched.c b/drivers/block/deadline-iosched.c index 52a3ae5289a0..7929471d7df7 100644 --- a/drivers/block/deadline-iosched.c +++ b/drivers/block/deadline-iosched.c @@ -50,7 +50,6 @@ struct deadline_data { * next in sort order. read, write or both are NULL */ struct deadline_rq *next_drq[2]; - struct list_head *dispatch; /* driver dispatch queue */ struct list_head *hash; /* request hash */ unsigned int batching; /* number of sequential requests made */ sector_t last_sector; /* head position */ @@ -113,15 +112,6 @@ static inline void deadline_del_drq_hash(struct deadline_rq *drq) __deadline_del_drq_hash(drq); } -static void -deadline_remove_merge_hints(request_queue_t *q, struct deadline_rq *drq) -{ - deadline_del_drq_hash(drq); - - if (q->last_merge == drq->request) - q->last_merge = NULL; -} - static inline void deadline_add_drq_hash(struct deadline_data *dd, struct deadline_rq *drq) { @@ -239,10 +229,9 @@ deadline_del_drq_rb(struct deadline_data *dd, struct deadline_rq *drq) dd->next_drq[data_dir] = rb_entry_drq(rbnext); } - if (ON_RB(&drq->rb_node)) { - rb_erase(&drq->rb_node, DRQ_RB_ROOT(dd, drq)); - RB_CLEAR(&drq->rb_node); - } + BUG_ON(!ON_RB(&drq->rb_node)); + rb_erase(&drq->rb_node, DRQ_RB_ROOT(dd, drq)); + RB_CLEAR(&drq->rb_node); } static struct request * @@ -286,7 +275,7 @@ deadline_find_first_drq(struct deadline_data *dd, int data_dir) /* * add drq to rbtree and fifo */ -static inline void +static void deadline_add_request(struct request_queue *q, struct request *rq) { struct deadline_data *dd = q->elevator->elevator_data; @@ -301,12 +290,8 @@ deadline_add_request(struct request_queue *q, struct request *rq) drq->expires = jiffies + dd->fifo_expire[data_dir]; list_add_tail(&drq->fifo, &dd->fifo_list[data_dir]); - if (rq_mergeable(rq)) { + if (rq_mergeable(rq)) deadline_add_drq_hash(dd, drq); - - if (!q->last_merge) - q->last_merge = rq; - } } /* @@ -315,14 +300,11 @@ deadline_add_request(struct request_queue *q, struct request *rq) static void deadline_remove_request(request_queue_t *q, struct request *rq) { struct deadline_rq *drq = RQ_DATA(rq); + struct deadline_data *dd = q->elevator->elevator_data; - if (drq) { - struct deadline_data *dd = q->elevator->elevator_data; - - list_del_init(&drq->fifo); - deadline_remove_merge_hints(q, drq); - deadline_del_drq_rb(dd, drq); - } + list_del_init(&drq->fifo); + deadline_del_drq_rb(dd, drq); + deadline_del_drq_hash(drq); } static int @@ -333,15 +315,6 @@ deadline_merge(request_queue_t *q, struct request **req, struct bio *bio) int ret; /* - * try last_merge to avoid going to hash - */ - ret = elv_try_last_merge(q, bio); - if (ret != ELEVATOR_NO_MERGE) { - __rq = q->last_merge; - goto out_insert; - } - - /* * see if the merge hash can satisfy a back merge */ __rq = deadline_find_drq_hash(dd, bio->bi_sector); @@ -373,8 +346,6 @@ deadline_merge(request_queue_t *q, struct request **req, struct bio *bio) return ELEVATOR_NO_MERGE; out: - q->last_merge = __rq; -out_insert: if (ret) deadline_hot_drq_hash(dd, RQ_DATA(__rq)); *req = __rq; @@ -399,8 +370,6 @@ static void deadline_merged_request(request_queue_t *q, struct request *req) deadline_del_drq_rb(dd, drq); deadline_add_drq_rb(dd, drq); } - - q->last_merge = req; } static void @@ -452,7 +421,7 @@ deadline_move_to_dispatch(struct deadline_data *dd, struct deadline_rq *drq) request_queue_t *q = drq->request->q; deadline_remove_request(q, drq->request); - list_add_tail(&drq->request->queuelist, dd->dispatch); + elv_dispatch_add_tail(q, drq->request); } /* @@ -502,8 +471,9 @@ static inline int deadline_check_fifo(struct deadline_data *dd, int ddir) * deadline_dispatch_requests selects the best request according to * read/write expire, fifo_batch, etc */ -static int deadline_dispatch_requests(struct deadline_data *dd) +static int deadline_dispatch_requests(request_queue_t *q, int force) { + struct deadline_data *dd = q->elevator->elevator_data; const int reads = !list_empty(&dd->fifo_list[READ]); const int writes = !list_empty(&dd->fifo_list[WRITE]); struct deadline_rq *drq; @@ -597,65 +567,12 @@ dispatch_request: return 1; } -static struct request *deadline_next_request(request_queue_t *q) -{ - struct deadline_data *dd = q->elevator->elevator_data; - struct request *rq; - - /* - * if there are still requests on the dispatch queue, grab the first one - */ - if (!list_empty(dd->dispatch)) { -dispatch: - rq = list_entry_rq(dd->dispatch->next); - return rq; - } - - if (deadline_dispatch_requests(dd)) - goto dispatch; - - return NULL; -} - -static void -deadline_insert_request(request_queue_t *q, struct request *rq, int where) -{ - struct deadline_data *dd = q->elevator->elevator_data; - - /* barriers must flush the reorder queue */ - if (unlikely(rq->flags & (REQ_SOFTBARRIER | REQ_HARDBARRIER) - && where == ELEVATOR_INSERT_SORT)) - where = ELEVATOR_INSERT_BACK; - - switch (where) { - case ELEVATOR_INSERT_BACK: - while (deadline_dispatch_requests(dd)) - ; - list_add_tail(&rq->queuelist, dd->dispatch); - break; - case ELEVATOR_INSERT_FRONT: - list_add(&rq->queuelist, dd->dispatch); - break; - case ELEVATOR_INSERT_SORT: - BUG_ON(!blk_fs_request(rq)); - deadline_add_request(q, rq); - break; - default: - printk("%s: bad insert point %d\n", __FUNCTION__,where); - return; - } -} - static int deadline_queue_empty(request_queue_t *q) { struct deadline_data *dd = q->elevator->elevator_data; - if (!list_empty(&dd->fifo_list[WRITE]) - || !list_empty(&dd->fifo_list[READ]) - || !list_empty(dd->dispatch)) - return 0; - - return 1; + return list_empty(&dd->fifo_list[WRITE]) + && list_empty(&dd->fifo_list[READ]); } static struct request * @@ -733,7 +650,6 @@ static int deadline_init_queue(request_queue_t *q, elevator_t *e) INIT_LIST_HEAD(&dd->fifo_list[WRITE]); dd->sort_list[READ] = RB_ROOT; dd->sort_list[WRITE] = RB_ROOT; - dd->dispatch = &q->queue_head; dd->fifo_expire[READ] = read_expire; dd->fifo_expire[WRITE] = write_expire; dd->writes_starved = writes_starved; @@ -748,15 +664,13 @@ static void deadline_put_request(request_queue_t *q, struct request *rq) struct deadline_data *dd = q->elevator->elevator_data; struct deadline_rq *drq = RQ_DATA(rq); - if (drq) { - mempool_free(drq, dd->drq_pool); - rq->elevator_private = NULL; - } + mempool_free(drq, dd->drq_pool); + rq->elevator_private = NULL; } static int deadline_set_request(request_queue_t *q, struct request *rq, struct bio *bio, - int gfp_mask) + gfp_t gfp_mask) { struct deadline_data *dd = q->elevator->elevator_data; struct deadline_rq *drq; @@ -917,9 +831,8 @@ static struct elevator_type iosched_deadline = { .elevator_merge_fn = deadline_merge, .elevator_merged_fn = deadline_merged_request, .elevator_merge_req_fn = deadline_merged_requests, - .elevator_next_req_fn = deadline_next_request, - .elevator_add_req_fn = deadline_insert_request, - .elevator_remove_req_fn = deadline_remove_request, + .elevator_dispatch_fn = deadline_dispatch_requests, + .elevator_add_req_fn = deadline_add_request, .elevator_queue_empty_fn = deadline_queue_empty, .elevator_former_req_fn = deadline_former_request, .elevator_latter_req_fn = deadline_latter_request, diff --git a/drivers/block/elevator.c b/drivers/block/elevator.c index 98f0126a2deb..36f1057084b0 100644 --- a/drivers/block/elevator.c +++ b/drivers/block/elevator.c @@ -34,6 +34,7 @@ #include <linux/slab.h> #include <linux/init.h> #include <linux/compiler.h> +#include <linux/delay.h> #include <asm/uaccess.h> @@ -83,21 +84,11 @@ inline int elv_try_merge(struct request *__rq, struct bio *bio) } EXPORT_SYMBOL(elv_try_merge); -inline int elv_try_last_merge(request_queue_t *q, struct bio *bio) -{ - if (q->last_merge) - return elv_try_merge(q->last_merge, bio); - - return ELEVATOR_NO_MERGE; -} -EXPORT_SYMBOL(elv_try_last_merge); - static struct elevator_type *elevator_find(const char *name) { struct elevator_type *e = NULL; struct list_head *entry; - spin_lock_irq(&elv_list_lock); list_for_each(entry, &elv_list) { struct elevator_type *__e; @@ -108,7 +99,6 @@ static struct elevator_type *elevator_find(const char *name) break; } } - spin_unlock_irq(&elv_list_lock); return e; } @@ -120,12 +110,15 @@ static void elevator_put(struct elevator_type *e) static struct elevator_type *elevator_get(const char *name) { - struct elevator_type *e = elevator_find(name); + struct elevator_type *e; - if (!e) - return NULL; - if (!try_module_get(e->elevator_owner)) - return NULL; + spin_lock_irq(&elv_list_lock); + + e = elevator_find(name); + if (e && !try_module_get(e->elevator_owner)) + e = NULL; + + spin_unlock_irq(&elv_list_lock); return e; } @@ -139,8 +132,6 @@ static int elevator_attach(request_queue_t *q, struct elevator_type *e, eq->ops = &e->ops; eq->elevator_type = e; - INIT_LIST_HEAD(&q->queue_head); - q->last_merge = NULL; q->elevator = eq; if (eq->ops->elevator_init_fn) @@ -153,23 +144,20 @@ static char chosen_elevator[16]; static void elevator_setup_default(void) { + struct elevator_type *e; + /* - * check if default is set and exists + * If default has not been set, use the compiled-in selection. */ - if (chosen_elevator[0] && elevator_find(chosen_elevator)) - return; - -#if defined(CONFIG_IOSCHED_AS) - strcpy(chosen_elevator, "anticipatory"); -#elif defined(CONFIG_IOSCHED_DEADLINE) - strcpy(chosen_elevator, "deadline"); -#elif defined(CONFIG_IOSCHED_CFQ) - strcpy(chosen_elevator, "cfq"); -#elif defined(CONFIG_IOSCHED_NOOP) - strcpy(chosen_elevator, "noop"); -#else -#error "You must build at least 1 IO scheduler into the kernel" -#endif + if (!chosen_elevator[0]) + strcpy(chosen_elevator, CONFIG_DEFAULT_IOSCHED); + + /* + * If the given scheduler is not available, fall back to no-op. + */ + if (!(e = elevator_find(chosen_elevator))) + strcpy(chosen_elevator, "noop"); + elevator_put(e); } static int __init elevator_setup(char *str) @@ -186,6 +174,11 @@ int elevator_init(request_queue_t *q, char *name) struct elevator_queue *eq; int ret = 0; + INIT_LIST_HEAD(&q->queue_head); + q->last_merge = NULL; + q->end_sector = 0; + q->boundary_rq = NULL; + elevator_setup_default(); if (!name) @@ -220,9 +213,52 @@ void elevator_exit(elevator_t *e) kfree(e); } +/* + * Insert rq into dispatch queue of q. Queue lock must be held on + * entry. If sort != 0, rq is sort-inserted; otherwise, rq will be + * appended to the dispatch queue. To be used by specific elevators. + */ +void elv_dispatch_sort(request_queue_t *q, struct request *rq) +{ + sector_t boundary; + struct list_head *entry; + + if (q->last_merge == rq) + q->last_merge = NULL; + + boundary = q->end_sector; + + list_for_each_prev(entry, &q->queue_head) { + struct request *pos = list_entry_rq(entry); + + if (pos->flags & (REQ_SOFTBARRIER|REQ_HARDBARRIER|REQ_STARTED)) + break; + if (rq->sector >= boundary) { + if (pos->sector < boundary) + continue; + } else { + if (pos->sector >= boundary) + break; + } + if (rq->sector >= pos->sector) + break; + } + + list_add(&rq->queuelist, entry); +} + int elv_merge(request_queue_t *q, struct request **req, struct bio *bio) { elevator_t *e = q->elevator; + int ret; + + if (q->last_merge) { + ret = elv_try_merge(q->last_merge, bio); + if (ret != ELEVATOR_NO_MERGE) { + *req = q->last_merge; + return ret; + } + } if (e->ops->elevator_merge_fn) return e->ops->elevator_merge_fn(q, req, bio); @@ -236,6 +272,8 @@ void elv_merged_request(request_queue_t *q, struct request *rq) if (e->ops->elevator_merged_fn) e->ops->elevator_merged_fn(q, rq); + + q->last_merge = rq; } void elv_merge_requests(request_queue_t *q, struct request *rq, @@ -243,20 +281,13 @@ void elv_merge_requests(request_queue_t *q, struct request *rq, { elevator_t *e = q->elevator; - if (q->last_merge == next) - q->last_merge = NULL; - if (e->ops->elevator_merge_req_fn) e->ops->elevator_merge_req_fn(q, rq, next); + + q->last_merge = rq; } -/* - * For careful internal use by the block layer. Essentially the same as - * a requeue in that it tells the io scheduler that this request is not - * active in the driver or hardware anymore, but we don't want the request - * added back to the scheduler. Function is not exported. - */ -void elv_deactivate_request(request_queue_t *q, struct request *rq) +void elv_requeue_request(request_queue_t *q, struct request *rq) { elevator_t *e = q->elevator; @@ -264,19 +295,14 @@ void elv_deactivate_request(request_queue_t *q, struct request *rq) * it already went through dequeue, we need to decrement the * in_flight count again */ - if (blk_account_rq(rq)) + if (blk_account_rq(rq)) { q->in_flight--; + if (blk_sorted_rq(rq) && e->ops->elevator_deactivate_req_fn) + e->ops->elevator_deactivate_req_fn(q, rq); + } rq->flags &= ~REQ_STARTED; - if (e->ops->elevator_deactivate_req_fn) - e->ops->elevator_deactivate_req_fn(q, rq); -} - -void elv_requeue_request(request_queue_t *q, struct request *rq) -{ - elv_deactivate_request(q, rq); - /* * if this is the flush, requeue the original instead and drop the flush */ @@ -285,31 +311,27 @@ void elv_requeue_request(request_queue_t *q, struct request *rq) rq = rq->end_io_data; } - /* - * the request is prepped and may have some resources allocated. - * allowing unprepped requests to pass this one may cause resource - * deadlock. turn on softbarrier. - */ - rq->flags |= REQ_SOFTBARRIER; - - /* - * if iosched has an explicit requeue hook, then use that. otherwise - * just put the request at the front of the queue - */ - if (q->elevator->ops->elevator_requeue_req_fn) - q->elevator->ops->elevator_requeue_req_fn(q, rq); - else - __elv_add_request(q, rq, ELEVATOR_INSERT_FRONT, 0); + __elv_add_request(q, rq, ELEVATOR_INSERT_FRONT, 0); } void __elv_add_request(request_queue_t *q, struct request *rq, int where, int plug) { - /* - * barriers implicitly indicate back insertion - */ - if (rq->flags & (REQ_SOFTBARRIER | REQ_HARDBARRIER) && - where == ELEVATOR_INSERT_SORT) + if (rq->flags & (REQ_SOFTBARRIER | REQ_HARDBARRIER)) { + /* + * barriers implicitly indicate back insertion + */ + if (where == ELEVATOR_INSERT_SORT) + where = ELEVATOR_INSERT_BACK; + + /* + * this request is scheduling boundary, update end_sector + */ + if (blk_fs_request(rq)) { + q->end_sector = rq_end_sector(rq); + q->boundary_rq = rq; + } + } else if (!(rq->flags & REQ_ELVPRIV) && where == ELEVATOR_INSERT_SORT) where = ELEVATOR_INSERT_BACK; if (plug) @@ -317,23 +339,54 @@ void __elv_add_request(request_queue_t *q, struct request *rq, int where, rq->q = q; - if (!test_bit(QUEUE_FLAG_DRAIN, &q->queue_flags)) { - q->elevator->ops->elevator_add_req_fn(q, rq, where); + switch (where) { + case ELEVATOR_INSERT_FRONT: + rq->flags |= REQ_SOFTBARRIER; - if (blk_queue_plugged(q)) { - int nrq = q->rq.count[READ] + q->rq.count[WRITE] - - q->in_flight; + list_add(&rq->queuelist, &q->queue_head); + break; - if (nrq >= q->unplug_thresh) - __generic_unplug_device(q); - } - } else + case ELEVATOR_INSERT_BACK: + rq->flags |= REQ_SOFTBARRIER; + + while (q->elevator->ops->elevator_dispatch_fn(q, 1)) + ; + list_add_tail(&rq->queuelist, &q->queue_head); /* - * if drain is set, store the request "locally". when the drain - * is finished, the requests will be handed ordered to the io - * scheduler + * We kick the queue here for the following reasons. + * - The elevator might have returned NULL previously + * to delay requests and returned them now. As the + * queue wasn't empty before this request, ll_rw_blk + * won't run the queue on return, resulting in hang. + * - Usually, back inserted requests won't be merged + * with anything. There's no point in delaying queue + * processing. */ - list_add_tail(&rq->queuelist, &q->drain_list); + blk_remove_plug(q); + q->request_fn(q); + break; + + case ELEVATOR_INSERT_SORT: + BUG_ON(!blk_fs_request(rq)); + rq->flags |= REQ_SORTED; + q->elevator->ops->elevator_add_req_fn(q, rq); + if (q->last_merge == NULL && rq_mergeable(rq)) + q->last_merge = rq; + break; + + default: + printk(KERN_ERR "%s: bad insertion point %d\n", + __FUNCTION__, where); + BUG(); + } + + if (blk_queue_plugged(q)) { + int nrq = q->rq.count[READ] + q->rq.count[WRITE] + - q->in_flight; + + if (nrq >= q->unplug_thresh) + __generic_unplug_device(q); + } } void elv_add_request(request_queue_t *q, struct request *rq, int where, @@ -348,13 +401,19 @@ void elv_add_request(request_queue_t *q, struct request *rq, int where, static inline struct request *__elv_next_request(request_queue_t *q) { - struct request *rq = q->elevator->ops->elevator_next_req_fn(q); + struct request *rq; + + if (unlikely(list_empty(&q->queue_head) && + !q->elevator->ops->elevator_dispatch_fn(q, 0))) + return NULL; + + rq = list_entry_rq(q->queue_head.next); /* * if this is a barrier write and the device has to issue a * flush sequence to support it, check how far we are */ - if (rq && blk_fs_request(rq) && blk_barrier_rq(rq)) { + if (blk_fs_request(rq) && blk_barrier_rq(rq)) { BUG_ON(q->ordered == QUEUE_ORDERED_NONE); if (q->ordered == QUEUE_ORDERED_FLUSH && @@ -371,15 +430,30 @@ struct request *elv_next_request(request_queue_t *q) int ret; while ((rq = __elv_next_request(q)) != NULL) { - /* - * just mark as started even if we don't start it, a request - * that has been delayed should not be passed by new incoming - * requests - */ - rq->flags |= REQ_STARTED; + if (!(rq->flags & REQ_STARTED)) { + elevator_t *e = q->elevator; + + /* + * This is the first time the device driver + * sees this request (possibly after + * requeueing). Notify IO scheduler. + */ + if (blk_sorted_rq(rq) && + e->ops->elevator_activate_req_fn) + e->ops->elevator_activate_req_fn(q, rq); + + /* + * just mark as started even if we don't start + * it, a request that has been delayed should + * not be passed by new incoming requests + */ + rq->flags |= REQ_STARTED; + } - if (rq == q->last_merge) - q->last_merge = NULL; + if (!q->boundary_rq || q->boundary_rq == rq) { + q->end_sector = rq_end_sector(rq); + q->boundary_rq = NULL; + } if ((rq->flags & REQ_DONTPREP) || !q->prep_rq_fn) break; @@ -391,9 +465,9 @@ struct request *elv_next_request(request_queue_t *q) /* * the request may have been (partially) prepped. * we need to keep this request in the front to - * avoid resource deadlock. turn on softbarrier. + * avoid resource deadlock. REQ_STARTED will + * prevent other fs requests from passing this one. */ - rq->flags |= REQ_SOFTBARRIER; rq = NULL; break; } else if (ret == BLKPREP_KILL) { @@ -416,42 +490,32 @@ struct request *elv_next_request(request_queue_t *q) return rq; } -void elv_remove_request(request_queue_t *q, struct request *rq) +void elv_dequeue_request(request_queue_t *q, struct request *rq) { - elevator_t *e = q->elevator; + BUG_ON(list_empty(&rq->queuelist)); + + list_del_init(&rq->queuelist); /* * the time frame between a request being removed from the lists * and to it is freed is accounted as io that is in progress at - * the driver side. note that we only account requests that the - * driver has seen (REQ_STARTED set), to avoid false accounting - * for request-request merges + * the driver side. */ if (blk_account_rq(rq)) q->in_flight++; - - /* - * the main clearing point for q->last_merge is on retrieval of - * request by driver (it calls elv_next_request()), but it _can_ - * also happen here if a request is added to the queue but later - * deleted without ever being given to driver (merged with another - * request). - */ - if (rq == q->last_merge) - q->last_merge = NULL; - - if (e->ops->elevator_remove_req_fn) - e->ops->elevator_remove_req_fn(q, rq); } int elv_queue_empty(request_queue_t *q) { elevator_t *e = q->elevator; + if (!list_empty(&q->queue_head)) + return 0; + if (e->ops->elevator_queue_empty_fn) return e->ops->elevator_queue_empty_fn(q); - return list_empty(&q->queue_head); + return 1; } struct request *elv_latter_request(request_queue_t *q, struct request *rq) @@ -487,7 +551,7 @@ struct request *elv_former_request(request_queue_t *q, struct request *rq) } int elv_set_request(request_queue_t *q, struct request *rq, struct bio *bio, - int gfp_mask) + gfp_t gfp_mask) { elevator_t *e = q->elevator; @@ -523,11 +587,11 @@ void elv_completed_request(request_queue_t *q, struct request *rq) /* * request is released from the driver, io must be done */ - if (blk_account_rq(rq)) + if (blk_account_rq(rq)) { q->in_flight--; - - if (e->ops->elevator_completed_req_fn) - e->ops->elevator_completed_req_fn(q, rq); + if (blk_sorted_rq(rq) && e->ops->elevator_completed_req_fn) + e->ops->elevator_completed_req_fn(q, rq); + } } int elv_register_queue(struct request_queue *q) @@ -555,10 +619,9 @@ void elv_unregister_queue(struct request_queue *q) int elv_register(struct elevator_type *e) { + spin_lock_irq(&elv_list_lock); if (elevator_find(e->elevator_name)) BUG(); - - spin_lock_irq(&elv_list_lock); list_add_tail(&e->list, &elv_list); spin_unlock_irq(&elv_list_lock); @@ -572,6 +635,27 @@ EXPORT_SYMBOL_GPL(elv_register); void elv_unregister(struct elevator_type *e) { + struct task_struct *g, *p; + + /* + * Iterate every thread in the process to remove the io contexts. + */ + read_lock(&tasklist_lock); + do_each_thread(g, p) { + struct io_context *ioc = p->io_context; + if (ioc && ioc->cic) { + ioc->cic->exit(ioc->cic); + ioc->cic->dtor(ioc->cic); + ioc->cic = NULL; + } + if (ioc && ioc->aic) { + ioc->aic->exit(ioc->aic); + ioc->aic->dtor(ioc->aic); + ioc->aic = NULL; + } + } while_each_thread(g, p); + read_unlock(&tasklist_lock); + spin_lock_irq(&elv_list_lock); list_del_init(&e->list); spin_unlock_irq(&elv_list_lock); @@ -582,25 +666,36 @@ EXPORT_SYMBOL_GPL(elv_unregister); * switch to new_e io scheduler. be careful not to introduce deadlocks - * we don't free the old io scheduler, before we have allocated what we * need for the new one. this way we have a chance of going back to the old - * one, if the new one fails init for some reason. we also do an intermediate - * switch to noop to ensure safety with stack-allocated requests, since they - * don't originate from the block layer allocator. noop is safe here, because - * it never needs to touch the elevator itself for completion events. DRAIN - * flags will make sure we don't touch it for additions either. + * one, if the new one fails init for some reason. */ static void elevator_switch(request_queue_t *q, struct elevator_type *new_e) { - elevator_t *e = kmalloc(sizeof(elevator_t), GFP_KERNEL); - struct elevator_type *noop_elevator = NULL; - elevator_t *old_elevator; + elevator_t *old_elevator, *e; + /* + * Allocate new elevator + */ + e = kmalloc(sizeof(elevator_t), GFP_KERNEL); if (!e) goto error; /* - * first step, drain requests from the block freelist + * Turn on BYPASS and drain all requests w/ elevator private data */ - blk_wait_queue_drained(q, 0); + spin_lock_irq(q->queue_lock); + + set_bit(QUEUE_FLAG_ELVSWITCH, &q->queue_flags); + + while (q->elevator->ops->elevator_dispatch_fn(q, 1)) + ; + + while (q->rq.elvpriv) { + spin_unlock_irq(q->queue_lock); + msleep(10); + spin_lock_irq(q->queue_lock); + } + + spin_unlock_irq(q->queue_lock); /* * unregister old elevator data @@ -609,18 +704,6 @@ static void elevator_switch(request_queue_t *q, struct elevator_type *new_e) old_elevator = q->elevator; /* - * next step, switch to noop since it uses no private rq structures - * and doesn't allocate any memory for anything. then wait for any - * non-fs requests in-flight - */ - noop_elevator = elevator_get("noop"); - spin_lock_irq(q->queue_lock); - elevator_attach(q, noop_elevator, e); - spin_unlock_irq(q->queue_lock); - - blk_wait_queue_drained(q, 1); - - /* * attach and start new elevator */ if (elevator_attach(q, new_e, e)) @@ -630,11 +713,10 @@ static void elevator_switch(request_queue_t *q, struct elevator_type *new_e) goto fail_register; /* - * finally exit old elevator and start queue again + * finally exit old elevator and turn off BYPASS. */ elevator_exit(old_elevator); - blk_finish_queue_drain(q); - elevator_put(noop_elevator); + clear_bit(QUEUE_FLAG_ELVSWITCH, &q->queue_flags); return; fail_register: @@ -643,13 +725,13 @@ fail_register: * one again (along with re-adding the sysfs dir) */ elevator_exit(e); + e = NULL; fail: q->elevator = old_elevator; elv_register_queue(q); - blk_finish_queue_drain(q); + clear_bit(QUEUE_FLAG_ELVSWITCH, &q->queue_flags); + kfree(e); error: - if (noop_elevator) - elevator_put(noop_elevator); elevator_put(new_e); printk(KERN_ERR "elevator: switch to %s failed\n",new_e->elevator_name); } @@ -671,8 +753,10 @@ ssize_t elv_iosched_store(request_queue_t *q, const char *name, size_t count) return -EINVAL; } - if (!strcmp(elevator_name, q->elevator->elevator_type->elevator_name)) + if (!strcmp(elevator_name, q->elevator->elevator_type->elevator_name)) { + elevator_put(e); return count; + } elevator_switch(q, e); return count; @@ -701,11 +785,12 @@ ssize_t elv_iosched_show(request_queue_t *q, char *name) return len; } +EXPORT_SYMBOL(elv_dispatch_sort); EXPORT_SYMBOL(elv_add_request); EXPORT_SYMBOL(__elv_add_request); EXPORT_SYMBOL(elv_requeue_request); EXPORT_SYMBOL(elv_next_request); -EXPORT_SYMBOL(elv_remove_request); +EXPORT_SYMBOL(elv_dequeue_request); EXPORT_SYMBOL(elv_queue_empty); EXPORT_SYMBOL(elv_completed_request); EXPORT_SYMBOL(elevator_exit); diff --git a/drivers/block/genhd.c b/drivers/block/genhd.c index d42840cc0d1d..486ce1fdeb8c 100644 --- a/drivers/block/genhd.c +++ b/drivers/block/genhd.c @@ -337,10 +337,30 @@ static ssize_t disk_attr_show(struct kobject *kobj, struct attribute *attr, return ret; } +static ssize_t disk_attr_store(struct kobject * kobj, struct attribute * attr, + const char *page, size_t count) +{ + struct gendisk *disk = to_disk(kobj); + struct disk_attribute *disk_attr = + container_of(attr,struct disk_attribute,attr); + ssize_t ret = 0; + + if (disk_attr->store) + ret = disk_attr->store(disk, page, count); + return ret; +} + static struct sysfs_ops disk_sysfs_ops = { .show = &disk_attr_show, + .store = &disk_attr_store, }; +static ssize_t disk_uevent_store(struct gendisk * disk, + const char *buf, size_t count) +{ + kobject_hotplug(&disk->kobj, KOBJ_ADD); + return count; +} static ssize_t disk_dev_read(struct gendisk * disk, char *page) { dev_t base = MKDEV(disk->major, disk->first_minor); @@ -382,6 +402,10 @@ static ssize_t disk_stats_read(struct gendisk * disk, char *page) jiffies_to_msecs(disk_stat_read(disk, io_ticks)), jiffies_to_msecs(disk_stat_read(disk, time_in_queue))); } +static struct disk_attribute disk_attr_uevent = { + .attr = {.name = "uevent", .mode = S_IWUSR }, + .store = disk_uevent_store +}; static struct disk_attribute disk_attr_dev = { .attr = {.name = "dev", .mode = S_IRUGO }, .show = disk_dev_read @@ -404,6 +428,7 @@ static struct disk_attribute disk_attr_stat = { }; static struct attribute * default_attrs[] = { + &disk_attr_uevent.attr, &disk_attr_dev.attr, &disk_attr_range.attr, &disk_attr_removable.attr, diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index baedac522945..0af73512b9a8 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -263,8 +263,6 @@ void blk_queue_make_request(request_queue_t * q, make_request_fn * mfn) blk_queue_bounce_limit(q, BLK_BOUNCE_HIGH); blk_queue_activity_fn(q, NULL, NULL); - - INIT_LIST_HEAD(&q->drain_list); } EXPORT_SYMBOL(blk_queue_make_request); @@ -353,6 +351,8 @@ static void blk_pre_flush_end_io(struct request *flush_rq) struct request *rq = flush_rq->end_io_data; request_queue_t *q = rq->q; + elv_completed_request(q, flush_rq); + rq->flags |= REQ_BAR_PREFLUSH; if (!flush_rq->errors) @@ -369,6 +369,8 @@ static void blk_post_flush_end_io(struct request *flush_rq) struct request *rq = flush_rq->end_io_data; request_queue_t *q = rq->q; + elv_completed_request(q, flush_rq); + rq->flags |= REQ_BAR_POSTFLUSH; q->end_flush_fn(q, flush_rq); @@ -408,8 +410,6 @@ struct request *blk_start_pre_flush(request_queue_t *q, struct request *rq) if (!list_empty(&rq->queuelist)) blkdev_dequeue_request(rq); - elv_deactivate_request(q, rq); - flush_rq->end_io_data = rq; flush_rq->end_io = blk_pre_flush_end_io; @@ -1040,6 +1040,7 @@ EXPORT_SYMBOL(blk_queue_invalidate_tags); static char *rq_flags[] = { "REQ_RW", "REQ_FAILFAST", + "REQ_SORTED", "REQ_SOFTBARRIER", "REQ_HARDBARRIER", "REQ_CMD", @@ -1047,6 +1048,7 @@ static char *rq_flags[] = { "REQ_STARTED", "REQ_DONTPREP", "REQ_QUEUED", + "REQ_ELVPRIV", "REQ_PC", "REQ_BLOCK_PC", "REQ_SENSE", @@ -1637,9 +1639,9 @@ static int blk_init_free_list(request_queue_t *q) rl->count[READ] = rl->count[WRITE] = 0; rl->starved[READ] = rl->starved[WRITE] = 0; + rl->elvpriv = 0; init_waitqueue_head(&rl->wait[READ]); init_waitqueue_head(&rl->wait[WRITE]); - init_waitqueue_head(&rl->drain); rl->rq_pool = mempool_create_node(BLKDEV_MIN_RQ, mempool_alloc_slab, mempool_free_slab, request_cachep, q->node); @@ -1652,13 +1654,13 @@ static int blk_init_free_list(request_queue_t *q) static int __make_request(request_queue_t *, struct bio *); -request_queue_t *blk_alloc_queue(int gfp_mask) +request_queue_t *blk_alloc_queue(gfp_t gfp_mask) { return blk_alloc_queue_node(gfp_mask, -1); } EXPORT_SYMBOL(blk_alloc_queue); -request_queue_t *blk_alloc_queue_node(int gfp_mask, int node_id) +request_queue_t *blk_alloc_queue_node(gfp_t gfp_mask, int node_id) { request_queue_t *q; @@ -1782,12 +1784,14 @@ EXPORT_SYMBOL(blk_get_queue); static inline void blk_free_request(request_queue_t *q, struct request *rq) { - elv_put_request(q, rq); + if (rq->flags & REQ_ELVPRIV) + elv_put_request(q, rq); mempool_free(rq, q->rq.rq_pool); } static inline struct request * -blk_alloc_request(request_queue_t *q, int rw, struct bio *bio, int gfp_mask) +blk_alloc_request(request_queue_t *q, int rw, struct bio *bio, + int priv, gfp_t gfp_mask) { struct request *rq = mempool_alloc(q->rq.rq_pool, gfp_mask); @@ -1800,11 +1804,15 @@ blk_alloc_request(request_queue_t *q, int rw, struct bio *bio, int gfp_mask) */ rq->flags = rw; - if (!elv_set_request(q, rq, bio, gfp_mask)) - return rq; + if (priv) { + if (unlikely(elv_set_request(q, rq, bio, gfp_mask))) { + mempool_free(rq, q->rq.rq_pool); + return NULL; + } + rq->flags |= REQ_ELVPRIV; + } - mempool_free(rq, q->rq.rq_pool); - return NULL; + return rq; } /* @@ -1860,22 +1868,18 @@ static void __freed_request(request_queue_t *q, int rw) * A request has just been released. Account for it, update the full and * congestion status, wake up any waiters. Called under q->queue_lock. */ -static void freed_request(request_queue_t *q, int rw) +static void freed_request(request_queue_t *q, int rw, int priv) { struct request_list *rl = &q->rq; rl->count[rw]--; + if (priv) + rl->elvpriv--; __freed_request(q, rw); if (unlikely(rl->starved[rw ^ 1])) __freed_request(q, rw ^ 1); - - if (!rl->count[READ] && !rl->count[WRITE]) { - smp_mb(); - if (unlikely(waitqueue_active(&rl->drain))) - wake_up(&rl->drain); - } } #define blkdev_free_rq(list) list_entry((list)->next, struct request, queuelist) @@ -1885,14 +1889,12 @@ static void freed_request(request_queue_t *q, int rw) * Returns !NULL on success, with queue_lock *not held*. */ static struct request *get_request(request_queue_t *q, int rw, struct bio *bio, - int gfp_mask) + gfp_t gfp_mask) { struct request *rq = NULL; struct request_list *rl = &q->rq; struct io_context *ioc = current_io_context(GFP_ATOMIC); - - if (unlikely(test_bit(QUEUE_FLAG_DRAIN, &q->queue_flags))) - goto out; + int priv; if (rl->count[rw]+1 >= q->nr_requests) { /* @@ -1937,9 +1939,14 @@ get_rq: rl->starved[rw] = 0; if (rl->count[rw] >= queue_congestion_on_threshold(q)) set_queue_congested(q, rw); + + priv = !test_bit(QUEUE_FLAG_ELVSWITCH, &q->queue_flags); + if (priv) + rl->elvpriv++; + spin_unlock_irq(q->queue_lock); - rq = blk_alloc_request(q, rw, bio, gfp_mask); + rq = blk_alloc_request(q, rw, bio, priv, gfp_mask); if (!rq) { /* * Allocation failed presumably due to memory. Undo anything @@ -1949,7 +1956,7 @@ get_rq: * wait queue, but this is pretty rare. */ spin_lock_irq(q->queue_lock); - freed_request(q, rw); + freed_request(q, rw, priv); /* * in the very unlikely event that allocation failed and no @@ -2019,7 +2026,7 @@ static struct request *get_request_wait(request_queue_t *q, int rw, return rq; } -struct request *blk_get_request(request_queue_t *q, int rw, int gfp_mask) +struct request *blk_get_request(request_queue_t *q, int rw, gfp_t gfp_mask) { struct request *rq; @@ -2251,7 +2258,7 @@ EXPORT_SYMBOL(blk_rq_unmap_user); * @gfp_mask: memory allocation flags */ int blk_rq_map_kern(request_queue_t *q, struct request *rq, void *kbuf, - unsigned int len, unsigned int gfp_mask) + unsigned int len, gfp_t gfp_mask) { struct bio *bio; @@ -2433,13 +2440,15 @@ void disk_round_stats(struct gendisk *disk) { unsigned long now = jiffies; - __disk_stat_add(disk, time_in_queue, - disk->in_flight * (now - disk->stamp)); - disk->stamp = now; + if (now == disk->stamp) + return; - if (disk->in_flight) - __disk_stat_add(disk, io_ticks, (now - disk->stamp_idle)); - disk->stamp_idle = now; + if (disk->in_flight) { + __disk_stat_add(disk, time_in_queue, + disk->in_flight * (now - disk->stamp)); + __disk_stat_add(disk, io_ticks, (now - disk->stamp)); + } + disk->stamp = now; } /* @@ -2454,6 +2463,8 @@ static void __blk_put_request(request_queue_t *q, struct request *req) if (unlikely(--req->ref_count)) return; + elv_completed_request(q, req); + req->rq_status = RQ_INACTIVE; req->rl = NULL; @@ -2463,26 +2474,25 @@ static void __blk_put_request(request_queue_t *q, struct request *req) */ if (rl) { int rw = rq_data_dir(req); - - elv_completed_request(q, req); + int priv = req->flags & REQ_ELVPRIV; BUG_ON(!list_empty(&req->queuelist)); blk_free_request(q, req); - freed_request(q, rw); + freed_request(q, rw, priv); } } void blk_put_request(struct request *req) { + unsigned long flags; + request_queue_t *q = req->q; + /* - * if req->rl isn't set, this request didnt originate from the - * block layer, so it's safe to just disregard it + * Gee, IDE calls in w/ NULL q. Fix IDE and remove the + * following if (q) test. */ - if (req->rl) { - unsigned long flags; - request_queue_t *q = req->q; - + if (q) { spin_lock_irqsave(q->queue_lock, flags); __blk_put_request(q, req); spin_unlock_irqrestore(q->queue_lock, flags); @@ -2797,97 +2807,6 @@ static inline void blk_partition_remap(struct bio *bio) } } -void blk_finish_queue_drain(request_queue_t *q) -{ - struct request_list *rl = &q->rq; - struct request *rq; - int requeued = 0; - - spin_lock_irq(q->queue_lock); - clear_bit(QUEUE_FLAG_DRAIN, &q->queue_flags); - - while (!list_empty(&q->drain_list)) { - rq = list_entry_rq(q->drain_list.next); - - list_del_init(&rq->queuelist); - elv_requeue_request(q, rq); - requeued++; - } - - if (requeued) - q->request_fn(q); - - spin_unlock_irq(q->queue_lock); - - wake_up(&rl->wait[0]); - wake_up(&rl->wait[1]); - wake_up(&rl->drain); -} - -static int wait_drain(request_queue_t *q, struct request_list *rl, int dispatch) -{ - int wait = rl->count[READ] + rl->count[WRITE]; - - if (dispatch) - wait += !list_empty(&q->queue_head); - - return wait; -} - -/* - * We rely on the fact that only requests allocated through blk_alloc_request() - * have io scheduler private data structures associated with them. Any other - * type of request (allocated on stack or through kmalloc()) should not go - * to the io scheduler core, but be attached to the queue head instead. - */ -void blk_wait_queue_drained(request_queue_t *q, int wait_dispatch) -{ - struct request_list *rl = &q->rq; - DEFINE_WAIT(wait); - - spin_lock_irq(q->queue_lock); - set_bit(QUEUE_FLAG_DRAIN, &q->queue_flags); - - while (wait_drain(q, rl, wait_dispatch)) { - prepare_to_wait(&rl->drain, &wait, TASK_UNINTERRUPTIBLE); - - if (wait_drain(q, rl, wait_dispatch)) { - __generic_unplug_device(q); - spin_unlock_irq(q->queue_lock); - io_schedule(); - spin_lock_irq(q->queue_lock); - } - - finish_wait(&rl->drain, &wait); - } - - spin_unlock_irq(q->queue_lock); -} - -/* - * block waiting for the io scheduler being started again. - */ -static inline void block_wait_queue_running(request_queue_t *q) -{ - DEFINE_WAIT(wait); - - while (unlikely(test_bit(QUEUE_FLAG_DRAIN, &q->queue_flags))) { - struct request_list *rl = &q->rq; - - prepare_to_wait_exclusive(&rl->drain, &wait, - TASK_UNINTERRUPTIBLE); - - /* - * re-check the condition. avoids using prepare_to_wait() - * in the fast path (queue is running) - */ - if (test_bit(QUEUE_FLAG_DRAIN, &q->queue_flags)) - io_schedule(); - - finish_wait(&rl->drain, &wait); - } -} - static void handle_bad_sector(struct bio *bio) { char b[BDEVNAME_SIZE]; @@ -2983,8 +2902,6 @@ end_io: if (unlikely(test_bit(QUEUE_FLAG_DEAD, &q->queue_flags))) goto end_io; - block_wait_queue_running(q); - /* * If this device has partitions, remap block n * of partition p to block n+start(p) of the disk. @@ -3393,7 +3310,7 @@ void exit_io_context(void) * but since the current task itself holds a reference, the context can be * used in general code, so long as it stays within `current` context. */ -struct io_context *current_io_context(int gfp_flags) +struct io_context *current_io_context(gfp_t gfp_flags) { struct task_struct *tsk = current; struct io_context *ret; @@ -3424,7 +3341,7 @@ EXPORT_SYMBOL(current_io_context); * * This is always called in the context of the task which submitted the I/O. */ -struct io_context *get_io_context(int gfp_flags) +struct io_context *get_io_context(gfp_t gfp_flags) { struct io_context *ret; ret = current_io_context(gfp_flags); diff --git a/drivers/block/loop.c b/drivers/block/loop.c index b35e08876dd4..96c664af8d06 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -881,7 +881,7 @@ loop_init_xfer(struct loop_device *lo, struct loop_func_table *xfer, static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev) { struct file *filp = lo->lo_backing_file; - int gfp = lo->old_gfp_mask; + gfp_t gfp = lo->old_gfp_mask; if (lo->lo_state != Lo_bound) return -ENXIO; diff --git a/drivers/block/noop-iosched.c b/drivers/block/noop-iosched.c index b1730b62c37e..f56b8edb06e4 100644 --- a/drivers/block/noop-iosched.c +++ b/drivers/block/noop-iosched.c @@ -7,57 +7,19 @@ #include <linux/module.h> #include <linux/init.h> -/* - * See if we can find a request that this buffer can be coalesced with. - */ -static int elevator_noop_merge(request_queue_t *q, struct request **req, - struct bio *bio) -{ - int ret; - - ret = elv_try_last_merge(q, bio); - if (ret != ELEVATOR_NO_MERGE) - *req = q->last_merge; - - return ret; -} - -static void elevator_noop_merge_requests(request_queue_t *q, struct request *req, - struct request *next) -{ - list_del_init(&next->queuelist); -} - -static void elevator_noop_add_request(request_queue_t *q, struct request *rq, - int where) +static void elevator_noop_add_request(request_queue_t *q, struct request *rq) { - if (where == ELEVATOR_INSERT_FRONT) - list_add(&rq->queuelist, &q->queue_head); - else - list_add_tail(&rq->queuelist, &q->queue_head); - - /* - * new merges must not precede this barrier - */ - if (rq->flags & REQ_HARDBARRIER) - q->last_merge = NULL; - else if (!q->last_merge) - q->last_merge = rq; + elv_dispatch_add_tail(q, rq); } -static struct request *elevator_noop_next_request(request_queue_t *q) +static int elevator_noop_dispatch(request_queue_t *q, int force) { - if (!list_empty(&q->queue_head)) - return list_entry_rq(q->queue_head.next); - - return NULL; + return 0; } static struct elevator_type elevator_noop = { .ops = { - .elevator_merge_fn = elevator_noop_merge, - .elevator_merge_req_fn = elevator_noop_merge_requests, - .elevator_next_req_fn = elevator_noop_next_request, + .elevator_dispatch_fn = elevator_noop_dispatch, .elevator_add_req_fn = elevator_noop_add_request, }, .elevator_name = "noop", diff --git a/drivers/block/paride/paride.c b/drivers/block/paride/paride.c index 1fef136c0e41..ce94aa11f6a7 100644 --- a/drivers/block/paride/paride.c +++ b/drivers/block/paride/paride.c @@ -29,6 +29,7 @@ #include <linux/string.h> #include <linux/spinlock.h> #include <linux/wait.h> +#include <linux/sched.h> /* TASK_* */ #ifdef CONFIG_PARPORT_MODULE #define CONFIG_PARPORT diff --git a/drivers/block/paride/pf.c b/drivers/block/paride/pf.c index 94af920465b5..e9746af29b9f 100644 --- a/drivers/block/paride/pf.c +++ b/drivers/block/paride/pf.c @@ -807,10 +807,6 @@ static int pf_next_buf(void) return 1; spin_lock_irqsave(&pf_spin_lock, saved_flags); pf_end_request(1); - if (pf_req) { - pf_count = pf_req->current_nr_sectors; - pf_buf = pf_req->buffer; - } spin_unlock_irqrestore(&pf_spin_lock, saved_flags); return 1; } diff --git a/drivers/block/paride/pg.c b/drivers/block/paride/pg.c index b3982395f22b..6f5df0fad703 100644 --- a/drivers/block/paride/pg.c +++ b/drivers/block/paride/pg.c @@ -162,6 +162,8 @@ enum {D_PRT, D_PRO, D_UNI, D_MOD, D_SLV, D_DLY}; #include <linux/mtio.h> #include <linux/pg.h> #include <linux/device.h> +#include <linux/sched.h> /* current, TASK_* */ +#include <linux/jiffies.h> #include <asm/uaccess.h> @@ -674,7 +676,7 @@ static int __init pg_init(void) for (unit = 0; unit < PG_UNITS; unit++) { struct pg *dev = &devices[unit]; if (dev->present) { - class_device_create(pg_class, MKDEV(major, unit), + class_device_create(pg_class, NULL, MKDEV(major, unit), NULL, "pg%u", unit); err = devfs_mk_cdev(MKDEV(major, unit), S_IFCHR | S_IRUSR | S_IWUSR, "pg/%u", diff --git a/drivers/block/paride/pt.c b/drivers/block/paride/pt.c index d8d35233cf49..715ae5dc88fb 100644 --- a/drivers/block/paride/pt.c +++ b/drivers/block/paride/pt.c @@ -146,6 +146,7 @@ static int (*drives[4])[6] = {&drive0, &drive1, &drive2, &drive3}; #include <linux/slab.h> #include <linux/mtio.h> #include <linux/device.h> +#include <linux/sched.h> /* current, TASK_*, schedule_timeout() */ #include <asm/uaccess.h> @@ -971,7 +972,7 @@ static int __init pt_init(void) devfs_mk_dir("pt"); for (unit = 0; unit < PT_UNITS; unit++) if (pt[unit].present) { - class_device_create(pt_class, MKDEV(major, unit), + class_device_create(pt_class, NULL, MKDEV(major, unit), NULL, "pt%d", unit); err = devfs_mk_cdev(MKDEV(major, unit), S_IFCHR | S_IRUSR | S_IWUSR, @@ -980,7 +981,7 @@ static int __init pt_init(void) class_device_destroy(pt_class, MKDEV(major, unit)); goto out_class; } - class_device_create(pt_class, MKDEV(major, unit + 128), + class_device_create(pt_class, NULL, MKDEV(major, unit + 128), NULL, "pt%dn", unit); err = devfs_mk_cdev(MKDEV(major, unit + 128), S_IFCHR | S_IRUSR | S_IWUSR, diff --git a/drivers/block/rd.c b/drivers/block/rd.c index 145c1fbffe01..68c60a5bcdab 100644 --- a/drivers/block/rd.c +++ b/drivers/block/rd.c @@ -348,7 +348,7 @@ static int rd_open(struct inode *inode, struct file *filp) struct block_device *bdev = inode->i_bdev; struct address_space *mapping; unsigned bsize; - int gfp_mask; + gfp_t gfp_mask; inode = igrab(bdev->bd_inode); rd_bdev[unit] = bdev; diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c index d57007b92f77..1ded3b433459 100644 --- a/drivers/block/sx8.c +++ b/drivers/block/sx8.c @@ -1,7 +1,7 @@ /* * sx8.c: Driver for Promise SATA SX8 looks-like-I2O hardware * - * Copyright 2004 Red Hat, Inc. + * Copyright 2004-2005 Red Hat, Inc. * * Author/maintainer: Jeff Garzik <jgarzik@pobox.com> * @@ -31,10 +31,6 @@ #include <asm/semaphore.h> #include <asm/uaccess.h> -MODULE_AUTHOR("Jeff Garzik"); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Promise SATA SX8 block driver"); - #if 0 #define CARM_DEBUG #define CARM_VERBOSE_DEBUG @@ -45,9 +41,35 @@ MODULE_DESCRIPTION("Promise SATA SX8 block driver"); #undef CARM_NDEBUG #define DRV_NAME "sx8" -#define DRV_VERSION "0.8" +#define DRV_VERSION "1.0" #define PFX DRV_NAME ": " +MODULE_AUTHOR("Jeff Garzik"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Promise SATA SX8 block driver"); +MODULE_VERSION(DRV_VERSION); + +/* + * SX8 hardware has a single message queue for all ATA ports. + * When this driver was written, the hardware (firmware?) would + * corrupt data eventually, if more than one request was outstanding. + * As one can imagine, having 8 ports bottlenecking on a single + * command hurts performance. + * + * Based on user reports, later versions of the hardware (firmware?) + * seem to be able to survive with more than one command queued. + * + * Therefore, we default to the safe option -- 1 command -- but + * allow the user to increase this. + * + * SX8 should be able to support up to ~60 queued commands (CARM_MAX_REQ), + * but problems seem to occur when you exceed ~30, even on newer hardware. + */ +static int max_queue = 1; +module_param(max_queue, int, 0444); +MODULE_PARM_DESC(max_queue, "Maximum number of queued commands. (min==1, max==30, safe==1)"); + + #define NEXT_RESP(idx) ((idx + 1) % RMSG_Q_LEN) /* 0xf is just arbitrary, non-zero noise; this is sorta like poisoning */ @@ -90,12 +112,10 @@ enum { /* command message queue limits */ CARM_MAX_REQ = 64, /* max command msgs per host */ - CARM_MAX_Q = 1, /* one command at a time */ CARM_MSG_LOW_WATER = (CARM_MAX_REQ / 4), /* refill mark */ /* S/G limits, host-wide and per-request */ CARM_MAX_REQ_SG = 32, /* max s/g entries per request */ - CARM_SG_BOUNDARY = 0xffffUL, /* s/g segment boundary */ CARM_MAX_HOST_SG = 600, /* max s/g entries per host */ CARM_SG_LOW_WATER = (CARM_MAX_HOST_SG / 4), /* re-fill mark */ @@ -181,6 +201,10 @@ enum { FL_DYN_MAJOR = (1 << 17), }; +enum { + CARM_SG_BOUNDARY = 0xffffUL, /* s/g segment boundary */ +}; + enum scatter_gather_types { SGT_32BIT = 0, SGT_64BIT = 1, @@ -218,7 +242,6 @@ static const char *state_name[] = { struct carm_port { unsigned int port_no; - unsigned int n_queued; struct gendisk *disk; struct carm_host *host; @@ -448,7 +471,7 @@ static inline int carm_lookup_bucket(u32 msg_size) for (i = 0; i < ARRAY_SIZE(msg_sizes); i++) if (msg_size <= msg_sizes[i]) return i; - + return -ENOENT; } @@ -509,7 +532,7 @@ static struct carm_request *carm_get_request(struct carm_host *host) if (host->hw_sg_used >= (CARM_MAX_HOST_SG - CARM_MAX_REQ_SG)) return NULL; - for (i = 0; i < CARM_MAX_Q; i++) + for (i = 0; i < max_queue; i++) if ((host->msg_alloc & (1ULL << i)) == 0) { struct carm_request *crq = &host->req[i]; crq->port = NULL; @@ -521,14 +544,14 @@ static struct carm_request *carm_get_request(struct carm_host *host) assert(host->n_msgs <= CARM_MAX_REQ); return crq; } - + DPRINTK("no request available, returning NULL\n"); return NULL; } static int carm_put_request(struct carm_host *host, struct carm_request *crq) { - assert(crq->tag < CARM_MAX_Q); + assert(crq->tag < max_queue); if (unlikely((host->msg_alloc & (1ULL << crq->tag)) == 0)) return -EINVAL; /* tried to clear a tag that was not active */ @@ -791,7 +814,7 @@ static inline void carm_end_rq(struct carm_host *host, struct carm_request *crq, int is_ok) { carm_end_request_queued(host, crq, is_ok); - if (CARM_MAX_Q == 1) + if (max_queue == 1) carm_round_robin(host); else if ((host->n_msgs <= CARM_MSG_LOW_WATER) && (host->hw_sg_used <= CARM_SG_LOW_WATER)) { diff --git a/drivers/block/ub.c b/drivers/block/ub.c index ed4d5006fe62..bfb23d543ff7 100644 --- a/drivers/block/ub.c +++ b/drivers/block/ub.c @@ -1512,7 +1512,7 @@ static void ub_state_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd) scmd->nsg = 1; sg = &scmd->sgv[0]; sg->page = virt_to_page(sc->top_sense); - sg->offset = (unsigned int)sc->top_sense & (PAGE_SIZE-1); + sg->offset = (unsigned long)sc->top_sense & (PAGE_SIZE-1); sg->length = UB_SENSE_SIZE; scmd->len = UB_SENSE_SIZE; scmd->lun = cmd->lun; @@ -1891,7 +1891,7 @@ static int ub_sync_read_cap(struct ub_dev *sc, struct ub_lun *lun, cmd->nsg = 1; sg = &cmd->sgv[0]; sg->page = virt_to_page(p); - sg->offset = (unsigned int)p & (PAGE_SIZE-1); + sg->offset = (unsigned long)p & (PAGE_SIZE-1); sg->length = 8; cmd->len = 8; cmd->lun = lun; diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index 543f93e0f23f..b9fbe6e7f9ae 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -55,14 +55,6 @@ config BT_HCIUART_BCSP Say Y here to compile support for HCI BCSP protocol. -config BT_HCIUART_BCSP_TXCRC - bool "Transmit CRC with every BCSP packet" - depends on BT_HCIUART_BCSP - help - If you say Y here, a 16-bit CRC checksum will be transmitted along with - every BCSP (BlueCore Serial Protocol) packet sent to the Bluetooth chip. - This increases reliability, but slightly reduces efficiency. - config BT_HCIBCM203X tristate "HCI BCM203x USB driver" depends on USB diff --git a/drivers/bluetooth/bpa10x.c b/drivers/bluetooth/bpa10x.c index 4fa85234d8b5..0db0400519c9 100644 --- a/drivers/bluetooth/bpa10x.c +++ b/drivers/bluetooth/bpa10x.c @@ -550,6 +550,9 @@ static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id * if (ignore) return -ENODEV; + if (intf->cur_altsetting->desc.bInterfaceNumber > 0) + return -ENODEV; + data = kmalloc(sizeof(*data), GFP_KERNEL); if (!data) { BT_ERR("Can't allocate data structure"); diff --git a/drivers/bluetooth/hci_bcsp.c b/drivers/bluetooth/hci_bcsp.c index 0ee324e1265d..0a4761415ac3 100644 --- a/drivers/bluetooth/hci_bcsp.c +++ b/drivers/bluetooth/hci_bcsp.c @@ -1,35 +1,27 @@ -/* - BlueCore Serial Protocol (BCSP) for Linux Bluetooth stack (BlueZ). - Copyright 2002 by Fabrizio Gennari <fabrizio.gennari@philips.com> - - Based on - hci_h4.c by Maxim Krasnyansky <maxk@qualcomm.com> - ABCSP by Carl Orsborn <cjo@csr.com> - - 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; - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. - IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY - CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - - ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, - COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS - SOFTWARE IS DISCLAIMED. -*/ - /* - * $Id: hci_bcsp.c,v 1.2 2002/09/26 05:05:14 maxk Exp $ + * + * Bluetooth HCI UART driver + * + * Copyright (C) 2002-2003 Fabrizio Gennari <fabrizio.gennari@philips.com> + * Copyright (C) 2004-2005 Marcel Holtmann <marcel@holtmann.org> + * + * + * 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 + * */ -#define VERSION "0.2" - #include <linux/config.h> #include <linux/module.h> @@ -52,16 +44,56 @@ #include <net/bluetooth/bluetooth.h> #include <net/bluetooth/hci_core.h> + #include "hci_uart.h" -#include "hci_bcsp.h" #ifndef CONFIG_BT_HCIUART_DEBUG #undef BT_DBG #define BT_DBG( A... ) #endif +#define VERSION "0.3" + +static int txcrc = 1; static int hciextn = 1; +#define BCSP_TXWINSIZE 4 + +#define BCSP_ACK_PKT 0x05 +#define BCSP_LE_PKT 0x06 + +struct bcsp_struct { + struct sk_buff_head unack; /* Unack'ed packets queue */ + struct sk_buff_head rel; /* Reliable packets queue */ + struct sk_buff_head unrel; /* Unreliable packets queue */ + + unsigned long rx_count; + struct sk_buff *rx_skb; + u8 rxseq_txack; /* rxseq == txack. */ + u8 rxack; /* Last packet sent by us that the peer ack'ed */ + struct timer_list tbcsp; + + enum { + BCSP_W4_PKT_DELIMITER, + BCSP_W4_PKT_START, + BCSP_W4_BCSP_HDR, + BCSP_W4_DATA, + BCSP_W4_CRC + } rx_state; + + enum { + BCSP_ESCSTATE_NOESC, + BCSP_ESCSTATE_ESC + } rx_esc_state; + + u8 use_crc; + u16 message_crc; + u8 txack_req; /* Do we need to send ack's to the peer? */ + + /* Reliable packet sequence number - used to assign seq to each rel pkt. */ + u8 msgq_txseq; +}; + /* ---- BCSP CRC calculation ---- */ /* Table for calculating CRC for polynomial 0x1021, LSB processed first, @@ -111,6 +143,7 @@ static u16 bcsp_crc_reverse(u16 crc) rev |= (crc & 1); crc = crc >> 1; } + return (rev); } @@ -119,6 +152,7 @@ static u16 bcsp_crc_reverse(u16 crc) static void bcsp_slip_msgdelim(struct sk_buff *skb) { const char pkt_delim = 0xc0; + memcpy(skb_put(skb, 1), &pkt_delim, 1); } @@ -173,11 +207,8 @@ static struct sk_buff *bcsp_prepare_pkt(struct bcsp_struct *bcsp, u8 *data, { struct sk_buff *nskb; u8 hdr[4], chan; - int rel, i; - -#ifdef CONFIG_BT_HCIUART_BCSP_TXCRC u16 BCSP_CRC_INIT(bcsp_txmsg_crc); -#endif + int rel, i; switch (pkt_type) { case HCI_ACLDATA_PKT: @@ -240,9 +271,9 @@ static struct sk_buff *bcsp_prepare_pkt(struct bcsp_struct *bcsp, u8 *data, BT_DBG("Sending packet with seqno %u", bcsp->msgq_txseq); bcsp->msgq_txseq = ++(bcsp->msgq_txseq) & 0x07; } -#ifdef CONFIG_BT_HCIUART_BCSP_TXCRC - hdr[0] |= 0x40; -#endif + + if (bcsp->use_crc) + hdr[0] |= 0x40; hdr[1] = ((len << 4) & 0xff) | chan; hdr[2] = len >> 4; @@ -251,25 +282,25 @@ static struct sk_buff *bcsp_prepare_pkt(struct bcsp_struct *bcsp, u8 *data, /* Put BCSP header */ for (i = 0; i < 4; i++) { bcsp_slip_one_byte(nskb, hdr[i]); -#ifdef CONFIG_BT_HCIUART_BCSP_TXCRC - bcsp_crc_update(&bcsp_txmsg_crc, hdr[i]); -#endif + + if (bcsp->use_crc) + bcsp_crc_update(&bcsp_txmsg_crc, hdr[i]); } /* Put payload */ for (i = 0; i < len; i++) { bcsp_slip_one_byte(nskb, data[i]); -#ifdef CONFIG_BT_HCIUART_BCSP_TXCRC - bcsp_crc_update(&bcsp_txmsg_crc, data[i]); -#endif + + if (bcsp->use_crc) + bcsp_crc_update(&bcsp_txmsg_crc, data[i]); } -#ifdef CONFIG_BT_HCIUART_BCSP_TXCRC /* Put CRC */ - bcsp_txmsg_crc = bcsp_crc_reverse(bcsp_txmsg_crc); - bcsp_slip_one_byte(nskb, (u8) ((bcsp_txmsg_crc >> 8) & 0x00ff)); - bcsp_slip_one_byte(nskb, (u8) (bcsp_txmsg_crc & 0x00ff)); -#endif + if (bcsp->use_crc) { + bcsp_txmsg_crc = bcsp_crc_reverse(bcsp_txmsg_crc); + bcsp_slip_one_byte(nskb, (u8) ((bcsp_txmsg_crc >> 8) & 0x00ff)); + bcsp_slip_one_byte(nskb, (u8) (bcsp_txmsg_crc & 0x00ff)); + } bcsp_slip_msgdelim(nskb); return nskb; @@ -317,7 +348,6 @@ static struct sk_buff *bcsp_dequeue(struct hci_uart *hu) spin_unlock_irqrestore(&bcsp->unack.lock, flags); - /* We could not send a reliable packet, either because there are none or because there are too many unack'ed pkts. Did we receive any packets we have not acknowledged yet ? */ @@ -363,7 +393,7 @@ static void bcsp_pkt_cull(struct bcsp_struct *bcsp) BT_ERR("Peer acked invalid packet"); BT_DBG("Removing %u pkts out of %u, up to seqno %u", - pkts_to_be_removed, bcsp->unack.qlen, (seqno - 1) & 0x07); + pkts_to_be_removed, bcsp->unack.qlen, (seqno - 1) & 0x07); for (i = 0, skb = ((struct sk_buff *) &bcsp->unack)->next; i < pkts_to_be_removed && skb != (struct sk_buff *) &bcsp->unack; i++) { @@ -374,8 +404,10 @@ static void bcsp_pkt_cull(struct bcsp_struct *bcsp) kfree_skb(skb); skb = nskb; } + if (bcsp->unack.qlen == 0) del_timer(&bcsp->tbcsp); + spin_unlock_irqrestore(&bcsp->unack.lock, flags); if (i != pkts_to_be_removed) @@ -530,6 +562,7 @@ static inline void bcsp_complete_rx_pkt(struct hci_uart *hu) hci_recv_frame(bcsp->rx_skb); } + bcsp->rx_state = BCSP_W4_PKT_DELIMITER; bcsp->rx_skb = NULL; } @@ -598,8 +631,8 @@ static int bcsp_recv(struct hci_uart *hu, void *data, int count) BT_ERR ("Checksum failed: computed %04x received %04x", bcsp_crc_reverse(bcsp->message_crc), - (bcsp->rx_skb-> data[bcsp->rx_skb->len - 2] << 8) + - bcsp->rx_skb->data[bcsp->rx_skb->len - 1]); + (bcsp->rx_skb-> data[bcsp->rx_skb->len - 2] << 8) + + bcsp->rx_skb->data[bcsp->rx_skb->len - 1]); kfree_skb(bcsp->rx_skb); bcsp->rx_state = BCSP_W4_PKT_DELIMITER; @@ -633,7 +666,7 @@ static int bcsp_recv(struct hci_uart *hu, void *data, int count) bcsp->rx_count = 4; bcsp->rx_esc_state = BCSP_ESCSTATE_NOESC; BCSP_CRC_INIT(bcsp->message_crc); - + /* Do not increment ptr or decrement count * Allocate packet. Max len of a BCSP pkt= * 0xFFF (payload) +4 (header) +2 (crc) */ @@ -698,6 +731,9 @@ static int bcsp_open(struct hci_uart *hu) bcsp->rx_state = BCSP_W4_PKT_DELIMITER; + if (txcrc) + bcsp->use_crc = 1; + return 0; } @@ -718,18 +754,19 @@ static int bcsp_close(struct hci_uart *hu) } static struct hci_uart_proto bcsp = { - .id = HCI_UART_BCSP, - .open = bcsp_open, - .close = bcsp_close, - .enqueue = bcsp_enqueue, - .dequeue = bcsp_dequeue, - .recv = bcsp_recv, - .flush = bcsp_flush + .id = HCI_UART_BCSP, + .open = bcsp_open, + .close = bcsp_close, + .enqueue = bcsp_enqueue, + .dequeue = bcsp_dequeue, + .recv = bcsp_recv, + .flush = bcsp_flush }; int bcsp_init(void) { int err = hci_uart_register_proto(&bcsp); + if (!err) BT_INFO("HCI BCSP protocol initialized"); else @@ -743,5 +780,8 @@ int bcsp_deinit(void) return hci_uart_unregister_proto(&bcsp); } +module_param(txcrc, bool, 0644); +MODULE_PARM_DESC(txcrc, "Transmit CRC with every BCSP packet"); + module_param(hciextn, bool, 0644); MODULE_PARM_DESC(hciextn, "Convert HCI Extensions into BCSP packets"); diff --git a/drivers/bluetooth/hci_bcsp.h b/drivers/bluetooth/hci_bcsp.h deleted file mode 100644 index a2b3bb92274b..000000000000 --- a/drivers/bluetooth/hci_bcsp.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - BlueCore Serial Protocol (BCSP) for Linux Bluetooth stack (BlueZ). - Copyright 2002 by Fabrizio Gennari <fabrizio.gennari@philips.com> - - Based on - hci_h4.c by Maxim Krasnyansky <maxk@qualcomm.com> - ABCSP by Carl Orsborn <cjo@csr.com> - - 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; - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. - IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY - CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - - ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, - COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS - SOFTWARE IS DISCLAIMED. -*/ - -/* - * $Id: hci_bcsp.h,v 1.2 2002/09/26 05:05:14 maxk Exp $ - */ - -#ifndef __HCI_BCSP_H__ -#define __HCI_BCSP_H__ - -#define BCSP_TXWINSIZE 4 - -#define BCSP_ACK_PKT 0x05 -#define BCSP_LE_PKT 0x06 - -struct bcsp_struct { - struct sk_buff_head unack; /* Unack'ed packets queue */ - struct sk_buff_head rel; /* Reliable packets queue */ - struct sk_buff_head unrel; /* Unreliable packets queue */ - - unsigned long rx_count; - struct sk_buff *rx_skb; - u8 rxseq_txack; /* rxseq == txack. */ - u8 rxack; /* Last packet sent by us that the peer ack'ed */ - struct timer_list tbcsp; - - enum { - BCSP_W4_PKT_DELIMITER, - BCSP_W4_PKT_START, - BCSP_W4_BCSP_HDR, - BCSP_W4_DATA, - BCSP_W4_CRC - } rx_state; - - enum { - BCSP_ESCSTATE_NOESC, - BCSP_ESCSTATE_ESC - } rx_esc_state; - - u16 message_crc; - u8 txack_req; /* Do we need to send ack's to the peer? */ - - /* Reliable packet sequence number - used to assign seq to each rel pkt. */ - u8 msgq_txseq; -}; - -#endif /* __HCI_BCSP_H__ */ diff --git a/drivers/bluetooth/hci_h4.c b/drivers/bluetooth/hci_h4.c index cf8a22d58d96..12e369a66fc2 100644 --- a/drivers/bluetooth/hci_h4.c +++ b/drivers/bluetooth/hci_h4.c @@ -1,33 +1,27 @@ -/* - BlueZ - Bluetooth protocol stack for Linux - Copyright (C) 2000-2001 Qualcomm Incorporated - - Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com> - - 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; - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. - IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY - CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - - ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, - COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS - SOFTWARE IS DISCLAIMED. -*/ - /* - * Bluetooth HCI UART(H4) protocol. * - * $Id: hci_h4.c,v 1.3 2002/09/09 01:17:32 maxk Exp $ + * Bluetooth HCI UART driver + * + * Copyright (C) 2000-2001 Qualcomm Incorporated + * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com> + * Copyright (C) 2004-2005 Marcel Holtmann <marcel@holtmann.org> + * + * + * 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 + * */ -#define VERSION "1.2" #include <linux/config.h> #include <linux/module.h> @@ -51,24 +45,41 @@ #include <net/bluetooth/bluetooth.h> #include <net/bluetooth/hci_core.h> + #include "hci_uart.h" -#include "hci_h4.h" #ifndef CONFIG_BT_HCIUART_DEBUG #undef BT_DBG #define BT_DBG( A... ) #endif +#define VERSION "1.2" + +struct h4_struct { + unsigned long rx_state; + unsigned long rx_count; + struct sk_buff *rx_skb; + struct sk_buff_head txq; +}; + +/* H4 receiver States */ +#define H4_W4_PACKET_TYPE 0 +#define H4_W4_EVENT_HDR 1 +#define H4_W4_ACL_HDR 2 +#define H4_W4_SCO_HDR 3 +#define H4_W4_DATA 4 + /* Initialize protocol */ static int h4_open(struct hci_uart *hu) { struct h4_struct *h4; - + BT_DBG("hu %p", hu); - + h4 = kmalloc(sizeof(*h4), GFP_ATOMIC); if (!h4) return -ENOMEM; + memset(h4, 0, sizeof(*h4)); skb_queue_head_init(&h4->txq); @@ -83,7 +94,9 @@ static int h4_flush(struct hci_uart *hu) struct h4_struct *h4 = hu->priv; BT_DBG("hu %p", hu); + skb_queue_purge(&h4->txq); + return 0; } @@ -91,16 +104,19 @@ static int h4_flush(struct hci_uart *hu) static int h4_close(struct hci_uart *hu) { struct h4_struct *h4 = hu->priv; + hu->priv = NULL; BT_DBG("hu %p", hu); skb_queue_purge(&h4->txq); + if (h4->rx_skb) kfree_skb(h4->rx_skb); hu->priv = NULL; kfree(h4); + return 0; } @@ -114,6 +130,7 @@ static int h4_enqueue(struct hci_uart *hu, struct sk_buff *skb) /* Prepend skb with frame type */ memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1); skb_queue_tail(&h4->txq, skb); + return 0; } @@ -122,6 +139,7 @@ static inline int h4_check_data_len(struct h4_struct *h4, int len) register int room = skb_tailroom(h4->rx_skb); BT_DBG("len %d room %d", len, room); + if (!len) { hci_recv_frame(h4->rx_skb); } else if (len > room) { @@ -136,6 +154,7 @@ static inline int h4_check_data_len(struct h4_struct *h4, int len) h4->rx_state = H4_W4_PACKET_TYPE; h4->rx_skb = NULL; h4->rx_count = 0; + return 0; } @@ -228,6 +247,7 @@ static int h4_recv(struct hci_uart *hu, void *data, int count) ptr++; count--; continue; }; + ptr++; count--; /* Allocate packet */ @@ -238,9 +258,11 @@ static int h4_recv(struct hci_uart *hu, void *data, int count) h4->rx_count = 0; return 0; } + h4->rx_skb->dev = (void *) hu->hdev; bt_cb(h4->rx_skb)->pkt_type = type; } + return count; } @@ -251,23 +273,24 @@ static struct sk_buff *h4_dequeue(struct hci_uart *hu) } static struct hci_uart_proto h4p = { - .id = HCI_UART_H4, - .open = h4_open, - .close = h4_close, - .recv = h4_recv, - .enqueue = h4_enqueue, - .dequeue = h4_dequeue, - .flush = h4_flush, + .id = HCI_UART_H4, + .open = h4_open, + .close = h4_close, + .recv = h4_recv, + .enqueue = h4_enqueue, + .dequeue = h4_dequeue, + .flush = h4_flush, }; - + int h4_init(void) { int err = hci_uart_register_proto(&h4p); + if (!err) BT_INFO("HCI H4 protocol initialized"); else BT_ERR("HCI H4 protocol registration failed"); - + return err; } diff --git a/drivers/bluetooth/hci_h4.h b/drivers/bluetooth/hci_h4.h deleted file mode 100644 index b95ff54bfd47..000000000000 --- a/drivers/bluetooth/hci_h4.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - BlueZ - Bluetooth protocol stack for Linux - Copyright (C) 2000-2001 Qualcomm Incorporated - - Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com> - - 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; - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. - IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY - CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - - ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, - COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS - SOFTWARE IS DISCLAIMED. -*/ - -/* - * $Id: hci_h4.h,v 1.2 2002/09/09 01:17:32 maxk Exp $ - */ - -#ifdef __KERNEL__ -struct h4_struct { - unsigned long rx_state; - unsigned long rx_count; - struct sk_buff *rx_skb; - struct sk_buff_head txq; -}; - -/* H4 receiver States */ -#define H4_W4_PACKET_TYPE 0 -#define H4_W4_EVENT_HDR 1 -#define H4_W4_ACL_HDR 2 -#define H4_W4_SCO_HDR 3 -#define H4_W4_DATA 4 - -#endif /* __KERNEL__ */ diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index aed80cc22890..4a775f6ea390 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -1,33 +1,27 @@ -/* - BlueZ - Bluetooth protocol stack for Linux - Copyright (C) 2000-2001 Qualcomm Incorporated - - Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com> - - 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; - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. - IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY - CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - - ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, - COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS - SOFTWARE IS DISCLAIMED. -*/ - /* - * Bluetooth HCI UART driver. * - * $Id: hci_ldisc.c,v 1.5 2002/10/02 18:37:20 maxk Exp $ + * Bluetooth HCI UART driver + * + * Copyright (C) 2000-2001 Qualcomm Incorporated + * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com> + * Copyright (C) 2004-2005 Marcel Holtmann <marcel@holtmann.org> + * + * + * 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 + * */ -#define VERSION "2.1" #include <linux/config.h> #include <linux/module.h> @@ -59,6 +53,8 @@ #define BT_DBG( A... ) #endif +#define VERSION "2.2" + static int reset = 0; static struct hci_uart_proto *hup[HCI_UART_MAX_PROTO]; @@ -72,6 +68,7 @@ int hci_uart_register_proto(struct hci_uart_proto *p) return -EEXIST; hup[p->id] = p; + return 0; } @@ -84,6 +81,7 @@ int hci_uart_unregister_proto(struct hci_uart_proto *p) return -EINVAL; hup[p->id] = NULL; + return 0; } @@ -91,13 +89,14 @@ static struct hci_uart_proto *hci_uart_get_proto(unsigned int id) { if (id >= HCI_UART_MAX_PROTO) return NULL; + return hup[id]; } static inline void hci_uart_tx_complete(struct hci_uart *hu, int pkt_type) { struct hci_dev *hdev = hu->hdev; - + /* Update HCI stat counters */ switch (pkt_type) { case HCI_COMMAND_PKT: @@ -117,10 +116,12 @@ static inline void hci_uart_tx_complete(struct hci_uart *hu, int pkt_type) static inline struct sk_buff *hci_uart_dequeue(struct hci_uart *hu) { struct sk_buff *skb = hu->tx_skb; + if (!skb) skb = hu->proto->dequeue(hu); else hu->tx_skb = NULL; + return skb; } @@ -129,7 +130,7 @@ int hci_uart_tx_wakeup(struct hci_uart *hu) struct tty_struct *tty = hu->tty; struct hci_dev *hdev = hu->hdev; struct sk_buff *skb; - + if (test_and_set_bit(HCI_UART_SENDING, &hu->tx_state)) { set_bit(HCI_UART_TX_WAKEUP, &hu->tx_state); return 0; @@ -142,7 +143,7 @@ restart: while ((skb = hci_uart_dequeue(hu))) { int len; - + set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); len = tty->driver->write(tty, skb->data, skb->len); hdev->stat.byte_tx += len; @@ -152,11 +153,11 @@ restart: hu->tx_skb = skb; break; } - + hci_uart_tx_complete(hu, bt_cb(skb)->pkt_type); kfree_skb(skb); - } - + } + if (test_bit(HCI_UART_TX_WAKEUP, &hu->tx_state)) goto restart; @@ -173,6 +174,7 @@ static int hci_uart_open(struct hci_dev *hdev) /* Nothing to do for UART driver */ set_bit(HCI_RUNNING, &hdev->flags); + return 0; } @@ -234,6 +236,7 @@ static int hci_uart_send_frame(struct sk_buff *skb) hu->proto->enqueue(hu, skb); hci_uart_tx_wakeup(hu); + return 0; } @@ -241,7 +244,8 @@ static void hci_uart_destruct(struct hci_dev *hdev) { struct hci_uart *hu; - if (!hdev) return; + if (!hdev) + return; BT_DBG("%s", hdev->name); @@ -272,6 +276,7 @@ static int hci_uart_tty_open(struct tty_struct *tty) BT_ERR("Can't allocate controll structure"); return -ENFILE; } + memset(hu, 0, sizeof(struct hci_uart)); tty->disc_data = hu; @@ -280,8 +285,10 @@ static int hci_uart_tty_open(struct tty_struct *tty) spin_lock_init(&hu->rx_lock); /* Flush any pending characters in the driver and line discipline. */ + /* FIXME: why is this needed. Note don't use ldisc_ref here as the open path is before the ldisc is referencable */ + if (tty->ldisc.flush_buffer) tty->ldisc.flush_buffer(tty); @@ -372,13 +379,13 @@ static int hci_uart_tty_room (struct tty_struct *tty) static void hci_uart_tty_receive(struct tty_struct *tty, const __u8 *data, char *flags, int count) { struct hci_uart *hu = (void *)tty->disc_data; - + if (!hu || tty != hu->tty) return; if (!test_bit(HCI_UART_PROTO_SET, &hu->flags)) return; - + spin_lock(&hu->rx_lock); hu->proto->recv(hu, (void *) data, count); hu->hdev->stat.byte_rx += count; @@ -429,8 +436,8 @@ static int hci_uart_register_dev(struct hci_uart *hu) static int hci_uart_set_proto(struct hci_uart *hu, int id) { struct hci_uart_proto *p; - int err; - + int err; + p = hci_uart_get_proto(id); if (!p) return -EPROTONOSUPPORT; @@ -446,6 +453,7 @@ static int hci_uart_set_proto(struct hci_uart *hu, int id) p->close(hu); return err; } + return 0; } @@ -463,7 +471,7 @@ static int hci_uart_set_proto(struct hci_uart *hu, int id) * Return Value: Command dependent */ static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file * file, - unsigned int cmd, unsigned long arg) + unsigned int cmd, unsigned long arg) { struct hci_uart *hu = (void *)tty->disc_data; int err = 0; @@ -483,14 +491,14 @@ static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file * file, return err; } tty->low_latency = 1; - } else + } else return -EBUSY; case HCIUARTGETPROTO: if (test_bit(HCI_UART_PROTO_SET, &hu->flags)) return hu->proto->id; return -EUNATCH; - + default: err = n_tty_ioctl(tty, file, cmd, arg); break; @@ -502,28 +510,24 @@ static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file * file, /* * We don't provide read/write/poll interface for user space. */ -static ssize_t hci_uart_tty_read(struct tty_struct *tty, struct file *file, unsigned char __user *buf, size_t nr) +static ssize_t hci_uart_tty_read(struct tty_struct *tty, struct file *file, + unsigned char __user *buf, size_t nr) { return 0; } -static ssize_t hci_uart_tty_write(struct tty_struct *tty, struct file *file, const unsigned char *data, size_t count) + +static ssize_t hci_uart_tty_write(struct tty_struct *tty, struct file *file, + const unsigned char *data, size_t count) { return 0; } -static unsigned int hci_uart_tty_poll(struct tty_struct *tty, struct file *filp, poll_table *wait) + +static unsigned int hci_uart_tty_poll(struct tty_struct *tty, + struct file *filp, poll_table *wait) { return 0; } -#ifdef CONFIG_BT_HCIUART_H4 -int h4_init(void); -int h4_deinit(void); -#endif -#ifdef CONFIG_BT_HCIUART_BCSP -int bcsp_init(void); -int bcsp_deinit(void); -#endif - static int __init hci_uart_init(void) { static struct tty_ldisc hci_uart_ldisc; @@ -534,18 +538,18 @@ static int __init hci_uart_init(void) /* Register the tty discipline */ memset(&hci_uart_ldisc, 0, sizeof (hci_uart_ldisc)); - hci_uart_ldisc.magic = TTY_LDISC_MAGIC; - hci_uart_ldisc.name = "n_hci"; - hci_uart_ldisc.open = hci_uart_tty_open; - hci_uart_ldisc.close = hci_uart_tty_close; - hci_uart_ldisc.read = hci_uart_tty_read; - hci_uart_ldisc.write = hci_uart_tty_write; - hci_uart_ldisc.ioctl = hci_uart_tty_ioctl; - hci_uart_ldisc.poll = hci_uart_tty_poll; - hci_uart_ldisc.receive_room= hci_uart_tty_room; - hci_uart_ldisc.receive_buf = hci_uart_tty_receive; - hci_uart_ldisc.write_wakeup= hci_uart_tty_wakeup; - hci_uart_ldisc.owner = THIS_MODULE; + hci_uart_ldisc.magic = TTY_LDISC_MAGIC; + hci_uart_ldisc.name = "n_hci"; + hci_uart_ldisc.open = hci_uart_tty_open; + hci_uart_ldisc.close = hci_uart_tty_close; + hci_uart_ldisc.read = hci_uart_tty_read; + hci_uart_ldisc.write = hci_uart_tty_write; + hci_uart_ldisc.ioctl = hci_uart_tty_ioctl; + hci_uart_ldisc.poll = hci_uart_tty_poll; + hci_uart_ldisc.receive_room = hci_uart_tty_room; + hci_uart_ldisc.receive_buf = hci_uart_tty_receive; + hci_uart_ldisc.write_wakeup = hci_uart_tty_wakeup; + hci_uart_ldisc.owner = THIS_MODULE; if ((err = tty_register_ldisc(N_HCI, &hci_uart_ldisc))) { BT_ERR("HCI line discipline registration failed. (%d)", err); diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h index 0a57d72790ec..b250e6789dee 100644 --- a/drivers/bluetooth/hci_uart.h +++ b/drivers/bluetooth/hci_uart.h @@ -1,32 +1,29 @@ -/* - BlueZ - Bluetooth protocol stack for Linux - Copyright (C) 2000-2001 Qualcomm Incorporated - - Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com> - - 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; - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. - IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY - CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - - ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, - COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS - SOFTWARE IS DISCLAIMED. -*/ - /* - * $Id: hci_uart.h,v 1.2 2002/09/09 01:17:32 maxk Exp $ + * + * Bluetooth HCI UART driver + * + * Copyright (C) 2000-2001 Qualcomm Incorporated + * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com> + * Copyright (C) 2004-2005 Marcel Holtmann <marcel@holtmann.org> + * + * + * 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 + * */ -#ifndef N_HCI +#ifndef N_HCI #define N_HCI 15 #endif @@ -42,7 +39,6 @@ #define HCI_UART_3WIRE 2 #define HCI_UART_H4DS 3 -#ifdef __KERNEL__ struct hci_uart; struct hci_uart_proto { @@ -56,27 +52,35 @@ struct hci_uart_proto { }; struct hci_uart { - struct tty_struct *tty; - struct hci_dev *hdev; - unsigned long flags; + struct tty_struct *tty; + struct hci_dev *hdev; + unsigned long flags; - struct hci_uart_proto *proto; - void *priv; - - struct sk_buff *tx_skb; - unsigned long tx_state; - spinlock_t rx_lock; + struct hci_uart_proto *proto; + void *priv; + + struct sk_buff *tx_skb; + unsigned long tx_state; + spinlock_t rx_lock; }; /* HCI_UART flag bits */ -#define HCI_UART_PROTO_SET 0 +#define HCI_UART_PROTO_SET 0 /* TX states */ -#define HCI_UART_SENDING 1 -#define HCI_UART_TX_WAKEUP 2 +#define HCI_UART_SENDING 1 +#define HCI_UART_TX_WAKEUP 2 int hci_uart_register_proto(struct hci_uart_proto *p); int hci_uart_unregister_proto(struct hci_uart_proto *p); int hci_uart_tx_wakeup(struct hci_uart *hu); -#endif /* __KERNEL__ */ +#ifdef CONFIG_BT_HCIUART_H4 +int h4_init(void); +int h4_deinit(void); +#endif + +#ifdef CONFIG_BT_HCIUART_BCSP +int bcsp_init(void); +int bcsp_deinit(void); +#endif diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index c29365d5b524..fdf4370db994 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -661,7 +661,7 @@ config HW_RANDOM config NVRAM tristate "/dev/nvram support" - depends on ATARI || X86 || X86_64 || ARM || GENERIC_NVRAM + depends on ATARI || X86 || ARM || GENERIC_NVRAM ---help--- If you say Y here and create a character special file /dev/nvram with major number 10 and minor number 144 using mknod ("man mknod"), @@ -985,7 +985,7 @@ config MAX_RAW_DEVS config HANGCHECK_TIMER tristate "Hangcheck timer" - depends on X86_64 || X86 || IA64 || PPC64 || ARCH_S390 + depends on X86 || IA64 || PPC64 || ARCH_S390 help The hangcheck-timer module detects when the system has gone out to lunch past a certain margin. It can reboot the system @@ -1001,5 +1001,17 @@ config MMTIMER source "drivers/char/tpm/Kconfig" +config TELCLOCK + tristate "Telecom clock driver for MPBL0010 ATCA SBC" + depends on EXPERIMENTAL + default n + help + The telecom clock device is specific to the MPBL0010 ATCA computer and + allows direct userspace access to the configuration of the telecom clock + configuration settings. This device is used for hardware synchronization + across the ATCA backplane fabric. Upon loading, the driver exports a + sysfs directory, /sys/devices/platform/telco_clock, with a number of + files for controlling the behavior of this hardware. + endmenu diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 08f69287ea36..4aeae687e88a 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -82,6 +82,7 @@ obj-$(CONFIG_NWFLASH) += nwflash.o obj-$(CONFIG_SCx200_GPIO) += scx200_gpio.o obj-$(CONFIG_GPIO_VR41XX) += vr41xx_giu.o obj-$(CONFIG_TANBAC_TB0219) += tb0219.o +obj-$(CONFIG_TELCLOCK) += tlclk.o obj-$(CONFIG_WATCHDOG) += watchdog/ obj-$(CONFIG_MWAVE) += mwave/ diff --git a/drivers/char/agp/Kconfig b/drivers/char/agp/Kconfig index 7f8c1b53b754..486ed8a11b59 100644 --- a/drivers/char/agp/Kconfig +++ b/drivers/char/agp/Kconfig @@ -27,7 +27,7 @@ config AGP config AGP_ALI tristate "ALI chipset support" - depends on AGP && X86 && !X86_64 + depends on AGP && X86_32 ---help--- This option gives you AGP support for the GLX component of XFree86 4.x on the following ALi chipsets. The supported chipsets @@ -45,7 +45,7 @@ config AGP_ALI config AGP_ATI tristate "ATI chipset support" - depends on AGP && X86 && !X86_64 + depends on AGP && X86_32 ---help--- This option gives you AGP support for the GLX component of XFree86 4.x on the ATI RadeonIGP family of chipsets. @@ -55,7 +55,7 @@ config AGP_ATI config AGP_AMD tristate "AMD Irongate, 761, and 762 chipset support" - depends on AGP && X86 && !X86_64 + depends on AGP && X86_32 help This option gives you AGP support for the GLX component of XFree86 4.x on AMD Irongate, 761, and 762 chipsets. @@ -91,7 +91,7 @@ config AGP_INTEL config AGP_NVIDIA tristate "NVIDIA nForce/nForce2 chipset support" - depends on AGP && X86 && !X86_64 + depends on AGP && X86_32 help This option gives you AGP support for the GLX component of XFree86 4.x on the following NVIDIA chipsets. The supported chipsets @@ -99,7 +99,7 @@ config AGP_NVIDIA config AGP_SIS tristate "SiS chipset support" - depends on AGP && X86 && !X86_64 + depends on AGP && X86_32 help This option gives you AGP support for the GLX component of XFree86 4.x on Silicon Integrated Systems [SiS] chipsets. @@ -111,14 +111,14 @@ config AGP_SIS config AGP_SWORKS tristate "Serverworks LE/HE chipset support" - depends on AGP && X86 && !X86_64 + depends on AGP && X86_32 help Say Y here to support the Serverworks AGP card. See <http://www.serverworks.com/> for product descriptions and images. config AGP_VIA tristate "VIA chipset support" - depends on AGP && X86 && !X86_64 + depends on AGP && X86_32 help This option gives you AGP support for the GLX component of XFree86 4.x on VIA MVP3/Apollo Pro chipsets. @@ -154,7 +154,7 @@ config AGP_UNINORTH config AGP_EFFICEON tristate "Transmeta Efficeon support" - depends on AGP && X86 && !X86_64 + depends on AGP && X86_32 help This option gives you AGP support for the Transmeta Efficeon series processors with integrated northbridges. diff --git a/drivers/char/agp/ali-agp.c b/drivers/char/agp/ali-agp.c index 9c9c9c2247ce..b02fc2267159 100644 --- a/drivers/char/agp/ali-agp.c +++ b/drivers/char/agp/ali-agp.c @@ -7,6 +7,7 @@ #include <linux/pci.h> #include <linux/init.h> #include <linux/agp_backend.h> +#include <asm/page.h> /* PAGE_SIZE */ #include "agp.h" #define ALI_AGPCTRL 0xb8 diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c index 0a7624a9b1c1..0e6c3a31d344 100644 --- a/drivers/char/agp/amd64-agp.c +++ b/drivers/char/agp/amd64-agp.c @@ -13,6 +13,7 @@ #include <linux/pci.h> #include <linux/init.h> #include <linux/agp_backend.h> +#include <asm/page.h> /* PAGE_SIZE */ #include "agp.h" /* Will need to be increased if AMD64 ever goes >8-way. */ diff --git a/drivers/char/agp/ati-agp.c b/drivers/char/agp/ati-agp.c index e572ced9100a..0b6e72642d6e 100644 --- a/drivers/char/agp/ati-agp.c +++ b/drivers/char/agp/ati-agp.c @@ -6,6 +6,8 @@ #include <linux/module.h> #include <linux/pci.h> #include <linux/init.h> +#include <linux/string.h> +#include <linux/slab.h> #include <linux/agp_backend.h> #include <asm/agp.h> #include "agp.h" diff --git a/drivers/char/agp/i460-agp.c b/drivers/char/agp/i460-agp.c index 94943298c03e..a2d9e5e48bbe 100644 --- a/drivers/char/agp/i460-agp.c +++ b/drivers/char/agp/i460-agp.c @@ -10,6 +10,8 @@ #include <linux/module.h> #include <linux/pci.h> #include <linux/init.h> +#include <linux/string.h> +#include <linux/slab.h> #include <linux/agp_backend.h> #include "agp.h" diff --git a/drivers/char/agp/isoch.c b/drivers/char/agp/isoch.c index c9ac731504f2..40083241804e 100644 --- a/drivers/char/agp/isoch.c +++ b/drivers/char/agp/isoch.c @@ -6,6 +6,7 @@ #include <linux/pci.h> #include <linux/agp_backend.h> #include <linux/module.h> +#include <linux/slab.h> #include "agp.h" diff --git a/drivers/char/agp/sgi-agp.c b/drivers/char/agp/sgi-agp.c index d3aa159c9dec..7957fc91f6ad 100644 --- a/drivers/char/agp/sgi-agp.c +++ b/drivers/char/agp/sgi-agp.c @@ -17,6 +17,7 @@ #include <linux/init.h> #include <linux/agp_backend.h> #include <asm/sn/addrs.h> +#include <asm/sn/io.h> #include <asm/sn/pcidev.h> #include <asm/sn/pcibus_provider_defs.h> #include <asm/sn/tioca_provider.h> diff --git a/drivers/char/agp/sworks-agp.c b/drivers/char/agp/sworks-agp.c index a9fb12c20eb7..71ea59a1dbeb 100644 --- a/drivers/char/agp/sworks-agp.c +++ b/drivers/char/agp/sworks-agp.c @@ -5,6 +5,8 @@ #include <linux/module.h> #include <linux/pci.h> #include <linux/init.h> +#include <linux/string.h> +#include <linux/slab.h> #include <linux/agp_backend.h> #include "agp.h" diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c index cf4c3648463d..c7f818cd7b02 100644 --- a/drivers/char/cyclades.c +++ b/drivers/char/cyclades.c @@ -281,7 +281,7 @@ static char rcsid[] = * make sure "cyc" appears in all kernel messages; all soft interrupts * handled by same routine; recognize out-of-band reception; comment * out some diagnostic messages; leave RTS/CTS flow control to hardware; - * fix race condition in -Z buffer management; only -Y needs to explictly + * fix race condition in -Z buffer management; only -Y needs to explicitly * flush chars; tidy up some startup messages; * * Revision 1.36.4.18 1996/07/25 18:57:31 bentson diff --git a/drivers/char/drm/drm_sysfs.c b/drivers/char/drm/drm_sysfs.c index 475cc5e555e1..6d3449761914 100644 --- a/drivers/char/drm/drm_sysfs.c +++ b/drivers/char/drm/drm_sysfs.c @@ -15,6 +15,8 @@ #include <linux/device.h> #include <linux/kdev_t.h> #include <linux/err.h> +#include <linux/slab.h> +#include <linux/string.h> #include "drm_core.h" #include "drmP.h" diff --git a/drivers/char/dsp56k.c b/drivers/char/dsp56k.c index 26271e3ca823..8693835cb2d5 100644 --- a/drivers/char/dsp56k.c +++ b/drivers/char/dsp56k.c @@ -515,7 +515,7 @@ static int __init dsp56k_init_driver(void) err = PTR_ERR(dsp56k_class); goto out_chrdev; } - class_device_create(dsp56k_class, MKDEV(DSP56K_MAJOR, 0), NULL, "dsp56k"); + class_device_create(dsp56k_class, NULL, MKDEV(DSP56K_MAJOR, 0), NULL, "dsp56k"); err = devfs_mk_cdev(MKDEV(DSP56K_MAJOR, 0), S_IFCHR | S_IRUSR | S_IWUSR, "dsp56k"); diff --git a/drivers/char/epca.c b/drivers/char/epca.c index 407708a001e4..b7a0e4d6b934 100644 --- a/drivers/char/epca.c +++ b/drivers/char/epca.c @@ -3113,6 +3113,7 @@ MODULE_DEVICE_TABLE(pci, epca_pci_tbl); int __init init_PCI (void) { /* Begin init_PCI */ memset (&epca_driver, 0, sizeof (epca_driver)); + epca_driver.owner = THIS_MODULE; epca_driver.name = "epca"; epca_driver.id_table = epca_pci_tbl; epca_driver.probe = epca_init_one; diff --git a/drivers/char/ftape/zftape/zftape-init.c b/drivers/char/ftape/zftape/zftape-init.c index 5745b74044ec..821357ce7e0e 100644 --- a/drivers/char/ftape/zftape/zftape-init.c +++ b/drivers/char/ftape/zftape/zftape-init.c @@ -331,27 +331,27 @@ KERN_INFO zft_class = class_create(THIS_MODULE, "zft"); for (i = 0; i < 4; i++) { - class_device_create(zft_class, MKDEV(QIC117_TAPE_MAJOR, i), NULL, "qft%i", i); + class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i), NULL, "qft%i", i); devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i), S_IFCHR | S_IRUSR | S_IWUSR, "qft%i", i); - class_device_create(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 4), NULL, "nqft%i", i); + class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i + 4), NULL, "nqft%i", i); devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i + 4), S_IFCHR | S_IRUSR | S_IWUSR, "nqft%i", i); - class_device_create(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 16), NULL, "zqft%i", i); + class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i + 16), NULL, "zqft%i", i); devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i + 16), S_IFCHR | S_IRUSR | S_IWUSR, "zqft%i", i); - class_device_create(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 20), NULL, "nzqft%i", i); + class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i + 20), NULL, "nzqft%i", i); devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i + 20), S_IFCHR | S_IRUSR | S_IWUSR, "nzqft%i", i); - class_device_create(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 32), NULL, "rawqft%i", i); + class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i + 32), NULL, "rawqft%i", i); devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i + 32), S_IFCHR | S_IRUSR | S_IWUSR, "rawqft%i", i); - class_device_create(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 36), NULL, "nrawrawqft%i", i); + class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i + 36), NULL, "nrawrawqft%i", i); devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i + 36), S_IFCHR | S_IRUSR | S_IWUSR, "nrawqft%i", i); diff --git a/drivers/char/hangcheck-timer.c b/drivers/char/hangcheck-timer.c index a54bc93353af..66e53dd450ff 100644 --- a/drivers/char/hangcheck-timer.c +++ b/drivers/char/hangcheck-timer.c @@ -117,7 +117,7 @@ __setup("hcheck_reboot", hangcheck_parse_reboot); __setup("hcheck_dump_tasks", hangcheck_parse_dump_tasks); #endif /* not MODULE */ -#if defined(CONFIG_X86) || defined(CONFIG_X86_64) +#if defined(CONFIG_X86) # define HAVE_MONOTONIC # define TIMER_FREQ 1000000000ULL #elif defined(CONFIG_ARCH_S390) diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c index c055bb630ffc..3808d9572619 100644 --- a/drivers/char/hpet.c +++ b/drivers/char/hpet.c @@ -49,7 +49,9 @@ #define HPET_USER_FREQ (64) #define HPET_DRIFT (500) -static u32 hpet_ntimer, hpet_nhpet, hpet_max_freq = HPET_USER_FREQ; +#define HPET_RANGE_SIZE 1024 /* from HPET spec */ + +static u32 hpet_nhpet, hpet_max_freq = HPET_USER_FREQ; /* A lock for concurrent access by app and isr hpet activity. */ static DEFINE_SPINLOCK(hpet_lock); @@ -78,7 +80,7 @@ struct hpets { struct hpet __iomem *hp_hpet; unsigned long hp_hpet_phys; struct time_interpolator *hp_interpolator; - unsigned long hp_period; + unsigned long long hp_tick_freq; unsigned long hp_delta; unsigned int hp_ntimer; unsigned int hp_which; @@ -90,6 +92,7 @@ static struct hpets *hpets; #define HPET_OPEN 0x0001 #define HPET_IE 0x0002 /* interrupt enabled */ #define HPET_PERIODIC 0x0004 +#define HPET_SHARED_IRQ 0x0008 #if BITS_PER_LONG == 64 #define write_counter(V, MC) writeq(V, MC) @@ -120,6 +123,11 @@ static irqreturn_t hpet_interrupt(int irq, void *data, struct pt_regs *regs) unsigned long isr; devp = data; + isr = 1 << (devp - devp->hd_hpets->hp_dev); + + if ((devp->hd_flags & HPET_SHARED_IRQ) && + !(isr & readl(&devp->hd_hpet->hpet_isr))) + return IRQ_NONE; spin_lock(&hpet_lock); devp->hd_irqdata++; @@ -137,8 +145,8 @@ static irqreturn_t hpet_interrupt(int irq, void *data, struct pt_regs *regs) &devp->hd_timer->hpet_compare); } - isr = (1 << (devp - devp->hd_hpets->hp_dev)); - writeq(isr, &devp->hd_hpet->hpet_isr); + if (devp->hd_flags & HPET_SHARED_IRQ) + writel(isr, &devp->hd_hpet->hpet_isr); spin_unlock(&hpet_lock); spin_lock(&hpet_task_lock); @@ -276,7 +284,8 @@ static int hpet_mmap(struct file *file, struct vm_area_struct *vma) if (io_remap_pfn_range(vma, vma->vm_start, addr >> PAGE_SHIFT, PAGE_SIZE, vma->vm_page_prot)) { - printk(KERN_ERR "remap_pfn_range failed in hpet.c\n"); + printk(KERN_ERR "%s: io_remap_pfn_range failed\n", + __FUNCTION__); return -EAGAIN; } @@ -364,7 +373,9 @@ static int hpet_ioctl_ieon(struct hpet_dev *devp) hpet = devp->hd_hpet; hpetp = devp->hd_hpets; - v = readq(&timer->hpet_config); + if (!devp->hd_ireqfreq) + return -EIO; + spin_lock_irq(&hpet_lock); if (devp->hd_flags & HPET_IE) { @@ -373,16 +384,21 @@ static int hpet_ioctl_ieon(struct hpet_dev *devp) } devp->hd_flags |= HPET_IE; + + if (readl(&timer->hpet_config) & Tn_INT_TYPE_CNF_MASK) + devp->hd_flags |= HPET_SHARED_IRQ; spin_unlock_irq(&hpet_lock); - t = readq(&timer->hpet_config); irq = devp->hd_hdwirq; if (irq) { - sprintf(devp->hd_name, "hpet%d", (int)(devp - hpetp->hp_dev)); + unsigned long irq_flags; - if (request_irq - (irq, hpet_interrupt, SA_INTERRUPT, devp->hd_name, (void *)devp)) { + sprintf(devp->hd_name, "hpet%d", (int)(devp - hpetp->hp_dev)); + irq_flags = devp->hd_flags & HPET_SHARED_IRQ + ? SA_SHIRQ : SA_INTERRUPT; + if (request_irq(irq, hpet_interrupt, irq_flags, + devp->hd_name, (void *)devp)) { printk(KERN_ERR "hpet: IRQ %d is not free\n", irq); irq = 0; } @@ -416,20 +432,24 @@ static int hpet_ioctl_ieon(struct hpet_dev *devp) write_counter(t + m + hpetp->hp_delta, &timer->hpet_compare); } - isr = (1 << (devp - hpets->hp_dev)); - writeq(isr, &hpet->hpet_isr); + if (devp->hd_flags & HPET_SHARED_IRQ) { + isr = 1 << (devp - devp->hd_hpets->hp_dev); + writel(isr, &hpet->hpet_isr); + } writeq(g, &timer->hpet_config); local_irq_restore(flags); return 0; } -static inline unsigned long hpet_time_div(unsigned long dis) +/* converts Hz to number of timer ticks */ +static inline unsigned long hpet_time_div(struct hpets *hpets, + unsigned long dis) { - unsigned long long m = 1000000000000000ULL; + unsigned long long m; + m = hpets->hp_tick_freq + (dis >> 1); do_div(m, dis); - return (unsigned long)m; } @@ -477,14 +497,21 @@ hpet_ioctl_common(struct hpet_dev *devp, int cmd, unsigned long arg, int kernel) { struct hpet_info info; - info.hi_ireqfreq = hpet_time_div(hpetp->hp_period * - devp->hd_ireqfreq); + if (devp->hd_ireqfreq) + info.hi_ireqfreq = + hpet_time_div(hpetp, devp->hd_ireqfreq); + else + info.hi_ireqfreq = 0; info.hi_flags = readq(&timer->hpet_config) & Tn_PER_INT_CAP_MASK; - info.hi_hpet = devp->hd_hpets->hp_which; - info.hi_timer = devp - devp->hd_hpets->hp_dev; - if (copy_to_user((void __user *)arg, &info, sizeof(info))) - err = -EFAULT; + info.hi_hpet = hpetp->hp_which; + info.hi_timer = devp - hpetp->hp_dev; + if (kernel) + memcpy((void *)arg, &info, sizeof(info)); + else + if (copy_to_user((void __user *)arg, &info, + sizeof(info))) + err = -EFAULT; break; } case HPET_EPI: @@ -516,12 +543,12 @@ hpet_ioctl_common(struct hpet_dev *devp, int cmd, unsigned long arg, int kernel) break; } - if (arg & (arg - 1)) { + if (!arg) { err = -EINVAL; break; } - devp->hd_ireqfreq = hpet_time_div(hpetp->hp_period * arg); + devp->hd_ireqfreq = hpet_time_div(hpetp, arg); } return err; @@ -539,6 +566,17 @@ static struct file_operations hpet_fops = { .mmap = hpet_mmap, }; +static int hpet_is_known(struct hpet_data *hdp) +{ + struct hpets *hpetp; + + for (hpetp = hpets; hpetp; hpetp = hpetp->hp_next) + if (hpetp->hp_hpet_phys == hdp->hd_phys_address) + return 1; + + return 0; +} + EXPORT_SYMBOL(hpet_alloc); EXPORT_SYMBOL(hpet_register); EXPORT_SYMBOL(hpet_unregister); @@ -563,6 +601,8 @@ int hpet_register(struct hpet_task *tp, int periodic) return -EINVAL; } + tp->ht_opaque = NULL; + spin_lock_irq(&hpet_task_lock); spin_lock(&hpet_lock); @@ -702,15 +742,14 @@ static void hpet_register_interpolator(struct hpets *hpetp) #ifdef CONFIG_TIME_INTERPOLATION struct time_interpolator *ti; - ti = kmalloc(sizeof(*ti), GFP_KERNEL); + ti = kzalloc(sizeof(*ti), GFP_KERNEL); if (!ti) return; - memset(ti, 0, sizeof(*ti)); ti->source = TIME_SOURCE_MMIO64; ti->shift = 10; ti->addr = &hpetp->hp_hpet->hpet_mc; - ti->frequency = hpet_time_div(hpets->hp_period); + ti->frequency = hpetp->hp_tick_freq; ti->drift = HPET_DRIFT; ti->mask = -1; @@ -743,11 +782,11 @@ static unsigned long hpet_calibrate(struct hpets *hpetp) if (!timer) return 0; - hpet = hpets->hp_hpet; + hpet = hpetp->hp_hpet; t = read_counter(&timer->hpet_compare); i = 0; - count = hpet_time_div(hpetp->hp_period * TICK_CALIBRATE); + count = hpet_time_div(hpetp, TICK_CALIBRATE); local_irq_save(flags); @@ -771,28 +810,29 @@ int hpet_alloc(struct hpet_data *hdp) struct hpets *hpetp; size_t siz; struct hpet __iomem *hpet; - static struct hpets *last = (struct hpets *)0; - unsigned long ns; + static struct hpets *last = NULL; + unsigned long period; + unsigned long long temp; /* * hpet_alloc can be called by platform dependent code. - * if platform dependent code has allocated the hpet - * ACPI also reports hpet, then we catch it here. + * If platform dependent code has allocated the hpet that + * ACPI has also reported, then we catch it here. */ - for (hpetp = hpets; hpetp; hpetp = hpetp->hp_next) - if (hpetp->hp_hpet == hdp->hd_address) - return 0; + if (hpet_is_known(hdp)) { + printk(KERN_DEBUG "%s: duplicate HPET ignored\n", + __FUNCTION__); + return 0; + } siz = sizeof(struct hpets) + ((hdp->hd_nirqs - 1) * sizeof(struct hpet_dev)); - hpetp = kmalloc(siz, GFP_KERNEL); + hpetp = kzalloc(siz, GFP_KERNEL); if (!hpetp) return -ENOMEM; - memset(hpetp, 0, siz); - hpetp->hp_which = hpet_nhpet++; hpetp->hp_hpet = hdp->hd_address; hpetp->hp_hpet_phys = hdp->hd_phys_address; @@ -822,21 +862,23 @@ int hpet_alloc(struct hpet_data *hdp) last = hpetp; - hpetp->hp_period = (cap & HPET_COUNTER_CLK_PERIOD_MASK) >> - HPET_COUNTER_CLK_PERIOD_SHIFT; + period = (cap & HPET_COUNTER_CLK_PERIOD_MASK) >> + HPET_COUNTER_CLK_PERIOD_SHIFT; /* fs, 10^-15 */ + temp = 1000000000000000uLL; /* 10^15 femtoseconds per second */ + temp += period >> 1; /* round */ + do_div(temp, period); + hpetp->hp_tick_freq = temp; /* ticks per second */ - printk(KERN_INFO "hpet%d: at MMIO 0x%lx, IRQ%s", - hpetp->hp_which, hdp->hd_phys_address, + printk(KERN_INFO "hpet%d: at MMIO 0x%lx (virtual 0x%p), IRQ%s", + hpetp->hp_which, hdp->hd_phys_address, hdp->hd_address, hpetp->hp_ntimer > 1 ? "s" : ""); for (i = 0; i < hpetp->hp_ntimer; i++) printk("%s %d", i > 0 ? "," : "", hdp->hd_irq[i]); printk("\n"); - ns = hpetp->hp_period; /* femptoseconds, 10^-15 */ - ns /= 1000000; /* convert to nanoseconds, 10^-9 */ - printk(KERN_INFO "hpet%d: %ldns tick, %d %d-bit timers\n", - hpetp->hp_which, ns, hpetp->hp_ntimer, - cap & HPET_COUNTER_SIZE_MASK ? 64 : 32); + printk(KERN_INFO "hpet%u: %u %d-bit timers, %Lu Hz\n", + hpetp->hp_which, hpetp->hp_ntimer, + cap & HPET_COUNTER_SIZE_MASK ? 64 : 32, hpetp->hp_tick_freq); mcfg = readq(&hpet->hpet_config); if ((mcfg & HPET_ENABLE_CNF_MASK) == 0) { @@ -845,13 +887,10 @@ int hpet_alloc(struct hpet_data *hdp) writeq(mcfg, &hpet->hpet_config); } - for (i = 0, devp = hpetp->hp_dev; i < hpetp->hp_ntimer; - i++, hpet_ntimer++, devp++) { - unsigned long v; + for (i = 0, devp = hpetp->hp_dev; i < hpetp->hp_ntimer; i++, devp++) { struct hpet_timer __iomem *timer; timer = &hpet->hpet_timers[devp - hpetp->hp_dev]; - v = readq(&timer->hpet_config); devp->hd_hpets = hpetp; devp->hd_hpet = hpet; @@ -880,7 +919,6 @@ static acpi_status hpet_resources(struct acpi_resource *res, void *data) struct hpet_data *hdp; acpi_status status; struct acpi_resource_address64 addr; - struct hpets *hpetp; hdp = data; @@ -893,9 +931,29 @@ static acpi_status hpet_resources(struct acpi_resource *res, void *data) hdp->hd_phys_address = addr.min_address_range; hdp->hd_address = ioremap(addr.min_address_range, size); - for (hpetp = hpets; hpetp; hpetp = hpetp->hp_next) - if (hpetp->hp_hpet == hdp->hd_address) - return -EBUSY; + if (hpet_is_known(hdp)) { + printk(KERN_DEBUG "%s: 0x%lx is busy\n", + __FUNCTION__, hdp->hd_phys_address); + iounmap(hdp->hd_address); + return -EBUSY; + } + } else if (res->id == ACPI_RSTYPE_FIXED_MEM32) { + struct acpi_resource_fixed_mem32 *fixmem32; + + fixmem32 = &res->data.fixed_memory32; + if (!fixmem32) + return -EINVAL; + + hdp->hd_phys_address = fixmem32->range_base_address; + hdp->hd_address = ioremap(fixmem32->range_base_address, + HPET_RANGE_SIZE); + + if (hpet_is_known(hdp)) { + printk(KERN_DEBUG "%s: 0x%lx is busy\n", + __FUNCTION__, hdp->hd_phys_address); + iounmap(hdp->hd_address); + return -EBUSY; + } } else if (res->id == ACPI_RSTYPE_EXT_IRQ) { struct acpi_resource_ext_irq *irqp; int i; diff --git a/drivers/char/ip2main.c b/drivers/char/ip2main.c index 9e4e26aef94e..d815d197dc3e 100644 --- a/drivers/char/ip2main.c +++ b/drivers/char/ip2main.c @@ -721,8 +721,9 @@ ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize) } if ( NULL != ( pB = i2BoardPtrTable[i] ) ) { - class_device_create(ip2_class, MKDEV(IP2_IPL_MAJOR, - 4 * i), NULL, "ipl%d", i); + class_device_create(ip2_class, NULL, + MKDEV(IP2_IPL_MAJOR, 4 * i), + NULL, "ipl%d", i); err = devfs_mk_cdev(MKDEV(IP2_IPL_MAJOR, 4 * i), S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR, "ip2/ipl%d", i); @@ -732,8 +733,9 @@ ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize) goto out_class; } - class_device_create(ip2_class, MKDEV(IP2_IPL_MAJOR, - 4 * i + 1), NULL, "stat%d", i); + class_device_create(ip2_class, NULL, + MKDEV(IP2_IPL_MAJOR, 4 * i + 1), + NULL, "stat%d", i); err = devfs_mk_cdev(MKDEV(IP2_IPL_MAJOR, 4 * i + 1), S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR, "ip2/stat%d", i); diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c index a09ff1080687..7c0684deea06 100644 --- a/drivers/char/ipmi/ipmi_devintf.c +++ b/drivers/char/ipmi/ipmi_devintf.c @@ -798,7 +798,7 @@ static void ipmi_new_smi(int if_num) devfs_mk_cdev(dev, S_IFCHR | S_IRUSR | S_IWUSR, "ipmidev/%d", if_num); - class_device_create(ipmi_class, dev, NULL, "ipmi%d", if_num); + class_device_create(ipmi_class, NULL, dev, NULL, "ipmi%d", if_num); } static void ipmi_smi_gone(int if_num) diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c index 9c19e5435a11..e3ddbdb85a2f 100644 --- a/drivers/char/istallion.c +++ b/drivers/char/istallion.c @@ -5246,7 +5246,8 @@ int __init stli_init(void) devfs_mk_cdev(MKDEV(STL_SIOMEMMAJOR, i), S_IFCHR | S_IRUSR | S_IWUSR, "staliomem/%d", i); - class_device_create(istallion_class, MKDEV(STL_SIOMEMMAJOR, i), + class_device_create(istallion_class, NULL, + MKDEV(STL_SIOMEMMAJOR, i), NULL, "staliomem%d", i); } diff --git a/drivers/char/lcd.c b/drivers/char/lcd.c index b77161146144..29963d8be667 100644 --- a/drivers/char/lcd.c +++ b/drivers/char/lcd.c @@ -575,8 +575,8 @@ static inline int button_pressed(void) static int lcd_waiters = 0; -static long lcd_read(struct inode *inode, struct file *file, char *buf, - unsigned long count) +static ssize_t lcd_read(struct file *file, char *buf, + size_t count, loff_t *ofs) { long buttons_now; diff --git a/drivers/char/lcd.h b/drivers/char/lcd.h index 878a95280e87..a8d4ae737158 100644 --- a/drivers/char/lcd.h +++ b/drivers/char/lcd.h @@ -22,7 +22,7 @@ static int timeout(volatile unsigned long); #define MAX_IDLE_TIME 120 struct lcd_display { - unsigned long buttons; + unsigned buttons; int size1; int size2; unsigned char line1[LCD_CHARS_PER_LINE]; diff --git a/drivers/char/lp.c b/drivers/char/lp.c index 2afb9038dbc5..e57260525293 100644 --- a/drivers/char/lp.c +++ b/drivers/char/lp.c @@ -805,7 +805,7 @@ static int lp_register(int nr, struct parport *port) if (reset) lp_reset(nr); - class_device_create(lp_class, MKDEV(LP_MAJOR, nr), NULL, + class_device_create(lp_class, NULL, MKDEV(LP_MAJOR, nr), NULL, "lp%d", nr); devfs_mk_cdev(MKDEV(LP_MAJOR, nr), S_IFCHR | S_IRUGO | S_IWUGO, "printers/%d", nr); diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 9df928d4f68d..91dd669273e0 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -918,7 +918,8 @@ static int __init chr_dev_init(void) mem_class = class_create(THIS_MODULE, "mem"); for (i = 0; i < ARRAY_SIZE(devlist); i++) { - class_device_create(mem_class, MKDEV(MEM_MAJOR, devlist[i].minor), + class_device_create(mem_class, NULL, + MKDEV(MEM_MAJOR, devlist[i].minor), NULL, devlist[i].name); devfs_mk_cdev(MKDEV(MEM_MAJOR, devlist[i].minor), S_IFCHR | devlist[i].mode, devlist[i].name); diff --git a/drivers/char/misc.c b/drivers/char/misc.c index 0c8375165e29..3e4c0414a01a 100644 --- a/drivers/char/misc.c +++ b/drivers/char/misc.c @@ -234,7 +234,7 @@ int misc_register(struct miscdevice * misc) } dev = MKDEV(MISC_MAJOR, misc->minor); - misc->class = class_device_create(misc_class, dev, misc->dev, + misc->class = class_device_create(misc_class, NULL, dev, misc->dev, "%s", misc->name); if (IS_ERR(misc->class)) { err = PTR_ERR(misc->class); diff --git a/drivers/char/mmtimer.c b/drivers/char/mmtimer.c index 12006182f575..78c89a3e7825 100644 --- a/drivers/char/mmtimer.c +++ b/drivers/char/mmtimer.c @@ -441,7 +441,7 @@ static irqreturn_t mmtimer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { int i; - mmtimer_t *base = timers + cpuid_to_cnodeid(smp_processor_id()) * + mmtimer_t *base = timers + cpu_to_node(smp_processor_id()) * NUM_COMPARATORS; unsigned long expires = 0; int result = IRQ_NONE; @@ -608,7 +608,7 @@ static int sgi_timer_set(struct k_itimer *timr, int flags, */ preempt_disable(); - nodeid = cpuid_to_cnodeid(smp_processor_id()); + nodeid = cpu_to_node(smp_processor_id()); base = timers + nodeid * NUM_COMPARATORS; retry: /* Don't use an allocated timer, or a deleted one that's pending */ diff --git a/drivers/char/mwave/3780i.c b/drivers/char/mwave/3780i.c index 613aed9e1840..d1fe05e83882 100644 --- a/drivers/char/mwave/3780i.c +++ b/drivers/char/mwave/3780i.c @@ -53,6 +53,8 @@ #include <linux/ioport.h> #include <linux/init.h> #include <linux/bitops.h> +#include <linux/sched.h> /* cond_resched() */ + #include <asm/io.h> #include <asm/uaccess.h> #include <asm/system.h> diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c index c9bdf544ed2c..c556f4d3ccd7 100644 --- a/drivers/char/n_tty.c +++ b/drivers/char/n_tty.c @@ -62,7 +62,7 @@ static inline unsigned char *alloc_buf(void) { - unsigned int prio = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL; + gfp_t prio = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL; if (PAGE_SIZE != N_TTY_BUF_SIZE) return kmalloc(N_TTY_BUF_SIZE, prio); diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c index 1af733d07321..9e24bbd4090c 100644 --- a/drivers/char/nvram.c +++ b/drivers/char/nvram.c @@ -32,9 +32,11 @@ * added changelog * 1.2 Erik Gilling: Cobalt Networks support * Tim Hockin: general cleanup, Cobalt support + * 1.3 Jon Ringle: Comdial MP1000 support + * */ -#define NVRAM_VERSION "1.2" +#define NVRAM_VERSION "1.3" #include <linux/module.h> #include <linux/config.h> @@ -45,6 +47,7 @@ #define PC 1 #define ATARI 2 #define COBALT 3 +#define MP1000 4 /* select machine configuration */ #if defined(CONFIG_ATARI) @@ -54,6 +57,9 @@ # if defined(CONFIG_COBALT) # include <linux/cobalt-nvram.h> # define MACH COBALT +# elif defined(CONFIG_MACH_MP1000) +# undef MACH +# define MACH MP1000 # else # define MACH PC # endif @@ -112,6 +118,23 @@ #endif +#if MACH == MP1000 + +/* RTC in a MP1000 */ +#define CHECK_DRIVER_INIT() 1 + +#define MP1000_CKS_RANGE_START 0 +#define MP1000_CKS_RANGE_END 111 +#define MP1000_CKS_LOC 112 + +#define NVRAM_BYTES (128-NVRAM_FIRST_BYTE) + +#define mach_check_checksum mp1000_check_checksum +#define mach_set_checksum mp1000_set_checksum +#define mach_proc_infos mp1000_proc_infos + +#endif + /* Note that *all* calls to CMOS_READ and CMOS_WRITE must be done with * rtc_lock held. Due to the index-port/data-port design of the RTC, we * don't want two different things trying to get to it at once. (e.g. the @@ -915,6 +938,91 @@ atari_proc_infos(unsigned char *nvram, char *buffer, int *len, #endif /* MACH == ATARI */ +#if MACH == MP1000 + +static int +mp1000_check_checksum(void) +{ + int i; + unsigned short sum = 0; + unsigned short expect; + + for (i = MP1000_CKS_RANGE_START; i <= MP1000_CKS_RANGE_END; ++i) + sum += __nvram_read_byte(i); + + expect = __nvram_read_byte(MP1000_CKS_LOC+1)<<8 | + __nvram_read_byte(MP1000_CKS_LOC); + return ((sum & 0xffff) == expect); +} + +static void +mp1000_set_checksum(void) +{ + int i; + unsigned short sum = 0; + + for (i = MP1000_CKS_RANGE_START; i <= MP1000_CKS_RANGE_END; ++i) + sum += __nvram_read_byte(i); + __nvram_write_byte(sum >> 8, MP1000_CKS_LOC + 1); + __nvram_write_byte(sum & 0xff, MP1000_CKS_LOC); +} + +#ifdef CONFIG_PROC_FS + +#define SERVER_N_LEN 32 +#define PATH_N_LEN 32 +#define FILE_N_LEN 32 +#define NVRAM_MAGIC_SIG 0xdead + +typedef struct NvRamImage +{ + unsigned short int magic; + unsigned short int mode; + char fname[FILE_N_LEN]; + char path[PATH_N_LEN]; + char server[SERVER_N_LEN]; + char pad[12]; +} NvRam; + +static int +mp1000_proc_infos(unsigned char *nvram, char *buffer, int *len, + off_t *begin, off_t offset, int size) +{ + int checksum; + NvRam* nv = (NvRam*)nvram; + + spin_lock_irq(&rtc_lock); + checksum = __nvram_check_checksum(); + spin_unlock_irq(&rtc_lock); + + PRINT_PROC("Checksum status: %svalid\n", checksum ? "" : "not "); + + switch( nv->mode ) + { + case 0 : + PRINT_PROC( "\tMode 0, tftp prompt\n" ); + break; + case 1 : + PRINT_PROC( "\tMode 1, booting from disk\n" ); + break; + case 2 : + PRINT_PROC( "\tMode 2, Alternate boot from disk /boot/%s\n", nv->fname ); + break; + case 3 : + PRINT_PROC( "\tMode 3, Booting from net:\n" ); + PRINT_PROC( "\t\t%s:%s%s\n",nv->server, nv->path, nv->fname ); + break; + default: + PRINT_PROC( "\tInconsistant nvram?\n" ); + break; + } + + return 1; +} +#endif + +#endif /* MACH == MP1000 */ + MODULE_LICENSE("GPL"); EXPORT_SYMBOL(__nvram_read_byte); diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c index 0e22880432bc..306ee0f091a4 100644 --- a/drivers/char/ppdev.c +++ b/drivers/char/ppdev.c @@ -752,7 +752,7 @@ static struct file_operations pp_fops = { static void pp_attach(struct parport *port) { - class_device_create(ppdev_class, MKDEV(PP_MAJOR, port->number), + class_device_create(ppdev_class, NULL, MKDEV(PP_MAJOR, port->number), NULL, "parport%d", port->number); } diff --git a/drivers/char/qtronix.c b/drivers/char/qtronix.c index 40a3cf62e1a8..601d09baf9d7 100644 --- a/drivers/char/qtronix.c +++ b/drivers/char/qtronix.c @@ -591,6 +591,11 @@ static int __init psaux_init(void) return retval; queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL); + if (!queue) { + misc_deregister(&psaux_mouse); + return -ENOMEM; + } + memset(queue, 0, sizeof(*queue)); queue->head = queue->tail = 0; init_waitqueue_head(&queue->proc_list); diff --git a/drivers/char/raw.c b/drivers/char/raw.c index f13e5de02207..30e4cbe16bb0 100644 --- a/drivers/char/raw.c +++ b/drivers/char/raw.c @@ -128,7 +128,7 @@ raw_ioctl(struct inode *inode, struct file *filp, static void bind_device(struct raw_config_request *rq) { class_device_destroy(raw_class, MKDEV(RAW_MAJOR, rq->raw_minor)); - class_device_create(raw_class, MKDEV(RAW_MAJOR, rq->raw_minor), + class_device_create(raw_class, NULL, MKDEV(RAW_MAJOR, rq->raw_minor), NULL, "raw%d", rq->raw_minor); } @@ -307,7 +307,7 @@ static int __init raw_init(void) unregister_chrdev_region(dev, MAX_RAW_MINORS); goto error; } - class_device_create(raw_class, MKDEV(RAW_MAJOR, 0), NULL, "rawctl"); + class_device_create(raw_class, NULL, MKDEV(RAW_MAJOR, 0), NULL, "rawctl"); devfs_mk_cdev(MKDEV(RAW_MAJOR, 0), S_IFCHR | S_IRUGO | S_IWUGO, diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c index 5b1d3680c8ab..928b850cc679 100644 --- a/drivers/char/rocket.c +++ b/drivers/char/rocket.c @@ -256,7 +256,6 @@ static int sInitController(CONTROLLER_T * CtlP, int CtlNum, ByteIO_t MudbacIO, static int sReadAiopID(ByteIO_t io); static int sReadAiopNumChan(WordIO_t io); -#ifdef MODULE MODULE_AUTHOR("Theodore Ts'o"); MODULE_DESCRIPTION("Comtrol RocketPort driver"); module_param(board1, ulong, 0); @@ -288,17 +287,14 @@ MODULE_PARM_DESC(pc104_3, "set interface types for ISA(PC104) board #3 (e.g. pc1 module_param_array(pc104_4, ulong, NULL, 0); MODULE_PARM_DESC(pc104_4, "set interface types for ISA(PC104) board #4 (e.g. pc104_4=232,232,485,485,..."); -int rp_init(void); +static int rp_init(void); static void rp_cleanup_module(void); module_init(rp_init); module_exit(rp_cleanup_module); -#endif -#ifdef MODULE_LICENSE MODULE_LICENSE("Dual BSD/GPL"); -#endif /*************************************************************************/ /* Module code starts here */ @@ -2378,7 +2374,7 @@ static struct tty_operations rocket_ops = { /* * The module "startup" routine; it's run when the module is loaded. */ -int __init rp_init(void) +static int __init rp_init(void) { int retval, pci_boards_found, isa_boards_found, i; @@ -2502,7 +2498,6 @@ int __init rp_init(void) return 0; } -#ifdef MODULE static void rp_cleanup_module(void) { @@ -2530,7 +2525,6 @@ static void rp_cleanup_module(void) if (controller) release_region(controller, 4); } -#endif /*************************************************************************** Function: sInitController diff --git a/drivers/char/s3c2410-rtc.c b/drivers/char/s3c2410-rtc.c index e1a90d9a8756..887b8b2d7882 100644 --- a/drivers/char/s3c2410-rtc.c +++ b/drivers/char/s3c2410-rtc.c @@ -519,30 +519,28 @@ static struct timespec s3c2410_rtc_delta; static int ticnt_save; -static int s3c2410_rtc_suspend(struct device *dev, pm_message_t state, u32 level) +static int s3c2410_rtc_suspend(struct device *dev, pm_message_t state) { struct rtc_time tm; struct timespec time; time.tv_nsec = 0; - if (level == SUSPEND_POWER_DOWN) { - /* save TICNT for anyone using periodic interrupts */ + /* save TICNT for anyone using periodic interrupts */ - ticnt_save = readb(S3C2410_TICNT); + ticnt_save = readb(S3C2410_TICNT); - /* calculate time delta for suspend */ + /* calculate time delta for suspend */ - s3c2410_rtc_gettime(&tm); - rtc_tm_to_time(&tm, &time.tv_sec); - save_time_delta(&s3c2410_rtc_delta, &time); - s3c2410_rtc_enable(dev, 0); - } + s3c2410_rtc_gettime(&tm); + rtc_tm_to_time(&tm, &time.tv_sec); + save_time_delta(&s3c2410_rtc_delta, &time); + s3c2410_rtc_enable(dev, 0); return 0; } -static int s3c2410_rtc_resume(struct device *dev, u32 level) +static int s3c2410_rtc_resume(struct device *dev) { struct rtc_time tm; struct timespec time; diff --git a/drivers/char/ser_a2232.c b/drivers/char/ser_a2232.c index 6b4e9d155f50..dda30e42ec79 100644 --- a/drivers/char/ser_a2232.c +++ b/drivers/char/ser_a2232.c @@ -790,7 +790,7 @@ static int __init a2232board_init(void) } - printk("Total: %d A2232 boards initialized.\n.", nr_a2232); /* Some status report if no card was found */ + printk("Total: %d A2232 boards initialized.\n", nr_a2232); /* Some status report if no card was found */ a2232_init_portstructs(); diff --git a/drivers/char/snsc.c b/drivers/char/snsc.c index 261a41bf6d02..0e7d216e7eb0 100644 --- a/drivers/char/snsc.c +++ b/drivers/char/snsc.c @@ -377,7 +377,7 @@ scdrv_init(void) dev_t first_dev, dev; nasid_t event_nasid = ia64_sn_get_console_nasid(); - if (alloc_chrdev_region(&first_dev, 0, numionodes, + if (alloc_chrdev_region(&first_dev, 0, num_cnodes, SYSCTL_BASENAME) < 0) { printk("%s: failed to register SN system controller device\n", __FUNCTION__); @@ -385,7 +385,7 @@ scdrv_init(void) } snsc_class = class_create(THIS_MODULE, SYSCTL_BASENAME); - for (cnode = 0; cnode < numionodes; cnode++) { + for (cnode = 0; cnode < num_cnodes; cnode++) { geoid = cnodeid_get_geoid(cnode); devnamep = devname; format_module_id(devnamep, geo_module(geoid), @@ -437,7 +437,7 @@ scdrv_init(void) continue; } - class_device_create(snsc_class, dev, NULL, + class_device_create(snsc_class, NULL, dev, NULL, "%s", devname); ia64_sn_irtr_intr_enable(scd->scd_nasid, diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c index 36ae9ad2598c..f86c15587238 100644 --- a/drivers/char/sonypi.c +++ b/drivers/char/sonypi.c @@ -424,10 +424,6 @@ static struct sonypi_eventtypes { #define SONYPI_BUF_SIZE 128 -/* The name of the devices for the input device drivers */ -#define SONYPI_JOG_INPUTNAME "Sony Vaio Jogdial" -#define SONYPI_KEY_INPUTNAME "Sony Vaio Keys" - /* Correspondance table between sonypi events and input layer events */ static struct { int sonypiev; @@ -490,8 +486,8 @@ static struct sonypi_device { struct fasync_struct *fifo_async; int open_count; int model; - struct input_dev input_jog_dev; - struct input_dev input_key_dev; + struct input_dev *input_jog_dev; + struct input_dev *input_key_dev; struct work_struct input_work; struct kfifo *input_fifo; spinlock_t input_fifo_lock; @@ -779,8 +775,8 @@ static void input_keyrelease(void *data) static void sonypi_report_input_event(u8 event) { - struct input_dev *jog_dev = &sonypi_device.input_jog_dev; - struct input_dev *key_dev = &sonypi_device.input_key_dev; + struct input_dev *jog_dev = sonypi_device.input_jog_dev; + struct input_dev *key_dev = sonypi_device.input_key_dev; struct sonypi_keypress kp = { NULL }; int i; @@ -1171,19 +1167,17 @@ static int sonypi_disable(void) #ifdef CONFIG_PM static int old_camera_power; -static int sonypi_suspend(struct device *dev, pm_message_t state, u32 level) +static int sonypi_suspend(struct device *dev, pm_message_t state) { - if (level == SUSPEND_DISABLE) { - old_camera_power = sonypi_device.camera_power; - sonypi_disable(); - } + old_camera_power = sonypi_device.camera_power; + sonypi_disable(); + return 0; } -static int sonypi_resume(struct device *dev, u32 level) +static int sonypi_resume(struct device *dev) { - if (level == RESUME_ENABLE) - sonypi_enable(old_camera_power); + sonypi_enable(old_camera_power); return 0; } #endif @@ -1203,6 +1197,47 @@ static struct device_driver sonypi_driver = { .shutdown = sonypi_shutdown, }; +static int __devinit sonypi_create_input_devices(void) +{ + struct input_dev *jog_dev; + struct input_dev *key_dev; + int i; + + sonypi_device.input_jog_dev = jog_dev = input_allocate_device(); + if (!jog_dev) + return -ENOMEM; + + jog_dev->name = "Sony Vaio Jogdial"; + jog_dev->id.bustype = BUS_ISA; + jog_dev->id.vendor = PCI_VENDOR_ID_SONY; + + jog_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL); + jog_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_MIDDLE); + jog_dev->relbit[0] = BIT(REL_WHEEL); + + sonypi_device.input_key_dev = key_dev = input_allocate_device(); + if (!key_dev) { + input_free_device(jog_dev); + sonypi_device.input_jog_dev = NULL; + return -ENOMEM; + } + + key_dev->name = "Sony Vaio Keys"; + key_dev->id.bustype = BUS_ISA; + key_dev->id.vendor = PCI_VENDOR_ID_SONY; + + /* Initialize the Input Drivers: special keys */ + key_dev->evbit[0] = BIT(EV_KEY); + for (i = 0; sonypi_inputkeys[i].sonypiev; i++) + if (sonypi_inputkeys[i].inputev) + set_bit(sonypi_inputkeys[i].inputev, key_dev->keybit); + + input_register_device(jog_dev); + input_register_device(key_dev); + + return 0; +} + static int __devinit sonypi_probe(void) { int i, ret; @@ -1298,34 +1333,10 @@ static int __devinit sonypi_probe(void) } if (useinput) { - /* Initialize the Input Drivers: jogdial */ - int i; - sonypi_device.input_jog_dev.evbit[0] = - BIT(EV_KEY) | BIT(EV_REL); - sonypi_device.input_jog_dev.keybit[LONG(BTN_MOUSE)] = - BIT(BTN_MIDDLE); - sonypi_device.input_jog_dev.relbit[0] = BIT(REL_WHEEL); - sonypi_device.input_jog_dev.name = SONYPI_JOG_INPUTNAME; - sonypi_device.input_jog_dev.id.bustype = BUS_ISA; - sonypi_device.input_jog_dev.id.vendor = PCI_VENDOR_ID_SONY; - - input_register_device(&sonypi_device.input_jog_dev); - printk(KERN_INFO "%s input method installed.\n", - sonypi_device.input_jog_dev.name); - - /* Initialize the Input Drivers: special keys */ - sonypi_device.input_key_dev.evbit[0] = BIT(EV_KEY); - for (i = 0; sonypi_inputkeys[i].sonypiev; i++) - if (sonypi_inputkeys[i].inputev) - set_bit(sonypi_inputkeys[i].inputev, - sonypi_device.input_key_dev.keybit); - sonypi_device.input_key_dev.name = SONYPI_KEY_INPUTNAME; - sonypi_device.input_key_dev.id.bustype = BUS_ISA; - sonypi_device.input_key_dev.id.vendor = PCI_VENDOR_ID_SONY; - input_register_device(&sonypi_device.input_key_dev); - printk(KERN_INFO "%s input method installed.\n", - sonypi_device.input_key_dev.name); + ret = sonypi_create_input_devices(); + if (ret) + goto out_inputdevices; spin_lock_init(&sonypi_device.input_fifo_lock); sonypi_device.input_fifo = @@ -1375,8 +1386,9 @@ static int __devinit sonypi_probe(void) out_platformdev: kfifo_free(sonypi_device.input_fifo); out_infifo: - input_unregister_device(&sonypi_device.input_key_dev); - input_unregister_device(&sonypi_device.input_jog_dev); + input_unregister_device(sonypi_device.input_key_dev); + input_unregister_device(sonypi_device.input_jog_dev); +out_inputdevices: free_irq(sonypi_device.irq, sonypi_irq); out_reqirq: release_region(sonypi_device.ioport1, sonypi_device.region_size); @@ -1402,8 +1414,8 @@ static void __devexit sonypi_remove(void) platform_device_unregister(sonypi_device.pdev); if (useinput) { - input_unregister_device(&sonypi_device.input_key_dev); - input_unregister_device(&sonypi_device.input_jog_dev); + input_unregister_device(sonypi_device.input_key_dev); + input_unregister_device(sonypi_device.input_jog_dev); kfifo_free(sonypi_device.input_fifo); } diff --git a/drivers/char/specialix.c b/drivers/char/specialix.c index 50e0b612a8a2..352547eabf7b 100644 --- a/drivers/char/specialix.c +++ b/drivers/char/specialix.c @@ -38,19 +38,19 @@ * * Revision 1.0: April 1st 1997. * Initial release for alpha testing. - * Revision 1.1: April 14th 1997. - * Incorporated Richard Hudsons suggestions, + * Revision 1.1: April 14th 1997. + * Incorporated Richard Hudsons suggestions, * removed some debugging printk's. * Revision 1.2: April 15th 1997. * Ported to 2.1.x kernels. - * Revision 1.3: April 17th 1997 - * Backported to 2.0. (Compatibility macros). + * Revision 1.3: April 17th 1997 + * Backported to 2.0. (Compatibility macros). * Revision 1.4: April 18th 1997 - * Fixed DTR/RTS bug that caused the card to indicate - * "don't send data" to a modem after the password prompt. + * Fixed DTR/RTS bug that caused the card to indicate + * "don't send data" to a modem after the password prompt. * Fixed bug for premature (fake) interrupts. * Revision 1.5: April 19th 1997 - * fixed a minor typo in the header file, cleanup a little. + * fixed a minor typo in the header file, cleanup a little. * performance warnings are now MAXed at once per minute. * Revision 1.6: May 23 1997 * Changed the specialix=... format to include interrupt. @@ -60,10 +60,10 @@ * port to linux-2.1.43 kernel. * Revision 1.9: Oct 9 1998 * Added stuff for the IO8+/PCI version. - * Revision 1.10: Oct 22 1999 / Jan 21 2000. - * Added stuff for setserial. + * Revision 1.10: Oct 22 1999 / Jan 21 2000. + * Added stuff for setserial. * Nicolas Mailhot (Nicolas.Mailhot@email.enst.fr) - * + * */ #define VERSION "1.11" @@ -154,7 +154,7 @@ static int sx_poll = HZ; -/* +/* * The following defines are mostly for testing purposes. But if you need * some nice reporting in your syslog, you can define them also. */ @@ -188,7 +188,7 @@ static DECLARE_MUTEX(tmp_buf_sem); static unsigned long baud_table[] = { 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, - 9600, 19200, 38400, 57600, 115200, 0, + 9600, 19200, 38400, 57600, 115200, 0, }; static struct specialix_board sx_board[SX_NBOARD] = { @@ -216,7 +216,7 @@ static inline int sx_paranoia_check(struct specialix_port const * port, KERN_ERR "sx: Warning: bad specialix port magic number for device %s in %s\n"; static const char *badinfo = KERN_ERR "sx: Warning: null specialix port for device %s in %s\n"; - + if (!port) { printk(badinfo, name, routine); return 1; @@ -231,9 +231,9 @@ static inline int sx_paranoia_check(struct specialix_port const * port, /* - * + * * Service functions for specialix IO8+ driver. - * + * */ /* Get board number from pointer */ @@ -246,7 +246,7 @@ static inline int board_No (struct specialix_board * bp) /* Get port number from pointer */ static inline int port_No (struct specialix_port const * port) { - return SX_PORT(port - sx_port); + return SX_PORT(port - sx_port); } @@ -309,7 +309,7 @@ static inline void sx_wait_CCR(struct specialix_board * bp) return; udelay (1); } - + printk(KERN_ERR "sx%d: Timeout waiting for CCR.\n", board_No(bp)); } @@ -329,7 +329,7 @@ static inline void sx_wait_CCR_off(struct specialix_board * bp) return; udelay (1); } - + printk(KERN_ERR "sx%d: Timeout waiting for CCR.\n", board_No(bp)); } @@ -338,34 +338,28 @@ static inline void sx_wait_CCR_off(struct specialix_board * bp) * specialix IO8+ IO range functions. */ -static inline int sx_check_io_range(struct specialix_board * bp) +static inline int sx_request_io_range(struct specialix_board * bp) { - return check_region (bp->base, SX_IO_SPACE); -} - - -static inline void sx_request_io_range(struct specialix_board * bp) -{ - request_region(bp->base, - bp->flags&SX_BOARD_IS_PCI?SX_PCI_IO_SPACE:SX_IO_SPACE, - "specialix IO8+" ); + return request_region(bp->base, + bp->flags & SX_BOARD_IS_PCI ? SX_PCI_IO_SPACE : SX_IO_SPACE, + "specialix IO8+") == NULL; } static inline void sx_release_io_range(struct specialix_board * bp) { - release_region(bp->base, + release_region(bp->base, bp->flags&SX_BOARD_IS_PCI?SX_PCI_IO_SPACE:SX_IO_SPACE); } - + /* Must be called with enabled interrupts */ -/* Ugly. Very ugly. Don't use this for anything else than initialization +/* Ugly. Very ugly. Don't use this for anything else than initialization code */ static inline void sx_long_delay(unsigned long delay) { unsigned long i; - + for (i = jiffies + delay; time_after(i, jiffies); ) ; } @@ -378,7 +372,7 @@ static int sx_set_irq ( struct specialix_board *bp) int i; unsigned long flags; - if (bp->flags & SX_BOARD_IS_PCI) + if (bp->flags & SX_BOARD_IS_PCI) return 1; switch (bp->irq) { /* In the same order as in the docs... */ @@ -420,7 +414,7 @@ static int sx_init_CD186x(struct specialix_board * bp) sx_out_off(bp, CD186x_PILR3, SX_ACK_RINT); /* Prio for receiver intr */ /* Set RegAckEn */ sx_out_off(bp, CD186x_SRCR, sx_in (bp, CD186x_SRCR) | SRCR_REGACKEN); - + /* Setting up prescaler. We need 4 ticks per 1 ms */ scaler = SX_OSCFREQ/SPECIALIX_TPS; @@ -448,7 +442,7 @@ static int read_cross_byte (struct specialix_board *bp, int reg, int bit) spin_lock_irqsave(&bp->lock, flags); for (i=0, t=0;i<8;i++) { sx_out_off (bp, CD186x_CAR, i); - if (sx_in_off (bp, reg) & bit) + if (sx_in_off (bp, reg) & bit) t |= 1 << i; } spin_unlock_irqrestore(&bp->lock, flags); @@ -472,7 +466,7 @@ void missed_irq (unsigned long data) spin_unlock_irqrestore(&bp->lock, flags); if (irq) { printk (KERN_INFO "Missed interrupt... Calling int from timer. \n"); - sx_interrupt (((struct specialix_board *)data)->irq, + sx_interrupt (((struct specialix_board *)data)->irq, (void*)data, NULL); } missed_irq_timer.expires = jiffies + sx_poll; @@ -495,7 +489,7 @@ static int sx_probe(struct specialix_board *bp) func_enter(); - if (sx_check_io_range(bp)) { + if (sx_request_io_range(bp)) { func_exit(); return 1; } @@ -509,15 +503,16 @@ static int sx_probe(struct specialix_board *bp) short_pause (); val2 = sx_in_off(bp, CD186x_PPRL); - + if ((val1 != 0x5a) || (val2 != 0xa5)) { printk(KERN_INFO "sx%d: specialix IO8+ Board at 0x%03x not found.\n", board_No(bp), bp->base); + sx_release_io_range(bp); func_exit(); return 1; } - /* Check the DSR lines that Specialix uses as board + /* Check the DSR lines that Specialix uses as board identification */ val1 = read_cross_byte (bp, CD186x_MSVR, MSVR_DSR); val2 = read_cross_byte (bp, CD186x_MSVR, MSVR_RTS); @@ -532,6 +527,7 @@ static int sx_probe(struct specialix_board *bp) if (val1 != val2) { printk(KERN_INFO "sx%d: specialix IO8+ ID %02x at 0x%03x not found (%02x).\n", board_No(bp), val2, bp->base, val1); + sx_release_io_range(bp); func_exit(); return 1; } @@ -546,7 +542,7 @@ static int sx_probe(struct specialix_board *bp) sx_wait_CCR(bp); sx_out(bp, CD186x_CCR, CCR_TXEN); /* Enable transmitter */ sx_out(bp, CD186x_IER, IER_TXRDY); /* Enable tx empty intr */ - sx_long_delay(HZ/20); + sx_long_delay(HZ/20); irqs = probe_irq_off(irqs); dprintk (SX_DEBUG_INIT, "SRSR = %02x, ", sx_in(bp, CD186x_SRSR)); @@ -561,14 +557,15 @@ static int sx_probe(struct specialix_board *bp) } dprintk (SX_DEBUG_INIT "val1 = %02x, val2 = %02x, val3 = %02x.\n", - val1, val2, val3); - + val1, val2, val3); + } - + #if 0 if (irqs <= 0) { printk(KERN_ERR "sx%d: Can't find IRQ for specialix IO8+ board at 0x%03x.\n", board_No(bp), bp->base); + sx_release_io_range(bp); func_exit(); return 1; } @@ -579,19 +576,20 @@ static int sx_probe(struct specialix_board *bp) #endif /* Reset CD186x again */ if (!sx_init_CD186x(bp)) { + sx_release_io_range(bp); func_exit(); - return -EIO; + return 1; } sx_request_io_range(bp); bp->flags |= SX_BOARD_PRESENT; - + /* Chip revcode pkgtype GFRCR SRCR bit 7 CD180 rev B 0x81 0 CD180 rev C 0x82 0 CD1864 rev A 0x82 1 - CD1865 rev A 0x83 1 -- Do not use!!! Does not work. + CD1865 rev A 0x83 1 -- Do not use!!! Does not work. CD1865 rev B 0x84 1 -- Thanks to Gwen Wang, Cirrus Logic. */ @@ -623,8 +621,8 @@ static int sx_probe(struct specialix_board *bp) return 0; } -/* - * +/* + * * Interrupt processing routines. * */ @@ -657,7 +655,7 @@ static inline struct specialix_port * sx_get_port(struct specialix_board * bp, return port; } } - printk(KERN_INFO "sx%d: %s interrupt from invalid port %d\n", + printk(KERN_INFO "sx%d: %s interrupt from invalid port %d\n", board_No(bp), what, channel); return NULL; } @@ -681,7 +679,7 @@ static inline void sx_receive_exc(struct specialix_board * bp) tty = port->tty; dprintk (SX_DEBUG_RX, "port: %p count: %d BUFF_SIZE: %d\n", port, tty->flip.count, TTY_FLIPBUF_SIZE); - + status = sx_in(bp, CD186x_RCSR); dprintk (SX_DEBUG_RX, "status: 0x%x\n", status); @@ -707,30 +705,30 @@ static inline void sx_receive_exc(struct specialix_board * bp) return; } if (status & RCSR_TOUT) { - printk(KERN_INFO "sx%d: port %d: Receiver timeout. Hardware problems ?\n", + printk(KERN_INFO "sx%d: port %d: Receiver timeout. Hardware problems ?\n", board_No(bp), port_No(port)); func_exit(); return; - + } else if (status & RCSR_BREAK) { dprintk(SX_DEBUG_RX, "sx%d: port %d: Handling break...\n", board_No(bp), port_No(port)); *tty->flip.flag_buf_ptr++ = TTY_BREAK; if (port->flags & ASYNC_SAK) do_SAK(tty); - - } else if (status & RCSR_PE) + + } else if (status & RCSR_PE) *tty->flip.flag_buf_ptr++ = TTY_PARITY; - - else if (status & RCSR_FE) + + else if (status & RCSR_FE) *tty->flip.flag_buf_ptr++ = TTY_FRAME; - + else if (status & RCSR_OE) *tty->flip.flag_buf_ptr++ = TTY_OVERRUN; - + else *tty->flip.flag_buf_ptr++ = 0; - + *tty->flip.char_buf_ptr++ = ch; tty->flip.count++; schedule_delayed_work(&tty->flip.work, 1); @@ -746,18 +744,18 @@ static inline void sx_receive(struct specialix_board * bp) unsigned char count; func_enter(); - + if (!(port = sx_get_port(bp, "Receive"))) { dprintk (SX_DEBUG_RX, "Hmm, couldn't find port.\n"); func_exit(); return; } tty = port->tty; - + count = sx_in(bp, CD186x_RDCR); dprintk (SX_DEBUG_RX, "port: %p: count: %d\n", port, count); port->hits[count > 8 ? 9 : count]++; - + while (count--) { if (tty->flip.count >= TTY_FLIPBUF_SIZE) { printk(KERN_INFO "sx%d: port %d: Working around flip buffer overflow.\n", @@ -787,7 +785,7 @@ static inline void sx_transmit(struct specialix_board * bp) } dprintk (SX_DEBUG_TX, "port: %p\n", port); tty = port->tty; - + if (port->IER & IER_TXEMPTY) { /* FIFO drained */ sx_out(bp, CD186x_CAR, port_No(port)); @@ -796,7 +794,7 @@ static inline void sx_transmit(struct specialix_board * bp) func_exit(); return; } - + if ((port->xmit_cnt <= 0 && !port->break_length) || tty->stopped || tty->hw_stopped) { sx_out(bp, CD186x_CAR, port_No(port)); @@ -805,7 +803,7 @@ static inline void sx_transmit(struct specialix_board * bp) func_exit(); return; } - + if (port->break_length) { if (port->break_length > 0) { if (port->COR2 & COR2_ETC) { @@ -831,7 +829,7 @@ static inline void sx_transmit(struct specialix_board * bp) func_exit(); return; } - + count = CD186x_NFIFO; do { sx_out(bp, CD186x_TDR, port->xmit_buf[port->xmit_tail++]); @@ -839,7 +837,7 @@ static inline void sx_transmit(struct specialix_board * bp) if (--port->xmit_cnt <= 0) break; } while (--count > 0); - + if (port->xmit_cnt <= 0) { sx_out(bp, CD186x_CAR, port_No(port)); port->IER &= ~IER_TXRDY; @@ -862,9 +860,9 @@ static inline void sx_check_modem(struct specialix_board * bp) dprintk (SX_DEBUG_SIGNALS, "Modem intr. "); if (!(port = sx_get_port(bp, "Modem"))) return; - + tty = port->tty; - + mcr = sx_in(bp, CD186x_MCR); printk ("mcr = %02x.\n", mcr); @@ -879,7 +877,7 @@ static inline void sx_check_modem(struct specialix_board * bp) schedule_work(&port->tqueue_hangup); } } - + #ifdef SPECIALIX_BRAIN_DAMAGED_CTS if (mcr & MCR_CTSCHG) { if (sx_in(bp, CD186x_MSVR) & MSVR_CTS) { @@ -906,7 +904,7 @@ static inline void sx_check_modem(struct specialix_board * bp) sx_out(bp, CD186x_IER, port->IER); } #endif /* SPECIALIX_BRAIN_DAMAGED_CTS */ - + /* Clear change bits */ sx_out(bp, CD186x_MCR, 0); } @@ -940,7 +938,7 @@ static irqreturn_t sx_interrupt(int irq, void *dev_id, struct pt_regs *regs) while ((++loop < 16) && (status = (sx_in(bp, CD186x_SRSR) & (SRSR_RREQint | SRSR_TREQint | - SRSR_MREQint)))) { + SRSR_MREQint)))) { if (status & SRSR_RREQint) { ack = sx_in(bp, CD186x_RRAR); @@ -951,7 +949,7 @@ static irqreturn_t sx_interrupt(int irq, void *dev_id, struct pt_regs *regs) else printk(KERN_ERR "sx%d: status: 0x%x Bad receive ack 0x%02x.\n", board_No(bp), status, ack); - + } else if (status & SRSR_TREQint) { ack = sx_in(bp, CD186x_TRAR); @@ -963,13 +961,13 @@ static irqreturn_t sx_interrupt(int irq, void *dev_id, struct pt_regs *regs) } else if (status & SRSR_MREQint) { ack = sx_in(bp, CD186x_MRAR); - if (ack == (SX_ID | GIVR_IT_MODEM)) + if (ack == (SX_ID | GIVR_IT_MODEM)) sx_check_modem(bp); else printk(KERN_ERR "sx%d: status: 0x%x Bad modem ack 0x%02x.\n", board_No(bp), status, ack); - - } + + } sx_out(bp, CD186x_EOIR, 0); /* Mark end of interrupt */ } @@ -1026,7 +1024,7 @@ static inline int sx_setup_board(struct specialix_board * bp) { int error; - if (bp->flags & SX_BOARD_ACTIVE) + if (bp->flags & SX_BOARD_ACTIVE) return 0; if (bp->flags & SX_BOARD_IS_PCI) @@ -1034,7 +1032,7 @@ static inline int sx_setup_board(struct specialix_board * bp) else error = request_irq(bp->irq, sx_interrupt, SA_INTERRUPT, "specialix IO8+", bp); - if (error) + if (error) return error; turn_ints_on (bp); @@ -1055,7 +1053,7 @@ static inline void sx_shutdown_board(struct specialix_board *bp) } bp->flags &= ~SX_BOARD_ACTIVE; - + dprintk (SX_DEBUG_IRQ, "Freeing IRQ%d for board %d.\n", bp->irq, board_No (bp)); free_irq(bp->irq, bp); @@ -1068,7 +1066,7 @@ static inline void sx_shutdown_board(struct specialix_board *bp) /* - * Setting up port characteristics. + * Setting up port characteristics. * Must be called with disabled interrupts */ static void sx_change_speed(struct specialix_board *bp, struct specialix_port *port) @@ -1103,10 +1101,10 @@ static void sx_change_speed(struct specialix_board *bp, struct specialix_port *p spin_unlock_irqrestore(&bp->lock, flags); dprintk (SX_DEBUG_TERMIOS, "sx: got MSVR=%02x.\n", port->MSVR); baud = C_BAUD(tty); - + if (baud & CBAUDEX) { baud &= ~CBAUDEX; - if (baud < 1 || baud > 2) + if (baud < 1 || baud > 2) port->tty->termios->c_cflag &= ~CBAUDEX; else baud += 15; @@ -1117,8 +1115,8 @@ static void sx_change_speed(struct specialix_board *bp, struct specialix_port *p if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) baud += 2; } - - + + if (!baud_table[baud]) { /* Drop DTR & exit */ dprintk (SX_DEBUG_TERMIOS, "Dropping DTR... Hmm....\n"); @@ -1127,7 +1125,7 @@ static void sx_change_speed(struct specialix_board *bp, struct specialix_port *p spin_lock_irqsave(&bp->lock, flags); sx_out(bp, CD186x_MSVR, port->MSVR ); spin_unlock_irqrestore(&bp->lock, flags); - } + } else dprintk (SX_DEBUG_TERMIOS, "Can't drop DTR: no DTR.\n"); return; @@ -1137,9 +1135,9 @@ static void sx_change_speed(struct specialix_board *bp, struct specialix_port *p port ->MSVR |= MSVR_DTR; } } - + /* - * Now we must calculate some speed depended things + * Now we must calculate some speed depended things */ /* Set baud rate for port */ @@ -1152,7 +1150,7 @@ static void sx_change_speed(struct specialix_board *bp, struct specialix_port *p tmp = (((SX_OSCFREQ + baud_table[baud]/2) / baud_table[baud] + CD186x_TPC/2) / CD186x_TPC); - if ((tmp < 0x10) && time_before(again, jiffies)) { + if ((tmp < 0x10) && time_before(again, jiffies)) { again = jiffies + HZ * 60; /* Page 48 of version 2.0 of the CL-CD1865 databook */ if (tmp >= 12) { @@ -1164,27 +1162,27 @@ static void sx_change_speed(struct specialix_board *bp, struct specialix_port *p printk (KERN_INFO "sx%d: Baud rate divisor is %ld. \n" "Warning: overstressing Cirrus chip. " "This might not work.\n" - "Read specialix.txt for more info.\n", + "Read specialix.txt for more info.\n", port_No (port), tmp); } } spin_lock_irqsave(&bp->lock, flags); - sx_out(bp, CD186x_RBPRH, (tmp >> 8) & 0xff); - sx_out(bp, CD186x_TBPRH, (tmp >> 8) & 0xff); - sx_out(bp, CD186x_RBPRL, tmp & 0xff); + sx_out(bp, CD186x_RBPRH, (tmp >> 8) & 0xff); + sx_out(bp, CD186x_TBPRH, (tmp >> 8) & 0xff); + sx_out(bp, CD186x_RBPRL, tmp & 0xff); sx_out(bp, CD186x_TBPRL, tmp & 0xff); spin_unlock_irqrestore(&bp->lock, flags); if (port->custom_divisor) { baud = (SX_OSCFREQ + port->custom_divisor/2) / port->custom_divisor; baud = ( baud + 5 ) / 10; - } else + } else baud = (baud_table[baud] + 5) / 10; /* Estimated CPS */ /* Two timer ticks seems enough to wakeup something like SLIP driver */ - tmp = ((baud + HZ/2) / HZ) * 2 - CD186x_NFIFO; + tmp = ((baud + HZ/2) / HZ) * 2 - CD186x_NFIFO; port->wakeup_chars = (tmp < 0) ? 0 : ((tmp >= SERIAL_XMIT_SIZE) ? SERIAL_XMIT_SIZE - 1 : tmp); - + /* Receiver timeout will be transmission time for 1.5 chars */ tmp = (SPECIALIX_TPS + SPECIALIX_TPS/2 + baud/2) / baud; tmp = (tmp > 0xff) ? 0xff : tmp; @@ -1205,29 +1203,29 @@ static void sx_change_speed(struct specialix_board *bp, struct specialix_port *p cor1 |= COR1_8BITS; break; } - - if (C_CSTOPB(tty)) + + if (C_CSTOPB(tty)) cor1 |= COR1_2SB; - + cor1 |= COR1_IGNORE; if (C_PARENB(tty)) { cor1 |= COR1_NORMPAR; - if (C_PARODD(tty)) + if (C_PARODD(tty)) cor1 |= COR1_ODDP; - if (I_INPCK(tty)) + if (I_INPCK(tty)) cor1 &= ~COR1_IGNORE; } /* Set marking of some errors */ port->mark_mask = RCSR_OE | RCSR_TOUT; - if (I_INPCK(tty)) + if (I_INPCK(tty)) port->mark_mask |= RCSR_FE | RCSR_PE; - if (I_BRKINT(tty) || I_PARMRK(tty)) + if (I_BRKINT(tty) || I_PARMRK(tty)) port->mark_mask |= RCSR_BREAK; - if (I_IGNPAR(tty)) + if (I_IGNPAR(tty)) port->mark_mask &= ~(RCSR_FE | RCSR_PE); if (I_IGNBRK(tty)) { port->mark_mask &= ~RCSR_BREAK; - if (I_IGNPAR(tty)) + if (I_IGNPAR(tty)) /* Real raw mode. Ignore all */ port->mark_mask &= ~RCSR_OE; } @@ -1241,7 +1239,7 @@ static void sx_change_speed(struct specialix_board *bp, struct specialix_port *p tty->hw_stopped = !(sx_in(bp, CD186x_MSVR) & (MSVR_CTS|MSVR_DSR)); spin_unlock_irqrestore(&bp->lock, flags); #else - port->COR2 |= COR2_CTSAE; + port->COR2 |= COR2_CTSAE; #endif } /* Enable Software Flow Control. FIXME: I'm not sure about this */ @@ -1264,11 +1262,11 @@ static void sx_change_speed(struct specialix_board *bp, struct specialix_port *p mcor1 |= MCOR1_CDZD; mcor2 |= MCOR2_CDOD; } - - if (C_CREAD(tty)) + + if (C_CREAD(tty)) /* Enable receiver */ port->IER |= IER_RXD; - + /* Set input FIFO size (1-8 bytes) */ cor3 |= sx_rxfifo; /* Setting up CD186x channel registers */ @@ -1311,11 +1309,11 @@ static int sx_setup_port(struct specialix_board *bp, struct specialix_port *port func_exit(); return 0; } - + if (!port->xmit_buf) { /* We may sleep in get_zeroed_page() */ unsigned long tmp; - + if (!(tmp = get_zeroed_page(GFP_KERNEL))) { func_exit(); return -ENOMEM; @@ -1328,10 +1326,10 @@ static int sx_setup_port(struct specialix_board *bp, struct specialix_port *port } port->xmit_buf = (unsigned char *) tmp; } - + spin_lock_irqsave(&port->lock, flags); - if (port->tty) + if (port->tty) clear_bit(TTY_IO_ERROR, &port->tty->flags); port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; @@ -1340,7 +1338,7 @@ static int sx_setup_port(struct specialix_board *bp, struct specialix_port *port spin_unlock_irqrestore(&port->lock, flags); - + func_exit(); return 0; } @@ -1352,14 +1350,14 @@ static void sx_shutdown_port(struct specialix_board *bp, struct specialix_port * struct tty_struct *tty; int i; unsigned long flags; - + func_enter(); if (!(port->flags & ASYNC_INITIALIZED)) { func_exit(); return; } - + if (sx_debug & SX_DEBUG_FIFO) { dprintk(SX_DEBUG_FIFO, "sx%d: port %d: %ld overruns, FIFO hits [ ", board_No(bp), port_No(port), port->overrun); @@ -1394,13 +1392,13 @@ static void sx_shutdown_port(struct specialix_board *bp, struct specialix_port * if (tty) set_bit(TTY_IO_ERROR, &tty->flags); port->flags &= ~ASYNC_INITIALIZED; - - if (!bp->count) + + if (!bp->count) sx_shutdown_board(bp); func_exit(); } - + static int block_til_ready(struct tty_struct *tty, struct file * filp, struct specialix_port *port) { @@ -1427,7 +1425,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, return -ERESTARTSYS; } } - + /* * If non-blocking mode is set, or the port is not enabled, * then make the check up front and then exit. @@ -1477,7 +1475,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, if (port->flags & ASYNC_HUP_NOTIFY) retval = -EAGAIN; else - retval = -ERESTARTSYS; + retval = -ERESTARTSYS; break; } if (!(port->flags & ASYNC_CLOSING) && @@ -1506,7 +1504,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, port->flags |= ASYNC_NORMAL_ACTIVE; func_exit(); return 0; -} +} static int sx_open(struct tty_struct * tty, struct file * filp) @@ -1526,7 +1524,7 @@ static int sx_open(struct tty_struct * tty, struct file * filp) func_exit(); return -ENODEV; } - + bp = &sx_board[board]; port = sx_port + board * SX_NPORT + SX_PORT(tty->index); port->overrun = 0; @@ -1557,7 +1555,7 @@ static int sx_open(struct tty_struct * tty, struct file * filp) func_enter(); return error; } - + if ((error = block_til_ready(tty, filp, port))) { func_enter(); return error; @@ -1574,7 +1572,7 @@ static void sx_close(struct tty_struct * tty, struct file * filp) struct specialix_board *bp; unsigned long flags; unsigned long timeout; - + func_enter(); if (!port || sx_paranoia_check(port, tty->name, "close")) { func_exit(); @@ -1587,7 +1585,7 @@ static void sx_close(struct tty_struct * tty, struct file * filp) func_exit(); return; } - + bp = port_Board(port); if ((tty->count == 1) && (port->count != 1)) { printk(KERN_ERR "sx%d: sx_close: bad port count;" @@ -1607,7 +1605,7 @@ static void sx_close(struct tty_struct * tty, struct file * filp) } port->flags |= ASYNC_CLOSING; /* - * Now we wait for the transmit buffer to clear; and we notify + * Now we wait for the transmit buffer to clear; and we notify * the line discipline to only process XON/XOFF characters. */ tty->closing = 1; @@ -1681,7 +1679,7 @@ static void sx_close(struct tty_struct * tty, struct file * filp) } -static int sx_write(struct tty_struct * tty, +static int sx_write(struct tty_struct * tty, const unsigned char *buf, int count) { struct specialix_port *port = (struct specialix_port *)tty->driver_data; @@ -1694,7 +1692,7 @@ static int sx_write(struct tty_struct * tty, func_exit(); return 0; } - + bp = port_Board(port); if (!tty || !port->xmit_buf || !tmp_buf) { @@ -1824,7 +1822,7 @@ static int sx_chars_in_buffer(struct tty_struct *tty) struct specialix_port *port = (struct specialix_port *)tty->driver_data; func_enter(); - + if (sx_paranoia_check(port, tty->name, "sx_chars_in_buffer")) { func_exit(); return 0; @@ -1881,13 +1879,13 @@ static int sx_tiocmget(struct tty_struct *tty, struct file *file) port_No(port), status, sx_in (bp, CD186x_CAR)); dprintk (SX_DEBUG_INIT, "sx_port = %p, port = %p\n", sx_port, port); if (SX_CRTSCTS(port->tty)) { - result = /* (status & MSVR_RTS) ? */ TIOCM_DTR /* : 0) */ + result = /* (status & MSVR_RTS) ? */ TIOCM_DTR /* : 0) */ | ((status & MSVR_DTR) ? TIOCM_RTS : 0) | ((status & MSVR_CD) ? TIOCM_CAR : 0) |/* ((status & MSVR_DSR) ? */ TIOCM_DSR /* : 0) */ | ((status & MSVR_CTS) ? TIOCM_CTS : 0); } else { - result = /* (status & MSVR_RTS) ? */ TIOCM_RTS /* : 0) */ + result = /* (status & MSVR_RTS) ? */ TIOCM_RTS /* : 0) */ | ((status & MSVR_DTR) ? TIOCM_DTR : 0) | ((status & MSVR_CD) ? TIOCM_CAR : 0) |/* ((status & MSVR_DSR) ? */ TIOCM_DSR /* : 0) */ @@ -1955,7 +1953,7 @@ static inline void sx_send_break(struct specialix_port * port, unsigned long len { struct specialix_board *bp = port_Board(port); unsigned long flags; - + func_enter(); spin_lock_irqsave (&port->lock, flags); @@ -1996,8 +1994,8 @@ static inline int sx_set_serial_info(struct specialix_port * port, func_enter(); return -EFAULT; } - -#if 0 + +#if 0 if ((tmp.irq != bp->irq) || (tmp.port != bp->base) || (tmp.type != PORT_CIRRUS) || @@ -2008,12 +2006,12 @@ static inline int sx_set_serial_info(struct specialix_port * port, func_exit(); return -EINVAL; } -#endif +#endif change_speed = ((port->flags & ASYNC_SPD_MASK) != (tmp.flags & ASYNC_SPD_MASK)); change_speed |= (tmp.custom_divisor != port->custom_divisor); - + if (!capable(CAP_SYS_ADMIN)) { if ((tmp.close_delay != port->close_delay) || (tmp.closing_wait != port->closing_wait) || @@ -2045,7 +2043,7 @@ static inline int sx_get_serial_info(struct specialix_port * port, { struct serial_struct tmp; struct specialix_board *bp = port_Board(port); - + func_enter(); /* @@ -2074,7 +2072,7 @@ static inline int sx_get_serial_info(struct specialix_port * port, } -static int sx_ioctl(struct tty_struct * tty, struct file * filp, +static int sx_ioctl(struct tty_struct * tty, struct file * filp, unsigned int cmd, unsigned long arg) { struct specialix_port *port = (struct specialix_port *)tty->driver_data; @@ -2087,7 +2085,7 @@ static int sx_ioctl(struct tty_struct * tty, struct file * filp, func_exit(); return -ENODEV; } - + switch (cmd) { case TCSBRK: /* SVID version: non-zero arg --> no break */ retval = tty_check_change(tty); @@ -2129,7 +2127,7 @@ static int sx_ioctl(struct tty_struct * tty, struct file * filp, case TIOCGSERIAL: func_exit(); return sx_get_serial_info(port, argp); - case TIOCSSERIAL: + case TIOCSSERIAL: func_exit(); return sx_set_serial_info(port, argp); default: @@ -2153,16 +2151,16 @@ static void sx_throttle(struct tty_struct * tty) func_exit(); return; } - + bp = port_Board(port); - + /* Use DTR instead of RTS ! */ - if (SX_CRTSCTS (tty)) + if (SX_CRTSCTS (tty)) port->MSVR &= ~MSVR_DTR; else { /* Auch!!! I think the system shouldn't call this then. */ /* Or maybe we're supposed (allowed?) to do our side of hw - handshake anyway, even when hardware handshake is off. + handshake anyway, even when hardware handshake is off. When you see this in your logs, please report.... */ printk (KERN_ERR "sx%d: Need to throttle, but can't (hardware hs is off)\n", port_No (port)); @@ -2193,14 +2191,14 @@ static void sx_unthrottle(struct tty_struct * tty) unsigned long flags; func_enter(); - + if (sx_paranoia_check(port, tty->name, "sx_unthrottle")) { func_exit(); return; } - + bp = port_Board(port); - + spin_lock_irqsave(&port->lock, flags); /* XXXX Use DTR INSTEAD???? */ if (SX_CRTSCTS(tty)) { @@ -2234,14 +2232,14 @@ static void sx_stop(struct tty_struct * tty) unsigned long flags; func_enter(); - + if (sx_paranoia_check(port, tty->name, "sx_stop")) { func_exit(); return; } bp = port_Board(port); - + spin_lock_irqsave(&port->lock, flags); port->IER &= ~IER_TXRDY; spin_lock_irqsave(&bp->lock, flags); @@ -2261,14 +2259,14 @@ static void sx_start(struct tty_struct * tty) unsigned long flags; func_enter(); - + if (sx_paranoia_check(port, tty->name, "sx_start")) { func_exit(); return; } - + bp = port_Board(port); - + spin_lock_irqsave(&port->lock, flags); if (port->xmit_cnt && port->xmit_buf && !(port->IER & IER_TXRDY)) { port->IER |= IER_TXRDY; @@ -2290,13 +2288,13 @@ static void sx_start(struct tty_struct * tty) * * serial interrupt routine -> (workqueue) -> * do_sx_hangup() -> tty->hangup() -> sx_hangup() - * + * */ static void do_sx_hangup(void *private_) { struct specialix_port *port = (struct specialix_port *) private_; struct tty_struct *tty; - + func_enter(); tty = port->tty; @@ -2319,9 +2317,9 @@ static void sx_hangup(struct tty_struct * tty) func_exit(); return; } - + bp = port_Board(port); - + sx_shutdown_port(bp, port); spin_lock_irqsave(&port->lock, flags); port->event = 0; @@ -2346,10 +2344,10 @@ static void sx_set_termios(struct tty_struct * tty, struct termios * old_termios struct specialix_port *port = (struct specialix_port *)tty->driver_data; unsigned long flags; struct specialix_board * bp; - + if (sx_paranoia_check(port, tty->name, "sx_set_termios")) return; - + if (tty->termios->c_cflag == old_termios->c_cflag && tty->termios->c_iflag == old_termios->c_iflag) return; @@ -2420,7 +2418,7 @@ static int sx_init_drivers(void) func_exit(); return 1; } - + if (!(tmp_buf = (unsigned char *) get_zeroed_page(GFP_KERNEL))) { printk(KERN_ERR "sx: Couldn't get free page.\n"); put_tty_driver(specialix_driver); @@ -2457,7 +2455,7 @@ static int sx_init_drivers(void) init_waitqueue_head(&sx_port[i].close_wait); spin_lock_init(&sx_port[i].lock); } - + func_exit(); return 0; } @@ -2472,8 +2470,8 @@ static void sx_release_drivers(void) func_exit(); } -/* - * This routine must be called by kernel at boot time +/* + * This routine must be called by kernel at boot time */ static int __init specialix_init(void) { @@ -2489,7 +2487,7 @@ static int __init specialix_init(void) #else printk (KERN_INFO "sx: DTR/RTS pin is RTS when CRTSCTS is on.\n"); #endif - + for (i = 0; i < SX_NBOARD; i++) sx_board[i].lock = SPIN_LOCK_UNLOCKED; @@ -2498,7 +2496,7 @@ static int __init specialix_init(void) return -EIO; } - for (i = 0; i < SX_NBOARD; i++) + for (i = 0; i < SX_NBOARD; i++) if (sx_board[i].base && !sx_probe(&sx_board[i])) found++; @@ -2512,8 +2510,8 @@ static int __init specialix_init(void) i++; continue; } - pdev = pci_find_device (PCI_VENDOR_ID_SPECIALIX, - PCI_DEVICE_ID_SPECIALIX_IO8, + pdev = pci_find_device (PCI_VENDOR_ID_SPECIALIX, + PCI_DEVICE_ID_SPECIALIX_IO8, pdev); if (!pdev) break; @@ -2557,10 +2555,10 @@ module_param(sx_poll, int, 0); /* * You can setup up to 4 boards. * by specifying "iobase=0xXXX,0xXXX ..." as insmod parameter. - * You should specify the IRQs too in that case "irq=....,...". - * + * You should specify the IRQs too in that case "irq=....,...". + * * More than 4 boards in one computer is not possible, as the card can - * only use 4 different interrupts. + * only use 4 different interrupts. * */ static int __init specialix_init_module(void) @@ -2583,16 +2581,16 @@ static int __init specialix_init_module(void) return specialix_init(); } - + static void __exit specialix_exit_module(void) { int i; - + func_enter(); sx_release_drivers(); for (i = 0; i < SX_NBOARD; i++) - if (sx_board[i].flags & SX_BOARD_PRESENT) + if (sx_board[i].flags & SX_BOARD_PRESENT) sx_release_io_range(&sx_board[i]); #ifdef SPECIALIX_TIMER del_timer (&missed_irq_timer); diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c index 951545a6ef2d..1c686414e0a1 100644 --- a/drivers/char/stallion.c +++ b/drivers/char/stallion.c @@ -3095,7 +3095,9 @@ static int __init stl_init(void) devfs_mk_cdev(MKDEV(STL_SIOMEMMAJOR, i), S_IFCHR|S_IRUSR|S_IWUSR, "staliomem/%d", i); - class_device_create(stallion_class, MKDEV(STL_SIOMEMMAJOR, i), NULL, "staliomem%d", i); + class_device_create(stallion_class, NULL, + MKDEV(STL_SIOMEMMAJOR, i), NULL, + "staliomem%d", i); } stl_serial->owner = THIS_MODULE; diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c index ea2d54be4843..0133dc0e25d0 100644 --- a/drivers/char/synclink.c +++ b/drivers/char/synclink.c @@ -912,6 +912,7 @@ MODULE_DEVICE_TABLE(pci, synclink_pci_tbl); MODULE_LICENSE("GPL"); static struct pci_driver synclink_pci_driver = { + .owner = THIS_MODULE, .name = "synclink", .id_table = synclink_pci_tbl, .probe = synclink_init_one, diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c index 6fb165cf8a61..f185724448b1 100644 --- a/drivers/char/synclinkmp.c +++ b/drivers/char/synclinkmp.c @@ -500,6 +500,7 @@ MODULE_DEVICE_TABLE(pci, synclinkmp_pci_tbl); MODULE_LICENSE("GPL"); static struct pci_driver synclinkmp_pci_driver = { + .owner = THIS_MODULE, .name = "synclinkmp", .id_table = synclinkmp_pci_tbl, .probe = synclinkmp_init_one, diff --git a/drivers/char/tipar.c b/drivers/char/tipar.c index ec78d2f161f7..41a94bc79f67 100644 --- a/drivers/char/tipar.c +++ b/drivers/char/tipar.c @@ -436,7 +436,7 @@ tipar_register(int nr, struct parport *port) goto out; } - class_device_create(tipar_class, MKDEV(TIPAR_MAJOR, + class_device_create(tipar_class, NULL, MKDEV(TIPAR_MAJOR, TIPAR_MINOR + nr), NULL, "par%d", nr); /* Use devfs, tree: /dev/ticables/par/[0..2] */ err = devfs_mk_cdev(MKDEV(TIPAR_MAJOR, TIPAR_MINOR + nr), diff --git a/drivers/char/tlclk.c b/drivers/char/tlclk.c new file mode 100644 index 000000000000..18cdd4361dc6 --- /dev/null +++ b/drivers/char/tlclk.c @@ -0,0 +1,896 @@ +/* + * Telecom Clock driver for Intel NetStructure(tm) MPCBL0010 + * + * Copyright (C) 2005 Kontron Canada + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to <sebastien.bouchard@ca.kontron.com> and the current + * Maintainer <mark.gross@intel.com> + * + * Description : This is the TELECOM CLOCK module driver for the ATCA + * MPCBL0010 ATCA computer. + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/kernel.h> /* printk() */ +#include <linux/fs.h> /* everything... */ +#include <linux/errno.h> /* error codes */ +#include <linux/delay.h> /* udelay */ +#include <linux/slab.h> +#include <linux/ioport.h> +#include <linux/interrupt.h> +#include <linux/spinlock.h> +#include <linux/timer.h> +#include <linux/sysfs.h> +#include <linux/device.h> +#include <linux/miscdevice.h> +#include <asm/io.h> /* inb/outb */ +#include <asm/uaccess.h> + +MODULE_AUTHOR("Sebastien Bouchard <sebastien.bouchard@ca.kontron.com>"); +MODULE_LICENSE("GPL"); + +/*Hardware Reset of the PLL */ +#define RESET_ON 0x00 +#define RESET_OFF 0x01 + +/* MODE SELECT */ +#define NORMAL_MODE 0x00 +#define HOLDOVER_MODE 0x10 +#define FREERUN_MODE 0x20 + +/* FILTER SELECT */ +#define FILTER_6HZ 0x04 +#define FILTER_12HZ 0x00 + +/* SELECT REFERENCE FREQUENCY */ +#define REF_CLK1_8kHz 0x00 +#define REF_CLK2_19_44MHz 0x02 + +/* Select primary or secondary redundant clock */ +#define PRIMARY_CLOCK 0x00 +#define SECONDARY_CLOCK 0x01 + +/* CLOCK TRANSMISSION DEFINE */ +#define CLK_8kHz 0xff +#define CLK_16_384MHz 0xfb + +#define CLK_1_544MHz 0x00 +#define CLK_2_048MHz 0x01 +#define CLK_4_096MHz 0x02 +#define CLK_6_312MHz 0x03 +#define CLK_8_192MHz 0x04 +#define CLK_19_440MHz 0x06 + +#define CLK_8_592MHz 0x08 +#define CLK_11_184MHz 0x09 +#define CLK_34_368MHz 0x0b +#define CLK_44_736MHz 0x0a + +/* RECEIVED REFERENCE */ +#define AMC_B1 0 +#define AMC_B2 1 + +/* HARDWARE SWITCHING DEFINE */ +#define HW_ENABLE 0x80 +#define HW_DISABLE 0x00 + +/* HARDWARE SWITCHING MODE DEFINE */ +#define PLL_HOLDOVER 0x40 +#define LOST_CLOCK 0x00 + +/* ALARMS DEFINE */ +#define UNLOCK_MASK 0x10 +#define HOLDOVER_MASK 0x20 +#define SEC_LOST_MASK 0x40 +#define PRI_LOST_MASK 0x80 + +/* INTERRUPT CAUSE DEFINE */ + +#define PRI_LOS_01_MASK 0x01 +#define PRI_LOS_10_MASK 0x02 + +#define SEC_LOS_01_MASK 0x04 +#define SEC_LOS_10_MASK 0x08 + +#define HOLDOVER_01_MASK 0x10 +#define HOLDOVER_10_MASK 0x20 + +#define UNLOCK_01_MASK 0x40 +#define UNLOCK_10_MASK 0x80 + +struct tlclk_alarms { + __u32 lost_clocks; + __u32 lost_primary_clock; + __u32 lost_secondary_clock; + __u32 primary_clock_back; + __u32 secondary_clock_back; + __u32 switchover_primary; + __u32 switchover_secondary; + __u32 pll_holdover; + __u32 pll_end_holdover; + __u32 pll_lost_sync; + __u32 pll_sync; +}; +/* Telecom clock I/O register definition */ +#define TLCLK_BASE 0xa08 +#define TLCLK_REG0 TLCLK_BASE +#define TLCLK_REG1 (TLCLK_BASE+1) +#define TLCLK_REG2 (TLCLK_BASE+2) +#define TLCLK_REG3 (TLCLK_BASE+3) +#define TLCLK_REG4 (TLCLK_BASE+4) +#define TLCLK_REG5 (TLCLK_BASE+5) +#define TLCLK_REG6 (TLCLK_BASE+6) +#define TLCLK_REG7 (TLCLK_BASE+7) + +#define SET_PORT_BITS(port, mask, val) outb(((inb(port) & mask) | val), port) + +/* 0 = Dynamic allocation of the major device number */ +#define TLCLK_MAJOR 0 + +/* sysfs interface definition: +Upon loading the driver will create a sysfs directory under +/sys/devices/platform/telco_clock. + +This directory exports the following interfaces. There operation is +documented in the MCPBL0010 TPS under the Telecom Clock API section, 11.4. +alarms : +current_ref : +enable_clk3a_output : +enable_clk3b_output : +enable_clka0_output : +enable_clka1_output : +enable_clkb0_output : +enable_clkb1_output : +filter_select : +hardware_switching : +hardware_switching_mode : +interrupt_switch : +mode_select : +refalign : +reset : +select_amcb1_transmit_clock : +select_amcb2_transmit_clock : +select_redundant_clock : +select_ref_frequency : +test_mode : + +All sysfs interfaces are integers in hex format, i.e echo 99 > refalign +has the same effect as echo 0x99 > refalign. +*/ + +static unsigned int telclk_interrupt; + +static int int_events; /* Event that generate a interrupt */ +static int got_event; /* if events processing have been done */ + +static void switchover_timeout(unsigned long data); +static struct timer_list switchover_timer = + TIMER_INITIALIZER(switchover_timeout , 0, 0); + +static struct tlclk_alarms *alarm_events; + +static DEFINE_SPINLOCK(event_lock); + +static int tlclk_major = TLCLK_MAJOR; + +static irqreturn_t tlclk_interrupt(int irq, void *dev_id, struct pt_regs *regs); + +static DECLARE_WAIT_QUEUE_HEAD(wq); + +static int tlclk_open(struct inode *inode, struct file *filp) +{ + int result; + + /* Make sure there is no interrupt pending while + * initialising interrupt handler */ + inb(TLCLK_REG6); + + /* This device is wired through the FPGA IO space of the ATCA blade + * we can't share this IRQ */ + result = request_irq(telclk_interrupt, &tlclk_interrupt, + SA_INTERRUPT, "telco_clock", tlclk_interrupt); + if (result == -EBUSY) { + printk(KERN_ERR "telco_clock: Interrupt can't be reserved!\n"); + return -EBUSY; + } + inb(TLCLK_REG6); /* Clear interrupt events */ + + return 0; +} + +static int tlclk_release(struct inode *inode, struct file *filp) +{ + free_irq(telclk_interrupt, tlclk_interrupt); + + return 0; +} + +ssize_t tlclk_read(struct file *filp, char __user *buf, size_t count, + loff_t *f_pos) +{ + if (count < sizeof(struct tlclk_alarms)) + return -EIO; + + wait_event_interruptible(wq, got_event); + if (copy_to_user(buf, alarm_events, sizeof(struct tlclk_alarms))) + return -EFAULT; + + memset(alarm_events, 0, sizeof(struct tlclk_alarms)); + got_event = 0; + + return sizeof(struct tlclk_alarms); +} + +ssize_t tlclk_write(struct file *filp, const char __user *buf, size_t count, + loff_t *f_pos) +{ + return 0; +} + +static struct file_operations tlclk_fops = { + .read = tlclk_read, + .write = tlclk_write, + .open = tlclk_open, + .release = tlclk_release, + +}; + +static struct miscdevice tlclk_miscdev = { + .minor = MISC_DYNAMIC_MINOR, + .name = "telco_clock", + .fops = &tlclk_fops, +}; + +static ssize_t show_current_ref(struct device *d, + struct device_attribute *attr, char *buf) +{ + unsigned long ret_val; + unsigned long flags; + + spin_lock_irqsave(&event_lock, flags); + ret_val = ((inb(TLCLK_REG1) & 0x08) >> 3); + spin_unlock_irqrestore(&event_lock, flags); + + return sprintf(buf, "0x%lX\n", ret_val); +} + +static DEVICE_ATTR(current_ref, S_IRUGO, show_current_ref, NULL); + + +static ssize_t show_interrupt_switch(struct device *d, + struct device_attribute *attr, char *buf) +{ + unsigned long ret_val; + unsigned long flags; + + spin_lock_irqsave(&event_lock, flags); + ret_val = inb(TLCLK_REG6); + spin_unlock_irqrestore(&event_lock, flags); + + return sprintf(buf, "0x%lX\n", ret_val); +} + +static DEVICE_ATTR(interrupt_switch, S_IRUGO, + show_interrupt_switch, NULL); + +static ssize_t show_alarms(struct device *d, + struct device_attribute *attr, char *buf) +{ + unsigned long ret_val; + unsigned long flags; + + spin_lock_irqsave(&event_lock, flags); + ret_val = (inb(TLCLK_REG2) & 0xf0); + spin_unlock_irqrestore(&event_lock, flags); + + return sprintf(buf, "0x%lX\n", ret_val); +} + +static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); + +static ssize_t store_enable_clk3b_output(struct device *d, + struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned long tmp; + unsigned char val; + unsigned long flags; + + sscanf(buf, "%lX", &tmp); + dev_dbg(d, ": tmp = 0x%lX\n", tmp); + + val = (unsigned char)tmp; + spin_lock_irqsave(&event_lock, flags); + SET_PORT_BITS(TLCLK_REG3, 0x7f, val << 7); + spin_unlock_irqrestore(&event_lock, flags); + + return strnlen(buf, count); +} + +static DEVICE_ATTR(enable_clk3b_output, S_IWUGO, NULL, + store_enable_clk3b_output); + +static ssize_t store_enable_clk3a_output(struct device *d, + struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned long flags; + unsigned long tmp; + unsigned char val; + + sscanf(buf, "%lX", &tmp); + dev_dbg(d, "tmp = 0x%lX\n", tmp); + + val = (unsigned char)tmp; + spin_lock_irqsave(&event_lock, flags); + SET_PORT_BITS(TLCLK_REG3, 0xbf, val << 6); + spin_unlock_irqrestore(&event_lock, flags); + + return strnlen(buf, count); +} + +static DEVICE_ATTR(enable_clk3a_output, S_IWUGO, NULL, + store_enable_clk3a_output); + +static ssize_t store_enable_clkb1_output(struct device *d, + struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned long flags; + unsigned long tmp; + unsigned char val; + + sscanf(buf, "%lX", &tmp); + dev_dbg(d, "tmp = 0x%lX\n", tmp); + + val = (unsigned char)tmp; + spin_lock_irqsave(&event_lock, flags); + SET_PORT_BITS(TLCLK_REG2, 0xf7, val << 3); + spin_unlock_irqrestore(&event_lock, flags); + + return strnlen(buf, count); +} + +static DEVICE_ATTR(enable_clkb1_output, S_IWUGO, NULL, + store_enable_clkb1_output); + + +static ssize_t store_enable_clka1_output(struct device *d, + struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned long flags; + unsigned long tmp; + unsigned char val; + + sscanf(buf, "%lX", &tmp); + dev_dbg(d, "tmp = 0x%lX\n", tmp); + + val = (unsigned char)tmp; + spin_lock_irqsave(&event_lock, flags); + SET_PORT_BITS(TLCLK_REG2, 0xfb, val << 2); + spin_unlock_irqrestore(&event_lock, flags); + + return strnlen(buf, count); +} + +static DEVICE_ATTR(enable_clka1_output, S_IWUGO, NULL, + store_enable_clka1_output); + +static ssize_t store_enable_clkb0_output(struct device *d, + struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned long flags; + unsigned long tmp; + unsigned char val; + + sscanf(buf, "%lX", &tmp); + dev_dbg(d, "tmp = 0x%lX\n", tmp); + + val = (unsigned char)tmp; + spin_lock_irqsave(&event_lock, flags); + SET_PORT_BITS(TLCLK_REG2, 0xfd, val << 1); + spin_unlock_irqrestore(&event_lock, flags); + + return strnlen(buf, count); +} + +static DEVICE_ATTR(enable_clkb0_output, S_IWUGO, NULL, + store_enable_clkb0_output); + +static ssize_t store_enable_clka0_output(struct device *d, + struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned long flags; + unsigned long tmp; + unsigned char val; + + sscanf(buf, "%lX", &tmp); + dev_dbg(d, "tmp = 0x%lX\n", tmp); + + val = (unsigned char)tmp; + spin_lock_irqsave(&event_lock, flags); + SET_PORT_BITS(TLCLK_REG2, 0xfe, val); + spin_unlock_irqrestore(&event_lock, flags); + + return strnlen(buf, count); +} + +static DEVICE_ATTR(enable_clka0_output, S_IWUGO, NULL, + store_enable_clka0_output); + +static ssize_t store_test_mode(struct device *d, + struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned long flags; + unsigned long tmp; + unsigned char val; + + sscanf(buf, "%lX", &tmp); + dev_dbg(d, "tmp = 0x%lX\n", tmp); + + val = (unsigned char)tmp; + spin_lock_irqsave(&event_lock, flags); + SET_PORT_BITS(TLCLK_REG4, 0xfd, 2); + spin_unlock_irqrestore(&event_lock, flags); + + return strnlen(buf, count); +} + +static DEVICE_ATTR(test_mode, S_IWUGO, NULL, store_test_mode); + +static ssize_t store_select_amcb2_transmit_clock(struct device *d, + struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned long flags; + unsigned long tmp; + unsigned char val; + + sscanf(buf, "%lX", &tmp); + dev_dbg(d, "tmp = 0x%lX\n", tmp); + + val = (unsigned char)tmp; + spin_lock_irqsave(&event_lock, flags); + if ((val == CLK_8kHz) || (val == CLK_16_384MHz)) { + SET_PORT_BITS(TLCLK_REG3, 0xc7, 0x28); + SET_PORT_BITS(TLCLK_REG1, 0xfb, ~val); + } else if (val >= CLK_8_592MHz) { + SET_PORT_BITS(TLCLK_REG3, 0xc7, 0x38); + switch (val) { + case CLK_8_592MHz: + SET_PORT_BITS(TLCLK_REG0, 0xfc, 1); + break; + case CLK_11_184MHz: + SET_PORT_BITS(TLCLK_REG0, 0xfc, 0); + break; + case CLK_34_368MHz: + SET_PORT_BITS(TLCLK_REG0, 0xfc, 3); + break; + case CLK_44_736MHz: + SET_PORT_BITS(TLCLK_REG0, 0xfc, 2); + break; + } + } else + SET_PORT_BITS(TLCLK_REG3, 0xc7, val << 3); + + spin_unlock_irqrestore(&event_lock, flags); + + return strnlen(buf, count); +} + +static DEVICE_ATTR(select_amcb2_transmit_clock, S_IWUGO, NULL, + store_select_amcb2_transmit_clock); + +static ssize_t store_select_amcb1_transmit_clock(struct device *d, + struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned long tmp; + unsigned char val; + unsigned long flags; + + sscanf(buf, "%lX", &tmp); + dev_dbg(d, "tmp = 0x%lX\n", tmp); + + val = (unsigned char)tmp; + spin_lock_irqsave(&event_lock, flags); + if ((val == CLK_8kHz) || (val == CLK_16_384MHz)) { + SET_PORT_BITS(TLCLK_REG3, 0xf8, 0x5); + SET_PORT_BITS(TLCLK_REG1, 0xfb, ~val); + } else if (val >= CLK_8_592MHz) { + SET_PORT_BITS(TLCLK_REG3, 0xf8, 0x7); + switch (val) { + case CLK_8_592MHz: + SET_PORT_BITS(TLCLK_REG0, 0xfc, 1); + break; + case CLK_11_184MHz: + SET_PORT_BITS(TLCLK_REG0, 0xfc, 0); + break; + case CLK_34_368MHz: + SET_PORT_BITS(TLCLK_REG0, 0xfc, 3); + break; + case CLK_44_736MHz: + SET_PORT_BITS(TLCLK_REG0, 0xfc, 2); + break; + } + } else + SET_PORT_BITS(TLCLK_REG3, 0xf8, val); + spin_unlock_irqrestore(&event_lock, flags); + + return strnlen(buf, count); +} + +static DEVICE_ATTR(select_amcb1_transmit_clock, S_IWUGO, NULL, + store_select_amcb1_transmit_clock); + +static ssize_t store_select_redundant_clock(struct device *d, + struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned long tmp; + unsigned char val; + unsigned long flags; + + sscanf(buf, "%lX", &tmp); + dev_dbg(d, "tmp = 0x%lX\n", tmp); + + val = (unsigned char)tmp; + spin_lock_irqsave(&event_lock, flags); + SET_PORT_BITS(TLCLK_REG1, 0xfe, val); + spin_unlock_irqrestore(&event_lock, flags); + + return strnlen(buf, count); +} + +static DEVICE_ATTR(select_redundant_clock, S_IWUGO, NULL, + store_select_redundant_clock); + +static ssize_t store_select_ref_frequency(struct device *d, + struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned long tmp; + unsigned char val; + unsigned long flags; + + sscanf(buf, "%lX", &tmp); + dev_dbg(d, "tmp = 0x%lX\n", tmp); + + val = (unsigned char)tmp; + spin_lock_irqsave(&event_lock, flags); + SET_PORT_BITS(TLCLK_REG1, 0xfd, val); + spin_unlock_irqrestore(&event_lock, flags); + + return strnlen(buf, count); +} + +static DEVICE_ATTR(select_ref_frequency, S_IWUGO, NULL, + store_select_ref_frequency); + +static ssize_t store_filter_select(struct device *d, + struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned long tmp; + unsigned char val; + unsigned long flags; + + sscanf(buf, "%lX", &tmp); + dev_dbg(d, "tmp = 0x%lX\n", tmp); + + val = (unsigned char)tmp; + spin_lock_irqsave(&event_lock, flags); + SET_PORT_BITS(TLCLK_REG0, 0xfb, val); + spin_unlock_irqrestore(&event_lock, flags); + + return strnlen(buf, count); +} + +static DEVICE_ATTR(filter_select, S_IWUGO, NULL, store_filter_select); + +static ssize_t store_hardware_switching_mode(struct device *d, + struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned long tmp; + unsigned char val; + unsigned long flags; + + sscanf(buf, "%lX", &tmp); + dev_dbg(d, "tmp = 0x%lX\n", tmp); + + val = (unsigned char)tmp; + spin_lock_irqsave(&event_lock, flags); + SET_PORT_BITS(TLCLK_REG0, 0xbf, val); + spin_unlock_irqrestore(&event_lock, flags); + + return strnlen(buf, count); +} + +static DEVICE_ATTR(hardware_switching_mode, S_IWUGO, NULL, + store_hardware_switching_mode); + +static ssize_t store_hardware_switching(struct device *d, + struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned long tmp; + unsigned char val; + unsigned long flags; + + sscanf(buf, "%lX", &tmp); + dev_dbg(d, "tmp = 0x%lX\n", tmp); + + val = (unsigned char)tmp; + spin_lock_irqsave(&event_lock, flags); + SET_PORT_BITS(TLCLK_REG0, 0x7f, val); + spin_unlock_irqrestore(&event_lock, flags); + + return strnlen(buf, count); +} + +static DEVICE_ATTR(hardware_switching, S_IWUGO, NULL, + store_hardware_switching); + +static ssize_t store_refalign (struct device *d, + struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned long tmp; + unsigned long flags; + + sscanf(buf, "%lX", &tmp); + dev_dbg(d, "tmp = 0x%lX\n", tmp); + spin_lock_irqsave(&event_lock, flags); + SET_PORT_BITS(TLCLK_REG0, 0xf7, 0); + udelay(2); + SET_PORT_BITS(TLCLK_REG0, 0xf7, 0x08); + udelay(2); + SET_PORT_BITS(TLCLK_REG0, 0xf7, 0); + spin_unlock_irqrestore(&event_lock, flags); + + return strnlen(buf, count); +} + +static DEVICE_ATTR(refalign, S_IWUGO, NULL, store_refalign); + +static ssize_t store_mode_select (struct device *d, + struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned long tmp; + unsigned char val; + unsigned long flags; + + sscanf(buf, "%lX", &tmp); + dev_dbg(d, "tmp = 0x%lX\n", tmp); + + val = (unsigned char)tmp; + spin_lock_irqsave(&event_lock, flags); + SET_PORT_BITS(TLCLK_REG0, 0xcf, val); + spin_unlock_irqrestore(&event_lock, flags); + + return strnlen(buf, count); +} + +static DEVICE_ATTR(mode_select, S_IWUGO, NULL, store_mode_select); + +static ssize_t store_reset (struct device *d, + struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned long tmp; + unsigned char val; + unsigned long flags; + + sscanf(buf, "%lX", &tmp); + dev_dbg(d, "tmp = 0x%lX\n", tmp); + + val = (unsigned char)tmp; + spin_lock_irqsave(&event_lock, flags); + SET_PORT_BITS(TLCLK_REG4, 0xfd, val); + spin_unlock_irqrestore(&event_lock, flags); + + return strnlen(buf, count); +} + +static DEVICE_ATTR(reset, S_IWUGO, NULL, store_reset); + +static struct attribute *tlclk_sysfs_entries[] = { + &dev_attr_current_ref.attr, + &dev_attr_interrupt_switch.attr, + &dev_attr_alarms.attr, + &dev_attr_enable_clk3a_output.attr, + &dev_attr_enable_clk3b_output.attr, + &dev_attr_enable_clkb1_output.attr, + &dev_attr_enable_clka1_output.attr, + &dev_attr_enable_clkb0_output.attr, + &dev_attr_enable_clka0_output.attr, + &dev_attr_test_mode.attr, + &dev_attr_select_amcb1_transmit_clock.attr, + &dev_attr_select_amcb2_transmit_clock.attr, + &dev_attr_select_redundant_clock.attr, + &dev_attr_select_ref_frequency.attr, + &dev_attr_filter_select.attr, + &dev_attr_hardware_switching_mode.attr, + &dev_attr_hardware_switching.attr, + &dev_attr_refalign.attr, + &dev_attr_mode_select.attr, + &dev_attr_reset.attr, + NULL +}; + +static struct attribute_group tlclk_attribute_group = { + .name = NULL, /* put in device directory */ + .attrs = tlclk_sysfs_entries, +}; + +static struct platform_device *tlclk_device; + +static int __init tlclk_init(void) +{ + int ret; + + ret = register_chrdev(tlclk_major, "telco_clock", &tlclk_fops); + if (ret < 0) { + printk(KERN_ERR "telco_clock: can't get major! %d\n", tlclk_major); + return ret; + } + alarm_events = kzalloc( sizeof(struct tlclk_alarms), GFP_KERNEL); + if (!alarm_events) + goto out1; + + /* Read telecom clock IRQ number (Set by BIOS) */ + if (!request_region(TLCLK_BASE, 8, "telco_clock")) { + printk(KERN_ERR "tlclk: request_region failed! 0x%X\n", + TLCLK_BASE); + ret = -EBUSY; + goto out2; + } + telclk_interrupt = (inb(TLCLK_REG7) & 0x0f); + + if (0x0F == telclk_interrupt ) { /* not MCPBL0010 ? */ + printk(KERN_ERR "telclk_interrup = 0x%x non-mcpbl0010 hw\n", + telclk_interrupt); + ret = -ENXIO; + goto out3; + } + + init_timer(&switchover_timer); + + ret = misc_register(&tlclk_miscdev); + if (ret < 0) { + printk(KERN_ERR " misc_register retruns %d\n", ret); + ret = -EBUSY; + goto out3; + } + + tlclk_device = platform_device_register_simple("telco_clock", + -1, NULL, 0); + if (!tlclk_device) { + printk(KERN_ERR " platform_device_register retruns 0x%X\n", + (unsigned int) tlclk_device); + ret = -EBUSY; + goto out4; + } + + ret = sysfs_create_group(&tlclk_device->dev.kobj, + &tlclk_attribute_group); + if (ret) { + printk(KERN_ERR "failed to create sysfs device attributes\n"); + sysfs_remove_group(&tlclk_device->dev.kobj, + &tlclk_attribute_group); + goto out5; + } + + return 0; +out5: + platform_device_unregister(tlclk_device); +out4: + misc_deregister(&tlclk_miscdev); +out3: + release_region(TLCLK_BASE, 8); +out2: + kfree(alarm_events); +out1: + unregister_chrdev(tlclk_major, "telco_clock"); + return ret; +} + +static void __exit tlclk_cleanup(void) +{ + sysfs_remove_group(&tlclk_device->dev.kobj, &tlclk_attribute_group); + platform_device_unregister(tlclk_device); + misc_deregister(&tlclk_miscdev); + unregister_chrdev(tlclk_major, "telco_clock"); + + release_region(TLCLK_BASE, 8); + del_timer_sync(&switchover_timer); + kfree(alarm_events); + +} + +static void switchover_timeout(unsigned long data) +{ + if ((data & 1)) { + if ((inb(TLCLK_REG1) & 0x08) != (data & 0x08)) + alarm_events->switchover_primary++; + } else { + if ((inb(TLCLK_REG1) & 0x08) != (data & 0x08)) + alarm_events->switchover_secondary++; + } + + /* Alarm processing is done, wake up read task */ + del_timer(&switchover_timer); + got_event = 1; + wake_up(&wq); +} + +static irqreturn_t tlclk_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned long flags; + + spin_lock_irqsave(&event_lock, flags); + /* Read and clear interrupt events */ + int_events = inb(TLCLK_REG6); + + /* Primary_Los changed from 0 to 1 ? */ + if (int_events & PRI_LOS_01_MASK) { + if (inb(TLCLK_REG2) & SEC_LOST_MASK) + alarm_events->lost_clocks++; + else + alarm_events->lost_primary_clock++; + } + + /* Primary_Los changed from 1 to 0 ? */ + if (int_events & PRI_LOS_10_MASK) { + alarm_events->primary_clock_back++; + SET_PORT_BITS(TLCLK_REG1, 0xFE, 1); + } + /* Secondary_Los changed from 0 to 1 ? */ + if (int_events & SEC_LOS_01_MASK) { + if (inb(TLCLK_REG2) & PRI_LOST_MASK) + alarm_events->lost_clocks++; + else + alarm_events->lost_secondary_clock++; + } + /* Secondary_Los changed from 1 to 0 ? */ + if (int_events & SEC_LOS_10_MASK) { + alarm_events->secondary_clock_back++; + SET_PORT_BITS(TLCLK_REG1, 0xFE, 0); + } + if (int_events & HOLDOVER_10_MASK) + alarm_events->pll_end_holdover++; + + if (int_events & UNLOCK_01_MASK) + alarm_events->pll_lost_sync++; + + if (int_events & UNLOCK_10_MASK) + alarm_events->pll_sync++; + + /* Holdover changed from 0 to 1 ? */ + if (int_events & HOLDOVER_01_MASK) { + alarm_events->pll_holdover++; + + /* TIMEOUT in ~10ms */ + switchover_timer.expires = jiffies + msecs_to_jiffies(10); + switchover_timer.data = inb(TLCLK_REG1); + add_timer(&switchover_timer); + } else { + got_event = 1; + wake_up(&wq); + } + spin_unlock_irqrestore(&event_lock, flags); + + return IRQ_HANDLED; +} + +module_init(tlclk_init); +module_exit(tlclk_cleanup); diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 049d128ae7f0..303f15880466 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -64,7 +64,7 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, if (count == 0) return -ENODATA; if (count > bufsiz) { - dev_err(&chip->pci_dev->dev, + dev_err(chip->dev, "invalid count value %x %zx \n", count, bufsiz); return -E2BIG; } @@ -72,21 +72,21 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, down(&chip->tpm_mutex); if ((rc = chip->vendor->send(chip, (u8 *) buf, count)) < 0) { - dev_err(&chip->pci_dev->dev, + dev_err(chip->dev, "tpm_transmit: tpm_send: error %zd\n", rc); goto out; } stop = jiffies + 2 * 60 * HZ; do { - u8 status = inb(chip->vendor->base + 1); + u8 status = chip->vendor->status(chip); if ((status & chip->vendor->req_complete_mask) == chip->vendor->req_complete_val) { goto out_recv; } if ((status == chip->vendor->req_canceled)) { - dev_err(&chip->pci_dev->dev, "Operation Canceled\n"); + dev_err(chip->dev, "Operation Canceled\n"); rc = -ECANCELED; goto out; } @@ -97,14 +97,14 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, chip->vendor->cancel(chip); - dev_err(&chip->pci_dev->dev, "Operation Timed out\n"); + dev_err(chip->dev, "Operation Timed out\n"); rc = -ETIME; goto out; out_recv: rc = chip->vendor->recv(chip, (u8 *) buf, bufsiz); if (rc < 0) - dev_err(&chip->pci_dev->dev, + dev_err(chip->dev, "tpm_transmit: tpm_recv: error %zd\n", rc); out: up(&chip->tpm_mutex); @@ -139,15 +139,14 @@ ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr, __be32 index; char *str = buf; - struct tpm_chip *chip = - pci_get_drvdata(to_pci_dev(dev)); + struct tpm_chip *chip = dev_get_drvdata(dev); if (chip == NULL) return -ENODEV; memcpy(data, cap_pcr, sizeof(cap_pcr)); if ((len = tpm_transmit(chip, data, sizeof(data))) < CAP_PCR_RESULT_SIZE) { - dev_dbg(&chip->pci_dev->dev, "A TPM error (%d) occurred " + dev_dbg(chip->dev, "A TPM error (%d) occurred " "attempting to determine the number of PCRS\n", be32_to_cpu(*((__be32 *) (data + 6)))); return 0; @@ -161,9 +160,10 @@ ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr, memcpy(data + 10, &index, 4); if ((len = tpm_transmit(chip, data, sizeof(data))) < READ_PCR_RESULT_SIZE){ - dev_dbg(&chip->pci_dev->dev, "A TPM error (%d) occurred" + dev_dbg(chip->dev, "A TPM error (%d) occurred" " attempting to read PCR %d of %d\n", - be32_to_cpu(*((__be32 *) (data + 6))), i, num_pcrs); + be32_to_cpu(*((__be32 *) (data + 6))), + i, num_pcrs); goto out; } str += sprintf(str, "PCR-%02d: ", i); @@ -191,21 +191,19 @@ ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr, int i, rc; char *str = buf; - struct tpm_chip *chip = - pci_get_drvdata(to_pci_dev(dev)); + struct tpm_chip *chip = dev_get_drvdata(dev); if (chip == NULL) return -ENODEV; - data = kmalloc(READ_PUBEK_RESULT_SIZE, GFP_KERNEL); + data = kzalloc(READ_PUBEK_RESULT_SIZE, GFP_KERNEL); if (!data) return -ENOMEM; memcpy(data, readpubek, sizeof(readpubek)); - memset(data + sizeof(readpubek), 0, 20); /* zero nonce */ if ((len = tpm_transmit(chip, data, READ_PUBEK_RESULT_SIZE)) < READ_PUBEK_RESULT_SIZE) { - dev_dbg(&chip->pci_dev->dev, "A TPM error (%d) occurred " + dev_dbg(chip->dev, "A TPM error (%d) occurred " "attempting to read the PUBEK\n", be32_to_cpu(*((__be32 *) (data + 6)))); rc = 0; @@ -245,7 +243,6 @@ out: kfree(data); return rc; } - EXPORT_SYMBOL_GPL(tpm_show_pubek); #define CAP_VER_RESULT_SIZE 18 @@ -274,8 +271,7 @@ ssize_t tpm_show_caps(struct device *dev, struct device_attribute *attr, ssize_t len; char *str = buf; - struct tpm_chip *chip = - pci_get_drvdata(to_pci_dev(dev)); + struct tpm_chip *chip = dev_get_drvdata(dev); if (chip == NULL) return -ENODEV; @@ -315,7 +311,6 @@ ssize_t tpm_store_cancel(struct device *dev, struct device_attribute *attr, } EXPORT_SYMBOL_GPL(tpm_store_cancel); - /* * Device file system interface to the TPM */ @@ -339,21 +334,20 @@ int tpm_open(struct inode *inode, struct file *file) } if (chip->num_opens) { - dev_dbg(&chip->pci_dev->dev, - "Another process owns this TPM\n"); + dev_dbg(chip->dev, "Another process owns this TPM\n"); rc = -EBUSY; goto err_out; } chip->num_opens++; - pci_dev_get(chip->pci_dev); + get_device(chip->dev); spin_unlock(&driver_lock); chip->data_buffer = kmalloc(TPM_BUFSIZE * sizeof(u8), GFP_KERNEL); if (chip->data_buffer == NULL) { chip->num_opens--; - pci_dev_put(chip->pci_dev); + put_device(chip->dev); return -ENOMEM; } @@ -366,7 +360,6 @@ err_out: spin_unlock(&driver_lock); return rc; } - EXPORT_SYMBOL_GPL(tpm_open); int tpm_release(struct inode *inode, struct file *file) @@ -378,15 +371,14 @@ int tpm_release(struct inode *inode, struct file *file) chip->num_opens--; del_singleshot_timer_sync(&chip->user_read_timer); atomic_set(&chip->data_pending, 0); - pci_dev_put(chip->pci_dev); + put_device(chip->dev); kfree(chip->data_buffer); spin_unlock(&driver_lock); return 0; } - EXPORT_SYMBOL_GPL(tpm_release); -ssize_t tpm_write(struct file * file, const char __user * buf, +ssize_t tpm_write(struct file *file, const char __user *buf, size_t size, loff_t * off) { struct tpm_chip *chip = file->private_data; @@ -422,7 +414,7 @@ ssize_t tpm_write(struct file * file, const char __user * buf, EXPORT_SYMBOL_GPL(tpm_write); -ssize_t tpm_read(struct file * file, char __user * buf, +ssize_t tpm_read(struct file * file, char __user *buf, size_t size, loff_t * off) { struct tpm_chip *chip = file->private_data; @@ -444,15 +436,14 @@ ssize_t tpm_read(struct file * file, char __user * buf, return ret_size; } - EXPORT_SYMBOL_GPL(tpm_read); -void __devexit tpm_remove(struct pci_dev *pci_dev) +void tpm_remove_hardware(struct device *dev) { - struct tpm_chip *chip = pci_get_drvdata(pci_dev); + struct tpm_chip *chip = dev_get_drvdata(dev); if (chip == NULL) { - dev_err(&pci_dev->dev, "No device data found\n"); + dev_err(dev, "No device data found\n"); return; } @@ -462,22 +453,20 @@ void __devexit tpm_remove(struct pci_dev *pci_dev) spin_unlock(&driver_lock); - pci_set_drvdata(pci_dev, NULL); + dev_set_drvdata(dev, NULL); misc_deregister(&chip->vendor->miscdev); kfree(chip->vendor->miscdev.name); - sysfs_remove_group(&pci_dev->dev.kobj, chip->vendor->attr_group); + sysfs_remove_group(&dev->kobj, chip->vendor->attr_group); - pci_disable_device(pci_dev); - - dev_mask[chip->dev_num / TPM_NUM_MASK_ENTRIES ] &= !(1 << (chip->dev_num % TPM_NUM_MASK_ENTRIES)); + dev_mask[chip->dev_num / TPM_NUM_MASK_ENTRIES ] &= + !(1 << (chip->dev_num % TPM_NUM_MASK_ENTRIES)); kfree(chip); - pci_dev_put(pci_dev); + put_device(dev); } - -EXPORT_SYMBOL_GPL(tpm_remove); +EXPORT_SYMBOL_GPL(tpm_remove_hardware); static u8 savestate[] = { 0, 193, /* TPM_TAG_RQU_COMMAND */ @@ -489,32 +478,30 @@ static u8 savestate[] = { * We are about to suspend. Save the TPM state * so that it can be restored. */ -int tpm_pm_suspend(struct pci_dev *pci_dev, pm_message_t pm_state) +int tpm_pm_suspend(struct device *dev, pm_message_t pm_state) { - struct tpm_chip *chip = pci_get_drvdata(pci_dev); + struct tpm_chip *chip = dev_get_drvdata(dev); if (chip == NULL) return -ENODEV; tpm_transmit(chip, savestate, sizeof(savestate)); return 0; } - EXPORT_SYMBOL_GPL(tpm_pm_suspend); /* * Resume from a power safe. The BIOS already restored * the TPM state. */ -int tpm_pm_resume(struct pci_dev *pci_dev) +int tpm_pm_resume(struct device *dev) { - struct tpm_chip *chip = pci_get_drvdata(pci_dev); + struct tpm_chip *chip = dev_get_drvdata(dev); if (chip == NULL) return -ENODEV; return 0; } - EXPORT_SYMBOL_GPL(tpm_pm_resume); /* @@ -524,8 +511,7 @@ EXPORT_SYMBOL_GPL(tpm_pm_resume); * upon errant exit from this function specific probe function should call * pci_disable_device */ -int tpm_register_hardware(struct pci_dev *pci_dev, - struct tpm_vendor_specific *entry) +int tpm_register_hardware(struct device *dev, struct tpm_vendor_specific *entry) { #define DEVNAME_SIZE 7 @@ -534,12 +520,10 @@ int tpm_register_hardware(struct pci_dev *pci_dev, int i, j; /* Driver specific per-device data */ - chip = kmalloc(sizeof(*chip), GFP_KERNEL); + chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; - memset(chip, 0, sizeof(struct tpm_chip)); - init_MUTEX(&chip->buffer_mutex); init_MUTEX(&chip->tpm_mutex); INIT_LIST_HEAD(&chip->list); @@ -563,8 +547,7 @@ int tpm_register_hardware(struct pci_dev *pci_dev, dev_num_search_complete: if (chip->dev_num < 0) { - dev_err(&pci_dev->dev, - "No available tpm device numbers\n"); + dev_err(dev, "No available tpm device numbers\n"); kfree(chip); return -ENODEV; } else if (chip->dev_num == 0) @@ -576,15 +559,15 @@ dev_num_search_complete: scnprintf(devname, DEVNAME_SIZE, "%s%d", "tpm", chip->dev_num); chip->vendor->miscdev.name = devname; - chip->vendor->miscdev.dev = &(pci_dev->dev); - chip->pci_dev = pci_dev_get(pci_dev); + chip->vendor->miscdev.dev = dev; + chip->dev = get_device(dev); if (misc_register(&chip->vendor->miscdev)) { - dev_err(&chip->pci_dev->dev, + dev_err(chip->dev, "unable to misc_register %s, minor %d\n", chip->vendor->miscdev.name, chip->vendor->miscdev.minor); - pci_dev_put(pci_dev); + put_device(dev); kfree(chip); dev_mask[i] &= !(1 << j); return -ENODEV; @@ -592,17 +575,16 @@ dev_num_search_complete: spin_lock(&driver_lock); - pci_set_drvdata(pci_dev, chip); + dev_set_drvdata(dev, chip); list_add(&chip->list, &tpm_chip_list); spin_unlock(&driver_lock); - sysfs_create_group(&pci_dev->dev.kobj, chip->vendor->attr_group); + sysfs_create_group(&dev->kobj, chip->vendor->attr_group); return 0; } - EXPORT_SYMBOL_GPL(tpm_register_hardware); MODULE_AUTHOR("Leendert van Doorn (leendert@watson.ibm.com)"); diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 373b41f6b460..024814b50c3c 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -55,12 +55,13 @@ struct tpm_vendor_specific { int (*recv) (struct tpm_chip *, u8 *, size_t); int (*send) (struct tpm_chip *, u8 *, size_t); void (*cancel) (struct tpm_chip *); + u8 (*status) (struct tpm_chip *); struct miscdevice miscdev; struct attribute_group *attr_group; }; struct tpm_chip { - struct pci_dev *pci_dev; /* PCI device stuff */ + struct device *dev; /* Device stuff */ int dev_num; /* /dev/tpm# */ int num_opens; /* only one allowed */ @@ -91,13 +92,13 @@ static inline void tpm_write_index(int base, int index, int value) outb(value & 0xFF, base+1); } -extern int tpm_register_hardware(struct pci_dev *, +extern int tpm_register_hardware(struct device *, struct tpm_vendor_specific *); extern int tpm_open(struct inode *, struct file *); extern int tpm_release(struct inode *, struct file *); extern ssize_t tpm_write(struct file *, const char __user *, size_t, loff_t *); extern ssize_t tpm_read(struct file *, char __user *, size_t, loff_t *); -extern void __devexit tpm_remove(struct pci_dev *); -extern int tpm_pm_suspend(struct pci_dev *, pm_message_t); -extern int tpm_pm_resume(struct pci_dev *); +extern void tpm_remove_hardware(struct device *); +extern int tpm_pm_suspend(struct device *, pm_message_t); +extern int tpm_pm_resume(struct device *); diff --git a/drivers/char/tpm/tpm_atmel.c b/drivers/char/tpm/tpm_atmel.c index c0d64914595f..8cb42e84723c 100644 --- a/drivers/char/tpm/tpm_atmel.c +++ b/drivers/char/tpm/tpm_atmel.c @@ -40,7 +40,7 @@ enum tpm_atmel_read_status { ATML_STATUS_READY = 0x08 }; -static int tpm_atml_recv(struct tpm_chip *chip, u8 * buf, size_t count) +static int tpm_atml_recv(struct tpm_chip *chip, u8 *buf, size_t count) { u8 status, *hdr = buf; u32 size; @@ -54,7 +54,7 @@ static int tpm_atml_recv(struct tpm_chip *chip, u8 * buf, size_t count) for (i = 0; i < 6; i++) { status = inb(chip->vendor->base + 1); if ((status & ATML_STATUS_DATA_AVAIL) == 0) { - dev_err(&chip->pci_dev->dev, + dev_err(chip->dev, "error reading header\n"); return -EIO; } @@ -66,12 +66,12 @@ static int tpm_atml_recv(struct tpm_chip *chip, u8 * buf, size_t count) size = be32_to_cpu(*native_size); if (count < size) { - dev_err(&chip->pci_dev->dev, + dev_err(chip->dev, "Recv size(%d) less than available space\n", size); for (; i < size; i++) { /* clear the waiting data anyway */ status = inb(chip->vendor->base + 1); if ((status & ATML_STATUS_DATA_AVAIL) == 0) { - dev_err(&chip->pci_dev->dev, + dev_err(chip->dev, "error reading data\n"); return -EIO; } @@ -83,7 +83,7 @@ static int tpm_atml_recv(struct tpm_chip *chip, u8 * buf, size_t count) for (; i < size; i++) { status = inb(chip->vendor->base + 1); if ((status & ATML_STATUS_DATA_AVAIL) == 0) { - dev_err(&chip->pci_dev->dev, + dev_err(chip->dev, "error reading data\n"); return -EIO; } @@ -93,20 +93,20 @@ static int tpm_atml_recv(struct tpm_chip *chip, u8 * buf, size_t count) /* make sure data available is gone */ status = inb(chip->vendor->base + 1); if (status & ATML_STATUS_DATA_AVAIL) { - dev_err(&chip->pci_dev->dev, "data available is stuck\n"); + dev_err(chip->dev, "data available is stuck\n"); return -EIO; } return size; } -static int tpm_atml_send(struct tpm_chip *chip, u8 * buf, size_t count) +static int tpm_atml_send(struct tpm_chip *chip, u8 *buf, size_t count) { int i; - dev_dbg(&chip->pci_dev->dev, "tpm_atml_send: "); + dev_dbg(chip->dev, "tpm_atml_send:\n"); for (i = 0; i < count; i++) { - dev_dbg(&chip->pci_dev->dev, "0x%x(%d) ", buf[i], buf[i]); + dev_dbg(chip->dev, "%d 0x%x(%d)\n", i, buf[i], buf[i]); outb(buf[i], chip->vendor->base); } @@ -118,6 +118,11 @@ static void tpm_atml_cancel(struct tpm_chip *chip) outb(ATML_STATUS_ABORT, chip->vendor->base + 1); } +static u8 tpm_atml_status(struct tpm_chip *chip) +{ + return inb(chip->vendor->base + 1); +} + static struct file_operations atmel_ops = { .owner = THIS_MODULE, .llseek = no_llseek, @@ -137,7 +142,7 @@ static struct attribute* atmel_attrs[] = { &dev_attr_pcrs.attr, &dev_attr_caps.attr, &dev_attr_cancel.attr, - 0, + NULL, }; static struct attribute_group atmel_attr_grp = { .attrs = atmel_attrs }; @@ -146,6 +151,7 @@ static struct tpm_vendor_specific tpm_atmel = { .recv = tpm_atml_recv, .send = tpm_atml_send, .cancel = tpm_atml_cancel, + .status = tpm_atml_status, .req_complete_mask = ATML_STATUS_BUSY | ATML_STATUS_DATA_AVAIL, .req_complete_val = ATML_STATUS_DATA_AVAIL, .req_canceled = ATML_STATUS_READY, @@ -153,86 +159,94 @@ static struct tpm_vendor_specific tpm_atmel = { .miscdev = { .fops = &atmel_ops, }, }; -static int __devinit tpm_atml_init(struct pci_dev *pci_dev, - const struct pci_device_id *pci_id) +static struct platform_device *pdev; + +static void __devexit tpm_atml_remove(struct device *dev) +{ + struct tpm_chip *chip = dev_get_drvdata(dev); + if (chip) { + release_region(chip->vendor->base, 2); + tpm_remove_hardware(chip->dev); + } +} + +static struct device_driver atml_drv = { + .name = "tpm_atmel", + .bus = &platform_bus_type, + .owner = THIS_MODULE, + .suspend = tpm_pm_suspend, + .resume = tpm_pm_resume, +}; + +static int __init init_atmel(void) { - u8 version[4]; int rc = 0; int lo, hi; - if (pci_enable_device(pci_dev)) - return -EIO; + driver_register(&atml_drv); lo = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_LO); hi = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_HI); tpm_atmel.base = (hi<<8)|lo; - dev_dbg( &pci_dev->dev, "Operating with base: 0x%x\n", tpm_atmel.base); /* verify that it is an Atmel part */ if (tpm_read_index(TPM_ADDR, 4) != 'A' || tpm_read_index(TPM_ADDR, 5) != 'T' || tpm_read_index(TPM_ADDR, 6) != 'M' || tpm_read_index(TPM_ADDR, 7) != 'L') { - rc = -ENODEV; - goto out_err; + return -ENODEV; } - /* query chip for its version number */ - if ((version[0] = tpm_read_index(TPM_ADDR, 0x00)) != 0xFF) { - version[1] = tpm_read_index(TPM_ADDR, 0x01); - version[2] = tpm_read_index(TPM_ADDR, 0x02); - version[3] = tpm_read_index(TPM_ADDR, 0x03); - } else { - dev_info(&pci_dev->dev, "version query failed\n"); - rc = -ENODEV; - goto out_err; + /* verify chip version number is 1.1 */ + if ( (tpm_read_index(TPM_ADDR, 0x00) != 0x01) || + (tpm_read_index(TPM_ADDR, 0x01) != 0x01 )) + return -ENODEV; + + pdev = kzalloc(sizeof(struct platform_device), GFP_KERNEL); + if ( !pdev ) + return -ENOMEM; + + pdev->name = "tpm_atmel0"; + pdev->id = -1; + pdev->num_resources = 0; + pdev->dev.release = tpm_atml_remove; + pdev->dev.driver = &atml_drv; + + if ((rc = platform_device_register(pdev)) < 0) { + kfree(pdev); + pdev = NULL; + return rc; } - if ((rc = tpm_register_hardware(pci_dev, &tpm_atmel)) < 0) - goto out_err; + if (request_region(tpm_atmel.base, 2, "tpm_atmel0") == NULL ) { + platform_device_unregister(pdev); + kfree(pdev); + pdev = NULL; + return -EBUSY; + } - dev_info(&pci_dev->dev, - "Atmel TPM version %d.%d.%d.%d\n", version[0], version[1], - version[2], version[3]); + if ((rc = tpm_register_hardware(&pdev->dev, &tpm_atmel)) < 0) { + release_region(tpm_atmel.base, 2); + platform_device_unregister(pdev); + kfree(pdev); + pdev = NULL; + return rc; + } + dev_info(&pdev->dev, "Atmel TPM 1.1, Base Address: 0x%x\n", + tpm_atmel.base); return 0; -out_err: - pci_disable_device(pci_dev); - return rc; -} - -static struct pci_device_id tpm_pci_tbl[] __devinitdata = { - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_0)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0)}, - {PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_LPC)}, - {PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6LPC)}, - {0,} -}; - -MODULE_DEVICE_TABLE(pci, tpm_pci_tbl); - -static struct pci_driver atmel_pci_driver = { - .name = "tpm_atmel", - .id_table = tpm_pci_tbl, - .probe = tpm_atml_init, - .remove = __devexit_p(tpm_remove), - .suspend = tpm_pm_suspend, - .resume = tpm_pm_resume, -}; - -static int __init init_atmel(void) -{ - return pci_register_driver(&atmel_pci_driver); } static void __exit cleanup_atmel(void) { - pci_unregister_driver(&atmel_pci_driver); + if (pdev) { + tpm_atml_remove(&pdev->dev); + platform_device_unregister(pdev); + kfree(pdev); + pdev = NULL; + } + + driver_unregister(&atml_drv); } module_init(init_atmel); diff --git a/drivers/char/tpm/tpm_infineon.c b/drivers/char/tpm/tpm_infineon.c index 939e51e119e6..8198dbb7370f 100644 --- a/drivers/char/tpm/tpm_infineon.c +++ b/drivers/char/tpm/tpm_infineon.c @@ -5,6 +5,7 @@ * Specifications at www.trustedcomputinggroup.org * * Copyright (C) 2005, Marcel Selhorst <selhorst@crypto.rub.de> + * Sirrix AG - security technologies, http://www.sirrix.com and * Applied Data Security Group, Ruhr-University Bochum, Germany * Project-Homepage: http://www.prosec.rub.de/tpm * @@ -29,9 +30,10 @@ #define TPM_INFINEON_DEV_VEN_VALUE 0x15D1 /* These values will be filled after PnP-call */ -static int TPM_INF_DATA = 0; -static int TPM_INF_ADDR = 0; -static int pnp_registered = 0; +static int TPM_INF_DATA; +static int TPM_INF_ADDR; +static int TPM_INF_BASE; +static int TPM_INF_PORT_LEN; /* TPM header definitions */ enum infineon_tpm_header { @@ -143,11 +145,9 @@ static int wait(struct tpm_chip *chip, int wait_for_bit) } if (i == TPM_MAX_TRIES) { /* timeout occurs */ if (wait_for_bit == STAT_XFE) - dev_err(&chip->pci_dev->dev, - "Timeout in wait(STAT_XFE)\n"); + dev_err(chip->dev, "Timeout in wait(STAT_XFE)\n"); if (wait_for_bit == STAT_RDA) - dev_err(&chip->pci_dev->dev, - "Timeout in wait(STAT_RDA)\n"); + dev_err(chip->dev, "Timeout in wait(STAT_RDA)\n"); return -EIO; } return 0; @@ -170,7 +170,7 @@ static void wait_and_send(struct tpm_chip *chip, u8 sendbyte) static void tpm_wtx(struct tpm_chip *chip) { number_of_wtx++; - dev_info(&chip->pci_dev->dev, "Granting WTX (%02d / %02d)\n", + dev_info(chip->dev, "Granting WTX (%02d / %02d)\n", number_of_wtx, TPM_MAX_WTX_PACKAGES); wait_and_send(chip, TPM_VL_VER); wait_and_send(chip, TPM_CTRL_WTX); @@ -181,7 +181,7 @@ static void tpm_wtx(struct tpm_chip *chip) static void tpm_wtx_abort(struct tpm_chip *chip) { - dev_info(&chip->pci_dev->dev, "Aborting WTX\n"); + dev_info(chip->dev, "Aborting WTX\n"); wait_and_send(chip, TPM_VL_VER); wait_and_send(chip, TPM_CTRL_WTX_ABORT); wait_and_send(chip, 0x00); @@ -206,7 +206,7 @@ recv_begin: } if (buf[0] != TPM_VL_VER) { - dev_err(&chip->pci_dev->dev, + dev_err(chip->dev, "Wrong transport protocol implementation!\n"); return -EIO; } @@ -221,8 +221,7 @@ recv_begin: } if ((size == 0x6D00) && (buf[1] == 0x80)) { - dev_err(&chip->pci_dev->dev, - "Error handling on vendor layer!\n"); + dev_err(chip->dev, "Error handling on vendor layer!\n"); return -EIO; } @@ -234,7 +233,7 @@ recv_begin: } if (buf[1] == TPM_CTRL_WTX) { - dev_info(&chip->pci_dev->dev, "WTX-package received\n"); + dev_info(chip->dev, "WTX-package received\n"); if (number_of_wtx < TPM_MAX_WTX_PACKAGES) { tpm_wtx(chip); goto recv_begin; @@ -245,14 +244,14 @@ recv_begin: } if (buf[1] == TPM_CTRL_WTX_ABORT_ACK) { - dev_info(&chip->pci_dev->dev, "WTX-abort acknowledged\n"); + dev_info(chip->dev, "WTX-abort acknowledged\n"); return size; } if (buf[1] == TPM_CTRL_ERROR) { - dev_err(&chip->pci_dev->dev, "ERROR-package received:\n"); + dev_err(chip->dev, "ERROR-package received:\n"); if (buf[4] == TPM_INF_NAK) - dev_err(&chip->pci_dev->dev, + dev_err(chip->dev, "-> Negative acknowledgement" " - retransmit command!\n"); return -EIO; @@ -271,7 +270,7 @@ static int tpm_inf_send(struct tpm_chip *chip, u8 * buf, size_t count) ret = empty_fifo(chip, 1); if (ret) { - dev_err(&chip->pci_dev->dev, "Timeout while clearing FIFO\n"); + dev_err(chip->dev, "Timeout while clearing FIFO\n"); return -EIO; } @@ -316,6 +315,11 @@ static void tpm_inf_cancel(struct tpm_chip *chip) */ } +static u8 tpm_inf_status(struct tpm_chip *chip) +{ + return inb(chip->vendor->base + STAT); +} + static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL); static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL); static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL); @@ -344,6 +348,7 @@ static struct tpm_vendor_specific tpm_inf = { .recv = tpm_inf_recv, .send = tpm_inf_send, .cancel = tpm_inf_cancel, + .status = tpm_inf_status, .req_complete_mask = 0, .req_complete_val = 0, .attr_group = &inf_attr_grp, @@ -356,30 +361,11 @@ static const struct pnp_device_id tpm_pnp_tbl[] = { {"IFX0102", 0}, {"", 0} }; + MODULE_DEVICE_TABLE(pnp, tpm_pnp_tbl); static int __devinit tpm_inf_pnp_probe(struct pnp_dev *dev, - const struct pnp_device_id *dev_id) -{ - if (pnp_port_valid(dev, 0)) { - TPM_INF_ADDR = (pnp_port_start(dev, 0) & 0xff); - TPM_INF_DATA = ((TPM_INF_ADDR + 1) & 0xff); - tpm_inf.base = pnp_port_start(dev, 1); - dev_info(&dev->dev, "Found %s with ID %s\n", - dev->name, dev_id->id); - return 0; - } - return -ENODEV; -} - -static struct pnp_driver tpm_inf_pnp = { - .name = "tpm_inf_pnp", - .id_table = tpm_pnp_tbl, - .probe = tpm_inf_pnp_probe, -}; - -static int __devinit tpm_inf_probe(struct pci_dev *pci_dev, - const struct pci_device_id *pci_id) + const struct pnp_device_id *dev_id) { int rc = 0; u8 iol, ioh; @@ -388,30 +374,28 @@ static int __devinit tpm_inf_probe(struct pci_dev *pci_dev, int productid[2]; char chipname[20]; - rc = pci_enable_device(pci_dev); - if (rc) - return rc; - - dev_info(&pci_dev->dev, "LPC-bus found at 0x%x\n", pci_id->device); - - /* read IO-ports from PnP */ - rc = pnp_register_driver(&tpm_inf_pnp); - if (rc < 0) { - dev_err(&pci_dev->dev, - "Error %x from pnp_register_driver!\n",rc); - goto error2; - } - if (!rc) { - dev_info(&pci_dev->dev, "No Infineon TPM found!\n"); - goto error; + /* read IO-ports through PnP */ + if (pnp_port_valid(dev, 0) && pnp_port_valid(dev, 1) && + !(pnp_port_flags(dev, 0) & IORESOURCE_DISABLED)) { + TPM_INF_ADDR = pnp_port_start(dev, 0); + TPM_INF_DATA = (TPM_INF_ADDR + 1); + TPM_INF_BASE = pnp_port_start(dev, 1); + TPM_INF_PORT_LEN = pnp_port_len(dev, 1); + if (!TPM_INF_PORT_LEN) + return -EINVAL; + dev_info(&dev->dev, "Found %s with ID %s\n", + dev->name, dev_id->id); + if (!((TPM_INF_BASE >> 8) & 0xff)) + return -EINVAL; + /* publish my base address and request region */ + tpm_inf.base = TPM_INF_BASE; + if (request_region + (tpm_inf.base, TPM_INF_PORT_LEN, "tpm_infineon0") == NULL) { + release_region(tpm_inf.base, TPM_INF_PORT_LEN); + return -EINVAL; + } } else { - pnp_registered = 1; - } - - /* Make sure, we have received valid config ports */ - if (!TPM_INF_ADDR) { - dev_err(&pci_dev->dev, "No valid IO-ports received!\n"); - goto error; + return -EINVAL; } /* query chip for its vendor, its version number a.s.o. */ @@ -443,10 +427,6 @@ static int __devinit tpm_inf_probe(struct pci_dev *pci_dev, if ((vendorid[0] << 8 | vendorid[1]) == (TPM_INFINEON_DEV_VEN_VALUE)) { - if (tpm_inf.base == 0) { - dev_err(&pci_dev->dev, "No IO-ports found!\n"); - goto error; - } /* configure TPM with IO-ports */ outb(IOLIMH, TPM_INF_ADDR); outb(((tpm_inf.base >> 8) & 0xff), TPM_INF_DATA); @@ -460,10 +440,11 @@ static int __devinit tpm_inf_probe(struct pci_dev *pci_dev, iol = inb(TPM_INF_DATA); if ((ioh << 8 | iol) != tpm_inf.base) { - dev_err(&pci_dev->dev, + dev_err(&dev->dev, "Could not set IO-ports to %04x\n", tpm_inf.base); - goto error; + release_region(tpm_inf.base, TPM_INF_PORT_LEN); + return -EIO; } /* activate register */ @@ -475,7 +456,7 @@ static int __devinit tpm_inf_probe(struct pci_dev *pci_dev, outb(RESET_LP_IRQC_DISABLE, tpm_inf.base + CMD); /* Finally, we're done, print some infos */ - dev_info(&pci_dev->dev, "TPM found: " + dev_info(&dev->dev, "TPM found: " "config base 0x%x, " "io base 0x%x, " "chip version %02x%02x, " @@ -483,59 +464,53 @@ static int __devinit tpm_inf_probe(struct pci_dev *pci_dev, "product id %02x%02x" "%s\n", TPM_INF_ADDR, - tpm_inf.base, + TPM_INF_BASE, version[0], version[1], vendorid[0], vendorid[1], productid[0], productid[1], chipname); - rc = tpm_register_hardware(pci_dev, &tpm_inf); - if (rc < 0) - goto error; + rc = tpm_register_hardware(&dev->dev, &tpm_inf); + if (rc < 0) { + release_region(tpm_inf.base, TPM_INF_PORT_LEN); + return -ENODEV; + } return 0; } else { - dev_info(&pci_dev->dev, "No Infineon TPM found!\n"); -error: - pnp_unregister_driver(&tpm_inf_pnp); -error2: - pci_disable_device(pci_dev); - pnp_registered = 0; + dev_info(&dev->dev, "No Infineon TPM found!\n"); return -ENODEV; } } -static struct pci_device_id tpm_pci_tbl[] __devinitdata = { - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_0)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_2)}, - {0,} -}; +static __devexit void tpm_inf_pnp_remove(struct pnp_dev *dev) +{ + struct tpm_chip *chip = pnp_get_drvdata(dev); -MODULE_DEVICE_TABLE(pci, tpm_pci_tbl); + if (chip) { + release_region(chip->vendor->base, TPM_INF_PORT_LEN); + tpm_remove_hardware(chip->dev); + } +} -static struct pci_driver inf_pci_driver = { - .name = "tpm_inf", - .id_table = tpm_pci_tbl, - .probe = tpm_inf_probe, - .remove = __devexit_p(tpm_remove), - .suspend = tpm_pm_suspend, - .resume = tpm_pm_resume, +static struct pnp_driver tpm_inf_pnp = { + .name = "tpm_inf_pnp", + .driver = { + .owner = THIS_MODULE, + .suspend = tpm_pm_suspend, + .resume = tpm_pm_resume, + }, + .id_table = tpm_pnp_tbl, + .probe = tpm_inf_pnp_probe, + .remove = tpm_inf_pnp_remove, }; static int __init init_inf(void) { - return pci_register_driver(&inf_pci_driver); + return pnp_register_driver(&tpm_inf_pnp); } static void __exit cleanup_inf(void) { - if (pnp_registered) - pnp_unregister_driver(&tpm_inf_pnp); - pci_unregister_driver(&inf_pci_driver); + pnp_unregister_driver(&tpm_inf_pnp); } module_init(init_inf); @@ -543,5 +518,5 @@ module_exit(cleanup_inf); MODULE_AUTHOR("Marcel Selhorst <selhorst@crypto.rub.de>"); MODULE_DESCRIPTION("Driver for Infineon TPM SLD 9630 TT 1.1 / SLB 9635 TT 1.2"); -MODULE_VERSION("1.5"); +MODULE_VERSION("1.6"); MODULE_LICENSE("GPL"); diff --git a/drivers/char/tpm/tpm_nsc.c b/drivers/char/tpm/tpm_nsc.c index b4127348c063..253871b5b1e2 100644 --- a/drivers/char/tpm/tpm_nsc.c +++ b/drivers/char/tpm/tpm_nsc.c @@ -111,7 +111,7 @@ static int nsc_wait_for_ready(struct tpm_chip *chip) } while (time_before(jiffies, stop)); - dev_info(&chip->pci_dev->dev, "wait for ready failed\n"); + dev_info(chip->dev, "wait for ready failed\n"); return -EBUSY; } @@ -127,12 +127,12 @@ static int tpm_nsc_recv(struct tpm_chip *chip, u8 * buf, size_t count) return -EIO; if (wait_for_stat(chip, NSC_STATUS_F0, NSC_STATUS_F0, &data) < 0) { - dev_err(&chip->pci_dev->dev, "F0 timeout\n"); + dev_err(chip->dev, "F0 timeout\n"); return -EIO; } if ((data = inb(chip->vendor->base + NSC_DATA)) != NSC_COMMAND_NORMAL) { - dev_err(&chip->pci_dev->dev, "not in normal mode (0x%x)\n", + dev_err(chip->dev, "not in normal mode (0x%x)\n", data); return -EIO; } @@ -141,7 +141,7 @@ static int tpm_nsc_recv(struct tpm_chip *chip, u8 * buf, size_t count) for (p = buffer; p < &buffer[count]; p++) { if (wait_for_stat (chip, NSC_STATUS_OBF, NSC_STATUS_OBF, &data) < 0) { - dev_err(&chip->pci_dev->dev, + dev_err(chip->dev, "OBF timeout (while reading data)\n"); return -EIO; } @@ -152,11 +152,11 @@ static int tpm_nsc_recv(struct tpm_chip *chip, u8 * buf, size_t count) if ((data & NSC_STATUS_F0) == 0 && (wait_for_stat(chip, NSC_STATUS_F0, NSC_STATUS_F0, &data) < 0)) { - dev_err(&chip->pci_dev->dev, "F0 not set\n"); + dev_err(chip->dev, "F0 not set\n"); return -EIO; } if ((data = inb(chip->vendor->base + NSC_DATA)) != NSC_COMMAND_EOC) { - dev_err(&chip->pci_dev->dev, + dev_err(chip->dev, "expected end of command(0x%x)\n", data); return -EIO; } @@ -187,19 +187,19 @@ static int tpm_nsc_send(struct tpm_chip *chip, u8 * buf, size_t count) return -EIO; if (wait_for_stat(chip, NSC_STATUS_IBF, 0, &data) < 0) { - dev_err(&chip->pci_dev->dev, "IBF timeout\n"); + dev_err(chip->dev, "IBF timeout\n"); return -EIO; } outb(NSC_COMMAND_NORMAL, chip->vendor->base + NSC_COMMAND); if (wait_for_stat(chip, NSC_STATUS_IBR, NSC_STATUS_IBR, &data) < 0) { - dev_err(&chip->pci_dev->dev, "IBR timeout\n"); + dev_err(chip->dev, "IBR timeout\n"); return -EIO; } for (i = 0; i < count; i++) { if (wait_for_stat(chip, NSC_STATUS_IBF, 0, &data) < 0) { - dev_err(&chip->pci_dev->dev, + dev_err(chip->dev, "IBF timeout (while writing data)\n"); return -EIO; } @@ -207,7 +207,7 @@ static int tpm_nsc_send(struct tpm_chip *chip, u8 * buf, size_t count) } if (wait_for_stat(chip, NSC_STATUS_IBF, 0, &data) < 0) { - dev_err(&chip->pci_dev->dev, "IBF timeout\n"); + dev_err(chip->dev, "IBF timeout\n"); return -EIO; } outb(NSC_COMMAND_EOC, chip->vendor->base + NSC_COMMAND); @@ -220,6 +220,11 @@ static void tpm_nsc_cancel(struct tpm_chip *chip) outb(NSC_COMMAND_CANCEL, chip->vendor->base + NSC_COMMAND); } +static u8 tpm_nsc_status(struct tpm_chip *chip) +{ + return inb(chip->vendor->base + NSC_STATUS); +} + static struct file_operations nsc_ops = { .owner = THIS_MODULE, .llseek = no_llseek, @@ -239,7 +244,7 @@ static struct attribute * nsc_attrs[] = { &dev_attr_pcrs.attr, &dev_attr_caps.attr, &dev_attr_cancel.attr, - 0, + NULL, }; static struct attribute_group nsc_attr_grp = { .attrs = nsc_attrs }; @@ -248,6 +253,7 @@ static struct tpm_vendor_specific tpm_nsc = { .recv = tpm_nsc_recv, .send = tpm_nsc_send, .cancel = tpm_nsc_cancel, + .status = tpm_nsc_status, .req_complete_mask = NSC_STATUS_OBF, .req_complete_val = NSC_STATUS_OBF, .req_canceled = NSC_STATUS_RDY, @@ -255,16 +261,32 @@ static struct tpm_vendor_specific tpm_nsc = { .miscdev = { .fops = &nsc_ops, }, }; -static int __devinit tpm_nsc_init(struct pci_dev *pci_dev, - const struct pci_device_id *pci_id) +static struct platform_device *pdev = NULL; + +static void __devexit tpm_nsc_remove(struct device *dev) +{ + struct tpm_chip *chip = dev_get_drvdata(dev); + if ( chip ) { + release_region(chip->vendor->base, 2); + tpm_remove_hardware(chip->dev); + } +} + +static struct device_driver nsc_drv = { + .name = "tpm_nsc", + .bus = &platform_bus_type, + .owner = THIS_MODULE, + .suspend = tpm_pm_suspend, + .resume = tpm_pm_resume, +}; + +static int __init init_nsc(void) { int rc = 0; int lo, hi; int nscAddrBase = TPM_ADDR; - - if (pci_enable_device(pci_dev)) - return -EIO; + driver_register(&nsc_drv); /* select PM channel 1 */ tpm_write_index(nscAddrBase,NSC_LDN_INDEX, 0x12); @@ -273,37 +295,71 @@ static int __devinit tpm_nsc_init(struct pci_dev *pci_dev, if (tpm_read_index(TPM_ADDR, NSC_SID_INDEX) != 0xEF) { nscAddrBase = (tpm_read_index(TPM_SUPERIO_ADDR, 0x2C)<<8)| (tpm_read_index(TPM_SUPERIO_ADDR, 0x2B)&0xFE); - if (tpm_read_index(nscAddrBase, NSC_SID_INDEX) != 0xF6) { - rc = -ENODEV; - goto out_err; - } + if (tpm_read_index(nscAddrBase, NSC_SID_INDEX) != 0xF6) + return -ENODEV; } hi = tpm_read_index(nscAddrBase, TPM_NSC_BASE0_HI); lo = tpm_read_index(nscAddrBase, TPM_NSC_BASE0_LO); tpm_nsc.base = (hi<<8) | lo; - dev_dbg(&pci_dev->dev, "NSC TPM detected\n"); - dev_dbg(&pci_dev->dev, + /* enable the DPM module */ + tpm_write_index(nscAddrBase, NSC_LDC_INDEX, 0x01); + + pdev = kmalloc(sizeof(struct platform_device), GFP_KERNEL); + if ( !pdev ) + return -ENOMEM; + + memset(pdev, 0, sizeof(struct platform_device)); + + pdev->name = "tpm_nscl0"; + pdev->id = -1; + pdev->num_resources = 0; + pdev->dev.release = tpm_nsc_remove; + pdev->dev.driver = &nsc_drv; + + if ((rc=platform_device_register(pdev)) < 0) { + kfree(pdev); + pdev = NULL; + return rc; + } + + if (request_region(tpm_nsc.base, 2, "tpm_nsc0") == NULL ) { + platform_device_unregister(pdev); + kfree(pdev); + pdev = NULL; + return -EBUSY; + } + + if ((rc = tpm_register_hardware(&pdev->dev, &tpm_nsc)) < 0) { + release_region(tpm_nsc.base, 2); + platform_device_unregister(pdev); + kfree(pdev); + pdev = NULL; + return rc; + } + + dev_dbg(&pdev->dev, "NSC TPM detected\n"); + dev_dbg(&pdev->dev, "NSC LDN 0x%x, SID 0x%x, SRID 0x%x\n", tpm_read_index(nscAddrBase,0x07), tpm_read_index(nscAddrBase,0x20), tpm_read_index(nscAddrBase,0x27)); - dev_dbg(&pci_dev->dev, + dev_dbg(&pdev->dev, "NSC SIOCF1 0x%x SIOCF5 0x%x SIOCF6 0x%x SIOCF8 0x%x\n", tpm_read_index(nscAddrBase,0x21), tpm_read_index(nscAddrBase,0x25), tpm_read_index(nscAddrBase,0x26), tpm_read_index(nscAddrBase,0x28)); - dev_dbg(&pci_dev->dev, "NSC IO Base0 0x%x\n", + dev_dbg(&pdev->dev, "NSC IO Base0 0x%x\n", (tpm_read_index(nscAddrBase,0x60) << 8) | tpm_read_index(nscAddrBase,0x61)); - dev_dbg(&pci_dev->dev, "NSC IO Base1 0x%x\n", + dev_dbg(&pdev->dev, "NSC IO Base1 0x%x\n", (tpm_read_index(nscAddrBase,0x62) << 8) | tpm_read_index(nscAddrBase,0x63)); - dev_dbg(&pci_dev->dev, "NSC Interrupt number and wakeup 0x%x\n", + dev_dbg(&pdev->dev, "NSC Interrupt number and wakeup 0x%x\n", tpm_read_index(nscAddrBase,0x70)); - dev_dbg(&pci_dev->dev, "NSC IRQ type select 0x%x\n", + dev_dbg(&pdev->dev, "NSC IRQ type select 0x%x\n", tpm_read_index(nscAddrBase,0x71)); - dev_dbg(&pci_dev->dev, + dev_dbg(&pdev->dev, "NSC DMA channel select0 0x%x, select1 0x%x\n", tpm_read_index(nscAddrBase,0x74), tpm_read_index(nscAddrBase,0x75)); - dev_dbg(&pci_dev->dev, + dev_dbg(&pdev->dev, "NSC Config " "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", tpm_read_index(nscAddrBase,0xF0), tpm_read_index(nscAddrBase,0xF1), @@ -312,55 +368,23 @@ static int __devinit tpm_nsc_init(struct pci_dev *pci_dev, tpm_read_index(nscAddrBase,0xF6), tpm_read_index(nscAddrBase,0xF7), tpm_read_index(nscAddrBase,0xF8), tpm_read_index(nscAddrBase,0xF9)); - dev_info(&pci_dev->dev, + dev_info(&pdev->dev, "NSC TPM revision %d\n", tpm_read_index(nscAddrBase, 0x27) & 0x1F); - /* enable the DPM module */ - tpm_write_index(nscAddrBase, NSC_LDC_INDEX, 0x01); - - if ((rc = tpm_register_hardware(pci_dev, &tpm_nsc)) < 0) - goto out_err; - return 0; - -out_err: - pci_disable_device(pci_dev); - return rc; -} - -static struct pci_device_id tpm_pci_tbl[] __devinitdata = { - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_0)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0)}, - {PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_LPC)}, - {0,} -}; - -MODULE_DEVICE_TABLE(pci, tpm_pci_tbl); - -static struct pci_driver nsc_pci_driver = { - .name = "tpm_nsc", - .id_table = tpm_pci_tbl, - .probe = tpm_nsc_init, - .remove = __devexit_p(tpm_remove), - .suspend = tpm_pm_suspend, - .resume = tpm_pm_resume, -}; - -static int __init init_nsc(void) -{ - return pci_register_driver(&nsc_pci_driver); } static void __exit cleanup_nsc(void) { - pci_unregister_driver(&nsc_pci_driver); + if (pdev) { + tpm_nsc_remove(&pdev->dev); + platform_device_unregister(pdev); + kfree(pdev); + pdev = NULL; + } + + driver_unregister(&nsc_drv); } module_init(init_nsc); diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index e5953f3433f3..c586bfa852ee 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -809,7 +809,7 @@ static void do_tty_hangup(void *data) check_tty_count(tty, "do_tty_hangup"); file_list_lock(); /* This breaks for file handles being sent over AF_UNIX sockets ? */ - list_for_each_entry(filp, &tty->tty_files, f_list) { + list_for_each_entry(filp, &tty->tty_files, f_u.fu_list) { if (filp->f_op->write == redirected_tty_write) cons_filp = filp; if (filp->f_op->write != tty_write) @@ -2728,7 +2728,7 @@ void tty_register_device(struct tty_driver *driver, unsigned index, pty_line_name(driver, index, name); else tty_line_name(driver, index, name); - class_device_create(tty_class, dev, device, name); + class_device_create(tty_class, NULL, dev, device, "%s", name); } /** @@ -2983,14 +2983,14 @@ static int __init tty_init(void) register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty") < 0) panic("Couldn't register /dev/tty driver\n"); devfs_mk_cdev(MKDEV(TTYAUX_MAJOR, 0), S_IFCHR|S_IRUGO|S_IWUGO, "tty"); - class_device_create(tty_class, MKDEV(TTYAUX_MAJOR, 0), NULL, "tty"); + class_device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL, "tty"); cdev_init(&console_cdev, &console_fops); if (cdev_add(&console_cdev, MKDEV(TTYAUX_MAJOR, 1), 1) || register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console") < 0) panic("Couldn't register /dev/console driver\n"); devfs_mk_cdev(MKDEV(TTYAUX_MAJOR, 1), S_IFCHR|S_IRUSR|S_IWUSR, "console"); - class_device_create(tty_class, MKDEV(TTYAUX_MAJOR, 1), NULL, "console"); + class_device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL, "console"); #ifdef CONFIG_UNIX98_PTYS cdev_init(&ptmx_cdev, &ptmx_fops); @@ -2998,7 +2998,7 @@ static int __init tty_init(void) register_chrdev_region(MKDEV(TTYAUX_MAJOR, 2), 1, "/dev/ptmx") < 0) panic("Couldn't register /dev/ptmx driver\n"); devfs_mk_cdev(MKDEV(TTYAUX_MAJOR, 2), S_IFCHR|S_IRUGO|S_IWUGO, "ptmx"); - class_device_create(tty_class, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx"); + class_device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx"); #endif #ifdef CONFIG_VT @@ -3007,7 +3007,7 @@ static int __init tty_init(void) register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0) panic("Couldn't register /dev/tty0 driver\n"); devfs_mk_cdev(MKDEV(TTY_MAJOR, 0), S_IFCHR|S_IRUSR|S_IWUSR, "vc/0"); - class_device_create(tty_class, MKDEV(TTY_MAJOR, 0), NULL, "tty0"); + class_device_create(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0"); vty_init(); #endif diff --git a/drivers/char/vc_screen.c b/drivers/char/vc_screen.c index 79c2928a8817..f66c7ad6fd38 100644 --- a/drivers/char/vc_screen.c +++ b/drivers/char/vc_screen.c @@ -484,8 +484,10 @@ void vcs_make_devfs(struct tty_struct *tty) devfs_mk_cdev(MKDEV(VCS_MAJOR, tty->index + 129), S_IFCHR|S_IRUSR|S_IWUSR, "vcc/a%u", tty->index + 1); - class_device_create(vc_class, MKDEV(VCS_MAJOR, tty->index + 1), NULL, "vcs%u", tty->index + 1); - class_device_create(vc_class, MKDEV(VCS_MAJOR, tty->index + 129), NULL, "vcsa%u", tty->index + 1); + class_device_create(vc_class, NULL, MKDEV(VCS_MAJOR, tty->index + 1), + NULL, "vcs%u", tty->index + 1); + class_device_create(vc_class, NULL, MKDEV(VCS_MAJOR, tty->index + 129), + NULL, "vcsa%u", tty->index + 1); } void vcs_remove_devfs(struct tty_struct *tty) { @@ -503,7 +505,7 @@ int __init vcs_init(void) devfs_mk_cdev(MKDEV(VCS_MAJOR, 0), S_IFCHR|S_IRUSR|S_IWUSR, "vcc/0"); devfs_mk_cdev(MKDEV(VCS_MAJOR, 128), S_IFCHR|S_IRUSR|S_IWUSR, "vcc/a0"); - class_device_create(vc_class, MKDEV(VCS_MAJOR, 0), NULL, "vcs"); - class_device_create(vc_class, MKDEV(VCS_MAJOR, 128), NULL, "vcsa"); + class_device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 0), NULL, "vcs"); + class_device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 128), NULL, "vcsa"); return 0; } diff --git a/drivers/char/viotape.c b/drivers/char/viotape.c index d92a05645007..51abd3defc1c 100644 --- a/drivers/char/viotape.c +++ b/drivers/char/viotape.c @@ -956,9 +956,9 @@ static int viotape_probe(struct vio_dev *vdev, const struct vio_device_id *id) state[i].cur_part = 0; for (j = 0; j < MAX_PARTITIONS; ++j) state[i].part_stat_rwi[j] = VIOT_IDLE; - class_device_create(tape_class, MKDEV(VIOTAPE_MAJOR, i), NULL, + class_device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i), NULL, "iseries!vt%d", i); - class_device_create(tape_class, MKDEV(VIOTAPE_MAJOR, i | 0x80), + class_device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i | 0x80), NULL, "iseries!nvt%d", i); devfs_mk_cdev(MKDEV(VIOTAPE_MAJOR, i), S_IFCHR | S_IRUSR | S_IWUSR, "iseries/vt%d", i); diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c index 1d44f69e1fda..003dda147cd0 100644 --- a/drivers/char/vt_ioctl.c +++ b/drivers/char/vt_ioctl.c @@ -192,6 +192,9 @@ do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm) int i, j, k; int ret; + if (!capable(CAP_SYS_TTY_CONFIG)) + return -EPERM; + kbs = kmalloc(sizeof(*kbs), GFP_KERNEL); if (!kbs) { ret = -ENOMEM; diff --git a/drivers/char/watchdog/cpu5wdt.c b/drivers/char/watchdog/cpu5wdt.c index 2865dac0a813..e75045fe2641 100644 --- a/drivers/char/watchdog/cpu5wdt.c +++ b/drivers/char/watchdog/cpu5wdt.c @@ -28,6 +28,7 @@ #include <linux/init.h> #include <linux/ioport.h> #include <linux/timer.h> +#include <linux/jiffies.h> #include <asm/io.h> #include <asm/uaccess.h> diff --git a/drivers/char/watchdog/mixcomwd.c b/drivers/char/watchdog/mixcomwd.c index 7fc2188386d9..d8dede575402 100644 --- a/drivers/char/watchdog/mixcomwd.c +++ b/drivers/char/watchdog/mixcomwd.c @@ -45,6 +45,8 @@ #include <linux/fs.h> #include <linux/reboot.h> #include <linux/init.h> +#include <linux/jiffies.h> +#include <linux/timer.h> #include <asm/uaccess.h> #include <asm/io.h> diff --git a/drivers/char/watchdog/pcwd.c b/drivers/char/watchdog/pcwd.c index 427ad51b7a35..37c9e13ad3ac 100644 --- a/drivers/char/watchdog/pcwd.c +++ b/drivers/char/watchdog/pcwd.c @@ -66,7 +66,7 @@ #include <linux/init.h> #include <linux/spinlock.h> #include <linux/reboot.h> - +#include <linux/sched.h> /* TASK_INTERRUPTIBLE, set_current_state() and friends */ #include <asm/uaccess.h> #include <asm/io.h> diff --git a/drivers/char/watchdog/pcwd_pci.c b/drivers/char/watchdog/pcwd_pci.c index 0b8e493be045..5308e5c8f29a 100644 --- a/drivers/char/watchdog/pcwd_pci.c +++ b/drivers/char/watchdog/pcwd_pci.c @@ -753,6 +753,7 @@ static struct pci_device_id pcipcwd_pci_tbl[] = { MODULE_DEVICE_TABLE(pci, pcipcwd_pci_tbl); static struct pci_driver pcipcwd_driver = { + .owner = THIS_MODULE, .name = WATCHDOG_NAME, .id_table = pcipcwd_pci_tbl, .probe = pcipcwd_card_init, diff --git a/drivers/char/watchdog/s3c2410_wdt.c b/drivers/char/watchdog/s3c2410_wdt.c index 3625b2601b42..b732020acadb 100644 --- a/drivers/char/watchdog/s3c2410_wdt.c +++ b/drivers/char/watchdog/s3c2410_wdt.c @@ -464,32 +464,28 @@ static void s3c2410wdt_shutdown(struct device *dev) static unsigned long wtcon_save; static unsigned long wtdat_save; -static int s3c2410wdt_suspend(struct device *dev, pm_message_t state, u32 level) +static int s3c2410wdt_suspend(struct device *dev, pm_message_t state) { - if (level == SUSPEND_POWER_DOWN) { - /* Save watchdog state, and turn it off. */ - wtcon_save = readl(wdt_base + S3C2410_WTCON); - wtdat_save = readl(wdt_base + S3C2410_WTDAT); + /* Save watchdog state, and turn it off. */ + wtcon_save = readl(wdt_base + S3C2410_WTCON); + wtdat_save = readl(wdt_base + S3C2410_WTDAT); - /* Note that WTCNT doesn't need to be saved. */ - s3c2410wdt_stop(); - } + /* Note that WTCNT doesn't need to be saved. */ + s3c2410wdt_stop(); return 0; } -static int s3c2410wdt_resume(struct device *dev, u32 level) +static int s3c2410wdt_resume(struct device *dev) { - if (level == RESUME_POWER_ON) { - /* Restore watchdog state. */ + /* Restore watchdog state. */ - writel(wtdat_save, wdt_base + S3C2410_WTDAT); - writel(wtdat_save, wdt_base + S3C2410_WTCNT); /* Reset count */ - writel(wtcon_save, wdt_base + S3C2410_WTCON); + writel(wtdat_save, wdt_base + S3C2410_WTDAT); + writel(wtdat_save, wdt_base + S3C2410_WTCNT); /* Reset count */ + writel(wtcon_save, wdt_base + S3C2410_WTCON); - printk(KERN_INFO PFX "watchdog %sabled\n", - (wtcon_save & S3C2410_WTCON_ENABLE) ? "en" : "dis"); - } + printk(KERN_INFO PFX "watchdog %sabled\n", + (wtcon_save & S3C2410_WTCON_ENABLE) ? "en" : "dis"); return 0; } diff --git a/drivers/char/watchdog/sc520_wdt.c b/drivers/char/watchdog/sc520_wdt.c index 72501be79b0c..4ee9974ad8cb 100644 --- a/drivers/char/watchdog/sc520_wdt.c +++ b/drivers/char/watchdog/sc520_wdt.c @@ -63,6 +63,7 @@ #include <linux/notifier.h> #include <linux/reboot.h> #include <linux/init.h> +#include <linux/jiffies.h> #include <asm/io.h> #include <asm/uaccess.h> diff --git a/drivers/char/watchdog/softdog.c b/drivers/char/watchdog/softdog.c index 20e5eb8667f2..a91edaf3a350 100644 --- a/drivers/char/watchdog/softdog.c +++ b/drivers/char/watchdog/softdog.c @@ -47,6 +47,8 @@ #include <linux/notifier.h> #include <linux/reboot.h> #include <linux/init.h> +#include <linux/jiffies.h> + #include <asm/uaccess.h> #define PFX "SoftDog: " diff --git a/drivers/char/watchdog/wdt_pci.c b/drivers/char/watchdog/wdt_pci.c index 4b3311993d48..dc9370f6c348 100644 --- a/drivers/char/watchdog/wdt_pci.c +++ b/drivers/char/watchdog/wdt_pci.c @@ -711,6 +711,7 @@ MODULE_DEVICE_TABLE(pci, wdtpci_pci_tbl); static struct pci_driver wdtpci_driver = { + .owner = THIS_MODULE, .name = "wdt_pci", .id_table = wdtpci_pci_tbl, .probe = wdtpci_init_one, diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 109d62ccf651..6c6121b85a54 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -4,6 +4,9 @@ * Copyright (C) 2001 Russell King * (C) 2002 - 2003 Dominik Brodowski <linux@brodo.de> * + * Oct 2005 - Ashok Raj <ashok.raj@intel.com> + * Added handling for CPU hotplug + * * 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. @@ -36,13 +39,6 @@ static struct cpufreq_policy *cpufreq_cpu_data[NR_CPUS]; static DEFINE_SPINLOCK(cpufreq_driver_lock); -/* we keep a copy of all ->add'ed CPU's struct sys_device here; - * as it is only accessed in ->add and ->remove, no lock or reference - * count is necessary. - */ -static struct sys_device *cpu_sys_devices[NR_CPUS]; - - /* internal prototypes */ static int __cpufreq_governor(struct cpufreq_policy *policy, unsigned int event); static void handle_update(void *data); @@ -574,6 +570,9 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) unsigned long flags; unsigned int j; + if (cpu_is_offline(cpu)) + return 0; + cpufreq_debug_disable_ratelimit(); dprintk("adding CPU %u\n", cpu); @@ -582,7 +581,6 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) * CPU because it is in the same boat. */ policy = cpufreq_cpu_get(cpu); if (unlikely(policy)) { - cpu_sys_devices[cpu] = sys_dev; dprintk("CPU already managed, adding link\n"); sysfs_create_link(&sys_dev->kobj, &policy->kobj, "cpufreq"); cpufreq_debug_enable_ratelimit(); @@ -657,7 +655,6 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) } module_put(cpufreq_driver->owner); - cpu_sys_devices[cpu] = sys_dev; dprintk("initialization complete\n"); cpufreq_debug_enable_ratelimit(); @@ -682,7 +679,7 @@ err_out: nomem_out: module_put(cpufreq_driver->owner); - module_out: +module_out: cpufreq_debug_enable_ratelimit(); return ret; } @@ -698,6 +695,7 @@ static int cpufreq_remove_dev (struct sys_device * sys_dev) unsigned int cpu = sys_dev->id; unsigned long flags; struct cpufreq_policy *data; + struct sys_device *cpu_sys_dev; #ifdef CONFIG_SMP unsigned int j; #endif @@ -710,7 +708,6 @@ static int cpufreq_remove_dev (struct sys_device * sys_dev) if (!data) { spin_unlock_irqrestore(&cpufreq_driver_lock, flags); - cpu_sys_devices[cpu] = NULL; cpufreq_debug_enable_ratelimit(); return -EINVAL; } @@ -725,14 +722,12 @@ static int cpufreq_remove_dev (struct sys_device * sys_dev) dprintk("removing link\n"); spin_unlock_irqrestore(&cpufreq_driver_lock, flags); sysfs_remove_link(&sys_dev->kobj, "cpufreq"); - cpu_sys_devices[cpu] = NULL; cpufreq_cpu_put(data); cpufreq_debug_enable_ratelimit(); return 0; } #endif - cpu_sys_devices[cpu] = NULL; if (!kobject_get(&data->kobj)) { spin_unlock_irqrestore(&cpufreq_driver_lock, flags); @@ -761,7 +756,8 @@ static int cpufreq_remove_dev (struct sys_device * sys_dev) if (j == cpu) continue; dprintk("removing link for cpu %u\n", j); - sysfs_remove_link(&cpu_sys_devices[j]->kobj, "cpufreq"); + cpu_sys_dev = get_cpu_sysdev(j); + sysfs_remove_link(&cpu_sys_dev->kobj, "cpufreq"); cpufreq_cpu_put(data); } } @@ -772,7 +768,6 @@ static int cpufreq_remove_dev (struct sys_device * sys_dev) down(&data->lock); if (cpufreq_driver->target) __cpufreq_governor(data, CPUFREQ_GOV_STOP); - cpufreq_driver->target = NULL; up(&data->lock); kobject_unregister(&data->kobj); @@ -1119,17 +1114,30 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy, unsigned int relation) { int retval = -EINVAL; - lock_cpu_hotplug(); + + /* + * Converted the lock_cpu_hotplug to preempt_disable() + * and preempt_enable(). This is a bit kludgy and relies on how cpu + * hotplug works. All we need is a guarantee that cpu hotplug won't make + * progress on any cpu. Once we do preempt_disable(), this would ensure + * that hotplug threads don't get onto this cpu, thereby delaying + * the cpu remove process. + * + * We removed the lock_cpu_hotplug since we need to call this function + * via cpu hotplug callbacks, which result in locking the cpu hotplug + * thread itself. Agree this is not very clean, cpufreq community + * could improve this if required. - Ashok Raj <ashok.raj@intel.com> + */ + preempt_disable(); dprintk("target for CPU %u: %u kHz, relation %u\n", policy->cpu, target_freq, relation); if (cpu_online(policy->cpu) && cpufreq_driver->target) retval = cpufreq_driver->target(policy, target_freq, relation); - unlock_cpu_hotplug(); + preempt_enable(); return retval; } EXPORT_SYMBOL_GPL(__cpufreq_driver_target); - int cpufreq_driver_target(struct cpufreq_policy *policy, unsigned int target_freq, unsigned int relation) @@ -1416,6 +1424,45 @@ int cpufreq_update_policy(unsigned int cpu) } EXPORT_SYMBOL(cpufreq_update_policy); +static int __cpuinit cpufreq_cpu_callback(struct notifier_block *nfb, + unsigned long action, void *hcpu) +{ + unsigned int cpu = (unsigned long)hcpu; + struct cpufreq_policy *policy; + struct sys_device *sys_dev; + + sys_dev = get_cpu_sysdev(cpu); + + if (sys_dev) { + switch (action) { + case CPU_ONLINE: + cpufreq_add_dev(sys_dev); + break; + case CPU_DOWN_PREPARE: + /* + * We attempt to put this cpu in lowest frequency + * possible before going down. This will permit + * hardware-managed P-State to switch other related + * threads to min or higher speeds if possible. + */ + policy = cpufreq_cpu_data[cpu]; + if (policy) { + cpufreq_driver_target(policy, policy->min, + CPUFREQ_RELATION_H); + } + break; + case CPU_DEAD: + cpufreq_remove_dev(sys_dev); + break; + } + } + return NOTIFY_OK; +} + +static struct notifier_block cpufreq_cpu_notifier = +{ + .notifier_call = cpufreq_cpu_callback, +}; /********************************************************************* * REGISTER / UNREGISTER CPUFREQ DRIVER * @@ -1476,6 +1523,7 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data) } if (!ret) { + register_cpu_notifier(&cpufreq_cpu_notifier); dprintk("driver %s up and running\n", driver_data->name); cpufreq_debug_enable_ratelimit(); } @@ -1507,6 +1555,7 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver) dprintk("unregistering driver %s\n", driver->name); sysdev_driver_unregister(&cpu_sysdev_class, &cpufreq_sysdev_driver); + unregister_cpu_notifier(&cpufreq_cpu_notifier); spin_lock_irqsave(&cpufreq_driver_lock, flags); cpufreq_driver = NULL; diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index 741b6b191e6a..3597f25d5efa 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -19,6 +19,7 @@ #include <linux/percpu.h> #include <linux/kobject.h> #include <linux/spinlock.h> +#include <linux/notifier.h> #include <asm/cputime.h> static spinlock_t cpufreq_stats_lock; @@ -298,6 +299,27 @@ cpufreq_stat_notifier_trans (struct notifier_block *nb, unsigned long val, return 0; } +static int __cpuinit cpufreq_stat_cpu_callback(struct notifier_block *nfb, + unsigned long action, void *hcpu) +{ + unsigned int cpu = (unsigned long)hcpu; + + switch (action) { + case CPU_ONLINE: + cpufreq_update_policy(cpu); + break; + case CPU_DEAD: + cpufreq_stats_free_table(cpu); + break; + } + return NOTIFY_OK; +} + +static struct notifier_block cpufreq_stat_cpu_notifier = +{ + .notifier_call = cpufreq_stat_cpu_callback, +}; + static struct notifier_block notifier_policy_block = { .notifier_call = cpufreq_stat_notifier_policy }; @@ -311,6 +333,7 @@ __init cpufreq_stats_init(void) { int ret; unsigned int cpu; + spin_lock_init(&cpufreq_stats_lock); if ((ret = cpufreq_register_notifier(¬ifier_policy_block, CPUFREQ_POLICY_NOTIFIER))) @@ -323,20 +346,31 @@ __init cpufreq_stats_init(void) return ret; } - for_each_cpu(cpu) - cpufreq_update_policy(cpu); + register_cpu_notifier(&cpufreq_stat_cpu_notifier); + lock_cpu_hotplug(); + for_each_online_cpu(cpu) { + cpufreq_stat_cpu_callback(&cpufreq_stat_cpu_notifier, CPU_ONLINE, + (void *)(long)cpu); + } + unlock_cpu_hotplug(); return 0; } static void __exit cpufreq_stats_exit(void) { unsigned int cpu; + cpufreq_unregister_notifier(¬ifier_policy_block, CPUFREQ_POLICY_NOTIFIER); cpufreq_unregister_notifier(¬ifier_trans_block, CPUFREQ_TRANSITION_NOTIFIER); - for_each_cpu(cpu) - cpufreq_stats_free_table(cpu); + unregister_cpu_notifier(&cpufreq_stat_cpu_notifier); + lock_cpu_hotplug(); + for_each_online_cpu(cpu) { + cpufreq_stat_cpu_callback(&cpufreq_stat_cpu_notifier, CPU_DEAD, + (void *)(long)cpu); + } + unlock_cpu_hotplug(); } MODULE_AUTHOR ("Zou Nan hai <nanhai.zou@intel.com>"); diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 094835cce321..4263935443cc 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -2,7 +2,7 @@ menu "Hardware crypto devices" config CRYPTO_DEV_PADLOCK tristate "Support for VIA PadLock ACE" - depends on CRYPTO && X86 && !X86_64 + depends on CRYPTO && X86_32 help Some VIA processors come with an integrated crypto engine (so called VIA PadLock ACE, Advanced Cryptography Engine) diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index 327b58e64875..b6815c6c29a2 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -70,8 +70,7 @@ config DELL_RBU config DCDBAS tristate "Dell Systems Management Base Driver" - depends on X86 || X86_64 - default m + depends on X86 help The Dell Systems Management Base Driver provides a sysfs interface for systems management software to perform System Management diff --git a/drivers/hwmon/adm1021.c b/drivers/hwmon/adm1021.c index e928cdb041cb..8102876c7c3f 100644 --- a/drivers/hwmon/adm1021.c +++ b/drivers/hwmon/adm1021.c @@ -121,7 +121,7 @@ static int adm1021_write_value(struct i2c_client *client, u8 reg, static struct adm1021_data *adm1021_update_device(struct device *dev); /* (amalysh) read only mode, otherwise any limit's writing confuse BIOS */ -static int read_only = 0; +static int read_only; /* This is the driver that will be inserted */ @@ -204,11 +204,10 @@ static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind) client structure, even though we cannot fill it completely yet. But it allows us to access adm1021_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct adm1021_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct adm1021_data), GFP_KERNEL))) { err = -ENOMEM; goto error0; } - memset(data, 0, sizeof(struct adm1021_data)); new_client = &data->client; i2c_set_clientdata(new_client, data); diff --git a/drivers/hwmon/adm1025.c b/drivers/hwmon/adm1025.c index 526b7ff179eb..3ec12421694f 100644 --- a/drivers/hwmon/adm1025.c +++ b/drivers/hwmon/adm1025.c @@ -331,11 +331,10 @@ static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind) if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) goto exit; - if (!(data = kmalloc(sizeof(struct adm1025_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct adm1025_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - memset(data, 0, sizeof(struct adm1025_data)); /* The common I2C client data is placed right before the ADM1025-specific data. */ diff --git a/drivers/hwmon/adm1026.c b/drivers/hwmon/adm1026.c index 625158110fd4..e0f56549d1d8 100644 --- a/drivers/hwmon/adm1026.c +++ b/drivers/hwmon/adm1026.c @@ -315,7 +315,7 @@ static struct i2c_driver adm1026_driver = { .detach_client = adm1026_detach_client, }; -int adm1026_attach_adapter(struct i2c_adapter *adapter) +static int adm1026_attach_adapter(struct i2c_adapter *adapter) { if (!(adapter->class & I2C_CLASS_HWMON)) { return 0; @@ -323,7 +323,7 @@ int adm1026_attach_adapter(struct i2c_adapter *adapter) return i2c_probe(adapter, &addr_data, adm1026_detect); } -int adm1026_detach_client(struct i2c_client *client) +static int adm1026_detach_client(struct i2c_client *client) { struct adm1026_data *data = i2c_get_clientdata(client); hwmon_device_unregister(data->class_dev); @@ -332,7 +332,7 @@ int adm1026_detach_client(struct i2c_client *client) return 0; } -int adm1026_read_value(struct i2c_client *client, u8 reg) +static int adm1026_read_value(struct i2c_client *client, u8 reg) { int res; @@ -346,7 +346,7 @@ int adm1026_read_value(struct i2c_client *client, u8 reg) return res; } -int adm1026_write_value(struct i2c_client *client, u8 reg, int value) +static int adm1026_write_value(struct i2c_client *client, u8 reg, int value) { int res; @@ -360,7 +360,7 @@ int adm1026_write_value(struct i2c_client *client, u8 reg, int value) return res; } -void adm1026_init_client(struct i2c_client *client) +static void adm1026_init_client(struct i2c_client *client) { int value, i; struct adm1026_data *data = i2c_get_clientdata(client); @@ -460,7 +460,7 @@ void adm1026_init_client(struct i2c_client *client) } } -void adm1026_print_gpio(struct i2c_client *client) +static void adm1026_print_gpio(struct i2c_client *client) { struct adm1026_data *data = i2c_get_clientdata(client); int i; @@ -492,7 +492,7 @@ void adm1026_print_gpio(struct i2c_client *client) } } -void adm1026_fixup_gpio(struct i2c_client *client) +static void adm1026_fixup_gpio(struct i2c_client *client) { struct adm1026_data *data = i2c_get_clientdata(client); int i; @@ -1452,8 +1452,8 @@ static DEVICE_ATTR(temp1_auto_point2_pwm, S_IRUGO, show_auto_pwm_max, NULL); static DEVICE_ATTR(temp2_auto_point2_pwm, S_IRUGO, show_auto_pwm_max, NULL); static DEVICE_ATTR(temp3_auto_point2_pwm, S_IRUGO, show_auto_pwm_max, NULL); -int adm1026_detect(struct i2c_adapter *adapter, int address, - int kind) +static int adm1026_detect(struct i2c_adapter *adapter, int address, + int kind) { int company, verstep; struct i2c_client *new_client; @@ -1470,13 +1470,11 @@ int adm1026_detect(struct i2c_adapter *adapter, int address, client structure, even though we cannot fill it completely yet. But it allows us to access adm1026_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct adm1026_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct adm1026_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - memset(data, 0, sizeof(struct adm1026_data)); - new_client = &data->client; i2c_set_clientdata(new_client, data); new_client->addr = address; diff --git a/drivers/hwmon/adm1031.c b/drivers/hwmon/adm1031.c index 58338ed7c8a1..7c545d5eee45 100644 --- a/drivers/hwmon/adm1031.c +++ b/drivers/hwmon/adm1031.c @@ -740,11 +740,10 @@ static int adm1031_detect(struct i2c_adapter *adapter, int address, int kind) if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) goto exit; - if (!(data = kmalloc(sizeof(struct adm1031_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct adm1031_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - memset(data, 0, sizeof(struct adm1031_data)); new_client = &data->client; i2c_set_clientdata(new_client, data); diff --git a/drivers/hwmon/adm9240.c b/drivers/hwmon/adm9240.c index bc7faef162f7..11dc95f8a17e 100644 --- a/drivers/hwmon/adm9240.c +++ b/drivers/hwmon/adm9240.c @@ -45,6 +45,7 @@ #include <linux/module.h> #include <linux/slab.h> #include <linux/i2c.h> +#include <linux/hwmon-sysfs.h> #include <linux/hwmon.h> #include <linux/hwmon-vid.h> #include <linux/err.h> @@ -69,8 +70,7 @@ I2C_CLIENT_INSMOD_3(adm9240, ds1780, lm81); #define ADM9240_REG_INT(nr) (0x41 + (nr)) #define ADM9240_REG_INT_MASK(nr) (0x43 + (nr)) #define ADM9240_REG_TEMP 0x27 -#define ADM9240_REG_TEMP_HIGH 0x39 -#define ADM9240_REG_TEMP_HYST 0x3a +#define ADM9240_REG_TEMP_MAX(nr) (0x39 + (nr)) /* 0, 1 = high, hyst */ #define ADM9240_REG_ANALOG_OUT 0x19 #define ADM9240_REG_CHASSIS_CLEAR 0x46 #define ADM9240_REG_VID_FAN_DIV 0x47 @@ -162,177 +162,155 @@ struct adm9240_data { u8 fan_min[2]; /* rw fan1_min */ u8 fan_div[2]; /* rw fan1_div, read-only accessor */ s16 temp; /* ro temp1_input, 9-bit sign-extended */ - s8 temp_high; /* rw temp1_max */ - s8 temp_hyst; /* rw temp1_max_hyst */ + s8 temp_max[2]; /* rw 0 -> temp_max, 1 -> temp_max_hyst */ u16 alarms; /* ro alarms */ u8 aout; /* rw aout_output */ u8 vid; /* ro vid */ u8 vrm; /* -- vrm set on startup, no accessor */ }; -/* i2c byte read/write interface */ -static int adm9240_read_value(struct i2c_client *client, u8 reg) +/*** sysfs accessors ***/ + +/* temperature */ +static ssize_t show_temp(struct device *dev, struct device_attribute *dummy, + char *buf) { - return i2c_smbus_read_byte_data(client, reg); + struct adm9240_data *data = adm9240_update_device(dev); + return sprintf(buf, "%d\n", data->temp * 500); /* 9-bit value */ } -static int adm9240_write_value(struct i2c_client *client, u8 reg, u8 value) +static ssize_t show_max(struct device *dev, struct device_attribute *devattr, + char *buf) { - return i2c_smbus_write_byte_data(client, reg, value); + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct adm9240_data *data = adm9240_update_device(dev); + return sprintf(buf, "%d\n", data->temp_max[attr->index] * 1000); } -/*** sysfs accessors ***/ +static ssize_t set_max(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct i2c_client *client = to_i2c_client(dev); + struct adm9240_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->temp_max[attr->index] = TEMP_TO_REG(val); + i2c_smbus_write_byte_data(client, ADM9240_REG_TEMP_MAX(attr->index), + data->temp_max[attr->index]); + up(&data->update_lock); + return count; +} -/* temperature */ -#define show_temp(value, scale) \ -static ssize_t show_##value(struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ -{ \ - struct adm9240_data *data = adm9240_update_device(dev); \ - return sprintf(buf, "%d\n", data->value * scale); \ -} -show_temp(temp_high, 1000); -show_temp(temp_hyst, 1000); -show_temp(temp, 500); /* 0.5'C per bit */ - -#define set_temp(value, reg) \ -static ssize_t set_##value(struct device *dev, \ - struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct adm9240_data *data = adm9240_update_device(dev); \ - long temp = simple_strtoul(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - data->value = TEMP_TO_REG(temp); \ - adm9240_write_value(client, reg, data->value); \ - up(&data->update_lock); \ - return count; \ -} - -set_temp(temp_high, ADM9240_REG_TEMP_HIGH); -set_temp(temp_hyst, ADM9240_REG_TEMP_HYST); - -static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, - show_temp_high, set_temp_high); -static DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, - show_temp_hyst, set_temp_hyst); static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL); +static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, + show_max, set_max, 0); +static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, + show_max, set_max, 1); /* voltage */ -static ssize_t show_in(struct device *dev, char *buf, int nr) +static ssize_t show_in(struct device *dev, struct device_attribute *devattr, + char *buf) { + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct adm9240_data *data = adm9240_update_device(dev); - return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr], nr)); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in[attr->index], + attr->index)); } -static ssize_t show_in_min(struct device *dev, char *buf, int nr) +static ssize_t show_in_min(struct device *dev, + struct device_attribute *devattr, char *buf) { + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct adm9240_data *data = adm9240_update_device(dev); - return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr], nr)); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[attr->index], + attr->index)); } -static ssize_t show_in_max(struct device *dev, char *buf, int nr) +static ssize_t show_in_max(struct device *dev, + struct device_attribute *devattr, char *buf) { + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct adm9240_data *data = adm9240_update_device(dev); - return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr], nr)); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[attr->index], + attr->index)); } -static ssize_t set_in_min(struct device *dev, const char *buf, - size_t count, int nr) +static ssize_t set_in_min(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) { + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct i2c_client *client = to_i2c_client(dev); struct adm9240_data *data = i2c_get_clientdata(client); unsigned long val = simple_strtoul(buf, NULL, 10); down(&data->update_lock); - data->in_min[nr] = IN_TO_REG(val, nr); - adm9240_write_value(client, ADM9240_REG_IN_MIN(nr), data->in_min[nr]); + data->in_min[attr->index] = IN_TO_REG(val, attr->index); + i2c_smbus_write_byte_data(client, ADM9240_REG_IN_MIN(attr->index), + data->in_min[attr->index]); up(&data->update_lock); return count; } -static ssize_t set_in_max(struct device *dev, const char *buf, - size_t count, int nr) +static ssize_t set_in_max(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) { + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct i2c_client *client = to_i2c_client(dev); struct adm9240_data *data = i2c_get_clientdata(client); unsigned long val = simple_strtoul(buf, NULL, 10); down(&data->update_lock); - data->in_max[nr] = IN_TO_REG(val, nr); - adm9240_write_value(client, ADM9240_REG_IN_MAX(nr), data->in_max[nr]); + data->in_max[attr->index] = IN_TO_REG(val, attr->index); + i2c_smbus_write_byte_data(client, ADM9240_REG_IN_MAX(attr->index), + data->in_max[attr->index]); up(&data->update_lock); return count; } -#define show_in_offset(offset) \ -static ssize_t show_in##offset(struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ -{ \ - return show_in(dev, buf, offset); \ -} \ -static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in##offset, NULL); \ -static ssize_t show_in##offset##_min(struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ -{ \ - return show_in_min(dev, buf, offset); \ -} \ -static ssize_t show_in##offset##_max(struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ -{ \ - return show_in_max(dev, buf, offset); \ -} \ -static ssize_t \ -set_in##offset##_min(struct device *dev, \ - struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - return set_in_min(dev, buf, count, offset); \ -} \ -static ssize_t \ -set_in##offset##_max(struct device *dev, \ - struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - return set_in_max(dev, buf, count, offset); \ -} \ -static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ - show_in##offset##_min, set_in##offset##_min); \ -static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ - show_in##offset##_max, set_in##offset##_max); - -show_in_offset(0); -show_in_offset(1); -show_in_offset(2); -show_in_offset(3); -show_in_offset(4); -show_in_offset(5); +#define vin(nr) \ +static SENSOR_DEVICE_ATTR(in##nr##_input, S_IRUGO, \ + show_in, NULL, nr); \ +static SENSOR_DEVICE_ATTR(in##nr##_min, S_IRUGO | S_IWUSR, \ + show_in_min, set_in_min, nr); \ +static SENSOR_DEVICE_ATTR(in##nr##_max, S_IRUGO | S_IWUSR, \ + show_in_max, set_in_max, nr); + +vin(0); +vin(1); +vin(2); +vin(3); +vin(4); +vin(5); /* fans */ -static ssize_t show_fan(struct device *dev, char *buf, int nr) +static ssize_t show_fan(struct device *dev, + struct device_attribute *devattr, char *buf) { + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct adm9240_data *data = adm9240_update_device(dev); - return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr], - 1 << data->fan_div[nr])); + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[attr->index], + 1 << data->fan_div[attr->index])); } -static ssize_t show_fan_min(struct device *dev, char *buf, int nr) +static ssize_t show_fan_min(struct device *dev, + struct device_attribute *devattr, char *buf) { + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct adm9240_data *data = adm9240_update_device(dev); - return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[nr], - 1 << data->fan_div[nr])); + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[attr->index], + 1 << data->fan_div[attr->index])); } -static ssize_t show_fan_div(struct device *dev, char *buf, int nr) +static ssize_t show_fan_div(struct device *dev, + struct device_attribute *devattr, char *buf) { + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct adm9240_data *data = adm9240_update_device(dev); - return sprintf(buf, "%d\n", 1 << data->fan_div[nr]); + return sprintf(buf, "%d\n", 1 << data->fan_div[attr->index]); } /* write new fan div, callers must hold data->update_lock */ @@ -341,16 +319,16 @@ static void adm9240_write_fan_div(struct i2c_client *client, int nr, { u8 reg, old, shift = (nr + 2) * 2; - reg = adm9240_read_value(client, ADM9240_REG_VID_FAN_DIV); + reg = i2c_smbus_read_byte_data(client, ADM9240_REG_VID_FAN_DIV); old = (reg >> shift) & 3; reg &= ~(3 << shift); reg |= (fan_div << shift); - adm9240_write_value(client, ADM9240_REG_VID_FAN_DIV, reg); + i2c_smbus_write_byte_data(client, ADM9240_REG_VID_FAN_DIV, reg); dev_dbg(&client->dev, "fan%d clock divider changed from %u " "to %u\n", nr + 1, 1 << old, 1 << fan_div); } -/* +/* * set fan speed low limit: * * - value is zero: disable fan speed low limit alarm @@ -361,12 +339,15 @@ static void adm9240_write_fan_div(struct i2c_client *client, int nr, * - otherwise: select fan clock divider to suit fan speed low limit, * measurement code may adjust registers to ensure fan speed reading */ -static ssize_t set_fan_min(struct device *dev, const char *buf, - size_t count, int nr) +static ssize_t set_fan_min(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) { + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct i2c_client *client = to_i2c_client(dev); struct adm9240_data *data = i2c_get_clientdata(client); unsigned long val = simple_strtoul(buf, NULL, 10); + int nr = attr->index; u8 new_div; down(&data->update_lock); @@ -406,50 +387,27 @@ static ssize_t set_fan_min(struct device *dev, const char *buf, data->fan_div[nr] = new_div; adm9240_write_fan_div(client, nr, new_div); } - adm9240_write_value(client, ADM9240_REG_FAN_MIN(nr), + i2c_smbus_write_byte_data(client, ADM9240_REG_FAN_MIN(nr), data->fan_min[nr]); up(&data->update_lock); return count; } -#define show_fan_offset(offset) \ -static ssize_t show_fan_##offset (struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ -{ \ -return show_fan(dev, buf, offset - 1); \ -} \ -static ssize_t show_fan_##offset##_div (struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ -{ \ -return show_fan_div(dev, buf, offset - 1); \ -} \ -static ssize_t show_fan_##offset##_min (struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ -{ \ -return show_fan_min(dev, buf, offset - 1); \ -} \ -static ssize_t set_fan_##offset##_min (struct device *dev, \ - struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ -return set_fan_min(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(fan##offset##_input, S_IRUGO, \ - show_fan_##offset, NULL); \ -static DEVICE_ATTR(fan##offset##_div, S_IRUGO, \ - show_fan_##offset##_div, NULL); \ -static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ - show_fan_##offset##_min, set_fan_##offset##_min); - -show_fan_offset(1); -show_fan_offset(2); +#define fan(nr) \ +static SENSOR_DEVICE_ATTR(fan##nr##_input, S_IRUGO, \ + show_fan, NULL, nr - 1); \ +static SENSOR_DEVICE_ATTR(fan##nr##_div, S_IRUGO, \ + show_fan_div, NULL, nr - 1); \ +static SENSOR_DEVICE_ATTR(fan##nr##_min, S_IRUGO | S_IWUSR, \ + show_fan_min, set_fan_min, nr - 1); + +fan(1); +fan(2); /* alarms */ -static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_alarms(struct device *dev, + struct device_attribute *attr, char *buf) { struct adm9240_data *data = adm9240_update_device(dev); return sprintf(buf, "%u\n", data->alarms); @@ -457,7 +415,8 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, ch static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); /* vid */ -static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_vid(struct device *dev, + struct device_attribute *attr, char *buf) { struct adm9240_data *data = adm9240_update_device(dev); return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm)); @@ -465,13 +424,16 @@ static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); /* analog output */ -static ssize_t show_aout(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_aout(struct device *dev, + struct device_attribute *attr, char *buf) { struct adm9240_data *data = adm9240_update_device(dev); return sprintf(buf, "%d\n", AOUT_FROM_REG(data->aout)); } -static ssize_t set_aout(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t set_aout(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct adm9240_data *data = i2c_get_clientdata(client); @@ -479,20 +441,23 @@ static ssize_t set_aout(struct device *dev, struct device_attribute *attr, const down(&data->update_lock); data->aout = AOUT_TO_REG(val); - adm9240_write_value(client, ADM9240_REG_ANALOG_OUT, data->aout); + i2c_smbus_write_byte_data(client, ADM9240_REG_ANALOG_OUT, data->aout); up(&data->update_lock); return count; } static DEVICE_ATTR(aout_output, S_IRUGO | S_IWUSR, show_aout, set_aout); /* chassis_clear */ -static ssize_t chassis_clear(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t chassis_clear(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); unsigned long val = simple_strtol(buf, NULL, 10); if (val == 1) { - adm9240_write_value(client, ADM9240_REG_CHASSIS_CLEAR, 0x80); + i2c_smbus_write_byte_data(client, + ADM9240_REG_CHASSIS_CLEAR, 0x80); dev_dbg(&client->dev, "chassis intrusion latch cleared\n"); } return count; @@ -513,11 +478,10 @@ static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind) if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) goto exit; - if (!(data = kmalloc(sizeof(struct adm9240_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(*data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - memset(data, 0, sizeof(struct adm9240_data)); new_client = &data->client; i2c_set_clientdata(new_client, data); @@ -533,7 +497,7 @@ static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind) if (kind < 0) { /* verify chip: reg address should match i2c address */ - if (adm9240_read_value(new_client, ADM9240_REG_I2C_ADDR) + if (i2c_smbus_read_byte_data(new_client, ADM9240_REG_I2C_ADDR) != address) { dev_err(&adapter->dev, "detect fail: address match, " "0x%02x\n", address); @@ -541,8 +505,8 @@ static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind) } /* check known chip manufacturer */ - man_id = adm9240_read_value(new_client, ADM9240_REG_MAN_ID); - + man_id = i2c_smbus_read_byte_data(new_client, + ADM9240_REG_MAN_ID); if (man_id == 0x23) { kind = adm9240; } else if (man_id == 0xda) { @@ -556,7 +520,8 @@ static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind) } /* successful detect, print chip info */ - die_rev = adm9240_read_value(new_client, ADM9240_REG_DIE_REV); + die_rev = i2c_smbus_read_byte_data(new_client, + ADM9240_REG_DIE_REV); dev_info(&adapter->dev, "found %s revision %u\n", man_id == 0x23 ? "ADM9240" : man_id == 0xda ? "DS1780" : "LM81", die_rev); @@ -588,33 +553,59 @@ static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind) goto exit_detach; } - device_create_file(&new_client->dev, &dev_attr_in0_input); - device_create_file(&new_client->dev, &dev_attr_in0_min); - device_create_file(&new_client->dev, &dev_attr_in0_max); - device_create_file(&new_client->dev, &dev_attr_in1_input); - device_create_file(&new_client->dev, &dev_attr_in1_min); - device_create_file(&new_client->dev, &dev_attr_in1_max); - device_create_file(&new_client->dev, &dev_attr_in2_input); - device_create_file(&new_client->dev, &dev_attr_in2_min); - device_create_file(&new_client->dev, &dev_attr_in2_max); - device_create_file(&new_client->dev, &dev_attr_in3_input); - device_create_file(&new_client->dev, &dev_attr_in3_min); - device_create_file(&new_client->dev, &dev_attr_in3_max); - device_create_file(&new_client->dev, &dev_attr_in4_input); - device_create_file(&new_client->dev, &dev_attr_in4_min); - device_create_file(&new_client->dev, &dev_attr_in4_max); - device_create_file(&new_client->dev, &dev_attr_in5_input); - device_create_file(&new_client->dev, &dev_attr_in5_min); - device_create_file(&new_client->dev, &dev_attr_in5_max); - device_create_file(&new_client->dev, &dev_attr_temp1_max); - device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst); + device_create_file(&new_client->dev, + &sensor_dev_attr_in0_input.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_in0_min.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_in0_max.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_in1_input.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_in1_min.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_in1_max.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_in2_input.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_in2_min.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_in2_max.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_in3_input.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_in3_min.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_in3_max.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_in4_input.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_in4_min.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_in4_max.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_in5_input.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_in5_min.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_in5_max.dev_attr); device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_fan1_input); - device_create_file(&new_client->dev, &dev_attr_fan1_div); - device_create_file(&new_client->dev, &dev_attr_fan1_min); - device_create_file(&new_client->dev, &dev_attr_fan2_input); - device_create_file(&new_client->dev, &dev_attr_fan2_div); - device_create_file(&new_client->dev, &dev_attr_fan2_min); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_max.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_max_hyst.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_fan1_input.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_fan1_div.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_fan1_min.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_fan2_input.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_fan2_div.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_fan2_min.dev_attr); device_create_file(&new_client->dev, &dev_attr_alarms); device_create_file(&new_client->dev, &dev_attr_aout_output); device_create_file(&new_client->dev, &dev_attr_chassis_clear); @@ -654,8 +645,8 @@ static int adm9240_detach_client(struct i2c_client *client) static void adm9240_init_client(struct i2c_client *client) { struct adm9240_data *data = i2c_get_clientdata(client); - u8 conf = adm9240_read_value(client, ADM9240_REG_CONFIG); - u8 mode = adm9240_read_value(client, ADM9240_REG_TEMP_CONF) & 3; + u8 conf = i2c_smbus_read_byte_data(client, ADM9240_REG_CONFIG); + u8 mode = i2c_smbus_read_byte_data(client, ADM9240_REG_TEMP_CONF) & 3; data->vrm = vid_which_vrm(); /* need this to report vid as mV */ @@ -672,18 +663,22 @@ static void adm9240_init_client(struct i2c_client *client) for (i = 0; i < 6; i++) { - adm9240_write_value(client, + i2c_smbus_write_byte_data(client, ADM9240_REG_IN_MIN(i), 0); - adm9240_write_value(client, + i2c_smbus_write_byte_data(client, ADM9240_REG_IN_MAX(i), 255); } - adm9240_write_value(client, ADM9240_REG_FAN_MIN(0), 255); - adm9240_write_value(client, ADM9240_REG_FAN_MIN(1), 255); - adm9240_write_value(client, ADM9240_REG_TEMP_HIGH, 127); - adm9240_write_value(client, ADM9240_REG_TEMP_HYST, 127); + i2c_smbus_write_byte_data(client, + ADM9240_REG_FAN_MIN(0), 255); + i2c_smbus_write_byte_data(client, + ADM9240_REG_FAN_MIN(1), 255); + i2c_smbus_write_byte_data(client, + ADM9240_REG_TEMP_MAX(0), 127); + i2c_smbus_write_byte_data(client, + ADM9240_REG_TEMP_MAX(1), 127); /* start measurement cycle */ - adm9240_write_value(client, ADM9240_REG_CONFIG, 1); + i2c_smbus_write_byte_data(client, ADM9240_REG_CONFIG, 1); dev_info(&client->dev, "cold start: config was 0x%02x " "mode %u\n", conf, mode); @@ -704,25 +699,25 @@ static struct adm9240_data *adm9240_update_device(struct device *dev) for (i = 0; i < 6; i++) /* read voltages */ { - data->in[i] = adm9240_read_value(client, + data->in[i] = i2c_smbus_read_byte_data(client, ADM9240_REG_IN(i)); } - data->alarms = adm9240_read_value(client, + data->alarms = i2c_smbus_read_byte_data(client, ADM9240_REG_INT(0)) | - adm9240_read_value(client, + i2c_smbus_read_byte_data(client, ADM9240_REG_INT(1)) << 8; /* read temperature: assume temperature changes less than * 0.5'C per two measurement cycles thus ignore possible * but unlikely aliasing error on lsb reading. --Grant */ - data->temp = ((adm9240_read_value(client, + data->temp = ((i2c_smbus_read_byte_data(client, ADM9240_REG_TEMP) << 8) | - adm9240_read_value(client, + i2c_smbus_read_byte_data(client, ADM9240_REG_TEMP_CONF)) / 128; for (i = 0; i < 2; i++) /* read fans */ { - data->fan[i] = adm9240_read_value(client, + data->fan[i] = i2c_smbus_read_byte_data(client, ADM9240_REG_FAN(i)); /* adjust fan clock divider on overflow */ @@ -747,30 +742,30 @@ static struct adm9240_data *adm9240_update_device(struct device *dev) for (i = 0; i < 6; i++) { - data->in_min[i] = adm9240_read_value(client, + data->in_min[i] = i2c_smbus_read_byte_data(client, ADM9240_REG_IN_MIN(i)); - data->in_max[i] = adm9240_read_value(client, + data->in_max[i] = i2c_smbus_read_byte_data(client, ADM9240_REG_IN_MAX(i)); } for (i = 0; i < 2; i++) { - data->fan_min[i] = adm9240_read_value(client, + data->fan_min[i] = i2c_smbus_read_byte_data(client, ADM9240_REG_FAN_MIN(i)); } - data->temp_high = adm9240_read_value(client, - ADM9240_REG_TEMP_HIGH); - data->temp_hyst = adm9240_read_value(client, - ADM9240_REG_TEMP_HYST); + data->temp_max[0] = i2c_smbus_read_byte_data(client, + ADM9240_REG_TEMP_MAX(0)); + data->temp_max[1] = i2c_smbus_read_byte_data(client, + ADM9240_REG_TEMP_MAX(1)); /* read fan divs and 5-bit VID */ - i = adm9240_read_value(client, ADM9240_REG_VID_FAN_DIV); + i = i2c_smbus_read_byte_data(client, ADM9240_REG_VID_FAN_DIV); data->fan_div[0] = (i >> 4) & 3; data->fan_div[1] = (i >> 6) & 3; data->vid = i & 0x0f; - data->vid |= (adm9240_read_value(client, + data->vid |= (i2c_smbus_read_byte_data(client, ADM9240_REG_VID4) & 1) << 4; /* read analog out */ - data->aout = adm9240_read_value(client, + data->aout = i2c_smbus_read_byte_data(client, ADM9240_REG_ANALOG_OUT); data->last_updated_config = jiffies; diff --git a/drivers/hwmon/asb100.c b/drivers/hwmon/asb100.c index 8e34855a6274..52c469722a65 100644 --- a/drivers/hwmon/asb100.c +++ b/drivers/hwmon/asb100.c @@ -629,19 +629,17 @@ static int asb100_detect_subclients(struct i2c_adapter *adapter, int address, int i, id, err; struct asb100_data *data = i2c_get_clientdata(new_client); - data->lm75[0] = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); + data->lm75[0] = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); if (!(data->lm75[0])) { err = -ENOMEM; goto ERROR_SC_0; } - memset(data->lm75[0], 0x00, sizeof(struct i2c_client)); - data->lm75[1] = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); + data->lm75[1] = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); if (!(data->lm75[1])) { err = -ENOMEM; goto ERROR_SC_1; } - memset(data->lm75[1], 0x00, sizeof(struct i2c_client)); id = i2c_adapter_id(adapter); @@ -724,12 +722,11 @@ static int asb100_detect(struct i2c_adapter *adapter, int address, int kind) client structure, even though we cannot fill it completely yet. But it allows us to access asb100_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct asb100_data), GFP_KERNEL))) { - pr_debug("asb100.o: detect failed, kmalloc failed!\n"); + if (!(data = kzalloc(sizeof(struct asb100_data), GFP_KERNEL))) { + pr_debug("asb100.o: detect failed, kzalloc failed!\n"); err = -ENOMEM; goto ERROR0; } - memset(data, 0, sizeof(struct asb100_data)); new_client = &data->client; init_MUTEX(&data->lock); diff --git a/drivers/hwmon/atxp1.c b/drivers/hwmon/atxp1.c index deb4d34c9539..53324f56404e 100644 --- a/drivers/hwmon/atxp1.c +++ b/drivers/hwmon/atxp1.c @@ -253,6 +253,8 @@ static DEVICE_ATTR(gpio2, S_IRUGO | S_IWUSR, atxp1_showgpio2, atxp1_storegpio2); static int atxp1_attach_adapter(struct i2c_adapter *adapter) { + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; return i2c_probe(adapter, &addr_data, &atxp1_detect); }; @@ -266,12 +268,11 @@ static int atxp1_detect(struct i2c_adapter *adapter, int address, int kind) if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) goto exit; - if (!(data = kmalloc(sizeof(struct atxp1_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct atxp1_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - memset(data, 0, sizeof(struct atxp1_data)); new_client = &data->client; i2c_set_clientdata(new_client, data); diff --git a/drivers/hwmon/ds1621.c b/drivers/hwmon/ds1621.c index b0199e063d0e..34f71b7c7f37 100644 --- a/drivers/hwmon/ds1621.c +++ b/drivers/hwmon/ds1621.c @@ -180,12 +180,14 @@ static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max, set_temp_max); static int ds1621_attach_adapter(struct i2c_adapter *adapter) { + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; return i2c_probe(adapter, &addr_data, ds1621_detect); } /* This function is called by i2c_probe */ -int ds1621_detect(struct i2c_adapter *adapter, int address, - int kind) +static int ds1621_detect(struct i2c_adapter *adapter, int address, + int kind) { int conf, temp; struct i2c_client *new_client; @@ -200,11 +202,10 @@ int ds1621_detect(struct i2c_adapter *adapter, int address, /* OK. For now, we presume we have a valid client. We now create the client structure, even though we cannot fill it completely yet. But it allows us to access ds1621_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct ds1621_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct ds1621_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - memset(data, 0, sizeof(struct ds1621_data)); new_client = &data->client; i2c_set_clientdata(new_client, data); diff --git a/drivers/hwmon/fscher.c b/drivers/hwmon/fscher.c index eef6061d786b..a02e1c34c757 100644 --- a/drivers/hwmon/fscher.c +++ b/drivers/hwmon/fscher.c @@ -303,11 +303,10 @@ static int fscher_detect(struct i2c_adapter *adapter, int address, int kind) /* OK. For now, we presume we have a valid client. We now create the * client structure, even though we cannot fill it completely yet. * But it allows us to access i2c_smbus_read_byte_data. */ - if (!(data = kmalloc(sizeof(struct fscher_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct fscher_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - memset(data, 0, sizeof(struct fscher_data)); /* The common I2C client data is placed right before the * Hermes-specific data. */ diff --git a/drivers/hwmon/fscpos.c b/drivers/hwmon/fscpos.c index 5fc77a5fed07..64e4edc64f8d 100644 --- a/drivers/hwmon/fscpos.c +++ b/drivers/hwmon/fscpos.c @@ -438,7 +438,7 @@ static int fscpos_attach_adapter(struct i2c_adapter *adapter) return i2c_probe(adapter, &addr_data, fscpos_detect); } -int fscpos_detect(struct i2c_adapter *adapter, int address, int kind) +static int fscpos_detect(struct i2c_adapter *adapter, int address, int kind) { struct i2c_client *new_client; struct fscpos_data *data; @@ -453,11 +453,10 @@ int fscpos_detect(struct i2c_adapter *adapter, int address, int kind) * But it allows us to access fscpos_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct fscpos_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct fscpos_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - memset(data, 0, sizeof(struct fscpos_data)); new_client = &data->client; i2c_set_clientdata(new_client, data); diff --git a/drivers/hwmon/gl518sm.c b/drivers/hwmon/gl518sm.c index 256b9323c84b..2f178dbe3d87 100644 --- a/drivers/hwmon/gl518sm.c +++ b/drivers/hwmon/gl518sm.c @@ -365,11 +365,10 @@ static int gl518_detect(struct i2c_adapter *adapter, int address, int kind) client structure, even though we cannot fill it completely yet. But it allows us to access gl518_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct gl518_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct gl518_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - memset(data, 0, sizeof(struct gl518_data)); new_client = &data->client; i2c_set_clientdata(new_client, data); diff --git a/drivers/hwmon/gl520sm.c b/drivers/hwmon/gl520sm.c index 12fd757066fc..c39ba1239426 100644 --- a/drivers/hwmon/gl520sm.c +++ b/drivers/hwmon/gl520sm.c @@ -536,11 +536,10 @@ static int gl520_detect(struct i2c_adapter *adapter, int address, int kind) client structure, even though we cannot fill it completely yet. But it allows us to access gl520_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct gl520_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct gl520_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - memset(data, 0, sizeof(struct gl520_data)); new_client = &data->client; i2c_set_clientdata(new_client, data); diff --git a/drivers/hwmon/hdaps.c b/drivers/hwmon/hdaps.c index 7f0107613827..0015da5668a1 100644 --- a/drivers/hwmon/hdaps.c +++ b/drivers/hwmon/hdaps.c @@ -296,11 +296,9 @@ static int hdaps_probe(struct device *dev) return 0; } -static int hdaps_resume(struct device *dev, u32 level) +static int hdaps_resume(struct device *dev) { - if (level == RESUME_ENABLE) - return hdaps_device_init(); - return 0; + return hdaps_device_init(); } static struct device_driver hdaps_driver = { diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c index 9b41c9bd805f..6f48579799b5 100644 --- a/drivers/hwmon/hwmon.c +++ b/drivers/hwmon/hwmon.c @@ -45,7 +45,7 @@ struct class_device *hwmon_device_register(struct device *dev) return ERR_PTR(-ENOMEM); id = id & MAX_ID_MASK; - cdev = class_device_create(hwmon_class, MKDEV(0,0), dev, + cdev = class_device_create(hwmon_class, NULL, MKDEV(0,0), dev, HWMON_ID_FORMAT, id); if (IS_ERR(cdev)) diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index 53cc2b6d6385..6c41e25e670b 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -2,7 +2,7 @@ it87.c - Part of lm_sensors, Linux kernel modules for hardware monitoring. - Supports: IT8705F Super I/O chip w/LPC interface & SMBus + Supports: IT8705F Super I/O chip w/LPC interface IT8712F Super I/O chip w/LPC interface & SMBus Sis950 A clone of the IT8705F @@ -47,7 +47,7 @@ /* Addresses to scan */ static unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END }; -static unsigned short isa_address = 0x290; +static unsigned short isa_address; /* Insmod parameters */ I2C_CLIENT_INSMOD_2(it87, it8712); @@ -706,7 +706,7 @@ static int it87_isa_attach_adapter(struct i2c_adapter *adapter) } /* SuperIO detection - will change isa_address if a chip is found */ -static int __init it87_find(int *address) +static int __init it87_find(unsigned short *address) { int err = -ENODEV; @@ -738,7 +738,7 @@ exit: } /* This function is called by i2c_probe */ -int it87_detect(struct i2c_adapter *adapter, int address, int kind) +static int it87_detect(struct i2c_adapter *adapter, int address, int kind) { int i; struct i2c_client *new_client; @@ -757,42 +757,14 @@ int it87_detect(struct i2c_adapter *adapter, int address, int kind) if (!request_region(address, IT87_EXTENT, it87_isa_driver.name)) goto ERROR0; - /* Probe whether there is anything available on this address. Already - done for SMBus and Super-I/O clients */ - if (kind < 0) { - if (is_isa && !chip_type) { -#define REALLY_SLOW_IO - /* We need the timeouts for at least some IT87-like chips. But only - if we read 'undefined' registers. */ - i = inb_p(address + 1); - if (inb_p(address + 2) != i - || inb_p(address + 3) != i - || inb_p(address + 7) != i) { - err = -ENODEV; - goto ERROR1; - } -#undef REALLY_SLOW_IO - - /* Let's just hope nothing breaks here */ - i = inb_p(address + 5) & 0x7f; - outb_p(~i & 0x7f, address + 5); - if ((inb_p(address + 5) & 0x7f) != (~i & 0x7f)) { - outb_p(i, address + 5); - err = -ENODEV; - goto ERROR1; - } - } - } - - /* OK. For now, we presume we have a valid client. We now create the + /* For now, we presume we have a valid client. We create the client structure, even though we cannot fill it completely yet. But it allows us to access it87_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct it87_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct it87_data), GFP_KERNEL))) { err = -ENOMEM; goto ERROR1; } - memset(data, 0, sizeof(struct it87_data)); new_client = &data->client; if (is_isa) @@ -1182,20 +1154,18 @@ static struct it87_data *it87_update_device(struct device *dev) static int __init sm_it87_init(void) { - int addr, res; - - if (!it87_find(&addr)) { - isa_address = addr; - } + int res; res = i2c_add_driver(&it87_driver); if (res) return res; - res = i2c_isa_add_driver(&it87_isa_driver); - if (res) { - i2c_del_driver(&it87_driver); - return res; + if (!it87_find(&isa_address)) { + res = i2c_isa_add_driver(&it87_isa_driver); + if (res) { + i2c_del_driver(&it87_driver); + return res; + } } return 0; diff --git a/drivers/hwmon/lm63.c b/drivers/hwmon/lm63.c index be5c7095ecbb..954ec2497249 100644 --- a/drivers/hwmon/lm63.c +++ b/drivers/hwmon/lm63.c @@ -375,11 +375,10 @@ static int lm63_detect(struct i2c_adapter *adapter, int address, int kind) if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) goto exit; - if (!(data = kmalloc(sizeof(struct lm63_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct lm63_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - memset(data, 0, sizeof(struct lm63_data)); /* The common I2C client data is placed right before the LM63-specific data. */ diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c index 9a3ebdf583f4..d70f4c8fc1e6 100644 --- a/drivers/hwmon/lm75.c +++ b/drivers/hwmon/lm75.c @@ -127,11 +127,10 @@ static int lm75_detect(struct i2c_adapter *adapter, int address, int kind) /* OK. For now, we presume we have a valid client. We now create the client structure, even though we cannot fill it completely yet. But it allows us to access lm75_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct lm75_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct lm75_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - memset(data, 0, sizeof(struct lm75_data)); new_client = &data->client; i2c_set_clientdata(new_client, data); diff --git a/drivers/hwmon/lm77.c b/drivers/hwmon/lm77.c index 866eab96a6f6..9380fda7dcd1 100644 --- a/drivers/hwmon/lm77.c +++ b/drivers/hwmon/lm77.c @@ -226,11 +226,10 @@ static int lm77_detect(struct i2c_adapter *adapter, int address, int kind) /* OK. For now, we presume we have a valid client. We now create the client structure, even though we cannot fill it completely yet. But it allows us to access lm77_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct lm77_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct lm77_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - memset(data, 0, sizeof(struct lm77_data)); new_client = &data->client; i2c_set_clientdata(new_client, data); diff --git a/drivers/hwmon/lm78.c b/drivers/hwmon/lm78.c index f6730dc3573b..bde0cda9477e 100644 --- a/drivers/hwmon/lm78.c +++ b/drivers/hwmon/lm78.c @@ -480,7 +480,7 @@ static int lm78_isa_attach_adapter(struct i2c_adapter *adapter) } /* This function is called by i2c_probe */ -int lm78_detect(struct i2c_adapter *adapter, int address, int kind) +static int lm78_detect(struct i2c_adapter *adapter, int address, int kind) { int i, err; struct i2c_client *new_client; @@ -540,11 +540,10 @@ int lm78_detect(struct i2c_adapter *adapter, int address, int kind) client structure, even though we cannot fill it completely yet. But it allows us to access lm78_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct lm78_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct lm78_data), GFP_KERNEL))) { err = -ENOMEM; goto ERROR1; } - memset(data, 0, sizeof(struct lm78_data)); new_client = &data->client; if (is_isa) @@ -726,7 +725,6 @@ static int lm78_write_value(struct i2c_client *client, u8 reg, u8 value) return i2c_smbus_write_byte_data(client, reg, value); } -/* Called when we have found a new LM78. It should set limits, etc. */ static void lm78_init_client(struct i2c_client *client) { u8 config = lm78_read_value(client, LM78_REG_CONFIG); diff --git a/drivers/hwmon/lm80.c b/drivers/hwmon/lm80.c index 83af8b3a0cac..c359fdea211e 100644 --- a/drivers/hwmon/lm80.c +++ b/drivers/hwmon/lm80.c @@ -393,7 +393,7 @@ static int lm80_attach_adapter(struct i2c_adapter *adapter) return i2c_probe(adapter, &addr_data, lm80_detect); } -int lm80_detect(struct i2c_adapter *adapter, int address, int kind) +static int lm80_detect(struct i2c_adapter *adapter, int address, int kind) { int i, cur; struct i2c_client *new_client; @@ -407,11 +407,10 @@ int lm80_detect(struct i2c_adapter *adapter, int address, int kind) /* OK. For now, we presume we have a valid client. We now create the client structure, even though we cannot fill it completely yet. But it allows us to access lm80_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct lm80_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct lm80_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - memset(data, 0, sizeof(struct lm80_data)); new_client = &data->client; i2c_set_clientdata(new_client, data); diff --git a/drivers/hwmon/lm83.c b/drivers/hwmon/lm83.c index d74b2c20c719..9a70611a9f69 100644 --- a/drivers/hwmon/lm83.c +++ b/drivers/hwmon/lm83.c @@ -230,11 +230,10 @@ static int lm83_detect(struct i2c_adapter *adapter, int address, int kind) if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) goto exit; - if (!(data = kmalloc(sizeof(struct lm83_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct lm83_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - memset(data, 0, sizeof(struct lm83_data)); /* The common I2C client data is placed right after the * LM83-specific data. */ diff --git a/drivers/hwmon/lm85.c b/drivers/hwmon/lm85.c index ab214df9624b..d1070ed2bee6 100644 --- a/drivers/hwmon/lm85.c +++ b/drivers/hwmon/lm85.c @@ -1007,14 +1007,14 @@ temp_auto(1); temp_auto(2); temp_auto(3); -int lm85_attach_adapter(struct i2c_adapter *adapter) +static int lm85_attach_adapter(struct i2c_adapter *adapter) { if (!(adapter->class & I2C_CLASS_HWMON)) return 0; return i2c_probe(adapter, &addr_data, lm85_detect); } -int lm85_detect(struct i2c_adapter *adapter, int address, +static int lm85_detect(struct i2c_adapter *adapter, int address, int kind) { int company, verstep ; @@ -1033,11 +1033,10 @@ int lm85_detect(struct i2c_adapter *adapter, int address, client structure, even though we cannot fill it completely yet. But it allows us to access lm85_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct lm85_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct lm85_data), GFP_KERNEL))) { err = -ENOMEM; goto ERROR0; } - memset(data, 0, sizeof(struct lm85_data)); new_client = &data->client; i2c_set_clientdata(new_client, data); @@ -1236,7 +1235,7 @@ int lm85_detect(struct i2c_adapter *adapter, int address, return err; } -int lm85_detach_client(struct i2c_client *client) +static int lm85_detach_client(struct i2c_client *client) { struct lm85_data *data = i2c_get_clientdata(client); hwmon_device_unregister(data->class_dev); @@ -1246,7 +1245,7 @@ int lm85_detach_client(struct i2c_client *client) } -int lm85_read_value(struct i2c_client *client, u8 reg) +static int lm85_read_value(struct i2c_client *client, u8 reg) { int res; @@ -1276,7 +1275,7 @@ int lm85_read_value(struct i2c_client *client, u8 reg) return res ; } -int lm85_write_value(struct i2c_client *client, u8 reg, int value) +static int lm85_write_value(struct i2c_client *client, u8 reg, int value) { int res ; @@ -1305,7 +1304,7 @@ int lm85_write_value(struct i2c_client *client, u8 reg, int value) return res ; } -void lm85_init_client(struct i2c_client *client) +static void lm85_init_client(struct i2c_client *client) { int value; struct lm85_data *data = i2c_get_clientdata(client); diff --git a/drivers/hwmon/lm87.c b/drivers/hwmon/lm87.c index dca996de4c33..eeec18177861 100644 --- a/drivers/hwmon/lm87.c +++ b/drivers/hwmon/lm87.c @@ -554,11 +554,10 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind) if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) goto exit; - if (!(data = kmalloc(sizeof(struct lm87_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct lm87_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - memset(data, 0, sizeof(struct lm87_data)); /* The common I2C client data is placed right before the LM87-specific data. */ diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c index 14de05fcd431..83cf2e1b09f5 100644 --- a/drivers/hwmon/lm90.c +++ b/drivers/hwmon/lm90.c @@ -31,7 +31,7 @@ * Devices. That chip is similar to the LM90, with a few differences * that are not handled by this driver. Complete datasheet can be * obtained from Analog's website at: - * http://products.analog.com/products/info.asp?product=ADM1032 + * http://www.analog.com/en/prod/0,2877,ADM1032,00.html * Among others, it has a higher accuracy than the LM90, much like the * LM86 does. * @@ -49,7 +49,7 @@ * register values are decoded differently) it is ignored by this * driver. Complete datasheet can be obtained from Analog's website * at: - * http://products.analog.com/products/info.asp?product=ADT7461 + * http://www.analog.com/en/prod/0,2877,ADT7461,00.html * * Since the LM90 was the first chipset supported by this driver, most * comments will refer to this chipset, but are actually general and @@ -83,10 +83,10 @@ * Addresses to scan * Address is fully defined internally and cannot be changed except for * MAX6659. - * LM86, LM89, LM90, LM99, ADM1032, MAX6657 and MAX6658 have address 0x4c. - * LM89-1, and LM99-1 have address 0x4d. + * LM86, LM89, LM90, LM99, ADM1032, ADM1032-1, ADT7461, MAX6657 and MAX6658 + * have address 0x4c. + * ADM1032-2, ADT7461-2, LM89-1, and LM99-1 have address 0x4d. * MAX6659 can have address 0x4c, 0x4d or 0x4e (unsupported). - * ADT7461 always has address 0x4c. */ static unsigned short normal_i2c[] = { 0x4c, 0x4d, I2C_CLIENT_END }; @@ -345,10 +345,74 @@ static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temphyst, static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_temphyst, NULL, 4); static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); +/* pec used for ADM1032 only */ +static ssize_t show_pec(struct device *dev, struct device_attribute *dummy, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + return sprintf(buf, "%d\n", !!(client->flags & I2C_CLIENT_PEC)); +} + +static ssize_t set_pec(struct device *dev, struct device_attribute *dummy, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + long val = simple_strtol(buf, NULL, 10); + + switch (val) { + case 0: + client->flags &= ~I2C_CLIENT_PEC; + break; + case 1: + client->flags |= I2C_CLIENT_PEC; + break; + default: + return -EINVAL; + } + + return count; +} + +static DEVICE_ATTR(pec, S_IWUSR | S_IRUGO, show_pec, set_pec); + /* * Real code */ +/* The ADM1032 supports PEC but not on write byte transactions, so we need + to explicitely ask for a transaction without PEC. */ +static inline s32 adm1032_write_byte(struct i2c_client *client, u8 value) +{ + return i2c_smbus_xfer(client->adapter, client->addr, + client->flags & ~I2C_CLIENT_PEC, + I2C_SMBUS_WRITE, value, I2C_SMBUS_BYTE, NULL); +} + +/* It is assumed that client->update_lock is held (unless we are in + detection or initialization steps). This matters when PEC is enabled, + because we don't want the address pointer to change between the write + byte and the read byte transactions. */ +static int lm90_read_reg(struct i2c_client* client, u8 reg, u8 *value) +{ + int err; + + if (client->flags & I2C_CLIENT_PEC) { + err = adm1032_write_byte(client, reg); + if (err >= 0) + err = i2c_smbus_read_byte(client); + } else + err = i2c_smbus_read_byte_data(client, reg); + + if (err < 0) { + dev_warn(&client->dev, "Register %#02x read failed (%d)\n", + reg, err); + return err; + } + *value = err; + + return 0; +} + static int lm90_attach_adapter(struct i2c_adapter *adapter) { if (!(adapter->class & I2C_CLASS_HWMON)) @@ -370,11 +434,10 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind) if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) goto exit; - if (!(data = kmalloc(sizeof(struct lm90_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct lm90_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - memset(data, 0, sizeof(struct lm90_data)); /* The common I2C client data is placed right before the LM90-specific data. */ @@ -403,20 +466,22 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind) if (kind < 0) { /* detection and identification */ u8 man_id, chip_id, reg_config1, reg_convrate; - man_id = i2c_smbus_read_byte_data(new_client, - LM90_REG_R_MAN_ID); - chip_id = i2c_smbus_read_byte_data(new_client, - LM90_REG_R_CHIP_ID); - reg_config1 = i2c_smbus_read_byte_data(new_client, - LM90_REG_R_CONFIG1); - reg_convrate = i2c_smbus_read_byte_data(new_client, - LM90_REG_R_CONVRATE); + if (lm90_read_reg(new_client, LM90_REG_R_MAN_ID, + &man_id) < 0 + || lm90_read_reg(new_client, LM90_REG_R_CHIP_ID, + &chip_id) < 0 + || lm90_read_reg(new_client, LM90_REG_R_CONFIG1, + ®_config1) < 0 + || lm90_read_reg(new_client, LM90_REG_R_CONVRATE, + ®_convrate) < 0) + goto exit_free; if (man_id == 0x01) { /* National Semiconductor */ u8 reg_config2; - reg_config2 = i2c_smbus_read_byte_data(new_client, - LM90_REG_R_CONFIG2); + if (lm90_read_reg(new_client, LM90_REG_R_CONFIG2, + ®_config2) < 0) + goto exit_free; if ((reg_config1 & 0x2A) == 0x00 && (reg_config2 & 0xF8) == 0x00 @@ -435,14 +500,12 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind) } } else if (man_id == 0x41) { /* Analog Devices */ - if (address == 0x4C - && (chip_id & 0xF0) == 0x40 /* ADM1032 */ + if ((chip_id & 0xF0) == 0x40 /* ADM1032 */ && (reg_config1 & 0x3F) == 0x00 && reg_convrate <= 0x0A) { kind = adm1032; } else - if (address == 0x4c - && chip_id == 0x51 /* ADT7461 */ + if (chip_id == 0x51 /* ADT7461 */ && (reg_config1 & 0x1F) == 0x00 /* check compat mode */ && reg_convrate <= 0x0A) { kind = adt7461; @@ -477,6 +540,10 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind) name = "lm90"; } else if (kind == adm1032) { name = "adm1032"; + /* The ADM1032 supports PEC, but only if combined + transactions are not used. */ + if (i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) + new_client->flags |= I2C_CLIENT_PEC; } else if (kind == lm99) { name = "lm99"; } else if (kind == lm86) { @@ -529,6 +596,9 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind) &sensor_dev_attr_temp2_crit_hyst.dev_attr); device_create_file(&new_client->dev, &dev_attr_alarms); + if (new_client->flags & I2C_CLIENT_PEC) + device_create_file(&new_client->dev, &dev_attr_pec); + return 0; exit_detach: @@ -548,7 +618,10 @@ static void lm90_init_client(struct i2c_client *client) */ i2c_smbus_write_byte_data(client, LM90_REG_W_CONVRATE, 5); /* 2 Hz */ - config = i2c_smbus_read_byte_data(client, LM90_REG_R_CONFIG1); + if (lm90_read_reg(client, LM90_REG_R_CONFIG1, &config) < 0) { + dev_warn(&client->dev, "Initialization failed!\n"); + return; + } if (config & 0x40) i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, config & 0xBF); /* run */ @@ -576,21 +649,15 @@ static struct lm90_data *lm90_update_device(struct device *dev) down(&data->update_lock); if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) { - u8 oldh, newh; + u8 oldh, newh, l; dev_dbg(&client->dev, "Updating lm90 data.\n"); - data->temp8[0] = i2c_smbus_read_byte_data(client, - LM90_REG_R_LOCAL_TEMP); - data->temp8[1] = i2c_smbus_read_byte_data(client, - LM90_REG_R_LOCAL_LOW); - data->temp8[2] = i2c_smbus_read_byte_data(client, - LM90_REG_R_LOCAL_HIGH); - data->temp8[3] = i2c_smbus_read_byte_data(client, - LM90_REG_R_LOCAL_CRIT); - data->temp8[4] = i2c_smbus_read_byte_data(client, - LM90_REG_R_REMOTE_CRIT); - data->temp_hyst = i2c_smbus_read_byte_data(client, - LM90_REG_R_TCRIT_HYST); + lm90_read_reg(client, LM90_REG_R_LOCAL_TEMP, &data->temp8[0]); + lm90_read_reg(client, LM90_REG_R_LOCAL_LOW, &data->temp8[1]); + lm90_read_reg(client, LM90_REG_R_LOCAL_HIGH, &data->temp8[2]); + lm90_read_reg(client, LM90_REG_R_LOCAL_CRIT, &data->temp8[3]); + lm90_read_reg(client, LM90_REG_R_REMOTE_CRIT, &data->temp8[4]); + lm90_read_reg(client, LM90_REG_R_TCRIT_HYST, &data->temp_hyst); /* * There is a trick here. We have to read two registers to @@ -606,36 +673,20 @@ static struct lm90_data *lm90_update_device(struct device *dev) * then we have a valid reading. Else we have to read the low * byte again, and now we believe we have a correct reading. */ - oldh = i2c_smbus_read_byte_data(client, - LM90_REG_R_REMOTE_TEMPH); - data->temp11[0] = i2c_smbus_read_byte_data(client, - LM90_REG_R_REMOTE_TEMPL); - newh = i2c_smbus_read_byte_data(client, - LM90_REG_R_REMOTE_TEMPH); - if (newh != oldh) { - data->temp11[0] = i2c_smbus_read_byte_data(client, - LM90_REG_R_REMOTE_TEMPL); -#ifdef DEBUG - oldh = i2c_smbus_read_byte_data(client, - LM90_REG_R_REMOTE_TEMPH); - /* oldh is actually newer */ - if (newh != oldh) - dev_warn(&client->dev, "Remote temperature may be " - "wrong.\n"); -#endif - } - data->temp11[0] |= (newh << 8); - - data->temp11[1] = (i2c_smbus_read_byte_data(client, - LM90_REG_R_REMOTE_LOWH) << 8) + - i2c_smbus_read_byte_data(client, - LM90_REG_R_REMOTE_LOWL); - data->temp11[2] = (i2c_smbus_read_byte_data(client, - LM90_REG_R_REMOTE_HIGHH) << 8) + - i2c_smbus_read_byte_data(client, - LM90_REG_R_REMOTE_HIGHL); - data->alarms = i2c_smbus_read_byte_data(client, - LM90_REG_R_STATUS); + if (lm90_read_reg(client, LM90_REG_R_REMOTE_TEMPH, &oldh) == 0 + && lm90_read_reg(client, LM90_REG_R_REMOTE_TEMPL, &l) == 0 + && lm90_read_reg(client, LM90_REG_R_REMOTE_TEMPH, &newh) == 0 + && (newh == oldh + || lm90_read_reg(client, LM90_REG_R_REMOTE_TEMPL, &l) == 0)) + data->temp11[0] = (newh << 8) | l; + + if (lm90_read_reg(client, LM90_REG_R_REMOTE_LOWH, &newh) == 0 + && lm90_read_reg(client, LM90_REG_R_REMOTE_LOWL, &l) == 0) + data->temp11[1] = (newh << 8) | l; + if (lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHH, &newh) == 0 + && lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHL, &l) == 0) + data->temp11[2] = (newh << 8) | l; + lm90_read_reg(client, LM90_REG_R_STATUS, &data->alarms); data->last_updated = jiffies; data->valid = 1; diff --git a/drivers/hwmon/lm92.c b/drivers/hwmon/lm92.c index 647b7c7cd575..7a4b3701ed1a 100644 --- a/drivers/hwmon/lm92.c +++ b/drivers/hwmon/lm92.c @@ -300,11 +300,10 @@ static int lm92_detect(struct i2c_adapter *adapter, int address, int kind) | I2C_FUNC_SMBUS_WORD_DATA)) goto exit; - if (!(data = kmalloc(sizeof(struct lm92_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct lm92_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - memset(data, 0, sizeof(struct lm92_data)); /* Fill in enough client fields so that we can read from the chip, which is required for identication */ diff --git a/drivers/hwmon/max1619.c b/drivers/hwmon/max1619.c index 16bf71f3a04d..6a82ffae1bfd 100644 --- a/drivers/hwmon/max1619.c +++ b/drivers/hwmon/max1619.c @@ -197,11 +197,10 @@ static int max1619_detect(struct i2c_adapter *adapter, int address, int kind) if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) goto exit; - if (!(data = kmalloc(sizeof(struct max1619_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct max1619_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - memset(data, 0, sizeof(struct max1619_data)); /* The common I2C client data is placed right before the MAX1619-specific data. */ diff --git a/drivers/hwmon/pc87360.c b/drivers/hwmon/pc87360.c index cf2a35799c7c..17f745a23d04 100644 --- a/drivers/hwmon/pc87360.c +++ b/drivers/hwmon/pc87360.c @@ -754,9 +754,8 @@ static int pc87360_detect(struct i2c_adapter *adapter) const char *name = "pc87360"; int use_thermistors = 0; - if (!(data = kmalloc(sizeof(struct pc87360_data), GFP_KERNEL))) + if (!(data = kzalloc(sizeof(struct pc87360_data), GFP_KERNEL))) return -ENOMEM; - memset(data, 0x00, sizeof(struct pc87360_data)); new_client = &data->client; i2c_set_clientdata(new_client, data); diff --git a/drivers/hwmon/sis5595.c b/drivers/hwmon/sis5595.c index 21aa9a41f62c..9c6cadec1087 100644 --- a/drivers/hwmon/sis5595.c +++ b/drivers/hwmon/sis5595.c @@ -518,11 +518,10 @@ static int sis5595_detect(struct i2c_adapter *adapter) goto exit_release; } - if (!(data = kmalloc(sizeof(struct sis5595_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct sis5595_data), GFP_KERNEL))) { err = -ENOMEM; goto exit_release; } - memset(data, 0, sizeof(struct sis5595_data)); new_client = &data->client; new_client->addr = address; diff --git a/drivers/hwmon/smsc47b397.c b/drivers/hwmon/smsc47b397.c index 7fe71576dea4..2a3e21b5b6b4 100644 --- a/drivers/hwmon/smsc47b397.c +++ b/drivers/hwmon/smsc47b397.c @@ -244,11 +244,10 @@ static int smsc47b397_detect(struct i2c_adapter *adapter) return -EBUSY; } - if (!(data = kmalloc(sizeof(struct smsc47b397_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct smsc47b397_data), GFP_KERNEL))) { err = -ENOMEM; goto error_release; } - memset(data, 0x00, sizeof(struct smsc47b397_data)); new_client = &data->client; i2c_set_clientdata(new_client, data); @@ -299,7 +298,7 @@ static int __init smsc47b397_find(unsigned short *addr) superio_enter(); id = superio_inb(SUPERIO_REG_DEVID); - if (id != 0x6f) { + if ((id != 0x6f) && (id != 0x81)) { superio_exit(); return -ENODEV; } @@ -310,8 +309,9 @@ static int __init smsc47b397_find(unsigned short *addr) *addr = (superio_inb(SUPERIO_REG_BASE_MSB) << 8) | superio_inb(SUPERIO_REG_BASE_LSB); - printk(KERN_INFO "smsc47b397: found SMSC LPC47B397-NC " - "(base address 0x%04x, revision %u)\n", *addr, rev); + printk(KERN_INFO "smsc47b397: found SMSC %s " + "(base address 0x%04x, revision %u)\n", + id == 0x81 ? "SCH5307-NS" : "LPC47B397-NC", *addr, rev); superio_exit(); return 0; diff --git a/drivers/hwmon/smsc47m1.c b/drivers/hwmon/smsc47m1.c index c9cc683eba4a..5905c1af88f2 100644 --- a/drivers/hwmon/smsc47m1.c +++ b/drivers/hwmon/smsc47m1.c @@ -3,7 +3,7 @@ for hardware monitoring Supports the SMSC LPC47B27x, LPC47M10x, LPC47M13x, LPC47M14x, - LPC47M15x and LPC47M192 Super-I/O chips. + LPC47M15x, LPC47M192 and LPC47M997 Super-I/O chips. Copyright (C) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com> Copyright (C) 2004 Jean Delvare <khali@linux-fr.org> @@ -356,6 +356,8 @@ static int __init smsc47m1_find(unsigned short *addr) * 0x5F) and LPC47B27x (device id 0x51) have fan control. * The LPC47M15x and LPC47M192 chips "with hardware monitoring block" * can do much more besides (device id 0x60). + * The LPC47M997 is undocumented, but seems to be compatible with + * the LPC47M192, and has the same device id. */ if (val == 0x51) printk(KERN_INFO "smsc47m1: Found SMSC LPC47B27x\n"); @@ -364,7 +366,8 @@ static int __init smsc47m1_find(unsigned short *addr) else if (val == 0x5F) printk(KERN_INFO "smsc47m1: Found SMSC LPC47M14x\n"); else if (val == 0x60) - printk(KERN_INFO "smsc47m1: Found SMSC LPC47M15x/LPC47M192\n"); + printk(KERN_INFO "smsc47m1: Found SMSC " + "LPC47M15x/LPC47M192/LPC47M997\n"); else { superio_exit(); return -ENODEV; @@ -396,11 +399,10 @@ static int smsc47m1_detect(struct i2c_adapter *adapter) return -EBUSY; } - if (!(data = kmalloc(sizeof(struct smsc47m1_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct smsc47m1_data), GFP_KERNEL))) { err = -ENOMEM; goto error_release; } - memset(data, 0x00, sizeof(struct smsc47m1_data)); new_client = &data->client; i2c_set_clientdata(new_client, data); diff --git a/drivers/hwmon/via686a.c b/drivers/hwmon/via686a.c index 05ddc88e7dd2..6f696f897176 100644 --- a/drivers/hwmon/via686a.c +++ b/drivers/hwmon/via686a.c @@ -44,7 +44,7 @@ /* If force_addr is set to anything different from 0, we forcibly enable the device at the given address. */ -static unsigned short force_addr = 0; +static unsigned short force_addr; module_param(force_addr, ushort, 0); MODULE_PARM_DESC(force_addr, "Initialize the base address of the sensors"); @@ -198,7 +198,7 @@ static inline u8 FAN_TO_REG(long rpm, int div) but the function is very linear in the useful range (0-80 deg C), so we'll just use linear interpolation for 10-bit readings.) So, tempLUT is the temp at via register values 0-255: */ -static const long tempLUT[] = +static const s16 tempLUT[] = { -709, -688, -667, -646, -627, -607, -589, -570, -553, -536, -519, -503, -487, -471, -456, -442, -428, -414, -400, -387, -375, -362, -350, -339, -327, -316, -305, -295, -285, -275, -265, @@ -270,7 +270,7 @@ static inline u8 TEMP_TO_REG(long val) } /* for 8-bit temperature hyst and over registers */ -#define TEMP_FROM_REG(val) (tempLUT[(val)] * 100) +#define TEMP_FROM_REG(val) ((long)tempLUT[val] * 100) /* for 10-bit temperature readings */ static inline long TEMP_FROM_REG10(u16 val) @@ -589,10 +589,8 @@ static int via686a_detect(struct i2c_adapter *adapter) u16 val; /* 8231 requires multiple of 256, we enforce that on 686 as well */ - if (force_addr) - address = force_addr & 0xFF00; - if (force_addr) { + address = force_addr & 0xFF00; dev_warn(&adapter->dev, "forcing ISA address 0x%04X\n", address); if (PCIBIOS_SUCCESSFUL != @@ -603,11 +601,17 @@ static int via686a_detect(struct i2c_adapter *adapter) pci_read_config_word(s_bridge, VIA686A_ENABLE_REG, &val)) return -ENODEV; if (!(val & 0x0001)) { - dev_warn(&adapter->dev, "enabling sensors\n"); - if (PCIBIOS_SUCCESSFUL != - pci_write_config_word(s_bridge, VIA686A_ENABLE_REG, - val | 0x0001)) + if (force_addr) { + dev_info(&adapter->dev, "enabling sensors\n"); + if (PCIBIOS_SUCCESSFUL != + pci_write_config_word(s_bridge, VIA686A_ENABLE_REG, + val | 0x0001)) + return -ENODEV; + } else { + dev_warn(&adapter->dev, "sensors disabled - enable " + "with force_addr=0x%x\n", address); return -ENODEV; + } } /* Reserve the ISA region */ @@ -617,11 +621,10 @@ static int via686a_detect(struct i2c_adapter *adapter) return -ENODEV; } - if (!(data = kmalloc(sizeof(struct via686a_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct via686a_data), GFP_KERNEL))) { err = -ENOMEM; goto exit_release; } - memset(data, 0, sizeof(struct via686a_data)); new_client = &data->client; i2c_set_clientdata(new_client, data); @@ -708,7 +711,6 @@ static int via686a_detach_client(struct i2c_client *client) return 0; } -/* Called when we have found a new VIA686A. Set limits, etc. */ static void via686a_init_client(struct i2c_client *client) { u8 reg; diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c index b60efe8f8b26..eee22a57e929 100644 --- a/drivers/hwmon/w83627ehf.c +++ b/drivers/hwmon/w83627ehf.c @@ -105,7 +105,9 @@ superio_exit(void) * ISA constants */ -#define REGION_LENGTH 8 +#define REGION_ALIGNMENT ~7 +#define REGION_OFFSET 5 +#define REGION_LENGTH 2 #define ADDR_REG_OFFSET 5 #define DATA_REG_OFFSET 6 @@ -673,16 +675,16 @@ static int w83627ehf_detect(struct i2c_adapter *adapter) struct w83627ehf_data *data; int i, err = 0; - if (!request_region(address, REGION_LENGTH, w83627ehf_driver.name)) { + if (!request_region(address + REGION_OFFSET, REGION_LENGTH, + w83627ehf_driver.name)) { err = -EBUSY; goto exit; } - if (!(data = kmalloc(sizeof(struct w83627ehf_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct w83627ehf_data), GFP_KERNEL))) { err = -ENOMEM; goto exit_release; } - memset(data, 0, sizeof(struct w83627ehf_data)); client = &data->client; i2c_set_clientdata(client, data); @@ -762,7 +764,7 @@ exit_detach: exit_free: kfree(data); exit_release: - release_region(address, REGION_LENGTH); + release_region(address + REGION_OFFSET, REGION_LENGTH); exit: return err; } @@ -776,7 +778,7 @@ static int w83627ehf_detach_client(struct i2c_client *client) if ((err = i2c_detach_client(client))) return err; - release_region(client->addr, REGION_LENGTH); + release_region(client->addr + REGION_OFFSET, REGION_LENGTH); kfree(data); return 0; @@ -807,7 +809,7 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr) superio_select(W83627EHF_LD_HWM); val = (superio_inb(SIO_REG_ADDR) << 8) | superio_inb(SIO_REG_ADDR + 1); - *addr = val & ~(REGION_LENGTH - 1); + *addr = val & REGION_ALIGNMENT; if (*addr == 0) { superio_exit(); return -ENODEV; diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c index 3479dc5208e2..70ef926c3bd8 100644 --- a/drivers/hwmon/w83627hf.c +++ b/drivers/hwmon/w83627hf.c @@ -142,10 +142,14 @@ superio_exit(void) #define WINB_BASE_REG 0x60 /* Constants specified below */ -/* Length of ISA address segment */ -#define WINB_EXTENT 8 +/* Alignment of the base address */ +#define WINB_ALIGNMENT ~7 -/* Where are the ISA address/data registers relative to the base address */ +/* Offset & size of I/O region we are interested in */ +#define WINB_REGION_OFFSET 5 +#define WINB_REGION_SIZE 2 + +/* Where are the sensors address/data registers relative to the base address */ #define W83781D_ADDR_REG_OFFSET 5 #define W83781D_DATA_REG_OFFSET 6 @@ -197,7 +201,6 @@ superio_exit(void) #define W83627HF_REG_PWM1 0x5A #define W83627HF_REG_PWM2 0x5B -#define W83627HF_REG_PWMCLK12 0x5C #define W83627THF_REG_PWM1 0x01 /* 697HF and 637HF too */ #define W83627THF_REG_PWM2 0x03 /* 697HF and 637HF too */ @@ -981,7 +984,7 @@ static int __init w83627hf_find(int sioaddr, unsigned short *addr) superio_select(W83627HF_LD_HWM); val = (superio_inb(WINB_BASE_REG) << 8) | superio_inb(WINB_BASE_REG + 1); - *addr = val & ~(WINB_EXTENT - 1); + *addr = val & WINB_ALIGNMENT; if (*addr == 0 && force_addr == 0) { superio_exit(); return -ENODEV; @@ -1000,9 +1003,10 @@ static int w83627hf_detect(struct i2c_adapter *adapter) const char *client_name = ""; if(force_addr) - address = force_addr & ~(WINB_EXTENT - 1); + address = force_addr & WINB_ALIGNMENT; - if (!request_region(address, WINB_EXTENT, w83627hf_driver.name)) { + if (!request_region(address + WINB_REGION_OFFSET, WINB_REGION_SIZE, + w83627hf_driver.name)) { err = -EBUSY; goto ERROR0; } @@ -1041,11 +1045,10 @@ static int w83627hf_detect(struct i2c_adapter *adapter) client structure, even though we cannot fill it completely yet. But it allows us to access w83627hf_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct w83627hf_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct w83627hf_data), GFP_KERNEL))) { err = -ENOMEM; goto ERROR1; } - memset(data, 0, sizeof(struct w83627hf_data)); new_client = &data->client; i2c_set_clientdata(new_client, data); @@ -1148,7 +1151,7 @@ static int w83627hf_detect(struct i2c_adapter *adapter) ERROR2: kfree(data); ERROR1: - release_region(address, WINB_EXTENT); + release_region(address + WINB_REGION_OFFSET, WINB_REGION_SIZE); ERROR0: return err; } @@ -1163,7 +1166,7 @@ static int w83627hf_detach_client(struct i2c_client *client) if ((err = i2c_detach_client(client))) return err; - release_region(client->addr, WINB_EXTENT); + release_region(client->addr + WINB_REGION_OFFSET, WINB_REGION_SIZE); kfree(data); return 0; @@ -1275,7 +1278,6 @@ static int w83627hf_write_value(struct i2c_client *client, u16 reg, u16 value) return 0; } -/* Called when we have found a new W83781D. It should set limits, etc. */ static void w83627hf_init_client(struct i2c_client *client) { struct w83627hf_data *data = i2c_get_clientdata(client); @@ -1369,12 +1371,6 @@ static void w83627hf_init_client(struct i2c_client *client) } } - if (type == w83627hf) { - /* enable PWM2 control (can't hurt since PWM reg - should have been reset to 0xff) */ - w83627hf_write_value(client, W83627HF_REG_PWMCLK12, - 0x19); - } /* enable comparator mode for temp2 and temp3 so alarm indication will work correctly */ i = w83627hf_read_value(client, W83781D_REG_IRQ); diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c index 4c43337ca780..9265f32122fa 100644 --- a/drivers/hwmon/w83781d.c +++ b/drivers/hwmon/w83781d.c @@ -889,12 +889,11 @@ w83781d_detect_subclients(struct i2c_adapter *adapter, int address, int kind, const char *client_name = ""; struct w83781d_data *data = i2c_get_clientdata(new_client); - data->lm75[0] = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); + data->lm75[0] = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); if (!(data->lm75[0])) { err = -ENOMEM; goto ERROR_SC_0; } - memset(data->lm75[0], 0x00, sizeof (struct i2c_client)); id = i2c_adapter_id(adapter); @@ -919,13 +918,11 @@ w83781d_detect_subclients(struct i2c_adapter *adapter, int address, int kind, } if (kind != w83783s) { - - data->lm75[1] = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); + data->lm75[1] = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); if (!(data->lm75[1])) { err = -ENOMEM; goto ERROR_SC_1; } - memset(data->lm75[1], 0x0, sizeof(struct i2c_client)); if (force_subclients[0] == id && force_subclients[1] == address) { @@ -1064,11 +1061,10 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) client structure, even though we cannot fill it completely yet. But it allows us to access w83781d_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct w83781d_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct w83781d_data), GFP_KERNEL))) { err = -ENOMEM; goto ERROR1; } - memset(data, 0, sizeof(struct w83781d_data)); new_client = &data->client; i2c_set_clientdata(new_client, data); @@ -1451,7 +1447,6 @@ w83781d_write_value(struct i2c_client *client, u16 reg, u16 value) return 0; } -/* Called when we have found a new W83781D. It should set limits, etc. */ static void w83781d_init_client(struct i2c_client *client) { diff --git a/drivers/hwmon/w83792d.c b/drivers/hwmon/w83792d.c index ba0c28015f6a..4be59dbb78c4 100644 --- a/drivers/hwmon/w83792d.c +++ b/drivers/hwmon/w83792d.c @@ -1086,11 +1086,10 @@ w83792d_create_subclient(struct i2c_adapter *adapter, int err; struct i2c_client *sub_client; - (*sub_cli) = sub_client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); + (*sub_cli) = sub_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); if (!(sub_client)) { return -ENOMEM; } - memset(sub_client, 0x00, sizeof(struct i2c_client)); sub_client->addr = 0x48 + addr; i2c_set_clientdata(sub_client, NULL); sub_client->adapter = adapter; @@ -1184,11 +1183,10 @@ w83792d_detect(struct i2c_adapter *adapter, int address, int kind) client structure, even though we cannot fill it completely yet. But it allows us to access w83792d_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct w83792d_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct w83792d_data), GFP_KERNEL))) { err = -ENOMEM; goto ERROR0; } - memset(data, 0, sizeof(struct w83792d_data)); new_client = &data->client; i2c_set_clientdata(new_client, data); @@ -1429,7 +1427,6 @@ w83792d_write_value(struct i2c_client *client, u8 reg, u8 value) return 0; } -/* Called when we have found a new W83792D. It should set limits, etc. */ static void w83792d_init_client(struct i2c_client *client) { diff --git a/drivers/hwmon/w83l785ts.c b/drivers/hwmon/w83l785ts.c index 133e34ab1d0a..f495b6378668 100644 --- a/drivers/hwmon/w83l785ts.c +++ b/drivers/hwmon/w83l785ts.c @@ -37,6 +37,7 @@ #include <linux/jiffies.h> #include <linux/i2c.h> #include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> #include <linux/err.h> /* How many retries on register read error */ @@ -73,7 +74,7 @@ I2C_CLIENT_INSMOD_1(w83l785ts); * The W83L785TS-S uses signed 8-bit values. */ -#define TEMP_FROM_REG(val) ((val & 0x80 ? val-0x100 : val) * 1000) +#define TEMP_FROM_REG(val) ((val) * 1000) /* * Functions declaration @@ -111,27 +112,24 @@ struct w83l785ts_data { unsigned long last_updated; /* in jiffies */ /* registers values */ - u8 temp, temp_over; + s8 temp[2]; /* 0: input + 1: critical limit */ }; /* * Sysfs stuff */ -static ssize_t show_temp(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, + char *buf) { + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct w83l785ts_data *data = w83l785ts_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp)); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[attr->index])); } -static ssize_t show_temp_over(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct w83l785ts_data *data = w83l785ts_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_over)); -} - -static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL); -static DEVICE_ATTR(temp1_max, S_IRUGO, show_temp_over, NULL); +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0); +static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, show_temp, NULL, 1); /* * Real code @@ -158,12 +156,10 @@ static int w83l785ts_detect(struct i2c_adapter *adapter, int address, int kind) if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) goto exit; - if (!(data = kmalloc(sizeof(struct w83l785ts_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct w83l785ts_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - memset(data, 0, sizeof(struct w83l785ts_data)); - /* The common I2C client data is placed right before the * W83L785TS-specific data. */ @@ -228,7 +224,7 @@ static int w83l785ts_detect(struct i2c_adapter *adapter, int address, int kind) init_MUTEX(&data->update_lock); /* Default values in case the first read fails (unlikely). */ - data->temp_over = data->temp = 0; + data->temp[1] = data->temp[0] = 0; /* Tell the I2C layer a new client has arrived. */ if ((err = i2c_attach_client(new_client))) @@ -246,8 +242,10 @@ static int w83l785ts_detect(struct i2c_adapter *adapter, int address, int kind) goto exit_detach; } - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_temp1_max); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_input.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_max.dev_attr); return 0; @@ -305,10 +303,10 @@ static struct w83l785ts_data *w83l785ts_update_device(struct device *dev) if (!data->valid || time_after(jiffies, data->last_updated + HZ * 2)) { dev_dbg(&client->dev, "Updating w83l785ts data.\n"); - data->temp = w83l785ts_read_value(client, - W83L785TS_REG_TEMP, data->temp); - data->temp_over = w83l785ts_read_value(client, - W83L785TS_REG_TEMP_OVER, data->temp_over); + data->temp[0] = w83l785ts_read_value(client, + W83L785TS_REG_TEMP, data->temp[0]); + data->temp[1] = w83l785ts_read_value(client, + W83L785TS_REG_TEMP_OVER, data->temp[1]); data->last_updated = jiffies; data->valid = 1; diff --git a/drivers/i2c/algos/i2c-algo-pca.c b/drivers/i2c/algos/i2c-algo-pca.c index beb10edfe9c1..82946acab4c7 100644 --- a/drivers/i2c/algos/i2c-algo-pca.c +++ b/drivers/i2c/algos/i2c-algo-pca.c @@ -34,7 +34,7 @@ #define DEB2(fmt, args...) do { if (i2c_debug>=2) printk(fmt, ## args); } while(0) #define DEB3(fmt, args...) do { if (i2c_debug>=3) printk(fmt, ## args); } while(0) -static int i2c_debug=0; +static int i2c_debug; #define pca_outw(adap, reg, val) adap->write_byte(adap, reg, val) #define pca_inw(adap, reg) adap->read_byte(adap, reg) diff --git a/drivers/i2c/algos/i2c-algo-sibyte.c b/drivers/i2c/algos/i2c-algo-sibyte.c index 8ed5ad12552f..938848ae162d 100644 --- a/drivers/i2c/algos/i2c-algo-sibyte.c +++ b/drivers/i2c/algos/i2c-algo-sibyte.c @@ -42,7 +42,7 @@ /* module parameters: */ -static int bit_scan=0; /* have a look at what's hanging 'round */ +static int bit_scan; /* have a look at what's hanging 'round */ static int smbus_xfer(struct i2c_adapter *i2c_adap, u16 addr, diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 3badfec75b1c..4010fe92e72b 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -135,11 +135,12 @@ config I2C_I810 help If you say yes to this option, support will be included for the Intel 810/815 family of mainboard I2C interfaces. Specifically, the - following versions of the chipset is supported: + following versions of the chipset are supported: i810AA i810AB i810E i815 + i845G This driver can also be built as a module. If so, the module will be called i2c-i810. diff --git a/drivers/i2c/busses/i2c-ali1535.c b/drivers/i2c/busses/i2c-ali1535.c index f021acd2674e..ba90f5140af6 100644 --- a/drivers/i2c/busses/i2c-ali1535.c +++ b/drivers/i2c/busses/i2c-ali1535.c @@ -134,7 +134,7 @@ /* -> Read = 1 */ #define ALI1535_SMBIO_EN 0x04 /* SMB I/O Space enable */ - +static struct pci_driver ali1535_driver; static unsigned short ali1535_smba; static DECLARE_MUTEX(i2c_ali1535_sem); @@ -162,7 +162,8 @@ static int ali1535_setup(struct pci_dev *dev) goto exit; } - if (!request_region(ali1535_smba, ALI1535_SMB_IOSIZE, "ali1535-smb")) { + if (!request_region(ali1535_smba, ALI1535_SMB_IOSIZE, + ali1535_driver.name)) { dev_err(&dev->dev, "ALI1535_smb region 0x%x already in use!\n", ali1535_smba); goto exit; @@ -480,7 +481,6 @@ static struct i2c_adapter ali1535_adapter = { .owner = THIS_MODULE, .class = I2C_CLASS_HWMON, .algo = &smbus_algorithm, - .name = "unset", }; static struct pci_device_id ali1535_ids[] = { @@ -513,6 +513,7 @@ static void __devexit ali1535_remove(struct pci_dev *dev) } static struct pci_driver ali1535_driver = { + .owner = THIS_MODULE, .name = "ali1535_smbus", .id_table = ali1535_ids, .probe = ali1535_probe, diff --git a/drivers/i2c/busses/i2c-ali1563.c b/drivers/i2c/busses/i2c-ali1563.c index 86947504aea1..f1a62d892425 100644 --- a/drivers/i2c/busses/i2c-ali1563.c +++ b/drivers/i2c/busses/i2c-ali1563.c @@ -60,6 +60,7 @@ #define HST_CNTL2_SIZEMASK 0x38 +static struct pci_driver ali1563_pci_driver; static unsigned short ali1563_smba; static int ali1563_transaction(struct i2c_adapter * a, int size) @@ -350,7 +351,8 @@ static int __devinit ali1563_setup(struct pci_dev * dev) dev_warn(&dev->dev,"ali1563_smba Uninitialized\n"); goto Err; } - if (!request_region(ali1563_smba,ALI1563_SMB_IOSIZE,"i2c-ali1563")) { + if (!request_region(ali1563_smba, ALI1563_SMB_IOSIZE, + ali1563_pci_driver.name)) { dev_warn(&dev->dev,"Could not allocate I/O space"); goto Err; } @@ -406,7 +408,8 @@ static struct pci_device_id __devinitdata ali1563_id_table[] = { MODULE_DEVICE_TABLE (pci, ali1563_id_table); static struct pci_driver ali1563_pci_driver = { - .name = "ali1563_i2c", + .owner = THIS_MODULE, + .name = "ali1563_smbus", .id_table = ali1563_id_table, .probe = ali1563_probe, .remove = __devexit_p(ali1563_remove), diff --git a/drivers/i2c/busses/i2c-ali15x3.c b/drivers/i2c/busses/i2c-ali15x3.c index b3f50bff39a0..400b08ed4299 100644 --- a/drivers/i2c/busses/i2c-ali15x3.c +++ b/drivers/i2c/busses/i2c-ali15x3.c @@ -125,12 +125,13 @@ /* If force_addr is set to anything different from 0, we forcibly enable the device at the given address. */ -static u16 force_addr = 0; +static u16 force_addr; module_param(force_addr, ushort, 0); MODULE_PARM_DESC(force_addr, "Initialize the base address of the i2c controller"); -static unsigned short ali15x3_smba = 0; +static struct pci_driver ali15x3_driver; +static unsigned short ali15x3_smba; static int ali15x3_setup(struct pci_dev *ALI15X3_dev) { @@ -166,7 +167,8 @@ static int ali15x3_setup(struct pci_dev *ALI15X3_dev) if(force_addr) ali15x3_smba = force_addr & ~(ALI15X3_SMB_IOSIZE - 1); - if (!request_region(ali15x3_smba, ALI15X3_SMB_IOSIZE, "ali15x3-smb")) { + if (!request_region(ali15x3_smba, ALI15X3_SMB_IOSIZE, + ali15x3_driver.name)) { dev_err(&ALI15X3_dev->dev, "ALI15X3_smb region 0x%x already in use!\n", ali15x3_smba); @@ -470,7 +472,6 @@ static struct i2c_adapter ali15x3_adapter = { .owner = THIS_MODULE, .class = I2C_CLASS_HWMON, .algo = &smbus_algorithm, - .name = "unset", }; static struct pci_device_id ali15x3_ids[] = { @@ -503,6 +504,7 @@ static void __devexit ali15x3_remove(struct pci_dev *dev) } static struct pci_driver ali15x3_driver = { + .owner = THIS_MODULE, .name = "ali15x3_smbus", .id_table = ali15x3_ids, .probe = ali15x3_probe, diff --git a/drivers/i2c/busses/i2c-amd756-s4882.c b/drivers/i2c/busses/i2c-amd756-s4882.c index 4e553e8c5cba..f51ab652300a 100644 --- a/drivers/i2c/busses/i2c-amd756-s4882.c +++ b/drivers/i2c/busses/i2c-amd756-s4882.c @@ -169,12 +169,12 @@ static int __init amd756_s4882_init(void) init_MUTEX(&amd756_lock); /* Define the 5 virtual adapters and algorithms structures */ - if (!(s4882_adapter = kmalloc(5 * sizeof(struct i2c_adapter), + if (!(s4882_adapter = kzalloc(5 * sizeof(struct i2c_adapter), GFP_KERNEL))) { error = -ENOMEM; goto ERROR1; } - if (!(s4882_algo = kmalloc(5 * sizeof(struct i2c_algorithm), + if (!(s4882_algo = kzalloc(5 * sizeof(struct i2c_algorithm), GFP_KERNEL))) { error = -ENOMEM; goto ERROR2; diff --git a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c index 6ad0603384b8..de035d137c3f 100644 --- a/drivers/i2c/busses/i2c-amd756.c +++ b/drivers/i2c/busses/i2c-amd756.c @@ -85,8 +85,8 @@ #define AMD756_PROCESS_CALL 0x04 #define AMD756_BLOCK_DATA 0x05 - -static unsigned short amd756_ioport = 0; +static struct pci_driver amd756_driver; +static unsigned short amd756_ioport; /* SMBUS event = I/O 28-29 bit 11 @@ -303,7 +303,6 @@ struct i2c_adapter amd756_smbus = { .owner = THIS_MODULE, .class = I2C_CLASS_HWMON, .algo = &smbus_algorithm, - .name = "unset", }; enum chiptype { AMD756, AMD766, AMD768, NFORCE, AMD8111 }; @@ -365,7 +364,7 @@ static int __devinit amd756_probe(struct pci_dev *pdev, amd756_ioport += SMB_ADDR_OFFSET; } - if (!request_region(amd756_ioport, SMB_IOSIZE, "amd756-smbus")) { + if (!request_region(amd756_ioport, SMB_IOSIZE, amd756_driver.name)) { dev_err(&pdev->dev, "SMB region 0x%x already in use!\n", amd756_ioport); return -ENODEV; @@ -402,6 +401,7 @@ static void __devexit amd756_remove(struct pci_dev *dev) } static struct pci_driver amd756_driver = { + .owner = THIS_MODULE, .name = "amd756_smbus", .id_table = amd756_ids, .probe = amd756_probe, diff --git a/drivers/i2c/busses/i2c-amd8111.c b/drivers/i2c/busses/i2c-amd8111.c index 45ea24ba14d5..f3b79a68dbec 100644 --- a/drivers/i2c/busses/i2c-amd8111.c +++ b/drivers/i2c/busses/i2c-amd8111.c @@ -30,6 +30,8 @@ struct amd_smbus { int size; }; +static struct pci_driver amd8111_driver; + /* * AMD PCI control registers definitions. */ @@ -242,7 +244,6 @@ static s32 amd8111_access(struct i2c_adapter * adap, u16 addr, unsigned short fl break; case I2C_SMBUS_BLOCK_PROC_CALL: - protocol |= pec; len = min_t(u8, data->block[0], 31); amd_ec_write(smbus, AMD_SMB_CMD, command); amd_ec_write(smbus, AMD_SMB_BCNT, len); @@ -252,13 +253,6 @@ static s32 amd8111_access(struct i2c_adapter * adap, u16 addr, unsigned short fl read_write = I2C_SMBUS_READ; break; - case I2C_SMBUS_WORD_DATA_PEC: - case I2C_SMBUS_BLOCK_DATA_PEC: - case I2C_SMBUS_PROC_CALL_PEC: - case I2C_SMBUS_BLOCK_PROC_CALL_PEC: - dev_warn(&adap->dev, "Unexpected software PEC transaction %d\n.", size); - return -1; - default: dev_warn(&adap->dev, "Unsupported transaction %d\n", size); return -1; @@ -343,16 +337,15 @@ static int __devinit amd8111_probe(struct pci_dev *dev, const struct pci_device_ if (~pci_resource_flags(dev, 0) & IORESOURCE_IO) return -ENODEV; - smbus = kmalloc(sizeof(struct amd_smbus), GFP_KERNEL); + smbus = kzalloc(sizeof(struct amd_smbus), GFP_KERNEL); if (!smbus) return -ENOMEM; - memset(smbus, 0, sizeof(struct amd_smbus)); smbus->dev = dev; smbus->base = pci_resource_start(dev, 0); smbus->size = pci_resource_len(dev, 0); - if (!request_region(smbus->base, smbus->size, "amd8111 SMBus 2.0")) + if (!request_region(smbus->base, smbus->size, amd8111_driver.name)) goto out_kfree; smbus->adapter.owner = THIS_MODULE; @@ -391,6 +384,7 @@ static void __devexit amd8111_remove(struct pci_dev *dev) } static struct pci_driver amd8111_driver = { + .owner = THIS_MODULE, .name = "amd8111_smbus2", .id_table = amd8111_ids, .probe = amd8111_probe, diff --git a/drivers/i2c/busses/i2c-elektor.c b/drivers/i2c/busses/i2c-elektor.c index 6930b660e508..59f8308c2356 100644 --- a/drivers/i2c/busses/i2c-elektor.c +++ b/drivers/i2c/busses/i2c-elektor.c @@ -22,7 +22,7 @@ /* With some changes from Kysti Mlkki <kmalkki@cc.hut.fi> and even Frodo Looijaard <frodol@dds.nl> */ -/* Partialy rewriten by Oleg I. Vdovikin for mmapped support of +/* Partialy rewriten by Oleg I. Vdovikin for mmapped support of for Alpha Processor Inc. UP-2000(+) boards */ #include <linux/kernel.h> @@ -46,12 +46,14 @@ #define DEFAULT_BASE 0x330 static int base; +static u8 __iomem *base_iomem; + static int irq; static int clock = 0x1c; static int own = 0x55; static int mmapped; -/* vdovikin: removed static struct i2c_pcf_isa gpi; code - +/* vdovikin: removed static struct i2c_pcf_isa gpi; code - this module in real supports only one device, due to missing arguments in some functions, called from the algo-pcf module. Sometimes it's need to be rewriten - but for now just remove this for simpler reading */ @@ -60,40 +62,33 @@ static wait_queue_head_t pcf_wait; static int pcf_pending; static spinlock_t lock; +static struct i2c_adapter pcf_isa_ops; + /* ----- local functions ---------------------------------------------- */ static void pcf_isa_setbyte(void *data, int ctl, int val) { - int address = ctl ? (base + 1) : base; + u8 __iomem *address = ctl ? (base_iomem + 1) : base_iomem; /* enable irq if any specified for serial operation */ if (ctl && irq && (val & I2C_PCF_ESO)) { val |= I2C_PCF_ENI; } - pr_debug("i2c-elektor: Write 0x%X 0x%02X\n", address, val & 255); - - switch (mmapped) { - case 0: /* regular I/O */ - outb(val, address); - break; - case 2: /* double mapped I/O needed for UP2000 board, - I don't know why this... */ - writeb(val, (void *)address); - /* fall */ - case 1: /* memory mapped I/O */ - writeb(val, (void *)address); - break; - } + pr_debug("%s: Write %p 0x%02X\n", pcf_isa_ops.name, address, val); + iowrite8(val, address); +#ifdef __alpha__ + /* API UP2000 needs some hardware fudging to make the write stick */ + iowrite8(val, address); +#endif } static int pcf_isa_getbyte(void *data, int ctl) { - int address = ctl ? (base + 1) : base; - int val = mmapped ? readb((void *)address) : inb(address); - - pr_debug("i2c-elektor: Read 0x%X 0x%02X\n", address, val); + u8 __iomem *address = ctl ? (base_iomem + 1) : base_iomem; + int val = ioread8(address); + pr_debug("%s: Read %p 0x%02X\n", pcf_isa_ops.name, address, val); return (val); } @@ -149,16 +144,40 @@ static int pcf_isa_init(void) { spin_lock_init(&lock); if (!mmapped) { - if (!request_region(base, 2, "i2c (isa bus adapter)")) { - printk(KERN_ERR - "i2c-elektor: requested I/O region (0x%X:2) " - "is in use.\n", base); + if (!request_region(base, 2, pcf_isa_ops.name)) { + printk(KERN_ERR "%s: requested I/O region (%#x:2) is " + "in use\n", pcf_isa_ops.name, base); + return -ENODEV; + } + base_iomem = ioport_map(base, 2); + if (!base_iomem) { + printk(KERN_ERR "%s: remap of I/O region %#x failed\n", + pcf_isa_ops.name, base); + release_region(base, 2); + return -ENODEV; + } + } else { + if (!request_mem_region(base, 2, pcf_isa_ops.name)) { + printk(KERN_ERR "%s: requested memory region (%#x:2) " + "is in use\n", pcf_isa_ops.name, base); + return -ENODEV; + } + base_iomem = ioremap(base, 2); + if (base_iomem == NULL) { + printk(KERN_ERR "%s: remap of memory region %#x " + "failed\n", pcf_isa_ops.name, base); + release_mem_region(base, 2); return -ENODEV; } } + pr_debug("%s: registers %#x remapped to %p\n", pcf_isa_ops.name, base, + base_iomem); + if (irq > 0) { - if (request_irq(irq, pcf_isa_handler, 0, "PCF8584", NULL) < 0) { - printk(KERN_ERR "i2c-elektor: Request irq%d failed\n", irq); + if (request_irq(irq, pcf_isa_handler, 0, pcf_isa_ops.name, + NULL) < 0) { + printk(KERN_ERR "%s: Request irq%d failed\n", + pcf_isa_ops.name, irq); irq = 0; } else enable_irq(irq); @@ -186,47 +205,49 @@ static struct i2c_adapter pcf_isa_ops = { .class = I2C_CLASS_HWMON, .id = I2C_HW_P_ELEK, .algo_data = &pcf_isa_data, - .name = "PCF8584 ISA adapter", + .name = "i2c-elektor", }; -static int __init i2c_pcfisa_init(void) +static int __init i2c_pcfisa_init(void) { #ifdef __alpha__ - /* check to see we have memory mapped PCF8584 connected to the + /* check to see we have memory mapped PCF8584 connected to the Cypress cy82c693 PCI-ISA bridge as on UP2000 board */ if (base == 0) { struct pci_dev *cy693_dev; - - cy693_dev = pci_get_device(PCI_VENDOR_ID_CONTAQ, + + cy693_dev = pci_get_device(PCI_VENDOR_ID_CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693, NULL); if (cy693_dev) { - char config; + unsigned char config; /* yeap, we've found cypress, let's check config */ if (!pci_read_config_byte(cy693_dev, 0x47, &config)) { - - pr_debug("i2c-elektor: found cy82c693, config register 0x47 = 0x%02x.\n", config); + + pr_debug("%s: found cy82c693, config " + "register 0x47 = 0x%02x\n", + pcf_isa_ops.name, config); /* UP2000 board has this register set to 0xe1, - but the most significant bit as seems can be + but the most significant bit as seems can be reset during the proper initialisation - sequence if guys from API decides to do that - (so, we can even enable Tsunami Pchip - window for the upper 1 Gb) */ + sequence if guys from API decides to do that + (so, we can even enable Tsunami Pchip + window for the upper 1 Gb) */ /* so just check for ROMCS at 0xe0000, - ROMCS enabled for writes + ROMCS enabled for writes and external XD Bus buffer in use. */ if ((config & 0x7f) == 0x61) { /* seems to be UP2000 like board */ base = 0xe0000; - /* I don't know why we need to - write twice */ - mmapped = 2; - /* UP2000 drives ISA with + mmapped = 1; + /* UP2000 drives ISA with 8.25 MHz (PCI/4) clock (this can be read from cypress) */ clock = I2C_PCF_CLK | I2C_PCF_TRNS90; - printk(KERN_INFO "i2c-elektor: found API UP2000 like board, will probe PCF8584 later.\n"); + pr_info("%s: found API UP2000 like " + "board, will probe PCF8584 " + "later\n", pcf_isa_ops.name); } } pci_dev_put(cy693_dev); @@ -236,12 +257,11 @@ static int __init i2c_pcfisa_init(void) /* sanity checks for mmapped I/O */ if (mmapped && base < 0xc8000) { - printk(KERN_ERR "i2c-elektor: incorrect base address (0x%0X) specified for mmapped I/O.\n", base); + printk(KERN_ERR "%s: incorrect base address (%#x) specified " + "for mmapped I/O\n", pcf_isa_ops.name, base); return -ENODEV; } - printk(KERN_INFO "i2c-elektor: i2c pcf8584-isa adapter driver\n"); - if (base == 0) { base = DEFAULT_BASE; } @@ -251,8 +271,8 @@ static int __init i2c_pcfisa_init(void) return -ENODEV; if (i2c_pcf_add_bus(&pcf_isa_ops) < 0) goto fail; - - printk(KERN_ERR "i2c-elektor: found device at %#x.\n", base); + + dev_info(&pcf_isa_ops.dev, "found device at %#x\n", base); return 0; @@ -262,8 +282,13 @@ static int __init i2c_pcfisa_init(void) free_irq(irq, NULL); } - if (!mmapped) - release_region(base , 2); + if (!mmapped) { + ioport_unmap(base_iomem); + release_region(base, 2); + } else { + iounmap(base_iomem); + release_mem_region(base, 2); + } return -ENODEV; } @@ -276,8 +301,13 @@ static void i2c_pcfisa_exit(void) free_irq(irq, NULL); } - if (!mmapped) - release_region(base , 2); + if (!mmapped) { + ioport_unmap(base_iomem); + release_region(base, 2); + } else { + iounmap(base_iomem); + release_mem_region(base, 2); + } } MODULE_AUTHOR("Hans Berglund <hb@spacetec.no>"); diff --git a/drivers/i2c/busses/i2c-hydra.c b/drivers/i2c/busses/i2c-hydra.c index e0cb3b0f92fa..1b5354e24bf5 100644 --- a/drivers/i2c/busses/i2c-hydra.c +++ b/drivers/i2c/busses/i2c-hydra.c @@ -155,6 +155,7 @@ static void __devexit hydra_remove(struct pci_dev *dev) static struct pci_driver hydra_driver = { + .owner = THIS_MODULE, .name = "hydra_smbus", .id_table = hydra_ids, .probe = hydra_probe, diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 709beab76609..4f63195069da 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -52,10 +52,6 @@ #include <linux/i2c.h> #include <asm/io.h> -#ifdef I2C_FUNC_SMBUS_BLOCK_DATA_PEC -#define HAVE_PEC -#endif - /* I801 SMBus address offsets */ #define SMBHSTSTS (0 + i801_smba) #define SMBHSTCNT (2 + i801_smba) @@ -106,10 +102,11 @@ MODULE_PARM_DESC(force_addr, "EXTREMELY DANGEROUS!"); static int i801_transaction(void); -static int i801_block_transaction(union i2c_smbus_data *data, - char read_write, int command); +static int i801_block_transaction(union i2c_smbus_data *data, char read_write, + int command, int hwpec); static unsigned short i801_smba; +static struct pci_driver i801_driver; static struct pci_dev *I801_dev; static int isich4; @@ -143,7 +140,7 @@ static int i801_setup(struct pci_dev *dev) } } - if (!request_region(i801_smba, (isich4 ? 16 : 8), "i801-smbus")) { + if (!request_region(i801_smba, (isich4 ? 16 : 8), i801_driver.name)) { dev_err(&dev->dev, "I801_smb region 0x%x already in use!\n", i801_smba); error_return = -EBUSY; @@ -252,7 +249,7 @@ static int i801_transaction(void) /* All-inclusive block transaction function */ static int i801_block_transaction(union i2c_smbus_data *data, char read_write, - int command) + int command, int hwpec) { int i, len; int smbcmd; @@ -391,8 +388,7 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write, goto END; } -#ifdef HAVE_PEC - if(isich4 && command == I2C_SMBUS_BLOCK_DATA_PEC) { + if (hwpec) { /* wait for INTR bit as advised by Intel */ timeout = 0; do { @@ -406,7 +402,6 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write, } outb_p(temp, SMBHSTSTS); } -#endif result = 0; END: if (command == I2C_SMBUS_I2C_BLOCK_DATA) { @@ -421,14 +416,13 @@ static s32 i801_access(struct i2c_adapter * adap, u16 addr, unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data * data) { - int hwpec = 0; + int hwpec; int block = 0; int ret, xact = 0; -#ifdef HAVE_PEC - if(isich4) - hwpec = (flags & I2C_CLIENT_PEC) != 0; -#endif + hwpec = isich4 && (flags & I2C_CLIENT_PEC) + && size != I2C_SMBUS_QUICK + && size != I2C_SMBUS_I2C_BLOCK_DATA; switch (size) { case I2C_SMBUS_QUICK: @@ -463,11 +457,6 @@ static s32 i801_access(struct i2c_adapter * adap, u16 addr, break; case I2C_SMBUS_BLOCK_DATA: case I2C_SMBUS_I2C_BLOCK_DATA: -#ifdef HAVE_PEC - case I2C_SMBUS_BLOCK_DATA_PEC: - if(hwpec && size == I2C_SMBUS_BLOCK_DATA) - size = I2C_SMBUS_BLOCK_DATA_PEC; -#endif outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD); outb_p(command, SMBHSTCMD); @@ -479,27 +468,18 @@ static s32 i801_access(struct i2c_adapter * adap, u16 addr, return -1; } -#ifdef HAVE_PEC - if(isich4 && hwpec) { - if(size != I2C_SMBUS_QUICK && - size != I2C_SMBUS_I2C_BLOCK_DATA) - outb_p(1, SMBAUXCTL); /* enable HW PEC */ - } -#endif + if (hwpec) + outb_p(1, SMBAUXCTL); /* enable hardware PEC */ + if(block) - ret = i801_block_transaction(data, read_write, size); + ret = i801_block_transaction(data, read_write, size, hwpec); else { outb_p(xact | ENABLE_INT9, SMBHSTCNT); ret = i801_transaction(); } -#ifdef HAVE_PEC - if(isich4 && hwpec) { - if(size != I2C_SMBUS_QUICK && - size != I2C_SMBUS_I2C_BLOCK_DATA) - outb_p(0, SMBAUXCTL); - } -#endif + if (hwpec) + outb_p(0, SMBAUXCTL); /* disable hardware PEC */ if(block) return ret; @@ -526,12 +506,7 @@ static u32 i801_func(struct i2c_adapter *adapter) return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK -#ifdef HAVE_PEC - | (isich4 ? I2C_FUNC_SMBUS_BLOCK_DATA_PEC | - I2C_FUNC_SMBUS_HWPEC_CALC - : 0) -#endif - ; + | (isich4 ? I2C_FUNC_SMBUS_HWPEC_CALC : 0); } static struct i2c_algorithm smbus_algorithm = { @@ -543,7 +518,6 @@ static struct i2c_adapter i801_adapter = { .owner = THIS_MODULE, .class = I2C_CLASS_HWMON, .algo = &smbus_algorithm, - .name = "unset", }; static struct pci_device_id i801_ids[] = { @@ -586,6 +560,7 @@ static void __devexit i801_remove(struct pci_dev *dev) } static struct pci_driver i801_driver = { + .owner = THIS_MODULE, .name = "i801_smbus", .id_table = i801_ids, .probe = i801_probe, diff --git a/drivers/i2c/busses/i2c-i810.c b/drivers/i2c/busses/i2c-i810.c index 0ff7016e0629..52bc30593bd7 100644 --- a/drivers/i2c/busses/i2c-i810.c +++ b/drivers/i2c/busses/i2c-i810.c @@ -32,6 +32,7 @@ i810AB 7123 i810E 7125 i815 1132 + i845G 2562 */ #include <linux/kernel.h> @@ -232,6 +233,7 @@ static void __devexit i810_remove(struct pci_dev *dev) } static struct pci_driver i810_driver = { + .owner = THIS_MODULE, .name = "i810_smbus", .id_table = i810_ids, .probe = i810_probe, diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c index a3ed9590f028..1a587253d716 100644 --- a/drivers/i2c/busses/i2c-ibm_iic.c +++ b/drivers/i2c/busses/i2c-ibm_iic.c @@ -672,13 +672,12 @@ static int __devinit iic_probe(struct ocp_device *ocp){ printk(KERN_WARNING"ibm-iic%d: missing additional data!\n", ocp->def->index); - if (!(dev = kmalloc(sizeof(*dev), GFP_KERNEL))){ + if (!(dev = kzalloc(sizeof(*dev), GFP_KERNEL))) { printk(KERN_CRIT "ibm-iic%d: failed to allocate device data\n", ocp->def->index); return -ENOMEM; } - memset(dev, 0, sizeof(*dev)); dev->idx = ocp->def->index; ocp_set_drvdata(ocp, dev); diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c index 7bd9102db701..9888fae1f37a 100644 --- a/drivers/i2c/busses/i2c-iop3xx.c +++ b/drivers/i2c/busses/i2c-iop3xx.c @@ -43,7 +43,7 @@ #include "i2c-iop3xx.h" /* global unit counter */ -static int i2c_id = 0; +static int i2c_id; static inline unsigned char iic_cook_addr(struct i2c_msg *msg) @@ -440,19 +440,17 @@ iop3xx_i2c_probe(struct device *dev) struct i2c_adapter *new_adapter; struct i2c_algo_iop3xx_data *adapter_data; - new_adapter = kmalloc(sizeof(struct i2c_adapter), GFP_KERNEL); + new_adapter = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL); if (!new_adapter) { ret = -ENOMEM; goto out; } - memset((void*)new_adapter, 0, sizeof(*new_adapter)); - adapter_data = kmalloc(sizeof(struct i2c_algo_iop3xx_data), GFP_KERNEL); + adapter_data = kzalloc(sizeof(struct i2c_algo_iop3xx_data), GFP_KERNEL); if (!adapter_data) { ret = -ENOMEM; goto free_adapter; } - memset((void*)adapter_data, 0, sizeof(*adapter_data)); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { @@ -525,6 +523,7 @@ out: static struct device_driver iop3xx_i2c_driver = { + .owner = THIS_MODULE, .name = "IOP3xx-I2C", .bus = &platform_bus_type, .probe = iop3xx_i2c_probe, diff --git a/drivers/i2c/busses/i2c-isa.c b/drivers/i2c/busses/i2c-isa.c index bdc6806dafae..4fdc02411609 100644 --- a/drivers/i2c/busses/i2c-isa.c +++ b/drivers/i2c/busses/i2c-isa.c @@ -92,6 +92,7 @@ int i2c_isa_add_driver(struct i2c_driver *driver) /* Add the driver to the list of i2c drivers in the driver core */ driver->driver.name = driver->name; + driver->driver.owner = driver->owner; driver->driver.bus = &i2c_bus_type; driver->driver.probe = i2c_isa_device_probe; driver->driver.remove = i2c_isa_device_remove; diff --git a/drivers/i2c/busses/i2c-ixp2000.c b/drivers/i2c/busses/i2c-ixp2000.c index 1956af382cd8..42016ee6ef13 100644 --- a/drivers/i2c/busses/i2c-ixp2000.c +++ b/drivers/i2c/busses/i2c-ixp2000.c @@ -36,6 +36,8 @@ #include <asm/hardware.h> /* Pick up IXP2000-specific bits */ #include <asm/arch/gpio.h> +static struct device_driver ixp2000_i2c_driver; + static inline int ixp2000_scl_pin(void *data) { return ((struct ixp2000_i2c_pins*)data)->scl_pin; @@ -104,11 +106,10 @@ static int ixp2000_i2c_probe(struct device *dev) struct platform_device *plat_dev = to_platform_device(dev); struct ixp2000_i2c_pins *gpio = plat_dev->dev.platform_data; struct ixp2000_i2c_data *drv_data = - kmalloc(sizeof(struct ixp2000_i2c_data), GFP_KERNEL); + kzalloc(sizeof(struct ixp2000_i2c_data), GFP_KERNEL); if (!drv_data) return -ENOMEM; - memzero(drv_data, sizeof(*drv_data)); drv_data->gpio_pins = gpio; drv_data->algo_data.data = gpio; @@ -121,6 +122,8 @@ static int ixp2000_i2c_probe(struct device *dev) drv_data->algo_data.timeout = 100; drv_data->adapter.id = I2C_HW_B_IXP2000, + strlcpy(drv_data->adapter.name, ixp2000_i2c_driver.name, + I2C_NAME_SIZE); drv_data->adapter.algo_data = &drv_data->algo_data, drv_data->adapter.dev.parent = &plat_dev->dev; @@ -142,6 +145,7 @@ static int ixp2000_i2c_probe(struct device *dev) } static struct device_driver ixp2000_i2c_driver = { + .owner = THIS_MODULE, .name = "IXP2000-I2C", .bus = &platform_bus_type, .probe = ixp2000_i2c_probe, diff --git a/drivers/i2c/busses/i2c-ixp4xx.c b/drivers/i2c/busses/i2c-ixp4xx.c index f6f5ca31fdba..69303ab65e04 100644 --- a/drivers/i2c/busses/i2c-ixp4xx.c +++ b/drivers/i2c/busses/i2c-ixp4xx.c @@ -35,6 +35,8 @@ #include <asm/hardware.h> /* Pick up IXP4xx-specific bits */ +static struct device_driver ixp4xx_i2c_driver; + static inline int ixp4xx_scl_pin(void *data) { return ((struct ixp4xx_i2c_pins*)data)->scl_pin; @@ -105,12 +107,11 @@ static int ixp4xx_i2c_probe(struct device *dev) struct platform_device *plat_dev = to_platform_device(dev); struct ixp4xx_i2c_pins *gpio = plat_dev->dev.platform_data; struct ixp4xx_i2c_data *drv_data = - kmalloc(sizeof(struct ixp4xx_i2c_data), GFP_KERNEL); + kzalloc(sizeof(struct ixp4xx_i2c_data), GFP_KERNEL); if(!drv_data) return -ENOMEM; - memzero(drv_data, sizeof(struct ixp4xx_i2c_data)); drv_data->gpio_pins = gpio; /* @@ -129,6 +130,8 @@ static int ixp4xx_i2c_probe(struct device *dev) drv_data->algo_data.timeout = 100; drv_data->adapter.id = I2C_HW_B_IXP4XX; + strlcpy(drv_data->adapter.name, ixp4xx_i2c_driver.name, + I2C_NAME_SIZE); drv_data->adapter.algo_data = &drv_data->algo_data; drv_data->adapter.dev.parent = &plat_dev->dev; @@ -151,6 +154,7 @@ static int ixp4xx_i2c_probe(struct device *dev) } static struct device_driver ixp4xx_i2c_driver = { + .owner = THIS_MODULE, .name = "IXP4XX-I2C", .bus = &platform_bus_type, .probe = ixp4xx_i2c_probe, diff --git a/drivers/i2c/busses/i2c-keywest.c b/drivers/i2c/busses/i2c-keywest.c index eff5896ce865..d61f748278fc 100644 --- a/drivers/i2c/busses/i2c-keywest.c +++ b/drivers/i2c/busses/i2c-keywest.c @@ -535,13 +535,12 @@ create_iface(struct device_node *np, struct device *dev) tsize = sizeof(struct keywest_iface) + (sizeof(struct keywest_chan) + 4) * nchan; - iface = (struct keywest_iface *) kmalloc(tsize, GFP_KERNEL); + iface = kzalloc(tsize, GFP_KERNEL); if (iface == NULL) { printk(KERN_ERR "i2c-keywest: can't allocate inteface !\n"); pmac_low_i2c_unlock(np); return -ENOMEM; } - memset(iface, 0, tsize); spin_lock_init(&iface->lock); init_completion(&iface->complete); iface->node = of_node_get(np); @@ -716,6 +715,7 @@ static struct of_device_id i2c_keywest_match[] = static struct macio_driver i2c_keywest_macio_driver = { + .owner = THIS_MODULE, .name = "i2c-keywest", .match_table = i2c_keywest_match, .probe = create_iface_macio, @@ -724,6 +724,7 @@ static struct macio_driver i2c_keywest_macio_driver = static struct of_platform_driver i2c_keywest_of_platform_driver = { + .owner = THIS_MODULE, .name = "i2c-keywest", .match_table = i2c_keywest_match, .probe = create_iface_of_platform, diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c index f065583ddcf1..8491633005b8 100644 --- a/drivers/i2c/busses/i2c-mpc.c +++ b/drivers/i2c/busses/i2c-mpc.c @@ -296,10 +296,9 @@ static int fsl_i2c_probe(struct device *device) pdata = (struct fsl_i2c_platform_data *) pdev->dev.platform_data; - if (!(i2c = kmalloc(sizeof(*i2c), GFP_KERNEL))) { + if (!(i2c = kzalloc(sizeof(*i2c), GFP_KERNEL))) { return -ENOMEM; } - memset(i2c, 0, sizeof(*i2c)); i2c->irq = platform_get_irq(pdev, 0); i2c->flags = pdata->device_flags; @@ -361,6 +360,7 @@ static int fsl_i2c_remove(struct device *device) /* Structure for a device driver */ static struct device_driver fsl_i2c_driver = { + .owner = THIS_MODULE, .name = "fsl-i2c", .bus = &platform_bus_type, .probe = fsl_i2c_probe, diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index 99abca45fece..d0d2a6f1386e 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -500,13 +500,10 @@ mv64xxx_i2c_probe(struct device *dev) if ((pd->id != 0) || !pdata) return -ENODEV; - drv_data = kmalloc(sizeof(struct mv64xxx_i2c_data), GFP_KERNEL); - + drv_data = kzalloc(sizeof(struct mv64xxx_i2c_data), GFP_KERNEL); if (!drv_data) return -ENOMEM; - memset(drv_data, 0, sizeof(struct mv64xxx_i2c_data)); - if (mv64xxx_i2c_map_regs(pd, drv_data)) { rc = -ENODEV; goto exit_kfree; @@ -570,6 +567,7 @@ mv64xxx_i2c_remove(struct device *dev) } static struct device_driver mv64xxx_i2c_driver = { + .owner = THIS_MODULE, .name = MV64XXX_I2C_CTLR_NAME, .bus = &platform_bus_type, .probe = mv64xxx_i2c_probe, diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c index fe9c0f42a2b7..fd26036e68a3 100644 --- a/drivers/i2c/busses/i2c-nforce2.c +++ b/drivers/i2c/busses/i2c-nforce2.c @@ -97,6 +97,7 @@ struct nforce2_smbus { #define NVIDIA_SMB_PRTCL_I2C_BLOCK_DATA 0x4a #define NVIDIA_SMB_PRTCL_PEC 0x80 +static struct pci_driver nforce2_driver; static s32 nforce2_access(struct i2c_adapter *adap, u16 addr, unsigned short flags, char read_write, @@ -113,7 +114,6 @@ static struct i2c_adapter nforce2_adapter = { .owner = THIS_MODULE, .class = I2C_CLASS_HWMON, .algo = &smbus_algorithm, - .name = "unset", }; /* Return -1 on error. See smbus.h for more information */ @@ -188,13 +188,6 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr, dev_err(&adap->dev, "I2C_SMBUS_BLOCK_PROC_CALL not supported!\n"); return -1; - case I2C_SMBUS_WORD_DATA_PEC: - case I2C_SMBUS_BLOCK_DATA_PEC: - case I2C_SMBUS_PROC_CALL_PEC: - case I2C_SMBUS_BLOCK_PROC_CALL_PEC: - dev_err(&adap->dev, "Unexpected software PEC transaction %d\n.", size); - return -1; - default: dev_err(&adap->dev, "Unsupported transaction %d\n", size); return -1; @@ -285,7 +278,7 @@ static int __devinit nforce2_probe_smb (struct pci_dev *dev, int reg, smbus->base = iobase & 0xfffc; smbus->size = 8; - if (!request_region(smbus->base, smbus->size, "nForce2 SMBus")) { + if (!request_region(smbus->base, smbus->size, nforce2_driver.name)) { dev_err(&smbus->adapter.dev, "Error requesting region %02x .. %02X for %s\n", smbus->base, smbus->base+smbus->size-1, name); return -1; @@ -313,10 +306,8 @@ static int __devinit nforce2_probe(struct pci_dev *dev, const struct pci_device_ int res1, res2; /* we support 2 SMBus adapters */ - if (!(smbuses = (void *)kmalloc(2*sizeof(struct nforce2_smbus), - GFP_KERNEL))) + if (!(smbuses = kzalloc(2*sizeof(struct nforce2_smbus), GFP_KERNEL))) return -ENOMEM; - memset (smbuses, 0, 2*sizeof(struct nforce2_smbus)); pci_set_drvdata(dev, smbuses); /* SMBus adapter 1 */ @@ -356,6 +347,7 @@ static void __devexit nforce2_remove(struct pci_dev *dev) } static struct pci_driver nforce2_driver = { + .owner = THIS_MODULE, .name = "nForce2_smbus", .id_table = nforce2_ids, .probe = nforce2_probe, diff --git a/drivers/i2c/busses/i2c-parport.c b/drivers/i2c/busses/i2c-parport.c index 71a2502fe069..2854d858fc9b 100644 --- a/drivers/i2c/busses/i2c-parport.c +++ b/drivers/i2c/busses/i2c-parport.c @@ -155,12 +155,11 @@ static void i2c_parport_attach (struct parport *port) { struct i2c_par *adapter; - adapter = kmalloc(sizeof(struct i2c_par), GFP_KERNEL); + adapter = kzalloc(sizeof(struct i2c_par), GFP_KERNEL); if (adapter == NULL) { - printk(KERN_ERR "i2c-parport: Failed to kmalloc\n"); + printk(KERN_ERR "i2c-parport: Failed to kzalloc\n"); return; } - memset(adapter, 0x00, sizeof(struct i2c_par)); pr_debug("i2c-parport: attaching to %s\n", port->name); adapter->pdev = parport_register_device(port, "i2c-parport", @@ -232,7 +231,7 @@ static void i2c_parport_detach (struct parport *port) } } -static struct parport_driver i2c_driver = { +static struct parport_driver i2c_parport_driver = { .name = "i2c-parport", .attach = i2c_parport_attach, .detach = i2c_parport_detach, @@ -250,12 +249,12 @@ static int __init i2c_parport_init(void) type = 0; } - return parport_register_driver(&i2c_driver); + return parport_register_driver(&i2c_parport_driver); } static void __exit i2c_parport_exit(void) { - parport_unregister_driver(&i2c_driver); + parport_unregister_driver(&i2c_parport_driver); } MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>"); diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c index 6d48a4da7bed..7d63eec423fe 100644 --- a/drivers/i2c/busses/i2c-piix4.c +++ b/drivers/i2c/busses/i2c-piix4.c @@ -90,13 +90,13 @@ struct sd { /* If force is set to anything different from 0, we forcibly enable the PIIX4. DANGEROUS! */ -static int force = 0; +static int force; module_param (force, int, 0); MODULE_PARM_DESC(force, "Forcibly enable the PIIX4. DANGEROUS!"); /* If force_addr is set to anything different from 0, we forcibly enable the PIIX4 at the given address. VERY DANGEROUS! */ -static int force_addr = 0; +static int force_addr; module_param (force_addr, int, 0); MODULE_PARM_DESC(force_addr, "Forcibly enable the PIIX4 at the given address. " @@ -104,14 +104,15 @@ MODULE_PARM_DESC(force_addr, /* If fix_hstcfg is set to anything different from 0, we reset one of the registers to be a valid value. */ -static int fix_hstcfg = 0; +static int fix_hstcfg; module_param (fix_hstcfg, int, 0); MODULE_PARM_DESC(fix_hstcfg, "Fix config register. Needed on some boards (Force CPCI735)."); static int piix4_transaction(void); -static unsigned short piix4_smba = 0; +static unsigned short piix4_smba; +static struct pci_driver piix4_driver; static struct i2c_adapter piix4_adapter; static struct dmi_system_id __devinitdata piix4_dmi_table[] = { @@ -157,7 +158,7 @@ static int __devinit piix4_setup(struct pci_dev *PIIX4_dev, } } - if (!request_region(piix4_smba, SMBIOSIZE, "piix4-smbus")) { + if (!request_region(piix4_smba, SMBIOSIZE, piix4_driver.name)) { dev_err(&PIIX4_dev->dev, "SMB region 0x%x already in use!\n", piix4_smba); return -ENODEV; @@ -407,7 +408,6 @@ static struct i2c_adapter piix4_adapter = { .owner = THIS_MODULE, .class = I2C_CLASS_HWMON, .algo = &smbus_algorithm, - .name = "unset", }; static struct pci_device_id piix4_ids[] = { @@ -462,6 +462,7 @@ static void __devexit piix4_remove(struct pci_dev *dev) } static struct pci_driver piix4_driver = { + .owner = THIS_MODULE, .name = "piix4_smbus", .id_table = piix4_ids, .probe = piix4_probe, diff --git a/drivers/i2c/busses/i2c-pmac-smu.c b/drivers/i2c/busses/i2c-pmac-smu.c index 8a9f5648a23d..bfefe7f7a53d 100644 --- a/drivers/i2c/busses/i2c-pmac-smu.c +++ b/drivers/i2c/busses/i2c-pmac-smu.c @@ -211,12 +211,11 @@ static int create_iface(struct device_node *np, struct device *dev) } busid = *reg; - iface = kmalloc(sizeof(struct smu_iface), GFP_KERNEL); + iface = kzalloc(sizeof(struct smu_iface), GFP_KERNEL); if (iface == NULL) { printk(KERN_ERR "i2c-pmac-smu: can't allocate inteface !\n"); return -ENOMEM; } - memset(iface, 0, sizeof(struct smu_iface)); init_completion(&iface->complete); iface->busid = busid; diff --git a/drivers/i2c/busses/i2c-prosavage.c b/drivers/i2c/busses/i2c-prosavage.c index 83fd16d61ce5..42cb1d8ca659 100644 --- a/drivers/i2c/busses/i2c-prosavage.c +++ b/drivers/i2c/busses/i2c-prosavage.c @@ -83,11 +83,6 @@ struct s_i2c_chip { /* * i2c configuration */ -#ifndef I2C_HW_B_S3VIA -#define I2C_HW_B_S3VIA 0x18 /* S3VIA ProSavage adapter */ -#endif - -/* delays */ #define CYCLE_DELAY 10 #define TIMEOUT (HZ / 2) @@ -241,14 +236,12 @@ static int __devinit prosavage_probe(struct pci_dev *dev, const struct pci_devic struct s_i2c_chip *chip; struct s_i2c_bus *bus; - pci_set_drvdata(dev, kmalloc(sizeof(struct s_i2c_chip), GFP_KERNEL)); + pci_set_drvdata(dev, kzalloc(sizeof(struct s_i2c_chip), GFP_KERNEL)); chip = (struct s_i2c_chip *)pci_get_drvdata(dev); if (chip == NULL) { return -ENOMEM; } - memset(chip, 0, sizeof(struct s_i2c_chip)); - base = dev->resource[0].start & PCI_BASE_ADDRESS_MEM_MASK; len = dev->resource[0].end - base + 1; chip->mmio = ioremap_nocache(base, len); @@ -308,6 +301,7 @@ static struct pci_device_id prosavage_pci_tbl[] = { MODULE_DEVICE_TABLE (pci, prosavage_pci_tbl); static struct pci_driver prosavage_driver = { + .owner = THIS_MODULE, .name = "prosavage_smbus", .id_table = prosavage_pci_tbl, .probe = prosavage_probe, diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 73a092fb0e7e..6ced28e90070 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -879,14 +879,12 @@ static int s3c24xx_i2c_remove(struct device *dev) } #ifdef CONFIG_PM -static int s3c24xx_i2c_resume(struct device *dev, u32 level) +static int s3c24xx_i2c_resume(struct device *dev) { struct s3c24xx_i2c *i2c = dev_get_drvdata(dev); - - if (i2c != NULL && level == RESUME_ENABLE) { - dev_dbg(dev, "resume: level %d\n", level); + + if (i2c != NULL) s3c24xx_i2c_init(i2c); - } return 0; } @@ -898,6 +896,7 @@ static int s3c24xx_i2c_resume(struct device *dev, u32 level) /* device driver for platform bus bits */ static struct device_driver s3c2410_i2c_driver = { + .owner = THIS_MODULE, .name = "s3c2410-i2c", .bus = &platform_bus_type, .probe = s3c24xx_i2c_probe, @@ -906,6 +905,7 @@ static struct device_driver s3c2410_i2c_driver = { }; static struct device_driver s3c2440_i2c_driver = { + .owner = THIS_MODULE, .name = "s3c2440-i2c", .bus = &platform_bus_type, .probe = s3c24xx_i2c_probe, diff --git a/drivers/i2c/busses/i2c-savage4.c b/drivers/i2c/busses/i2c-savage4.c index 0c8518298e4d..aebe87ba4033 100644 --- a/drivers/i2c/busses/i2c-savage4.c +++ b/drivers/i2c/busses/i2c-savage4.c @@ -179,6 +179,7 @@ static void __devexit savage4_remove(struct pci_dev *dev) } static struct pci_driver savage4_driver = { + .owner = THIS_MODULE, .name = "savage4_smbus", .id_table = savage4_ids, .probe = savage4_probe, diff --git a/drivers/i2c/busses/i2c-sis5595.c b/drivers/i2c/busses/i2c-sis5595.c index 080318d6f54b..3ad27c3ba15b 100644 --- a/drivers/i2c/busses/i2c-sis5595.c +++ b/drivers/i2c/busses/i2c-sis5595.c @@ -123,11 +123,12 @@ static int blacklist[] = { /* If force_addr is set to anything different from 0, we forcibly enable the device at the given address. */ -static u16 force_addr = 0; +static u16 force_addr; module_param(force_addr, ushort, 0); MODULE_PARM_DESC(force_addr, "Initialize the base address of the i2c controller"); -static unsigned short sis5595_base = 0; +static struct pci_driver sis5595_driver; +static unsigned short sis5595_base; static u8 sis5595_read(u8 reg) { @@ -172,7 +173,8 @@ static int sis5595_setup(struct pci_dev *SIS5595_dev) /* NB: We grab just the two SMBus registers here, but this may still * interfere with ACPI :-( */ - if (!request_region(sis5595_base + SMB_INDEX, 2, "sis5595-smbus")) { + if (!request_region(sis5595_base + SMB_INDEX, 2, + sis5595_driver.name)) { dev_err(&SIS5595_dev->dev, "SMBus registers 0x%04x-0x%04x already in use!\n", sis5595_base + SMB_INDEX, sis5595_base + SMB_INDEX + 1); return -ENODEV; @@ -364,7 +366,6 @@ static struct i2c_algorithm smbus_algorithm = { static struct i2c_adapter sis5595_adapter = { .owner = THIS_MODULE, .class = I2C_CLASS_HWMON, - .name = "unset", .algo = &smbus_algorithm, }; @@ -397,6 +398,7 @@ static void __devexit sis5595_remove(struct pci_dev *dev) } static struct pci_driver sis5595_driver = { + .owner = THIS_MODULE, .name = "sis5595_smbus", .id_table = sis5595_ids, .probe = sis5595_probe, diff --git a/drivers/i2c/busses/i2c-sis630.c b/drivers/i2c/busses/i2c-sis630.c index 86f0f448fa0b..7f49e5fd3ff0 100644 --- a/drivers/i2c/busses/i2c-sis630.c +++ b/drivers/i2c/busses/i2c-sis630.c @@ -92,6 +92,8 @@ #define SIS630_PCALL 0x04 #define SIS630_BLOCK_DATA 0x05 +static struct pci_driver sis630_driver; + /* insmod parameters */ static int high_clock; static int force; @@ -101,7 +103,7 @@ module_param(force, bool, 0); MODULE_PARM_DESC(force, "Forcibly enable the SIS630. DANGEROUS!"); /* acpi base address */ -static unsigned short acpi_base = 0; +static unsigned short acpi_base; /* supported chips */ static int supported[] = { @@ -432,7 +434,8 @@ static int sis630_setup(struct pci_dev *sis630_dev) dev_dbg(&sis630_dev->dev, "ACPI base at 0x%04x\n", acpi_base); /* Everything is happy, let's grab the memory and set things up. */ - if (!request_region(acpi_base + SMB_STS, SIS630_SMB_IOREGION, "sis630-smbus")) { + if (!request_region(acpi_base + SMB_STS, SIS630_SMB_IOREGION, + sis630_driver.name)) { dev_err(&sis630_dev->dev, "SMBus registers 0x%04x-0x%04x already " "in use!\n", acpi_base + SMB_STS, acpi_base + SMB_SAA); goto exit; @@ -455,7 +458,6 @@ static struct i2c_algorithm smbus_algorithm = { static struct i2c_adapter sis630_adapter = { .owner = THIS_MODULE, .class = I2C_CLASS_HWMON, - .name = "unset", .algo = &smbus_algorithm, }; @@ -494,6 +496,7 @@ static void __devexit sis630_remove(struct pci_dev *dev) static struct pci_driver sis630_driver = { + .owner = THIS_MODULE, .name = "sis630_smbus", .id_table = sis630_ids, .probe = sis630_probe, diff --git a/drivers/i2c/busses/i2c-sis96x.c b/drivers/i2c/busses/i2c-sis96x.c index ead2ff3cf60e..6a134c091324 100644 --- a/drivers/i2c/busses/i2c-sis96x.c +++ b/drivers/i2c/busses/i2c-sis96x.c @@ -82,8 +82,9 @@ #define SIS96x_PROC_CALL 0x04 #define SIS96x_BLOCK_DATA 0x05 +static struct pci_driver sis96x_driver; static struct i2c_adapter sis96x_adapter; -static u16 sis96x_smbus_base = 0; +static u16 sis96x_smbus_base; static inline u8 sis96x_read(u8 reg) { @@ -257,7 +258,6 @@ static struct i2c_adapter sis96x_adapter = { .owner = THIS_MODULE, .class = I2C_CLASS_HWMON, .algo = &smbus_algorithm, - .name = "unset", }; static struct pci_device_id sis96x_ids[] = { @@ -294,7 +294,8 @@ static int __devinit sis96x_probe(struct pci_dev *dev, sis96x_smbus_base); /* Everything is happy, let's grab the memory and set things up. */ - if (!request_region(sis96x_smbus_base, SMB_IOSIZE, "sis96x-smbus")) { + if (!request_region(sis96x_smbus_base, SMB_IOSIZE, + sis96x_driver.name)) { dev_err(&dev->dev, "SMBus registers 0x%04x-0x%04x " "already in use!\n", sis96x_smbus_base, sis96x_smbus_base + SMB_IOSIZE - 1); @@ -328,6 +329,7 @@ static void __devexit sis96x_remove(struct pci_dev *dev) } static struct pci_driver sis96x_driver = { + .owner = THIS_MODULE, .name = "sis96x_smbus", .id_table = sis96x_ids, .probe = sis96x_probe, diff --git a/drivers/i2c/busses/i2c-via.c b/drivers/i2c/busses/i2c-via.c index 040b8abeabba..544a38e64394 100644 --- a/drivers/i2c/busses/i2c-via.c +++ b/drivers/i2c/busses/i2c-via.c @@ -43,9 +43,9 @@ /* io-region reservation */ #define IOSPACE 0x06 -#define IOTEXT "via-i2c" -static u16 pm_io_base = 0; +static struct pci_driver vt586b_driver; +static u16 pm_io_base; /* It does not appear from the datasheet that the GPIO pins are @@ -130,7 +130,7 @@ static int __devinit vt586b_probe(struct pci_dev *dev, const struct pci_device_i pci_read_config_word(dev, base, &pm_io_base); pm_io_base &= (0xff << 8); - if (!request_region(I2C_DIR, IOSPACE, IOTEXT)) { + if (!request_region(I2C_DIR, IOSPACE, vt586b_driver.name)) { dev_err(&dev->dev, "IO 0x%x-0x%x already in use\n", I2C_DIR, I2C_DIR + IOSPACE); return -ENODEV; } @@ -159,6 +159,7 @@ static void __devexit vt586b_remove(struct pci_dev *dev) static struct pci_driver vt586b_driver = { + .owner = THIS_MODULE, .name = "vt586b_smbus", .id_table = vt586b_ids, .probe = vt586b_probe, diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c index 99d209e0485a..c9366b504833 100644 --- a/drivers/i2c/busses/i2c-viapro.c +++ b/drivers/i2c/busses/i2c-viapro.c @@ -1,9 +1,10 @@ /* i2c-viapro.c - Part of lm_sensors, Linux kernel modules for hardware monitoring - Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl>, + Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl>, Philip Edelbrock <phil@netroedge.com>, Kysti Mlkki <kmalkki@cc.hut.fi>, Mark D. Studebaker <mdsxyz123@yahoo.com> + Copyright (C) 2005 Jean Delvare <khali@linux-fr.org> 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 @@ -21,15 +22,19 @@ */ /* - Supports Via devices: - 82C596A/B (0x3050) - 82C596B (0x3051) - 82C686A/B - 8231 - 8233 - 8233A (0x3147 and 0x3177) - 8235 - 8237 + Supports the following VIA south bridges: + + Chip name PCI ID REV I2C block + VT82C596A 0x3050 no + VT82C596B 0x3051 no + VT82C686A 0x3057 0x30 no + VT82C686B 0x3057 0x40 yes + VT8231 0x8235 no? + VT8233 0x3074 yes + VT8233A 0x3147 yes? + VT8235 0x3177 yes + VT8237R 0x3227 yes + Note: we assume there can only be one device, with one SMBus interface. */ @@ -38,7 +43,6 @@ #include <linux/pci.h> #include <linux/kernel.h> #include <linux/stddef.h> -#include <linux/sched.h> #include <linux/ioport.h> #include <linux/i2c.h> #include <linux/init.h> @@ -46,48 +50,37 @@ static struct pci_dev *vt596_pdev; -#define SMBBA1 0x90 -#define SMBBA2 0x80 -#define SMBBA3 0xD0 +#define SMBBA1 0x90 +#define SMBBA2 0x80 +#define SMBBA3 0xD0 /* SMBus address offsets */ static unsigned short vt596_smba; #define SMBHSTSTS (vt596_smba + 0) -#define SMBHSLVSTS (vt596_smba + 1) #define SMBHSTCNT (vt596_smba + 2) #define SMBHSTCMD (vt596_smba + 3) #define SMBHSTADD (vt596_smba + 4) #define SMBHSTDAT0 (vt596_smba + 5) #define SMBHSTDAT1 (vt596_smba + 6) #define SMBBLKDAT (vt596_smba + 7) -#define SMBSLVCNT (vt596_smba + 8) -#define SMBSHDWCMD (vt596_smba + 9) -#define SMBSLVEVT (vt596_smba + 0xA) -#define SMBSLVDAT (vt596_smba + 0xC) /* PCI Address Constants */ /* SMBus data in configuration space can be found in two places, - We try to select the better one*/ - -static unsigned short smb_cf_hstcfg = 0xD2; + We try to select the better one */ -#define SMBHSTCFG (smb_cf_hstcfg) -#define SMBSLVC (smb_cf_hstcfg + 1) -#define SMBSHDW1 (smb_cf_hstcfg + 2) -#define SMBSHDW2 (smb_cf_hstcfg + 3) -#define SMBREV (smb_cf_hstcfg + 4) +static unsigned short SMBHSTCFG = 0xD2; /* Other settings */ #define MAX_TIMEOUT 500 -#define ENABLE_INT9 0 /* VT82C596 constants */ -#define VT596_QUICK 0x00 -#define VT596_BYTE 0x04 -#define VT596_BYTE_DATA 0x08 -#define VT596_WORD_DATA 0x0C -#define VT596_BLOCK_DATA 0x14 +#define VT596_QUICK 0x00 +#define VT596_BYTE 0x04 +#define VT596_BYTE_DATA 0x08 +#define VT596_WORD_DATA 0x0C +#define VT596_BLOCK_DATA 0x14 +#define VT596_I2C_BLOCK_DATA 0x34 /* If force is set to anything different from 0, we forcibly enable the @@ -105,40 +98,65 @@ MODULE_PARM_DESC(force_addr, "EXTREMELY DANGEROUS!"); +static struct pci_driver vt596_driver; static struct i2c_adapter vt596_adapter; -/* Another internally used function */ -static int vt596_transaction(void) +#define FEATURE_I2CBLOCK (1<<0) +static unsigned int vt596_features; + +#ifdef DEBUG +static void vt596_dump_regs(const char *msg, u8 size) +{ + dev_dbg(&vt596_adapter.dev, "%s: STS=%02x CNT=%02x CMD=%02x ADD=%02x " + "DAT=%02x,%02x\n", msg, inb_p(SMBHSTSTS), inb_p(SMBHSTCNT), + inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), + inb_p(SMBHSTDAT1)); + + if (size == VT596_BLOCK_DATA + || size == VT596_I2C_BLOCK_DATA) { + int i; + + dev_dbg(&vt596_adapter.dev, "BLK="); + for (i = 0; i < I2C_SMBUS_BLOCK_MAX / 2; i++) + printk("%02x,", inb_p(SMBBLKDAT)); + printk("\n"); + dev_dbg(&vt596_adapter.dev, " "); + for (; i < I2C_SMBUS_BLOCK_MAX - 1; i++) + printk("%02x,", inb_p(SMBBLKDAT)); + printk("%02x\n", inb_p(SMBBLKDAT)); + } +} +#else +static inline void vt596_dump_regs(const char *msg, u8 size) { } +#endif + +/* Return -1 on error, 0 on success */ +static int vt596_transaction(u8 size) { int temp; int result = 0; int timeout = 0; - dev_dbg(&vt596_adapter.dev, "Transaction (pre): CNT=%02x, CMD=%02x, " - "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT), - inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), - inb_p(SMBHSTDAT1)); + vt596_dump_regs("Transaction (pre)", size); /* Make sure the SMBus host is ready to start transmitting */ if ((temp = inb_p(SMBHSTSTS)) & 0x1F) { dev_dbg(&vt596_adapter.dev, "SMBus busy (0x%02x). " - "Resetting...\n", temp); - + "Resetting... ", temp); + outb_p(temp, SMBHSTSTS); if ((temp = inb_p(SMBHSTSTS)) & 0x1F) { - dev_dbg(&vt596_adapter.dev, "Failed! (0x%02x)\n", temp); - + printk("Failed! (0x%02x)\n", temp); return -1; } else { - dev_dbg(&vt596_adapter.dev, "Successfull!\n"); + printk("Successful!\n"); } } - /* start the transaction by setting bit 6 */ - outb_p(inb(SMBHSTCNT) | 0x040, SMBHSTCNT); + /* Start the transaction by setting bit 6 */ + outb_p(0x40 | (size & 0x3C), SMBHSTCNT); - /* We will always wait for a fraction of a second! - I don't know if VIA needs this, Intel did */ + /* We will always wait for a fraction of a second */ do { msleep(1); temp = inb_p(SMBHSTSTS); @@ -147,77 +165,61 @@ static int vt596_transaction(void) /* If the SMBus is still busy, we give up */ if (timeout >= MAX_TIMEOUT) { result = -1; - dev_dbg(&vt596_adapter.dev, "SMBus Timeout!\n"); + dev_err(&vt596_adapter.dev, "SMBus timeout!\n"); } if (temp & 0x10) { result = -1; - dev_dbg(&vt596_adapter.dev, "Error: Failed bus transaction\n"); + dev_err(&vt596_adapter.dev, "Transaction failed (0x%02x)\n", + inb_p(SMBHSTCNT) & 0x3C); } if (temp & 0x08) { result = -1; - dev_info(&vt596_adapter.dev, "Bus collision! SMBus may be " - "locked until next hard\nreset. (sorry!)\n"); - /* Clock stops and slave is stuck in mid-transmission */ + dev_err(&vt596_adapter.dev, "SMBus collision!\n"); } if (temp & 0x04) { result = -1; - dev_dbg(&vt596_adapter.dev, "Error: no response!\n"); + /* Quick commands are used to probe for chips, so + errors are expected, and we don't want to frighten the + user. */ + if ((inb_p(SMBHSTCNT) & 0x3C) != VT596_QUICK) + dev_err(&vt596_adapter.dev, "Transaction error!\n"); } - if ((temp = inb_p(SMBHSTSTS)) & 0x1F) { + /* Resetting status register */ + if (temp & 0x1F) outb_p(temp, SMBHSTSTS); - if ((temp = inb_p(SMBHSTSTS)) & 0x1F) { - dev_warn(&vt596_adapter.dev, "Failed reset at end " - "of transaction (%02x)\n", temp); - } - } - dev_dbg(&vt596_adapter.dev, "Transaction (post): CNT=%02x, CMD=%02x, " - "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT), - inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), - inb_p(SMBHSTDAT1)); - + vt596_dump_regs("Transaction (post)", size); + return result; } -/* Return -1 on error. */ +/* Return -1 on error, 0 on success */ static s32 vt596_access(struct i2c_adapter *adap, u16 addr, - unsigned short flags, char read_write, u8 command, - int size, union i2c_smbus_data *data) + unsigned short flags, char read_write, u8 command, + int size, union i2c_smbus_data *data) { - int i, len; + int i; switch (size) { - case I2C_SMBUS_PROC_CALL: - dev_info(&vt596_adapter.dev, - "I2C_SMBUS_PROC_CALL not supported!\n"); - return -1; case I2C_SMBUS_QUICK: - outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), - SMBHSTADD); size = VT596_QUICK; break; case I2C_SMBUS_BYTE: - outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), - SMBHSTADD); if (read_write == I2C_SMBUS_WRITE) outb_p(command, SMBHSTCMD); size = VT596_BYTE; break; case I2C_SMBUS_BYTE_DATA: - outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), - SMBHSTADD); outb_p(command, SMBHSTCMD); if (read_write == I2C_SMBUS_WRITE) outb_p(data->byte, SMBHSTDAT0); size = VT596_BYTE_DATA; break; case I2C_SMBUS_WORD_DATA: - outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), - SMBHSTADD); outb_p(command, SMBHSTCMD); if (read_write == I2C_SMBUS_WRITE) { outb_p(data->word & 0xff, SMBHSTDAT0); @@ -225,28 +227,33 @@ static s32 vt596_access(struct i2c_adapter *adap, u16 addr, } size = VT596_WORD_DATA; break; + case I2C_SMBUS_I2C_BLOCK_DATA: + if (!(vt596_features & FEATURE_I2CBLOCK)) + goto exit_unsupported; + if (read_write == I2C_SMBUS_READ) + outb_p(I2C_SMBUS_BLOCK_MAX, SMBHSTDAT0); + /* Fall through */ case I2C_SMBUS_BLOCK_DATA: - outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), - SMBHSTADD); outb_p(command, SMBHSTCMD); if (read_write == I2C_SMBUS_WRITE) { - len = data->block[0]; - if (len < 0) - len = 0; + u8 len = data->block[0]; if (len > I2C_SMBUS_BLOCK_MAX) len = I2C_SMBUS_BLOCK_MAX; outb_p(len, SMBHSTDAT0); - i = inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */ + inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */ for (i = 1; i <= len; i++) outb_p(data->block[i], SMBBLKDAT); } - size = VT596_BLOCK_DATA; + size = (size == I2C_SMBUS_I2C_BLOCK_DATA) ? + VT596_I2C_BLOCK_DATA : VT596_BLOCK_DATA; break; + default: + goto exit_unsupported; } - outb_p((size & 0x1C) + (ENABLE_INT9 & 1), SMBHSTCNT); + outb_p(((addr & 0x7f) << 1) | read_write, SMBHSTADD); - if (vt596_transaction()) /* Error in transaction */ + if (vt596_transaction(size)) /* Error in transaction */ return -1; if ((read_write == I2C_SMBUS_WRITE) || (size == VT596_QUICK)) @@ -254,35 +261,39 @@ static s32 vt596_access(struct i2c_adapter *adap, u16 addr, switch (size) { case VT596_BYTE: - /* Where is the result put? I assume here it is in - * SMBHSTDAT0 but it might just as well be in the - * SMBHSTCMD. No clue in the docs - */ - data->byte = inb_p(SMBHSTDAT0); - break; case VT596_BYTE_DATA: data->byte = inb_p(SMBHSTDAT0); break; case VT596_WORD_DATA: data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8); break; + case VT596_I2C_BLOCK_DATA: case VT596_BLOCK_DATA: data->block[0] = inb_p(SMBHSTDAT0); if (data->block[0] > I2C_SMBUS_BLOCK_MAX) data->block[0] = I2C_SMBUS_BLOCK_MAX; - i = inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */ + inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */ for (i = 1; i <= data->block[0]; i++) data->block[i] = inb_p(SMBBLKDAT); break; } return 0; + +exit_unsupported: + dev_warn(&vt596_adapter.dev, "Unsupported command invoked! (0x%02x)\n", + size); + return -1; } static u32 vt596_func(struct i2c_adapter *adapter) { - return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | + u32 func = I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA; + + if (vt596_features & FEATURE_I2CBLOCK) + func |= I2C_FUNC_SMBUS_I2C_BLOCK; + return func; } static struct i2c_algorithm smbus_algorithm = { @@ -294,7 +305,6 @@ static struct i2c_adapter vt596_adapter = { .owner = THIS_MODULE, .class = I2C_CLASS_HWMON, .algo = &smbus_algorithm, - .name = "unset", }; static int __devinit vt596_probe(struct pci_dev *pdev, @@ -302,7 +312,7 @@ static int __devinit vt596_probe(struct pci_dev *pdev, { unsigned char temp; int error = -ENODEV; - + /* Determine the address of the SMBus areas */ if (force_addr) { vt596_smba = force_addr & 0xfff0; @@ -311,12 +321,12 @@ static int __devinit vt596_probe(struct pci_dev *pdev, } if ((pci_read_config_word(pdev, id->driver_data, &vt596_smba)) || - !(vt596_smba & 0x1)) { + !(vt596_smba & 0x0001)) { /* try 2nd address and config reg. for 596 */ if (id->device == PCI_DEVICE_ID_VIA_82C596_3 && !pci_read_config_word(pdev, SMBBA2, &vt596_smba) && - (vt596_smba & 0x1)) { - smb_cf_hstcfg = 0x84; + (vt596_smba & 0x0001)) { + SMBHSTCFG = 0x84; } else { /* no matches at all */ dev_err(&pdev->dev, "Cannot configure " @@ -333,10 +343,10 @@ static int __devinit vt596_probe(struct pci_dev *pdev, return -ENODEV; } - found: - if (!request_region(vt596_smba, 8, "viapro-smbus")) { +found: + if (!request_region(vt596_smba, 8, vt596_driver.name)) { dev_err(&pdev->dev, "SMBus region 0x%x already in use!\n", - vt596_smba); + vt596_smba); return -ENODEV; } @@ -348,16 +358,16 @@ static int __devinit vt596_probe(struct pci_dev *pdev, pci_write_config_word(pdev, id->driver_data, vt596_smba); pci_write_config_byte(pdev, SMBHSTCFG, temp | 0x01); dev_warn(&pdev->dev, "WARNING: SMBus interface set to new " - "address 0x%04x!\n", vt596_smba); - } else if ((temp & 1) == 0) { + "address 0x%04x!\n", vt596_smba); + } else if (!(temp & 0x01)) { if (force) { - /* NOTE: This assumes I/O space and other allocations - * WERE done by the Bios! Don't complain if your - * hardware does weird things after enabling this. - * :') Check for Bios updates before resorting to + /* NOTE: This assumes I/O space and other allocations + * WERE done by the Bios! Don't complain if your + * hardware does weird things after enabling this. + * :') Check for Bios updates before resorting to * this. */ - pci_write_config_byte(pdev, SMBHSTCFG, temp | 1); + pci_write_config_byte(pdev, SMBHSTCFG, temp | 0x01); dev_info(&pdev->dev, "Enabling SMBus device\n"); } else { dev_err(&pdev->dev, "SMBUS: Error: Host SMBus " @@ -367,22 +377,28 @@ static int __devinit vt596_probe(struct pci_dev *pdev, } } - if ((temp & 0x0E) == 8) - dev_dbg(&pdev->dev, "using Interrupt 9 for SMBus.\n"); - else if ((temp & 0x0E) == 0) - dev_dbg(&pdev->dev, "using Interrupt SMI# for SMBus.\n"); - else - dev_dbg(&pdev->dev, "Illegal Interrupt configuration " - "(or code out of date)!\n"); - - pci_read_config_byte(pdev, SMBREV, &temp); - dev_dbg(&pdev->dev, "SMBREV = 0x%X\n", temp); dev_dbg(&pdev->dev, "VT596_smba = 0x%X\n", vt596_smba); + switch (pdev->device) { + case PCI_DEVICE_ID_VIA_8237: + case PCI_DEVICE_ID_VIA_8235: + case PCI_DEVICE_ID_VIA_8233A: + case PCI_DEVICE_ID_VIA_8233_0: + vt596_features |= FEATURE_I2CBLOCK; + break; + case PCI_DEVICE_ID_VIA_82C686_4: + /* The VT82C686B (rev 0x40) does support I2C block + transactions, but the VT82C686A (rev 0x30) doesn't */ + if (!pci_read_config_byte(pdev, PCI_REVISION_ID, &temp) + && temp >= 0x40) + vt596_features |= FEATURE_I2CBLOCK; + break; + } + vt596_adapter.dev.parent = &pdev->dev; snprintf(vt596_adapter.name, I2C_NAME_SIZE, - "SMBus Via Pro adapter at %04x", vt596_smba); - + "SMBus Via Pro adapter at %04x", vt596_smba); + vt596_pdev = pci_dev_get(pdev); if (i2c_add_adapter(&vt596_adapter)) { pci_dev_put(vt596_pdev); @@ -395,7 +411,7 @@ static int __devinit vt596_probe(struct pci_dev *pdev, */ return -ENODEV; - release_region: +release_region: release_region(vt596_smba, 8); return error; } @@ -420,9 +436,10 @@ static struct pci_device_id vt596_ids[] = { { 0, } }; -MODULE_DEVICE_TABLE (pci, vt596_ids); +MODULE_DEVICE_TABLE(pci, vt596_ids); static struct pci_driver vt596_driver = { + .owner = THIS_MODULE, .name = "vt596_smbus", .id_table = vt596_ids, .probe = vt596_probe, diff --git a/drivers/i2c/busses/i2c-voodoo3.c b/drivers/i2c/busses/i2c-voodoo3.c index b675773b0cc1..650c3ebde84c 100644 --- a/drivers/i2c/busses/i2c-voodoo3.c +++ b/drivers/i2c/busses/i2c-voodoo3.c @@ -225,6 +225,7 @@ static void __devexit voodoo3_remove(struct pci_dev *dev) } static struct pci_driver voodoo3_driver = { + .owner = THIS_MODULE, .name = "voodoo3_smbus", .id_table = voodoo3_ids, .probe = voodoo3_probe, diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c index a1d580e05361..d3478e084522 100644 --- a/drivers/i2c/busses/scx200_acb.c +++ b/drivers/i2c/busses/scx200_acb.c @@ -442,14 +442,13 @@ static int __init scx200_acb_create(int base, int index) int rc = 0; char description[64]; - iface = kmalloc(sizeof(*iface), GFP_KERNEL); + iface = kzalloc(sizeof(*iface), GFP_KERNEL); if (!iface) { printk(KERN_ERR NAME ": can't allocate memory\n"); rc = -ENOMEM; goto errout; } - memset(iface, 0, sizeof(*iface)); adapter = &iface->adapter; i2c_set_adapdata(adapter, iface); snprintf(adapter->name, I2C_NAME_SIZE, "SCx200 ACB%d", index); diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig index 6bd44a44cd28..f9fae28f5612 100644 --- a/drivers/i2c/chips/Kconfig +++ b/drivers/i2c/chips/Kconfig @@ -126,4 +126,13 @@ config SENSORS_MAX6875 This driver can also be built as a module. If so, the module will be called max6875. +config RTC_X1205_I2C + tristate "Xicor X1205 RTC chip" + depends on I2C && EXPERIMENTAL + help + If you say yes here you get support for the Xicor X1205 RTC chip. + + This driver can also be built as a module. If so, the module + will be called x1205. + endmenu diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile index a876dd42b860..46178b57b1f1 100644 --- a/drivers/i2c/chips/Makefile +++ b/drivers/i2c/chips/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o obj-$(CONFIG_SENSORS_RTC8564) += rtc8564.o obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o obj-$(CONFIG_TPS65010) += tps65010.o +obj-$(CONFIG_RTC_X1205_I2C) += x1205.o ifeq ($(CONFIG_I2C_DEBUG_CHIP),y) EXTRA_CFLAGS += -DDEBUG diff --git a/drivers/i2c/chips/ds1337.c b/drivers/i2c/chips/ds1337.c index 9d3175c03395..01b037007410 100644 --- a/drivers/i2c/chips/ds1337.c +++ b/drivers/i2c/chips/ds1337.c @@ -243,11 +243,10 @@ static int ds1337_detect(struct i2c_adapter *adapter, int address, int kind) I2C_FUNC_I2C)) goto exit; - if (!(data = kmalloc(sizeof(struct ds1337_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct ds1337_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - memset(data, 0, sizeof(struct ds1337_data)); INIT_LIST_HEAD(&data->list); /* The common I2C client data is placed right before the diff --git a/drivers/i2c/chips/ds1374.c b/drivers/i2c/chips/ds1374.c index 0936327a946d..da488b735abf 100644 --- a/drivers/i2c/chips/ds1374.c +++ b/drivers/i2c/chips/ds1374.c @@ -167,7 +167,8 @@ static void ds1374_set_tlet(ulong arg) static ulong new_time; -DECLARE_TASKLET_DISABLED(ds1374_tasklet, ds1374_set_tlet, (ulong) & new_time); +static DECLARE_TASKLET_DISABLED(ds1374_tasklet, ds1374_set_tlet, + (ulong) & new_time); int ds1374_set_rtc_time(ulong nowtime) { @@ -193,13 +194,11 @@ static int ds1374_probe(struct i2c_adapter *adap, int addr, int kind) struct i2c_client *client; int rc; - client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); + client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); if (!client) return -ENOMEM; - memset(client, 0, sizeof(struct i2c_client)); strncpy(client->name, DS1374_DRV_NAME, I2C_NAME_SIZE); - client->flags = I2C_DF_NOTIFY; client->addr = addr; client->adapter = adap; client->driver = &ds1374_driver; diff --git a/drivers/i2c/chips/eeprom.c b/drivers/i2c/chips/eeprom.c index d58403a47908..4baf573fa04f 100644 --- a/drivers/i2c/chips/eeprom.c +++ b/drivers/i2c/chips/eeprom.c @@ -88,8 +88,8 @@ static void eeprom_update_client(struct i2c_client *client, u8 slice) dev_dbg(&client->dev, "Starting eeprom update, slice %u\n", slice); if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { - for (i = slice << 5; i < (slice + 1) << 5; i += I2C_SMBUS_I2C_BLOCK_MAX) - if (i2c_smbus_read_i2c_block_data(client, i, data->data + i) != I2C_SMBUS_I2C_BLOCK_MAX) + for (i = slice << 5; i < (slice + 1) << 5; i += I2C_SMBUS_BLOCK_MAX) + if (i2c_smbus_read_i2c_block_data(client, i, data->data + i) != I2C_SMBUS_BLOCK_MAX) goto exit; } else { if (i2c_smbus_write_byte(client, slice << 5)) { @@ -155,7 +155,7 @@ static int eeprom_attach_adapter(struct i2c_adapter *adapter) } /* This function is called by i2c_probe */ -int eeprom_detect(struct i2c_adapter *adapter, int address, int kind) +static int eeprom_detect(struct i2c_adapter *adapter, int address, int kind) { struct i2c_client *new_client; struct eeprom_data *data; @@ -171,11 +171,10 @@ int eeprom_detect(struct i2c_adapter *adapter, int address, int kind) | I2C_FUNC_SMBUS_BYTE)) goto exit; - if (!(data = kmalloc(sizeof(struct eeprom_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct eeprom_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - memset(data, 0, sizeof(struct eeprom_data)); new_client = &data->client; memset(data->data, 0xff, EEPROM_SIZE); diff --git a/drivers/i2c/chips/isp1301_omap.c b/drivers/i2c/chips/isp1301_omap.c index 8ee56d4b3891..eaa4742e04fa 100644 --- a/drivers/i2c/chips/isp1301_omap.c +++ b/drivers/i2c/chips/isp1301_omap.c @@ -888,6 +888,7 @@ static int otg_remove(struct device *dev) } struct device_driver omap_otg_driver = { + .owner = THIS_MODULE, .name = "omap_otg", .bus = &platform_bus_type, .probe = otg_probe, diff --git a/drivers/i2c/chips/m41t00.c b/drivers/i2c/chips/m41t00.c index 3f14528a52a9..3df309ae44a6 100644 --- a/drivers/i2c/chips/m41t00.c +++ b/drivers/i2c/chips/m41t00.c @@ -174,13 +174,11 @@ m41t00_probe(struct i2c_adapter *adap, int addr, int kind) struct i2c_client *client; int rc; - client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); + client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); if (!client) return -ENOMEM; - memset(client, 0, sizeof(struct i2c_client)); strncpy(client->name, M41T00_DRV_NAME, I2C_NAME_SIZE); - client->flags = I2C_DF_NOTIFY; client->addr = addr; client->adapter = adap; client->driver = &m41t00_driver; diff --git a/drivers/i2c/chips/max6875.c b/drivers/i2c/chips/max6875.c index 9e1aeb69abf9..b376a006883c 100644 --- a/drivers/i2c/chips/max6875.c +++ b/drivers/i2c/chips/max6875.c @@ -179,16 +179,14 @@ static int max6875_detect(struct i2c_adapter *adapter, int address, int kind) if (address & 1) return 0; - if (!(data = kmalloc(sizeof(struct max6875_data), GFP_KERNEL))) + if (!(data = kzalloc(sizeof(struct max6875_data), GFP_KERNEL))) return -ENOMEM; - memset(data, 0, sizeof(struct max6875_data)); /* A fake client is created on the odd address */ - if (!(fake_client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL))) { + if (!(fake_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL))) { err = -ENOMEM; goto exit_kfree1; } - memset(fake_client, 0, sizeof(struct i2c_client)); /* Init real i2c_client */ real_client = &data->client; diff --git a/drivers/i2c/chips/pca9539.c b/drivers/i2c/chips/pca9539.c index 225577fdda4d..59a930346229 100644 --- a/drivers/i2c/chips/pca9539.c +++ b/drivers/i2c/chips/pca9539.c @@ -122,11 +122,10 @@ static int pca9539_detect(struct i2c_adapter *adapter, int address, int kind) /* OK. For now, we presume we have a valid client. We now create the client structure, even though we cannot fill it completely yet. */ - if (!(data = kmalloc(sizeof(struct pca9539_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct pca9539_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - memset(data, 0, sizeof(struct pca9539_data)); new_client = &data->client; i2c_set_clientdata(new_client, data); diff --git a/drivers/i2c/chips/pcf8574.c b/drivers/i2c/chips/pcf8574.c index 6525743ff9fd..c323c2de236c 100644 --- a/drivers/i2c/chips/pcf8574.c +++ b/drivers/i2c/chips/pcf8574.c @@ -115,7 +115,7 @@ static int pcf8574_attach_adapter(struct i2c_adapter *adapter) } /* This function is called by i2c_probe */ -int pcf8574_detect(struct i2c_adapter *adapter, int address, int kind) +static int pcf8574_detect(struct i2c_adapter *adapter, int address, int kind) { struct i2c_client *new_client; struct pcf8574_data *data; @@ -127,11 +127,10 @@ int pcf8574_detect(struct i2c_adapter *adapter, int address, int kind) /* OK. For now, we presume we have a valid client. We now create the client structure, even though we cannot fill it completely yet. */ - if (!(data = kmalloc(sizeof(struct pcf8574_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct pcf8574_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - memset(data, 0, sizeof(struct pcf8574_data)); new_client = &data->client; i2c_set_clientdata(new_client, data); diff --git a/drivers/i2c/chips/pcf8591.c b/drivers/i2c/chips/pcf8591.c index 80f1df9a4500..ce420a67560b 100644 --- a/drivers/i2c/chips/pcf8591.c +++ b/drivers/i2c/chips/pcf8591.c @@ -166,7 +166,7 @@ static int pcf8591_attach_adapter(struct i2c_adapter *adapter) } /* This function is called by i2c_probe */ -int pcf8591_detect(struct i2c_adapter *adapter, int address, int kind) +static int pcf8591_detect(struct i2c_adapter *adapter, int address, int kind) { struct i2c_client *new_client; struct pcf8591_data *data; @@ -178,11 +178,10 @@ int pcf8591_detect(struct i2c_adapter *adapter, int address, int kind) /* OK. For now, we presume we have a valid client. We now create the client structure, even though we cannot fill it completely yet. */ - if (!(data = kmalloc(sizeof(struct pcf8591_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct pcf8591_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - memset(data, 0, sizeof(struct pcf8591_data)); new_client = &data->client; i2c_set_clientdata(new_client, data); diff --git a/drivers/i2c/chips/rtc8564.c b/drivers/i2c/chips/rtc8564.c index 0b5385c892b1..916cdc1af23c 100644 --- a/drivers/i2c/chips/rtc8564.c +++ b/drivers/i2c/chips/rtc8564.c @@ -148,17 +148,16 @@ static int rtc8564_attach(struct i2c_adapter *adap, int addr, int kind) {addr, I2C_M_RD, 2, data} }; - d = kmalloc(sizeof(struct rtc8564_data), GFP_KERNEL); + d = kzalloc(sizeof(struct rtc8564_data), GFP_KERNEL); if (!d) { ret = -ENOMEM; goto done; } - memset(d, 0, sizeof(struct rtc8564_data)); new_client = &d->client; strlcpy(new_client->name, "RTC8564", I2C_NAME_SIZE); i2c_set_clientdata(new_client, d); - new_client->flags = I2C_CLIENT_ALLOW_USE | I2C_DF_NOTIFY; + new_client->flags = I2C_CLIENT_ALLOW_USE; new_client->addr = addr; new_client->adapter = adap; new_client->driver = &rtc8564_driver; diff --git a/drivers/i2c/chips/tps65010.c b/drivers/i2c/chips/tps65010.c index 280e9638c0f8..280dd7a45db6 100644 --- a/drivers/i2c/chips/tps65010.c +++ b/drivers/i2c/chips/tps65010.c @@ -500,11 +500,10 @@ tps65010_probe(struct i2c_adapter *bus, int address, int kind) return 0; } - tps = kmalloc(sizeof *tps, GFP_KERNEL); + tps = kzalloc(sizeof *tps, GFP_KERNEL); if (!tps) return 0; - memset(tps, 0, sizeof *tps); init_MUTEX(&tps->lock); INIT_WORK(&tps->work, tps65010_work, tps); tps->irq = -1; diff --git a/drivers/i2c/chips/x1205.c b/drivers/i2c/chips/x1205.c new file mode 100644 index 000000000000..7da366cdc18c --- /dev/null +++ b/drivers/i2c/chips/x1205.c @@ -0,0 +1,698 @@ +/* + * x1205.c - An i2c driver for the Xicor X1205 RTC + * Copyright 2004 Karen Spearel + * Copyright 2005 Alessandro Zummo + * + * please send all reports to: + * kas11 at tampabay dot rr dot com + * a dot zummo at towertech dot it + * + * based on the other drivers in this same directory. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/i2c.h> +#include <linux/string.h> +#include <linux/bcd.h> +#include <linux/rtc.h> +#include <linux/list.h> + +#include <linux/x1205.h> + +#define DRV_VERSION "0.9.9" + +/* Addresses to scan: none. This chip is located at + * 0x6f and uses a two bytes register addressing. + * Two bytes need to be written to read a single register, + * while most other chips just require one and take the second + * one as the data to be written. To prevent corrupting + * unknown chips, the user must explicitely set the probe parameter. + */ + +static unsigned short normal_i2c[] = { I2C_CLIENT_END }; + +/* Insmod parameters */ +I2C_CLIENT_INSMOD; +I2C_CLIENT_MODULE_PARM(hctosys, + "Set the system time from the hardware clock upon initialization"); + +/* offsets into CCR area */ + +#define CCR_SEC 0 +#define CCR_MIN 1 +#define CCR_HOUR 2 +#define CCR_MDAY 3 +#define CCR_MONTH 4 +#define CCR_YEAR 5 +#define CCR_WDAY 6 +#define CCR_Y2K 7 + +#define X1205_REG_SR 0x3F /* status register */ +#define X1205_REG_Y2K 0x37 +#define X1205_REG_DW 0x36 +#define X1205_REG_YR 0x35 +#define X1205_REG_MO 0x34 +#define X1205_REG_DT 0x33 +#define X1205_REG_HR 0x32 +#define X1205_REG_MN 0x31 +#define X1205_REG_SC 0x30 +#define X1205_REG_DTR 0x13 +#define X1205_REG_ATR 0x12 +#define X1205_REG_INT 0x11 +#define X1205_REG_0 0x10 +#define X1205_REG_Y2K1 0x0F +#define X1205_REG_DWA1 0x0E +#define X1205_REG_YRA1 0x0D +#define X1205_REG_MOA1 0x0C +#define X1205_REG_DTA1 0x0B +#define X1205_REG_HRA1 0x0A +#define X1205_REG_MNA1 0x09 +#define X1205_REG_SCA1 0x08 +#define X1205_REG_Y2K0 0x07 +#define X1205_REG_DWA0 0x06 +#define X1205_REG_YRA0 0x05 +#define X1205_REG_MOA0 0x04 +#define X1205_REG_DTA0 0x03 +#define X1205_REG_HRA0 0x02 +#define X1205_REG_MNA0 0x01 +#define X1205_REG_SCA0 0x00 + +#define X1205_CCR_BASE 0x30 /* Base address of CCR */ +#define X1205_ALM0_BASE 0x00 /* Base address of ALARM0 */ + +#define X1205_SR_RTCF 0x01 /* Clock failure */ +#define X1205_SR_WEL 0x02 /* Write Enable Latch */ +#define X1205_SR_RWEL 0x04 /* Register Write Enable */ + +#define X1205_DTR_DTR0 0x01 +#define X1205_DTR_DTR1 0x02 +#define X1205_DTR_DTR2 0x04 + +#define X1205_HR_MIL 0x80 /* Set in ccr.hour for 24 hr mode */ + +/* Prototypes */ +static int x1205_attach(struct i2c_adapter *adapter); +static int x1205_detach(struct i2c_client *client); +static int x1205_probe(struct i2c_adapter *adapter, int address, int kind); +static int x1205_command(struct i2c_client *client, unsigned int cmd, + void *arg); + +static struct i2c_driver x1205_driver = { + .owner = THIS_MODULE, + .name = "x1205", + .flags = I2C_DF_NOTIFY, + .attach_adapter = &x1205_attach, + .detach_client = &x1205_detach, +}; + +struct x1205_data { + struct i2c_client client; + struct list_head list; + unsigned int epoch; +}; + +static const unsigned char days_in_mo[] = + { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + +static LIST_HEAD(x1205_clients); + +/* Workaround until the I2C subsytem will allow to send + * commands to a specific client. This function will send the command + * to the first client. + */ +int x1205_do_command(unsigned int cmd, void *arg) +{ + struct list_head *walk; + struct list_head *tmp; + struct x1205_data *data; + + list_for_each_safe(walk, tmp, &x1205_clients) { + data = list_entry(walk, struct x1205_data, list); + return x1205_command(&data->client, cmd, arg); + } + + return -ENODEV; +} + +#define is_leap(year) \ + ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0)) + +/* make sure the rtc_time values are in bounds */ +static int x1205_validate_tm(struct rtc_time *tm) +{ + int year = tm->tm_year + 1900; + + if ((tm->tm_year < 70) || (tm->tm_year > 255)) + return -EINVAL; + + if ((tm->tm_mon > 11) || (tm->tm_mday == 0)) + return -EINVAL; + + if (tm->tm_mday > days_in_mo[tm->tm_mon] + + ((tm->tm_mon == 1) && is_leap(year))) + return -EINVAL; + + if ((tm->tm_hour >= 24) || (tm->tm_min >= 60) || (tm->tm_sec >= 60)) + return -EINVAL; + + return 0; +} + +/* + * In the routines that deal directly with the x1205 hardware, we use + * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch + * Epoch is initialized as 2000. Time is set to UTC. + */ +static int x1205_get_datetime(struct i2c_client *client, struct rtc_time *tm, + u8 reg_base) +{ + unsigned char dt_addr[2] = { 0, reg_base }; + static unsigned char sr_addr[2] = { 0, X1205_REG_SR }; + + unsigned char buf[8], sr; + + struct i2c_msg msgs[] = { + { client->addr, 0, 2, sr_addr }, /* setup read ptr */ + { client->addr, I2C_M_RD, 1, &sr }, /* read status */ + { client->addr, 0, 2, dt_addr }, /* setup read ptr */ + { client->addr, I2C_M_RD, 8, buf }, /* read date */ + }; + + struct x1205_data *data = i2c_get_clientdata(client); + + /* read status register */ + if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) { + dev_err(&client->dev, "%s: read error\n", __FUNCTION__); + return -EIO; + } + + /* check for battery failure */ + if (sr & X1205_SR_RTCF) { + dev_warn(&client->dev, + "Clock had a power failure, you must set the date.\n"); + return -EINVAL; + } + + /* read date registers */ + if ((i2c_transfer(client->adapter, &msgs[2], 2)) != 2) { + dev_err(&client->dev, "%s: read error\n", __FUNCTION__); + return -EIO; + } + + dev_dbg(&client->dev, + "%s: raw read data - sec=%02x, min=%02x, hr=%02x, " + "mday=%02x, mon=%02x, year=%02x, wday=%02x, y2k=%02x\n", + __FUNCTION__, + buf[0], buf[1], buf[2], buf[3], + buf[4], buf[5], buf[6], buf[7]); + + tm->tm_sec = BCD2BIN(buf[CCR_SEC]); + tm->tm_min = BCD2BIN(buf[CCR_MIN]); + tm->tm_hour = BCD2BIN(buf[CCR_HOUR] & 0x3F); /* hr is 0-23 */ + tm->tm_mday = BCD2BIN(buf[CCR_MDAY]); + tm->tm_mon = BCD2BIN(buf[CCR_MONTH]); + data->epoch = BCD2BIN(buf[CCR_Y2K]) * 100; + tm->tm_year = BCD2BIN(buf[CCR_YEAR]) + data->epoch - 1900; + tm->tm_wday = buf[CCR_WDAY]; + + dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, " + "mday=%d, mon=%d, year=%d, wday=%d\n", + __FUNCTION__, + tm->tm_sec, tm->tm_min, tm->tm_hour, + tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); + + return 0; +} + +static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm, + int datetoo, u8 reg_base) +{ + int i, err, xfer; + + unsigned char buf[8]; + + static const unsigned char wel[3] = { 0, X1205_REG_SR, + X1205_SR_WEL }; + + static const unsigned char rwel[3] = { 0, X1205_REG_SR, + X1205_SR_WEL | X1205_SR_RWEL }; + + static const unsigned char diswe[3] = { 0, X1205_REG_SR, 0 }; + + struct x1205_data *data = i2c_get_clientdata(client); + + /* check if all values in the tm struct are correct */ + if ((err = x1205_validate_tm(tm)) < 0) + return err; + + dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, " + "mday=%d, mon=%d, year=%d, wday=%d\n", + __FUNCTION__, + tm->tm_sec, tm->tm_min, tm->tm_hour, + tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); + + buf[CCR_SEC] = BIN2BCD(tm->tm_sec); + buf[CCR_MIN] = BIN2BCD(tm->tm_min); + + /* set hour and 24hr bit */ + buf[CCR_HOUR] = BIN2BCD(tm->tm_hour) | X1205_HR_MIL; + + /* should we also set the date? */ + if (datetoo) { + buf[CCR_MDAY] = BIN2BCD(tm->tm_mday); + + /* month, 0 - 11 */ + buf[CCR_MONTH] = BIN2BCD(tm->tm_mon); + + /* year, since 1900 */ + buf[CCR_YEAR] = BIN2BCD(tm->tm_year + 1900 - data->epoch); + buf[CCR_WDAY] = tm->tm_wday & 0x07; + buf[CCR_Y2K] = BIN2BCD(data->epoch / 100); + } + + /* this sequence is required to unlock the chip */ + xfer = i2c_master_send(client, wel, 3); + if (xfer != 3) { + dev_err(&client->dev, "%s: wel - %d\n", __FUNCTION__, xfer); + return -EIO; + } + + xfer = i2c_master_send(client, rwel, 3); + if (xfer != 3) { + dev_err(&client->dev, "%s: rwel - %d\n", __FUNCTION__, xfer); + return -EIO; + } + + /* write register's data */ + for (i = 0; i < (datetoo ? 8 : 3); i++) { + unsigned char rdata[3] = { 0, reg_base + i, buf[i] }; + + xfer = i2c_master_send(client, rdata, 3); + if (xfer != 3) { + dev_err(&client->dev, + "%s: xfer=%d addr=%02x, data=%02x\n", + __FUNCTION__, + xfer, rdata[1], rdata[2]); + return -EIO; + } + }; + + /* disable further writes */ + xfer = i2c_master_send(client, diswe, 3); + if (xfer != 3) { + dev_err(&client->dev, "%s: diswe - %d\n", __FUNCTION__, xfer); + return -EIO; + } + + return 0; +} + +static int x1205_get_dtrim(struct i2c_client *client, int *trim) +{ + unsigned char dtr; + static unsigned char dtr_addr[2] = { 0, X1205_REG_DTR }; + + struct i2c_msg msgs[] = { + { client->addr, 0, 2, dtr_addr }, /* setup read ptr */ + { client->addr, I2C_M_RD, 1, &dtr }, /* read dtr */ + }; + + /* read dtr register */ + if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) { + dev_err(&client->dev, "%s: read error\n", __FUNCTION__); + return -EIO; + } + + dev_dbg(&client->dev, "%s: raw dtr=%x\n", __FUNCTION__, dtr); + + *trim = 0; + + if (dtr & X1205_DTR_DTR0) + *trim += 20; + + if (dtr & X1205_DTR_DTR1) + *trim += 10; + + if (dtr & X1205_DTR_DTR2) + *trim = -*trim; + + return 0; +} + +static int x1205_get_atrim(struct i2c_client *client, int *trim) +{ + s8 atr; + static unsigned char atr_addr[2] = { 0, X1205_REG_ATR }; + + struct i2c_msg msgs[] = { + { client->addr, 0, 2, atr_addr }, /* setup read ptr */ + { client->addr, I2C_M_RD, 1, &atr }, /* read atr */ + }; + + /* read atr register */ + if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) { + dev_err(&client->dev, "%s: read error\n", __FUNCTION__); + return -EIO; + } + + dev_dbg(&client->dev, "%s: raw atr=%x\n", __FUNCTION__, atr); + + /* atr is a two's complement value on 6 bits, + * perform sign extension. The formula is + * Catr = (atr * 0.25pF) + 11.00pF. + */ + if (atr & 0x20) + atr |= 0xC0; + + dev_dbg(&client->dev, "%s: raw atr=%x (%d)\n", __FUNCTION__, atr, atr); + + *trim = (atr * 250) + 11000; + + dev_dbg(&client->dev, "%s: real=%d\n", __FUNCTION__, *trim); + + return 0; +} + +static int x1205_hctosys(struct i2c_client *client) +{ + int err; + + struct rtc_time tm; + struct timespec tv; + + err = x1205_command(client, X1205_CMD_GETDATETIME, &tm); + + if (err) { + dev_err(&client->dev, + "Unable to set the system clock\n"); + return err; + } + + /* IMPORTANT: the RTC only stores whole seconds. It is arbitrary + * whether it stores the most close value or the value with partial + * seconds truncated. However, it is important that we use it to store + * the truncated value. This is because otherwise it is necessary, + * in an rtc sync function, to read both xtime.tv_sec and + * xtime.tv_nsec. On some processors (i.e. ARM), an atomic read + * of >32bits is not possible. So storing the most close value would + * slow down the sync API. So here we have the truncated value and + * the best guess is to add 0.5s. + */ + + tv.tv_nsec = NSEC_PER_SEC >> 1; + + /* WARNING: this is not the C library 'mktime' call, it is a built in + * inline function from include/linux/time.h. It expects (requires) + * the month to be in the range 1-12 + */ + + tv.tv_sec = mktime(tm.tm_year + 1900, tm.tm_mon + 1, + tm.tm_mday, tm.tm_hour, + tm.tm_min, tm.tm_sec); + + do_settimeofday(&tv); + + dev_info(&client->dev, + "setting the system clock to %d-%d-%d %d:%d:%d\n", + tm.tm_year + 1900, tm.tm_mon + 1, + tm.tm_mday, tm.tm_hour, tm.tm_min, + tm.tm_sec); + + return 0; +} + +struct x1205_limit +{ + unsigned char reg; + unsigned char mask; + unsigned char min; + unsigned char max; +}; + +static int x1205_validate_client(struct i2c_client *client) +{ + int i, xfer; + + /* Probe array. We will read the register at the specified + * address and check if the given bits are zero. + */ + static const unsigned char probe_zero_pattern[] = { + /* register, mask */ + X1205_REG_SR, 0x18, + X1205_REG_DTR, 0xF8, + X1205_REG_ATR, 0xC0, + X1205_REG_INT, 0x18, + X1205_REG_0, 0xFF, + }; + + static const struct x1205_limit probe_limits_pattern[] = { + /* register, mask, min, max */ + { X1205_REG_Y2K, 0xFF, 19, 20 }, + { X1205_REG_DW, 0xFF, 0, 6 }, + { X1205_REG_YR, 0xFF, 0, 99 }, + { X1205_REG_MO, 0xFF, 0, 12 }, + { X1205_REG_DT, 0xFF, 0, 31 }, + { X1205_REG_HR, 0x7F, 0, 23 }, + { X1205_REG_MN, 0xFF, 0, 59 }, + { X1205_REG_SC, 0xFF, 0, 59 }, + { X1205_REG_Y2K1, 0xFF, 19, 20 }, + { X1205_REG_Y2K0, 0xFF, 19, 20 }, + }; + + /* check that registers have bits a 0 where expected */ + for (i = 0; i < ARRAY_SIZE(probe_zero_pattern); i += 2) { + unsigned char buf; + + unsigned char addr[2] = { 0, probe_zero_pattern[i] }; + + struct i2c_msg msgs[2] = { + { client->addr, 0, 2, addr }, + { client->addr, I2C_M_RD, 1, &buf }, + }; + + xfer = i2c_transfer(client->adapter, msgs, 2); + if (xfer != 2) { + dev_err(&client->adapter->dev, + "%s: could not read register %x\n", + __FUNCTION__, addr[1]); + + return -EIO; + } + + if ((buf & probe_zero_pattern[i+1]) != 0) { + dev_err(&client->adapter->dev, + "%s: register=%02x, zero pattern=%d, value=%x\n", + __FUNCTION__, addr[1], i, buf); + + return -ENODEV; + } + } + + /* check limits (only registers with bcd values) */ + for (i = 0; i < ARRAY_SIZE(probe_limits_pattern); i++) { + unsigned char reg, value; + + unsigned char addr[2] = { 0, probe_limits_pattern[i].reg }; + + struct i2c_msg msgs[2] = { + { client->addr, 0, 2, addr }, + { client->addr, I2C_M_RD, 1, ® }, + }; + + xfer = i2c_transfer(client->adapter, msgs, 2); + + if (xfer != 2) { + dev_err(&client->adapter->dev, + "%s: could not read register %x\n", + __FUNCTION__, addr[1]); + + return -EIO; + } + + value = BCD2BIN(reg & probe_limits_pattern[i].mask); + + if (value > probe_limits_pattern[i].max || + value < probe_limits_pattern[i].min) { + dev_dbg(&client->adapter->dev, + "%s: register=%x, lim pattern=%d, value=%d\n", + __FUNCTION__, addr[1], i, value); + + return -ENODEV; + } + } + + return 0; +} + +static int x1205_attach(struct i2c_adapter *adapter) +{ + dev_dbg(&adapter->dev, "%s\n", __FUNCTION__); + + return i2c_probe(adapter, &addr_data, x1205_probe); +} + +int x1205_direct_attach(int adapter_id, + struct i2c_client_address_data *address_data) +{ + int err; + struct i2c_adapter *adapter = i2c_get_adapter(adapter_id); + + if (adapter) { + err = i2c_probe(adapter, + address_data, x1205_probe); + + i2c_put_adapter(adapter); + + return err; + } + + return -ENODEV; +} + +static int x1205_probe(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *client; + struct x1205_data *data; + + int err = 0; + + dev_dbg(&adapter->dev, "%s\n", __FUNCTION__); + + if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) { + err = -ENODEV; + goto exit; + } + + if (!(data = kzalloc(sizeof(struct x1205_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + + /* Initialize our structures */ + data->epoch = 2000; + + client = &data->client; + client->addr = address; + client->driver = &x1205_driver; + client->adapter = adapter; + + strlcpy(client->name, "x1205", I2C_NAME_SIZE); + + i2c_set_clientdata(client, data); + + /* Verify the chip is really an X1205 */ + if (kind < 0) { + if (x1205_validate_client(client) < 0) { + err = -ENODEV; + goto exit_kfree; + } + } + + /* Inform the i2c layer */ + if ((err = i2c_attach_client(client))) + goto exit_kfree; + + list_add(&data->list, &x1205_clients); + + dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n"); + + /* If requested, set the system time */ + if (hctosys) + x1205_hctosys(client); + + return 0; + +exit_kfree: + kfree(data); + +exit: + return err; +} + +static int x1205_detach(struct i2c_client *client) +{ + int err; + struct x1205_data *data = i2c_get_clientdata(client); + + dev_dbg(&client->dev, "%s\n", __FUNCTION__); + + if ((err = i2c_detach_client(client))) + return err; + + list_del(&data->list); + + kfree(data); + + return 0; +} + +static int x1205_command(struct i2c_client *client, unsigned int cmd, + void *param) +{ + if (param == NULL) + return -EINVAL; + + if (!capable(CAP_SYS_TIME)) + return -EACCES; + + dev_dbg(&client->dev, "%s: cmd=%d\n", __FUNCTION__, cmd); + + switch (cmd) { + case X1205_CMD_GETDATETIME: + return x1205_get_datetime(client, param, X1205_CCR_BASE); + + case X1205_CMD_SETTIME: + return x1205_set_datetime(client, param, 0, + X1205_CCR_BASE); + + case X1205_CMD_SETDATETIME: + return x1205_set_datetime(client, param, 1, + X1205_CCR_BASE); + + case X1205_CMD_GETALARM: + return x1205_get_datetime(client, param, X1205_ALM0_BASE); + + case X1205_CMD_SETALARM: + return x1205_set_datetime(client, param, 1, + X1205_ALM0_BASE); + + case X1205_CMD_GETDTRIM: + return x1205_get_dtrim(client, param); + + case X1205_CMD_GETATRIM: + return x1205_get_atrim(client, param); + + default: + return -EINVAL; + } +} + +static int __init x1205_init(void) +{ + return i2c_add_driver(&x1205_driver); +} + +static void __exit x1205_exit(void) +{ + i2c_del_driver(&x1205_driver); +} + +MODULE_AUTHOR( + "Karen Spearel <kas11@tampabay.rr.com>, " + "Alessandro Zummo <a.zummo@towertech.it>"); +MODULE_DESCRIPTION("Xicor X1205 RTC driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_VERSION); + +EXPORT_SYMBOL_GPL(x1205_do_command); +EXPORT_SYMBOL_GPL(x1205_direct_attach); + +module_init(x1205_init); +module_exit(x1205_exit); diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index dda472e5e8be..02e335a04f09 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -19,7 +19,8 @@ /* With some changes from Kysti Mlkki <kmalkki@cc.hut.fi>. All SMBus-related things are written by Frodo Looijaard <frodol@dds.nl> - SMBus 2.0 support by Mark Studebaker <mdsxyz123@yahoo.com> */ + SMBus 2.0 support by Mark Studebaker <mdsxyz123@yahoo.com> and + Jean Delvare <khali@linux-fr.org> */ #include <linux/module.h> #include <linux/kernel.h> @@ -48,7 +49,7 @@ static int i2c_bus_suspend(struct device * dev, pm_message_t state) int rc = 0; if (dev->driver && dev->driver->suspend) - rc = dev->driver->suspend(dev,state,0); + rc = dev->driver->suspend(dev, state); return rc; } @@ -57,7 +58,7 @@ static int i2c_bus_resume(struct device * dev) int rc = 0; if (dev->driver && dev->driver->resume) - rc = dev->driver->resume(dev,0); + rc = dev->driver->resume(dev); return rc; } @@ -85,6 +86,7 @@ void i2c_adapter_dev_release(struct device *dev) } struct device_driver i2c_adapter_driver = { + .owner = THIS_MODULE, .name = "i2c_adapter", .bus = &i2c_bus_type, .probe = i2c_device_probe, @@ -98,6 +100,7 @@ static void i2c_adapter_class_dev_release(struct class_device *dev) } struct class i2c_adapter_class = { + .owner = THIS_MODULE, .name = "i2c-adapter", .release = &i2c_adapter_class_dev_release, }; @@ -291,6 +294,7 @@ int i2c_add_driver(struct i2c_driver *driver) down(&core_lists); /* add the driver to the list of i2c drivers in the driver core */ + driver->driver.owner = driver->owner; driver->driver.name = driver->name; driver->driver.bus = &i2c_bus_type; driver->driver.probe = i2c_device_probe; @@ -706,10 +710,6 @@ int i2c_probe(struct i2c_adapter *adapter, int i, err; int adap_id = i2c_adapter_id(adapter); - /* Forget it if we can't probe using SMBUS_QUICK */ - if (! i2c_check_functionality(adapter,I2C_FUNC_SMBUS_QUICK)) - return -1; - /* Force entries are done first, and are not affected by ignore entries */ if (address_data->forces) { @@ -736,6 +736,17 @@ int i2c_probe(struct i2c_adapter *adapter, } } + /* Stop here if we can't use SMBUS_QUICK */ + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_QUICK)) { + if (address_data->probe[0] == I2C_CLIENT_END + && address_data->normal_i2c[0] == I2C_CLIENT_END) + return 0; + + dev_warn(&adapter->dev, "SMBus Quick command not supported, " + "can't probe for chips\n"); + return -1; + } + /* Probe entries are done second, and are not affected by ignore entries either */ for (i = 0; address_data->probe[i] != I2C_CLIENT_END; i += 2) { @@ -820,101 +831,44 @@ crc8(u16 data) return (u8)(data >> 8); } -/* CRC over count bytes in the first array plus the bytes in the rest - array if it is non-null. rest[0] is the (length of rest) - 1 - and is included. */ -static u8 i2c_smbus_partial_pec(u8 crc, int count, u8 *first, u8 *rest) +/* Incremental CRC8 over count bytes in the array pointed to by p */ +static u8 i2c_smbus_pec(u8 crc, u8 *p, size_t count) { int i; for(i = 0; i < count; i++) - crc = crc8((crc ^ first[i]) << 8); - if(rest != NULL) - for(i = 0; i <= rest[0]; i++) - crc = crc8((crc ^ rest[i]) << 8); + crc = crc8((crc ^ p[i]) << 8); return crc; } -static u8 i2c_smbus_pec(int count, u8 *first, u8 *rest) +/* Assume a 7-bit address, which is reasonable for SMBus */ +static u8 i2c_smbus_msg_pec(u8 pec, struct i2c_msg *msg) { - return i2c_smbus_partial_pec(0, count, first, rest); + /* The address will be sent first */ + u8 addr = (msg->addr << 1) | !!(msg->flags & I2C_M_RD); + pec = i2c_smbus_pec(pec, &addr, 1); + + /* The data buffer follows */ + return i2c_smbus_pec(pec, msg->buf, msg->len); } -/* Returns new "size" (transaction type) - Note that we convert byte to byte_data and byte_data to word_data - rather than invent new xxx_PEC transactions. */ -static int i2c_smbus_add_pec(u16 addr, u8 command, int size, - union i2c_smbus_data *data) +/* Used for write only transactions */ +static inline void i2c_smbus_add_pec(struct i2c_msg *msg) { - u8 buf[3]; - - buf[0] = addr << 1; - buf[1] = command; - switch(size) { - case I2C_SMBUS_BYTE: - data->byte = i2c_smbus_pec(2, buf, NULL); - size = I2C_SMBUS_BYTE_DATA; - break; - case I2C_SMBUS_BYTE_DATA: - buf[2] = data->byte; - data->word = buf[2] || - (i2c_smbus_pec(3, buf, NULL) << 8); - size = I2C_SMBUS_WORD_DATA; - break; - case I2C_SMBUS_WORD_DATA: - /* unsupported */ - break; - case I2C_SMBUS_BLOCK_DATA: - data->block[data->block[0] + 1] = - i2c_smbus_pec(2, buf, data->block); - size = I2C_SMBUS_BLOCK_DATA_PEC; - break; - } - return size; + msg->buf[msg->len] = i2c_smbus_msg_pec(0, msg); + msg->len++; } -static int i2c_smbus_check_pec(u16 addr, u8 command, int size, u8 partial, - union i2c_smbus_data *data) +/* Return <0 on CRC error + If there was a write before this read (most cases) we need to take the + partial CRC from the write part into account. + Note that this function does modify the message (we need to decrease the + message length to hide the CRC byte from the caller). */ +static int i2c_smbus_check_pec(u8 cpec, struct i2c_msg *msg) { - u8 buf[3], rpec, cpec; + u8 rpec = msg->buf[--msg->len]; + cpec = i2c_smbus_msg_pec(cpec, msg); - buf[1] = command; - switch(size) { - case I2C_SMBUS_BYTE_DATA: - buf[0] = (addr << 1) | 1; - cpec = i2c_smbus_pec(2, buf, NULL); - rpec = data->byte; - break; - case I2C_SMBUS_WORD_DATA: - buf[0] = (addr << 1) | 1; - buf[2] = data->word & 0xff; - cpec = i2c_smbus_pec(3, buf, NULL); - rpec = data->word >> 8; - break; - case I2C_SMBUS_WORD_DATA_PEC: - /* unsupported */ - cpec = rpec = 0; - break; - case I2C_SMBUS_PROC_CALL_PEC: - /* unsupported */ - cpec = rpec = 0; - break; - case I2C_SMBUS_BLOCK_DATA_PEC: - buf[0] = (addr << 1); - buf[2] = (addr << 1) | 1; - cpec = i2c_smbus_pec(3, buf, data->block); - rpec = data->block[data->block[0] + 1]; - break; - case I2C_SMBUS_BLOCK_PROC_CALL_PEC: - buf[0] = (addr << 1) | 1; - rpec = i2c_smbus_partial_pec(partial, 1, - buf, data->block); - cpec = data->block[data->block[0] + 1]; - break; - default: - cpec = rpec = 0; - break; - } if (rpec != cpec) { pr_debug("i2c-core: Bad PEC 0x%02x vs. 0x%02x\n", rpec, cpec); @@ -941,9 +895,8 @@ s32 i2c_smbus_read_byte(struct i2c_client *client) s32 i2c_smbus_write_byte(struct i2c_client *client, u8 value) { - union i2c_smbus_data data; /* only for PEC */ return i2c_smbus_xfer(client->adapter,client->addr,client->flags, - I2C_SMBUS_WRITE,value, I2C_SMBUS_BYTE,&data); + I2C_SMBUS_WRITE, value, I2C_SMBUS_BYTE, NULL); } s32 i2c_smbus_read_byte_data(struct i2c_client *client, u8 command) @@ -1026,13 +979,14 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr, need to use only one message; when reading, we need two. We initialize most things with sane defaults, to keep the code below somewhat simpler. */ - unsigned char msgbuf0[34]; - unsigned char msgbuf1[34]; + unsigned char msgbuf0[I2C_SMBUS_BLOCK_MAX+3]; + unsigned char msgbuf1[I2C_SMBUS_BLOCK_MAX+2]; int num = read_write == I2C_SMBUS_READ?2:1; struct i2c_msg msg[2] = { { addr, flags, 1, msgbuf0 }, { addr, flags | I2C_M_RD, 0, msgbuf1 } }; int i; + u8 partial_pec = 0; msgbuf0[0] = command; switch(size) { @@ -1075,7 +1029,6 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr, msgbuf0[2] = (data->word >> 8) & 0xff; break; case I2C_SMBUS_BLOCK_DATA: - case I2C_SMBUS_BLOCK_DATA_PEC: if (read_write == I2C_SMBUS_READ) { dev_err(&adapter->dev, "Block read not supported " "under I2C emulation!\n"); @@ -1088,23 +1041,20 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr, data->block[0]); return -1; } - if(size == I2C_SMBUS_BLOCK_DATA_PEC) - (msg[0].len)++; - for (i = 1; i <= msg[0].len; i++) + for (i = 1; i < msg[0].len; i++) msgbuf0[i] = data->block[i-1]; } break; case I2C_SMBUS_BLOCK_PROC_CALL: - case I2C_SMBUS_BLOCK_PROC_CALL_PEC: dev_dbg(&adapter->dev, "Block process call not supported " "under I2C emulation!\n"); return -1; case I2C_SMBUS_I2C_BLOCK_DATA: if (read_write == I2C_SMBUS_READ) { - msg[1].len = I2C_SMBUS_I2C_BLOCK_MAX; + msg[1].len = I2C_SMBUS_BLOCK_MAX; } else { msg[0].len = data->block[0] + 1; - if (msg[0].len > I2C_SMBUS_I2C_BLOCK_MAX + 1) { + if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 1) { dev_err(&adapter->dev, "i2c_smbus_xfer_emulated called with " "invalid block write size (%d)\n", data->block[0]); @@ -1120,9 +1070,30 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr, return -1; } + i = ((flags & I2C_CLIENT_PEC) && size != I2C_SMBUS_QUICK + && size != I2C_SMBUS_I2C_BLOCK_DATA); + if (i) { + /* Compute PEC if first message is a write */ + if (!(msg[0].flags & I2C_M_RD)) { + if (num == 1) /* Write only */ + i2c_smbus_add_pec(&msg[0]); + else /* Write followed by read */ + partial_pec = i2c_smbus_msg_pec(0, &msg[0]); + } + /* Ask for PEC if last message is a read */ + if (msg[num-1].flags & I2C_M_RD) + msg[num-1].len++; + } + if (i2c_transfer(adapter, msg, num) < 0) return -1; + /* Check PEC if last message is a read */ + if (i && (msg[num-1].flags & I2C_M_RD)) { + if (i2c_smbus_check_pec(partial_pec, &msg[num-1]) < 0) + return -1; + } + if (read_write == I2C_SMBUS_READ) switch(size) { case I2C_SMBUS_BYTE: @@ -1137,8 +1108,8 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr, break; case I2C_SMBUS_I2C_BLOCK_DATA: /* fixed at 32 for now */ - data->block[0] = I2C_SMBUS_I2C_BLOCK_MAX; - for (i = 0; i < I2C_SMBUS_I2C_BLOCK_MAX; i++) + data->block[0] = I2C_SMBUS_BLOCK_MAX; + for (i = 0; i < I2C_SMBUS_BLOCK_MAX; i++) data->block[i+1] = msgbuf1[i]; break; } @@ -1151,28 +1122,8 @@ s32 i2c_smbus_xfer(struct i2c_adapter * adapter, u16 addr, unsigned short flags, union i2c_smbus_data * data) { s32 res; - int swpec = 0; - u8 partial = 0; flags &= I2C_M_TEN | I2C_CLIENT_PEC; - if((flags & I2C_CLIENT_PEC) && - !(i2c_check_functionality(adapter, I2C_FUNC_SMBUS_HWPEC_CALC))) { - swpec = 1; - if(read_write == I2C_SMBUS_READ && - size == I2C_SMBUS_BLOCK_DATA) - size = I2C_SMBUS_BLOCK_DATA_PEC; - else if(size == I2C_SMBUS_PROC_CALL) - size = I2C_SMBUS_PROC_CALL_PEC; - else if(size == I2C_SMBUS_BLOCK_PROC_CALL) { - i2c_smbus_add_pec(addr, command, - I2C_SMBUS_BLOCK_DATA, data); - partial = data->block[data->block[0] + 1]; - size = I2C_SMBUS_BLOCK_PROC_CALL_PEC; - } else if(read_write == I2C_SMBUS_WRITE && - size != I2C_SMBUS_QUICK && - size != I2C_SMBUS_I2C_BLOCK_DATA) - size = i2c_smbus_add_pec(addr, command, size, data); - } if (adapter->algo->smbus_xfer) { down(&adapter->bus_lock); @@ -1183,13 +1134,6 @@ s32 i2c_smbus_xfer(struct i2c_adapter * adapter, u16 addr, unsigned short flags, res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write, command,size,data); - if(res >= 0 && swpec && - size != I2C_SMBUS_QUICK && size != I2C_SMBUS_I2C_BLOCK_DATA && - (read_write == I2C_SMBUS_READ || size == I2C_SMBUS_PROC_CALL_PEC || - size == I2C_SMBUS_BLOCK_PROC_CALL_PEC)) { - if(i2c_smbus_check_pec(addr, command, size, partial, data)) - return -1; - } return res; } diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index aa7a4fadef64..ea14c8f1c82b 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c @@ -26,15 +26,11 @@ /* The I2C_RDWR ioctl code is written by Kolja Waschk <waschk@telos.de> */ -/* The devfs code is contributed by Philipp Matthias Hahn - <pmhahn@titan.lahn.de> */ - #include <linux/kernel.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/slab.h> #include <linux/smp_lock.h> -#include <linux/devfs_fs_kernel.h> #include <linux/init.h> #include <linux/i2c.h> #include <linux/i2c-dev.h> @@ -80,10 +76,9 @@ static struct i2c_dev *get_free_i2c_dev(struct i2c_adapter *adap) { struct i2c_dev *i2c_dev; - i2c_dev = kmalloc(sizeof(*i2c_dev), GFP_KERNEL); + i2c_dev = kzalloc(sizeof(*i2c_dev), GFP_KERNEL); if (!i2c_dev) return ERR_PTR(-ENOMEM); - memset(i2c_dev, 0x00, sizeof(*i2c_dev)); spin_lock(&i2c_dev_array_lock); if (i2c_dev_array[adap->nr]) { @@ -177,8 +172,8 @@ static int i2cdev_ioctl(struct inode *inode, struct file *file, int i,datasize,res; unsigned long funcs; - dev_dbg(&client->adapter->dev, "i2c-%d ioctl, cmd: 0x%x, arg: %lx.\n", - iminor(inode),cmd, arg); + dev_dbg(&client->adapter->dev, "ioctl, cmd=0x%02x, arg=0x%02lx\n", + cmd, arg); switch ( cmd ) { case I2C_SLAVE: @@ -432,8 +427,6 @@ static int i2cdev_attach_adapter(struct i2c_adapter *adap) if (IS_ERR(i2c_dev)) return PTR_ERR(i2c_dev); - devfs_mk_cdev(MKDEV(I2C_MAJOR, i2c_dev->minor), - S_IFCHR|S_IRUSR|S_IWUSR, "i2c/%d", i2c_dev->minor); pr_debug("i2c-dev: adapter [%s] registered as minor %d\n", adap->name, i2c_dev->minor); @@ -466,7 +459,6 @@ static int i2cdev_detach_adapter(struct i2c_adapter *adap) return -ENODEV; init_completion(&i2c_dev->released); - devfs_remove("i2c/%d", i2c_dev->minor); return_i2c_dev(i2c_dev); class_device_unregister(&i2c_dev->class_dev); wait_for_completion(&i2c_dev->released); @@ -522,8 +514,6 @@ static int __init i2c_dev_init(void) if (res) goto out_unreg_class; - devfs_mk_dir("i2c"); - return 0; out_unreg_class: @@ -539,7 +529,6 @@ static void __exit i2c_dev_exit(void) { i2c_del_driver(&i2cdev_driver); class_unregister(&i2c_dev_class); - devfs_remove("i2c"); unregister_chrdev(I2C_MAJOR,"i2c"); } diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig index 1cadd2c3cadd..a737886e39d1 100644 --- a/drivers/ide/Kconfig +++ b/drivers/ide/Kconfig @@ -778,6 +778,35 @@ config BLK_DEV_IDE_PMAC_BLINK This option enables the use of the sleep LED as a hard drive activity LED. +config BLK_DEV_IDE_AU1XXX + bool "IDE for AMD Alchemy Au1200" + depends on SOC_AU1200 +choice + prompt "IDE Mode for AMD Alchemy Au1200" + default CONFIG_BLK_DEV_IDE_AU1XXX_PIO_DBDMA + depends on SOC_AU1200 && BLK_DEV_IDE_AU1XXX + +config BLK_DEV_IDE_AU1XXX_PIO_DBDMA + bool "PIO+DbDMA IDE for AMD Alchemy Au1200" + +config BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA + bool "MDMA2+DbDMA IDE for AMD Alchemy Au1200" + depends on SOC_AU1200 && BLK_DEV_IDE_AU1XXX +endchoice + +config BLK_DEV_IDE_AU1XXX_BURSTABLE_ON + bool "Enable burstable Mode on DbDMA" + default false + depends BLK_DEV_IDE_AU1XXX + help + This option enable the burstable Flag on DbDMA controller + (cf. "AMD Alchemy 'Au1200' Processor Data Book - PRELIMINARY"). + +config BLK_DEV_IDE_AU1XXX_SEQTS_PER_RQ + int "Maximum transfer size (KB) per request (up to 128)" + default "128" + depends BLK_DEV_IDE_AU1XXX + config IDE_ARM def_bool ARM && (ARCH_A5K || ARCH_CLPS7500 || ARCH_RPC || ARCH_SHARK) @@ -1013,7 +1042,7 @@ config BLK_DEV_UMC8672 endif config BLK_DEV_IDEDMA - def_bool BLK_DEV_IDEDMA_PCI || BLK_DEV_IDEDMA_PMAC || BLK_DEV_IDEDMA_ICS + def_bool BLK_DEV_IDEDMA_PCI || BLK_DEV_IDEDMA_PMAC || BLK_DEV_IDEDMA_ICS || BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA config IDEDMA_IVB bool "IGNORE word93 Validation BITS" diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index 74af7e074868..8b9d85526596 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -2211,13 +2211,12 @@ static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense) if (toc == NULL) { /* Try to allocate space. */ - toc = (struct atapi_toc *) kmalloc (sizeof (struct atapi_toc), - GFP_KERNEL); - info->toc = toc; + toc = kmalloc(sizeof(struct atapi_toc), GFP_KERNEL); if (toc == NULL) { printk (KERN_ERR "%s: No cdrom TOC buffer!\n", drive->name); return -ENOMEM; } + info->toc = toc; } /* Check to see if the existing data is still valid. @@ -2240,7 +2239,8 @@ static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense) /* First read just the header, so we know how long the TOC is. */ stat = cdrom_read_tocentry(drive, 0, 1, 0, (char *) &toc->hdr, sizeof(struct atapi_toc_header), sense); - if (stat) return stat; + if (stat) + return stat; #if ! STANDARD_ATAPI if (CDROM_CONFIG_FLAGS(drive)->toctracks_as_bcd) { @@ -2324,7 +2324,8 @@ static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense) /* Read the multisession information. */ stat = cdrom_read_tocentry(drive, 0, 0, 1, (char *)&ms_tmp, sizeof(ms_tmp), sense); - if (stat) return stat; + if (stat) + return stat; toc->last_session_lba = be32_to_cpu(ms_tmp.ent.addr.lba); } else { @@ -2460,7 +2461,7 @@ static int ide_cdrom_packet(struct cdrom_device_info *cdi, struct packet_command *cgc) { struct request req; - ide_drive_t *drive = (ide_drive_t*) cdi->handle; + ide_drive_t *drive = cdi->handle; if (cgc->timeout <= 0) cgc->timeout = ATAPI_WAIT_PC; @@ -2537,7 +2538,7 @@ int ide_cdrom_audio_ioctl (struct cdrom_device_info *cdi, unsigned int cmd, void *arg) { - ide_drive_t *drive = (ide_drive_t*) cdi->handle; + ide_drive_t *drive = cdi->handle; struct cdrom_info *info = drive->driver_data; int stat; @@ -2548,7 +2549,7 @@ int ide_cdrom_audio_ioctl (struct cdrom_device_info *cdi, */ case CDROMPLAYTRKIND: { unsigned long lba_start, lba_end; - struct cdrom_ti *ti = (struct cdrom_ti *)arg; + struct cdrom_ti *ti = arg; struct atapi_toc_entry *first_toc, *last_toc; stat = cdrom_get_toc_entry(drive, ti->cdti_trk0, &first_toc); @@ -2571,12 +2572,13 @@ int ide_cdrom_audio_ioctl (struct cdrom_device_info *cdi, } case CDROMREADTOCHDR: { - struct cdrom_tochdr *tochdr = (struct cdrom_tochdr *) arg; + struct cdrom_tochdr *tochdr = arg; struct atapi_toc *toc; /* Make sure our saved TOC is valid. */ stat = cdrom_read_toc(drive, NULL); - if (stat) return stat; + if (stat) + return stat; toc = info->toc; tochdr->cdth_trk0 = toc->hdr.first_track; @@ -2586,11 +2588,12 @@ int ide_cdrom_audio_ioctl (struct cdrom_device_info *cdi, } case CDROMREADTOCENTRY: { - struct cdrom_tocentry *tocentry = (struct cdrom_tocentry*) arg; + struct cdrom_tocentry *tocentry = arg; struct atapi_toc_entry *toce; stat = cdrom_get_toc_entry(drive, tocentry->cdte_track, &toce); - if (stat) return stat; + if (stat) + return stat; tocentry->cdte_ctrl = toce->control; tocentry->cdte_adr = toce->adr; @@ -2613,7 +2616,7 @@ int ide_cdrom_audio_ioctl (struct cdrom_device_info *cdi, static int ide_cdrom_reset (struct cdrom_device_info *cdi) { - ide_drive_t *drive = (ide_drive_t*) cdi->handle; + ide_drive_t *drive = cdi->handle; struct request_sense sense; struct request req; int ret; @@ -2636,12 +2639,13 @@ int ide_cdrom_reset (struct cdrom_device_info *cdi) static int ide_cdrom_tray_move (struct cdrom_device_info *cdi, int position) { - ide_drive_t *drive = (ide_drive_t*) cdi->handle; + ide_drive_t *drive = cdi->handle; struct request_sense sense; if (position) { int stat = cdrom_lockdoor(drive, 0, &sense); - if (stat) return stat; + if (stat) + return stat; } return cdrom_eject(drive, !position, &sense); @@ -2650,7 +2654,7 @@ int ide_cdrom_tray_move (struct cdrom_device_info *cdi, int position) static int ide_cdrom_lock_door (struct cdrom_device_info *cdi, int lock) { - ide_drive_t *drive = (ide_drive_t*) cdi->handle; + ide_drive_t *drive = cdi->handle; return cdrom_lockdoor(drive, lock, NULL); } @@ -2700,7 +2704,7 @@ void ide_cdrom_update_speed (ide_drive_t *drive, struct atapi_capabilities_page static int ide_cdrom_select_speed (struct cdrom_device_info *cdi, int speed) { - ide_drive_t *drive = (ide_drive_t*) cdi->handle; + ide_drive_t *drive = cdi->handle; struct request_sense sense; struct atapi_capabilities_page cap; int stat; @@ -2723,7 +2727,7 @@ int ide_cdrom_select_speed (struct cdrom_device_info *cdi, int speed) static int ide_cdrom_drive_status (struct cdrom_device_info *cdi, int slot_nr) { - ide_drive_t *drive = (ide_drive_t*) cdi->handle; + ide_drive_t *drive = cdi->handle; struct media_event_desc med; struct request_sense sense; int stat; @@ -2769,7 +2773,7 @@ int ide_cdrom_get_last_session (struct cdrom_device_info *cdi, struct cdrom_multisession *ms_info) { struct atapi_toc *toc; - ide_drive_t *drive = (ide_drive_t*) cdi->handle; + ide_drive_t *drive = cdi->handle; struct cdrom_info *info = drive->driver_data; struct request_sense sense; int ret; @@ -2791,7 +2795,7 @@ int ide_cdrom_get_mcn (struct cdrom_device_info *cdi, { int stat; char mcnbuf[24]; - ide_drive_t *drive = (ide_drive_t*) cdi->handle; + ide_drive_t *drive = cdi->handle; /* get MCN */ if ((stat = cdrom_read_subchannel(drive, 2, mcnbuf, sizeof (mcnbuf), NULL))) @@ -2815,7 +2819,7 @@ static int ide_cdrom_check_media_change_real (struct cdrom_device_info *cdi, int slot_nr) { - ide_drive_t *drive = (ide_drive_t*) cdi->handle; + ide_drive_t *drive = cdi->handle; int retval; if (slot_nr == CDSL_CURRENT) { @@ -2886,7 +2890,7 @@ static int ide_cdrom_register (ide_drive_t *drive, int nslots) devinfo->mask = 0; devinfo->speed = CDROM_STATE_FLAGS(drive)->current_speed; devinfo->capacity = nslots; - devinfo->handle = (void *) drive; + devinfo->handle = drive; strcpy(devinfo->name, drive->name); /* set capability mask to match the probe. */ @@ -2942,7 +2946,7 @@ int ide_cdrom_probe_capabilities (ide_drive_t *drive) * registered with the Uniform layer yet, it can't do this. * Same goes for cdi->ops. */ - cdi->handle = (ide_drive_t *) drive; + cdi->handle = drive; cdi->ops = &ide_cdrom_dops; if (ide_cdrom_get_capabilities(drive, &cap)) @@ -3254,6 +3258,7 @@ int ide_cdrom_setup (ide_drive_t *drive) return 0; } +#ifdef CONFIG_PROC_FS static sector_t ide_cdrom_capacity (ide_drive_t *drive) { @@ -3264,6 +3269,7 @@ sector_t ide_cdrom_capacity (ide_drive_t *drive) return capacity * sectors_per_frame; } +#endif static int ide_cd_remove(struct device *dev) { @@ -3309,7 +3315,7 @@ static int ide_cd_probe(struct device *); static int proc_idecd_read_capacity (char *page, char **start, off_t off, int count, int *eof, void *data) { - ide_drive_t*drive = (ide_drive_t *)data; + ide_drive_t *drive = data; int len; len = sprintf(page,"%llu\n", (long long)ide_cdrom_capacity(drive)); @@ -3449,7 +3455,7 @@ static int ide_cd_probe(struct device *dev) printk(KERN_INFO "ide-cd: passing drive %s to ide-scsi emulation.\n", drive->name); goto failed; } - info = (struct cdrom_info *) kmalloc (sizeof (struct cdrom_info), GFP_KERNEL); + info = kmalloc(sizeof(struct cdrom_info), GFP_KERNEL); if (info == NULL) { printk(KERN_ERR "%s: Can't allocate a cdrom structure\n", drive->name); goto failed; diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c index 4063d2c34e3d..84665e2ba3c8 100644 --- a/drivers/ide/ide-proc.c +++ b/drivers/ide/ide-proc.c @@ -64,6 +64,7 @@ static int proc_ide_read_imodel case ide_cy82c693: name = "cy82c693"; break; case ide_4drives: name = "4drives"; break; case ide_pmac: name = "mac-io"; break; + case ide_au1xxx: name = "au1xxx"; break; default: name = "(unknown)"; break; } len = sprintf(page, "%s\n", name); diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index ee38e6b143a4..47f2b832555f 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -1013,6 +1013,8 @@ typedef struct ide_tape_obj { static DECLARE_MUTEX(idetape_ref_sem); +static struct class *idetape_sysfs_class; + #define to_ide_tape(obj) container_of(obj, struct ide_tape_obj, kref) #define ide_tape_g(disk) \ @@ -4704,6 +4706,10 @@ static void ide_tape_release(struct kref *kref) drive->dsc_overlap = 0; drive->driver_data = NULL; + class_device_destroy(idetape_sysfs_class, + MKDEV(IDETAPE_MAJOR, tape->minor)); + class_device_destroy(idetape_sysfs_class, + MKDEV(IDETAPE_MAJOR, tape->minor + 128)); devfs_remove("%s/mt", drive->devfs_name); devfs_remove("%s/mtn", drive->devfs_name); devfs_unregister_tape(g->number); @@ -4878,6 +4884,11 @@ static int ide_tape_probe(struct device *dev) idetape_setup(drive, tape, minor); + class_device_create(idetape_sysfs_class, NULL, + MKDEV(IDETAPE_MAJOR, minor), dev, "%s", tape->name); + class_device_create(idetape_sysfs_class, NULL, + MKDEV(IDETAPE_MAJOR, minor + 128), dev, "n%s", tape->name); + devfs_mk_cdev(MKDEV(HWIF(drive)->major, minor), S_IFCHR | S_IRUGO | S_IWUGO, "%s/mt", drive->devfs_name); @@ -4903,6 +4914,7 @@ MODULE_LICENSE("GPL"); static void __exit idetape_exit (void) { driver_unregister(&idetape_driver.gen_driver); + class_destroy(idetape_sysfs_class); unregister_chrdev(IDETAPE_MAJOR, "ht"); } @@ -4911,11 +4923,33 @@ static void __exit idetape_exit (void) */ static int idetape_init (void) { + int error = 1; + idetape_sysfs_class = class_create(THIS_MODULE, "ide_tape"); + if (IS_ERR(idetape_sysfs_class)) { + idetape_sysfs_class = NULL; + printk(KERN_ERR "Unable to create sysfs class for ide tapes\n"); + error = -EBUSY; + goto out; + } + if (register_chrdev(IDETAPE_MAJOR, "ht", &idetape_fops)) { printk(KERN_ERR "ide-tape: Failed to register character device interface\n"); - return -EBUSY; + error = -EBUSY; + goto out_free_class; } - return driver_register(&idetape_driver.gen_driver); + + error = driver_register(&idetape_driver.gen_driver); + if (error) + goto out_free_driver; + + return 0; + +out_free_driver: + driver_unregister(&idetape_driver.gen_driver); +out_free_class: + class_destroy(idetape_sysfs_class); +out: + return error; } module_init(idetape_init); diff --git a/drivers/ide/mips/au1xxx-ide.c b/drivers/ide/mips/au1xxx-ide.c new file mode 100644 index 000000000000..2b6327c576b9 --- /dev/null +++ b/drivers/ide/mips/au1xxx-ide.c @@ -0,0 +1,1250 @@ +/* + * linux/drivers/ide/mips/au1xxx-ide.c version 01.30.00 Aug. 02 2005 + * + * BRIEF MODULE DESCRIPTION + * AMD Alchemy Au1xxx IDE interface routines over the Static Bus + * + * Copyright (c) 2003-2005 AMD, Personal Connectivity Solutions + * + * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Note: for more information, please refer "AMD Alchemy Au1200/Au1550 IDE + * Interface and Linux Device Driver" Application Note. + */ +#undef REALLY_SLOW_IO /* most systems can safely undef this */ + +#include <linux/config.h> /* for CONFIG_BLK_DEV_IDEPCI */ +#include <linux/types.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/timer.h> +#include <linux/mm.h> +#include <linux/ioport.h> +#include <linux/hdreg.h> +#include <linux/init.h> +#include <linux/ide.h> +#include <linux/sysdev.h> + +#include <linux/dma-mapping.h> + +#include <asm/io.h> +#include <asm/mach-au1x00/au1xxx.h> +#include <asm/mach-au1x00/au1xxx_dbdma.h> + +#if CONFIG_PM +#include <asm/mach-au1x00/au1xxx_pm.h> +#endif + +#include <asm/mach-au1x00/au1xxx_ide.h> + +#define DRV_NAME "au1200-ide" +#define DRV_VERSION "1.0" +#define DRV_AUTHOR "AMD PCS / Pete Popov <ppopov@embeddedalley.com>" +#define DRV_DESC "Au1200 IDE" + +static _auide_hwif auide_hwif; +static spinlock_t ide_tune_drive_spin_lock = SPIN_LOCK_UNLOCKED; +static spinlock_t ide_tune_chipset_spin_lock = SPIN_LOCK_UNLOCKED; +static int dbdma_init_done = 0; + +/* + * local I/O functions + */ +u8 auide_inb(unsigned long port) +{ + return (au_readb(port)); +} + +u16 auide_inw(unsigned long port) +{ + return (au_readw(port)); +} + +u32 auide_inl(unsigned long port) +{ + return (au_readl(port)); +} + +void auide_insw(unsigned long port, void *addr, u32 count) +{ +#if defined(CONFIG_BLK_DEV_IDE_AU1XXX_PIO_DBDMA) + + _auide_hwif *ahwif = &auide_hwif; + chan_tab_t *ctp; + au1x_ddma_desc_t *dp; + + if(!put_dest_flags(ahwif->rx_chan, (void*)addr, count << 1, + DDMA_FLAGS_NOIE)) { + printk(KERN_ERR "%s failed %d\n", __FUNCTION__, __LINE__); + return; + } + ctp = *((chan_tab_t **)ahwif->rx_chan); + dp = ctp->cur_ptr; + while (dp->dscr_cmd0 & DSCR_CMD0_V) + ; + ctp->cur_ptr = au1xxx_ddma_get_nextptr_virt(dp); +#else + while (count--) + { + *(u16 *)addr = au_readw(port); + addr +=2 ; + } +#endif +} + +void auide_insl(unsigned long port, void *addr, u32 count) +{ + while (count--) + { + *(u32 *)addr = au_readl(port); + /* NOTE: For IDE interfaces over PCMCIA, + * 32-bit access does not work + */ + addr += 4; + } +} + +void auide_outb(u8 addr, unsigned long port) +{ + return (au_writeb(addr, port)); +} + +void auide_outbsync(ide_drive_t *drive, u8 addr, unsigned long port) +{ + return (au_writeb(addr, port)); +} + +void auide_outw(u16 addr, unsigned long port) +{ + return (au_writew(addr, port)); +} + +void auide_outl(u32 addr, unsigned long port) +{ + return (au_writel(addr, port)); +} + +void auide_outsw(unsigned long port, void *addr, u32 count) +{ +#if defined(CONFIG_BLK_DEV_IDE_AU1XXX_PIO_DBDMA) + _auide_hwif *ahwif = &auide_hwif; + chan_tab_t *ctp; + au1x_ddma_desc_t *dp; + + if(!put_source_flags(ahwif->tx_chan, (void*)addr, + count << 1, DDMA_FLAGS_NOIE)) { + printk(KERN_ERR "%s failed %d\n", __FUNCTION__, __LINE__); + return; + } + ctp = *((chan_tab_t **)ahwif->tx_chan); + dp = ctp->cur_ptr; + while (dp->dscr_cmd0 & DSCR_CMD0_V) + ; + ctp->cur_ptr = au1xxx_ddma_get_nextptr_virt(dp); +#else + while (count--) + { + au_writew(*(u16 *)addr, port); + addr += 2; + } +#endif +} + +void auide_outsl(unsigned long port, void *addr, u32 count) +{ + while (count--) + { + au_writel(*(u32 *)addr, port); + /* NOTE: For IDE interfaces over PCMCIA, + * 32-bit access does not work + */ + addr += 4; + } +} + +static void auide_tune_drive(ide_drive_t *drive, byte pio) +{ + int mem_sttime; + int mem_stcfg; + unsigned long flags; + u8 speed; + + /* get the best pio mode for the drive */ + pio = ide_get_best_pio_mode(drive, pio, 4, NULL); + + printk("%s: setting Au1XXX IDE to PIO mode%d\n", + drive->name, pio); + + spin_lock_irqsave(&ide_tune_drive_spin_lock, flags); + + mem_sttime = 0; + mem_stcfg = au_readl(MEM_STCFG2); + + /* set pio mode! */ + switch(pio) { + case 0: + /* set timing parameters for RCS2# */ + mem_sttime = SBC_IDE_PIO0_TWCS + | SBC_IDE_PIO0_TCSH + | SBC_IDE_PIO0_TCSOFF + | SBC_IDE_PIO0_TWP + | SBC_IDE_PIO0_TCSW + | SBC_IDE_PIO0_TPM + | SBC_IDE_PIO0_TA; + /* set configuration for RCS2# */ + mem_stcfg |= TS_MASK; + mem_stcfg &= ~TCSOE_MASK; + mem_stcfg &= ~TOECS_MASK; + mem_stcfg |= SBC_IDE_PIO0_TCSOE | SBC_IDE_PIO0_TOECS; + + au_writel(mem_sttime,MEM_STTIME2); + au_writel(mem_stcfg,MEM_STCFG2); + break; + + case 1: + /* set timing parameters for RCS2# */ + mem_sttime = SBC_IDE_PIO1_TWCS + | SBC_IDE_PIO1_TCSH + | SBC_IDE_PIO1_TCSOFF + | SBC_IDE_PIO1_TWP + | SBC_IDE_PIO1_TCSW + | SBC_IDE_PIO1_TPM + | SBC_IDE_PIO1_TA; + /* set configuration for RCS2# */ + mem_stcfg |= TS_MASK; + mem_stcfg &= ~TCSOE_MASK; + mem_stcfg &= ~TOECS_MASK; + mem_stcfg |= SBC_IDE_PIO1_TCSOE | SBC_IDE_PIO1_TOECS; + break; + + case 2: + /* set timing parameters for RCS2# */ + mem_sttime = SBC_IDE_PIO2_TWCS + | SBC_IDE_PIO2_TCSH + | SBC_IDE_PIO2_TCSOFF + | SBC_IDE_PIO2_TWP + | SBC_IDE_PIO2_TCSW + | SBC_IDE_PIO2_TPM + | SBC_IDE_PIO2_TA; + /* set configuration for RCS2# */ + mem_stcfg &= ~TS_MASK; + mem_stcfg &= ~TCSOE_MASK; + mem_stcfg &= ~TOECS_MASK; + mem_stcfg |= SBC_IDE_PIO2_TCSOE | SBC_IDE_PIO2_TOECS; + break; + + case 3: + /* set timing parameters for RCS2# */ + mem_sttime = SBC_IDE_PIO3_TWCS + | SBC_IDE_PIO3_TCSH + | SBC_IDE_PIO3_TCSOFF + | SBC_IDE_PIO3_TWP + | SBC_IDE_PIO3_TCSW + | SBC_IDE_PIO3_TPM + | SBC_IDE_PIO3_TA; + /* set configuration for RCS2# */ + mem_stcfg |= TS_MASK; + mem_stcfg &= ~TS_MASK; + mem_stcfg &= ~TCSOE_MASK; + mem_stcfg &= ~TOECS_MASK; + mem_stcfg |= SBC_IDE_PIO3_TCSOE | SBC_IDE_PIO3_TOECS; + + break; + + case 4: + /* set timing parameters for RCS2# */ + mem_sttime = SBC_IDE_PIO4_TWCS + | SBC_IDE_PIO4_TCSH + | SBC_IDE_PIO4_TCSOFF + | SBC_IDE_PIO4_TWP + | SBC_IDE_PIO4_TCSW + | SBC_IDE_PIO4_TPM + | SBC_IDE_PIO4_TA; + /* set configuration for RCS2# */ + mem_stcfg &= ~TS_MASK; + mem_stcfg &= ~TCSOE_MASK; + mem_stcfg &= ~TOECS_MASK; + mem_stcfg |= SBC_IDE_PIO4_TCSOE | SBC_IDE_PIO4_TOECS; + break; + } + + au_writel(mem_sttime,MEM_STTIME2); + au_writel(mem_stcfg,MEM_STCFG2); + + spin_unlock_irqrestore(&ide_tune_drive_spin_lock, flags); + + speed = pio + XFER_PIO_0; + ide_config_drive_speed(drive, speed); +} + +static int auide_tune_chipset (ide_drive_t *drive, u8 speed) +{ + u8 mode = 0; + int mem_sttime; + int mem_stcfg; + unsigned long flags; +#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA + struct hd_driveid *id = drive->id; + + /* + * Now see what the current drive is capable of, + * selecting UDMA only if the mate said it was ok. + */ + if (id && (id->capability & 1) && drive->autodma && + !__ide_dma_bad_drive(drive)) { + if (!mode && (id->field_valid & 2) && (id->dma_mword & 7)) { + if (id->dma_mword & 4) + mode = XFER_MW_DMA_2; + else if (id->dma_mword & 2) + mode = XFER_MW_DMA_1; + else if (id->dma_mword & 1) + mode = XFER_MW_DMA_0; + } + } +#endif + + spin_lock_irqsave(&ide_tune_chipset_spin_lock, flags); + + mem_sttime = 0; + mem_stcfg = au_readl(MEM_STCFG2); + + switch(speed) { + case XFER_PIO_4: + case XFER_PIO_3: + case XFER_PIO_2: + case XFER_PIO_1: + case XFER_PIO_0: + auide_tune_drive(drive, (speed - XFER_PIO_0)); + break; +#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA + case XFER_MW_DMA_2: + /* set timing parameters for RCS2# */ + mem_sttime = SBC_IDE_MDMA2_TWCS + | SBC_IDE_MDMA2_TCSH + | SBC_IDE_MDMA2_TCSOFF + | SBC_IDE_MDMA2_TWP + | SBC_IDE_MDMA2_TCSW + | SBC_IDE_MDMA2_TPM + | SBC_IDE_MDMA2_TA; + /* set configuration for RCS2# */ + mem_stcfg &= ~TS_MASK; + mem_stcfg &= ~TCSOE_MASK; + mem_stcfg &= ~TOECS_MASK; + mem_stcfg |= SBC_IDE_MDMA2_TCSOE | SBC_IDE_MDMA2_TOECS; + + mode = XFER_MW_DMA_2; + break; + case XFER_MW_DMA_1: + /* set timing parameters for RCS2# */ + mem_sttime = SBC_IDE_MDMA1_TWCS + | SBC_IDE_MDMA1_TCSH + | SBC_IDE_MDMA1_TCSOFF + | SBC_IDE_MDMA1_TWP + | SBC_IDE_MDMA1_TCSW + | SBC_IDE_MDMA1_TPM + | SBC_IDE_MDMA1_TA; + /* set configuration for RCS2# */ + mem_stcfg &= ~TS_MASK; + mem_stcfg &= ~TCSOE_MASK; + mem_stcfg &= ~TOECS_MASK; + mem_stcfg |= SBC_IDE_MDMA1_TCSOE | SBC_IDE_MDMA1_TOECS; + + mode = XFER_MW_DMA_1; + break; + case XFER_MW_DMA_0: + /* set timing parameters for RCS2# */ + mem_sttime = SBC_IDE_MDMA0_TWCS + | SBC_IDE_MDMA0_TCSH + | SBC_IDE_MDMA0_TCSOFF + | SBC_IDE_MDMA0_TWP + | SBC_IDE_MDMA0_TCSW + | SBC_IDE_MDMA0_TPM + | SBC_IDE_MDMA0_TA; + /* set configuration for RCS2# */ + mem_stcfg |= TS_MASK; + mem_stcfg &= ~TCSOE_MASK; + mem_stcfg &= ~TOECS_MASK; + mem_stcfg |= SBC_IDE_MDMA0_TCSOE | SBC_IDE_MDMA0_TOECS; + + mode = XFER_MW_DMA_0; + break; +#endif + default: + return 1; + } + + /* + * Tell the drive to switch to the new mode; abort on failure. + */ + if (!mode || ide_config_drive_speed(drive, mode)) + { + return 1; /* failure */ + } + + + au_writel(mem_sttime,MEM_STTIME2); + au_writel(mem_stcfg,MEM_STCFG2); + + spin_unlock_irqrestore(&ide_tune_chipset_spin_lock, flags); + + return 0; +} + +/* + * Multi-Word DMA + DbDMA functions + */ +#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA + +static int in_drive_list(struct hd_driveid *id, + const struct drive_list_entry *drive_table) +{ + for ( ; drive_table->id_model ; drive_table++){ + if ((!strcmp(drive_table->id_model, id->model)) && + ((strstr(drive_table->id_firmware, id->fw_rev)) || + (!strcmp(drive_table->id_firmware, "ALL"))) + ) + return 1; + } + return 0; +} + +static int auide_build_sglist(ide_drive_t *drive, struct request *rq) +{ + ide_hwif_t *hwif = drive->hwif; + _auide_hwif *ahwif = (_auide_hwif*)hwif->hwif_data; + struct scatterlist *sg = hwif->sg_table; + + ide_map_sg(drive, rq); + + if (rq_data_dir(rq) == READ) + hwif->sg_dma_direction = DMA_FROM_DEVICE; + else + hwif->sg_dma_direction = DMA_TO_DEVICE; + + return dma_map_sg(ahwif->dev, sg, hwif->sg_nents, + hwif->sg_dma_direction); +} + +static int auide_build_dmatable(ide_drive_t *drive) +{ + int i, iswrite, count = 0; + ide_hwif_t *hwif = HWIF(drive); + + struct request *rq = HWGROUP(drive)->rq; + + _auide_hwif *ahwif = (_auide_hwif*)hwif->hwif_data; + struct scatterlist *sg; + + iswrite = (rq_data_dir(rq) == WRITE); + /* Save for interrupt context */ + ahwif->drive = drive; + + /* Build sglist */ + hwif->sg_nents = i = auide_build_sglist(drive, rq); + + if (!i) + return 0; + + /* fill the descriptors */ + sg = hwif->sg_table; + while (i && sg_dma_len(sg)) { + u32 cur_addr; + u32 cur_len; + + cur_addr = sg_dma_address(sg); + cur_len = sg_dma_len(sg); + + while (cur_len) { + u32 flags = DDMA_FLAGS_NOIE; + unsigned int tc = (cur_len < 0xfe00)? cur_len: 0xfe00; + + if (++count >= PRD_ENTRIES) { + printk(KERN_WARNING "%s: DMA table too small\n", + drive->name); + goto use_pio_instead; + } + + /* Lets enable intr for the last descriptor only */ + if (1==i) + flags = DDMA_FLAGS_IE; + else + flags = DDMA_FLAGS_NOIE; + + if (iswrite) { + if(!put_source_flags(ahwif->tx_chan, + (void*)(page_address(sg->page) + + sg->offset), + tc, flags)) { + printk(KERN_ERR "%s failed %d\n", + __FUNCTION__, __LINE__); + } + } else + { + if(!put_dest_flags(ahwif->rx_chan, + (void*)(page_address(sg->page) + + sg->offset), + tc, flags)) { + printk(KERN_ERR "%s failed %d\n", + __FUNCTION__, __LINE__); + } + } + + cur_addr += tc; + cur_len -= tc; + } + sg++; + i--; + } + + if (count) + return 1; + +use_pio_instead: + dma_unmap_sg(ahwif->dev, + hwif->sg_table, + hwif->sg_nents, + hwif->sg_dma_direction); + + return 0; /* revert to PIO for this request */ +} + +static int auide_dma_end(ide_drive_t *drive) +{ + ide_hwif_t *hwif = HWIF(drive); + _auide_hwif *ahwif = (_auide_hwif*)hwif->hwif_data; + + if (hwif->sg_nents) { + dma_unmap_sg(ahwif->dev, hwif->sg_table, hwif->sg_nents, + hwif->sg_dma_direction); + hwif->sg_nents = 0; + } + + return 0; +} + +static void auide_dma_start(ide_drive_t *drive ) +{ +// printk("%s\n", __FUNCTION__); +} + +ide_startstop_t auide_dma_intr(ide_drive_t *drive) +{ + //printk("%s\n", __FUNCTION__); + + u8 stat = 0, dma_stat = 0; + + dma_stat = HWIF(drive)->ide_dma_end(drive); + stat = HWIF(drive)->INB(IDE_STATUS_REG); /* get drive status */ + if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) { + if (!dma_stat) { + struct request *rq = HWGROUP(drive)->rq; + + ide_end_request(drive, 1, rq->nr_sectors); + return ide_stopped; + } + printk(KERN_ERR "%s: dma_intr: bad DMA status (dma_stat=%x)\n", + drive->name, dma_stat); + } + return ide_error(drive, "dma_intr", stat); +} + +static void auide_dma_exec_cmd(ide_drive_t *drive, u8 command) +{ + //printk("%s\n", __FUNCTION__); + + /* issue cmd to drive */ + ide_execute_command(drive, command, &auide_dma_intr, + (2*WAIT_CMD), NULL); +} + +static int auide_dma_setup(ide_drive_t *drive) +{ +// printk("%s\n", __FUNCTION__); + + if (drive->media != ide_disk) + return 1; + + if (!auide_build_dmatable(drive)) + /* try PIO instead of DMA */ + return 1; + + drive->waiting_for_dma = 1; + + return 0; +} + +static int auide_dma_check(ide_drive_t *drive) +{ +// printk("%s\n", __FUNCTION__); + +#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA + if( !dbdma_init_done ){ + auide_hwif.white_list = in_drive_list(drive->id, + dma_white_list); + auide_hwif.black_list = in_drive_list(drive->id, + dma_black_list); + auide_hwif.drive = drive; + auide_ddma_init(&auide_hwif); + dbdma_init_done = 1; + } +#endif + + /* Is the drive in our DMA black list? */ + if ( auide_hwif.black_list ) { + drive->using_dma = 0; + printk("%s found in dma_blacklist[]! Disabling DMA.\n", + drive->id->model); + } + else + drive->using_dma = 1; + + return HWIF(drive)->ide_dma_host_on(drive); +} + +static int auide_dma_test_irq(ide_drive_t *drive) +{ +// printk("%s\n", __FUNCTION__); + + if (!drive->waiting_for_dma) + printk(KERN_WARNING "%s: ide_dma_test_irq \ + called while not waiting\n", drive->name); + + /* If dbdma didn't execute the STOP command yet, the + * active bit is still set + */ + drive->waiting_for_dma++; + if (drive->waiting_for_dma >= DMA_WAIT_TIMEOUT) { + printk(KERN_WARNING "%s: timeout waiting for ddma to \ + complete\n", drive->name); + return 1; + } + udelay(10); + return 0; +} + +static int auide_dma_host_on(ide_drive_t *drive) +{ +// printk("%s\n", __FUNCTION__); + return 0; +} + +static int auide_dma_on(ide_drive_t *drive) +{ +// printk("%s\n", __FUNCTION__); + drive->using_dma = 1; + return auide_dma_host_on(drive); +} + + +static int auide_dma_host_off(ide_drive_t *drive) +{ +// printk("%s\n", __FUNCTION__); + return 0; +} + +static int auide_dma_off_quietly(ide_drive_t *drive) +{ +// printk("%s\n", __FUNCTION__); + drive->using_dma = 0; + return auide_dma_host_off(drive); +} + +static int auide_dma_lostirq(ide_drive_t *drive) +{ +// printk("%s\n", __FUNCTION__); + + printk(KERN_ERR "%s: IRQ lost\n", drive->name); + return 0; +} + +static void auide_ddma_tx_callback(int irq, void *param, struct pt_regs *regs) +{ +// printk("%s\n", __FUNCTION__); + + _auide_hwif *ahwif = (_auide_hwif*)param; + ahwif->drive->waiting_for_dma = 0; + return; +} + +static void auide_ddma_rx_callback(int irq, void *param, struct pt_regs *regs) +{ +// printk("%s\n", __FUNCTION__); + + _auide_hwif *ahwif = (_auide_hwif*)param; + ahwif->drive->waiting_for_dma = 0; + return; +} + +static int auide_dma_timeout(ide_drive_t *drive) +{ +// printk("%s\n", __FUNCTION__); + + printk(KERN_ERR "%s: DMA timeout occurred: ", drive->name); + + if (HWIF(drive)->ide_dma_test_irq(drive)) + return 0; + + return HWIF(drive)->ide_dma_end(drive); +} +#endif /* end CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA */ + + +static int auide_ddma_init( _auide_hwif *auide ) +{ +// printk("%s\n", __FUNCTION__); + + dbdev_tab_t source_dev_tab; +#if defined(CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA) + dbdev_tab_t target_dev_tab; + ide_hwif_t *hwif = auide->hwif; + char warning_output [2][80]; + int i; +#endif + + /* Add our custom device to DDMA device table */ + /* Create our new device entries in the table */ +#if defined(CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA) + source_dev_tab.dev_id = AU1XXX_ATA_DDMA_REQ; + + if( auide->white_list || auide->black_list ){ + source_dev_tab.dev_tsize = 8; + source_dev_tab.dev_devwidth = 32; + source_dev_tab.dev_physaddr = (u32)AU1XXX_ATA_PHYS_ADDR; + source_dev_tab.dev_intlevel = 0; + source_dev_tab.dev_intpolarity = 0; + + /* init device table for target - static bus controller - */ + target_dev_tab.dev_id = DSCR_CMD0_ALWAYS; + target_dev_tab.dev_tsize = 8; + target_dev_tab.dev_devwidth = 32; + target_dev_tab.dev_physaddr = (u32)AU1XXX_ATA_PHYS_ADDR; + target_dev_tab.dev_intlevel = 0; + target_dev_tab.dev_intpolarity = 0; + target_dev_tab.dev_flags = DEV_FLAGS_ANYUSE; + } + else{ + source_dev_tab.dev_tsize = 1; + source_dev_tab.dev_devwidth = 16; + source_dev_tab.dev_physaddr = (u32)AU1XXX_ATA_PHYS_ADDR; + source_dev_tab.dev_intlevel = 0; + source_dev_tab.dev_intpolarity = 0; + + /* init device table for target - static bus controller - */ + target_dev_tab.dev_id = DSCR_CMD0_ALWAYS; + target_dev_tab.dev_tsize = 1; + target_dev_tab.dev_devwidth = 16; + target_dev_tab.dev_physaddr = (u32)AU1XXX_ATA_PHYS_ADDR; + target_dev_tab.dev_intlevel = 0; + target_dev_tab.dev_intpolarity = 0; + target_dev_tab.dev_flags = DEV_FLAGS_ANYUSE; + + sprintf(&warning_output[0][0], + "%s is not on ide driver white list.", + auide_hwif.drive->id->model); + for ( i=strlen(&warning_output[0][0]) ; i<76; i++ ){ + sprintf(&warning_output[0][i]," "); + } + + sprintf(&warning_output[1][0], + "To add %s please read 'Documentation/mips/AU1xxx_IDE.README'.", + auide_hwif.drive->id->model); + for ( i=strlen(&warning_output[1][0]) ; i<76; i++ ){ + sprintf(&warning_output[1][i]," "); + } + + printk("\n****************************************"); + printk("****************************************\n"); + printk("* %s *\n",&warning_output[0][0]); + printk("* Switch to safe MWDMA Mode! "); + printk(" *\n"); + printk("* %s *\n",&warning_output[1][0]); + printk("****************************************"); + printk("****************************************\n\n"); + } +#else + source_dev_tab.dev_id = DSCR_CMD0_ALWAYS; + source_dev_tab.dev_tsize = 8; + source_dev_tab.dev_devwidth = 32; + source_dev_tab.dev_physaddr = (u32)AU1XXX_ATA_PHYS_ADDR; + source_dev_tab.dev_intlevel = 0; + source_dev_tab.dev_intpolarity = 0; +#endif + +#if CONFIG_BLK_DEV_IDE_AU1XXX_BURSTABLE_ON + /* set flags for tx channel */ + source_dev_tab.dev_flags = DEV_FLAGS_OUT + | DEV_FLAGS_SYNC + | DEV_FLAGS_BURSTABLE; + auide->tx_dev_id = au1xxx_ddma_add_device( &source_dev_tab ); + /* set flags for rx channel */ + source_dev_tab.dev_flags = DEV_FLAGS_IN + | DEV_FLAGS_SYNC + | DEV_FLAGS_BURSTABLE; + auide->rx_dev_id = au1xxx_ddma_add_device( &source_dev_tab ); +#else + /* set flags for tx channel */ + source_dev_tab.dev_flags = DEV_FLAGS_OUT | DEV_FLAGS_SYNC; + auide->tx_dev_id = au1xxx_ddma_add_device( &source_dev_tab ); + /* set flags for rx channel */ + source_dev_tab.dev_flags = DEV_FLAGS_IN | DEV_FLAGS_SYNC; + auide->rx_dev_id = au1xxx_ddma_add_device( &source_dev_tab ); +#endif + +#if defined(CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA) + + auide->target_dev_id = au1xxx_ddma_add_device(&target_dev_tab); + + /* Get a channel for TX */ + auide->tx_chan = au1xxx_dbdma_chan_alloc(auide->target_dev_id, + auide->tx_dev_id, + auide_ddma_tx_callback, + (void*)auide); + /* Get a channel for RX */ + auide->rx_chan = au1xxx_dbdma_chan_alloc(auide->rx_dev_id, + auide->target_dev_id, + auide_ddma_rx_callback, + (void*)auide); +#else /* CONFIG_BLK_DEV_IDE_AU1XXX_PIO_DBDMA */ + /* + * Note: if call back is not enabled, update ctp->cur_ptr manually + */ + auide->tx_chan = au1xxx_dbdma_chan_alloc(DSCR_CMD0_ALWAYS, + auide->tx_dev_id, + NULL, + (void*)auide); + auide->rx_chan = au1xxx_dbdma_chan_alloc(auide->rx_dev_id, + DSCR_CMD0_ALWAYS, + NULL, + (void*)auide); +#endif + auide->tx_desc_head = (void*)au1xxx_dbdma_ring_alloc(auide->tx_chan, + NUM_DESCRIPTORS); + auide->rx_desc_head = (void*)au1xxx_dbdma_ring_alloc(auide->rx_chan, + NUM_DESCRIPTORS); + +#if defined(CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA) + hwif->dmatable_cpu = dma_alloc_coherent(auide->dev, + PRD_ENTRIES * PRD_BYTES, /* 1 Page */ + &hwif->dmatable_dma, GFP_KERNEL); + + auide->sg_table = kmalloc(sizeof(struct scatterlist) * PRD_ENTRIES, + GFP_KERNEL|GFP_DMA); + if (auide->sg_table == NULL) { + return -ENOMEM; + } +#endif + au1xxx_dbdma_start( auide->tx_chan ); + au1xxx_dbdma_start( auide->rx_chan ); + return 0; +} + +static void auide_setup_ports(hw_regs_t *hw, _auide_hwif *ahwif) +{ + int i; +#define ide_ioreg_t unsigned long + ide_ioreg_t *ata_regs = hw->io_ports; + + /* fixme */ + for (i = 0; i < IDE_CONTROL_OFFSET; i++) { + *ata_regs++ = (ide_ioreg_t) ahwif->regbase + + (ide_ioreg_t)(i << AU1XXX_ATA_REG_OFFSET); + } + + /* set the Alternative Status register */ + *ata_regs = (ide_ioreg_t) ahwif->regbase + + (ide_ioreg_t)(14 << AU1XXX_ATA_REG_OFFSET); +} + +static int au_ide_probe(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + _auide_hwif *ahwif = &auide_hwif; + ide_hwif_t *hwif; + struct resource *res; + int ret = 0; + +#if defined(CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA) + char *mode = "MWDMA2"; +#elif defined(CONFIG_BLK_DEV_IDE_AU1XXX_PIO_DBDMA) + char *mode = "PIO+DDMA(offload)"; +#endif + + memset(&auide_hwif, 0, sizeof(_auide_hwif)); + auide_hwif.dev = 0; + + ahwif->dev = dev; + ahwif->irq = platform_get_irq(pdev, 0); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + if (res == NULL) { + pr_debug("%s %d: no base address\n", DRV_NAME, pdev->id); + ret = -ENODEV; + goto out; + } + + if (!request_mem_region (res->start, res->end-res->start, pdev->name)) { + pr_debug("%s: request_mem_region failed\n", DRV_NAME); + ret = -EBUSY; + goto out; + } + + ahwif->regbase = (u32)ioremap(res->start, res->end-res->start); + if (ahwif->regbase == 0) { + ret = -ENOMEM; + goto out; + } + + hwif = &ide_hwifs[pdev->id]; + hw_regs_t *hw = &hwif->hw; + hwif->irq = hw->irq = ahwif->irq; + hwif->chipset = ide_au1xxx; + + auide_setup_ports(hw, ahwif); + memcpy(hwif->io_ports, hw->io_ports, sizeof(hwif->io_ports)); + +#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_SEQTS_PER_RQ + hwif->rqsize = CONFIG_BLK_DEV_IDE_AU1XXX_SEQTS_PER_RQ; + hwif->rqsize = ((hwif->rqsize > AU1XXX_ATA_RQSIZE) + || (hwif->rqsize < 32)) ? AU1XXX_ATA_RQSIZE : hwif->rqsize; +#else /* if kernel config is not set */ + hwif->rqsize = AU1XXX_ATA_RQSIZE; +#endif + + hwif->ultra_mask = 0x0; /* Disable Ultra DMA */ +#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA + hwif->mwdma_mask = 0x07; /* Multimode-2 DMA */ + hwif->swdma_mask = 0x07; +#else + hwif->mwdma_mask = 0x0; + hwif->swdma_mask = 0x0; +#endif + //hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET]; + hwif->noprobe = 0; + hwif->drives[0].unmask = 1; + hwif->drives[1].unmask = 1; + + /* hold should be on in all cases */ + hwif->hold = 1; + hwif->mmio = 2; + + /* set up local I/O function entry points */ + hwif->INB = auide_inb; + hwif->INW = auide_inw; + hwif->INL = auide_inl; + hwif->INSW = auide_insw; + hwif->INSL = auide_insl; + hwif->OUTB = auide_outb; + hwif->OUTBSYNC = auide_outbsync; + hwif->OUTW = auide_outw; + hwif->OUTL = auide_outl; + hwif->OUTSW = auide_outsw; + hwif->OUTSL = auide_outsl; + + hwif->tuneproc = &auide_tune_drive; + hwif->speedproc = &auide_tune_chipset; + +#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA + hwif->ide_dma_off_quietly = &auide_dma_off_quietly; + hwif->ide_dma_timeout = &auide_dma_timeout; + + hwif->ide_dma_check = &auide_dma_check; + hwif->dma_exec_cmd = &auide_dma_exec_cmd; + hwif->dma_start = &auide_dma_start; + hwif->ide_dma_end = &auide_dma_end; + hwif->dma_setup = &auide_dma_setup; + hwif->ide_dma_test_irq = &auide_dma_test_irq; + hwif->ide_dma_host_off = &auide_dma_host_off; + hwif->ide_dma_host_on = &auide_dma_host_on; + hwif->ide_dma_lostirq = &auide_dma_lostirq; + hwif->ide_dma_on = &auide_dma_on; + + hwif->autodma = 1; + hwif->drives[0].autodma = hwif->autodma; + hwif->drives[1].autodma = hwif->autodma; + hwif->atapi_dma = 1; + hwif->drives[0].using_dma = 1; + hwif->drives[1].using_dma = 1; +#else /* !CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA */ + hwif->autodma = 0; + hwif->channel = 0; + hwif->hold = 1; + hwif->select_data = 0; /* no chipset-specific code */ + hwif->config_data = 0; /* no chipset-specific code */ + + hwif->drives[0].autodma = 0; + hwif->drives[0].drive_data = 0; /* no drive data */ + hwif->drives[0].using_dma = 0; + hwif->drives[0].waiting_for_dma = 0; + hwif->drives[0].autotune = 1; /* 1=autotune, 2=noautotune, 0=default */ + /* secondary hdd not supported */ + hwif->drives[1].autodma = 0; + + hwif->drives[1].drive_data = 0; + hwif->drives[1].using_dma = 0; + hwif->drives[1].waiting_for_dma = 0; + hwif->drives[1].autotune = 2; /* 1=autotune, 2=noautotune, 0=default */ +#endif + hwif->drives[0].io_32bit = 0; /* 0=16-bit, 1=32-bit, 2/3=32bit+sync */ + hwif->drives[1].io_32bit = 0; /* 0=16-bit, 1=32-bit, 2/3=32bit+sync */ + + /*Register Driver with PM Framework*/ +#ifdef CONFIG_PM + auide_hwif.pm.lock = SPIN_LOCK_UNLOCKED; + auide_hwif.pm.stopped = 0; + + auide_hwif.pm.dev = new_au1xxx_power_device( "ide", + &au1200ide_pm_callback, + NULL); + if ( auide_hwif.pm.dev == NULL ) + printk(KERN_INFO "Unable to create a power management \ + device entry for the au1200-IDE.\n"); + else + printk(KERN_INFO "Power management device entry for the \ + au1200-IDE loaded.\n"); +#endif + + auide_hwif.hwif = hwif; + hwif->hwif_data = &auide_hwif; + +#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_PIO_DBDMA + auide_ddma_init(&auide_hwif); + dbdma_init_done = 1; +#endif + + probe_hwif_init(hwif); + dev_set_drvdata(dev, hwif); + + printk(KERN_INFO "Au1xxx IDE(builtin) configured for %s\n", mode ); + +out: + return ret; +} + +static int au_ide_remove(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct resource *res; + ide_hwif_t *hwif = dev_get_drvdata(dev); + _auide_hwif *ahwif = &auide_hwif; + + ide_unregister(hwif - ide_hwifs); + + iounmap((void *)ahwif->regbase); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(res->start, res->end - res->start); + + return 0; +} + +static struct device_driver au1200_ide_driver = { + .name = "au1200-ide", + .bus = &platform_bus_type, + .probe = au_ide_probe, + .remove = au_ide_remove, +}; + +static int __init au_ide_init(void) +{ + return driver_register(&au1200_ide_driver); +} + +static void __init au_ide_exit(void) +{ + driver_unregister(&au1200_ide_driver); +} + +#ifdef CONFIG_PM +int au1200ide_pm_callback( au1xxx_power_dev_t *dev,\ + au1xxx_request_t request, void *data) { + + unsigned int d, err = 0; + unsigned long flags; + + spin_lock_irqsave(auide_hwif.pm.lock, flags); + + switch (request){ + case AU1XXX_PM_SLEEP: + err = au1xxxide_pm_sleep(dev); + break; + case AU1XXX_PM_WAKEUP: + d = *((unsigned int*)data); + if ( d > 0 && d <= 99) { + err = au1xxxide_pm_standby(dev); + } + else { + err = au1xxxide_pm_resume(dev); + } + break; + case AU1XXX_PM_GETSTATUS: + err = au1xxxide_pm_getstatus(dev); + break; + case AU1XXX_PM_ACCESS: + err = au1xxxide_pm_access(dev); + break; + case AU1XXX_PM_IDLE: + err = au1xxxide_pm_idle(dev); + break; + case AU1XXX_PM_CLEANUP: + err = au1xxxide_pm_cleanup(dev); + break; + default: + err = -1; + break; + } + + spin_unlock_irqrestore(auide_hwif.pm.lock, flags); + + return err; +} + +static int au1xxxide_pm_standby( au1xxx_power_dev_t *dev ) { + return 0; +} + +static int au1xxxide_pm_sleep( au1xxx_power_dev_t *dev ) { + + int retval; + ide_hwif_t *hwif = auide_hwif.hwif; + struct request rq; + struct request_pm_state rqpm; + ide_task_t args; + + if(auide_hwif.pm.stopped) + return -1; + + /* + * wait until hard disc is ready + */ + if ( wait_for_ready(&hwif->drives[0], 35000) ) { + printk("Wait for drive sleep timeout!\n"); + retval = -1; + } + + /* + * sequenz to tell the high level ide driver that pm is resuming + */ + memset(&rq, 0, sizeof(rq)); + memset(&rqpm, 0, sizeof(rqpm)); + memset(&args, 0, sizeof(args)); + rq.flags = REQ_PM_SUSPEND; + rq.special = &args; + rq.pm = &rqpm; + rqpm.pm_step = ide_pm_state_start_suspend; + rqpm.pm_state = PMSG_SUSPEND; + + retval = ide_do_drive_cmd(&hwif->drives[0], &rq, ide_wait); + + if (wait_for_ready (&hwif->drives[0], 35000)) { + printk("Wait for drive sleep timeout!\n"); + retval = -1; + } + + /* + * stop dbdma channels + */ + au1xxx_dbdma_reset(auide_hwif.tx_chan); + au1xxx_dbdma_reset(auide_hwif.rx_chan); + + auide_hwif.pm.stopped = 1; + + return retval; +} + +static int au1xxxide_pm_resume( au1xxx_power_dev_t *dev ) { + + int retval; + ide_hwif_t *hwif = auide_hwif.hwif; + struct request rq; + struct request_pm_state rqpm; + ide_task_t args; + + if(!auide_hwif.pm.stopped) + return -1; + + /* + * start dbdma channels + */ + au1xxx_dbdma_start(auide_hwif.tx_chan); + au1xxx_dbdma_start(auide_hwif.rx_chan); + + /* + * wait until hard disc is ready + */ + if (wait_for_ready ( &hwif->drives[0], 35000)) { + printk("Wait for drive wake up timeout!\n"); + retval = -1; + } + + /* + * sequenz to tell the high level ide driver that pm is resuming + */ + memset(&rq, 0, sizeof(rq)); + memset(&rqpm, 0, sizeof(rqpm)); + memset(&args, 0, sizeof(args)); + rq.flags = REQ_PM_RESUME; + rq.special = &args; + rq.pm = &rqpm; + rqpm.pm_step = ide_pm_state_start_resume; + rqpm.pm_state = PMSG_ON; + + retval = ide_do_drive_cmd(&hwif->drives[0], &rq, ide_head_wait); + + /* + * wait for hard disc + */ + if ( wait_for_ready(&hwif->drives[0], 35000) ) { + printk("Wait for drive wake up timeout!\n"); + retval = -1; + } + + auide_hwif.pm.stopped = 0; + + return retval; +} + +static int au1xxxide_pm_getstatus( au1xxx_power_dev_t *dev ) { + return dev->cur_state; +} + +static int au1xxxide_pm_access( au1xxx_power_dev_t *dev ) { + if (dev->cur_state != AWAKE_STATE) + return 0; + else + return -1; +} + +static int au1xxxide_pm_idle( au1xxx_power_dev_t *dev ) { + return 0; +} + +static int au1xxxide_pm_cleanup( au1xxx_power_dev_t *dev ) { + return 0; +} +#endif /* CONFIG_PM */ + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("AU1200 IDE driver"); + +module_init(au_ide_init); +module_exit(au_ide_exit); diff --git a/drivers/ieee1394/dv1394.c b/drivers/ieee1394/dv1394.c index e34730c7a874..cbbbe14b8849 100644 --- a/drivers/ieee1394/dv1394.c +++ b/drivers/ieee1394/dv1394.c @@ -2361,7 +2361,7 @@ static void dv1394_add_host (struct hpsb_host *host) ohci = (struct ti_ohci *)host->hostdata; - class_device_create(hpsb_protocol_class, MKDEV( + class_device_create(hpsb_protocol_class, NULL, MKDEV( IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_DV1394 * 16 + (id<<2)), NULL, "dv1394-%d", id); devfs_mk_dir("ieee1394/dv/host%d", id); diff --git a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c index 4802bbbb6dc9..c9e92d85c893 100644 --- a/drivers/ieee1394/eth1394.c +++ b/drivers/ieee1394/eth1394.c @@ -1630,7 +1630,7 @@ static void ether1394_complete_cb(void *__ptask) /* Transmit a packet (called by kernel) */ static int ether1394_tx (struct sk_buff *skb, struct net_device *dev) { - int kmflags = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL; + gfp_t kmflags = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL; struct eth1394hdr *eth; struct eth1394_priv *priv = netdev_priv(dev); int proto; diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c index 347ece6b583c..7fff5a1d2ea4 100644 --- a/drivers/ieee1394/nodemgr.c +++ b/drivers/ieee1394/nodemgr.c @@ -1292,7 +1292,7 @@ static void nodemgr_suspend_ne(struct node_entry *ne) if (ud->device.driver && (!ud->device.driver->suspend || - ud->device.driver->suspend(&ud->device, PMSG_SUSPEND, 0))) + ud->device.driver->suspend(&ud->device, PMSG_SUSPEND))) device_release_driver(&ud->device); } up_write(&ne->device.bus->subsys.rwsem); @@ -1315,7 +1315,7 @@ static void nodemgr_resume_ne(struct node_entry *ne) continue; if (ud->device.driver && ud->device.driver->resume) - ud->device.driver->resume(&ud->device, 0); + ud->device.driver->resume(&ud->device); } up_read(&ne->device.bus->subsys.rwsem); diff --git a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c index 0470f77a9cd1..24411e666b21 100644 --- a/drivers/ieee1394/raw1394.c +++ b/drivers/ieee1394/raw1394.c @@ -2912,7 +2912,7 @@ static int __init init_raw1394(void) hpsb_register_highlevel(&raw1394_highlevel); - if (IS_ERR(class_device_create(hpsb_protocol_class, MKDEV( + if (IS_ERR(class_device_create(hpsb_protocol_class, NULL, MKDEV( IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_RAW1394 * 16), NULL, RAW1394_DEVICE_NAME))) { ret = -EFAULT; diff --git a/drivers/ieee1394/video1394.c b/drivers/ieee1394/video1394.c index 11be9c9c82a8..23911da50154 100644 --- a/drivers/ieee1394/video1394.c +++ b/drivers/ieee1394/video1394.c @@ -1370,7 +1370,7 @@ static void video1394_add_host (struct hpsb_host *host) hpsb_set_hostinfo_key(&video1394_highlevel, host, ohci->host->id); minor = IEEE1394_MINOR_BLOCK_VIDEO1394 * 16 + ohci->host->id; - class_device_create(hpsb_protocol_class, MKDEV( + class_device_create(hpsb_protocol_class, NULL, MKDEV( IEEE1394_MAJOR, minor), NULL, "%s-%d", VIDEO1394_DRIVER_NAME, ohci->host->id); devfs_mk_cdev(MKDEV(IEEE1394_MAJOR, minor), diff --git a/drivers/infiniband/core/agent.c b/drivers/infiniband/core/agent.c index 5ac86f566dc0..0c3c6952faae 100644 --- a/drivers/infiniband/core/agent.c +++ b/drivers/infiniband/core/agent.c @@ -37,58 +37,41 @@ * $Id: agent.c 1389 2004-12-27 22:56:47Z roland $ */ -#include <linux/dma-mapping.h> - -#include <asm/bug.h> +#include "agent.h" +#include "smi.h" -#include <rdma/ib_smi.h> +#define SPFX "ib_agent: " -#include "smi.h" -#include "agent_priv.h" -#include "mad_priv.h" -#include "agent.h" +struct ib_agent_port_private { + struct list_head port_list; + struct ib_mad_agent *agent[2]; +}; -spinlock_t ib_agent_port_list_lock; +static DEFINE_SPINLOCK(ib_agent_port_list_lock); static LIST_HEAD(ib_agent_port_list); -/* - * Caller must hold ib_agent_port_list_lock - */ -static inline struct ib_agent_port_private * -__ib_get_agent_port(struct ib_device *device, int port_num, - struct ib_mad_agent *mad_agent) +static struct ib_agent_port_private * +__ib_get_agent_port(struct ib_device *device, int port_num) { struct ib_agent_port_private *entry; - BUG_ON(!(!!device ^ !!mad_agent)); /* Exactly one MUST be (!NULL) */ - - if (device) { - list_for_each_entry(entry, &ib_agent_port_list, port_list) { - if (entry->smp_agent->device == device && - entry->port_num == port_num) - return entry; - } - } else { - list_for_each_entry(entry, &ib_agent_port_list, port_list) { - if ((entry->smp_agent == mad_agent) || - (entry->perf_mgmt_agent == mad_agent)) - return entry; - } + list_for_each_entry(entry, &ib_agent_port_list, port_list) { + if (entry->agent[0]->device == device && + entry->agent[0]->port_num == port_num) + return entry; } return NULL; } -static inline struct ib_agent_port_private * -ib_get_agent_port(struct ib_device *device, int port_num, - struct ib_mad_agent *mad_agent) +static struct ib_agent_port_private * +ib_get_agent_port(struct ib_device *device, int port_num) { struct ib_agent_port_private *entry; unsigned long flags; spin_lock_irqsave(&ib_agent_port_list_lock, flags); - entry = __ib_get_agent_port(device, port_num, mad_agent); + entry = __ib_get_agent_port(device, port_num); spin_unlock_irqrestore(&ib_agent_port_list_lock, flags); - return entry; } @@ -100,192 +83,76 @@ int smi_check_local_dr_smp(struct ib_smp *smp, if (smp->mgmt_class != IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) return 1; - port_priv = ib_get_agent_port(device, port_num, NULL); + + port_priv = ib_get_agent_port(device, port_num); if (!port_priv) { printk(KERN_DEBUG SPFX "smi_check_local_dr_smp %s port %d " - "not open\n", - device->name, port_num); + "not open\n", device->name, port_num); return 1; } - return smi_check_local_smp(port_priv->smp_agent, smp); + return smi_check_local_smp(port_priv->agent[0], smp); } -static int agent_mad_send(struct ib_mad_agent *mad_agent, - struct ib_agent_port_private *port_priv, - struct ib_mad_private *mad_priv, - struct ib_grh *grh, - struct ib_wc *wc) +int agent_send_response(struct ib_mad *mad, struct ib_grh *grh, + struct ib_wc *wc, struct ib_device *device, + int port_num, int qpn) { - struct ib_agent_send_wr *agent_send_wr; - struct ib_sge gather_list; - struct ib_send_wr send_wr; - struct ib_send_wr *bad_send_wr; - struct ib_ah_attr ah_attr; - unsigned long flags; - int ret = 1; - - agent_send_wr = kmalloc(sizeof(*agent_send_wr), GFP_KERNEL); - if (!agent_send_wr) - goto out; - agent_send_wr->mad = mad_priv; - - gather_list.addr = dma_map_single(mad_agent->device->dma_device, - &mad_priv->mad, - sizeof(mad_priv->mad), - DMA_TO_DEVICE); - gather_list.length = sizeof(mad_priv->mad); - gather_list.lkey = mad_agent->mr->lkey; - - send_wr.next = NULL; - send_wr.opcode = IB_WR_SEND; - send_wr.sg_list = &gather_list; - send_wr.num_sge = 1; - send_wr.wr.ud.remote_qpn = wc->src_qp; /* DQPN */ - send_wr.wr.ud.timeout_ms = 0; - send_wr.send_flags = IB_SEND_SIGNALED | IB_SEND_SOLICITED; + struct ib_agent_port_private *port_priv; + struct ib_mad_agent *agent; + struct ib_mad_send_buf *send_buf; + struct ib_ah *ah; + int ret; - ah_attr.dlid = wc->slid; - ah_attr.port_num = mad_agent->port_num; - ah_attr.src_path_bits = wc->dlid_path_bits; - ah_attr.sl = wc->sl; - ah_attr.static_rate = 0; - ah_attr.ah_flags = 0; /* No GRH */ - if (mad_priv->mad.mad.mad_hdr.mgmt_class == IB_MGMT_CLASS_PERF_MGMT) { - if (wc->wc_flags & IB_WC_GRH) { - ah_attr.ah_flags = IB_AH_GRH; - /* Should sgid be looked up ? */ - ah_attr.grh.sgid_index = 0; - ah_attr.grh.hop_limit = grh->hop_limit; - ah_attr.grh.flow_label = be32_to_cpu( - grh->version_tclass_flow) & 0xfffff; - ah_attr.grh.traffic_class = (be32_to_cpu( - grh->version_tclass_flow) >> 20) & 0xff; - memcpy(ah_attr.grh.dgid.raw, - grh->sgid.raw, - sizeof(ah_attr.grh.dgid)); - } + port_priv = ib_get_agent_port(device, port_num); + if (!port_priv) { + printk(KERN_ERR SPFX "Unable to find port agent\n"); + return -ENODEV; } - agent_send_wr->ah = ib_create_ah(mad_agent->qp->pd, &ah_attr); - if (IS_ERR(agent_send_wr->ah)) { - printk(KERN_ERR SPFX "No memory for address handle\n"); - kfree(agent_send_wr); - goto out; + agent = port_priv->agent[qpn]; + ah = ib_create_ah_from_wc(agent->qp->pd, wc, grh, port_num); + if (IS_ERR(ah)) { + ret = PTR_ERR(ah); + printk(KERN_ERR SPFX "ib_create_ah_from_wc error:%d\n", ret); + return ret; } - send_wr.wr.ud.ah = agent_send_wr->ah; - if (mad_priv->mad.mad.mad_hdr.mgmt_class == IB_MGMT_CLASS_PERF_MGMT) { - send_wr.wr.ud.pkey_index = wc->pkey_index; - send_wr.wr.ud.remote_qkey = IB_QP1_QKEY; - } else { /* for SMPs */ - send_wr.wr.ud.pkey_index = 0; - send_wr.wr.ud.remote_qkey = 0; + send_buf = ib_create_send_mad(agent, wc->src_qp, wc->pkey_index, 0, + IB_MGMT_MAD_HDR, IB_MGMT_MAD_DATA, + GFP_KERNEL); + if (IS_ERR(send_buf)) { + ret = PTR_ERR(send_buf); + printk(KERN_ERR SPFX "ib_create_send_mad error:%d\n", ret); + goto err1; } - send_wr.wr.ud.mad_hdr = &mad_priv->mad.mad.mad_hdr; - send_wr.wr_id = (unsigned long)agent_send_wr; - pci_unmap_addr_set(agent_send_wr, mapping, gather_list.addr); - - /* Send */ - spin_lock_irqsave(&port_priv->send_list_lock, flags); - if (ib_post_send_mad(mad_agent, &send_wr, &bad_send_wr)) { - spin_unlock_irqrestore(&port_priv->send_list_lock, flags); - dma_unmap_single(mad_agent->device->dma_device, - pci_unmap_addr(agent_send_wr, mapping), - sizeof(mad_priv->mad), - DMA_TO_DEVICE); - ib_destroy_ah(agent_send_wr->ah); - kfree(agent_send_wr); - } else { - list_add_tail(&agent_send_wr->send_list, - &port_priv->send_posted_list); - spin_unlock_irqrestore(&port_priv->send_list_lock, flags); - ret = 0; + memcpy(send_buf->mad, mad, sizeof *mad); + send_buf->ah = ah; + if ((ret = ib_post_send_mad(send_buf, NULL))) { + printk(KERN_ERR SPFX "ib_post_send_mad error:%d\n", ret); + goto err2; } - -out: + return 0; +err2: + ib_free_send_mad(send_buf); +err1: + ib_destroy_ah(ah); return ret; } -int agent_send(struct ib_mad_private *mad, - struct ib_grh *grh, - struct ib_wc *wc, - struct ib_device *device, - int port_num) -{ - struct ib_agent_port_private *port_priv; - struct ib_mad_agent *mad_agent; - - port_priv = ib_get_agent_port(device, port_num, NULL); - if (!port_priv) { - printk(KERN_DEBUG SPFX "agent_send %s port %d not open\n", - device->name, port_num); - return 1; - } - - /* Get mad agent based on mgmt_class in MAD */ - switch (mad->mad.mad.mad_hdr.mgmt_class) { - case IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE: - case IB_MGMT_CLASS_SUBN_LID_ROUTED: - mad_agent = port_priv->smp_agent; - break; - case IB_MGMT_CLASS_PERF_MGMT: - mad_agent = port_priv->perf_mgmt_agent; - break; - default: - return 1; - } - - return agent_mad_send(mad_agent, port_priv, mad, grh, wc); -} - static void agent_send_handler(struct ib_mad_agent *mad_agent, struct ib_mad_send_wc *mad_send_wc) { - struct ib_agent_port_private *port_priv; - struct ib_agent_send_wr *agent_send_wr; - unsigned long flags; - - /* Find matching MAD agent */ - port_priv = ib_get_agent_port(NULL, 0, mad_agent); - if (!port_priv) { - printk(KERN_ERR SPFX "agent_send_handler: no matching MAD " - "agent %p\n", mad_agent); - return; - } - - agent_send_wr = (struct ib_agent_send_wr *)(unsigned long)mad_send_wc->wr_id; - spin_lock_irqsave(&port_priv->send_list_lock, flags); - /* Remove completed send from posted send MAD list */ - list_del(&agent_send_wr->send_list); - spin_unlock_irqrestore(&port_priv->send_list_lock, flags); - - dma_unmap_single(mad_agent->device->dma_device, - pci_unmap_addr(agent_send_wr, mapping), - sizeof(agent_send_wr->mad->mad), - DMA_TO_DEVICE); - - ib_destroy_ah(agent_send_wr->ah); - - /* Release allocated memory */ - kmem_cache_free(ib_mad_cache, agent_send_wr->mad); - kfree(agent_send_wr); + ib_destroy_ah(mad_send_wc->send_buf->ah); + ib_free_send_mad(mad_send_wc->send_buf); } int ib_agent_port_open(struct ib_device *device, int port_num) { - int ret; struct ib_agent_port_private *port_priv; unsigned long flags; - - /* First, check if port already open for SMI */ - port_priv = ib_get_agent_port(device, port_num, NULL); - if (port_priv) { - printk(KERN_DEBUG SPFX "%s port %d already open\n", - device->name, port_num); - return 0; - } + int ret; /* Create new device info */ port_priv = kmalloc(sizeof *port_priv, GFP_KERNEL); @@ -294,32 +161,25 @@ int ib_agent_port_open(struct ib_device *device, int port_num) ret = -ENOMEM; goto error1; } - memset(port_priv, 0, sizeof *port_priv); - port_priv->port_num = port_num; - spin_lock_init(&port_priv->send_list_lock); - INIT_LIST_HEAD(&port_priv->send_posted_list); - /* Obtain send only MAD agent for SM class (SMI QP) */ - port_priv->smp_agent = ib_register_mad_agent(device, port_num, - IB_QPT_SMI, - NULL, 0, + /* Obtain send only MAD agent for SMI QP */ + port_priv->agent[0] = ib_register_mad_agent(device, port_num, + IB_QPT_SMI, NULL, 0, &agent_send_handler, - NULL, NULL); - - if (IS_ERR(port_priv->smp_agent)) { - ret = PTR_ERR(port_priv->smp_agent); + NULL, NULL); + if (IS_ERR(port_priv->agent[0])) { + ret = PTR_ERR(port_priv->agent[0]); goto error2; } - /* Obtain send only MAD agent for PerfMgmt class (GSI QP) */ - port_priv->perf_mgmt_agent = ib_register_mad_agent(device, port_num, - IB_QPT_GSI, - NULL, 0, - &agent_send_handler, - NULL, NULL); - if (IS_ERR(port_priv->perf_mgmt_agent)) { - ret = PTR_ERR(port_priv->perf_mgmt_agent); + /* Obtain send only MAD agent for GSI QP */ + port_priv->agent[1] = ib_register_mad_agent(device, port_num, + IB_QPT_GSI, NULL, 0, + &agent_send_handler, + NULL, NULL); + if (IS_ERR(port_priv->agent[1])) { + ret = PTR_ERR(port_priv->agent[1]); goto error3; } @@ -330,7 +190,7 @@ int ib_agent_port_open(struct ib_device *device, int port_num) return 0; error3: - ib_unregister_mad_agent(port_priv->smp_agent); + ib_unregister_mad_agent(port_priv->agent[0]); error2: kfree(port_priv); error1: @@ -343,7 +203,7 @@ int ib_agent_port_close(struct ib_device *device, int port_num) unsigned long flags; spin_lock_irqsave(&ib_agent_port_list_lock, flags); - port_priv = __ib_get_agent_port(device, port_num, NULL); + port_priv = __ib_get_agent_port(device, port_num); if (port_priv == NULL) { spin_unlock_irqrestore(&ib_agent_port_list_lock, flags); printk(KERN_ERR SPFX "Port %d not found\n", port_num); @@ -352,9 +212,8 @@ int ib_agent_port_close(struct ib_device *device, int port_num) list_del(&port_priv->port_list); spin_unlock_irqrestore(&ib_agent_port_list_lock, flags); - ib_unregister_mad_agent(port_priv->perf_mgmt_agent); - ib_unregister_mad_agent(port_priv->smp_agent); + ib_unregister_mad_agent(port_priv->agent[1]); + ib_unregister_mad_agent(port_priv->agent[0]); kfree(port_priv); - return 0; } diff --git a/drivers/infiniband/core/agent.h b/drivers/infiniband/core/agent.h index d9426842254a..86d72fab37b0 100644 --- a/drivers/infiniband/core/agent.h +++ b/drivers/infiniband/core/agent.h @@ -39,17 +39,15 @@ #ifndef __AGENT_H_ #define __AGENT_H_ -extern spinlock_t ib_agent_port_list_lock; +#include <linux/err.h> +#include <rdma/ib_mad.h> -extern int ib_agent_port_open(struct ib_device *device, - int port_num); +extern int ib_agent_port_open(struct ib_device *device, int port_num); extern int ib_agent_port_close(struct ib_device *device, int port_num); -extern int agent_send(struct ib_mad_private *mad, - struct ib_grh *grh, - struct ib_wc *wc, - struct ib_device *device, - int port_num); +extern int agent_send_response(struct ib_mad *mad, struct ib_grh *grh, + struct ib_wc *wc, struct ib_device *device, + int port_num, int qpn); #endif /* __AGENT_H_ */ diff --git a/drivers/infiniband/core/agent_priv.h b/drivers/infiniband/core/agent_priv.h deleted file mode 100644 index 2ec6d7f1b7d0..000000000000 --- a/drivers/infiniband/core/agent_priv.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2004, 2005 Mellanox Technologies Ltd. All rights reserved. - * Copyright (c) 2004, 2005 Infinicon Corporation. All rights reserved. - * Copyright (c) 2004, 2005 Intel Corporation. All rights reserved. - * Copyright (c) 2004, 2005 Topspin Corporation. All rights reserved. - * Copyright (c) 2004, 2005 Voltaire Corporation. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * $Id: agent_priv.h 1640 2005-01-24 22:39:02Z halr $ - */ - -#ifndef __IB_AGENT_PRIV_H__ -#define __IB_AGENT_PRIV_H__ - -#include <linux/pci.h> - -#define SPFX "ib_agent: " - -struct ib_agent_send_wr { - struct list_head send_list; - struct ib_ah *ah; - struct ib_mad_private *mad; - DECLARE_PCI_UNMAP_ADDR(mapping) -}; - -struct ib_agent_port_private { - struct list_head port_list; - struct list_head send_posted_list; - spinlock_t send_list_lock; - int port_num; - struct ib_mad_agent *smp_agent; /* SM class */ - struct ib_mad_agent *perf_mgmt_agent; /* PerfMgmt class */ -}; - -#endif /* __IB_AGENT_PRIV_H__ */ diff --git a/drivers/infiniband/core/cache.c b/drivers/infiniband/core/cache.c index f014e639088c..c57a3871184c 100644 --- a/drivers/infiniband/core/cache.c +++ b/drivers/infiniband/core/cache.c @@ -38,6 +38,7 @@ #include <linux/module.h> #include <linux/errno.h> #include <linux/slab.h> +#include <linux/sched.h> /* INIT_WORK, schedule_work(), flush_scheduled_work() */ #include <rdma/ib_cache.h> diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c index 54db6d4831f1..580c3a2bb102 100644 --- a/drivers/infiniband/core/cm.c +++ b/drivers/infiniband/core/cm.c @@ -135,6 +135,7 @@ struct cm_id_private { __be64 tid; __be32 local_qpn; __be32 remote_qpn; + enum ib_qp_type qp_type; __be32 sq_psn; __be32 rq_psn; int timeout_ms; @@ -175,8 +176,7 @@ static int cm_alloc_msg(struct cm_id_private *cm_id_priv, m = ib_create_send_mad(mad_agent, cm_id_priv->id.remote_cm_qpn, cm_id_priv->av.pkey_index, - ah, 0, sizeof(struct ib_mad_hdr), - sizeof(struct ib_mad)-sizeof(struct ib_mad_hdr), + 0, IB_MGMT_MAD_HDR, IB_MGMT_MAD_DATA, GFP_ATOMIC); if (IS_ERR(m)) { ib_destroy_ah(ah); @@ -184,7 +184,8 @@ static int cm_alloc_msg(struct cm_id_private *cm_id_priv, } /* Timeout set by caller if response is expected. */ - m->send_wr.wr.ud.retries = cm_id_priv->max_cm_retries; + m->ah = ah; + m->retries = cm_id_priv->max_cm_retries; atomic_inc(&cm_id_priv->refcount); m->context[0] = cm_id_priv; @@ -205,20 +206,20 @@ static int cm_alloc_response_msg(struct cm_port *port, return PTR_ERR(ah); m = ib_create_send_mad(port->mad_agent, 1, mad_recv_wc->wc->pkey_index, - ah, 0, sizeof(struct ib_mad_hdr), - sizeof(struct ib_mad)-sizeof(struct ib_mad_hdr), + 0, IB_MGMT_MAD_HDR, IB_MGMT_MAD_DATA, GFP_ATOMIC); if (IS_ERR(m)) { ib_destroy_ah(ah); return PTR_ERR(m); } + m->ah = ah; *msg = m; return 0; } static void cm_free_msg(struct ib_mad_send_buf *msg) { - ib_destroy_ah(msg->send_wr.wr.ud.ah); + ib_destroy_ah(msg->ah); if (msg->context[0]) cm_deref_id(msg->context[0]); ib_free_send_mad(msg); @@ -366,9 +367,15 @@ static struct cm_id_private * cm_insert_listen(struct cm_id_private *cm_id_priv) cur_cm_id_priv = rb_entry(parent, struct cm_id_private, service_node); if ((cur_cm_id_priv->id.service_mask & service_id) == - (service_mask & cur_cm_id_priv->id.service_id)) - return cm_id_priv; - if (service_id < cur_cm_id_priv->id.service_id) + (service_mask & cur_cm_id_priv->id.service_id) && + (cm_id_priv->id.device == cur_cm_id_priv->id.device)) + return cur_cm_id_priv; + + if (cm_id_priv->id.device < cur_cm_id_priv->id.device) + link = &(*link)->rb_left; + else if (cm_id_priv->id.device > cur_cm_id_priv->id.device) + link = &(*link)->rb_right; + else if (service_id < cur_cm_id_priv->id.service_id) link = &(*link)->rb_left; else link = &(*link)->rb_right; @@ -378,7 +385,8 @@ static struct cm_id_private * cm_insert_listen(struct cm_id_private *cm_id_priv) return NULL; } -static struct cm_id_private * cm_find_listen(__be64 service_id) +static struct cm_id_private * cm_find_listen(struct ib_device *device, + __be64 service_id) { struct rb_node *node = cm.listen_service_table.rb_node; struct cm_id_private *cm_id_priv; @@ -386,9 +394,15 @@ static struct cm_id_private * cm_find_listen(__be64 service_id) while (node) { cm_id_priv = rb_entry(node, struct cm_id_private, service_node); if ((cm_id_priv->id.service_mask & service_id) == - (cm_id_priv->id.service_mask & cm_id_priv->id.service_id)) + cm_id_priv->id.service_id && + (cm_id_priv->id.device == device)) return cm_id_priv; - if (service_id < cm_id_priv->id.service_id) + + if (device < cm_id_priv->id.device) + node = node->rb_left; + else if (device > cm_id_priv->id.device) + node = node->rb_right; + else if (service_id < cm_id_priv->id.service_id) node = node->rb_left; else node = node->rb_right; @@ -523,7 +537,8 @@ static void cm_reject_sidr_req(struct cm_id_private *cm_id_priv, ib_send_cm_sidr_rep(&cm_id_priv->id, ¶m); } -struct ib_cm_id *ib_create_cm_id(ib_cm_handler cm_handler, +struct ib_cm_id *ib_create_cm_id(struct ib_device *device, + ib_cm_handler cm_handler, void *context) { struct cm_id_private *cm_id_priv; @@ -535,6 +550,7 @@ struct ib_cm_id *ib_create_cm_id(ib_cm_handler cm_handler, memset(cm_id_priv, 0, sizeof *cm_id_priv); cm_id_priv->id.state = IB_CM_IDLE; + cm_id_priv->id.device = device; cm_id_priv->id.cm_handler = cm_handler; cm_id_priv->id.context = context; cm_id_priv->id.remote_cm_qpn = 1; @@ -662,8 +678,7 @@ retest: break; case IB_CM_SIDR_REQ_SENT: cm_id->state = IB_CM_IDLE; - ib_cancel_mad(cm_id_priv->av.port->mad_agent, - (unsigned long) cm_id_priv->msg); + ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg); spin_unlock_irqrestore(&cm_id_priv->lock, flags); break; case IB_CM_SIDR_REQ_RCVD: @@ -674,8 +689,7 @@ retest: case IB_CM_MRA_REQ_RCVD: case IB_CM_REP_SENT: case IB_CM_MRA_REP_RCVD: - ib_cancel_mad(cm_id_priv->av.port->mad_agent, - (unsigned long) cm_id_priv->msg); + ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg); /* Fall through */ case IB_CM_REQ_RCVD: case IB_CM_MRA_REQ_SENT: @@ -692,8 +706,7 @@ retest: ib_send_cm_dreq(cm_id, NULL, 0); goto retest; case IB_CM_DREQ_SENT: - ib_cancel_mad(cm_id_priv->av.port->mad_agent, - (unsigned long) cm_id_priv->msg); + ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg); cm_enter_timewait(cm_id_priv); spin_unlock_irqrestore(&cm_id_priv->lock, flags); break; @@ -867,7 +880,6 @@ int ib_send_cm_req(struct ib_cm_id *cm_id, struct ib_cm_req_param *param) { struct cm_id_private *cm_id_priv; - struct ib_send_wr *bad_send_wr; struct cm_req_msg *req_msg; unsigned long flags; int ret; @@ -911,6 +923,7 @@ int ib_send_cm_req(struct ib_cm_id *cm_id, cm_id_priv->responder_resources = param->responder_resources; cm_id_priv->retry_count = param->retry_count; cm_id_priv->path_mtu = param->primary_path->mtu; + cm_id_priv->qp_type = param->qp_type; ret = cm_alloc_msg(cm_id_priv, &cm_id_priv->msg); if (ret) @@ -919,7 +932,7 @@ int ib_send_cm_req(struct ib_cm_id *cm_id, req_msg = (struct cm_req_msg *) cm_id_priv->msg->mad; cm_format_req(req_msg, cm_id_priv, param); cm_id_priv->tid = req_msg->hdr.tid; - cm_id_priv->msg->send_wr.wr.ud.timeout_ms = cm_id_priv->timeout_ms; + cm_id_priv->msg->timeout_ms = cm_id_priv->timeout_ms; cm_id_priv->msg->context[1] = (void *) (unsigned long) IB_CM_REQ_SENT; cm_id_priv->local_qpn = cm_req_get_local_qpn(req_msg); @@ -928,8 +941,7 @@ int ib_send_cm_req(struct ib_cm_id *cm_id, cm_req_get_primary_local_ack_timeout(req_msg); spin_lock_irqsave(&cm_id_priv->lock, flags); - ret = ib_post_send_mad(cm_id_priv->av.port->mad_agent, - &cm_id_priv->msg->send_wr, &bad_send_wr); + ret = ib_post_send_mad(cm_id_priv->msg, NULL); if (ret) { spin_unlock_irqrestore(&cm_id_priv->lock, flags); goto error2; @@ -952,7 +964,6 @@ static int cm_issue_rej(struct cm_port *port, void *ari, u8 ari_length) { struct ib_mad_send_buf *msg = NULL; - struct ib_send_wr *bad_send_wr; struct cm_rej_msg *rej_msg, *rcv_msg; int ret; @@ -975,7 +986,7 @@ static int cm_issue_rej(struct cm_port *port, memcpy(rej_msg->ari, ari, ari_length); } - ret = ib_post_send_mad(port->mad_agent, &msg->send_wr, &bad_send_wr); + ret = ib_post_send_mad(msg, NULL); if (ret) cm_free_msg(msg); @@ -1047,7 +1058,6 @@ static void cm_format_req_event(struct cm_work *work, req_msg = (struct cm_req_msg *)work->mad_recv_wc->recv_buf.mad; param = &work->cm_event.param.req_rcvd; param->listen_id = listen_id; - param->device = cm_id_priv->av.port->mad_agent->device; param->port = cm_id_priv->av.port->port_num; param->primary_path = &work->path[0]; if (req_msg->alt_local_lid) @@ -1156,7 +1166,6 @@ static void cm_dup_req_handler(struct cm_work *work, struct cm_id_private *cm_id_priv) { struct ib_mad_send_buf *msg = NULL; - struct ib_send_wr *bad_send_wr; unsigned long flags; int ret; @@ -1185,8 +1194,7 @@ static void cm_dup_req_handler(struct cm_work *work, } spin_unlock_irqrestore(&cm_id_priv->lock, flags); - ret = ib_post_send_mad(cm_id_priv->av.port->mad_agent, &msg->send_wr, - &bad_send_wr); + ret = ib_post_send_mad(msg, NULL); if (ret) goto free; return; @@ -1226,7 +1234,8 @@ static struct cm_id_private * cm_match_req(struct cm_work *work, } /* Find matching listen request. */ - listen_cm_id_priv = cm_find_listen(req_msg->service_id); + listen_cm_id_priv = cm_find_listen(cm_id_priv->id.device, + req_msg->service_id); if (!listen_cm_id_priv) { spin_unlock_irqrestore(&cm.lock, flags); cm_issue_rej(work->port, work->mad_recv_wc, @@ -1254,7 +1263,7 @@ static int cm_req_handler(struct cm_work *work) req_msg = (struct cm_req_msg *)work->mad_recv_wc->recv_buf.mad; - cm_id = ib_create_cm_id(NULL, NULL); + cm_id = ib_create_cm_id(work->port->cm_dev->device, NULL, NULL); if (IS_ERR(cm_id)) return PTR_ERR(cm_id); @@ -1305,6 +1314,7 @@ static int cm_req_handler(struct cm_work *work) cm_req_get_primary_local_ack_timeout(req_msg); cm_id_priv->retry_count = cm_req_get_retry_count(req_msg); cm_id_priv->rnr_retry_count = cm_req_get_rnr_retry_count(req_msg); + cm_id_priv->qp_type = cm_req_get_qp_type(req_msg); cm_format_req_event(work, cm_id_priv, &listen_cm_id_priv->id); cm_process_work(cm_id_priv, work); @@ -1349,7 +1359,6 @@ int ib_send_cm_rep(struct ib_cm_id *cm_id, struct cm_id_private *cm_id_priv; struct ib_mad_send_buf *msg; struct cm_rep_msg *rep_msg; - struct ib_send_wr *bad_send_wr; unsigned long flags; int ret; @@ -1371,11 +1380,10 @@ int ib_send_cm_rep(struct ib_cm_id *cm_id, rep_msg = (struct cm_rep_msg *) msg->mad; cm_format_rep(rep_msg, cm_id_priv, param); - msg->send_wr.wr.ud.timeout_ms = cm_id_priv->timeout_ms; + msg->timeout_ms = cm_id_priv->timeout_ms; msg->context[1] = (void *) (unsigned long) IB_CM_REP_SENT; - ret = ib_post_send_mad(cm_id_priv->av.port->mad_agent, - &msg->send_wr, &bad_send_wr); + ret = ib_post_send_mad(msg, NULL); if (ret) { spin_unlock_irqrestore(&cm_id_priv->lock, flags); cm_free_msg(msg); @@ -1413,7 +1421,6 @@ int ib_send_cm_rtu(struct ib_cm_id *cm_id, { struct cm_id_private *cm_id_priv; struct ib_mad_send_buf *msg; - struct ib_send_wr *bad_send_wr; unsigned long flags; void *data; int ret; @@ -1440,8 +1447,7 @@ int ib_send_cm_rtu(struct ib_cm_id *cm_id, cm_format_rtu((struct cm_rtu_msg *) msg->mad, cm_id_priv, private_data, private_data_len); - ret = ib_post_send_mad(cm_id_priv->av.port->mad_agent, - &msg->send_wr, &bad_send_wr); + ret = ib_post_send_mad(msg, NULL); if (ret) { spin_unlock_irqrestore(&cm_id_priv->lock, flags); cm_free_msg(msg); @@ -1486,7 +1492,6 @@ static void cm_dup_rep_handler(struct cm_work *work) struct cm_id_private *cm_id_priv; struct cm_rep_msg *rep_msg; struct ib_mad_send_buf *msg = NULL; - struct ib_send_wr *bad_send_wr; unsigned long flags; int ret; @@ -1514,8 +1519,7 @@ static void cm_dup_rep_handler(struct cm_work *work) goto unlock; spin_unlock_irqrestore(&cm_id_priv->lock, flags); - ret = ib_post_send_mad(cm_id_priv->av.port->mad_agent, &msg->send_wr, - &bad_send_wr); + ret = ib_post_send_mad(msg, NULL); if (ret) goto free; goto deref; @@ -1583,8 +1587,7 @@ static int cm_rep_handler(struct cm_work *work) /* todo: handle peer_to_peer */ - ib_cancel_mad(cm_id_priv->av.port->mad_agent, - (unsigned long) cm_id_priv->msg); + ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg); ret = atomic_inc_and_test(&cm_id_priv->work_count); if (!ret) list_add_tail(&work->list, &cm_id_priv->work_list); @@ -1618,8 +1621,7 @@ static int cm_establish_handler(struct cm_work *work) goto out; } - ib_cancel_mad(cm_id_priv->av.port->mad_agent, - (unsigned long) cm_id_priv->msg); + ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg); ret = atomic_inc_and_test(&cm_id_priv->work_count); if (!ret) list_add_tail(&work->list, &cm_id_priv->work_list); @@ -1658,8 +1660,7 @@ static int cm_rtu_handler(struct cm_work *work) } cm_id_priv->id.state = IB_CM_ESTABLISHED; - ib_cancel_mad(cm_id_priv->av.port->mad_agent, - (unsigned long) cm_id_priv->msg); + ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg); ret = atomic_inc_and_test(&cm_id_priv->work_count); if (!ret) list_add_tail(&work->list, &cm_id_priv->work_list); @@ -1696,7 +1697,6 @@ int ib_send_cm_dreq(struct ib_cm_id *cm_id, { struct cm_id_private *cm_id_priv; struct ib_mad_send_buf *msg; - struct ib_send_wr *bad_send_wr; unsigned long flags; int ret; @@ -1718,11 +1718,10 @@ int ib_send_cm_dreq(struct ib_cm_id *cm_id, cm_format_dreq((struct cm_dreq_msg *) msg->mad, cm_id_priv, private_data, private_data_len); - msg->send_wr.wr.ud.timeout_ms = cm_id_priv->timeout_ms; + msg->timeout_ms = cm_id_priv->timeout_ms; msg->context[1] = (void *) (unsigned long) IB_CM_DREQ_SENT; - ret = ib_post_send_mad(cm_id_priv->av.port->mad_agent, - &msg->send_wr, &bad_send_wr); + ret = ib_post_send_mad(msg, NULL); if (ret) { cm_enter_timewait(cm_id_priv); spin_unlock_irqrestore(&cm_id_priv->lock, flags); @@ -1756,7 +1755,6 @@ int ib_send_cm_drep(struct ib_cm_id *cm_id, { struct cm_id_private *cm_id_priv; struct ib_mad_send_buf *msg; - struct ib_send_wr *bad_send_wr; unsigned long flags; void *data; int ret; @@ -1786,8 +1784,7 @@ int ib_send_cm_drep(struct ib_cm_id *cm_id, cm_format_drep((struct cm_drep_msg *) msg->mad, cm_id_priv, private_data, private_data_len); - ret = ib_post_send_mad(cm_id_priv->av.port->mad_agent, &msg->send_wr, - &bad_send_wr); + ret = ib_post_send_mad(msg, NULL); if (ret) { spin_unlock_irqrestore(&cm_id_priv->lock, flags); cm_free_msg(msg); @@ -1804,7 +1801,6 @@ static int cm_dreq_handler(struct cm_work *work) struct cm_id_private *cm_id_priv; struct cm_dreq_msg *dreq_msg; struct ib_mad_send_buf *msg = NULL; - struct ib_send_wr *bad_send_wr; unsigned long flags; int ret; @@ -1823,8 +1819,7 @@ static int cm_dreq_handler(struct cm_work *work) switch (cm_id_priv->id.state) { case IB_CM_REP_SENT: case IB_CM_DREQ_SENT: - ib_cancel_mad(cm_id_priv->av.port->mad_agent, - (unsigned long) cm_id_priv->msg); + ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg); break; case IB_CM_ESTABLISHED: case IB_CM_MRA_REP_RCVD: @@ -1838,8 +1833,7 @@ static int cm_dreq_handler(struct cm_work *work) cm_id_priv->private_data_len); spin_unlock_irqrestore(&cm_id_priv->lock, flags); - if (ib_post_send_mad(cm_id_priv->av.port->mad_agent, - &msg->send_wr, &bad_send_wr)) + if (ib_post_send_mad(msg, NULL)) cm_free_msg(msg); goto deref; default: @@ -1886,8 +1880,7 @@ static int cm_drep_handler(struct cm_work *work) } cm_enter_timewait(cm_id_priv); - ib_cancel_mad(cm_id_priv->av.port->mad_agent, - (unsigned long) cm_id_priv->msg); + ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg); ret = atomic_inc_and_test(&cm_id_priv->work_count); if (!ret) list_add_tail(&work->list, &cm_id_priv->work_list); @@ -1912,7 +1905,6 @@ int ib_send_cm_rej(struct ib_cm_id *cm_id, { struct cm_id_private *cm_id_priv; struct ib_mad_send_buf *msg; - struct ib_send_wr *bad_send_wr; unsigned long flags; int ret; @@ -1956,8 +1948,7 @@ int ib_send_cm_rej(struct ib_cm_id *cm_id, if (ret) goto out; - ret = ib_post_send_mad(cm_id_priv->av.port->mad_agent, - &msg->send_wr, &bad_send_wr); + ret = ib_post_send_mad(msg, NULL); if (ret) cm_free_msg(msg); @@ -2033,8 +2024,7 @@ static int cm_rej_handler(struct cm_work *work) case IB_CM_MRA_REQ_RCVD: case IB_CM_REP_SENT: case IB_CM_MRA_REP_RCVD: - ib_cancel_mad(cm_id_priv->av.port->mad_agent, - (unsigned long) cm_id_priv->msg); + ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg); /* fall through */ case IB_CM_REQ_RCVD: case IB_CM_MRA_REQ_SENT: @@ -2044,8 +2034,7 @@ static int cm_rej_handler(struct cm_work *work) cm_reset_to_idle(cm_id_priv); break; case IB_CM_DREQ_SENT: - ib_cancel_mad(cm_id_priv->av.port->mad_agent, - (unsigned long) cm_id_priv->msg); + ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg); /* fall through */ case IB_CM_REP_RCVD: case IB_CM_MRA_REP_SENT: @@ -2080,7 +2069,6 @@ int ib_send_cm_mra(struct ib_cm_id *cm_id, { struct cm_id_private *cm_id_priv; struct ib_mad_send_buf *msg; - struct ib_send_wr *bad_send_wr; void *data; unsigned long flags; int ret; @@ -2104,8 +2092,7 @@ int ib_send_cm_mra(struct ib_cm_id *cm_id, cm_format_mra((struct cm_mra_msg *) msg->mad, cm_id_priv, CM_MSG_RESPONSE_REQ, service_timeout, private_data, private_data_len); - ret = ib_post_send_mad(cm_id_priv->av.port->mad_agent, - &msg->send_wr, &bad_send_wr); + ret = ib_post_send_mad(msg, NULL); if (ret) goto error2; cm_id->state = IB_CM_MRA_REQ_SENT; @@ -2118,8 +2105,7 @@ int ib_send_cm_mra(struct ib_cm_id *cm_id, cm_format_mra((struct cm_mra_msg *) msg->mad, cm_id_priv, CM_MSG_RESPONSE_REP, service_timeout, private_data, private_data_len); - ret = ib_post_send_mad(cm_id_priv->av.port->mad_agent, - &msg->send_wr, &bad_send_wr); + ret = ib_post_send_mad(msg, NULL); if (ret) goto error2; cm_id->state = IB_CM_MRA_REP_SENT; @@ -2132,8 +2118,7 @@ int ib_send_cm_mra(struct ib_cm_id *cm_id, cm_format_mra((struct cm_mra_msg *) msg->mad, cm_id_priv, CM_MSG_RESPONSE_OTHER, service_timeout, private_data, private_data_len); - ret = ib_post_send_mad(cm_id_priv->av.port->mad_agent, - &msg->send_wr, &bad_send_wr); + ret = ib_post_send_mad(msg, NULL); if (ret) goto error2; cm_id->lap_state = IB_CM_MRA_LAP_SENT; @@ -2195,14 +2180,14 @@ static int cm_mra_handler(struct cm_work *work) case IB_CM_REQ_SENT: if (cm_mra_get_msg_mraed(mra_msg) != CM_MSG_RESPONSE_REQ || ib_modify_mad(cm_id_priv->av.port->mad_agent, - (unsigned long) cm_id_priv->msg, timeout)) + cm_id_priv->msg, timeout)) goto out; cm_id_priv->id.state = IB_CM_MRA_REQ_RCVD; break; case IB_CM_REP_SENT: if (cm_mra_get_msg_mraed(mra_msg) != CM_MSG_RESPONSE_REP || ib_modify_mad(cm_id_priv->av.port->mad_agent, - (unsigned long) cm_id_priv->msg, timeout)) + cm_id_priv->msg, timeout)) goto out; cm_id_priv->id.state = IB_CM_MRA_REP_RCVD; break; @@ -2210,7 +2195,7 @@ static int cm_mra_handler(struct cm_work *work) if (cm_mra_get_msg_mraed(mra_msg) != CM_MSG_RESPONSE_OTHER || cm_id_priv->id.lap_state != IB_CM_LAP_SENT || ib_modify_mad(cm_id_priv->av.port->mad_agent, - (unsigned long) cm_id_priv->msg, timeout)) + cm_id_priv->msg, timeout)) goto out; cm_id_priv->id.lap_state = IB_CM_MRA_LAP_RCVD; break; @@ -2273,7 +2258,6 @@ int ib_send_cm_lap(struct ib_cm_id *cm_id, { struct cm_id_private *cm_id_priv; struct ib_mad_send_buf *msg; - struct ib_send_wr *bad_send_wr; unsigned long flags; int ret; @@ -2294,11 +2278,10 @@ int ib_send_cm_lap(struct ib_cm_id *cm_id, cm_format_lap((struct cm_lap_msg *) msg->mad, cm_id_priv, alternate_path, private_data, private_data_len); - msg->send_wr.wr.ud.timeout_ms = cm_id_priv->timeout_ms; + msg->timeout_ms = cm_id_priv->timeout_ms; msg->context[1] = (void *) (unsigned long) IB_CM_ESTABLISHED; - ret = ib_post_send_mad(cm_id_priv->av.port->mad_agent, - &msg->send_wr, &bad_send_wr); + ret = ib_post_send_mad(msg, NULL); if (ret) { spin_unlock_irqrestore(&cm_id_priv->lock, flags); cm_free_msg(msg); @@ -2342,7 +2325,6 @@ static int cm_lap_handler(struct cm_work *work) struct cm_lap_msg *lap_msg; struct ib_cm_lap_event_param *param; struct ib_mad_send_buf *msg = NULL; - struct ib_send_wr *bad_send_wr; unsigned long flags; int ret; @@ -2376,8 +2358,7 @@ static int cm_lap_handler(struct cm_work *work) cm_id_priv->private_data_len); spin_unlock_irqrestore(&cm_id_priv->lock, flags); - if (ib_post_send_mad(cm_id_priv->av.port->mad_agent, - &msg->send_wr, &bad_send_wr)) + if (ib_post_send_mad(msg, NULL)) cm_free_msg(msg); goto deref; default: @@ -2433,7 +2414,6 @@ int ib_send_cm_apr(struct ib_cm_id *cm_id, { struct cm_id_private *cm_id_priv; struct ib_mad_send_buf *msg; - struct ib_send_wr *bad_send_wr; unsigned long flags; int ret; @@ -2456,8 +2436,7 @@ int ib_send_cm_apr(struct ib_cm_id *cm_id, cm_format_apr((struct cm_apr_msg *) msg->mad, cm_id_priv, status, info, info_length, private_data, private_data_len); - ret = ib_post_send_mad(cm_id_priv->av.port->mad_agent, - &msg->send_wr, &bad_send_wr); + ret = ib_post_send_mad(msg, NULL); if (ret) { spin_unlock_irqrestore(&cm_id_priv->lock, flags); cm_free_msg(msg); @@ -2496,8 +2475,7 @@ static int cm_apr_handler(struct cm_work *work) goto out; } cm_id_priv->id.lap_state = IB_CM_LAP_IDLE; - ib_cancel_mad(cm_id_priv->av.port->mad_agent, - (unsigned long) cm_id_priv->msg); + ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg); cm_id_priv->msg = NULL; ret = atomic_inc_and_test(&cm_id_priv->work_count); @@ -2572,7 +2550,6 @@ int ib_send_cm_sidr_req(struct ib_cm_id *cm_id, { struct cm_id_private *cm_id_priv; struct ib_mad_send_buf *msg; - struct ib_send_wr *bad_send_wr; unsigned long flags; int ret; @@ -2595,13 +2572,12 @@ int ib_send_cm_sidr_req(struct ib_cm_id *cm_id, cm_format_sidr_req((struct cm_sidr_req_msg *) msg->mad, cm_id_priv, param); - msg->send_wr.wr.ud.timeout_ms = cm_id_priv->timeout_ms; + msg->timeout_ms = cm_id_priv->timeout_ms; msg->context[1] = (void *) (unsigned long) IB_CM_SIDR_REQ_SENT; spin_lock_irqsave(&cm_id_priv->lock, flags); if (cm_id->state == IB_CM_IDLE) - ret = ib_post_send_mad(cm_id_priv->av.port->mad_agent, - &msg->send_wr, &bad_send_wr); + ret = ib_post_send_mad(msg, NULL); else ret = -EINVAL; @@ -2629,7 +2605,6 @@ static void cm_format_sidr_req_event(struct cm_work *work, param = &work->cm_event.param.sidr_req_rcvd; param->pkey = __be16_to_cpu(sidr_req_msg->pkey); param->listen_id = listen_id; - param->device = work->port->mad_agent->device; param->port = work->port->port_num; work->cm_event.private_data = &sidr_req_msg->private_data; } @@ -2642,7 +2617,7 @@ static int cm_sidr_req_handler(struct cm_work *work) struct ib_wc *wc; unsigned long flags; - cm_id = ib_create_cm_id(NULL, NULL); + cm_id = ib_create_cm_id(work->port->cm_dev->device, NULL, NULL); if (IS_ERR(cm_id)) return PTR_ERR(cm_id); cm_id_priv = container_of(cm_id, struct cm_id_private, id); @@ -2666,7 +2641,8 @@ static int cm_sidr_req_handler(struct cm_work *work) spin_unlock_irqrestore(&cm.lock, flags); goto out; /* Duplicate message. */ } - cur_cm_id_priv = cm_find_listen(sidr_req_msg->service_id); + cur_cm_id_priv = cm_find_listen(cm_id->device, + sidr_req_msg->service_id); if (!cur_cm_id_priv) { rb_erase(&cm_id_priv->sidr_id_node, &cm.remote_sidr_table); spin_unlock_irqrestore(&cm.lock, flags); @@ -2715,7 +2691,6 @@ int ib_send_cm_sidr_rep(struct ib_cm_id *cm_id, { struct cm_id_private *cm_id_priv; struct ib_mad_send_buf *msg; - struct ib_send_wr *bad_send_wr; unsigned long flags; int ret; @@ -2737,8 +2712,7 @@ int ib_send_cm_sidr_rep(struct ib_cm_id *cm_id, cm_format_sidr_rep((struct cm_sidr_rep_msg *) msg->mad, cm_id_priv, param); - ret = ib_post_send_mad(cm_id_priv->av.port->mad_agent, - &msg->send_wr, &bad_send_wr); + ret = ib_post_send_mad(msg, NULL); if (ret) { spin_unlock_irqrestore(&cm_id_priv->lock, flags); cm_free_msg(msg); @@ -2791,8 +2765,7 @@ static int cm_sidr_rep_handler(struct cm_work *work) goto out; } cm_id_priv->id.state = IB_CM_IDLE; - ib_cancel_mad(cm_id_priv->av.port->mad_agent, - (unsigned long) cm_id_priv->msg); + ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg); spin_unlock_irqrestore(&cm_id_priv->lock, flags); cm_format_sidr_rep_event(work); @@ -2860,9 +2833,7 @@ discard: static void cm_send_handler(struct ib_mad_agent *mad_agent, struct ib_mad_send_wc *mad_send_wc) { - struct ib_mad_send_buf *msg; - - msg = (struct ib_mad_send_buf *)(unsigned long)mad_send_wc->wr_id; + struct ib_mad_send_buf *msg = mad_send_wc->send_buf; switch (mad_send_wc->status) { case IB_WC_SUCCESS: @@ -3064,10 +3035,10 @@ static int cm_init_qp_init_attr(struct cm_id_private *cm_id_priv, case IB_CM_ESTABLISHED: *qp_attr_mask = IB_QP_STATE | IB_QP_ACCESS_FLAGS | IB_QP_PKEY_INDEX | IB_QP_PORT; - qp_attr->qp_access_flags = IB_ACCESS_LOCAL_WRITE; + qp_attr->qp_access_flags = IB_ACCESS_LOCAL_WRITE | + IB_ACCESS_REMOTE_WRITE; if (cm_id_priv->responder_resources) - qp_attr->qp_access_flags |= IB_ACCESS_REMOTE_WRITE | - IB_ACCESS_REMOTE_READ; + qp_attr->qp_access_flags |= IB_ACCESS_REMOTE_READ; qp_attr->pkey_index = cm_id_priv->av.pkey_index; qp_attr->port_num = cm_id_priv->av.port->port_num; ret = 0; @@ -3097,14 +3068,18 @@ static int cm_init_qp_rtr_attr(struct cm_id_private *cm_id_priv, case IB_CM_MRA_REP_RCVD: case IB_CM_ESTABLISHED: *qp_attr_mask = IB_QP_STATE | IB_QP_AV | IB_QP_PATH_MTU | - IB_QP_DEST_QPN | IB_QP_RQ_PSN | - IB_QP_MAX_DEST_RD_ATOMIC | IB_QP_MIN_RNR_TIMER; + IB_QP_DEST_QPN | IB_QP_RQ_PSN; qp_attr->ah_attr = cm_id_priv->av.ah_attr; qp_attr->path_mtu = cm_id_priv->path_mtu; qp_attr->dest_qp_num = be32_to_cpu(cm_id_priv->remote_qpn); qp_attr->rq_psn = be32_to_cpu(cm_id_priv->rq_psn); - qp_attr->max_dest_rd_atomic = cm_id_priv->responder_resources; - qp_attr->min_rnr_timer = 0; + if (cm_id_priv->qp_type == IB_QPT_RC) { + *qp_attr_mask |= IB_QP_MAX_DEST_RD_ATOMIC | + IB_QP_MIN_RNR_TIMER; + qp_attr->max_dest_rd_atomic = + cm_id_priv->responder_resources; + qp_attr->min_rnr_timer = 0; + } if (cm_id_priv->alt_av.ah_attr.dlid) { *qp_attr_mask |= IB_QP_ALT_PATH; qp_attr->alt_ah_attr = cm_id_priv->alt_av.ah_attr; @@ -3133,14 +3108,17 @@ static int cm_init_qp_rts_attr(struct cm_id_private *cm_id_priv, case IB_CM_REP_SENT: case IB_CM_MRA_REP_RCVD: case IB_CM_ESTABLISHED: - *qp_attr_mask = IB_QP_STATE | IB_QP_TIMEOUT | IB_QP_RETRY_CNT | - IB_QP_RNR_RETRY | IB_QP_SQ_PSN | - IB_QP_MAX_QP_RD_ATOMIC; - qp_attr->timeout = cm_id_priv->local_ack_timeout; - qp_attr->retry_cnt = cm_id_priv->retry_count; - qp_attr->rnr_retry = cm_id_priv->rnr_retry_count; + *qp_attr_mask = IB_QP_STATE | IB_QP_SQ_PSN; qp_attr->sq_psn = be32_to_cpu(cm_id_priv->sq_psn); - qp_attr->max_rd_atomic = cm_id_priv->initiator_depth; + if (cm_id_priv->qp_type == IB_QPT_RC) { + *qp_attr_mask |= IB_QP_TIMEOUT | IB_QP_RETRY_CNT | + IB_QP_RNR_RETRY | + IB_QP_MAX_QP_RD_ATOMIC; + qp_attr->timeout = cm_id_priv->local_ack_timeout; + qp_attr->retry_cnt = cm_id_priv->retry_count; + qp_attr->rnr_retry = cm_id_priv->rnr_retry_count; + qp_attr->max_rd_atomic = cm_id_priv->initiator_depth; + } if (cm_id_priv->alt_av.ah_attr.dlid) { *qp_attr_mask |= IB_QP_PATH_MIG_STATE; qp_attr->path_mig_state = IB_MIG_REARM; @@ -3323,6 +3301,7 @@ static void __exit ib_cm_cleanup(void) flush_workqueue(cm.wq); destroy_workqueue(cm.wq); ib_unregister_client(&cm_client); + idr_destroy(&cm.local_id_table); } module_init(ib_cm_init); diff --git a/drivers/infiniband/core/cm_msgs.h b/drivers/infiniband/core/cm_msgs.h index 813ab70bf6d5..4d3aee90c249 100644 --- a/drivers/infiniband/core/cm_msgs.h +++ b/drivers/infiniband/core/cm_msgs.h @@ -186,6 +186,7 @@ static inline void cm_req_set_qp_type(struct cm_req_msg *req_msg, req_msg->offset40 = cpu_to_be32((be32_to_cpu( req_msg->offset40) & 0xFFFFFFF9) | 0x2); + break; default: req_msg->offset40 = cpu_to_be32(be32_to_cpu( req_msg->offset40) & diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c index d3cf84e01587..5a6e44976405 100644 --- a/drivers/infiniband/core/device.c +++ b/drivers/infiniband/core/device.c @@ -514,6 +514,12 @@ int ib_query_port(struct ib_device *device, u8 port_num, struct ib_port_attr *port_attr) { + if (device->node_type == IB_NODE_SWITCH) { + if (port_num) + return -EINVAL; + } else if (port_num < 1 || port_num > device->phys_port_cnt) + return -EINVAL; + return device->query_port(device, port_num, port_attr); } EXPORT_SYMBOL(ib_query_port); @@ -583,6 +589,12 @@ int ib_modify_port(struct ib_device *device, u8 port_num, int port_modify_mask, struct ib_port_modify *port_modify) { + if (device->node_type == IB_NODE_SWITCH) { + if (port_num) + return -EINVAL; + } else if (port_num < 1 || port_num > device->phys_port_cnt) + return -EINVAL; + return device->modify_port(device, port_num, port_modify_mask, port_modify); } diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c index a14ca87fda18..88f9f8c9eacc 100644 --- a/drivers/infiniband/core/mad.c +++ b/drivers/infiniband/core/mad.c @@ -579,7 +579,7 @@ static void dequeue_mad(struct ib_mad_list_head *mad_list) } static void snoop_send(struct ib_mad_qp_info *qp_info, - struct ib_send_wr *send_wr, + struct ib_mad_send_buf *send_buf, struct ib_mad_send_wc *mad_send_wc, int mad_snoop_flags) { @@ -597,7 +597,7 @@ static void snoop_send(struct ib_mad_qp_info *qp_info, atomic_inc(&mad_snoop_priv->refcount); spin_unlock_irqrestore(&qp_info->snoop_lock, flags); mad_snoop_priv->agent.snoop_handler(&mad_snoop_priv->agent, - send_wr, mad_send_wc); + send_buf, mad_send_wc); if (atomic_dec_and_test(&mad_snoop_priv->refcount)) wake_up(&mad_snoop_priv->wait); spin_lock_irqsave(&qp_info->snoop_lock, flags); @@ -654,10 +654,10 @@ static void build_smp_wc(u64 wr_id, u16 slid, u16 pkey_index, u8 port_num, * Return < 0 if error */ static int handle_outgoing_dr_smp(struct ib_mad_agent_private *mad_agent_priv, - struct ib_smp *smp, - struct ib_send_wr *send_wr) + struct ib_mad_send_wr_private *mad_send_wr) { int ret; + struct ib_smp *smp = mad_send_wr->send_buf.mad; unsigned long flags; struct ib_mad_local_private *local; struct ib_mad_private *mad_priv; @@ -666,6 +666,7 @@ static int handle_outgoing_dr_smp(struct ib_mad_agent_private *mad_agent_priv, struct ib_device *device = mad_agent_priv->agent.device; u8 port_num = mad_agent_priv->agent.port_num; struct ib_wc mad_wc; + struct ib_send_wr *send_wr = &mad_send_wr->send_wr; if (!smi_handle_dr_smp_send(smp, device->node_type, port_num)) { ret = -EINVAL; @@ -745,13 +746,7 @@ static int handle_outgoing_dr_smp(struct ib_mad_agent_private *mad_agent_priv, goto out; } - local->send_wr = *send_wr; - local->send_wr.sg_list = local->sg_list; - memcpy(local->sg_list, send_wr->sg_list, - sizeof *send_wr->sg_list * send_wr->num_sge); - local->send_wr.next = NULL; - local->tid = send_wr->wr.ud.mad_hdr->tid; - local->wr_id = send_wr->wr_id; + local->mad_send_wr = mad_send_wr; /* Reference MAD agent until send side of local completion handled */ atomic_inc(&mad_agent_priv->refcount); /* Queue local completion to local list */ @@ -781,17 +776,17 @@ static int get_buf_length(int hdr_len, int data_len) struct ib_mad_send_buf * ib_create_send_mad(struct ib_mad_agent *mad_agent, u32 remote_qpn, u16 pkey_index, - struct ib_ah *ah, int rmpp_active, + int rmpp_active, int hdr_len, int data_len, gfp_t gfp_mask) { struct ib_mad_agent_private *mad_agent_priv; - struct ib_mad_send_buf *send_buf; + struct ib_mad_send_wr_private *mad_send_wr; int buf_size; void *buf; - mad_agent_priv = container_of(mad_agent, - struct ib_mad_agent_private, agent); + mad_agent_priv = container_of(mad_agent, struct ib_mad_agent_private, + agent); buf_size = get_buf_length(hdr_len, data_len); if ((!mad_agent->rmpp_version && @@ -799,45 +794,40 @@ struct ib_mad_send_buf * ib_create_send_mad(struct ib_mad_agent *mad_agent, (!rmpp_active && buf_size > sizeof(struct ib_mad))) return ERR_PTR(-EINVAL); - buf = kmalloc(sizeof *send_buf + buf_size, gfp_mask); + buf = kmalloc(sizeof *mad_send_wr + buf_size, gfp_mask); if (!buf) return ERR_PTR(-ENOMEM); - memset(buf, 0, sizeof *send_buf + buf_size); - - send_buf = buf + buf_size; - send_buf->mad = buf; - - send_buf->sge.addr = dma_map_single(mad_agent->device->dma_device, - buf, buf_size, DMA_TO_DEVICE); - pci_unmap_addr_set(send_buf, mapping, send_buf->sge.addr); - send_buf->sge.length = buf_size; - send_buf->sge.lkey = mad_agent->mr->lkey; - - send_buf->send_wr.wr_id = (unsigned long) send_buf; - send_buf->send_wr.sg_list = &send_buf->sge; - send_buf->send_wr.num_sge = 1; - send_buf->send_wr.opcode = IB_WR_SEND; - send_buf->send_wr.send_flags = IB_SEND_SIGNALED; - send_buf->send_wr.wr.ud.ah = ah; - send_buf->send_wr.wr.ud.mad_hdr = &send_buf->mad->mad_hdr; - send_buf->send_wr.wr.ud.remote_qpn = remote_qpn; - send_buf->send_wr.wr.ud.remote_qkey = IB_QP_SET_QKEY; - send_buf->send_wr.wr.ud.pkey_index = pkey_index; + memset(buf, 0, sizeof *mad_send_wr + buf_size); + + mad_send_wr = buf + buf_size; + mad_send_wr->send_buf.mad = buf; + + mad_send_wr->mad_agent_priv = mad_agent_priv; + mad_send_wr->sg_list[0].length = buf_size; + mad_send_wr->sg_list[0].lkey = mad_agent->mr->lkey; + + mad_send_wr->send_wr.wr_id = (unsigned long) mad_send_wr; + mad_send_wr->send_wr.sg_list = mad_send_wr->sg_list; + mad_send_wr->send_wr.num_sge = 1; + mad_send_wr->send_wr.opcode = IB_WR_SEND; + mad_send_wr->send_wr.send_flags = IB_SEND_SIGNALED; + mad_send_wr->send_wr.wr.ud.remote_qpn = remote_qpn; + mad_send_wr->send_wr.wr.ud.remote_qkey = IB_QP_SET_QKEY; + mad_send_wr->send_wr.wr.ud.pkey_index = pkey_index; if (rmpp_active) { - struct ib_rmpp_mad *rmpp_mad; - rmpp_mad = (struct ib_rmpp_mad *)send_buf->mad; + struct ib_rmpp_mad *rmpp_mad = mad_send_wr->send_buf.mad; rmpp_mad->rmpp_hdr.paylen_newwin = cpu_to_be32(hdr_len - - offsetof(struct ib_rmpp_mad, data) + data_len); + IB_MGMT_RMPP_HDR + data_len); rmpp_mad->rmpp_hdr.rmpp_version = mad_agent->rmpp_version; rmpp_mad->rmpp_hdr.rmpp_type = IB_MGMT_RMPP_TYPE_DATA; ib_set_rmpp_flags(&rmpp_mad->rmpp_hdr, IB_MGMT_RMPP_FLAG_ACTIVE); } - send_buf->mad_agent = mad_agent; + mad_send_wr->send_buf.mad_agent = mad_agent; atomic_inc(&mad_agent_priv->refcount); - return send_buf; + return &mad_send_wr->send_buf; } EXPORT_SYMBOL(ib_create_send_mad); @@ -847,10 +837,6 @@ void ib_free_send_mad(struct ib_mad_send_buf *send_buf) mad_agent_priv = container_of(send_buf->mad_agent, struct ib_mad_agent_private, agent); - - dma_unmap_single(send_buf->mad_agent->device->dma_device, - pci_unmap_addr(send_buf, mapping), - send_buf->sge.length, DMA_TO_DEVICE); kfree(send_buf->mad); if (atomic_dec_and_test(&mad_agent_priv->refcount)) @@ -861,8 +847,10 @@ EXPORT_SYMBOL(ib_free_send_mad); int ib_send_mad(struct ib_mad_send_wr_private *mad_send_wr) { struct ib_mad_qp_info *qp_info; - struct ib_send_wr *bad_send_wr; struct list_head *list; + struct ib_send_wr *bad_send_wr; + struct ib_mad_agent *mad_agent; + struct ib_sge *sge; unsigned long flags; int ret; @@ -871,10 +859,17 @@ int ib_send_mad(struct ib_mad_send_wr_private *mad_send_wr) mad_send_wr->send_wr.wr_id = (unsigned long)&mad_send_wr->mad_list; mad_send_wr->mad_list.mad_queue = &qp_info->send_queue; + mad_agent = mad_send_wr->send_buf.mad_agent; + sge = mad_send_wr->sg_list; + sge->addr = dma_map_single(mad_agent->device->dma_device, + mad_send_wr->send_buf.mad, sge->length, + DMA_TO_DEVICE); + pci_unmap_addr_set(mad_send_wr, mapping, sge->addr); + spin_lock_irqsave(&qp_info->send_queue.lock, flags); if (qp_info->send_queue.count < qp_info->send_queue.max_active) { - ret = ib_post_send(mad_send_wr->mad_agent_priv->agent.qp, - &mad_send_wr->send_wr, &bad_send_wr); + ret = ib_post_send(mad_agent->qp, &mad_send_wr->send_wr, + &bad_send_wr); list = &qp_info->send_queue.list; } else { ret = 0; @@ -886,6 +881,11 @@ int ib_send_mad(struct ib_mad_send_wr_private *mad_send_wr) list_add_tail(&mad_send_wr->mad_list.list, list); } spin_unlock_irqrestore(&qp_info->send_queue.lock, flags); + if (ret) + dma_unmap_single(mad_agent->device->dma_device, + pci_unmap_addr(mad_send_wr, mapping), + sge->length, DMA_TO_DEVICE); + return ret; } @@ -893,45 +893,28 @@ int ib_send_mad(struct ib_mad_send_wr_private *mad_send_wr) * ib_post_send_mad - Posts MAD(s) to the send queue of the QP associated * with the registered client */ -int ib_post_send_mad(struct ib_mad_agent *mad_agent, - struct ib_send_wr *send_wr, - struct ib_send_wr **bad_send_wr) +int ib_post_send_mad(struct ib_mad_send_buf *send_buf, + struct ib_mad_send_buf **bad_send_buf) { - int ret = -EINVAL; struct ib_mad_agent_private *mad_agent_priv; - - /* Validate supplied parameters */ - if (!bad_send_wr) - goto error1; - - if (!mad_agent || !send_wr) - goto error2; - - if (!mad_agent->send_handler) - goto error2; - - mad_agent_priv = container_of(mad_agent, - struct ib_mad_agent_private, - agent); + struct ib_mad_send_buf *next_send_buf; + struct ib_mad_send_wr_private *mad_send_wr; + unsigned long flags; + int ret = -EINVAL; /* Walk list of send WRs and post each on send list */ - while (send_wr) { - unsigned long flags; - struct ib_send_wr *next_send_wr; - struct ib_mad_send_wr_private *mad_send_wr; - struct ib_smp *smp; - - /* Validate more parameters */ - if (send_wr->num_sge > IB_MAD_SEND_REQ_MAX_SG) - goto error2; + for (; send_buf; send_buf = next_send_buf) { - if (send_wr->wr.ud.timeout_ms && !mad_agent->recv_handler) - goto error2; - - if (!send_wr->wr.ud.mad_hdr) { - printk(KERN_ERR PFX "MAD header must be supplied " - "in WR %p\n", send_wr); - goto error2; + mad_send_wr = container_of(send_buf, + struct ib_mad_send_wr_private, + send_buf); + mad_agent_priv = mad_send_wr->mad_agent_priv; + + if (!send_buf->mad_agent->send_handler || + (send_buf->timeout_ms && + !send_buf->mad_agent->recv_handler)) { + ret = -EINVAL; + goto error; } /* @@ -939,40 +922,24 @@ int ib_post_send_mad(struct ib_mad_agent *mad_agent, * current one completes, and the user modifies the work * request associated with the completion */ - next_send_wr = (struct ib_send_wr *)send_wr->next; + next_send_buf = send_buf->next; + mad_send_wr->send_wr.wr.ud.ah = send_buf->ah; - smp = (struct ib_smp *)send_wr->wr.ud.mad_hdr; - if (smp->mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) { - ret = handle_outgoing_dr_smp(mad_agent_priv, smp, - send_wr); + if (((struct ib_mad_hdr *) send_buf->mad)->mgmt_class == + IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) { + ret = handle_outgoing_dr_smp(mad_agent_priv, + mad_send_wr); if (ret < 0) /* error */ - goto error2; + goto error; else if (ret == 1) /* locally consumed */ - goto next; + continue; } - /* Allocate MAD send WR tracking structure */ - mad_send_wr = kmalloc(sizeof *mad_send_wr, GFP_ATOMIC); - if (!mad_send_wr) { - printk(KERN_ERR PFX "No memory for " - "ib_mad_send_wr_private\n"); - ret = -ENOMEM; - goto error2; - } - memset(mad_send_wr, 0, sizeof *mad_send_wr); - - mad_send_wr->send_wr = *send_wr; - mad_send_wr->send_wr.sg_list = mad_send_wr->sg_list; - memcpy(mad_send_wr->sg_list, send_wr->sg_list, - sizeof *send_wr->sg_list * send_wr->num_sge); - mad_send_wr->wr_id = send_wr->wr_id; - mad_send_wr->tid = send_wr->wr.ud.mad_hdr->tid; - mad_send_wr->mad_agent_priv = mad_agent_priv; + mad_send_wr->tid = ((struct ib_mad_hdr *) send_buf->mad)->tid; /* Timeout will be updated after send completes */ - mad_send_wr->timeout = msecs_to_jiffies(send_wr->wr. - ud.timeout_ms); - mad_send_wr->retries = mad_send_wr->send_wr.wr.ud.retries; - /* One reference for each work request to QP + response */ + mad_send_wr->timeout = msecs_to_jiffies(send_buf->timeout_ms); + mad_send_wr->retries = send_buf->retries; + /* Reference for work request to QP + response */ mad_send_wr->refcount = 1 + (mad_send_wr->timeout > 0); mad_send_wr->status = IB_WC_SUCCESS; @@ -995,16 +962,13 @@ int ib_post_send_mad(struct ib_mad_agent *mad_agent, list_del(&mad_send_wr->agent_list); spin_unlock_irqrestore(&mad_agent_priv->lock, flags); atomic_dec(&mad_agent_priv->refcount); - goto error2; + goto error; } -next: - send_wr = next_send_wr; } return 0; - -error2: - *bad_send_wr = send_wr; -error1: +error: + if (bad_send_buf) + *bad_send_buf = send_buf; return ret; } EXPORT_SYMBOL(ib_post_send_mad); @@ -1447,8 +1411,7 @@ find_mad_agent(struct ib_mad_port_private *port_priv, * of MAD. */ hi_tid = be64_to_cpu(mad->mad_hdr.tid) >> 32; - list_for_each_entry(entry, &port_priv->agent_list, - agent_list) { + list_for_each_entry(entry, &port_priv->agent_list, agent_list) { if (entry->agent.hi_tid == hi_tid) { mad_agent = entry; break; @@ -1571,8 +1534,7 @@ ib_find_send_mad(struct ib_mad_agent_private *mad_agent_priv, __be64 tid) */ list_for_each_entry(mad_send_wr, &mad_agent_priv->send_list, agent_list) { - if (is_data_mad(mad_agent_priv, - mad_send_wr->send_wr.wr.ud.mad_hdr) && + if (is_data_mad(mad_agent_priv, mad_send_wr->send_buf.mad) && mad_send_wr->tid == tid && mad_send_wr->timeout) { /* Verify request has not been canceled */ return (mad_send_wr->status == IB_WC_SUCCESS) ? @@ -1628,14 +1590,14 @@ static void ib_mad_complete_recv(struct ib_mad_agent_private *mad_agent_priv, spin_unlock_irqrestore(&mad_agent_priv->lock, flags); /* Defined behavior is to complete response before request */ - mad_recv_wc->wc->wr_id = mad_send_wr->wr_id; + mad_recv_wc->wc->wr_id = (unsigned long) &mad_send_wr->send_buf; mad_agent_priv->agent.recv_handler(&mad_agent_priv->agent, mad_recv_wc); atomic_dec(&mad_agent_priv->refcount); mad_send_wc.status = IB_WC_SUCCESS; mad_send_wc.vendor_err = 0; - mad_send_wc.wr_id = mad_send_wr->wr_id; + mad_send_wc.send_buf = &mad_send_wr->send_buf; ib_mad_complete_send_wr(mad_send_wr, &mad_send_wc); } else { mad_agent_priv->agent.recv_handler(&mad_agent_priv->agent, @@ -1728,11 +1690,11 @@ local: if (ret & IB_MAD_RESULT_CONSUMED) goto out; if (ret & IB_MAD_RESULT_REPLY) { - /* Send response */ - if (!agent_send(response, &recv->grh, wc, - port_priv->device, - port_priv->port_num)) - response = NULL; + agent_send_response(&response->mad.mad, + &recv->grh, wc, + port_priv->device, + port_priv->port_num, + qp_info->qp->qp_num); goto out; } } @@ -1866,15 +1828,15 @@ void ib_mad_complete_send_wr(struct ib_mad_send_wr_private *mad_send_wr, if (mad_send_wr->status != IB_WC_SUCCESS ) mad_send_wc->status = mad_send_wr->status; - if (ret != IB_RMPP_RESULT_INTERNAL) + if (ret == IB_RMPP_RESULT_INTERNAL) + ib_rmpp_send_handler(mad_send_wc); + else mad_agent_priv->agent.send_handler(&mad_agent_priv->agent, mad_send_wc); /* Release reference on agent taken when sending */ if (atomic_dec_and_test(&mad_agent_priv->refcount)) wake_up(&mad_agent_priv->wait); - - kfree(mad_send_wr); return; done: spin_unlock_irqrestore(&mad_agent_priv->lock, flags); @@ -1888,6 +1850,7 @@ static void ib_mad_send_done_handler(struct ib_mad_port_private *port_priv, struct ib_mad_qp_info *qp_info; struct ib_mad_queue *send_queue; struct ib_send_wr *bad_send_wr; + struct ib_mad_send_wc mad_send_wc; unsigned long flags; int ret; @@ -1898,6 +1861,9 @@ static void ib_mad_send_done_handler(struct ib_mad_port_private *port_priv, qp_info = send_queue->qp_info; retry: + dma_unmap_single(mad_send_wr->send_buf.mad_agent->device->dma_device, + pci_unmap_addr(mad_send_wr, mapping), + mad_send_wr->sg_list[0].length, DMA_TO_DEVICE); queued_send_wr = NULL; spin_lock_irqsave(&send_queue->lock, flags); list_del(&mad_list->list); @@ -1914,17 +1880,17 @@ retry: } spin_unlock_irqrestore(&send_queue->lock, flags); - /* Restore client wr_id in WC and complete send */ - wc->wr_id = mad_send_wr->wr_id; + mad_send_wc.send_buf = &mad_send_wr->send_buf; + mad_send_wc.status = wc->status; + mad_send_wc.vendor_err = wc->vendor_err; if (atomic_read(&qp_info->snoop_count)) - snoop_send(qp_info, &mad_send_wr->send_wr, - (struct ib_mad_send_wc *)wc, + snoop_send(qp_info, &mad_send_wr->send_buf, &mad_send_wc, IB_MAD_SNOOP_SEND_COMPLETIONS); - ib_mad_complete_send_wr(mad_send_wr, (struct ib_mad_send_wc *)wc); + ib_mad_complete_send_wr(mad_send_wr, &mad_send_wc); if (queued_send_wr) { ret = ib_post_send(qp_info->qp, &queued_send_wr->send_wr, - &bad_send_wr); + &bad_send_wr); if (ret) { printk(KERN_ERR PFX "ib_post_send failed: %d\n", ret); mad_send_wr = queued_send_wr; @@ -2066,38 +2032,37 @@ static void cancel_mads(struct ib_mad_agent_private *mad_agent_priv) list_for_each_entry_safe(mad_send_wr, temp_mad_send_wr, &cancel_list, agent_list) { - mad_send_wc.wr_id = mad_send_wr->wr_id; + mad_send_wc.send_buf = &mad_send_wr->send_buf; + list_del(&mad_send_wr->agent_list); mad_agent_priv->agent.send_handler(&mad_agent_priv->agent, &mad_send_wc); - - list_del(&mad_send_wr->agent_list); - kfree(mad_send_wr); atomic_dec(&mad_agent_priv->refcount); } } static struct ib_mad_send_wr_private* -find_send_by_wr_id(struct ib_mad_agent_private *mad_agent_priv, u64 wr_id) +find_send_wr(struct ib_mad_agent_private *mad_agent_priv, + struct ib_mad_send_buf *send_buf) { struct ib_mad_send_wr_private *mad_send_wr; list_for_each_entry(mad_send_wr, &mad_agent_priv->wait_list, agent_list) { - if (mad_send_wr->wr_id == wr_id) + if (&mad_send_wr->send_buf == send_buf) return mad_send_wr; } list_for_each_entry(mad_send_wr, &mad_agent_priv->send_list, agent_list) { - if (is_data_mad(mad_agent_priv, - mad_send_wr->send_wr.wr.ud.mad_hdr) && - mad_send_wr->wr_id == wr_id) + if (is_data_mad(mad_agent_priv, mad_send_wr->send_buf.mad) && + &mad_send_wr->send_buf == send_buf) return mad_send_wr; } return NULL; } -int ib_modify_mad(struct ib_mad_agent *mad_agent, u64 wr_id, u32 timeout_ms) +int ib_modify_mad(struct ib_mad_agent *mad_agent, + struct ib_mad_send_buf *send_buf, u32 timeout_ms) { struct ib_mad_agent_private *mad_agent_priv; struct ib_mad_send_wr_private *mad_send_wr; @@ -2107,7 +2072,7 @@ int ib_modify_mad(struct ib_mad_agent *mad_agent, u64 wr_id, u32 timeout_ms) mad_agent_priv = container_of(mad_agent, struct ib_mad_agent_private, agent); spin_lock_irqsave(&mad_agent_priv->lock, flags); - mad_send_wr = find_send_by_wr_id(mad_agent_priv, wr_id); + mad_send_wr = find_send_wr(mad_agent_priv, send_buf); if (!mad_send_wr || mad_send_wr->status != IB_WC_SUCCESS) { spin_unlock_irqrestore(&mad_agent_priv->lock, flags); return -EINVAL; @@ -2119,7 +2084,7 @@ int ib_modify_mad(struct ib_mad_agent *mad_agent, u64 wr_id, u32 timeout_ms) mad_send_wr->refcount -= (mad_send_wr->timeout > 0); } - mad_send_wr->send_wr.wr.ud.timeout_ms = timeout_ms; + mad_send_wr->send_buf.timeout_ms = timeout_ms; if (active) mad_send_wr->timeout = msecs_to_jiffies(timeout_ms); else @@ -2130,9 +2095,10 @@ int ib_modify_mad(struct ib_mad_agent *mad_agent, u64 wr_id, u32 timeout_ms) } EXPORT_SYMBOL(ib_modify_mad); -void ib_cancel_mad(struct ib_mad_agent *mad_agent, u64 wr_id) +void ib_cancel_mad(struct ib_mad_agent *mad_agent, + struct ib_mad_send_buf *send_buf) { - ib_modify_mad(mad_agent, wr_id, 0); + ib_modify_mad(mad_agent, send_buf, 0); } EXPORT_SYMBOL(ib_cancel_mad); @@ -2166,10 +2132,9 @@ static void local_completions(void *data) * Defined behavior is to complete response * before request */ - build_smp_wc(local->wr_id, + build_smp_wc((unsigned long) local->mad_send_wr, be16_to_cpu(IB_LID_PERMISSIVE), - 0 /* pkey index */, - recv_mad_agent->agent.port_num, &wc); + 0, recv_mad_agent->agent.port_num, &wc); local->mad_priv->header.recv_wc.wc = &wc; local->mad_priv->header.recv_wc.mad_len = @@ -2196,11 +2161,11 @@ local_send_completion: /* Complete send */ mad_send_wc.status = IB_WC_SUCCESS; mad_send_wc.vendor_err = 0; - mad_send_wc.wr_id = local->wr_id; + mad_send_wc.send_buf = &local->mad_send_wr->send_buf; if (atomic_read(&mad_agent_priv->qp_info->snoop_count)) - snoop_send(mad_agent_priv->qp_info, &local->send_wr, - &mad_send_wc, - IB_MAD_SNOOP_SEND_COMPLETIONS); + snoop_send(mad_agent_priv->qp_info, + &local->mad_send_wr->send_buf, + &mad_send_wc, IB_MAD_SNOOP_SEND_COMPLETIONS); mad_agent_priv->agent.send_handler(&mad_agent_priv->agent, &mad_send_wc); @@ -2221,8 +2186,7 @@ static int retry_send(struct ib_mad_send_wr_private *mad_send_wr) if (!mad_send_wr->retries--) return -ETIMEDOUT; - mad_send_wr->timeout = msecs_to_jiffies(mad_send_wr->send_wr. - wr.ud.timeout_ms); + mad_send_wr->timeout = msecs_to_jiffies(mad_send_wr->send_buf.timeout_ms); if (mad_send_wr->mad_agent_priv->agent.rmpp_version) { ret = ib_retry_rmpp(mad_send_wr); @@ -2285,11 +2249,10 @@ static void timeout_sends(void *data) mad_send_wc.status = IB_WC_RESP_TIMEOUT_ERR; else mad_send_wc.status = mad_send_wr->status; - mad_send_wc.wr_id = mad_send_wr->wr_id; + mad_send_wc.send_buf = &mad_send_wr->send_buf; mad_agent_priv->agent.send_handler(&mad_agent_priv->agent, &mad_send_wc); - kfree(mad_send_wr); atomic_dec(&mad_agent_priv->refcount); spin_lock_irqsave(&mad_agent_priv->lock, flags); } @@ -2683,40 +2646,47 @@ static int ib_mad_port_close(struct ib_device *device, int port_num) static void ib_mad_init_device(struct ib_device *device) { - int num_ports, cur_port, i; + int start, end, i; if (device->node_type == IB_NODE_SWITCH) { - num_ports = 1; - cur_port = 0; + start = 0; + end = 0; } else { - num_ports = device->phys_port_cnt; - cur_port = 1; + start = 1; + end = device->phys_port_cnt; } - for (i = 0; i < num_ports; i++, cur_port++) { - if (ib_mad_port_open(device, cur_port)) { + + for (i = start; i <= end; i++) { + if (ib_mad_port_open(device, i)) { printk(KERN_ERR PFX "Couldn't open %s port %d\n", - device->name, cur_port); - goto error_device_open; + device->name, i); + goto error; } - if (ib_agent_port_open(device, cur_port)) { + if (ib_agent_port_open(device, i)) { printk(KERN_ERR PFX "Couldn't open %s port %d " "for agents\n", - device->name, cur_port); - goto error_device_open; + device->name, i); + goto error_agent; } } return; -error_device_open: - while (i > 0) { - cur_port--; - if (ib_agent_port_close(device, cur_port)) +error_agent: + if (ib_mad_port_close(device, i)) + printk(KERN_ERR PFX "Couldn't close %s port %d\n", + device->name, i); + +error: + i--; + + while (i >= start) { + if (ib_agent_port_close(device, i)) printk(KERN_ERR PFX "Couldn't close %s port %d " "for agents\n", - device->name, cur_port); - if (ib_mad_port_close(device, cur_port)) + device->name, i); + if (ib_mad_port_close(device, i)) printk(KERN_ERR PFX "Couldn't close %s port %d\n", - device->name, cur_port); + device->name, i); i--; } } @@ -2754,7 +2724,6 @@ static int __init ib_mad_init_module(void) int ret; spin_lock_init(&ib_mad_port_list_lock); - spin_lock_init(&ib_agent_port_list_lock); ib_mad_cache = kmem_cache_create("ib_mad", sizeof(struct ib_mad_private), diff --git a/drivers/infiniband/core/mad_priv.h b/drivers/infiniband/core/mad_priv.h index f1ba794e0daa..570f78682af3 100644 --- a/drivers/infiniband/core/mad_priv.h +++ b/drivers/infiniband/core/mad_priv.h @@ -118,9 +118,10 @@ struct ib_mad_send_wr_private { struct ib_mad_list_head mad_list; struct list_head agent_list; struct ib_mad_agent_private *mad_agent_priv; + struct ib_mad_send_buf send_buf; + DECLARE_PCI_UNMAP_ADDR(mapping) struct ib_send_wr send_wr; struct ib_sge sg_list[IB_MAD_SEND_REQ_MAX_SG]; - u64 wr_id; /* client WR ID */ __be64 tid; unsigned long timeout; int retries; @@ -141,10 +142,7 @@ struct ib_mad_local_private { struct list_head completion_list; struct ib_mad_private *mad_priv; struct ib_mad_agent_private *recv_mad_agent; - struct ib_send_wr send_wr; - struct ib_sge sg_list[IB_MAD_SEND_REQ_MAX_SG]; - u64 wr_id; /* client WR ID */ - __be64 tid; + struct ib_mad_send_wr_private *mad_send_wr; }; struct ib_mad_mgmt_method_table { diff --git a/drivers/infiniband/core/mad_rmpp.c b/drivers/infiniband/core/mad_rmpp.c index e23836d0e21b..3249e1d8c07b 100644 --- a/drivers/infiniband/core/mad_rmpp.c +++ b/drivers/infiniband/core/mad_rmpp.c @@ -103,12 +103,12 @@ void ib_cancel_rmpp_recvs(struct ib_mad_agent_private *agent) static int data_offset(u8 mgmt_class) { if (mgmt_class == IB_MGMT_CLASS_SUBN_ADM) - return offsetof(struct ib_sa_mad, data); + return IB_MGMT_SA_HDR; else if ((mgmt_class >= IB_MGMT_CLASS_VENDOR_RANGE2_START) && (mgmt_class <= IB_MGMT_CLASS_VENDOR_RANGE2_END)) - return offsetof(struct ib_vendor_mad, data); + return IB_MGMT_VENDOR_HDR; else - return offsetof(struct ib_rmpp_mad, data); + return IB_MGMT_RMPP_HDR; } static void format_ack(struct ib_rmpp_mad *ack, @@ -135,55 +135,52 @@ static void ack_recv(struct mad_rmpp_recv *rmpp_recv, struct ib_mad_recv_wc *recv_wc) { struct ib_mad_send_buf *msg; - struct ib_send_wr *bad_send_wr; - int hdr_len, ret; + int ret; - hdr_len = sizeof(struct ib_mad_hdr) + sizeof(struct ib_rmpp_hdr); msg = ib_create_send_mad(&rmpp_recv->agent->agent, recv_wc->wc->src_qp, - recv_wc->wc->pkey_index, rmpp_recv->ah, 1, - hdr_len, sizeof(struct ib_rmpp_mad) - hdr_len, - GFP_KERNEL); + recv_wc->wc->pkey_index, 1, IB_MGMT_RMPP_HDR, + IB_MGMT_RMPP_DATA, GFP_KERNEL); if (!msg) return; - format_ack((struct ib_rmpp_mad *) msg->mad, - (struct ib_rmpp_mad *) recv_wc->recv_buf.mad, rmpp_recv); - ret = ib_post_send_mad(&rmpp_recv->agent->agent, &msg->send_wr, - &bad_send_wr); + format_ack(msg->mad, (struct ib_rmpp_mad *) recv_wc->recv_buf.mad, + rmpp_recv); + msg->ah = rmpp_recv->ah; + ret = ib_post_send_mad(msg, NULL); if (ret) ib_free_send_mad(msg); } -static int alloc_response_msg(struct ib_mad_agent *agent, - struct ib_mad_recv_wc *recv_wc, - struct ib_mad_send_buf **msg) +static struct ib_mad_send_buf *alloc_response_msg(struct ib_mad_agent *agent, + struct ib_mad_recv_wc *recv_wc) { - struct ib_mad_send_buf *m; + struct ib_mad_send_buf *msg; struct ib_ah *ah; - int hdr_len; ah = ib_create_ah_from_wc(agent->qp->pd, recv_wc->wc, recv_wc->recv_buf.grh, agent->port_num); if (IS_ERR(ah)) - return PTR_ERR(ah); - - hdr_len = sizeof(struct ib_mad_hdr) + sizeof(struct ib_rmpp_hdr); - m = ib_create_send_mad(agent, recv_wc->wc->src_qp, - recv_wc->wc->pkey_index, ah, 1, hdr_len, - sizeof(struct ib_rmpp_mad) - hdr_len, - GFP_KERNEL); - if (IS_ERR(m)) { + return (void *) ah; + + msg = ib_create_send_mad(agent, recv_wc->wc->src_qp, + recv_wc->wc->pkey_index, 1, + IB_MGMT_RMPP_HDR, IB_MGMT_RMPP_DATA, + GFP_KERNEL); + if (IS_ERR(msg)) ib_destroy_ah(ah); - return PTR_ERR(m); - } - *msg = m; - return 0; + else + msg->ah = ah; + + return msg; } -static void free_msg(struct ib_mad_send_buf *msg) +void ib_rmpp_send_handler(struct ib_mad_send_wc *mad_send_wc) { - ib_destroy_ah(msg->send_wr.wr.ud.ah); - ib_free_send_mad(msg); + struct ib_rmpp_mad *rmpp_mad = mad_send_wc->send_buf->mad; + + if (rmpp_mad->rmpp_hdr.rmpp_type != IB_MGMT_RMPP_TYPE_ACK) + ib_destroy_ah(mad_send_wc->send_buf->ah); + ib_free_send_mad(mad_send_wc->send_buf); } static void nack_recv(struct ib_mad_agent_private *agent, @@ -191,14 +188,13 @@ static void nack_recv(struct ib_mad_agent_private *agent, { struct ib_mad_send_buf *msg; struct ib_rmpp_mad *rmpp_mad; - struct ib_send_wr *bad_send_wr; int ret; - ret = alloc_response_msg(&agent->agent, recv_wc, &msg); - if (ret) + msg = alloc_response_msg(&agent->agent, recv_wc); + if (IS_ERR(msg)) return; - rmpp_mad = (struct ib_rmpp_mad *) msg->mad; + rmpp_mad = msg->mad; memcpy(rmpp_mad, recv_wc->recv_buf.mad, data_offset(recv_wc->recv_buf.mad->mad_hdr.mgmt_class)); @@ -210,9 +206,11 @@ static void nack_recv(struct ib_mad_agent_private *agent, rmpp_mad->rmpp_hdr.seg_num = 0; rmpp_mad->rmpp_hdr.paylen_newwin = 0; - ret = ib_post_send_mad(&agent->agent, &msg->send_wr, &bad_send_wr); - if (ret) - free_msg(msg); + ret = ib_post_send_mad(msg, NULL); + if (ret) { + ib_destroy_ah(msg->ah); + ib_free_send_mad(msg); + } } static void recv_timeout_handler(void *data) @@ -585,7 +583,7 @@ static int send_next_seg(struct ib_mad_send_wr_private *mad_send_wr) int timeout; u32 paylen; - rmpp_mad = (struct ib_rmpp_mad *)mad_send_wr->send_wr.wr.ud.mad_hdr; + rmpp_mad = mad_send_wr->send_buf.mad; ib_set_rmpp_flags(&rmpp_mad->rmpp_hdr, IB_MGMT_RMPP_FLAG_ACTIVE); rmpp_mad->rmpp_hdr.seg_num = cpu_to_be32(mad_send_wr->seg_num); @@ -612,7 +610,7 @@ static int send_next_seg(struct ib_mad_send_wr_private *mad_send_wr) } /* 2 seconds for an ACK until we can find the packet lifetime */ - timeout = mad_send_wr->send_wr.wr.ud.timeout_ms; + timeout = mad_send_wr->send_buf.timeout_ms; if (!timeout || timeout > 2000) mad_send_wr->timeout = msecs_to_jiffies(2000); mad_send_wr->seg_num++; @@ -640,7 +638,7 @@ static void abort_send(struct ib_mad_agent_private *agent, __be64 tid, wc.status = IB_WC_REM_ABORT_ERR; wc.vendor_err = rmpp_status; - wc.wr_id = mad_send_wr->wr_id; + wc.send_buf = &mad_send_wr->send_buf; ib_mad_complete_send_wr(mad_send_wr, &wc); return; out: @@ -694,12 +692,12 @@ static void process_rmpp_ack(struct ib_mad_agent_private *agent, if (seg_num > mad_send_wr->last_ack) { mad_send_wr->last_ack = seg_num; - mad_send_wr->retries = mad_send_wr->send_wr.wr.ud.retries; + mad_send_wr->retries = mad_send_wr->send_buf.retries; } mad_send_wr->newwin = newwin; if (mad_send_wr->last_ack == mad_send_wr->total_seg) { /* If no response is expected, the ACK completes the send */ - if (!mad_send_wr->send_wr.wr.ud.timeout_ms) { + if (!mad_send_wr->send_buf.timeout_ms) { struct ib_mad_send_wc wc; ib_mark_mad_done(mad_send_wr); @@ -707,13 +705,13 @@ static void process_rmpp_ack(struct ib_mad_agent_private *agent, wc.status = IB_WC_SUCCESS; wc.vendor_err = 0; - wc.wr_id = mad_send_wr->wr_id; + wc.send_buf = &mad_send_wr->send_buf; ib_mad_complete_send_wr(mad_send_wr, &wc); return; } if (mad_send_wr->refcount == 1) - ib_reset_mad_timeout(mad_send_wr, mad_send_wr-> - send_wr.wr.ud.timeout_ms); + ib_reset_mad_timeout(mad_send_wr, + mad_send_wr->send_buf.timeout_ms); } else if (mad_send_wr->refcount == 1 && mad_send_wr->seg_num < mad_send_wr->newwin && mad_send_wr->seg_num <= mad_send_wr->total_seg) { @@ -842,7 +840,7 @@ int ib_send_rmpp_mad(struct ib_mad_send_wr_private *mad_send_wr) struct ib_rmpp_mad *rmpp_mad; int i, total_len, ret; - rmpp_mad = (struct ib_rmpp_mad *)mad_send_wr->send_wr.wr.ud.mad_hdr; + rmpp_mad = mad_send_wr->send_buf.mad; if (!(ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) & IB_MGMT_RMPP_FLAG_ACTIVE)) return IB_RMPP_RESULT_UNHANDLED; @@ -863,7 +861,7 @@ int ib_send_rmpp_mad(struct ib_mad_send_wr_private *mad_send_wr) mad_send_wr->total_seg = (total_len - mad_send_wr->data_offset) / (sizeof(struct ib_rmpp_mad) - mad_send_wr->data_offset); - mad_send_wr->pad = total_len - offsetof(struct ib_rmpp_mad, data) - + mad_send_wr->pad = total_len - IB_MGMT_RMPP_HDR - be32_to_cpu(rmpp_mad->rmpp_hdr.paylen_newwin); /* We need to wait for the final ACK even if there isn't a response */ @@ -878,23 +876,15 @@ int ib_process_rmpp_send_wc(struct ib_mad_send_wr_private *mad_send_wr, struct ib_mad_send_wc *mad_send_wc) { struct ib_rmpp_mad *rmpp_mad; - struct ib_mad_send_buf *msg; int ret; - rmpp_mad = (struct ib_rmpp_mad *)mad_send_wr->send_wr.wr.ud.mad_hdr; + rmpp_mad = mad_send_wr->send_buf.mad; if (!(ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) & IB_MGMT_RMPP_FLAG_ACTIVE)) return IB_RMPP_RESULT_UNHANDLED; /* RMPP not active */ - if (rmpp_mad->rmpp_hdr.rmpp_type != IB_MGMT_RMPP_TYPE_DATA) { - msg = (struct ib_mad_send_buf *) (unsigned long) - mad_send_wc->wr_id; - if (rmpp_mad->rmpp_hdr.rmpp_type == IB_MGMT_RMPP_TYPE_ACK) - ib_free_send_mad(msg); - else - free_msg(msg); + if (rmpp_mad->rmpp_hdr.rmpp_type != IB_MGMT_RMPP_TYPE_DATA) return IB_RMPP_RESULT_INTERNAL; /* ACK, STOP, or ABORT */ - } if (mad_send_wc->status != IB_WC_SUCCESS || mad_send_wr->status != IB_WC_SUCCESS) @@ -905,7 +895,7 @@ int ib_process_rmpp_send_wc(struct ib_mad_send_wr_private *mad_send_wr, if (mad_send_wr->last_ack == mad_send_wr->total_seg) { mad_send_wr->timeout = - msecs_to_jiffies(mad_send_wr->send_wr.wr.ud.timeout_ms); + msecs_to_jiffies(mad_send_wr->send_buf.timeout_ms); return IB_RMPP_RESULT_PROCESSED; /* Send done */ } @@ -926,7 +916,7 @@ int ib_retry_rmpp(struct ib_mad_send_wr_private *mad_send_wr) struct ib_rmpp_mad *rmpp_mad; int ret; - rmpp_mad = (struct ib_rmpp_mad *)mad_send_wr->send_wr.wr.ud.mad_hdr; + rmpp_mad = mad_send_wr->send_buf.mad; if (!(ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) & IB_MGMT_RMPP_FLAG_ACTIVE)) return IB_RMPP_RESULT_UNHANDLED; /* RMPP not active */ diff --git a/drivers/infiniband/core/mad_rmpp.h b/drivers/infiniband/core/mad_rmpp.h index c4924dfb8e75..f0616fd22494 100644 --- a/drivers/infiniband/core/mad_rmpp.h +++ b/drivers/infiniband/core/mad_rmpp.h @@ -51,6 +51,8 @@ ib_process_rmpp_recv_wc(struct ib_mad_agent_private *agent, int ib_process_rmpp_send_wc(struct ib_mad_send_wr_private *mad_send_wr, struct ib_mad_send_wc *mad_send_wc); +void ib_rmpp_send_handler(struct ib_mad_send_wc *mad_send_wc); + void ib_cancel_rmpp_recvs(struct ib_mad_agent_private *agent); int ib_retry_rmpp(struct ib_mad_send_wr_private *mad_send_wr); diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c index 262618210c1c..acda7d63d6fe 100644 --- a/drivers/infiniband/core/sa_query.c +++ b/drivers/infiniband/core/sa_query.c @@ -43,6 +43,7 @@ #include <linux/dma-mapping.h> #include <linux/kref.h> #include <linux/idr.h> +#include <linux/workqueue.h> #include <rdma/ib_pack.h> #include <rdma/ib_sa.h> @@ -73,11 +74,10 @@ struct ib_sa_device { struct ib_sa_query { void (*callback)(struct ib_sa_query *, int, struct ib_sa_mad *); void (*release)(struct ib_sa_query *); - struct ib_sa_port *port; - struct ib_sa_mad *mad; - struct ib_sa_sm_ah *sm_ah; - DECLARE_PCI_UNMAP_ADDR(mapping) - int id; + struct ib_sa_port *port; + struct ib_mad_send_buf *mad_buf; + struct ib_sa_sm_ah *sm_ah; + int id; }; struct ib_sa_service_query { @@ -426,6 +426,7 @@ void ib_sa_cancel_query(int id, struct ib_sa_query *query) { unsigned long flags; struct ib_mad_agent *agent; + struct ib_mad_send_buf *mad_buf; spin_lock_irqsave(&idr_lock, flags); if (idr_find(&query_idr, id) != query) { @@ -433,9 +434,10 @@ void ib_sa_cancel_query(int id, struct ib_sa_query *query) return; } agent = query->port->agent; + mad_buf = query->mad_buf; spin_unlock_irqrestore(&idr_lock, flags); - ib_cancel_mad(agent, id); + ib_cancel_mad(agent, mad_buf); } EXPORT_SYMBOL(ib_sa_cancel_query); @@ -457,71 +459,46 @@ static void init_mad(struct ib_sa_mad *mad, struct ib_mad_agent *agent) static int send_mad(struct ib_sa_query *query, int timeout_ms) { - struct ib_sa_port *port = query->port; unsigned long flags; - int ret; - struct ib_sge gather_list; - struct ib_send_wr *bad_wr, wr = { - .opcode = IB_WR_SEND, - .sg_list = &gather_list, - .num_sge = 1, - .send_flags = IB_SEND_SIGNALED, - .wr = { - .ud = { - .mad_hdr = &query->mad->mad_hdr, - .remote_qpn = 1, - .remote_qkey = IB_QP1_QKEY, - .timeout_ms = timeout_ms, - } - } - }; + int ret, id; retry: if (!idr_pre_get(&query_idr, GFP_ATOMIC)) return -ENOMEM; spin_lock_irqsave(&idr_lock, flags); - ret = idr_get_new(&query_idr, query, &query->id); + ret = idr_get_new(&query_idr, query, &id); spin_unlock_irqrestore(&idr_lock, flags); if (ret == -EAGAIN) goto retry; if (ret) return ret; - wr.wr_id = query->id; + query->mad_buf->timeout_ms = timeout_ms; + query->mad_buf->context[0] = query; + query->id = id; - spin_lock_irqsave(&port->ah_lock, flags); - kref_get(&port->sm_ah->ref); - query->sm_ah = port->sm_ah; - wr.wr.ud.ah = port->sm_ah->ah; - spin_unlock_irqrestore(&port->ah_lock, flags); + spin_lock_irqsave(&query->port->ah_lock, flags); + kref_get(&query->port->sm_ah->ref); + query->sm_ah = query->port->sm_ah; + spin_unlock_irqrestore(&query->port->ah_lock, flags); - gather_list.addr = dma_map_single(port->agent->device->dma_device, - query->mad, - sizeof (struct ib_sa_mad), - DMA_TO_DEVICE); - gather_list.length = sizeof (struct ib_sa_mad); - gather_list.lkey = port->agent->mr->lkey; - pci_unmap_addr_set(query, mapping, gather_list.addr); + query->mad_buf->ah = query->sm_ah->ah; - ret = ib_post_send_mad(port->agent, &wr, &bad_wr); + ret = ib_post_send_mad(query->mad_buf, NULL); if (ret) { - dma_unmap_single(port->agent->device->dma_device, - pci_unmap_addr(query, mapping), - sizeof (struct ib_sa_mad), - DMA_TO_DEVICE); - kref_put(&query->sm_ah->ref, free_sm_ah); spin_lock_irqsave(&idr_lock, flags); - idr_remove(&query_idr, query->id); + idr_remove(&query_idr, id); spin_unlock_irqrestore(&idr_lock, flags); + + kref_put(&query->sm_ah->ref, free_sm_ah); } /* * It's not safe to dereference query any more, because the * send may already have completed and freed the query in - * another context. So use wr.wr_id, which has a copy of the - * query's id. + * another context. */ - return ret ? ret : wr.wr_id; + return ret ? ret : id; } static void ib_sa_path_rec_callback(struct ib_sa_query *sa_query, @@ -543,7 +520,6 @@ static void ib_sa_path_rec_callback(struct ib_sa_query *sa_query, static void ib_sa_path_rec_release(struct ib_sa_query *sa_query) { - kfree(sa_query->mad); kfree(container_of(sa_query, struct ib_sa_path_query, sa_query)); } @@ -583,43 +559,58 @@ int ib_sa_path_rec_get(struct ib_device *device, u8 port_num, { struct ib_sa_path_query *query; struct ib_sa_device *sa_dev = ib_get_client_data(device, &sa_client); - struct ib_sa_port *port = &sa_dev->port[port_num - sa_dev->start_port]; - struct ib_mad_agent *agent = port->agent; + struct ib_sa_port *port; + struct ib_mad_agent *agent; + struct ib_sa_mad *mad; int ret; + if (!sa_dev) + return -ENODEV; + + port = &sa_dev->port[port_num - sa_dev->start_port]; + agent = port->agent; + query = kmalloc(sizeof *query, gfp_mask); if (!query) return -ENOMEM; - query->sa_query.mad = kmalloc(sizeof *query->sa_query.mad, gfp_mask); - if (!query->sa_query.mad) { - kfree(query); - return -ENOMEM; + + query->sa_query.mad_buf = ib_create_send_mad(agent, 1, 0, + 0, IB_MGMT_SA_HDR, + IB_MGMT_SA_DATA, gfp_mask); + if (!query->sa_query.mad_buf) { + ret = -ENOMEM; + goto err1; } query->callback = callback; query->context = context; - init_mad(query->sa_query.mad, agent); + mad = query->sa_query.mad_buf->mad; + init_mad(mad, agent); - query->sa_query.callback = callback ? ib_sa_path_rec_callback : NULL; - query->sa_query.release = ib_sa_path_rec_release; - query->sa_query.port = port; - query->sa_query.mad->mad_hdr.method = IB_MGMT_METHOD_GET; - query->sa_query.mad->mad_hdr.attr_id = cpu_to_be16(IB_SA_ATTR_PATH_REC); - query->sa_query.mad->sa_hdr.comp_mask = comp_mask; + query->sa_query.callback = callback ? ib_sa_path_rec_callback : NULL; + query->sa_query.release = ib_sa_path_rec_release; + query->sa_query.port = port; + mad->mad_hdr.method = IB_MGMT_METHOD_GET; + mad->mad_hdr.attr_id = cpu_to_be16(IB_SA_ATTR_PATH_REC); + mad->sa_hdr.comp_mask = comp_mask; - ib_pack(path_rec_table, ARRAY_SIZE(path_rec_table), - rec, query->sa_query.mad->data); + ib_pack(path_rec_table, ARRAY_SIZE(path_rec_table), rec, mad->data); *sa_query = &query->sa_query; ret = send_mad(&query->sa_query, timeout_ms); - if (ret < 0) { - *sa_query = NULL; - kfree(query->sa_query.mad); - kfree(query); - } + if (ret < 0) + goto err2; + + return ret; +err2: + *sa_query = NULL; + ib_free_send_mad(query->sa_query.mad_buf); + +err1: + kfree(query); return ret; } EXPORT_SYMBOL(ib_sa_path_rec_get); @@ -643,7 +634,6 @@ static void ib_sa_service_rec_callback(struct ib_sa_query *sa_query, static void ib_sa_service_rec_release(struct ib_sa_query *sa_query) { - kfree(sa_query->mad); kfree(container_of(sa_query, struct ib_sa_service_query, sa_query)); } @@ -685,10 +675,17 @@ int ib_sa_service_rec_query(struct ib_device *device, u8 port_num, u8 method, { struct ib_sa_service_query *query; struct ib_sa_device *sa_dev = ib_get_client_data(device, &sa_client); - struct ib_sa_port *port = &sa_dev->port[port_num - sa_dev->start_port]; - struct ib_mad_agent *agent = port->agent; + struct ib_sa_port *port; + struct ib_mad_agent *agent; + struct ib_sa_mad *mad; int ret; + if (!sa_dev) + return -ENODEV; + + port = &sa_dev->port[port_num - sa_dev->start_port]; + agent = port->agent; + if (method != IB_MGMT_METHOD_GET && method != IB_MGMT_METHOD_SET && method != IB_SA_METHOD_DELETE) @@ -697,37 +694,45 @@ int ib_sa_service_rec_query(struct ib_device *device, u8 port_num, u8 method, query = kmalloc(sizeof *query, gfp_mask); if (!query) return -ENOMEM; - query->sa_query.mad = kmalloc(sizeof *query->sa_query.mad, gfp_mask); - if (!query->sa_query.mad) { - kfree(query); - return -ENOMEM; + + query->sa_query.mad_buf = ib_create_send_mad(agent, 1, 0, + 0, IB_MGMT_SA_HDR, + IB_MGMT_SA_DATA, gfp_mask); + if (!query->sa_query.mad_buf) { + ret = -ENOMEM; + goto err1; } query->callback = callback; query->context = context; - init_mad(query->sa_query.mad, agent); + mad = query->sa_query.mad_buf->mad; + init_mad(mad, agent); - query->sa_query.callback = callback ? ib_sa_service_rec_callback : NULL; - query->sa_query.release = ib_sa_service_rec_release; - query->sa_query.port = port; - query->sa_query.mad->mad_hdr.method = method; - query->sa_query.mad->mad_hdr.attr_id = - cpu_to_be16(IB_SA_ATTR_SERVICE_REC); - query->sa_query.mad->sa_hdr.comp_mask = comp_mask; + query->sa_query.callback = callback ? ib_sa_service_rec_callback : NULL; + query->sa_query.release = ib_sa_service_rec_release; + query->sa_query.port = port; + mad->mad_hdr.method = method; + mad->mad_hdr.attr_id = cpu_to_be16(IB_SA_ATTR_SERVICE_REC); + mad->sa_hdr.comp_mask = comp_mask; ib_pack(service_rec_table, ARRAY_SIZE(service_rec_table), - rec, query->sa_query.mad->data); + rec, mad->data); *sa_query = &query->sa_query; ret = send_mad(&query->sa_query, timeout_ms); - if (ret < 0) { - *sa_query = NULL; - kfree(query->sa_query.mad); - kfree(query); - } + if (ret < 0) + goto err2; + + return ret; +err2: + *sa_query = NULL; + ib_free_send_mad(query->sa_query.mad_buf); + +err1: + kfree(query); return ret; } EXPORT_SYMBOL(ib_sa_service_rec_query); @@ -751,7 +756,6 @@ static void ib_sa_mcmember_rec_callback(struct ib_sa_query *sa_query, static void ib_sa_mcmember_rec_release(struct ib_sa_query *sa_query) { - kfree(sa_query->mad); kfree(container_of(sa_query, struct ib_sa_mcmember_query, sa_query)); } @@ -768,60 +772,69 @@ int ib_sa_mcmember_rec_query(struct ib_device *device, u8 port_num, { struct ib_sa_mcmember_query *query; struct ib_sa_device *sa_dev = ib_get_client_data(device, &sa_client); - struct ib_sa_port *port = &sa_dev->port[port_num - sa_dev->start_port]; - struct ib_mad_agent *agent = port->agent; + struct ib_sa_port *port; + struct ib_mad_agent *agent; + struct ib_sa_mad *mad; int ret; + if (!sa_dev) + return -ENODEV; + + port = &sa_dev->port[port_num - sa_dev->start_port]; + agent = port->agent; + query = kmalloc(sizeof *query, gfp_mask); if (!query) return -ENOMEM; - query->sa_query.mad = kmalloc(sizeof *query->sa_query.mad, gfp_mask); - if (!query->sa_query.mad) { - kfree(query); - return -ENOMEM; + + query->sa_query.mad_buf = ib_create_send_mad(agent, 1, 0, + 0, IB_MGMT_SA_HDR, + IB_MGMT_SA_DATA, gfp_mask); + if (!query->sa_query.mad_buf) { + ret = -ENOMEM; + goto err1; } query->callback = callback; query->context = context; - init_mad(query->sa_query.mad, agent); + mad = query->sa_query.mad_buf->mad; + init_mad(mad, agent); - query->sa_query.callback = callback ? ib_sa_mcmember_rec_callback : NULL; - query->sa_query.release = ib_sa_mcmember_rec_release; - query->sa_query.port = port; - query->sa_query.mad->mad_hdr.method = method; - query->sa_query.mad->mad_hdr.attr_id = cpu_to_be16(IB_SA_ATTR_MC_MEMBER_REC); - query->sa_query.mad->sa_hdr.comp_mask = comp_mask; + query->sa_query.callback = callback ? ib_sa_mcmember_rec_callback : NULL; + query->sa_query.release = ib_sa_mcmember_rec_release; + query->sa_query.port = port; + mad->mad_hdr.method = method; + mad->mad_hdr.attr_id = cpu_to_be16(IB_SA_ATTR_MC_MEMBER_REC); + mad->sa_hdr.comp_mask = comp_mask; ib_pack(mcmember_rec_table, ARRAY_SIZE(mcmember_rec_table), - rec, query->sa_query.mad->data); + rec, mad->data); *sa_query = &query->sa_query; ret = send_mad(&query->sa_query, timeout_ms); - if (ret < 0) { - *sa_query = NULL; - kfree(query->sa_query.mad); - kfree(query); - } + if (ret < 0) + goto err2; return ret; + +err2: + *sa_query = NULL; + ib_free_send_mad(query->sa_query.mad_buf); + +err1: + kfree(query); + return ret; } EXPORT_SYMBOL(ib_sa_mcmember_rec_query); static void send_handler(struct ib_mad_agent *agent, struct ib_mad_send_wc *mad_send_wc) { - struct ib_sa_query *query; + struct ib_sa_query *query = mad_send_wc->send_buf->context[0]; unsigned long flags; - spin_lock_irqsave(&idr_lock, flags); - query = idr_find(&query_idr, mad_send_wc->wr_id); - spin_unlock_irqrestore(&idr_lock, flags); - - if (!query) - return; - if (query->callback) switch (mad_send_wc->status) { case IB_WC_SUCCESS: @@ -838,30 +851,25 @@ static void send_handler(struct ib_mad_agent *agent, break; } - dma_unmap_single(agent->device->dma_device, - pci_unmap_addr(query, mapping), - sizeof (struct ib_sa_mad), - DMA_TO_DEVICE); - kref_put(&query->sm_ah->ref, free_sm_ah); - - query->release(query); - spin_lock_irqsave(&idr_lock, flags); - idr_remove(&query_idr, mad_send_wc->wr_id); + idr_remove(&query_idr, query->id); spin_unlock_irqrestore(&idr_lock, flags); + + ib_free_send_mad(mad_send_wc->send_buf); + kref_put(&query->sm_ah->ref, free_sm_ah); + query->release(query); } static void recv_handler(struct ib_mad_agent *mad_agent, struct ib_mad_recv_wc *mad_recv_wc) { struct ib_sa_query *query; - unsigned long flags; + struct ib_mad_send_buf *mad_buf; - spin_lock_irqsave(&idr_lock, flags); - query = idr_find(&query_idr, mad_recv_wc->wc->wr_id); - spin_unlock_irqrestore(&idr_lock, flags); + mad_buf = (void *) (unsigned long) mad_recv_wc->wc->wr_id; + query = mad_buf->context[0]; - if (query && query->callback) { + if (query->callback) { if (mad_recv_wc->wc->status == IB_WC_SUCCESS) query->callback(query, mad_recv_wc->recv_buf.mad->mad_hdr.status ? @@ -975,6 +983,7 @@ static int __init ib_sa_init(void) static void __exit ib_sa_cleanup(void) { ib_unregister_client(&sa_client); + idr_destroy(&query_idr); } module_init(ib_sa_init); diff --git a/drivers/infiniband/core/smi.h b/drivers/infiniband/core/smi.h index db25503a0736..2b3c40198f81 100644 --- a/drivers/infiniband/core/smi.h +++ b/drivers/infiniband/core/smi.h @@ -39,6 +39,8 @@ #ifndef __SMI_H_ #define __SMI_H_ +#include <rdma/ib_smi.h> + int smi_handle_dr_smp_recv(struct ib_smp *smp, u8 node_type, int port_num, diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c index 211ba3223f65..7ce7a6c782fa 100644 --- a/drivers/infiniband/core/sysfs.c +++ b/drivers/infiniband/core/sysfs.c @@ -65,6 +65,11 @@ struct port_table_attribute { int index; }; +static inline int ibdev_is_alive(const struct ib_device *dev) +{ + return dev->reg_state == IB_DEV_REGISTERED; +} + static ssize_t port_attr_show(struct kobject *kobj, struct attribute *attr, char *buf) { @@ -74,6 +79,8 @@ static ssize_t port_attr_show(struct kobject *kobj, if (!port_attr->show) return -EIO; + if (!ibdev_is_alive(p->ibdev)) + return -ENODEV; return port_attr->show(p, port_attr, buf); } @@ -581,6 +588,9 @@ static ssize_t show_node_type(struct class_device *cdev, char *buf) { struct ib_device *dev = container_of(cdev, struct ib_device, class_dev); + if (!ibdev_is_alive(dev)) + return -ENODEV; + switch (dev->node_type) { case IB_NODE_CA: return sprintf(buf, "%d: CA\n", dev->node_type); case IB_NODE_SWITCH: return sprintf(buf, "%d: switch\n", dev->node_type); @@ -595,6 +605,9 @@ static ssize_t show_sys_image_guid(struct class_device *cdev, char *buf) struct ib_device_attr attr; ssize_t ret; + if (!ibdev_is_alive(dev)) + return -ENODEV; + ret = ib_query_device(dev, &attr); if (ret) return ret; @@ -612,6 +625,9 @@ static ssize_t show_node_guid(struct class_device *cdev, char *buf) struct ib_device_attr attr; ssize_t ret; + if (!ibdev_is_alive(dev)) + return -ENODEV; + ret = ib_query_device(dev, &attr); if (ret) return ret; diff --git a/drivers/infiniband/core/ucm.c b/drivers/infiniband/core/ucm.c index d0f0b0a2edd3..28477565ecba 100644 --- a/drivers/infiniband/core/ucm.c +++ b/drivers/infiniband/core/ucm.c @@ -41,37 +41,81 @@ #include <linux/file.h> #include <linux/mount.h> #include <linux/cdev.h> +#include <linux/idr.h> #include <asm/uaccess.h> -#include "ucm.h" +#include <rdma/ib_cm.h> +#include <rdma/ib_user_cm.h> MODULE_AUTHOR("Libor Michalek"); MODULE_DESCRIPTION("InfiniBand userspace Connection Manager access"); MODULE_LICENSE("Dual BSD/GPL"); -static int ucm_debug_level; +struct ib_ucm_device { + int devnum; + struct cdev dev; + struct class_device class_dev; + struct ib_device *ib_dev; +}; + +struct ib_ucm_file { + struct semaphore mutex; + struct file *filp; + struct ib_ucm_device *device; + + struct list_head ctxs; + struct list_head events; + wait_queue_head_t poll_wait; +}; + +struct ib_ucm_context { + int id; + wait_queue_head_t wait; + atomic_t ref; + int events_reported; + + struct ib_ucm_file *file; + struct ib_cm_id *cm_id; + __u64 uid; + + struct list_head events; /* list of pending events. */ + struct list_head file_list; /* member in file ctx list */ +}; + +struct ib_ucm_event { + struct ib_ucm_context *ctx; + struct list_head file_list; /* member in file event list */ + struct list_head ctx_list; /* member in ctx event list */ -module_param_named(debug_level, ucm_debug_level, int, 0644); -MODULE_PARM_DESC(debug_level, "Enable debug tracing if > 0"); + struct ib_cm_id *cm_id; + struct ib_ucm_event_resp resp; + void *data; + void *info; + int data_len; + int info_len; +}; enum { IB_UCM_MAJOR = 231, - IB_UCM_MINOR = 255 + IB_UCM_BASE_MINOR = 224, + IB_UCM_MAX_DEVICES = 32 }; -#define IB_UCM_DEV MKDEV(IB_UCM_MAJOR, IB_UCM_MINOR) +#define IB_UCM_BASE_DEV MKDEV(IB_UCM_MAJOR, IB_UCM_BASE_MINOR) -#define PFX "UCM: " +static void ib_ucm_add_one(struct ib_device *device); +static void ib_ucm_remove_one(struct ib_device *device); -#define ucm_dbg(format, arg...) \ - do { \ - if (ucm_debug_level > 0) \ - printk(KERN_DEBUG PFX format, ## arg); \ - } while (0) +static struct ib_client ucm_client = { + .name = "ucm", + .add = ib_ucm_add_one, + .remove = ib_ucm_remove_one +}; -static struct semaphore ctx_id_mutex; -static struct idr ctx_id_table; +static DECLARE_MUTEX(ctx_id_mutex); +static DEFINE_IDR(ctx_id_table); +static DECLARE_BITMAP(dev_map, IB_UCM_MAX_DEVICES); static struct ib_ucm_context *ib_ucm_ctx_get(struct ib_ucm_file *file, int id) { @@ -152,17 +196,13 @@ static struct ib_ucm_context *ib_ucm_ctx_alloc(struct ib_ucm_file *file) goto error; list_add_tail(&ctx->file_list, &file->ctxs); - ucm_dbg("Allocated CM ID <%d>\n", ctx->id); return ctx; error: kfree(ctx); return NULL; } -/* - * Event portion of the API, handle CM events - * and allow event polling. - */ + static void ib_ucm_event_path_get(struct ib_ucm_path_rec *upath, struct ib_sa_path_rec *kpath) { @@ -209,6 +249,7 @@ static void ib_ucm_event_req_get(struct ib_ucm_req_event_resp *ureq, ureq->retry_count = kreq->retry_count; ureq->rnr_retry_count = kreq->rnr_retry_count; ureq->srq = kreq->srq; + ureq->port = kreq->port; ib_ucm_event_path_get(&ureq->primary_path, kreq->primary_path); ib_ucm_event_path_get(&ureq->alternate_path, kreq->alternate_path); @@ -295,6 +336,8 @@ static int ib_ucm_event_process(struct ib_cm_event *evt, case IB_CM_SIDR_REQ_RECEIVED: uvt->resp.u.sidr_req_resp.pkey = evt->param.sidr_req_rcvd.pkey; + uvt->resp.u.sidr_req_resp.port = + evt->param.sidr_req_rcvd.port; uvt->data_len = IB_CM_SIDR_REQ_PRIVATE_DATA_SIZE; break; case IB_CM_SIDR_REP_RECEIVED: @@ -387,9 +430,7 @@ static ssize_t ib_ucm_event(struct ib_ucm_file *file, if (copy_from_user(&cmd, inbuf, sizeof(cmd))) return -EFAULT; - /* - * wait - */ + down(&file->mutex); while (list_empty(&file->events)) { @@ -471,7 +512,6 @@ done: return result; } - static ssize_t ib_ucm_create_id(struct ib_ucm_file *file, const char __user *inbuf, int in_len, int out_len) @@ -494,29 +534,27 @@ static ssize_t ib_ucm_create_id(struct ib_ucm_file *file, return -ENOMEM; ctx->uid = cmd.uid; - ctx->cm_id = ib_create_cm_id(ib_ucm_event_handler, ctx); + ctx->cm_id = ib_create_cm_id(file->device->ib_dev, + ib_ucm_event_handler, ctx); if (IS_ERR(ctx->cm_id)) { result = PTR_ERR(ctx->cm_id); - goto err; + goto err1; } resp.id = ctx->id; if (copy_to_user((void __user *)(unsigned long)cmd.response, &resp, sizeof(resp))) { result = -EFAULT; - goto err; + goto err2; } - return 0; -err: +err2: + ib_destroy_cm_id(ctx->cm_id); +err1: down(&ctx_id_mutex); idr_remove(&ctx_id_table, ctx->id); up(&ctx_id_mutex); - - if (!IS_ERR(ctx->cm_id)) - ib_destroy_cm_id(ctx->cm_id); - kfree(ctx); return result; } @@ -1184,9 +1222,6 @@ static ssize_t ib_ucm_write(struct file *filp, const char __user *buf, if (copy_from_user(&hdr, buf, sizeof(hdr))) return -EFAULT; - ucm_dbg("Write. cmd <%d> in <%d> out <%d> len <%Zu>\n", - hdr.cmd, hdr.in, hdr.out, len); - if (hdr.cmd < 0 || hdr.cmd >= ARRAY_SIZE(ucm_cmd_table)) return -EINVAL; @@ -1231,8 +1266,7 @@ static int ib_ucm_open(struct inode *inode, struct file *filp) filp->private_data = file; file->filp = filp; - - ucm_dbg("Created struct\n"); + file->device = container_of(inode->i_cdev, struct ib_ucm_device, dev); return 0; } @@ -1263,7 +1297,17 @@ static int ib_ucm_close(struct inode *inode, struct file *filp) return 0; } -static struct file_operations ib_ucm_fops = { +static void ib_ucm_release_class_dev(struct class_device *class_dev) +{ + struct ib_ucm_device *dev; + + dev = container_of(class_dev, struct ib_ucm_device, class_dev); + cdev_del(&dev->dev); + clear_bit(dev->devnum, dev_map); + kfree(dev); +} + +static struct file_operations ucm_fops = { .owner = THIS_MODULE, .open = ib_ucm_open, .release = ib_ucm_close, @@ -1271,55 +1315,142 @@ static struct file_operations ib_ucm_fops = { .poll = ib_ucm_poll, }; +static struct class ucm_class = { + .name = "infiniband_cm", + .release = ib_ucm_release_class_dev +}; -static struct class *ib_ucm_class; -static struct cdev ib_ucm_cdev; +static ssize_t show_dev(struct class_device *class_dev, char *buf) +{ + struct ib_ucm_device *dev; + + dev = container_of(class_dev, struct ib_ucm_device, class_dev); + return print_dev_t(buf, dev->dev.dev); +} +static CLASS_DEVICE_ATTR(dev, S_IRUGO, show_dev, NULL); -static int __init ib_ucm_init(void) +static ssize_t show_ibdev(struct class_device *class_dev, char *buf) { - int result; + struct ib_ucm_device *dev; + + dev = container_of(class_dev, struct ib_ucm_device, class_dev); + return sprintf(buf, "%s\n", dev->ib_dev->name); +} +static CLASS_DEVICE_ATTR(ibdev, S_IRUGO, show_ibdev, NULL); - result = register_chrdev_region(IB_UCM_DEV, 1, "infiniband_cm"); - if (result) { - ucm_dbg("Error <%d> registering dev\n", result); - goto err_chr; - } +static void ib_ucm_add_one(struct ib_device *device) +{ + struct ib_ucm_device *ucm_dev; + + if (!device->alloc_ucontext) + return; + + ucm_dev = kmalloc(sizeof *ucm_dev, GFP_KERNEL); + if (!ucm_dev) + return; - cdev_init(&ib_ucm_cdev, &ib_ucm_fops); + memset(ucm_dev, 0, sizeof *ucm_dev); + ucm_dev->ib_dev = device; + + ucm_dev->devnum = find_first_zero_bit(dev_map, IB_UCM_MAX_DEVICES); + if (ucm_dev->devnum >= IB_UCM_MAX_DEVICES) + goto err; + + set_bit(ucm_dev->devnum, dev_map); + + cdev_init(&ucm_dev->dev, &ucm_fops); + ucm_dev->dev.owner = THIS_MODULE; + kobject_set_name(&ucm_dev->dev.kobj, "ucm%d", ucm_dev->devnum); + if (cdev_add(&ucm_dev->dev, IB_UCM_BASE_DEV + ucm_dev->devnum, 1)) + goto err; - result = cdev_add(&ib_ucm_cdev, IB_UCM_DEV, 1); - if (result) { - ucm_dbg("Error <%d> adding cdev\n", result); + ucm_dev->class_dev.class = &ucm_class; + ucm_dev->class_dev.dev = device->dma_device; + snprintf(ucm_dev->class_dev.class_id, BUS_ID_SIZE, "ucm%d", + ucm_dev->devnum); + if (class_device_register(&ucm_dev->class_dev)) goto err_cdev; - } - ib_ucm_class = class_create(THIS_MODULE, "infiniband_cm"); - if (IS_ERR(ib_ucm_class)) { - result = PTR_ERR(ib_ucm_class); - ucm_dbg("Error <%d> creating class\n", result); + if (class_device_create_file(&ucm_dev->class_dev, + &class_device_attr_dev)) + goto err_class; + if (class_device_create_file(&ucm_dev->class_dev, + &class_device_attr_ibdev)) goto err_class; + + ib_set_client_data(device, &ucm_client, ucm_dev); + return; + +err_class: + class_device_unregister(&ucm_dev->class_dev); +err_cdev: + cdev_del(&ucm_dev->dev); + clear_bit(ucm_dev->devnum, dev_map); +err: + kfree(ucm_dev); + return; +} + +static void ib_ucm_remove_one(struct ib_device *device) +{ + struct ib_ucm_device *ucm_dev = ib_get_client_data(device, &ucm_client); + + if (!ucm_dev) + return; + + class_device_unregister(&ucm_dev->class_dev); +} + +static ssize_t show_abi_version(struct class *class, char *buf) +{ + return sprintf(buf, "%d\n", IB_USER_CM_ABI_VERSION); +} +static CLASS_ATTR(abi_version, S_IRUGO, show_abi_version, NULL); + +static int __init ib_ucm_init(void) +{ + int ret; + + ret = register_chrdev_region(IB_UCM_BASE_DEV, IB_UCM_MAX_DEVICES, + "infiniband_cm"); + if (ret) { + printk(KERN_ERR "ucm: couldn't register device number\n"); + goto err; } - class_device_create(ib_ucm_class, IB_UCM_DEV, NULL, "ucm"); + ret = class_register(&ucm_class); + if (ret) { + printk(KERN_ERR "ucm: couldn't create class infiniband_cm\n"); + goto err_chrdev; + } - idr_init(&ctx_id_table); - init_MUTEX(&ctx_id_mutex); + ret = class_create_file(&ucm_class, &class_attr_abi_version); + if (ret) { + printk(KERN_ERR "ucm: couldn't create abi_version attribute\n"); + goto err_class; + } + ret = ib_register_client(&ucm_client); + if (ret) { + printk(KERN_ERR "ucm: couldn't register client\n"); + goto err_class; + } return 0; + err_class: - cdev_del(&ib_ucm_cdev); -err_cdev: - unregister_chrdev_region(IB_UCM_DEV, 1); -err_chr: - return result; + class_unregister(&ucm_class); +err_chrdev: + unregister_chrdev_region(IB_UCM_BASE_DEV, IB_UCM_MAX_DEVICES); +err: + return ret; } static void __exit ib_ucm_cleanup(void) { - class_device_destroy(ib_ucm_class, IB_UCM_DEV); - class_destroy(ib_ucm_class); - cdev_del(&ib_ucm_cdev); - unregister_chrdev_region(IB_UCM_DEV, 1); + ib_unregister_client(&ucm_client); + class_unregister(&ucm_class); + unregister_chrdev_region(IB_UCM_BASE_DEV, IB_UCM_MAX_DEVICES); + idr_destroy(&ctx_id_table); } module_init(ib_ucm_init); diff --git a/drivers/infiniband/core/ucm.h b/drivers/infiniband/core/ucm.h deleted file mode 100644 index f46f37bc1201..000000000000 --- a/drivers/infiniband/core/ucm.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2005 Topspin Communications. All rights reserved. - * Copyright (c) 2005 Intel Corporation. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * $Id: ucm.h 2208 2005-04-22 23:24:31Z libor $ - */ - -#ifndef UCM_H -#define UCM_H - -#include <linux/fs.h> -#include <linux/device.h> -#include <linux/cdev.h> -#include <linux/idr.h> - -#include <rdma/ib_cm.h> -#include <rdma/ib_user_cm.h> - -struct ib_ucm_file { - struct semaphore mutex; - struct file *filp; - - struct list_head ctxs; /* list of active connections */ - struct list_head events; /* list of pending events */ - wait_queue_head_t poll_wait; -}; - -struct ib_ucm_context { - int id; - wait_queue_head_t wait; - atomic_t ref; - int events_reported; - - struct ib_ucm_file *file; - struct ib_cm_id *cm_id; - __u64 uid; - - struct list_head events; /* list of pending events. */ - struct list_head file_list; /* member in file ctx list */ -}; - -struct ib_ucm_event { - struct ib_ucm_context *ctx; - struct list_head file_list; /* member in file event list */ - struct list_head ctx_list; /* member in ctx event list */ - - struct ib_cm_id *cm_id; - struct ib_ucm_event_resp resp; - void *data; - void *info; - int data_len; - int info_len; -}; - -#endif /* UCM_H */ diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c index a64d6b4dcc16..97128e25f78b 100644 --- a/drivers/infiniband/core/user_mad.c +++ b/drivers/infiniband/core/user_mad.c @@ -64,18 +64,39 @@ enum { IB_UMAD_MINOR_BASE = 0 }; +/* + * Our lifetime rules for these structs are the following: each time a + * device special file is opened, we look up the corresponding struct + * ib_umad_port by minor in the umad_port[] table while holding the + * port_lock. If this lookup succeeds, we take a reference on the + * ib_umad_port's struct ib_umad_device while still holding the + * port_lock; if the lookup fails, we fail the open(). We drop these + * references in the corresponding close(). + * + * In addition to references coming from open character devices, there + * is one more reference to each ib_umad_device representing the + * module's reference taken when allocating the ib_umad_device in + * ib_umad_add_one(). + * + * When destroying an ib_umad_device, we clear all of its + * ib_umad_ports from umad_port[] while holding port_lock before + * dropping the module's reference to the ib_umad_device. This is + * always safe because any open() calls will either succeed and obtain + * a reference before we clear the umad_port[] entries, or fail after + * we clear the umad_port[] entries. + */ + struct ib_umad_port { - int devnum; - struct cdev dev; - struct class_device class_dev; + struct cdev *dev; + struct class_device *class_dev; - int sm_devnum; - struct cdev sm_dev; - struct class_device sm_class_dev; + struct cdev *sm_dev; + struct class_device *sm_class_dev; struct semaphore sm_sem; struct ib_device *ib_dev; struct ib_umad_device *umad_dev; + int dev_num; u8 port_num; }; @@ -96,21 +117,31 @@ struct ib_umad_file { }; struct ib_umad_packet { - struct ib_ah *ah; struct ib_mad_send_buf *msg; struct list_head list; int length; - DECLARE_PCI_UNMAP_ADDR(mapping) struct ib_user_mad mad; }; +static struct class *umad_class; + static const dev_t base_dev = MKDEV(IB_UMAD_MAJOR, IB_UMAD_MINOR_BASE); -static spinlock_t map_lock; + +static DEFINE_SPINLOCK(port_lock); +static struct ib_umad_port *umad_port[IB_UMAD_MAX_PORTS]; static DECLARE_BITMAP(dev_map, IB_UMAD_MAX_PORTS * 2); static void ib_umad_add_one(struct ib_device *device); static void ib_umad_remove_one(struct ib_device *device); +static void ib_umad_release_dev(struct kref *ref) +{ + struct ib_umad_device *dev = + container_of(ref, struct ib_umad_device, ref); + + kfree(dev); +} + static int queue_packet(struct ib_umad_file *file, struct ib_mad_agent *agent, struct ib_umad_packet *packet) @@ -139,22 +170,19 @@ static void send_handler(struct ib_mad_agent *agent, struct ib_mad_send_wc *send_wc) { struct ib_umad_file *file = agent->context; - struct ib_umad_packet *timeout, *packet = - (void *) (unsigned long) send_wc->wr_id; + struct ib_umad_packet *timeout; + struct ib_umad_packet *packet = send_wc->send_buf->context[0]; - ib_destroy_ah(packet->msg->send_wr.wr.ud.ah); + ib_destroy_ah(packet->msg->ah); ib_free_send_mad(packet->msg); if (send_wc->status == IB_WC_RESP_TIMEOUT_ERR) { - timeout = kmalloc(sizeof *timeout + sizeof (struct ib_mad_hdr), - GFP_KERNEL); + timeout = kzalloc(sizeof *timeout + IB_MGMT_MAD_HDR, GFP_KERNEL); if (!timeout) goto out; - memset(timeout, 0, sizeof *timeout + sizeof (struct ib_mad_hdr)); - - timeout->length = sizeof (struct ib_mad_hdr); - timeout->mad.hdr.id = packet->mad.hdr.id; + timeout->length = IB_MGMT_MAD_HDR; + timeout->mad.hdr.id = packet->mad.hdr.id; timeout->mad.hdr.status = ETIMEDOUT; memcpy(timeout->mad.data, packet->mad.data, sizeof (struct ib_mad_hdr)); @@ -177,11 +205,10 @@ static void recv_handler(struct ib_mad_agent *agent, goto out; length = mad_recv_wc->mad_len; - packet = kmalloc(sizeof *packet + length, GFP_KERNEL); + packet = kzalloc(sizeof *packet + length, GFP_KERNEL); if (!packet) goto out; - memset(packet, 0, sizeof *packet + length); packet->length = length; ib_coalesce_recv_mad(mad_recv_wc, packet->mad.data); @@ -247,7 +274,7 @@ static ssize_t ib_umad_read(struct file *filp, char __user *buf, else ret = -ENOSPC; } else if (copy_to_user(buf, &packet->mad, - packet->length + sizeof (struct ib_user_mad))) + packet->length + sizeof (struct ib_user_mad))) ret = -EFAULT; else ret = packet->length + sizeof (struct ib_user_mad); @@ -268,26 +295,23 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf, struct ib_umad_packet *packet; struct ib_mad_agent *agent; struct ib_ah_attr ah_attr; - struct ib_send_wr *bad_wr; + struct ib_ah *ah; struct ib_rmpp_mad *rmpp_mad; u8 method; __be64 *tid; - int ret, length, hdr_len, data_len, rmpp_hdr_size; + int ret, length, hdr_len, copy_offset; int rmpp_active = 0; if (count < sizeof (struct ib_user_mad)) return -EINVAL; length = count - sizeof (struct ib_user_mad); - packet = kmalloc(sizeof *packet + sizeof(struct ib_mad_hdr) + - sizeof(struct ib_rmpp_hdr), GFP_KERNEL); + packet = kmalloc(sizeof *packet + IB_MGMT_RMPP_HDR, GFP_KERNEL); if (!packet) return -ENOMEM; if (copy_from_user(&packet->mad, buf, - sizeof (struct ib_user_mad) + - sizeof(struct ib_mad_hdr) + - sizeof(struct ib_rmpp_hdr))) { + sizeof (struct ib_user_mad) + IB_MGMT_RMPP_HDR)) { ret = -EFAULT; goto err; } @@ -298,8 +322,6 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf, goto err; } - packet->length = length; - down_read(&file->agent_mutex); agent = file->agent[packet->mad.hdr.id]; @@ -321,9 +343,9 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf, ah_attr.grh.traffic_class = packet->mad.hdr.traffic_class; } - packet->ah = ib_create_ah(agent->qp->pd, &ah_attr); - if (IS_ERR(packet->ah)) { - ret = PTR_ERR(packet->ah); + ah = ib_create_ah(agent->qp->pd, &ah_attr); + if (IS_ERR(ah)) { + ret = PTR_ERR(ah); goto err_up; } @@ -337,64 +359,44 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf, /* Validate that the management class can support RMPP */ if (rmpp_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_ADM) { - hdr_len = offsetof(struct ib_sa_mad, data); - data_len = length - hdr_len; + hdr_len = IB_MGMT_SA_HDR; } else if ((rmpp_mad->mad_hdr.mgmt_class >= IB_MGMT_CLASS_VENDOR_RANGE2_START) && (rmpp_mad->mad_hdr.mgmt_class <= IB_MGMT_CLASS_VENDOR_RANGE2_END)) { - hdr_len = offsetof(struct ib_vendor_mad, data); - data_len = length - hdr_len; + hdr_len = IB_MGMT_VENDOR_HDR; } else { ret = -EINVAL; goto err_ah; } rmpp_active = 1; + copy_offset = IB_MGMT_RMPP_HDR; } else { - if (length > sizeof(struct ib_mad)) { - ret = -EINVAL; - goto err_ah; - } - hdr_len = offsetof(struct ib_mad, data); - data_len = length - hdr_len; + hdr_len = IB_MGMT_MAD_HDR; + copy_offset = IB_MGMT_MAD_HDR; } packet->msg = ib_create_send_mad(agent, be32_to_cpu(packet->mad.hdr.qpn), - 0, packet->ah, rmpp_active, - hdr_len, data_len, + 0, rmpp_active, + hdr_len, length - hdr_len, GFP_KERNEL); if (IS_ERR(packet->msg)) { ret = PTR_ERR(packet->msg); goto err_ah; } - packet->msg->send_wr.wr.ud.timeout_ms = packet->mad.hdr.timeout_ms; - packet->msg->send_wr.wr.ud.retries = packet->mad.hdr.retries; - - /* Override send WR WRID initialized in ib_create_send_mad */ - packet->msg->send_wr.wr_id = (unsigned long) packet; - - if (!rmpp_active) { - /* Copy message from user into send buffer */ - if (copy_from_user(packet->msg->mad, - buf + sizeof(struct ib_user_mad), length)) { - ret = -EFAULT; - goto err_msg; - } - } else { - rmpp_hdr_size = sizeof(struct ib_mad_hdr) + - sizeof(struct ib_rmpp_hdr); + packet->msg->ah = ah; + packet->msg->timeout_ms = packet->mad.hdr.timeout_ms; + packet->msg->retries = packet->mad.hdr.retries; + packet->msg->context[0] = packet; - /* Only copy MAD headers (RMPP header in place) */ - memcpy(packet->msg->mad, packet->mad.data, - sizeof(struct ib_mad_hdr)); - - /* Now, copy rest of message from user into send buffer */ - if (copy_from_user(((struct ib_rmpp_mad *) packet->msg->mad)->data, - buf + sizeof (struct ib_user_mad) + rmpp_hdr_size, - length - rmpp_hdr_size)) { - ret = -EFAULT; - goto err_msg; - } + /* Copy MAD headers (RMPP header in place) */ + memcpy(packet->msg->mad, packet->mad.data, IB_MGMT_MAD_HDR); + /* Now, copy rest of message from user into send buffer */ + if (copy_from_user(packet->msg->mad + copy_offset, + buf + sizeof (struct ib_user_mad) + copy_offset, + length - copy_offset)) { + ret = -EFAULT; + goto err_msg; } /* @@ -403,29 +405,29 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf, * transaction ID matches the agent being used to send the * MAD. */ - method = packet->msg->mad->mad_hdr.method; + method = ((struct ib_mad_hdr *) packet->msg->mad)->method; if (!(method & IB_MGMT_METHOD_RESP) && method != IB_MGMT_METHOD_TRAP_REPRESS && method != IB_MGMT_METHOD_SEND) { - tid = &packet->msg->mad->mad_hdr.tid; + tid = &((struct ib_mad_hdr *) packet->msg->mad)->tid; *tid = cpu_to_be64(((u64) agent->hi_tid) << 32 | (be64_to_cpup(tid) & 0xffffffff)); } - ret = ib_post_send_mad(agent, &packet->msg->send_wr, &bad_wr); + ret = ib_post_send_mad(packet->msg, NULL); if (ret) goto err_msg; up_read(&file->agent_mutex); - return sizeof (struct ib_user_mad_hdr) + packet->length; + return count; err_msg: ib_free_send_mad(packet->msg); err_ah: - ib_destroy_ah(packet->ah); + ib_destroy_ah(ah); err_up: up_read(&file->agent_mutex); @@ -565,15 +567,23 @@ static long ib_umad_ioctl(struct file *filp, unsigned int cmd, static int ib_umad_open(struct inode *inode, struct file *filp) { - struct ib_umad_port *port = - container_of(inode->i_cdev, struct ib_umad_port, dev); + struct ib_umad_port *port; struct ib_umad_file *file; - file = kmalloc(sizeof *file, GFP_KERNEL); - if (!file) - return -ENOMEM; + spin_lock(&port_lock); + port = umad_port[iminor(inode) - IB_UMAD_MINOR_BASE]; + if (port) + kref_get(&port->umad_dev->ref); + spin_unlock(&port_lock); - memset(file, 0, sizeof *file); + if (!port) + return -ENXIO; + + file = kzalloc(sizeof *file, GFP_KERNEL); + if (!file) { + kref_put(&port->umad_dev->ref, ib_umad_release_dev); + return -ENOMEM; + } spin_lock_init(&file->recv_lock); init_rwsem(&file->agent_mutex); @@ -589,6 +599,7 @@ static int ib_umad_open(struct inode *inode, struct file *filp) static int ib_umad_close(struct inode *inode, struct file *filp) { struct ib_umad_file *file = filp->private_data; + struct ib_umad_device *dev = file->port->umad_dev; struct ib_umad_packet *packet, *tmp; int i; @@ -603,6 +614,8 @@ static int ib_umad_close(struct inode *inode, struct file *filp) kfree(file); + kref_put(&dev->ref, ib_umad_release_dev); + return 0; } @@ -619,30 +632,46 @@ static struct file_operations umad_fops = { static int ib_umad_sm_open(struct inode *inode, struct file *filp) { - struct ib_umad_port *port = - container_of(inode->i_cdev, struct ib_umad_port, sm_dev); + struct ib_umad_port *port; struct ib_port_modify props = { .set_port_cap_mask = IB_PORT_SM }; int ret; + spin_lock(&port_lock); + port = umad_port[iminor(inode) - IB_UMAD_MINOR_BASE - IB_UMAD_MAX_PORTS]; + if (port) + kref_get(&port->umad_dev->ref); + spin_unlock(&port_lock); + + if (!port) + return -ENXIO; + if (filp->f_flags & O_NONBLOCK) { - if (down_trylock(&port->sm_sem)) - return -EAGAIN; + if (down_trylock(&port->sm_sem)) { + ret = -EAGAIN; + goto fail; + } } else { - if (down_interruptible(&port->sm_sem)) - return -ERESTARTSYS; + if (down_interruptible(&port->sm_sem)) { + ret = -ERESTARTSYS; + goto fail; + } } ret = ib_modify_port(port->ib_dev, port->port_num, 0, &props); if (ret) { up(&port->sm_sem); - return ret; + goto fail; } filp->private_data = port; return 0; + +fail: + kref_put(&port->umad_dev->ref, ib_umad_release_dev); + return ret; } static int ib_umad_sm_close(struct inode *inode, struct file *filp) @@ -656,6 +685,8 @@ static int ib_umad_sm_close(struct inode *inode, struct file *filp) ret = ib_modify_port(port->ib_dev, port->port_num, 0, &props); up(&port->sm_sem); + kref_put(&port->umad_dev->ref, ib_umad_release_dev); + return ret; } @@ -671,21 +702,13 @@ static struct ib_client umad_client = { .remove = ib_umad_remove_one }; -static ssize_t show_dev(struct class_device *class_dev, char *buf) -{ - struct ib_umad_port *port = class_get_devdata(class_dev); - - if (class_dev == &port->class_dev) - return print_dev_t(buf, port->dev.dev); - else - return print_dev_t(buf, port->sm_dev.dev); -} -static CLASS_DEVICE_ATTR(dev, S_IRUGO, show_dev, NULL); - static ssize_t show_ibdev(struct class_device *class_dev, char *buf) { struct ib_umad_port *port = class_get_devdata(class_dev); + if (!port) + return -ENODEV; + return sprintf(buf, "%s\n", port->ib_dev->name); } static CLASS_DEVICE_ATTR(ibdev, S_IRUGO, show_ibdev, NULL); @@ -694,38 +717,13 @@ static ssize_t show_port(struct class_device *class_dev, char *buf) { struct ib_umad_port *port = class_get_devdata(class_dev); + if (!port) + return -ENODEV; + return sprintf(buf, "%d\n", port->port_num); } static CLASS_DEVICE_ATTR(port, S_IRUGO, show_port, NULL); -static void ib_umad_release_dev(struct kref *ref) -{ - struct ib_umad_device *dev = - container_of(ref, struct ib_umad_device, ref); - - kfree(dev); -} - -static void ib_umad_release_port(struct class_device *class_dev) -{ - struct ib_umad_port *port = class_get_devdata(class_dev); - - if (class_dev == &port->class_dev) { - cdev_del(&port->dev); - clear_bit(port->devnum, dev_map); - } else { - cdev_del(&port->sm_dev); - clear_bit(port->sm_devnum, dev_map); - } - - kref_put(&port->umad_dev->ref, ib_umad_release_dev); -} - -static struct class umad_class = { - .name = "infiniband_mad", - .release = ib_umad_release_port -}; - static ssize_t show_abi_version(struct class *class, char *buf) { return sprintf(buf, "%d\n", IB_USER_MAD_ABI_VERSION); @@ -735,91 +733,102 @@ static CLASS_ATTR(abi_version, S_IRUGO, show_abi_version, NULL); static int ib_umad_init_port(struct ib_device *device, int port_num, struct ib_umad_port *port) { - spin_lock(&map_lock); - port->devnum = find_first_zero_bit(dev_map, IB_UMAD_MAX_PORTS); - if (port->devnum >= IB_UMAD_MAX_PORTS) { - spin_unlock(&map_lock); + spin_lock(&port_lock); + port->dev_num = find_first_zero_bit(dev_map, IB_UMAD_MAX_PORTS); + if (port->dev_num >= IB_UMAD_MAX_PORTS) { + spin_unlock(&port_lock); return -1; } - port->sm_devnum = find_next_zero_bit(dev_map, IB_UMAD_MAX_PORTS * 2, IB_UMAD_MAX_PORTS); - if (port->sm_devnum >= IB_UMAD_MAX_PORTS * 2) { - spin_unlock(&map_lock); - return -1; - } - set_bit(port->devnum, dev_map); - set_bit(port->sm_devnum, dev_map); - spin_unlock(&map_lock); + set_bit(port->dev_num, dev_map); + spin_unlock(&port_lock); port->ib_dev = device; port->port_num = port_num; init_MUTEX(&port->sm_sem); - cdev_init(&port->dev, &umad_fops); - port->dev.owner = THIS_MODULE; - kobject_set_name(&port->dev.kobj, "umad%d", port->devnum); - if (cdev_add(&port->dev, base_dev + port->devnum, 1)) + port->dev = cdev_alloc(); + if (!port->dev) return -1; - - port->class_dev.class = &umad_class; - port->class_dev.dev = device->dma_device; - - snprintf(port->class_dev.class_id, BUS_ID_SIZE, "umad%d", port->devnum); - - if (class_device_register(&port->class_dev)) + port->dev->owner = THIS_MODULE; + port->dev->ops = &umad_fops; + kobject_set_name(&port->dev->kobj, "umad%d", port->dev_num); + if (cdev_add(port->dev, base_dev + port->dev_num, 1)) goto err_cdev; - class_set_devdata(&port->class_dev, port); - kref_get(&port->umad_dev->ref); + port->class_dev = class_device_create(umad_class, NULL, port->dev->dev, + device->dma_device, + "umad%d", port->dev_num); + if (IS_ERR(port->class_dev)) + goto err_cdev; - if (class_device_create_file(&port->class_dev, &class_device_attr_dev)) - goto err_class; - if (class_device_create_file(&port->class_dev, &class_device_attr_ibdev)) + if (class_device_create_file(port->class_dev, &class_device_attr_ibdev)) goto err_class; - if (class_device_create_file(&port->class_dev, &class_device_attr_port)) + if (class_device_create_file(port->class_dev, &class_device_attr_port)) goto err_class; - cdev_init(&port->sm_dev, &umad_sm_fops); - port->sm_dev.owner = THIS_MODULE; - kobject_set_name(&port->dev.kobj, "issm%d", port->sm_devnum - IB_UMAD_MAX_PORTS); - if (cdev_add(&port->sm_dev, base_dev + port->sm_devnum, 1)) - return -1; - - port->sm_class_dev.class = &umad_class; - port->sm_class_dev.dev = device->dma_device; - - snprintf(port->sm_class_dev.class_id, BUS_ID_SIZE, "issm%d", port->sm_devnum - IB_UMAD_MAX_PORTS); + port->sm_dev = cdev_alloc(); + if (!port->sm_dev) + goto err_class; + port->sm_dev->owner = THIS_MODULE; + port->sm_dev->ops = &umad_sm_fops; + kobject_set_name(&port->dev->kobj, "issm%d", port->dev_num); + if (cdev_add(port->sm_dev, base_dev + port->dev_num + IB_UMAD_MAX_PORTS, 1)) + goto err_sm_cdev; - if (class_device_register(&port->sm_class_dev)) + port->sm_class_dev = class_device_create(umad_class, NULL, port->sm_dev->dev, + device->dma_device, + "issm%d", port->dev_num); + if (IS_ERR(port->sm_class_dev)) goto err_sm_cdev; - class_set_devdata(&port->sm_class_dev, port); - kref_get(&port->umad_dev->ref); + class_set_devdata(port->class_dev, port); + class_set_devdata(port->sm_class_dev, port); - if (class_device_create_file(&port->sm_class_dev, &class_device_attr_dev)) - goto err_sm_class; - if (class_device_create_file(&port->sm_class_dev, &class_device_attr_ibdev)) + if (class_device_create_file(port->sm_class_dev, &class_device_attr_ibdev)) goto err_sm_class; - if (class_device_create_file(&port->sm_class_dev, &class_device_attr_port)) + if (class_device_create_file(port->sm_class_dev, &class_device_attr_port)) goto err_sm_class; + spin_lock(&port_lock); + umad_port[port->dev_num] = port; + spin_unlock(&port_lock); + return 0; err_sm_class: - class_device_unregister(&port->sm_class_dev); + class_device_destroy(umad_class, port->sm_dev->dev); err_sm_cdev: - cdev_del(&port->sm_dev); + cdev_del(port->sm_dev); err_class: - class_device_unregister(&port->class_dev); + class_device_destroy(umad_class, port->dev->dev); err_cdev: - cdev_del(&port->dev); - clear_bit(port->devnum, dev_map); + cdev_del(port->dev); + clear_bit(port->dev_num, dev_map); return -1; } +static void ib_umad_kill_port(struct ib_umad_port *port) +{ + class_set_devdata(port->class_dev, NULL); + class_set_devdata(port->sm_class_dev, NULL); + + class_device_destroy(umad_class, port->dev->dev); + class_device_destroy(umad_class, port->sm_dev->dev); + + cdev_del(port->dev); + cdev_del(port->sm_dev); + + spin_lock(&port_lock); + umad_port[port->dev_num] = NULL; + spin_unlock(&port_lock); + + clear_bit(port->dev_num, dev_map); +} + static void ib_umad_add_one(struct ib_device *device) { struct ib_umad_device *umad_dev; @@ -832,15 +841,12 @@ static void ib_umad_add_one(struct ib_device *device) e = device->phys_port_cnt; } - umad_dev = kmalloc(sizeof *umad_dev + + umad_dev = kzalloc(sizeof *umad_dev + (e - s + 1) * sizeof (struct ib_umad_port), GFP_KERNEL); if (!umad_dev) return; - memset(umad_dev, 0, sizeof *umad_dev + - (e - s + 1) * sizeof (struct ib_umad_port)); - kref_init(&umad_dev->ref); umad_dev->start_port = s; @@ -858,10 +864,8 @@ static void ib_umad_add_one(struct ib_device *device) return; err: - while (--i >= s) { - class_device_unregister(&umad_dev->port[i - s].class_dev); - class_device_unregister(&umad_dev->port[i - s].sm_class_dev); - } + while (--i >= s) + ib_umad_kill_port(&umad_dev->port[i]); kref_put(&umad_dev->ref, ib_umad_release_dev); } @@ -874,10 +878,8 @@ static void ib_umad_remove_one(struct ib_device *device) if (!umad_dev) return; - for (i = 0; i <= umad_dev->end_port - umad_dev->start_port; ++i) { - class_device_unregister(&umad_dev->port[i].class_dev); - class_device_unregister(&umad_dev->port[i].sm_class_dev); - } + for (i = 0; i <= umad_dev->end_port - umad_dev->start_port; ++i) + ib_umad_kill_port(&umad_dev->port[i]); kref_put(&umad_dev->ref, ib_umad_release_dev); } @@ -886,8 +888,6 @@ static int __init ib_umad_init(void) { int ret; - spin_lock_init(&map_lock); - ret = register_chrdev_region(base_dev, IB_UMAD_MAX_PORTS * 2, "infiniband_mad"); if (ret) { @@ -895,13 +895,14 @@ static int __init ib_umad_init(void) goto out; } - ret = class_register(&umad_class); - if (ret) { + umad_class = class_create(THIS_MODULE, "infiniband_mad"); + if (IS_ERR(umad_class)) { + ret = PTR_ERR(umad_class); printk(KERN_ERR "user_mad: couldn't create class infiniband_mad\n"); goto out_chrdev; } - ret = class_create_file(&umad_class, &class_attr_abi_version); + ret = class_create_file(umad_class, &class_attr_abi_version); if (ret) { printk(KERN_ERR "user_mad: couldn't create abi_version attribute\n"); goto out_class; @@ -916,7 +917,7 @@ static int __init ib_umad_init(void) return 0; out_class: - class_unregister(&umad_class); + class_destroy(umad_class); out_chrdev: unregister_chrdev_region(base_dev, IB_UMAD_MAX_PORTS * 2); @@ -928,7 +929,7 @@ out: static void __exit ib_umad_cleanup(void) { ib_unregister_client(&umad_client); - class_unregister(&umad_class); + class_destroy(umad_class); unregister_chrdev_region(base_dev, IB_UMAD_MAX_PORTS * 2); } diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h index cc124344dd2c..031cdf3c066d 100644 --- a/drivers/infiniband/core/uverbs.h +++ b/drivers/infiniband/core/uverbs.h @@ -3,6 +3,7 @@ * Copyright (c) 2005 Cisco Systems. All rights reserved. * Copyright (c) 2005 Mellanox Technologies. All rights reserved. * Copyright (c) 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2005 PathScale, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -38,29 +39,47 @@ #ifndef UVERBS_H #define UVERBS_H -/* Include device.h and fs.h until cdev.h is self-sufficient */ -#include <linux/fs.h> -#include <linux/device.h> -#include <linux/cdev.h> #include <linux/kref.h> #include <linux/idr.h> #include <rdma/ib_verbs.h> #include <rdma/ib_user_verbs.h> +/* + * Our lifetime rules for these structs are the following: + * + * struct ib_uverbs_device: One reference is held by the module and + * released in ib_uverbs_remove_one(). Another reference is taken by + * ib_uverbs_open() each time the character special file is opened, + * and released in ib_uverbs_release_file() when the file is released. + * + * struct ib_uverbs_file: One reference is held by the VFS and + * released when the file is closed. Another reference is taken when + * an asynchronous event queue file is created and released when the + * event file is closed. + * + * struct ib_uverbs_event_file: One reference is held by the VFS and + * released when the file is closed. For asynchronous event files, + * another reference is held by the corresponding main context file + * and released when that file is closed. For completion event files, + * a reference is taken when a CQ is created that uses the file, and + * released when the CQ is destroyed. + */ + struct ib_uverbs_device { + struct kref ref; int devnum; - struct cdev dev; - struct class_device class_dev; + struct cdev *dev; + struct class_device *class_dev; struct ib_device *ib_dev; - int num_comp; + int num_comp_vectors; }; struct ib_uverbs_event_file { struct kref ref; + struct file *file; struct ib_uverbs_file *uverbs_file; spinlock_t lock; - int fd; int is_async; wait_queue_head_t poll_wait; struct fasync_struct *async_queue; @@ -73,8 +92,7 @@ struct ib_uverbs_file { struct ib_uverbs_device *device; struct ib_ucontext *ucontext; struct ib_event_handler event_handler; - struct ib_uverbs_event_file async_file; - struct ib_uverbs_event_file comp_file[1]; + struct ib_uverbs_event_file *async_file; }; struct ib_uverbs_event { @@ -110,10 +128,23 @@ extern struct idr ib_uverbs_cq_idr; extern struct idr ib_uverbs_qp_idr; extern struct idr ib_uverbs_srq_idr; +struct file *ib_uverbs_alloc_event_file(struct ib_uverbs_file *uverbs_file, + int is_async, int *fd); +void ib_uverbs_release_event_file(struct kref *ref); +struct ib_uverbs_event_file *ib_uverbs_lookup_comp_file(int fd); + +void ib_uverbs_release_ucq(struct ib_uverbs_file *file, + struct ib_uverbs_event_file *ev_file, + struct ib_ucq_object *uobj); +void ib_uverbs_release_uevent(struct ib_uverbs_file *file, + struct ib_uevent_object *uobj); + void ib_uverbs_comp_handler(struct ib_cq *cq, void *cq_context); void ib_uverbs_cq_event_handler(struct ib_event *event, void *context_ptr); void ib_uverbs_qp_event_handler(struct ib_event *event, void *context_ptr); void ib_uverbs_srq_event_handler(struct ib_event *event, void *context_ptr); +void ib_uverbs_event_handler(struct ib_event_handler *handler, + struct ib_event *event); int ib_umem_get(struct ib_device *dev, struct ib_umem *mem, void *addr, size_t size, int write); @@ -125,21 +156,26 @@ void ib_umem_release_on_close(struct ib_device *dev, struct ib_umem *umem); const char __user *buf, int in_len, \ int out_len) -IB_UVERBS_DECLARE_CMD(query_params); IB_UVERBS_DECLARE_CMD(get_context); IB_UVERBS_DECLARE_CMD(query_device); IB_UVERBS_DECLARE_CMD(query_port); -IB_UVERBS_DECLARE_CMD(query_gid); -IB_UVERBS_DECLARE_CMD(query_pkey); IB_UVERBS_DECLARE_CMD(alloc_pd); IB_UVERBS_DECLARE_CMD(dealloc_pd); IB_UVERBS_DECLARE_CMD(reg_mr); IB_UVERBS_DECLARE_CMD(dereg_mr); +IB_UVERBS_DECLARE_CMD(create_comp_channel); IB_UVERBS_DECLARE_CMD(create_cq); +IB_UVERBS_DECLARE_CMD(poll_cq); +IB_UVERBS_DECLARE_CMD(req_notify_cq); IB_UVERBS_DECLARE_CMD(destroy_cq); IB_UVERBS_DECLARE_CMD(create_qp); IB_UVERBS_DECLARE_CMD(modify_qp); IB_UVERBS_DECLARE_CMD(destroy_qp); +IB_UVERBS_DECLARE_CMD(post_send); +IB_UVERBS_DECLARE_CMD(post_recv); +IB_UVERBS_DECLARE_CMD(post_srq_recv); +IB_UVERBS_DECLARE_CMD(create_ah); +IB_UVERBS_DECLARE_CMD(destroy_ah); IB_UVERBS_DECLARE_CMD(attach_mcast); IB_UVERBS_DECLARE_CMD(detach_mcast); IB_UVERBS_DECLARE_CMD(create_srq); diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index 562445165d2b..8c89abc8c764 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -1,6 +1,7 @@ /* * Copyright (c) 2005 Topspin Communications. All rights reserved. * Copyright (c) 2005 Cisco Systems. All rights reserved. + * Copyright (c) 2005 PathScale, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -33,6 +34,9 @@ * $Id: uverbs_cmd.c 2708 2005-06-24 17:27:21Z roland $ */ +#include <linux/file.h> +#include <linux/fs.h> + #include <asm/uaccess.h> #include "uverbs.h" @@ -45,29 +49,6 @@ (udata)->outlen = (olen); \ } while (0) -ssize_t ib_uverbs_query_params(struct ib_uverbs_file *file, - const char __user *buf, - int in_len, int out_len) -{ - struct ib_uverbs_query_params cmd; - struct ib_uverbs_query_params_resp resp; - - if (out_len < sizeof resp) - return -ENOSPC; - - if (copy_from_user(&cmd, buf, sizeof cmd)) - return -EFAULT; - - memset(&resp, 0, sizeof resp); - - resp.num_cq_events = file->device->num_comp; - - if (copy_to_user((void __user *) (unsigned long) cmd.response, &resp, sizeof resp)) - return -EFAULT; - - return in_len; -} - ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file, const char __user *buf, int in_len, int out_len) @@ -77,7 +58,7 @@ ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file, struct ib_udata udata; struct ib_device *ibdev = file->device->ib_dev; struct ib_ucontext *ucontext; - int i; + struct file *filp; int ret; if (out_len < sizeof resp) @@ -110,26 +91,42 @@ ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file, INIT_LIST_HEAD(&ucontext->srq_list); INIT_LIST_HEAD(&ucontext->ah_list); - resp.async_fd = file->async_file.fd; - for (i = 0; i < file->device->num_comp; ++i) - if (copy_to_user((void __user *) (unsigned long) cmd.cq_fd_tab + - i * sizeof (__u32), - &file->comp_file[i].fd, sizeof (__u32))) { - ret = -EFAULT; - goto err_free; - } + resp.num_comp_vectors = file->device->num_comp_vectors; + + filp = ib_uverbs_alloc_event_file(file, 1, &resp.async_fd); + if (IS_ERR(filp)) { + ret = PTR_ERR(filp); + goto err_free; + } if (copy_to_user((void __user *) (unsigned long) cmd.response, &resp, sizeof resp)) { ret = -EFAULT; - goto err_free; + goto err_file; } + file->async_file = filp->private_data; + + INIT_IB_EVENT_HANDLER(&file->event_handler, file->device->ib_dev, + ib_uverbs_event_handler); + ret = ib_register_event_handler(&file->event_handler); + if (ret) + goto err_file; + + kref_get(&file->async_file->ref); + kref_get(&file->ref); file->ucontext = ucontext; + + fd_install(resp.async_fd, filp); + up(&file->mutex); return in_len; +err_file: + put_unused_fd(resp.async_fd); + fput(filp); + err_free: ibdev->dealloc_ucontext(ucontext); @@ -255,62 +252,6 @@ ssize_t ib_uverbs_query_port(struct ib_uverbs_file *file, return in_len; } -ssize_t ib_uverbs_query_gid(struct ib_uverbs_file *file, - const char __user *buf, - int in_len, int out_len) -{ - struct ib_uverbs_query_gid cmd; - struct ib_uverbs_query_gid_resp resp; - int ret; - - if (out_len < sizeof resp) - return -ENOSPC; - - if (copy_from_user(&cmd, buf, sizeof cmd)) - return -EFAULT; - - memset(&resp, 0, sizeof resp); - - ret = ib_query_gid(file->device->ib_dev, cmd.port_num, cmd.index, - (union ib_gid *) resp.gid); - if (ret) - return ret; - - if (copy_to_user((void __user *) (unsigned long) cmd.response, - &resp, sizeof resp)) - return -EFAULT; - - return in_len; -} - -ssize_t ib_uverbs_query_pkey(struct ib_uverbs_file *file, - const char __user *buf, - int in_len, int out_len) -{ - struct ib_uverbs_query_pkey cmd; - struct ib_uverbs_query_pkey_resp resp; - int ret; - - if (out_len < sizeof resp) - return -ENOSPC; - - if (copy_from_user(&cmd, buf, sizeof cmd)) - return -EFAULT; - - memset(&resp, 0, sizeof resp); - - ret = ib_query_pkey(file->device->ib_dev, cmd.port_num, cmd.index, - &resp.pkey); - if (ret) - return ret; - - if (copy_to_user((void __user *) (unsigned long) cmd.response, - &resp, sizeof resp)) - return -EFAULT; - - return in_len; -} - ssize_t ib_uverbs_alloc_pd(struct ib_uverbs_file *file, const char __user *buf, int in_len, int out_len) @@ -349,24 +290,20 @@ ssize_t ib_uverbs_alloc_pd(struct ib_uverbs_file *file, pd->uobject = uobj; atomic_set(&pd->usecnt, 0); + down(&ib_uverbs_idr_mutex); + retry: if (!idr_pre_get(&ib_uverbs_pd_idr, GFP_KERNEL)) { ret = -ENOMEM; - goto err_pd; + goto err_up; } - down(&ib_uverbs_idr_mutex); ret = idr_get_new(&ib_uverbs_pd_idr, pd, &uobj->id); - up(&ib_uverbs_idr_mutex); if (ret == -EAGAIN) goto retry; if (ret) - goto err_pd; - - down(&file->mutex); - list_add_tail(&uobj->list, &file->ucontext->pd_list); - up(&file->mutex); + goto err_up; memset(&resp, 0, sizeof resp); resp.pd_handle = uobj->id; @@ -374,21 +311,22 @@ retry: if (copy_to_user((void __user *) (unsigned long) cmd.response, &resp, sizeof resp)) { ret = -EFAULT; - goto err_list; + goto err_idr; } - return in_len; - -err_list: - down(&file->mutex); - list_del(&uobj->list); + down(&file->mutex); + list_add_tail(&uobj->list, &file->ucontext->pd_list); up(&file->mutex); - down(&ib_uverbs_idr_mutex); - idr_remove(&ib_uverbs_pd_idr, uobj->id); up(&ib_uverbs_idr_mutex); -err_pd: + return in_len; + +err_idr: + idr_remove(&ib_uverbs_pd_idr, uobj->id); + +err_up: + up(&ib_uverbs_idr_mutex); ib_dealloc_pd(pd); err: @@ -459,6 +397,14 @@ ssize_t ib_uverbs_reg_mr(struct ib_uverbs_file *file, if ((cmd.start & ~PAGE_MASK) != (cmd.hca_va & ~PAGE_MASK)) return -EINVAL; + /* + * Local write permission is required if remote write or + * remote atomic permission is also requested. + */ + if (cmd.access_flags & (IB_ACCESS_REMOTE_ATOMIC | IB_ACCESS_REMOTE_WRITE) && + !(cmd.access_flags & IB_ACCESS_LOCAL_WRITE)) + return -EINVAL; + obj = kmalloc(sizeof *obj, GFP_KERNEL); if (!obj) return -ENOMEM; @@ -524,24 +470,22 @@ retry: resp.mr_handle = obj->uobject.id; - down(&file->mutex); - list_add_tail(&obj->uobject.list, &file->ucontext->mr_list); - up(&file->mutex); - if (copy_to_user((void __user *) (unsigned long) cmd.response, &resp, sizeof resp)) { ret = -EFAULT; - goto err_list; + goto err_idr; } + down(&file->mutex); + list_add_tail(&obj->uobject.list, &file->ucontext->mr_list); + up(&file->mutex); + up(&ib_uverbs_idr_mutex); return in_len; -err_list: - down(&file->mutex); - list_del(&obj->uobject.list); - up(&file->mutex); +err_idr: + idr_remove(&ib_uverbs_mr_idr, obj->uobject.id); err_unreg: ib_dereg_mr(mr); @@ -595,6 +539,35 @@ out: return ret ? ret : in_len; } +ssize_t ib_uverbs_create_comp_channel(struct ib_uverbs_file *file, + const char __user *buf, int in_len, + int out_len) +{ + struct ib_uverbs_create_comp_channel cmd; + struct ib_uverbs_create_comp_channel_resp resp; + struct file *filp; + + if (out_len < sizeof resp) + return -ENOSPC; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + filp = ib_uverbs_alloc_event_file(file, 0, &resp.fd); + if (IS_ERR(filp)) + return PTR_ERR(filp); + + if (copy_to_user((void __user *) (unsigned long) cmd.response, + &resp, sizeof resp)) { + put_unused_fd(resp.fd); + fput(filp); + return -EFAULT; + } + + fd_install(resp.fd, filp); + return in_len; +} + ssize_t ib_uverbs_create_cq(struct ib_uverbs_file *file, const char __user *buf, int in_len, int out_len) @@ -603,6 +576,7 @@ ssize_t ib_uverbs_create_cq(struct ib_uverbs_file *file, struct ib_uverbs_create_cq_resp resp; struct ib_udata udata; struct ib_ucq_object *uobj; + struct ib_uverbs_event_file *ev_file = NULL; struct ib_cq *cq; int ret; @@ -616,9 +590,12 @@ ssize_t ib_uverbs_create_cq(struct ib_uverbs_file *file, (unsigned long) cmd.response + sizeof resp, in_len - sizeof cmd, out_len - sizeof resp); - if (cmd.event_handler >= file->device->num_comp) + if (cmd.comp_vector >= file->device->num_comp_vectors) return -EINVAL; + if (cmd.comp_channel >= 0) + ev_file = ib_uverbs_lookup_comp_file(cmd.comp_channel); + uobj = kmalloc(sizeof *uobj, GFP_KERNEL); if (!uobj) return -ENOMEM; @@ -641,27 +618,23 @@ ssize_t ib_uverbs_create_cq(struct ib_uverbs_file *file, cq->uobject = &uobj->uobject; cq->comp_handler = ib_uverbs_comp_handler; cq->event_handler = ib_uverbs_cq_event_handler; - cq->cq_context = file; + cq->cq_context = ev_file; atomic_set(&cq->usecnt, 0); + down(&ib_uverbs_idr_mutex); + retry: if (!idr_pre_get(&ib_uverbs_cq_idr, GFP_KERNEL)) { ret = -ENOMEM; - goto err_cq; + goto err_up; } - down(&ib_uverbs_idr_mutex); ret = idr_get_new(&ib_uverbs_cq_idr, cq, &uobj->uobject.id); - up(&ib_uverbs_idr_mutex); if (ret == -EAGAIN) goto retry; if (ret) - goto err_cq; - - down(&file->mutex); - list_add_tail(&uobj->uobject.list, &file->ucontext->cq_list); - up(&file->mutex); + goto err_up; memset(&resp, 0, sizeof resp); resp.cq_handle = uobj->uobject.id; @@ -670,21 +643,22 @@ retry: if (copy_to_user((void __user *) (unsigned long) cmd.response, &resp, sizeof resp)) { ret = -EFAULT; - goto err_list; + goto err_idr; } - return in_len; - -err_list: - down(&file->mutex); - list_del(&uobj->uobject.list); + down(&file->mutex); + list_add_tail(&uobj->uobject.list, &file->ucontext->cq_list); up(&file->mutex); - down(&ib_uverbs_idr_mutex); - idr_remove(&ib_uverbs_cq_idr, uobj->uobject.id); up(&ib_uverbs_idr_mutex); -err_cq: + return in_len; + +err_idr: + idr_remove(&ib_uverbs_cq_idr, uobj->uobject.id); + +err_up: + up(&ib_uverbs_idr_mutex); ib_destroy_cq(cq); err: @@ -692,6 +666,93 @@ err: return ret; } +ssize_t ib_uverbs_poll_cq(struct ib_uverbs_file *file, + const char __user *buf, int in_len, + int out_len) +{ + struct ib_uverbs_poll_cq cmd; + struct ib_uverbs_poll_cq_resp *resp; + struct ib_cq *cq; + struct ib_wc *wc; + int ret = 0; + int i; + int rsize; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + wc = kmalloc(cmd.ne * sizeof *wc, GFP_KERNEL); + if (!wc) + return -ENOMEM; + + rsize = sizeof *resp + cmd.ne * sizeof(struct ib_uverbs_wc); + resp = kmalloc(rsize, GFP_KERNEL); + if (!resp) { + ret = -ENOMEM; + goto out_wc; + } + + down(&ib_uverbs_idr_mutex); + cq = idr_find(&ib_uverbs_cq_idr, cmd.cq_handle); + if (!cq || cq->uobject->context != file->ucontext) { + ret = -EINVAL; + goto out; + } + + resp->count = ib_poll_cq(cq, cmd.ne, wc); + + for (i = 0; i < resp->count; i++) { + resp->wc[i].wr_id = wc[i].wr_id; + resp->wc[i].status = wc[i].status; + resp->wc[i].opcode = wc[i].opcode; + resp->wc[i].vendor_err = wc[i].vendor_err; + resp->wc[i].byte_len = wc[i].byte_len; + resp->wc[i].imm_data = wc[i].imm_data; + resp->wc[i].qp_num = wc[i].qp_num; + resp->wc[i].src_qp = wc[i].src_qp; + resp->wc[i].wc_flags = wc[i].wc_flags; + resp->wc[i].pkey_index = wc[i].pkey_index; + resp->wc[i].slid = wc[i].slid; + resp->wc[i].sl = wc[i].sl; + resp->wc[i].dlid_path_bits = wc[i].dlid_path_bits; + resp->wc[i].port_num = wc[i].port_num; + } + + if (copy_to_user((void __user *) (unsigned long) cmd.response, resp, rsize)) + ret = -EFAULT; + +out: + up(&ib_uverbs_idr_mutex); + kfree(resp); + +out_wc: + kfree(wc); + return ret ? ret : in_len; +} + +ssize_t ib_uverbs_req_notify_cq(struct ib_uverbs_file *file, + const char __user *buf, int in_len, + int out_len) +{ + struct ib_uverbs_req_notify_cq cmd; + struct ib_cq *cq; + int ret = -EINVAL; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + down(&ib_uverbs_idr_mutex); + cq = idr_find(&ib_uverbs_cq_idr, cmd.cq_handle); + if (cq && cq->uobject->context == file->ucontext) { + ib_req_notify_cq(cq, cmd.solicited_only ? + IB_CQ_SOLICITED : IB_CQ_NEXT_COMP); + ret = in_len; + } + up(&ib_uverbs_idr_mutex); + + return ret; +} + ssize_t ib_uverbs_destroy_cq(struct ib_uverbs_file *file, const char __user *buf, int in_len, int out_len) @@ -700,7 +761,7 @@ ssize_t ib_uverbs_destroy_cq(struct ib_uverbs_file *file, struct ib_uverbs_destroy_cq_resp resp; struct ib_cq *cq; struct ib_ucq_object *uobj; - struct ib_uverbs_event *evt, *tmp; + struct ib_uverbs_event_file *ev_file; u64 user_handle; int ret = -EINVAL; @@ -716,7 +777,8 @@ ssize_t ib_uverbs_destroy_cq(struct ib_uverbs_file *file, goto out; user_handle = cq->uobject->user_handle; - uobj = container_of(cq->uobject, struct ib_ucq_object, uobject); + uobj = container_of(cq->uobject, struct ib_ucq_object, uobject); + ev_file = cq->cq_context; ret = ib_destroy_cq(cq); if (ret) @@ -728,19 +790,7 @@ ssize_t ib_uverbs_destroy_cq(struct ib_uverbs_file *file, list_del(&uobj->uobject.list); up(&file->mutex); - spin_lock_irq(&file->comp_file[0].lock); - list_for_each_entry_safe(evt, tmp, &uobj->comp_list, obj_list) { - list_del(&evt->list); - kfree(evt); - } - spin_unlock_irq(&file->comp_file[0].lock); - - spin_lock_irq(&file->async_file.lock); - list_for_each_entry_safe(evt, tmp, &uobj->async_list, obj_list) { - list_del(&evt->list); - kfree(evt); - } - spin_unlock_irq(&file->async_file.lock); + ib_uverbs_release_ucq(file, ev_file, uobj); resp.comp_events_reported = uobj->comp_events_reported; resp.async_events_reported = uobj->async_events_reported; @@ -859,24 +909,22 @@ retry: resp.qp_handle = uobj->uobject.id; - down(&file->mutex); - list_add_tail(&uobj->uobject.list, &file->ucontext->qp_list); - up(&file->mutex); - if (copy_to_user((void __user *) (unsigned long) cmd.response, &resp, sizeof resp)) { ret = -EFAULT; - goto err_list; + goto err_idr; } + down(&file->mutex); + list_add_tail(&uobj->uobject.list, &file->ucontext->qp_list); + up(&file->mutex); + up(&ib_uverbs_idr_mutex); return in_len; -err_list: - down(&file->mutex); - list_del(&uobj->uobject.list); - up(&file->mutex); +err_idr: + idr_remove(&ib_uverbs_qp_idr, uobj->uobject.id); err_destroy: ib_destroy_qp(qp); @@ -979,7 +1027,6 @@ ssize_t ib_uverbs_destroy_qp(struct ib_uverbs_file *file, struct ib_uverbs_destroy_qp_resp resp; struct ib_qp *qp; struct ib_uevent_object *uobj; - struct ib_uverbs_event *evt, *tmp; int ret = -EINVAL; if (copy_from_user(&cmd, buf, sizeof cmd)) @@ -1005,12 +1052,7 @@ ssize_t ib_uverbs_destroy_qp(struct ib_uverbs_file *file, list_del(&uobj->uobject.list); up(&file->mutex); - spin_lock_irq(&file->async_file.lock); - list_for_each_entry_safe(evt, tmp, &uobj->event_list, obj_list) { - list_del(&evt->list); - kfree(evt); - } - spin_unlock_irq(&file->async_file.lock); + ib_uverbs_release_uevent(file, uobj); resp.events_reported = uobj->events_reported; @@ -1026,6 +1068,468 @@ out: return ret ? ret : in_len; } +ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file, + const char __user *buf, int in_len, + int out_len) +{ + struct ib_uverbs_post_send cmd; + struct ib_uverbs_post_send_resp resp; + struct ib_uverbs_send_wr *user_wr; + struct ib_send_wr *wr = NULL, *last, *next, *bad_wr; + struct ib_qp *qp; + int i, sg_ind; + ssize_t ret = -EINVAL; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + if (in_len < sizeof cmd + cmd.wqe_size * cmd.wr_count + + cmd.sge_count * sizeof (struct ib_uverbs_sge)) + return -EINVAL; + + if (cmd.wqe_size < sizeof (struct ib_uverbs_send_wr)) + return -EINVAL; + + user_wr = kmalloc(cmd.wqe_size, GFP_KERNEL); + if (!user_wr) + return -ENOMEM; + + down(&ib_uverbs_idr_mutex); + + qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle); + if (!qp || qp->uobject->context != file->ucontext) + goto out; + + sg_ind = 0; + last = NULL; + for (i = 0; i < cmd.wr_count; ++i) { + if (copy_from_user(user_wr, + buf + sizeof cmd + i * cmd.wqe_size, + cmd.wqe_size)) { + ret = -EFAULT; + goto out; + } + + if (user_wr->num_sge + sg_ind > cmd.sge_count) { + ret = -EINVAL; + goto out; + } + + next = kmalloc(ALIGN(sizeof *next, sizeof (struct ib_sge)) + + user_wr->num_sge * sizeof (struct ib_sge), + GFP_KERNEL); + if (!next) { + ret = -ENOMEM; + goto out; + } + + if (!last) + wr = next; + else + last->next = next; + last = next; + + next->next = NULL; + next->wr_id = user_wr->wr_id; + next->num_sge = user_wr->num_sge; + next->opcode = user_wr->opcode; + next->send_flags = user_wr->send_flags; + next->imm_data = user_wr->imm_data; + + if (qp->qp_type == IB_QPT_UD) { + next->wr.ud.ah = idr_find(&ib_uverbs_ah_idr, + user_wr->wr.ud.ah); + if (!next->wr.ud.ah) { + ret = -EINVAL; + goto out; + } + next->wr.ud.remote_qpn = user_wr->wr.ud.remote_qpn; + next->wr.ud.remote_qkey = user_wr->wr.ud.remote_qkey; + } else { + switch (next->opcode) { + case IB_WR_RDMA_WRITE: + case IB_WR_RDMA_WRITE_WITH_IMM: + case IB_WR_RDMA_READ: + next->wr.rdma.remote_addr = + user_wr->wr.rdma.remote_addr; + next->wr.rdma.rkey = + user_wr->wr.rdma.rkey; + break; + case IB_WR_ATOMIC_CMP_AND_SWP: + case IB_WR_ATOMIC_FETCH_AND_ADD: + next->wr.atomic.remote_addr = + user_wr->wr.atomic.remote_addr; + next->wr.atomic.compare_add = + user_wr->wr.atomic.compare_add; + next->wr.atomic.swap = user_wr->wr.atomic.swap; + next->wr.atomic.rkey = user_wr->wr.atomic.rkey; + break; + default: + break; + } + } + + if (next->num_sge) { + next->sg_list = (void *) next + + ALIGN(sizeof *next, sizeof (struct ib_sge)); + if (copy_from_user(next->sg_list, + buf + sizeof cmd + + cmd.wr_count * cmd.wqe_size + + sg_ind * sizeof (struct ib_sge), + next->num_sge * sizeof (struct ib_sge))) { + ret = -EFAULT; + goto out; + } + sg_ind += next->num_sge; + } else + next->sg_list = NULL; + } + + resp.bad_wr = 0; + ret = qp->device->post_send(qp, wr, &bad_wr); + if (ret) + for (next = wr; next; next = next->next) { + ++resp.bad_wr; + if (next == bad_wr) + break; + } + + if (copy_to_user((void __user *) (unsigned long) cmd.response, + &resp, sizeof resp)) + ret = -EFAULT; + +out: + up(&ib_uverbs_idr_mutex); + + while (wr) { + next = wr->next; + kfree(wr); + wr = next; + } + + kfree(user_wr); + + return ret ? ret : in_len; +} + +static struct ib_recv_wr *ib_uverbs_unmarshall_recv(const char __user *buf, + int in_len, + u32 wr_count, + u32 sge_count, + u32 wqe_size) +{ + struct ib_uverbs_recv_wr *user_wr; + struct ib_recv_wr *wr = NULL, *last, *next; + int sg_ind; + int i; + int ret; + + if (in_len < wqe_size * wr_count + + sge_count * sizeof (struct ib_uverbs_sge)) + return ERR_PTR(-EINVAL); + + if (wqe_size < sizeof (struct ib_uverbs_recv_wr)) + return ERR_PTR(-EINVAL); + + user_wr = kmalloc(wqe_size, GFP_KERNEL); + if (!user_wr) + return ERR_PTR(-ENOMEM); + + sg_ind = 0; + last = NULL; + for (i = 0; i < wr_count; ++i) { + if (copy_from_user(user_wr, buf + i * wqe_size, + wqe_size)) { + ret = -EFAULT; + goto err; + } + + if (user_wr->num_sge + sg_ind > sge_count) { + ret = -EINVAL; + goto err; + } + + next = kmalloc(ALIGN(sizeof *next, sizeof (struct ib_sge)) + + user_wr->num_sge * sizeof (struct ib_sge), + GFP_KERNEL); + if (!next) { + ret = -ENOMEM; + goto err; + } + + if (!last) + wr = next; + else + last->next = next; + last = next; + + next->next = NULL; + next->wr_id = user_wr->wr_id; + next->num_sge = user_wr->num_sge; + + if (next->num_sge) { + next->sg_list = (void *) next + + ALIGN(sizeof *next, sizeof (struct ib_sge)); + if (copy_from_user(next->sg_list, + buf + wr_count * wqe_size + + sg_ind * sizeof (struct ib_sge), + next->num_sge * sizeof (struct ib_sge))) { + ret = -EFAULT; + goto err; + } + sg_ind += next->num_sge; + } else + next->sg_list = NULL; + } + + kfree(user_wr); + return wr; + +err: + kfree(user_wr); + + while (wr) { + next = wr->next; + kfree(wr); + wr = next; + } + + return ERR_PTR(ret); +} + +ssize_t ib_uverbs_post_recv(struct ib_uverbs_file *file, + const char __user *buf, int in_len, + int out_len) +{ + struct ib_uverbs_post_recv cmd; + struct ib_uverbs_post_recv_resp resp; + struct ib_recv_wr *wr, *next, *bad_wr; + struct ib_qp *qp; + ssize_t ret = -EINVAL; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + wr = ib_uverbs_unmarshall_recv(buf + sizeof cmd, + in_len - sizeof cmd, cmd.wr_count, + cmd.sge_count, cmd.wqe_size); + if (IS_ERR(wr)) + return PTR_ERR(wr); + + down(&ib_uverbs_idr_mutex); + + qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle); + if (!qp || qp->uobject->context != file->ucontext) + goto out; + + resp.bad_wr = 0; + ret = qp->device->post_recv(qp, wr, &bad_wr); + if (ret) + for (next = wr; next; next = next->next) { + ++resp.bad_wr; + if (next == bad_wr) + break; + } + + + if (copy_to_user((void __user *) (unsigned long) cmd.response, + &resp, sizeof resp)) + ret = -EFAULT; + +out: + up(&ib_uverbs_idr_mutex); + + while (wr) { + next = wr->next; + kfree(wr); + wr = next; + } + + return ret ? ret : in_len; +} + +ssize_t ib_uverbs_post_srq_recv(struct ib_uverbs_file *file, + const char __user *buf, int in_len, + int out_len) +{ + struct ib_uverbs_post_srq_recv cmd; + struct ib_uverbs_post_srq_recv_resp resp; + struct ib_recv_wr *wr, *next, *bad_wr; + struct ib_srq *srq; + ssize_t ret = -EINVAL; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + wr = ib_uverbs_unmarshall_recv(buf + sizeof cmd, + in_len - sizeof cmd, cmd.wr_count, + cmd.sge_count, cmd.wqe_size); + if (IS_ERR(wr)) + return PTR_ERR(wr); + + down(&ib_uverbs_idr_mutex); + + srq = idr_find(&ib_uverbs_srq_idr, cmd.srq_handle); + if (!srq || srq->uobject->context != file->ucontext) + goto out; + + resp.bad_wr = 0; + ret = srq->device->post_srq_recv(srq, wr, &bad_wr); + if (ret) + for (next = wr; next; next = next->next) { + ++resp.bad_wr; + if (next == bad_wr) + break; + } + + + if (copy_to_user((void __user *) (unsigned long) cmd.response, + &resp, sizeof resp)) + ret = -EFAULT; + +out: + up(&ib_uverbs_idr_mutex); + + while (wr) { + next = wr->next; + kfree(wr); + wr = next; + } + + return ret ? ret : in_len; +} + +ssize_t ib_uverbs_create_ah(struct ib_uverbs_file *file, + const char __user *buf, int in_len, + int out_len) +{ + struct ib_uverbs_create_ah cmd; + struct ib_uverbs_create_ah_resp resp; + struct ib_uobject *uobj; + struct ib_pd *pd; + struct ib_ah *ah; + struct ib_ah_attr attr; + int ret; + + if (out_len < sizeof resp) + return -ENOSPC; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + uobj = kmalloc(sizeof *uobj, GFP_KERNEL); + if (!uobj) + return -ENOMEM; + + down(&ib_uverbs_idr_mutex); + + pd = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle); + if (!pd || pd->uobject->context != file->ucontext) { + ret = -EINVAL; + goto err_up; + } + + uobj->user_handle = cmd.user_handle; + uobj->context = file->ucontext; + + attr.dlid = cmd.attr.dlid; + attr.sl = cmd.attr.sl; + attr.src_path_bits = cmd.attr.src_path_bits; + attr.static_rate = cmd.attr.static_rate; + attr.port_num = cmd.attr.port_num; + attr.grh.flow_label = cmd.attr.grh.flow_label; + attr.grh.sgid_index = cmd.attr.grh.sgid_index; + attr.grh.hop_limit = cmd.attr.grh.hop_limit; + attr.grh.traffic_class = cmd.attr.grh.traffic_class; + memcpy(attr.grh.dgid.raw, cmd.attr.grh.dgid, 16); + + ah = ib_create_ah(pd, &attr); + if (IS_ERR(ah)) { + ret = PTR_ERR(ah); + goto err_up; + } + + ah->uobject = uobj; + +retry: + if (!idr_pre_get(&ib_uverbs_ah_idr, GFP_KERNEL)) { + ret = -ENOMEM; + goto err_destroy; + } + + ret = idr_get_new(&ib_uverbs_ah_idr, ah, &uobj->id); + + if (ret == -EAGAIN) + goto retry; + if (ret) + goto err_destroy; + + resp.ah_handle = uobj->id; + + if (copy_to_user((void __user *) (unsigned long) cmd.response, + &resp, sizeof resp)) { + ret = -EFAULT; + goto err_idr; + } + + down(&file->mutex); + list_add_tail(&uobj->list, &file->ucontext->ah_list); + up(&file->mutex); + + up(&ib_uverbs_idr_mutex); + + return in_len; + +err_idr: + idr_remove(&ib_uverbs_ah_idr, uobj->id); + +err_destroy: + ib_destroy_ah(ah); + +err_up: + up(&ib_uverbs_idr_mutex); + + kfree(uobj); + return ret; +} + +ssize_t ib_uverbs_destroy_ah(struct ib_uverbs_file *file, + const char __user *buf, int in_len, int out_len) +{ + struct ib_uverbs_destroy_ah cmd; + struct ib_ah *ah; + struct ib_uobject *uobj; + int ret = -EINVAL; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + down(&ib_uverbs_idr_mutex); + + ah = idr_find(&ib_uverbs_ah_idr, cmd.ah_handle); + if (!ah || ah->uobject->context != file->ucontext) + goto out; + + uobj = ah->uobject; + + ret = ib_destroy_ah(ah); + if (ret) + goto out; + + idr_remove(&ib_uverbs_ah_idr, cmd.ah_handle); + + down(&file->mutex); + list_del(&uobj->list); + up(&file->mutex); + + kfree(uobj); + +out: + up(&ib_uverbs_idr_mutex); + + return ret ? ret : in_len; +} + ssize_t ib_uverbs_attach_mcast(struct ib_uverbs_file *file, const char __user *buf, int in_len, int out_len) @@ -1148,24 +1652,22 @@ retry: resp.srq_handle = uobj->uobject.id; - down(&file->mutex); - list_add_tail(&uobj->uobject.list, &file->ucontext->srq_list); - up(&file->mutex); - if (copy_to_user((void __user *) (unsigned long) cmd.response, &resp, sizeof resp)) { ret = -EFAULT; - goto err_list; + goto err_idr; } + down(&file->mutex); + list_add_tail(&uobj->uobject.list, &file->ucontext->srq_list); + up(&file->mutex); + up(&ib_uverbs_idr_mutex); return in_len; -err_list: - down(&file->mutex); - list_del(&uobj->uobject.list); - up(&file->mutex); +err_idr: + idr_remove(&ib_uverbs_srq_idr, uobj->uobject.id); err_destroy: ib_destroy_srq(srq); @@ -1217,7 +1719,6 @@ ssize_t ib_uverbs_destroy_srq(struct ib_uverbs_file *file, struct ib_uverbs_destroy_srq_resp resp; struct ib_srq *srq; struct ib_uevent_object *uobj; - struct ib_uverbs_event *evt, *tmp; int ret = -EINVAL; if (copy_from_user(&cmd, buf, sizeof cmd)) @@ -1243,12 +1744,7 @@ ssize_t ib_uverbs_destroy_srq(struct ib_uverbs_file *file, list_del(&uobj->uobject.list); up(&file->mutex); - spin_lock_irq(&file->async_file.lock); - list_for_each_entry_safe(evt, tmp, &uobj->event_list, obj_list) { - list_del(&evt->list); - kfree(evt); - } - spin_unlock_irq(&file->async_file.lock); + ib_uverbs_release_uevent(file, uobj); resp.events_reported = uobj->events_reported; diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index 12511808de21..0eb38f479b39 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -3,6 +3,7 @@ * Copyright (c) 2005 Cisco Systems. All rights reserved. * Copyright (c) 2005 Mellanox Technologies. All rights reserved. * Copyright (c) 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2005 PathScale, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -43,6 +44,7 @@ #include <linux/poll.h> #include <linux/file.h> #include <linux/mount.h> +#include <linux/cdev.h> #include <asm/uaccess.h> @@ -62,6 +64,8 @@ enum { #define IB_UVERBS_BASE_DEV MKDEV(IB_UVERBS_MAJOR, IB_UVERBS_BASE_MINOR) +static struct class *uverbs_class; + DECLARE_MUTEX(ib_uverbs_idr_mutex); DEFINE_IDR(ib_uverbs_pd_idr); DEFINE_IDR(ib_uverbs_mr_idr); @@ -72,31 +76,37 @@ DEFINE_IDR(ib_uverbs_qp_idr); DEFINE_IDR(ib_uverbs_srq_idr); static spinlock_t map_lock; +static struct ib_uverbs_device *dev_table[IB_UVERBS_MAX_DEVICES]; static DECLARE_BITMAP(dev_map, IB_UVERBS_MAX_DEVICES); static ssize_t (*uverbs_cmd_table[])(struct ib_uverbs_file *file, const char __user *buf, int in_len, int out_len) = { - [IB_USER_VERBS_CMD_QUERY_PARAMS] = ib_uverbs_query_params, - [IB_USER_VERBS_CMD_GET_CONTEXT] = ib_uverbs_get_context, - [IB_USER_VERBS_CMD_QUERY_DEVICE] = ib_uverbs_query_device, - [IB_USER_VERBS_CMD_QUERY_PORT] = ib_uverbs_query_port, - [IB_USER_VERBS_CMD_QUERY_GID] = ib_uverbs_query_gid, - [IB_USER_VERBS_CMD_QUERY_PKEY] = ib_uverbs_query_pkey, - [IB_USER_VERBS_CMD_ALLOC_PD] = ib_uverbs_alloc_pd, - [IB_USER_VERBS_CMD_DEALLOC_PD] = ib_uverbs_dealloc_pd, - [IB_USER_VERBS_CMD_REG_MR] = ib_uverbs_reg_mr, - [IB_USER_VERBS_CMD_DEREG_MR] = ib_uverbs_dereg_mr, - [IB_USER_VERBS_CMD_CREATE_CQ] = ib_uverbs_create_cq, - [IB_USER_VERBS_CMD_DESTROY_CQ] = ib_uverbs_destroy_cq, - [IB_USER_VERBS_CMD_CREATE_QP] = ib_uverbs_create_qp, - [IB_USER_VERBS_CMD_MODIFY_QP] = ib_uverbs_modify_qp, - [IB_USER_VERBS_CMD_DESTROY_QP] = ib_uverbs_destroy_qp, - [IB_USER_VERBS_CMD_ATTACH_MCAST] = ib_uverbs_attach_mcast, - [IB_USER_VERBS_CMD_DETACH_MCAST] = ib_uverbs_detach_mcast, - [IB_USER_VERBS_CMD_CREATE_SRQ] = ib_uverbs_create_srq, - [IB_USER_VERBS_CMD_MODIFY_SRQ] = ib_uverbs_modify_srq, - [IB_USER_VERBS_CMD_DESTROY_SRQ] = ib_uverbs_destroy_srq, + [IB_USER_VERBS_CMD_GET_CONTEXT] = ib_uverbs_get_context, + [IB_USER_VERBS_CMD_QUERY_DEVICE] = ib_uverbs_query_device, + [IB_USER_VERBS_CMD_QUERY_PORT] = ib_uverbs_query_port, + [IB_USER_VERBS_CMD_ALLOC_PD] = ib_uverbs_alloc_pd, + [IB_USER_VERBS_CMD_DEALLOC_PD] = ib_uverbs_dealloc_pd, + [IB_USER_VERBS_CMD_REG_MR] = ib_uverbs_reg_mr, + [IB_USER_VERBS_CMD_DEREG_MR] = ib_uverbs_dereg_mr, + [IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL] = ib_uverbs_create_comp_channel, + [IB_USER_VERBS_CMD_CREATE_CQ] = ib_uverbs_create_cq, + [IB_USER_VERBS_CMD_POLL_CQ] = ib_uverbs_poll_cq, + [IB_USER_VERBS_CMD_REQ_NOTIFY_CQ] = ib_uverbs_req_notify_cq, + [IB_USER_VERBS_CMD_DESTROY_CQ] = ib_uverbs_destroy_cq, + [IB_USER_VERBS_CMD_CREATE_QP] = ib_uverbs_create_qp, + [IB_USER_VERBS_CMD_MODIFY_QP] = ib_uverbs_modify_qp, + [IB_USER_VERBS_CMD_DESTROY_QP] = ib_uverbs_destroy_qp, + [IB_USER_VERBS_CMD_POST_SEND] = ib_uverbs_post_send, + [IB_USER_VERBS_CMD_POST_RECV] = ib_uverbs_post_recv, + [IB_USER_VERBS_CMD_POST_SRQ_RECV] = ib_uverbs_post_srq_recv, + [IB_USER_VERBS_CMD_CREATE_AH] = ib_uverbs_create_ah, + [IB_USER_VERBS_CMD_DESTROY_AH] = ib_uverbs_destroy_ah, + [IB_USER_VERBS_CMD_ATTACH_MCAST] = ib_uverbs_attach_mcast, + [IB_USER_VERBS_CMD_DETACH_MCAST] = ib_uverbs_detach_mcast, + [IB_USER_VERBS_CMD_CREATE_SRQ] = ib_uverbs_create_srq, + [IB_USER_VERBS_CMD_MODIFY_SRQ] = ib_uverbs_modify_srq, + [IB_USER_VERBS_CMD_DESTROY_SRQ] = ib_uverbs_destroy_srq, }; static struct vfsmount *uverbs_event_mnt; @@ -104,7 +114,54 @@ static struct vfsmount *uverbs_event_mnt; static void ib_uverbs_add_one(struct ib_device *device); static void ib_uverbs_remove_one(struct ib_device *device); -static int ib_dealloc_ucontext(struct ib_ucontext *context) +static void ib_uverbs_release_dev(struct kref *ref) +{ + struct ib_uverbs_device *dev = + container_of(ref, struct ib_uverbs_device, ref); + + kfree(dev); +} + +void ib_uverbs_release_ucq(struct ib_uverbs_file *file, + struct ib_uverbs_event_file *ev_file, + struct ib_ucq_object *uobj) +{ + struct ib_uverbs_event *evt, *tmp; + + if (ev_file) { + spin_lock_irq(&ev_file->lock); + list_for_each_entry_safe(evt, tmp, &uobj->comp_list, obj_list) { + list_del(&evt->list); + kfree(evt); + } + spin_unlock_irq(&ev_file->lock); + + kref_put(&ev_file->ref, ib_uverbs_release_event_file); + } + + spin_lock_irq(&file->async_file->lock); + list_for_each_entry_safe(evt, tmp, &uobj->async_list, obj_list) { + list_del(&evt->list); + kfree(evt); + } + spin_unlock_irq(&file->async_file->lock); +} + +void ib_uverbs_release_uevent(struct ib_uverbs_file *file, + struct ib_uevent_object *uobj) +{ + struct ib_uverbs_event *evt, *tmp; + + spin_lock_irq(&file->async_file->lock); + list_for_each_entry_safe(evt, tmp, &uobj->event_list, obj_list) { + list_del(&evt->list); + kfree(evt); + } + spin_unlock_irq(&file->async_file->lock); +} + +static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file, + struct ib_ucontext *context) { struct ib_uobject *uobj, *tmp; @@ -113,30 +170,46 @@ static int ib_dealloc_ucontext(struct ib_ucontext *context) down(&ib_uverbs_idr_mutex); - /* XXX Free AHs */ + list_for_each_entry_safe(uobj, tmp, &context->ah_list, list) { + struct ib_ah *ah = idr_find(&ib_uverbs_ah_idr, uobj->id); + idr_remove(&ib_uverbs_ah_idr, uobj->id); + ib_destroy_ah(ah); + list_del(&uobj->list); + kfree(uobj); + } list_for_each_entry_safe(uobj, tmp, &context->qp_list, list) { struct ib_qp *qp = idr_find(&ib_uverbs_qp_idr, uobj->id); + struct ib_uevent_object *uevent = + container_of(uobj, struct ib_uevent_object, uobject); idr_remove(&ib_uverbs_qp_idr, uobj->id); ib_destroy_qp(qp); list_del(&uobj->list); - kfree(container_of(uobj, struct ib_uevent_object, uobject)); + ib_uverbs_release_uevent(file, uevent); + kfree(uevent); } list_for_each_entry_safe(uobj, tmp, &context->cq_list, list) { struct ib_cq *cq = idr_find(&ib_uverbs_cq_idr, uobj->id); + struct ib_uverbs_event_file *ev_file = cq->cq_context; + struct ib_ucq_object *ucq = + container_of(uobj, struct ib_ucq_object, uobject); idr_remove(&ib_uverbs_cq_idr, uobj->id); ib_destroy_cq(cq); list_del(&uobj->list); - kfree(container_of(uobj, struct ib_ucq_object, uobject)); + ib_uverbs_release_ucq(file, ev_file, ucq); + kfree(ucq); } list_for_each_entry_safe(uobj, tmp, &context->srq_list, list) { struct ib_srq *srq = idr_find(&ib_uverbs_srq_idr, uobj->id); + struct ib_uevent_object *uevent = + container_of(uobj, struct ib_uevent_object, uobject); idr_remove(&ib_uverbs_srq_idr, uobj->id); ib_destroy_srq(srq); list_del(&uobj->list); - kfree(container_of(uobj, struct ib_uevent_object, uobject)); + ib_uverbs_release_uevent(file, uevent); + kfree(uevent); } /* XXX Free MWs */ @@ -175,6 +248,8 @@ static void ib_uverbs_release_file(struct kref *ref) container_of(ref, struct ib_uverbs_file, ref); module_put(file->device->ib_dev->owner); + kref_put(&file->device->ref, ib_uverbs_release_dev); + kfree(file); } @@ -188,25 +263,19 @@ static ssize_t ib_uverbs_event_read(struct file *filp, char __user *buf, spin_lock_irq(&file->lock); - while (list_empty(&file->event_list) && file->fd >= 0) { + while (list_empty(&file->event_list)) { spin_unlock_irq(&file->lock); if (filp->f_flags & O_NONBLOCK) return -EAGAIN; if (wait_event_interruptible(file->poll_wait, - !list_empty(&file->event_list) || - file->fd < 0)) + !list_empty(&file->event_list))) return -ERESTARTSYS; spin_lock_irq(&file->lock); } - if (file->fd < 0) { - spin_unlock_irq(&file->lock); - return -ENODEV; - } - event = list_entry(file->event_list.next, struct ib_uverbs_event, list); if (file->is_async) @@ -248,26 +317,19 @@ static unsigned int ib_uverbs_event_poll(struct file *filp, poll_wait(filp, &file->poll_wait, wait); spin_lock_irq(&file->lock); - if (file->fd < 0) - pollflags = POLLERR; - else if (!list_empty(&file->event_list)) + if (!list_empty(&file->event_list)) pollflags = POLLIN | POLLRDNORM; spin_unlock_irq(&file->lock); return pollflags; } -static void ib_uverbs_event_release(struct ib_uverbs_event_file *file) +void ib_uverbs_release_event_file(struct kref *ref) { - struct ib_uverbs_event *entry, *tmp; + struct ib_uverbs_event_file *file = + container_of(ref, struct ib_uverbs_event_file, ref); - spin_lock_irq(&file->lock); - if (file->fd != -1) { - file->fd = -1; - list_for_each_entry_safe(entry, tmp, &file->event_list, list) - kfree(entry); - } - spin_unlock_irq(&file->lock); + kfree(file); } static int ib_uverbs_event_fasync(int fd, struct file *filp, int on) @@ -280,21 +342,30 @@ static int ib_uverbs_event_fasync(int fd, struct file *filp, int on) static int ib_uverbs_event_close(struct inode *inode, struct file *filp) { struct ib_uverbs_event_file *file = filp->private_data; + struct ib_uverbs_event *entry, *tmp; + + spin_lock_irq(&file->lock); + file->file = NULL; + list_for_each_entry_safe(entry, tmp, &file->event_list, list) { + if (entry->counter) + list_del(&entry->obj_list); + kfree(entry); + } + spin_unlock_irq(&file->lock); - ib_uverbs_event_release(file); ib_uverbs_event_fasync(-1, filp, 0); - kref_put(&file->uverbs_file->ref, ib_uverbs_release_file); + + if (file->is_async) { + ib_unregister_event_handler(&file->uverbs_file->event_handler); + kref_put(&file->uverbs_file->ref, ib_uverbs_release_file); + } + kref_put(&file->ref, ib_uverbs_release_event_file); return 0; } static struct file_operations uverbs_event_fops = { - /* - * No .owner field since we artificially create event files, - * so there is no increment to the module reference count in - * the open path. All event files come from a uverbs command - * file, which already takes a module reference, so this is OK. - */ + .owner = THIS_MODULE, .read = ib_uverbs_event_read, .poll = ib_uverbs_event_poll, .release = ib_uverbs_event_close, @@ -303,27 +374,37 @@ static struct file_operations uverbs_event_fops = { void ib_uverbs_comp_handler(struct ib_cq *cq, void *cq_context) { - struct ib_uverbs_file *file = cq_context; - struct ib_ucq_object *uobj; - struct ib_uverbs_event *entry; - unsigned long flags; + struct ib_uverbs_event_file *file = cq_context; + struct ib_ucq_object *uobj; + struct ib_uverbs_event *entry; + unsigned long flags; + + if (!file) + return; + + spin_lock_irqsave(&file->lock, flags); + if (!file->file) { + spin_unlock_irqrestore(&file->lock, flags); + return; + } entry = kmalloc(sizeof *entry, GFP_ATOMIC); - if (!entry) + if (!entry) { + spin_unlock_irqrestore(&file->lock, flags); return; + } uobj = container_of(cq->uobject, struct ib_ucq_object, uobject); entry->desc.comp.cq_handle = cq->uobject->user_handle; entry->counter = &uobj->comp_events_reported; - spin_lock_irqsave(&file->comp_file[0].lock, flags); - list_add_tail(&entry->list, &file->comp_file[0].event_list); + list_add_tail(&entry->list, &file->event_list); list_add_tail(&entry->obj_list, &uobj->comp_list); - spin_unlock_irqrestore(&file->comp_file[0].lock, flags); + spin_unlock_irqrestore(&file->lock, flags); - wake_up_interruptible(&file->comp_file[0].poll_wait); - kill_fasync(&file->comp_file[0].async_queue, SIGIO, POLL_IN); + wake_up_interruptible(&file->poll_wait); + kill_fasync(&file->async_queue, SIGIO, POLL_IN); } static void ib_uverbs_async_handler(struct ib_uverbs_file *file, @@ -334,32 +415,40 @@ static void ib_uverbs_async_handler(struct ib_uverbs_file *file, struct ib_uverbs_event *entry; unsigned long flags; + spin_lock_irqsave(&file->async_file->lock, flags); + if (!file->async_file->file) { + spin_unlock_irqrestore(&file->async_file->lock, flags); + return; + } + entry = kmalloc(sizeof *entry, GFP_ATOMIC); - if (!entry) + if (!entry) { + spin_unlock_irqrestore(&file->async_file->lock, flags); return; + } entry->desc.async.element = element; entry->desc.async.event_type = event; entry->counter = counter; - spin_lock_irqsave(&file->async_file.lock, flags); - list_add_tail(&entry->list, &file->async_file.event_list); + list_add_tail(&entry->list, &file->async_file->event_list); if (obj_list) list_add_tail(&entry->obj_list, obj_list); - spin_unlock_irqrestore(&file->async_file.lock, flags); + spin_unlock_irqrestore(&file->async_file->lock, flags); - wake_up_interruptible(&file->async_file.poll_wait); - kill_fasync(&file->async_file.async_queue, SIGIO, POLL_IN); + wake_up_interruptible(&file->async_file->poll_wait); + kill_fasync(&file->async_file->async_queue, SIGIO, POLL_IN); } void ib_uverbs_cq_event_handler(struct ib_event *event, void *context_ptr) { + struct ib_uverbs_event_file *ev_file = context_ptr; struct ib_ucq_object *uobj; uobj = container_of(event->element.cq->uobject, struct ib_ucq_object, uobject); - ib_uverbs_async_handler(context_ptr, uobj->uobject.user_handle, + ib_uverbs_async_handler(ev_file->uverbs_file, uobj->uobject.user_handle, event->event, &uobj->async_list, &uobj->async_events_reported); @@ -389,8 +478,8 @@ void ib_uverbs_srq_event_handler(struct ib_event *event, void *context_ptr) &uobj->events_reported); } -static void ib_uverbs_event_handler(struct ib_event_handler *handler, - struct ib_event *event) +void ib_uverbs_event_handler(struct ib_event_handler *handler, + struct ib_event *event) { struct ib_uverbs_file *file = container_of(handler, struct ib_uverbs_file, event_handler); @@ -399,38 +488,90 @@ static void ib_uverbs_event_handler(struct ib_event_handler *handler, NULL, NULL); } -static int ib_uverbs_event_init(struct ib_uverbs_event_file *file, - struct ib_uverbs_file *uverbs_file) +struct file *ib_uverbs_alloc_event_file(struct ib_uverbs_file *uverbs_file, + int is_async, int *fd) { + struct ib_uverbs_event_file *ev_file; struct file *filp; + int ret; - spin_lock_init(&file->lock); - INIT_LIST_HEAD(&file->event_list); - init_waitqueue_head(&file->poll_wait); - file->uverbs_file = uverbs_file; - file->async_queue = NULL; - - file->fd = get_unused_fd(); - if (file->fd < 0) - return file->fd; + ev_file = kmalloc(sizeof *ev_file, GFP_KERNEL); + if (!ev_file) + return ERR_PTR(-ENOMEM); + + kref_init(&ev_file->ref); + spin_lock_init(&ev_file->lock); + INIT_LIST_HEAD(&ev_file->event_list); + init_waitqueue_head(&ev_file->poll_wait); + ev_file->uverbs_file = uverbs_file; + ev_file->async_queue = NULL; + ev_file->is_async = is_async; + + *fd = get_unused_fd(); + if (*fd < 0) { + ret = *fd; + goto err; + } filp = get_empty_filp(); if (!filp) { - put_unused_fd(file->fd); - return -ENFILE; + ret = -ENFILE; + goto err_fd; } - filp->f_op = &uverbs_event_fops; + ev_file->file = filp; + + /* + * fops_get() can't fail here, because we're coming from a + * system call on a uverbs file, which will already have a + * module reference. + */ + filp->f_op = fops_get(&uverbs_event_fops); filp->f_vfsmnt = mntget(uverbs_event_mnt); filp->f_dentry = dget(uverbs_event_mnt->mnt_root); filp->f_mapping = filp->f_dentry->d_inode->i_mapping; filp->f_flags = O_RDONLY; filp->f_mode = FMODE_READ; - filp->private_data = file; + filp->private_data = ev_file; - fd_install(file->fd, filp); + return filp; - return 0; +err_fd: + put_unused_fd(*fd); + +err: + kfree(ev_file); + return ERR_PTR(ret); +} + +/* + * Look up a completion event file by FD. If lookup is successful, + * takes a ref to the event file struct that it returns; if + * unsuccessful, returns NULL. + */ +struct ib_uverbs_event_file *ib_uverbs_lookup_comp_file(int fd) +{ + struct ib_uverbs_event_file *ev_file = NULL; + struct file *filp; + + filp = fget(fd); + if (!filp) + return NULL; + + if (filp->f_op != &uverbs_event_fops) + goto out; + + ev_file = filp->private_data; + if (ev_file->is_async) { + ev_file = NULL; + goto out; + } + + kref_get(&ev_file->ref); + +out: + fput(filp); + return ev_file; } static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf, @@ -450,11 +591,11 @@ static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf, if (hdr.command < 0 || hdr.command >= ARRAY_SIZE(uverbs_cmd_table) || - !uverbs_cmd_table[hdr.command]) + !uverbs_cmd_table[hdr.command] || + !(file->device->ib_dev->uverbs_cmd_mask & (1ull << hdr.command))) return -EINVAL; - if (!file->ucontext && - hdr.command != IB_USER_VERBS_CMD_QUERY_PARAMS && + if (!file->ucontext && hdr.command != IB_USER_VERBS_CMD_GET_CONTEXT) return -EINVAL; @@ -474,84 +615,57 @@ static int ib_uverbs_mmap(struct file *filp, struct vm_area_struct *vma) static int ib_uverbs_open(struct inode *inode, struct file *filp) { - struct ib_uverbs_device *dev = - container_of(inode->i_cdev, struct ib_uverbs_device, dev); + struct ib_uverbs_device *dev; struct ib_uverbs_file *file; - int i = 0; int ret; - if (!try_module_get(dev->ib_dev->owner)) - return -ENODEV; + spin_lock(&map_lock); + dev = dev_table[iminor(inode) - IB_UVERBS_BASE_MINOR]; + if (dev) + kref_get(&dev->ref); + spin_unlock(&map_lock); + + if (!dev) + return -ENXIO; + + if (!try_module_get(dev->ib_dev->owner)) { + ret = -ENODEV; + goto err; + } - file = kmalloc(sizeof *file + - (dev->num_comp - 1) * sizeof (struct ib_uverbs_event_file), - GFP_KERNEL); + file = kmalloc(sizeof *file, GFP_KERNEL); if (!file) { ret = -ENOMEM; - goto err; + goto err_module; } - file->device = dev; + file->device = dev; + file->ucontext = NULL; + file->async_file = NULL; kref_init(&file->ref); init_MUTEX(&file->mutex); - file->ucontext = NULL; - - kref_get(&file->ref); - ret = ib_uverbs_event_init(&file->async_file, file); - if (ret) - goto err_kref; - - file->async_file.is_async = 1; - - for (i = 0; i < dev->num_comp; ++i) { - kref_get(&file->ref); - ret = ib_uverbs_event_init(&file->comp_file[i], file); - if (ret) - goto err_async; - file->comp_file[i].is_async = 0; - } - - filp->private_data = file; - INIT_IB_EVENT_HANDLER(&file->event_handler, dev->ib_dev, - ib_uverbs_event_handler); - if (ib_register_event_handler(&file->event_handler)) - goto err_async; - return 0; -err_async: - while (i--) - ib_uverbs_event_release(&file->comp_file[i]); - - ib_uverbs_event_release(&file->async_file); - -err_kref: - /* - * One extra kref_put() because we took a reference before the - * event file creation that failed and got us here. - */ - kref_put(&file->ref, ib_uverbs_release_file); - kref_put(&file->ref, ib_uverbs_release_file); +err_module: + module_put(dev->ib_dev->owner); err: - module_put(dev->ib_dev->owner); + kref_put(&dev->ref, ib_uverbs_release_dev); + return ret; } static int ib_uverbs_close(struct inode *inode, struct file *filp) { struct ib_uverbs_file *file = filp->private_data; - int i; - ib_unregister_event_handler(&file->event_handler); - ib_uverbs_event_release(&file->async_file); - ib_dealloc_ucontext(file->ucontext); + ib_uverbs_cleanup_ucontext(file, file->ucontext); - for (i = 0; i < file->device->num_comp; ++i) - ib_uverbs_event_release(&file->comp_file[i]); + if (file->async_file) + kref_put(&file->async_file->ref, ib_uverbs_release_event_file); kref_put(&file->ref, ib_uverbs_release_file); @@ -581,27 +695,25 @@ static struct ib_client uverbs_client = { static ssize_t show_ibdev(struct class_device *class_dev, char *buf) { - struct ib_uverbs_device *dev = - container_of(class_dev, struct ib_uverbs_device, class_dev); + struct ib_uverbs_device *dev = class_get_devdata(class_dev); + + if (!dev) + return -ENODEV; return sprintf(buf, "%s\n", dev->ib_dev->name); } static CLASS_DEVICE_ATTR(ibdev, S_IRUGO, show_ibdev, NULL); -static void ib_uverbs_release_class_dev(struct class_device *class_dev) +static ssize_t show_dev_abi_version(struct class_device *class_dev, char *buf) { - struct ib_uverbs_device *dev = - container_of(class_dev, struct ib_uverbs_device, class_dev); + struct ib_uverbs_device *dev = class_get_devdata(class_dev); - cdev_del(&dev->dev); - clear_bit(dev->devnum, dev_map); - kfree(dev); -} + if (!dev) + return -ENODEV; -static struct class uverbs_class = { - .name = "infiniband_verbs", - .release = ib_uverbs_release_class_dev -}; + return sprintf(buf, "%d\n", dev->ib_dev->uverbs_abi_ver); +} +static CLASS_DEVICE_ATTR(abi_version, S_IRUGO, show_dev_abi_version, NULL); static ssize_t show_abi_version(struct class *class, char *buf) { @@ -622,6 +734,8 @@ static void ib_uverbs_add_one(struct ib_device *device) memset(uverbs_dev, 0, sizeof *uverbs_dev); + kref_init(&uverbs_dev->ref); + spin_lock(&map_lock); uverbs_dev->devnum = find_first_zero_bit(dev_map, IB_UVERBS_MAX_DEVICES); if (uverbs_dev->devnum >= IB_UVERBS_MAX_DEVICES) { @@ -631,41 +745,49 @@ static void ib_uverbs_add_one(struct ib_device *device) set_bit(uverbs_dev->devnum, dev_map); spin_unlock(&map_lock); - uverbs_dev->ib_dev = device; - uverbs_dev->num_comp = 1; + uverbs_dev->ib_dev = device; + uverbs_dev->num_comp_vectors = 1; - if (device->mmap) - cdev_init(&uverbs_dev->dev, &uverbs_mmap_fops); - else - cdev_init(&uverbs_dev->dev, &uverbs_fops); - uverbs_dev->dev.owner = THIS_MODULE; - kobject_set_name(&uverbs_dev->dev.kobj, "uverbs%d", uverbs_dev->devnum); - if (cdev_add(&uverbs_dev->dev, IB_UVERBS_BASE_DEV + uverbs_dev->devnum, 1)) + uverbs_dev->dev = cdev_alloc(); + if (!uverbs_dev->dev) goto err; + uverbs_dev->dev->owner = THIS_MODULE; + uverbs_dev->dev->ops = device->mmap ? &uverbs_mmap_fops : &uverbs_fops; + kobject_set_name(&uverbs_dev->dev->kobj, "uverbs%d", uverbs_dev->devnum); + if (cdev_add(uverbs_dev->dev, IB_UVERBS_BASE_DEV + uverbs_dev->devnum, 1)) + goto err_cdev; - uverbs_dev->class_dev.class = &uverbs_class; - uverbs_dev->class_dev.dev = device->dma_device; - uverbs_dev->class_dev.devt = uverbs_dev->dev.dev; - snprintf(uverbs_dev->class_dev.class_id, BUS_ID_SIZE, "uverbs%d", uverbs_dev->devnum); - if (class_device_register(&uverbs_dev->class_dev)) + uverbs_dev->class_dev = class_device_create(uverbs_class, NULL, + uverbs_dev->dev->dev, + device->dma_device, + "uverbs%d", uverbs_dev->devnum); + if (IS_ERR(uverbs_dev->class_dev)) goto err_cdev; - if (class_device_create_file(&uverbs_dev->class_dev, &class_device_attr_ibdev)) + class_set_devdata(uverbs_dev->class_dev, uverbs_dev); + + if (class_device_create_file(uverbs_dev->class_dev, &class_device_attr_ibdev)) goto err_class; + if (class_device_create_file(uverbs_dev->class_dev, &class_device_attr_abi_version)) + goto err_class; + + spin_lock(&map_lock); + dev_table[uverbs_dev->devnum] = uverbs_dev; + spin_unlock(&map_lock); ib_set_client_data(device, &uverbs_client, uverbs_dev); return; err_class: - class_device_unregister(&uverbs_dev->class_dev); + class_device_destroy(uverbs_class, uverbs_dev->dev->dev); err_cdev: - cdev_del(&uverbs_dev->dev); + cdev_del(uverbs_dev->dev); clear_bit(uverbs_dev->devnum, dev_map); err: - kfree(uverbs_dev); + kref_put(&uverbs_dev->ref, ib_uverbs_release_dev); return; } @@ -676,7 +798,16 @@ static void ib_uverbs_remove_one(struct ib_device *device) if (!uverbs_dev) return; - class_device_unregister(&uverbs_dev->class_dev); + class_set_devdata(uverbs_dev->class_dev, NULL); + class_device_destroy(uverbs_class, uverbs_dev->dev->dev); + cdev_del(uverbs_dev->dev); + + spin_lock(&map_lock); + dev_table[uverbs_dev->devnum] = NULL; + spin_unlock(&map_lock); + + clear_bit(uverbs_dev->devnum, dev_map); + kref_put(&uverbs_dev->ref, ib_uverbs_release_dev); } static struct super_block *uverbs_event_get_sb(struct file_system_type *fs_type, int flags, @@ -706,13 +837,14 @@ static int __init ib_uverbs_init(void) goto out; } - ret = class_register(&uverbs_class); - if (ret) { + uverbs_class = class_create(THIS_MODULE, "infiniband_verbs"); + if (IS_ERR(uverbs_class)) { + ret = PTR_ERR(uverbs_class); printk(KERN_ERR "user_verbs: couldn't create class infiniband_verbs\n"); goto out_chrdev; } - ret = class_create_file(&uverbs_class, &class_attr_abi_version); + ret = class_create_file(uverbs_class, &class_attr_abi_version); if (ret) { printk(KERN_ERR "user_verbs: couldn't create abi_version attribute\n"); goto out_class; @@ -746,7 +878,7 @@ out_fs: unregister_filesystem(&uverbs_event_fs); out_class: - class_unregister(&uverbs_class); + class_destroy(uverbs_class); out_chrdev: unregister_chrdev_region(IB_UVERBS_BASE_DEV, IB_UVERBS_MAX_DEVICES); @@ -760,8 +892,15 @@ static void __exit ib_uverbs_cleanup(void) ib_unregister_client(&uverbs_client); mntput(uverbs_event_mnt); unregister_filesystem(&uverbs_event_fs); - class_unregister(&uverbs_class); + class_destroy(uverbs_class); unregister_chrdev_region(IB_UVERBS_BASE_DEV, IB_UVERBS_MAX_DEVICES); + idr_destroy(&ib_uverbs_pd_idr); + idr_destroy(&ib_uverbs_mr_idr); + idr_destroy(&ib_uverbs_mw_idr); + idr_destroy(&ib_uverbs_ah_idr); + idr_destroy(&ib_uverbs_cq_idr); + idr_destroy(&ib_uverbs_qp_idr); + idr_destroy(&ib_uverbs_srq_idr); } module_init(ib_uverbs_init); diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c index 5081d903e561..72d3ef786db5 100644 --- a/drivers/infiniband/core/verbs.c +++ b/drivers/infiniband/core/verbs.c @@ -523,16 +523,22 @@ EXPORT_SYMBOL(ib_dealloc_fmr); int ib_attach_mcast(struct ib_qp *qp, union ib_gid *gid, u16 lid) { - return qp->device->attach_mcast ? - qp->device->attach_mcast(qp, gid, lid) : - -ENOSYS; + if (!qp->device->attach_mcast) + return -ENOSYS; + if (gid->raw[0] != 0xff || qp->qp_type != IB_QPT_UD) + return -EINVAL; + + return qp->device->attach_mcast(qp, gid, lid); } EXPORT_SYMBOL(ib_attach_mcast); int ib_detach_mcast(struct ib_qp *qp, union ib_gid *gid, u16 lid) { - return qp->device->detach_mcast ? - qp->device->detach_mcast(qp, gid, lid) : - -ENOSYS; + if (!qp->device->detach_mcast) + return -ENOSYS; + if (gid->raw[0] != 0xff || qp->qp_type != IB_QPT_UD) + return -EINVAL; + + return qp->device->detach_mcast(qp, gid, lid); } EXPORT_SYMBOL(ib_detach_mcast); diff --git a/drivers/infiniband/hw/mthca/Makefile b/drivers/infiniband/hw/mthca/Makefile index c44f7bae5424..47ec5a7cba0b 100644 --- a/drivers/infiniband/hw/mthca/Makefile +++ b/drivers/infiniband/hw/mthca/Makefile @@ -7,4 +7,5 @@ obj-$(CONFIG_INFINIBAND_MTHCA) += ib_mthca.o ib_mthca-y := mthca_main.o mthca_cmd.o mthca_profile.o mthca_reset.o \ mthca_allocator.o mthca_eq.o mthca_pd.o mthca_cq.o \ mthca_mr.o mthca_qp.o mthca_av.o mthca_mcg.o mthca_mad.o \ - mthca_provider.o mthca_memfree.o mthca_uar.o mthca_srq.o + mthca_provider.o mthca_memfree.o mthca_uar.o mthca_srq.o \ + mthca_catas.o diff --git a/drivers/infiniband/hw/mthca/mthca_av.c b/drivers/infiniband/hw/mthca/mthca_av.c index 889e85096736..22fdc446f25c 100644 --- a/drivers/infiniband/hw/mthca/mthca_av.c +++ b/drivers/infiniband/hw/mthca/mthca_av.c @@ -34,6 +34,8 @@ */ #include <linux/init.h> +#include <linux/string.h> +#include <linux/slab.h> #include <rdma/ib_verbs.h> #include <rdma/ib_cache.h> diff --git a/drivers/infiniband/hw/mthca/mthca_catas.c b/drivers/infiniband/hw/mthca/mthca_catas.c new file mode 100644 index 000000000000..7ac52af43b99 --- /dev/null +++ b/drivers/infiniband/hw/mthca/mthca_catas.c @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2005 Cisco Systems. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include "mthca_dev.h" + +enum { + MTHCA_CATAS_POLL_INTERVAL = 5 * HZ, + + MTHCA_CATAS_TYPE_INTERNAL = 0, + MTHCA_CATAS_TYPE_UPLINK = 3, + MTHCA_CATAS_TYPE_DDR = 4, + MTHCA_CATAS_TYPE_PARITY = 5, +}; + +static DEFINE_SPINLOCK(catas_lock); + +static void handle_catas(struct mthca_dev *dev) +{ + struct ib_event event; + const char *type; + int i; + + event.device = &dev->ib_dev; + event.event = IB_EVENT_DEVICE_FATAL; + event.element.port_num = 0; + + ib_dispatch_event(&event); + + switch (swab32(readl(dev->catas_err.map)) >> 24) { + case MTHCA_CATAS_TYPE_INTERNAL: + type = "internal error"; + break; + case MTHCA_CATAS_TYPE_UPLINK: + type = "uplink bus error"; + break; + case MTHCA_CATAS_TYPE_DDR: + type = "DDR data error"; + break; + case MTHCA_CATAS_TYPE_PARITY: + type = "internal parity error"; + break; + default: + type = "unknown error"; + break; + } + + mthca_err(dev, "Catastrophic error detected: %s\n", type); + for (i = 0; i < dev->catas_err.size; ++i) + mthca_err(dev, " buf[%02x]: %08x\n", + i, swab32(readl(dev->catas_err.map + i))); +} + +static void poll_catas(unsigned long dev_ptr) +{ + struct mthca_dev *dev = (struct mthca_dev *) dev_ptr; + unsigned long flags; + int i; + + for (i = 0; i < dev->catas_err.size; ++i) + if (readl(dev->catas_err.map + i)) { + handle_catas(dev); + return; + } + + spin_lock_irqsave(&catas_lock, flags); + if (dev->catas_err.stop) + mod_timer(&dev->catas_err.timer, + jiffies + MTHCA_CATAS_POLL_INTERVAL); + spin_unlock_irqrestore(&catas_lock, flags); + + return; +} + +void mthca_start_catas_poll(struct mthca_dev *dev) +{ + unsigned long addr; + + init_timer(&dev->catas_err.timer); + dev->catas_err.stop = 0; + dev->catas_err.map = NULL; + + addr = pci_resource_start(dev->pdev, 0) + + ((pci_resource_len(dev->pdev, 0) - 1) & + dev->catas_err.addr); + + if (!request_mem_region(addr, dev->catas_err.size * 4, + DRV_NAME)) { + mthca_warn(dev, "couldn't request catastrophic error region " + "at 0x%lx/0x%x\n", addr, dev->catas_err.size * 4); + return; + } + + dev->catas_err.map = ioremap(addr, dev->catas_err.size * 4); + if (!dev->catas_err.map) { + mthca_warn(dev, "couldn't map catastrophic error region " + "at 0x%lx/0x%x\n", addr, dev->catas_err.size * 4); + release_mem_region(addr, dev->catas_err.size * 4); + return; + } + + dev->catas_err.timer.data = (unsigned long) dev; + dev->catas_err.timer.function = poll_catas; + dev->catas_err.timer.expires = jiffies + MTHCA_CATAS_POLL_INTERVAL; + add_timer(&dev->catas_err.timer); +} + +void mthca_stop_catas_poll(struct mthca_dev *dev) +{ + spin_lock_irq(&catas_lock); + dev->catas_err.stop = 1; + spin_unlock_irq(&catas_lock); + + del_timer_sync(&dev->catas_err.timer); + + if (dev->catas_err.map) { + iounmap(dev->catas_err.map); + release_mem_region(pci_resource_start(dev->pdev, 0) + + ((pci_resource_len(dev->pdev, 0) - 1) & + dev->catas_err.addr), + dev->catas_err.size * 4); + } +} diff --git a/drivers/infiniband/hw/mthca/mthca_cmd.c b/drivers/infiniband/hw/mthca/mthca_cmd.c index f6a8ac026557..49f211d55df7 100644 --- a/drivers/infiniband/hw/mthca/mthca_cmd.c +++ b/drivers/infiniband/hw/mthca/mthca_cmd.c @@ -1,6 +1,7 @@ /* * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * Copyright (c) 2005 Cisco Systems. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -524,7 +525,7 @@ void mthca_cmd_use_polling(struct mthca_dev *dev) } struct mthca_mailbox *mthca_alloc_mailbox(struct mthca_dev *dev, - unsigned int gfp_mask) + gfp_t gfp_mask) { struct mthca_mailbox *mailbox; @@ -706,9 +707,13 @@ int mthca_QUERY_FW(struct mthca_dev *dev, u8 *status) MTHCA_GET(lg, outbox, QUERY_FW_MAX_CMD_OFFSET); dev->cmd.max_cmds = 1 << lg; + MTHCA_GET(dev->catas_err.addr, outbox, QUERY_FW_ERR_START_OFFSET); + MTHCA_GET(dev->catas_err.size, outbox, QUERY_FW_ERR_SIZE_OFFSET); mthca_dbg(dev, "FW version %012llx, max commands %d\n", (unsigned long long) dev->fw_ver, dev->cmd.max_cmds); + mthca_dbg(dev, "Catastrophic error buffer at 0x%llx, size 0x%x\n", + (unsigned long long) dev->catas_err.addr, dev->catas_err.size); if (mthca_is_memfree(dev)) { MTHCA_GET(dev->fw.arbel.fw_pages, outbox, QUERY_FW_SIZE_OFFSET); @@ -933,9 +938,9 @@ int mthca_QUERY_DEV_LIM(struct mthca_dev *dev, goto out; MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_SRQ_SZ_OFFSET); - dev_lim->max_srq_sz = 1 << field; + dev_lim->max_srq_sz = (1 << field) - 1; MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_QP_SZ_OFFSET); - dev_lim->max_qp_sz = 1 << field; + dev_lim->max_qp_sz = (1 << field) - 1; MTHCA_GET(field, outbox, QUERY_DEV_LIM_RSVD_QP_OFFSET); dev_lim->reserved_qps = 1 << (field & 0xf); MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_QP_OFFSET); @@ -1045,6 +1050,8 @@ int mthca_QUERY_DEV_LIM(struct mthca_dev *dev, dev_lim->max_pds, dev_lim->reserved_pds, dev_lim->reserved_uars); mthca_dbg(dev, "Max QP/MCG: %d, reserved MGMs: %d\n", dev_lim->max_pds, dev_lim->reserved_mgms); + mthca_dbg(dev, "Max CQEs: %d, max WQEs: %d, max SRQ WQEs: %d\n", + dev_lim->max_cq_sz, dev_lim->max_qp_sz, dev_lim->max_srq_sz); mthca_dbg(dev, "Flags: %08x\n", dev_lim->flags); diff --git a/drivers/infiniband/hw/mthca/mthca_cmd.h b/drivers/infiniband/hw/mthca/mthca_cmd.h index 65f976a13e02..18175bec84c2 100644 --- a/drivers/infiniband/hw/mthca/mthca_cmd.h +++ b/drivers/infiniband/hw/mthca/mthca_cmd.h @@ -248,7 +248,7 @@ void mthca_cmd_event(struct mthca_dev *dev, u16 token, u8 status, u64 out_param); struct mthca_mailbox *mthca_alloc_mailbox(struct mthca_dev *dev, - unsigned int gfp_mask); + gfp_t gfp_mask); void mthca_free_mailbox(struct mthca_dev *dev, struct mthca_mailbox *mailbox); int mthca_SYS_EN(struct mthca_dev *dev, u8 *status); diff --git a/drivers/infiniband/hw/mthca/mthca_dev.h b/drivers/infiniband/hw/mthca/mthca_dev.h index 7bff5a8425f4..7e68bd4a3780 100644 --- a/drivers/infiniband/hw/mthca/mthca_dev.h +++ b/drivers/infiniband/hw/mthca/mthca_dev.h @@ -83,6 +83,8 @@ enum { /* Arbel FW gives us these, but we need them for Tavor */ MTHCA_MPT_ENTRY_SIZE = 0x40, MTHCA_MTT_SEG_SIZE = 0x40, + + MTHCA_QP_PER_MGM = 4 * (MTHCA_MGM_ENTRY_SIZE / 16 - 2) }; enum { @@ -128,12 +130,16 @@ struct mthca_limits { int num_uars; int max_sg; int num_qps; + int max_wqes; + int max_qp_init_rdma; int reserved_qps; int num_srqs; + int max_srq_wqes; int reserved_srqs; int num_eecs; int reserved_eecs; int num_cqs; + int max_cqes; int reserved_cqs; int num_eqs; int reserved_eqs; @@ -148,6 +154,7 @@ struct mthca_limits { int reserved_mcgs; int num_pds; int reserved_pds; + u32 flags; u8 port_width_cap; }; @@ -251,6 +258,14 @@ struct mthca_mcg_table { struct mthca_icm_table *table; }; +struct mthca_catas_err { + u64 addr; + u32 __iomem *map; + unsigned long stop; + u32 size; + struct timer_list timer; +}; + struct mthca_dev { struct ib_device ib_dev; struct pci_dev *pdev; @@ -311,6 +326,8 @@ struct mthca_dev { struct mthca_av_table av_table; struct mthca_mcg_table mcg_table; + struct mthca_catas_err catas_err; + struct mthca_uar driver_uar; struct mthca_db_table *db_tab; struct mthca_pd driver_pd; @@ -398,6 +415,9 @@ void mthca_cleanup_mcg_table(struct mthca_dev *dev); int mthca_register_device(struct mthca_dev *dev); void mthca_unregister_device(struct mthca_dev *dev); +void mthca_start_catas_poll(struct mthca_dev *dev); +void mthca_stop_catas_poll(struct mthca_dev *dev); + int mthca_uar_alloc(struct mthca_dev *dev, struct mthca_uar *uar); void mthca_uar_free(struct mthca_dev *dev, struct mthca_uar *uar); @@ -447,6 +467,8 @@ void mthca_cq_clean(struct mthca_dev *dev, u32 cqn, u32 qpn, int mthca_alloc_srq(struct mthca_dev *dev, struct mthca_pd *pd, struct ib_srq_attr *attr, struct mthca_srq *srq); void mthca_free_srq(struct mthca_dev *dev, struct mthca_srq *srq); +int mthca_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr, + enum ib_srq_attr_mask attr_mask); void mthca_srq_event(struct mthca_dev *dev, u32 srqn, enum ib_event_type event_type); void mthca_free_srq_wqe(struct mthca_srq *srq, u32 wqe_addr); diff --git a/drivers/infiniband/hw/mthca/mthca_eq.c b/drivers/infiniband/hw/mthca/mthca_eq.c index 8dfafda5ed24..e5a047a6dbeb 100644 --- a/drivers/infiniband/hw/mthca/mthca_eq.c +++ b/drivers/infiniband/hw/mthca/mthca_eq.c @@ -83,7 +83,8 @@ enum { MTHCA_EVENT_TYPE_PATH_MIG = 0x01, MTHCA_EVENT_TYPE_COMM_EST = 0x02, MTHCA_EVENT_TYPE_SQ_DRAINED = 0x03, - MTHCA_EVENT_TYPE_SRQ_LAST_WQE = 0x13, + MTHCA_EVENT_TYPE_SRQ_QP_LAST_WQE = 0x13, + MTHCA_EVENT_TYPE_SRQ_LIMIT = 0x14, MTHCA_EVENT_TYPE_CQ_ERROR = 0x04, MTHCA_EVENT_TYPE_WQ_CATAS_ERROR = 0x05, MTHCA_EVENT_TYPE_EEC_CATAS_ERROR = 0x06, @@ -110,8 +111,9 @@ enum { (1ULL << MTHCA_EVENT_TYPE_LOCAL_CATAS_ERROR) | \ (1ULL << MTHCA_EVENT_TYPE_PORT_CHANGE) | \ (1ULL << MTHCA_EVENT_TYPE_ECC_DETECT)) -#define MTHCA_SRQ_EVENT_MASK (1ULL << MTHCA_EVENT_TYPE_SRQ_CATAS_ERROR) | \ - (1ULL << MTHCA_EVENT_TYPE_SRQ_LAST_WQE) +#define MTHCA_SRQ_EVENT_MASK ((1ULL << MTHCA_EVENT_TYPE_SRQ_CATAS_ERROR) | \ + (1ULL << MTHCA_EVENT_TYPE_SRQ_QP_LAST_WQE) | \ + (1ULL << MTHCA_EVENT_TYPE_SRQ_LIMIT)) #define MTHCA_CMD_EVENT_MASK (1ULL << MTHCA_EVENT_TYPE_CMD) #define MTHCA_EQ_DB_INC_CI (1 << 24) @@ -142,6 +144,9 @@ struct mthca_eqe { __be32 qpn; } __attribute__((packed)) qp; struct { + __be32 srqn; + } __attribute__((packed)) srq; + struct { __be32 cqn; u32 reserved1; u8 reserved2[3]; @@ -305,6 +310,16 @@ static int mthca_eq_int(struct mthca_dev *dev, struct mthca_eq *eq) IB_EVENT_SQ_DRAINED); break; + case MTHCA_EVENT_TYPE_SRQ_QP_LAST_WQE: + mthca_qp_event(dev, be32_to_cpu(eqe->event.qp.qpn) & 0xffffff, + IB_EVENT_QP_LAST_WQE_REACHED); + break; + + case MTHCA_EVENT_TYPE_SRQ_LIMIT: + mthca_srq_event(dev, be32_to_cpu(eqe->event.srq.srqn) & 0xffffff, + IB_EVENT_SRQ_LIMIT_REACHED); + break; + case MTHCA_EVENT_TYPE_WQ_CATAS_ERROR: mthca_qp_event(dev, be32_to_cpu(eqe->event.qp.qpn) & 0xffffff, IB_EVENT_QP_FATAL); diff --git a/drivers/infiniband/hw/mthca/mthca_mad.c b/drivers/infiniband/hw/mthca/mthca_mad.c index 9804174f7f3c..1229c604c6e0 100644 --- a/drivers/infiniband/hw/mthca/mthca_mad.c +++ b/drivers/infiniband/hw/mthca/mthca_mad.c @@ -34,6 +34,9 @@ * $Id: mthca_mad.c 1349 2004-12-16 21:09:43Z roland $ */ +#include <linux/string.h> +#include <linux/slab.h> + #include <rdma/ib_verbs.h> #include <rdma/ib_mad.h> #include <rdma/ib_smi.h> @@ -46,11 +49,6 @@ enum { MTHCA_VENDOR_CLASS2 = 0xa }; -struct mthca_trap_mad { - struct ib_mad *mad; - DECLARE_PCI_UNMAP_ADDR(mapping) -}; - static void update_sm_ah(struct mthca_dev *dev, u8 port_num, u16 lid, u8 sl) { @@ -116,49 +114,14 @@ static void forward_trap(struct mthca_dev *dev, struct ib_mad *mad) { int qpn = mad->mad_hdr.mgmt_class != IB_MGMT_CLASS_SUBN_LID_ROUTED; - struct mthca_trap_mad *tmad; - struct ib_sge gather_list; - struct ib_send_wr *bad_wr, wr = { - .opcode = IB_WR_SEND, - .sg_list = &gather_list, - .num_sge = 1, - .send_flags = IB_SEND_SIGNALED, - .wr = { - .ud = { - .remote_qpn = qpn, - .remote_qkey = qpn ? IB_QP1_QKEY : 0, - .timeout_ms = 0 - } - } - }; + struct ib_mad_send_buf *send_buf; struct ib_mad_agent *agent = dev->send_agent[port_num - 1][qpn]; int ret; unsigned long flags; if (agent) { - tmad = kmalloc(sizeof *tmad, GFP_KERNEL); - if (!tmad) - return; - - tmad->mad = kmalloc(sizeof *tmad->mad, GFP_KERNEL); - if (!tmad->mad) { - kfree(tmad); - return; - } - - memcpy(tmad->mad, mad, sizeof *mad); - - wr.wr.ud.mad_hdr = &tmad->mad->mad_hdr; - wr.wr_id = (unsigned long) tmad; - - gather_list.addr = dma_map_single(agent->device->dma_device, - tmad->mad, - sizeof *tmad->mad, - DMA_TO_DEVICE); - gather_list.length = sizeof *tmad->mad; - gather_list.lkey = to_mpd(agent->qp->pd)->ntmr.ibmr.lkey; - pci_unmap_addr_set(tmad, mapping, gather_list.addr); - + send_buf = ib_create_send_mad(agent, qpn, 0, 0, IB_MGMT_MAD_HDR, + IB_MGMT_MAD_DATA, GFP_ATOMIC); /* * We rely here on the fact that MLX QPs don't use the * address handle after the send is posted (this is @@ -166,21 +129,15 @@ static void forward_trap(struct mthca_dev *dev, * it's OK for our devices). */ spin_lock_irqsave(&dev->sm_lock, flags); - wr.wr.ud.ah = dev->sm_ah[port_num - 1]; - if (wr.wr.ud.ah) - ret = ib_post_send_mad(agent, &wr, &bad_wr); + memcpy(send_buf->mad, mad, sizeof *mad); + if ((send_buf->ah = dev->sm_ah[port_num - 1])) + ret = ib_post_send_mad(send_buf, NULL); else ret = -EINVAL; spin_unlock_irqrestore(&dev->sm_lock, flags); - if (ret) { - dma_unmap_single(agent->device->dma_device, - pci_unmap_addr(tmad, mapping), - sizeof *tmad->mad, - DMA_TO_DEVICE); - kfree(tmad->mad); - kfree(tmad); - } + if (ret) + ib_free_send_mad(send_buf); } } @@ -267,15 +224,7 @@ int mthca_process_mad(struct ib_device *ibdev, static void send_handler(struct ib_mad_agent *agent, struct ib_mad_send_wc *mad_send_wc) { - struct mthca_trap_mad *tmad = - (void *) (unsigned long) mad_send_wc->wr_id; - - dma_unmap_single(agent->device->dma_device, - pci_unmap_addr(tmad, mapping), - sizeof *tmad->mad, - DMA_TO_DEVICE); - kfree(tmad->mad); - kfree(tmad); + ib_free_send_mad(mad_send_wc->send_buf); } int mthca_create_agents(struct mthca_dev *dev) diff --git a/drivers/infiniband/hw/mthca/mthca_main.c b/drivers/infiniband/hw/mthca/mthca_main.c index 23a3f56c7899..883d1e5a79bc 100644 --- a/drivers/infiniband/hw/mthca/mthca_main.c +++ b/drivers/infiniband/hw/mthca/mthca_main.c @@ -162,9 +162,18 @@ static int __devinit mthca_dev_lim(struct mthca_dev *mdev, struct mthca_dev_lim mdev->limits.pkey_table_len = dev_lim->max_pkeys; mdev->limits.local_ca_ack_delay = dev_lim->local_ca_ack_delay; mdev->limits.max_sg = dev_lim->max_sg; + mdev->limits.max_wqes = dev_lim->max_qp_sz; + mdev->limits.max_qp_init_rdma = dev_lim->max_requester_per_qp; mdev->limits.reserved_qps = dev_lim->reserved_qps; + mdev->limits.max_srq_wqes = dev_lim->max_srq_sz; mdev->limits.reserved_srqs = dev_lim->reserved_srqs; mdev->limits.reserved_eecs = dev_lim->reserved_eecs; + /* + * Subtract 1 from the limit because we need to allocate a + * spare CQE so the HCA HW can tell the difference between an + * empty CQ and a full CQ. + */ + mdev->limits.max_cqes = dev_lim->max_cq_sz - 1; mdev->limits.reserved_cqs = dev_lim->reserved_cqs; mdev->limits.reserved_eqs = dev_lim->reserved_eqs; mdev->limits.reserved_mtts = dev_lim->reserved_mtts; @@ -172,6 +181,7 @@ static int __devinit mthca_dev_lim(struct mthca_dev *mdev, struct mthca_dev_lim mdev->limits.reserved_uars = dev_lim->reserved_uars; mdev->limits.reserved_pds = dev_lim->reserved_pds; mdev->limits.port_width_cap = dev_lim->max_port_width; + mdev->limits.flags = dev_lim->flags; /* IB_DEVICE_RESIZE_MAX_WR not supported by driver. May be doable since hardware supports it for SRQ. @@ -1186,6 +1196,7 @@ MODULE_DEVICE_TABLE(pci, mthca_pci_table); static struct pci_driver mthca_driver = { .name = DRV_NAME, + .owner = THIS_MODULE, .id_table = mthca_pci_table, .probe = mthca_init_one, .remove = __devexit_p(mthca_remove_one) diff --git a/drivers/infiniband/hw/mthca/mthca_mcg.c b/drivers/infiniband/hw/mthca/mthca_mcg.c index a2707605f4c8..2fc449da418d 100644 --- a/drivers/infiniband/hw/mthca/mthca_mcg.c +++ b/drivers/infiniband/hw/mthca/mthca_mcg.c @@ -33,14 +33,12 @@ */ #include <linux/init.h> +#include <linux/string.h> +#include <linux/slab.h> #include "mthca_dev.h" #include "mthca_cmd.h" -enum { - MTHCA_QP_PER_MGM = 4 * (MTHCA_MGM_ENTRY_SIZE / 16 - 2) -}; - struct mthca_mgm { __be32 next_gid_index; u32 reserved[3]; @@ -189,7 +187,12 @@ int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) } for (i = 0; i < MTHCA_QP_PER_MGM; ++i) - if (!(mgm->qp[i] & cpu_to_be32(1 << 31))) { + if (mgm->qp[i] == cpu_to_be32(ibqp->qp_num | (1 << 31))) { + mthca_dbg(dev, "QP %06x already a member of MGM\n", + ibqp->qp_num); + err = 0; + goto out; + } else if (!(mgm->qp[i] & cpu_to_be32(1 << 31))) { mgm->qp[i] = cpu_to_be32(ibqp->qp_num | (1 << 31)); break; } diff --git a/drivers/infiniband/hw/mthca/mthca_memfree.c b/drivers/infiniband/hw/mthca/mthca_memfree.c index 7bd7a4bec7b4..d72fe95cba08 100644 --- a/drivers/infiniband/hw/mthca/mthca_memfree.c +++ b/drivers/infiniband/hw/mthca/mthca_memfree.c @@ -82,7 +82,7 @@ void mthca_free_icm(struct mthca_dev *dev, struct mthca_icm *icm) } struct mthca_icm *mthca_alloc_icm(struct mthca_dev *dev, int npages, - unsigned int gfp_mask) + gfp_t gfp_mask) { struct mthca_icm *icm; struct mthca_icm_chunk *chunk = NULL; @@ -487,7 +487,8 @@ void mthca_cleanup_user_db_tab(struct mthca_dev *dev, struct mthca_uar *uar, } } -int mthca_alloc_db(struct mthca_dev *dev, int type, u32 qn, __be32 **db) +int mthca_alloc_db(struct mthca_dev *dev, enum mthca_db_type type, + u32 qn, __be32 **db) { int group; int start, end, dir; diff --git a/drivers/infiniband/hw/mthca/mthca_memfree.h b/drivers/infiniband/hw/mthca/mthca_memfree.h index bafa51544aa3..4fdca26eea85 100644 --- a/drivers/infiniband/hw/mthca/mthca_memfree.h +++ b/drivers/infiniband/hw/mthca/mthca_memfree.h @@ -77,7 +77,7 @@ struct mthca_icm_iter { struct mthca_dev; struct mthca_icm *mthca_alloc_icm(struct mthca_dev *dev, int npages, - unsigned int gfp_mask); + gfp_t gfp_mask); void mthca_free_icm(struct mthca_dev *dev, struct mthca_icm *icm); struct mthca_icm_table *mthca_alloc_icm_table(struct mthca_dev *dev, @@ -173,7 +173,8 @@ void mthca_cleanup_user_db_tab(struct mthca_dev *dev, struct mthca_uar *uar, int mthca_init_db_tab(struct mthca_dev *dev); void mthca_cleanup_db_tab(struct mthca_dev *dev); -int mthca_alloc_db(struct mthca_dev *dev, int type, u32 qn, __be32 **db); +int mthca_alloc_db(struct mthca_dev *dev, enum mthca_db_type type, + u32 qn, __be32 **db); void mthca_free_db(struct mthca_dev *dev, int type, int db_index); #endif /* MTHCA_MEMFREE_H */ diff --git a/drivers/infiniband/hw/mthca/mthca_profile.c b/drivers/infiniband/hw/mthca/mthca_profile.c index 0576056b34f4..bd1338682074 100644 --- a/drivers/infiniband/hw/mthca/mthca_profile.c +++ b/drivers/infiniband/hw/mthca/mthca_profile.c @@ -35,6 +35,8 @@ #include <linux/module.h> #include <linux/moduleparam.h> +#include <linux/string.h> +#include <linux/slab.h> #include "mthca_profile.h" diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c index 3f5319a46577..1b9477edbd7b 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.c +++ b/drivers/infiniband/hw/mthca/mthca_provider.c @@ -37,6 +37,7 @@ */ #include <rdma/ib_smi.h> +#include <rdma/ib_user_verbs.h> #include <linux/mm.h> #include "mthca_dev.h" @@ -90,15 +91,26 @@ static int mthca_query_device(struct ib_device *ibdev, props->max_mr_size = ~0ull; props->max_qp = mdev->limits.num_qps - mdev->limits.reserved_qps; - props->max_qp_wr = 0xffff; + props->max_qp_wr = mdev->limits.max_wqes; props->max_sge = mdev->limits.max_sg; props->max_cq = mdev->limits.num_cqs - mdev->limits.reserved_cqs; - props->max_cqe = 0xffff; + props->max_cqe = mdev->limits.max_cqes; props->max_mr = mdev->limits.num_mpts - mdev->limits.reserved_mrws; props->max_pd = mdev->limits.num_pds - mdev->limits.reserved_pds; props->max_qp_rd_atom = 1 << mdev->qp_table.rdb_shift; - props->max_qp_init_rd_atom = 1 << mdev->qp_table.rdb_shift; + props->max_qp_init_rd_atom = mdev->limits.max_qp_init_rdma; + props->max_res_rd_atom = props->max_qp_rd_atom * props->max_qp; + props->max_srq = mdev->limits.num_srqs - mdev->limits.reserved_srqs; + props->max_srq_wr = mdev->limits.max_srq_wqes; + props->max_srq_sge = mdev->limits.max_sg; props->local_ca_ack_delay = mdev->limits.local_ca_ack_delay; + props->atomic_cap = mdev->limits.flags & DEV_LIM_FLAG_ATOMIC ? + IB_ATOMIC_HCA : IB_ATOMIC_NONE; + props->max_pkeys = mdev->limits.pkey_table_len; + props->max_mcast_grp = mdev->limits.num_mgms + mdev->limits.num_amgms; + props->max_mcast_qp_attach = MTHCA_QP_PER_MGM; + props->max_total_mcast_qp_attach = props->max_mcast_qp_attach * + props->max_mcast_grp; err = 0; out: @@ -150,9 +162,13 @@ static int mthca_query_port(struct ib_device *ibdev, props->gid_tbl_len = to_mdev(ibdev)->limits.gid_table_len; props->max_msg_sz = 0x80000000; props->pkey_tbl_len = to_mdev(ibdev)->limits.pkey_table_len; + props->bad_pkey_cntr = be16_to_cpup((__be16 *) (out_mad->data + 46)); props->qkey_viol_cntr = be16_to_cpup((__be16 *) (out_mad->data + 48)); props->active_width = out_mad->data[31] & 0xf; props->active_speed = out_mad->data[35] >> 4; + props->max_mtu = out_mad->data[41] & 0xf; + props->active_mtu = out_mad->data[36] >> 4; + props->subnet_timeout = out_mad->data[51] & 0x1f; out: kfree(in_mad); @@ -634,6 +650,9 @@ static struct ib_cq *mthca_create_cq(struct ib_device *ibdev, int entries, int nent; int err; + if (entries < 1 || entries > to_mdev(ibdev)->limits.max_cqes) + return ERR_PTR(-EINVAL); + if (context) { if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd)) return ERR_PTR(-EFAULT); @@ -1058,6 +1077,26 @@ int mthca_register_device(struct mthca_dev *dev) strlcpy(dev->ib_dev.name, "mthca%d", IB_DEVICE_NAME_MAX); dev->ib_dev.owner = THIS_MODULE; + dev->ib_dev.uverbs_abi_ver = MTHCA_UVERBS_ABI_VERSION; + dev->ib_dev.uverbs_cmd_mask = + (1ull << IB_USER_VERBS_CMD_GET_CONTEXT) | + (1ull << IB_USER_VERBS_CMD_QUERY_DEVICE) | + (1ull << IB_USER_VERBS_CMD_QUERY_PORT) | + (1ull << IB_USER_VERBS_CMD_ALLOC_PD) | + (1ull << IB_USER_VERBS_CMD_DEALLOC_PD) | + (1ull << IB_USER_VERBS_CMD_REG_MR) | + (1ull << IB_USER_VERBS_CMD_DEREG_MR) | + (1ull << IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL) | + (1ull << IB_USER_VERBS_CMD_CREATE_CQ) | + (1ull << IB_USER_VERBS_CMD_DESTROY_CQ) | + (1ull << IB_USER_VERBS_CMD_CREATE_QP) | + (1ull << IB_USER_VERBS_CMD_MODIFY_QP) | + (1ull << IB_USER_VERBS_CMD_DESTROY_QP) | + (1ull << IB_USER_VERBS_CMD_ATTACH_MCAST) | + (1ull << IB_USER_VERBS_CMD_DETACH_MCAST) | + (1ull << IB_USER_VERBS_CMD_CREATE_SRQ) | + (1ull << IB_USER_VERBS_CMD_MODIFY_SRQ) | + (1ull << IB_USER_VERBS_CMD_DESTROY_SRQ); dev->ib_dev.node_type = IB_NODE_CA; dev->ib_dev.phys_port_cnt = dev->limits.num_ports; dev->ib_dev.dma_device = &dev->pdev->dev; @@ -1077,6 +1116,7 @@ int mthca_register_device(struct mthca_dev *dev) if (dev->mthca_flags & MTHCA_FLAG_SRQ) { dev->ib_dev.create_srq = mthca_create_srq; + dev->ib_dev.modify_srq = mthca_modify_srq; dev->ib_dev.destroy_srq = mthca_destroy_srq; if (mthca_is_memfree(dev)) @@ -1135,10 +1175,13 @@ int mthca_register_device(struct mthca_dev *dev) } } + mthca_start_catas_poll(dev); + return 0; } void mthca_unregister_device(struct mthca_dev *dev) { + mthca_stop_catas_poll(dev); ib_unregister_device(&dev->ib_dev); } diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c index 5fa00669f9b8..7c9afde5ace5 100644 --- a/drivers/infiniband/hw/mthca/mthca_qp.c +++ b/drivers/infiniband/hw/mthca/mthca_qp.c @@ -36,6 +36,8 @@ */ #include <linux/init.h> +#include <linux/string.h> +#include <linux/slab.h> #include <rdma/ib_verbs.h> #include <rdma/ib_cache.h> @@ -338,8 +340,7 @@ static const struct { [UC] = (IB_QP_AV | IB_QP_PATH_MTU | IB_QP_DEST_QPN | - IB_QP_RQ_PSN | - IB_QP_MAX_DEST_RD_ATOMIC), + IB_QP_RQ_PSN), [RC] = (IB_QP_AV | IB_QP_PATH_MTU | IB_QP_DEST_QPN | @@ -368,8 +369,7 @@ static const struct { .trans = MTHCA_TRANS_RTR2RTS, .req_param = { [UD] = IB_QP_SQ_PSN, - [UC] = (IB_QP_SQ_PSN | - IB_QP_MAX_QP_RD_ATOMIC), + [UC] = IB_QP_SQ_PSN, [RC] = (IB_QP_TIMEOUT | IB_QP_RETRY_CNT | IB_QP_RNR_RETRY | @@ -446,8 +446,6 @@ static const struct { [UD] = (IB_QP_PKEY_INDEX | IB_QP_QKEY), [UC] = (IB_QP_AV | - IB_QP_MAX_QP_RD_ATOMIC | - IB_QP_MAX_DEST_RD_ATOMIC | IB_QP_CUR_STATE | IB_QP_ALT_PATH | IB_QP_ACCESS_FLAGS | @@ -478,7 +476,7 @@ static const struct { .opt_param = { [UD] = (IB_QP_CUR_STATE | IB_QP_QKEY), - [UC] = (IB_QP_CUR_STATE), + [UC] = IB_QP_CUR_STATE, [RC] = (IB_QP_CUR_STATE | IB_QP_MIN_RNR_TIMER), [MLX] = (IB_QP_CUR_STATE | @@ -1112,8 +1110,10 @@ static int mthca_set_qp_size(struct mthca_dev *dev, struct ib_qp_cap *cap, struct mthca_qp *qp) { /* Sanity check QP size before proceeding */ - if (cap->max_send_wr > 65536 || cap->max_recv_wr > 65536 || - cap->max_send_sge > 64 || cap->max_recv_sge > 64) + if (cap->max_send_wr > dev->limits.max_wqes || + cap->max_recv_wr > dev->limits.max_wqes || + cap->max_send_sge > dev->limits.max_sg || + cap->max_recv_sge > dev->limits.max_sg) return -EINVAL; if (mthca_is_memfree(dev)) { diff --git a/drivers/infiniband/hw/mthca/mthca_reset.c b/drivers/infiniband/hw/mthca/mthca_reset.c index 4f995391dd1d..df5e494a9d38 100644 --- a/drivers/infiniband/hw/mthca/mthca_reset.c +++ b/drivers/infiniband/hw/mthca/mthca_reset.c @@ -37,6 +37,7 @@ #include <linux/errno.h> #include <linux/pci.h> #include <linux/delay.h> +#include <linux/slab.h> #include "mthca_dev.h" #include "mthca_cmd.h" diff --git a/drivers/infiniband/hw/mthca/mthca_srq.c b/drivers/infiniband/hw/mthca/mthca_srq.c index 18998d48c53e..64f70aa1b3c0 100644 --- a/drivers/infiniband/hw/mthca/mthca_srq.c +++ b/drivers/infiniband/hw/mthca/mthca_srq.c @@ -186,7 +186,8 @@ int mthca_alloc_srq(struct mthca_dev *dev, struct mthca_pd *pd, int err; /* Sanity check SRQ size before proceeding */ - if (attr->max_wr > 16 << 20 || attr->max_sge > 64) + if (attr->max_wr > dev->limits.max_srq_wqes || + attr->max_sge > dev->limits.max_sg) return -EINVAL; srq->max = attr->max_wr; @@ -332,6 +333,29 @@ void mthca_free_srq(struct mthca_dev *dev, struct mthca_srq *srq) mthca_free_mailbox(dev, mailbox); } +int mthca_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr, + enum ib_srq_attr_mask attr_mask) +{ + struct mthca_dev *dev = to_mdev(ibsrq->device); + struct mthca_srq *srq = to_msrq(ibsrq); + int ret; + u8 status; + + /* We don't support resizing SRQs (yet?) */ + if (attr_mask & IB_SRQ_MAX_WR) + return -EINVAL; + + if (attr_mask & IB_SRQ_LIMIT) { + ret = mthca_ARM_SRQ(dev, srq->srqn, attr->srq_limit, &status); + if (ret) + return ret; + if (status) + return -EINVAL; + } + + return 0; +} + void mthca_srq_event(struct mthca_dev *dev, u32 srqn, enum ib_event_type event_type) { @@ -354,7 +378,7 @@ void mthca_srq_event(struct mthca_dev *dev, u32 srqn, event.device = &dev->ib_dev; event.event = event_type; - event.element.srq = &srq->ibsrq; + event.element.srq = &srq->ibsrq; srq->ibsrq.event_handler(&event, srq->ibsrq.srq_context); out: @@ -415,6 +439,14 @@ int mthca_tavor_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr, wqe = get_wqe(srq, ind); next_ind = *wqe_to_link(wqe); + + if (next_ind < 0) { + mthca_err(dev, "SRQ %06x full\n", srq->srqn); + err = -ENOMEM; + *bad_wr = wr; + break; + } + prev_wqe = srq->last; srq->last = wqe; @@ -506,6 +538,13 @@ int mthca_arbel_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr, wqe = get_wqe(srq, ind); next_ind = *wqe_to_link(wqe); + if (next_ind < 0) { + mthca_err(dev, "SRQ %06x full\n", srq->srqn); + err = -ENOMEM; + *bad_wr = wr; + break; + } + ((struct mthca_next_seg *) wqe)->nda_op = cpu_to_be32((next_ind << srq->wqe_shift) | 1); ((struct mthca_next_seg *) wqe)->ee_nds = 0; diff --git a/drivers/infiniband/hw/mthca/mthca_uar.c b/drivers/infiniband/hw/mthca/mthca_uar.c index 1c8791ded6ff..8e9219842be4 100644 --- a/drivers/infiniband/hw/mthca/mthca_uar.c +++ b/drivers/infiniband/hw/mthca/mthca_uar.c @@ -32,6 +32,8 @@ * $Id$ */ +#include <asm/page.h> /* PAGE_SHIFT */ + #include "mthca_dev.h" #include "mthca_memfree.h" diff --git a/drivers/infiniband/hw/mthca/mthca_user.h b/drivers/infiniband/hw/mthca/mthca_user.h index 41613ec8a04e..bb015c6494c4 100644 --- a/drivers/infiniband/hw/mthca/mthca_user.h +++ b/drivers/infiniband/hw/mthca/mthca_user.h @@ -38,6 +38,12 @@ #include <linux/types.h> /* + * Increment this value if any changes that break userspace ABI + * compatibility are made. + */ +#define MTHCA_UVERBS_ABI_VERSION 1 + +/* * Make sure that all structs defined in this file remain laid out so * that they pack the same way on 32-bit and 64-bit architectures (to * avoid incompatibility between 32-bit userspace and 64-bit kernels). diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h index 4ea1c1ca85bc..c994a916a58a 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib.h +++ b/drivers/infiniband/ulp/ipoib/ipoib.h @@ -100,7 +100,12 @@ struct ipoib_pseudoheader { struct ipoib_mcast; -struct ipoib_buf { +struct ipoib_rx_buf { + struct sk_buff *skb; + dma_addr_t mapping; +}; + +struct ipoib_tx_buf { struct sk_buff *skb; DECLARE_PCI_UNMAP_ADDR(mapping) }; @@ -150,14 +155,14 @@ struct ipoib_dev_priv { unsigned int admin_mtu; unsigned int mcast_mtu; - struct ipoib_buf *rx_ring; + struct ipoib_rx_buf *rx_ring; - spinlock_t tx_lock; - struct ipoib_buf *tx_ring; - unsigned tx_head; - unsigned tx_tail; - struct ib_sge tx_sge; - struct ib_send_wr tx_wr; + spinlock_t tx_lock; + struct ipoib_tx_buf *tx_ring; + unsigned tx_head; + unsigned tx_tail; + struct ib_sge tx_sge; + struct ib_send_wr tx_wr; struct ib_wc ibwc[IPOIB_NUM_WC]; @@ -277,7 +282,7 @@ int ipoib_mcast_attach(struct net_device *dev, u16 mlid, int ipoib_mcast_detach(struct net_device *dev, u16 mlid, union ib_gid *mgid); -int ipoib_qp_create(struct net_device *dev); +int ipoib_init_qp(struct net_device *dev); int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca); void ipoib_transport_dev_cleanup(struct net_device *dev); diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c index f7440096b5ed..192fef884e21 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c @@ -95,57 +95,65 @@ void ipoib_free_ah(struct kref *kref) } } -static inline int ipoib_ib_receive(struct ipoib_dev_priv *priv, - unsigned int wr_id, - dma_addr_t addr) +static int ipoib_ib_post_receive(struct net_device *dev, int id) { - struct ib_sge list = { - .addr = addr, - .length = IPOIB_BUF_SIZE, - .lkey = priv->mr->lkey, - }; - struct ib_recv_wr param = { - .wr_id = wr_id | IPOIB_OP_RECV, - .sg_list = &list, - .num_sge = 1, - }; + struct ipoib_dev_priv *priv = netdev_priv(dev); + struct ib_sge list; + struct ib_recv_wr param; struct ib_recv_wr *bad_wr; + int ret; + + list.addr = priv->rx_ring[id].mapping; + list.length = IPOIB_BUF_SIZE; + list.lkey = priv->mr->lkey; + + param.next = NULL; + param.wr_id = id | IPOIB_OP_RECV; + param.sg_list = &list; + param.num_sge = 1; + + ret = ib_post_recv(priv->qp, ¶m, &bad_wr); + if (unlikely(ret)) { + ipoib_warn(priv, "receive failed for buf %d (%d)\n", id, ret); + dma_unmap_single(priv->ca->dma_device, + priv->rx_ring[id].mapping, + IPOIB_BUF_SIZE, DMA_FROM_DEVICE); + dev_kfree_skb_any(priv->rx_ring[id].skb); + priv->rx_ring[id].skb = NULL; + } - return ib_post_recv(priv->qp, ¶m, &bad_wr); + return ret; } -static int ipoib_ib_post_receive(struct net_device *dev, int id) +static int ipoib_alloc_rx_skb(struct net_device *dev, int id) { struct ipoib_dev_priv *priv = netdev_priv(dev); struct sk_buff *skb; dma_addr_t addr; - int ret; skb = dev_alloc_skb(IPOIB_BUF_SIZE + 4); - if (!skb) { - ipoib_warn(priv, "failed to allocate receive buffer\n"); - - priv->rx_ring[id].skb = NULL; + if (!skb) return -ENOMEM; - } - skb_reserve(skb, 4); /* 16 byte align IP header */ - priv->rx_ring[id].skb = skb; + + /* + * IB will leave a 40 byte gap for a GRH and IPoIB adds a 4 byte + * header. So we need 4 more bytes to get to 48 and align the + * IP header to a multiple of 16. + */ + skb_reserve(skb, 4); + addr = dma_map_single(priv->ca->dma_device, skb->data, IPOIB_BUF_SIZE, DMA_FROM_DEVICE); - pci_unmap_addr_set(&priv->rx_ring[id], mapping, addr); - - ret = ipoib_ib_receive(priv, id, addr); - if (ret) { - ipoib_warn(priv, "ipoib_ib_receive failed for buf %d (%d)\n", - id, ret); - dma_unmap_single(priv->ca->dma_device, addr, - IPOIB_BUF_SIZE, DMA_FROM_DEVICE); + if (unlikely(dma_mapping_error(addr))) { dev_kfree_skb_any(skb); - priv->rx_ring[id].skb = NULL; + return -EIO; } - return ret; + priv->rx_ring[id].skb = skb; + priv->rx_ring[id].mapping = addr; + + return 0; } static int ipoib_ib_post_receives(struct net_device *dev) @@ -154,6 +162,10 @@ static int ipoib_ib_post_receives(struct net_device *dev) int i; for (i = 0; i < IPOIB_RX_RING_SIZE; ++i) { + if (ipoib_alloc_rx_skb(dev, i)) { + ipoib_warn(priv, "failed to allocate receive buffer %d\n", i); + return -ENOMEM; + } if (ipoib_ib_post_receive(dev, i)) { ipoib_warn(priv, "ipoib_ib_post_receive failed for buf %d\n", i); return -EIO; @@ -176,28 +188,36 @@ static void ipoib_ib_handle_wc(struct net_device *dev, wr_id &= ~IPOIB_OP_RECV; if (wr_id < IPOIB_RX_RING_SIZE) { - struct sk_buff *skb = priv->rx_ring[wr_id].skb; - - priv->rx_ring[wr_id].skb = NULL; + struct sk_buff *skb = priv->rx_ring[wr_id].skb; + dma_addr_t addr = priv->rx_ring[wr_id].mapping; - dma_unmap_single(priv->ca->dma_device, - pci_unmap_addr(&priv->rx_ring[wr_id], - mapping), - IPOIB_BUF_SIZE, - DMA_FROM_DEVICE); - - if (wc->status != IB_WC_SUCCESS) { + if (unlikely(wc->status != IB_WC_SUCCESS)) { if (wc->status != IB_WC_WR_FLUSH_ERR) ipoib_warn(priv, "failed recv event " "(status=%d, wrid=%d vend_err %x)\n", wc->status, wr_id, wc->vendor_err); + dma_unmap_single(priv->ca->dma_device, addr, + IPOIB_BUF_SIZE, DMA_FROM_DEVICE); dev_kfree_skb_any(skb); + priv->rx_ring[wr_id].skb = NULL; return; } + /* + * If we can't allocate a new RX buffer, dump + * this packet and reuse the old buffer. + */ + if (unlikely(ipoib_alloc_rx_skb(dev, wr_id))) { + ++priv->stats.rx_dropped; + goto repost; + } + ipoib_dbg_data(priv, "received %d bytes, SLID 0x%04x\n", wc->byte_len, wc->slid); + dma_unmap_single(priv->ca->dma_device, addr, + IPOIB_BUF_SIZE, DMA_FROM_DEVICE); + skb_put(skb, wc->byte_len); skb_pull(skb, IB_GRH_BYTES); @@ -220,8 +240,8 @@ static void ipoib_ib_handle_wc(struct net_device *dev, dev_kfree_skb_any(skb); } - /* repost receive */ - if (ipoib_ib_post_receive(dev, wr_id)) + repost: + if (unlikely(ipoib_ib_post_receive(dev, wr_id))) ipoib_warn(priv, "ipoib_ib_post_receive failed " "for buf %d\n", wr_id); } else @@ -229,7 +249,7 @@ static void ipoib_ib_handle_wc(struct net_device *dev, wr_id); } else { - struct ipoib_buf *tx_req; + struct ipoib_tx_buf *tx_req; unsigned long flags; if (wr_id >= IPOIB_TX_RING_SIZE) { @@ -302,7 +322,7 @@ void ipoib_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_ah *address, u32 qpn) { struct ipoib_dev_priv *priv = netdev_priv(dev); - struct ipoib_buf *tx_req; + struct ipoib_tx_buf *tx_req; dma_addr_t addr; if (skb->len > dev->mtu + INFINIBAND_ALEN) { @@ -387,9 +407,9 @@ int ipoib_ib_dev_open(struct net_device *dev) struct ipoib_dev_priv *priv = netdev_priv(dev); int ret; - ret = ipoib_qp_create(dev); + ret = ipoib_init_qp(dev); if (ret) { - ipoib_warn(priv, "ipoib_qp_create returned %d\n", ret); + ipoib_warn(priv, "ipoib_init_qp returned %d\n", ret); return -1; } @@ -468,7 +488,7 @@ int ipoib_ib_dev_stop(struct net_device *dev) struct ib_qp_attr qp_attr; int attr_mask; unsigned long begin; - struct ipoib_buf *tx_req; + struct ipoib_tx_buf *tx_req; int i; /* Kill the existing QP and allocate a new one */ diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 6c5bf07489f4..cd4f42328dbe 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -637,8 +637,11 @@ static void ipoib_timeout(struct net_device *dev) { struct ipoib_dev_priv *priv = netdev_priv(dev); - ipoib_warn(priv, "transmit timeout: latency %ld\n", - jiffies - dev->trans_start); + ipoib_warn(priv, "transmit timeout: latency %d msecs\n", + jiffies_to_msecs(jiffies - dev->trans_start)); + ipoib_warn(priv, "queue stopped %d, tx_head %u, tx_tail %u\n", + netif_queue_stopped(dev), + priv->tx_head, priv->tx_tail); /* XXX reset QP, etc. */ } @@ -729,7 +732,7 @@ int ipoib_dev_init(struct net_device *dev, struct ib_device *ca, int port) /* Allocate RX/TX "rings" to hold queued skbs */ - priv->rx_ring = kmalloc(IPOIB_RX_RING_SIZE * sizeof (struct ipoib_buf), + priv->rx_ring = kmalloc(IPOIB_RX_RING_SIZE * sizeof (struct ipoib_rx_buf), GFP_KERNEL); if (!priv->rx_ring) { printk(KERN_WARNING "%s: failed to allocate RX ring (%d entries)\n", @@ -737,9 +740,9 @@ int ipoib_dev_init(struct net_device *dev, struct ib_device *ca, int port) goto out; } memset(priv->rx_ring, 0, - IPOIB_RX_RING_SIZE * sizeof (struct ipoib_buf)); + IPOIB_RX_RING_SIZE * sizeof (struct ipoib_rx_buf)); - priv->tx_ring = kmalloc(IPOIB_TX_RING_SIZE * sizeof (struct ipoib_buf), + priv->tx_ring = kmalloc(IPOIB_TX_RING_SIZE * sizeof (struct ipoib_tx_buf), GFP_KERNEL); if (!priv->tx_ring) { printk(KERN_WARNING "%s: failed to allocate TX ring (%d entries)\n", @@ -747,7 +750,7 @@ int ipoib_dev_init(struct net_device *dev, struct ib_device *ca, int port) goto out_rx_ring_cleanup; } memset(priv->tx_ring, 0, - IPOIB_TX_RING_SIZE * sizeof (struct ipoib_buf)); + IPOIB_TX_RING_SIZE * sizeof (struct ipoib_tx_buf)); /* priv->tx_head & tx_tail are already 0 */ diff --git a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c index 79f59d0563ed..b5902a7ec240 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c @@ -92,7 +92,7 @@ int ipoib_mcast_detach(struct net_device *dev, u16 mlid, union ib_gid *mgid) return ret; } -int ipoib_qp_create(struct net_device *dev) +int ipoib_init_qp(struct net_device *dev) { struct ipoib_dev_priv *priv = netdev_priv(dev); int ret; @@ -149,10 +149,11 @@ int ipoib_qp_create(struct net_device *dev) return 0; out_fail: - ib_destroy_qp(priv->qp); - priv->qp = NULL; + qp_attr.qp_state = IB_QPS_RESET; + if (ib_modify_qp(priv->qp, &qp_attr, IB_QP_STATE)) + ipoib_warn(priv, "Failed to modify QP to RESET state\n"); - return -EINVAL; + return ret; } int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca) diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 3738d173f9a6..a4696cd0978c 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -20,7 +20,6 @@ #include <linux/major.h> #include <linux/smp_lock.h> #include <linux/device.h> -#include <linux/devfs_fs_kernel.h> #include <linux/compat.h> struct evdev { @@ -662,6 +661,7 @@ static struct file_operations evdev_fops = { static struct input_handle *evdev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id) { struct evdev *evdev; + struct class_device *cdev; int minor; for (minor = 0; minor < EVDEV_MINORS && evdev_table[minor]; minor++); @@ -687,11 +687,13 @@ static struct input_handle *evdev_connect(struct input_handler *handler, struct evdev_table[minor] = evdev; - devfs_mk_cdev(MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor), - S_IFCHR|S_IRUGO|S_IWUSR, "input/event%d", minor); - class_device_create(input_class, + cdev = class_device_create(&input_class, &dev->cdev, MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor), - dev->dev, "event%d", minor); + dev->cdev.dev, evdev->name); + + /* temporary symlink to keep userspace happy */ + sysfs_create_link(&input_class.subsys.kset.kobj, &cdev->kobj, + evdev->name); return &evdev->handle; } @@ -701,9 +703,9 @@ static void evdev_disconnect(struct input_handle *handle) struct evdev *evdev = handle->private; struct evdev_list *list; - class_device_destroy(input_class, + sysfs_remove_link(&input_class.subsys.kset.kobj, evdev->name); + class_device_destroy(&input_class, MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + evdev->minor)); - devfs_remove("input/event%d", evdev->minor); evdev->exist = 0; if (evdev->open) { diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c index ab09cf4093e3..0506934244f0 100644 --- a/drivers/input/gameport/gameport.c +++ b/drivers/input/gameport/gameport.c @@ -21,6 +21,7 @@ #include <linux/slab.h> #include <linux/delay.h> #include <linux/kthread.h> +#include <linux/sched.h> /* HZ */ /*#include <asm/io.h>*/ diff --git a/drivers/input/input.c b/drivers/input/input.c index 14ae5583e198..3b1685ff9d10 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -22,12 +22,12 @@ #include <linux/interrupt.h> #include <linux/poll.h> #include <linux/device.h> -#include <linux/devfs_fs_kernel.h> MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>"); MODULE_DESCRIPTION("Input core"); MODULE_LICENSE("GPL"); +EXPORT_SYMBOL(input_allocate_device); EXPORT_SYMBOL(input_register_device); EXPORT_SYMBOL(input_unregister_device); EXPORT_SYMBOL(input_register_handler); @@ -39,7 +39,7 @@ EXPORT_SYMBOL(input_close_device); EXPORT_SYMBOL(input_accept_process); EXPORT_SYMBOL(input_flush_device); EXPORT_SYMBOL(input_event); -EXPORT_SYMBOL(input_class); +EXPORT_SYMBOL_GPL(input_class); #define INPUT_DEVICES 256 @@ -316,124 +316,21 @@ static struct input_device_id *input_match_device(struct input_device_id *id, st return NULL; } - -/* - * Input hotplugging interface - loading event handlers based on - * device bitfields. - */ - -#ifdef CONFIG_HOTPLUG - -/* - * Input hotplugging invokes what /proc/sys/kernel/hotplug says - * (normally /sbin/hotplug) when input devices get added or removed. - * - * This invokes a user mode policy agent, typically helping to load driver - * or other modules, configure the device, and more. Drivers can provide - * a MODULE_DEVICE_TABLE to help with module loading subtasks. - * - */ - -#define SPRINTF_BIT_A(bit, name, max) \ - do { \ - envp[i++] = scratch; \ - scratch += sprintf(scratch, name); \ - for (j = NBITS(max) - 1; j >= 0; j--) \ - if (dev->bit[j]) break; \ - for (; j >= 0; j--) \ - scratch += sprintf(scratch, "%lx ", dev->bit[j]); \ - scratch++; \ - } while (0) - -#define SPRINTF_BIT_A2(bit, name, max, ev) \ - do { \ - if (test_bit(ev, dev->evbit)) \ - SPRINTF_BIT_A(bit, name, max); \ - } while (0) - -static void input_call_hotplug(char *verb, struct input_dev *dev) +static int input_print_bitmap(char *buf, int buf_size, unsigned long *bitmap, int max) { - char *argv[3], **envp, *buf, *scratch; - int i = 0, j, value; - - if (!hotplug_path[0]) { - printk(KERN_ERR "input.c: calling hotplug without a hotplug agent defined\n"); - return; - } - if (in_interrupt()) { - printk(KERN_ERR "input.c: calling hotplug from interrupt\n"); - return; - } - if (!current->fs->root) { - printk(KERN_WARNING "input.c: calling hotplug without valid filesystem\n"); - return; - } - if (!(envp = (char **) kmalloc(20 * sizeof(char *), GFP_KERNEL))) { - printk(KERN_ERR "input.c: not enough memory allocating hotplug environment\n"); - return; - } - if (!(buf = kmalloc(1024, GFP_KERNEL))) { - kfree (envp); - printk(KERN_ERR "input.c: not enough memory allocating hotplug environment\n"); - return; - } - - argv[0] = hotplug_path; - argv[1] = "input"; - argv[2] = NULL; - - envp[i++] = "HOME=/"; - envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; - - scratch = buf; - - envp[i++] = scratch; - scratch += sprintf(scratch, "ACTION=%s", verb) + 1; - - envp[i++] = scratch; - scratch += sprintf(scratch, "PRODUCT=%x/%x/%x/%x", - dev->id.bustype, dev->id.vendor, dev->id.product, dev->id.version) + 1; - - if (dev->name) { - envp[i++] = scratch; - scratch += sprintf(scratch, "NAME=%s", dev->name) + 1; - } - - if (dev->phys) { - envp[i++] = scratch; - scratch += sprintf(scratch, "PHYS=%s", dev->phys) + 1; - } - - SPRINTF_BIT_A(evbit, "EV=", EV_MAX); - SPRINTF_BIT_A2(keybit, "KEY=", KEY_MAX, EV_KEY); - SPRINTF_BIT_A2(relbit, "REL=", REL_MAX, EV_REL); - SPRINTF_BIT_A2(absbit, "ABS=", ABS_MAX, EV_ABS); - SPRINTF_BIT_A2(mscbit, "MSC=", MSC_MAX, EV_MSC); - SPRINTF_BIT_A2(ledbit, "LED=", LED_MAX, EV_LED); - SPRINTF_BIT_A2(sndbit, "SND=", SND_MAX, EV_SND); - SPRINTF_BIT_A2(ffbit, "FF=", FF_MAX, EV_FF); - SPRINTF_BIT_A2(swbit, "SW=", SW_MAX, EV_SW); - - envp[i++] = NULL; - -#ifdef INPUT_DEBUG - printk(KERN_DEBUG "input.c: calling %s %s [%s %s %s %s %s]\n", - argv[0], argv[1], envp[0], envp[1], envp[2], envp[3], envp[4]); -#endif - - value = call_usermodehelper(argv [0], argv, envp, 0); + int i; + int len = 0; - kfree(buf); - kfree(envp); + for (i = NBITS(max) - 1; i > 0; i--) + if (bitmap[i]) + break; -#ifdef INPUT_DEBUG - if (value != 0) - printk(KERN_DEBUG "input.c: hotplug returned %d\n", value); -#endif + for (; i >= 0; i--) + len += snprintf(buf + len, max(buf_size - len, 0), + "%lx%s", bitmap[i], i > 0 ? " " : ""); + return len; } -#endif - #ifdef CONFIG_PROC_FS static struct proc_dir_entry *proc_bus_input_dir; @@ -455,37 +352,39 @@ static unsigned int input_devices_poll(struct file *file, poll_table *wait) return 0; } -#define SPRINTF_BIT_B(bit, name, max) \ - do { \ - len += sprintf(buf + len, "B: %s", name); \ - for (i = NBITS(max) - 1; i >= 0; i--) \ - if (dev->bit[i]) break; \ - for (; i >= 0; i--) \ - len += sprintf(buf + len, "%lx ", dev->bit[i]); \ - len += sprintf(buf + len, "\n"); \ +#define SPRINTF_BIT(ev, bm) \ + do { \ + len += sprintf(buf + len, "B: %s=", #ev); \ + len += input_print_bitmap(buf + len, INT_MAX, \ + dev->bm##bit, ev##_MAX); \ + len += sprintf(buf + len, "\n"); \ } while (0) -#define SPRINTF_BIT_B2(bit, name, max, ev) \ - do { \ - if (test_bit(ev, dev->evbit)) \ - SPRINTF_BIT_B(bit, name, max); \ +#define TEST_AND_SPRINTF_BIT(ev, bm) \ + do { \ + if (test_bit(EV_##ev, dev->evbit)) \ + SPRINTF_BIT(ev, bm); \ } while (0) static int input_devices_read(char *buf, char **start, off_t pos, int count, int *eof, void *data) { struct input_dev *dev; struct input_handle *handle; + const char *path; off_t at = 0; - int i, len, cnt = 0; + int len, cnt = 0; list_for_each_entry(dev, &input_dev_list, node) { + path = dev->dynalloc ? kobject_get_path(&dev->cdev.kobj, GFP_KERNEL) : NULL; + len = sprintf(buf, "I: Bus=%04x Vendor=%04x Product=%04x Version=%04x\n", dev->id.bustype, dev->id.vendor, dev->id.product, dev->id.version); len += sprintf(buf + len, "N: Name=\"%s\"\n", dev->name ? dev->name : ""); len += sprintf(buf + len, "P: Phys=%s\n", dev->phys ? dev->phys : ""); + len += sprintf(buf + len, "S: Sysfs=%s\n", path ? path : ""); len += sprintf(buf + len, "H: Handlers="); list_for_each_entry(handle, &dev->h_list, d_node) @@ -493,15 +392,15 @@ static int input_devices_read(char *buf, char **start, off_t pos, int count, int len += sprintf(buf + len, "\n"); - SPRINTF_BIT_B(evbit, "EV=", EV_MAX); - SPRINTF_BIT_B2(keybit, "KEY=", KEY_MAX, EV_KEY); - SPRINTF_BIT_B2(relbit, "REL=", REL_MAX, EV_REL); - SPRINTF_BIT_B2(absbit, "ABS=", ABS_MAX, EV_ABS); - SPRINTF_BIT_B2(mscbit, "MSC=", MSC_MAX, EV_MSC); - SPRINTF_BIT_B2(ledbit, "LED=", LED_MAX, EV_LED); - SPRINTF_BIT_B2(sndbit, "SND=", SND_MAX, EV_SND); - SPRINTF_BIT_B2(ffbit, "FF=", FF_MAX, EV_FF); - SPRINTF_BIT_B2(swbit, "SW=", SW_MAX, EV_SW); + SPRINTF_BIT(EV, ev); + TEST_AND_SPRINTF_BIT(KEY, key); + TEST_AND_SPRINTF_BIT(REL, rel); + TEST_AND_SPRINTF_BIT(ABS, abs); + TEST_AND_SPRINTF_BIT(MSC, msc); + TEST_AND_SPRINTF_BIT(LED, led); + TEST_AND_SPRINTF_BIT(SND, snd); + TEST_AND_SPRINTF_BIT(FF, ff); + TEST_AND_SPRINTF_BIT(SW, sw); len += sprintf(buf + len, "\n"); @@ -516,6 +415,8 @@ static int input_devices_read(char *buf, char **start, off_t pos, int count, int if (cnt >= count) break; } + + kfree(path); } if (&dev->node == &input_dev_list) @@ -606,6 +507,240 @@ static inline int input_proc_init(void) { return 0; } static inline void input_proc_exit(void) { } #endif +#define INPUT_DEV_STRING_ATTR_SHOW(name) \ +static ssize_t input_dev_show_##name(struct class_device *dev, char *buf) \ +{ \ + struct input_dev *input_dev = to_input_dev(dev); \ + int retval; \ + \ + retval = down_interruptible(&input_dev->sem); \ + if (retval) \ + return retval; \ + \ + retval = sprintf(buf, "%s\n", input_dev->name ? input_dev->name : ""); \ + \ + up(&input_dev->sem); \ + \ + return retval; \ +} \ +static CLASS_DEVICE_ATTR(name, S_IRUGO, input_dev_show_##name, NULL); + +INPUT_DEV_STRING_ATTR_SHOW(name); +INPUT_DEV_STRING_ATTR_SHOW(phys); +INPUT_DEV_STRING_ATTR_SHOW(uniq); + +static struct attribute *input_dev_attrs[] = { + &class_device_attr_name.attr, + &class_device_attr_phys.attr, + &class_device_attr_uniq.attr, + NULL +}; + +static struct attribute_group input_dev_group = { + .attrs = input_dev_attrs, +}; + +#define INPUT_DEV_ID_ATTR(name) \ +static ssize_t input_dev_show_id_##name(struct class_device *dev, char *buf) \ +{ \ + struct input_dev *input_dev = to_input_dev(dev); \ + return sprintf(buf, "%04x\n", input_dev->id.name); \ +} \ +static CLASS_DEVICE_ATTR(name, S_IRUGO, input_dev_show_id_##name, NULL); + +INPUT_DEV_ID_ATTR(bustype); +INPUT_DEV_ID_ATTR(vendor); +INPUT_DEV_ID_ATTR(product); +INPUT_DEV_ID_ATTR(version); + +static struct attribute *input_dev_id_attrs[] = { + &class_device_attr_bustype.attr, + &class_device_attr_vendor.attr, + &class_device_attr_product.attr, + &class_device_attr_version.attr, + NULL +}; + +static struct attribute_group input_dev_id_attr_group = { + .name = "id", + .attrs = input_dev_id_attrs, +}; + +#define INPUT_DEV_CAP_ATTR(ev, bm) \ +static ssize_t input_dev_show_cap_##bm(struct class_device *dev, char *buf) \ +{ \ + struct input_dev *input_dev = to_input_dev(dev); \ + return input_print_bitmap(buf, PAGE_SIZE, input_dev->bm##bit, ev##_MAX);\ +} \ +static CLASS_DEVICE_ATTR(bm, S_IRUGO, input_dev_show_cap_##bm, NULL); + +INPUT_DEV_CAP_ATTR(EV, ev); +INPUT_DEV_CAP_ATTR(KEY, key); +INPUT_DEV_CAP_ATTR(REL, rel); +INPUT_DEV_CAP_ATTR(ABS, abs); +INPUT_DEV_CAP_ATTR(MSC, msc); +INPUT_DEV_CAP_ATTR(LED, led); +INPUT_DEV_CAP_ATTR(SND, snd); +INPUT_DEV_CAP_ATTR(FF, ff); +INPUT_DEV_CAP_ATTR(SW, sw); + +static struct attribute *input_dev_caps_attrs[] = { + &class_device_attr_ev.attr, + &class_device_attr_key.attr, + &class_device_attr_rel.attr, + &class_device_attr_abs.attr, + &class_device_attr_msc.attr, + &class_device_attr_led.attr, + &class_device_attr_snd.attr, + &class_device_attr_ff.attr, + &class_device_attr_sw.attr, + NULL +}; + +static struct attribute_group input_dev_caps_attr_group = { + .name = "capabilities", + .attrs = input_dev_caps_attrs, +}; + +static void input_dev_release(struct class_device *class_dev) +{ + struct input_dev *dev = to_input_dev(class_dev); + + kfree(dev); + module_put(THIS_MODULE); +} + +/* + * Input hotplugging interface - loading event handlers based on + * device bitfields. + */ +static int input_add_hotplug_bm_var(char **envp, int num_envp, int *cur_index, + char *buffer, int buffer_size, int *cur_len, + const char *name, unsigned long *bitmap, int max) +{ + if (*cur_index >= num_envp - 1) + return -ENOMEM; + + envp[*cur_index] = buffer + *cur_len; + + *cur_len += snprintf(buffer + *cur_len, max(buffer_size - *cur_len, 0), name); + if (*cur_len > buffer_size) + return -ENOMEM; + + *cur_len += input_print_bitmap(buffer + *cur_len, + max(buffer_size - *cur_len, 0), + bitmap, max) + 1; + if (*cur_len > buffer_size) + return -ENOMEM; + + (*cur_index)++; + return 0; +} + +#define INPUT_ADD_HOTPLUG_VAR(fmt, val...) \ + do { \ + int err = add_hotplug_env_var(envp, num_envp, &i, \ + buffer, buffer_size, &len, \ + fmt, val); \ + if (err) \ + return err; \ + } while (0) + +#define INPUT_ADD_HOTPLUG_BM_VAR(name, bm, max) \ + do { \ + int err = input_add_hotplug_bm_var(envp, num_envp, &i, \ + buffer, buffer_size, &len, \ + name, bm, max); \ + if (err) \ + return err; \ + } while (0) + +static int input_dev_hotplug(struct class_device *cdev, char **envp, + int num_envp, char *buffer, int buffer_size) +{ + struct input_dev *dev = to_input_dev(cdev); + int i = 0; + int len = 0; + + INPUT_ADD_HOTPLUG_VAR("PRODUCT=%x/%x/%x/%x", + dev->id.bustype, dev->id.vendor, + dev->id.product, dev->id.version); + if (dev->name) + INPUT_ADD_HOTPLUG_VAR("NAME=\"%s\"", dev->name); + if (dev->phys) + INPUT_ADD_HOTPLUG_VAR("PHYS=\"%s\"", dev->phys); + if (dev->phys) + INPUT_ADD_HOTPLUG_VAR("UNIQ=\"%s\"", dev->uniq); + + INPUT_ADD_HOTPLUG_BM_VAR("EV=", dev->evbit, EV_MAX); + if (test_bit(EV_KEY, dev->evbit)) + INPUT_ADD_HOTPLUG_BM_VAR("KEY=", dev->keybit, KEY_MAX); + if (test_bit(EV_REL, dev->evbit)) + INPUT_ADD_HOTPLUG_BM_VAR("REL=", dev->relbit, REL_MAX); + if (test_bit(EV_ABS, dev->evbit)) + INPUT_ADD_HOTPLUG_BM_VAR("ABS=", dev->absbit, ABS_MAX); + if (test_bit(EV_MSC, dev->evbit)) + INPUT_ADD_HOTPLUG_BM_VAR("MSC=", dev->mscbit, MSC_MAX); + if (test_bit(EV_LED, dev->evbit)) + INPUT_ADD_HOTPLUG_BM_VAR("LED=", dev->ledbit, LED_MAX); + if (test_bit(EV_SND, dev->evbit)) + INPUT_ADD_HOTPLUG_BM_VAR("SND=", dev->sndbit, SND_MAX); + if (test_bit(EV_FF, dev->evbit)) + INPUT_ADD_HOTPLUG_BM_VAR("FF=", dev->ffbit, FF_MAX); + if (test_bit(EV_SW, dev->evbit)) + INPUT_ADD_HOTPLUG_BM_VAR("SW=", dev->swbit, SW_MAX); + + envp[i] = NULL; + + return 0; +} + +struct class input_class = { + .name = "input", + .release = input_dev_release, + .hotplug = input_dev_hotplug, +}; + +struct input_dev *input_allocate_device(void) +{ + struct input_dev *dev; + + dev = kzalloc(sizeof(struct input_dev), GFP_KERNEL); + if (dev) { + dev->dynalloc = 1; + dev->cdev.class = &input_class; + class_device_initialize(&dev->cdev); + INIT_LIST_HEAD(&dev->h_list); + INIT_LIST_HEAD(&dev->node); + } + + return dev; +} + +static void input_register_classdevice(struct input_dev *dev) +{ + static atomic_t input_no = ATOMIC_INIT(0); + const char *path; + + __module_get(THIS_MODULE); + + dev->dev = dev->cdev.dev; + + snprintf(dev->cdev.class_id, sizeof(dev->cdev.class_id), + "input%ld", (unsigned long) atomic_inc_return(&input_no) - 1); + + path = kobject_get_path(&dev->cdev.class->subsys.kset.kobj, GFP_KERNEL); + printk(KERN_INFO "input: %s/%s as %s\n", + dev->name ? dev->name : "Unspecified device", + path ? path : "", dev->cdev.class_id); + kfree(path); + + class_device_add(&dev->cdev); + sysfs_create_group(&dev->cdev.kobj, &input_dev_group); + sysfs_create_group(&dev->cdev.kobj, &input_dev_id_attr_group); + sysfs_create_group(&dev->cdev.kobj, &input_dev_caps_attr_group); +} + void input_register_device(struct input_dev *dev) { struct input_handle *handle; @@ -632,15 +767,15 @@ void input_register_device(struct input_dev *dev) INIT_LIST_HEAD(&dev->h_list); list_add_tail(&dev->node, &input_dev_list); + if (dev->dynalloc) + input_register_classdevice(dev); + list_for_each_entry(handler, &input_handler_list, node) if (!handler->blacklist || !input_match_device(handler->blacklist, dev)) if ((id = input_match_device(handler->id_table, dev))) if ((handle = handler->connect(handler, dev, id))) input_link_handle(handle); -#ifdef CONFIG_HOTPLUG - input_call_hotplug("add", dev); -#endif input_wakeup_procfs_readers(); } @@ -660,12 +795,14 @@ void input_unregister_device(struct input_dev *dev) handle->handler->disconnect(handle); } -#ifdef CONFIG_HOTPLUG - input_call_hotplug("remove", dev); -#endif - list_del_init(&dev->node); + if (dev->dynalloc) { + sysfs_remove_group(&dev->cdev.kobj, &input_dev_caps_attr_group); + sysfs_remove_group(&dev->cdev.kobj, &input_dev_id_attr_group); + class_device_unregister(&dev->cdev); + } + input_wakeup_procfs_readers(); } @@ -748,16 +885,14 @@ static struct file_operations input_fops = { .open = input_open_file, }; -struct class *input_class; - static int __init input_init(void) { int err; - input_class = class_create(THIS_MODULE, "input"); - if (IS_ERR(input_class)) { - printk(KERN_ERR "input: unable to register input class\n"); - return PTR_ERR(input_class); + err = class_register(&input_class); + if (err) { + printk(KERN_ERR "input: unable to register input_dev class\n"); + return err; } err = input_proc_init(); @@ -770,24 +905,18 @@ static int __init input_init(void) goto fail2; } - err = devfs_mk_dir("input"); - if (err) - goto fail3; - return 0; - fail3: unregister_chrdev(INPUT_MAJOR, "input"); fail2: input_proc_exit(); - fail1: class_destroy(input_class); + fail1: class_unregister(&input_class); return err; } static void __exit input_exit(void) { input_proc_exit(); - devfs_remove("input"); unregister_chrdev(INPUT_MAJOR, "input"); - class_destroy(input_class); + class_unregister(&input_class); } subsys_initcall(input_init); diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index e0938d1d3ad7..20e2972b9204 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c @@ -26,7 +26,6 @@ #include <linux/init.h> #include <linux/smp_lock.h> #include <linux/device.h> -#include <linux/devfs_fs_kernel.h> MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); MODULE_DESCRIPTION("Joystick device interfaces"); @@ -449,6 +448,7 @@ static struct file_operations joydev_fops = { static struct input_handle *joydev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id) { struct joydev *joydev; + struct class_device *cdev; int i, j, t, minor; for (minor = 0; minor < JOYDEV_MINORS && joydev_table[minor]; minor++); @@ -514,11 +514,13 @@ static struct input_handle *joydev_connect(struct input_handler *handler, struct joydev_table[minor] = joydev; - devfs_mk_cdev(MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor), - S_IFCHR|S_IRUGO|S_IWUSR, "input/js%d", minor); - class_device_create(input_class, + cdev = class_device_create(&input_class, &dev->cdev, MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor), - dev->dev, "js%d", minor); + dev->cdev.dev, joydev->name); + + /* temporary symlink to keep userspace happy */ + sysfs_create_link(&input_class.subsys.kset.kobj, &cdev->kobj, + joydev->name); return &joydev->handle; } @@ -528,8 +530,8 @@ static void joydev_disconnect(struct input_handle *handle) struct joydev *joydev = handle->private; struct joydev_list *list; - class_device_destroy(input_class, MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + joydev->minor)); - devfs_remove("input/js%d", joydev->minor); + sysfs_remove_link(&input_class.subsys.kset.kobj, joydev->name); + class_device_destroy(&input_class, MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + joydev->minor)); joydev->exist = 0; if (joydev->open) { diff --git a/drivers/input/joystick/a3d.c b/drivers/input/joystick/a3d.c index bf65430181fa..4571ea3a4b92 100644 --- a/drivers/input/joystick/a3d.c +++ b/drivers/input/joystick/a3d.c @@ -34,6 +34,7 @@ #include <linux/init.h> #include <linux/gameport.h> #include <linux/input.h> +#include <linux/jiffies.h> #define DRIVER_DESC "FP-Gaming Assasin 3D joystick driver" diff --git a/drivers/input/joystick/adi.c b/drivers/input/joystick/adi.c index cf35ae638a0d..704bf70f1db7 100644 --- a/drivers/input/joystick/adi.c +++ b/drivers/input/joystick/adi.c @@ -34,6 +34,7 @@ #include <linux/input.h> #include <linux/gameport.h> #include <linux/init.h> +#include <linux/jiffies.h> #define DRIVER_DESC "Logitech ADI joystick family driver" @@ -54,7 +55,7 @@ MODULE_LICENSE("GPL"); #define ADI_MIN_LENGTH 8 #define ADI_MIN_LEN_LENGTH 10 #define ADI_MIN_ID_LENGTH 66 -#define ADI_MAX_NAME_LENGTH 48 +#define ADI_MAX_NAME_LENGTH 64 #define ADI_MAX_CNAME_LENGTH 16 #define ADI_MAX_PHYS_LENGTH 64 @@ -106,7 +107,7 @@ static struct { */ struct adi { - struct input_dev dev; + struct input_dev *dev; int length; int ret; int idx; @@ -215,7 +216,7 @@ static inline int adi_get_bits(struct adi *adi, int count) static int adi_decode(struct adi *adi) { - struct input_dev *dev = &adi->dev; + struct input_dev *dev = adi->dev; char *abs = adi->abs; short *key = adi->key; int i, t; @@ -318,7 +319,8 @@ static void adi_init_digital(struct gameport *gameport) for (i = 0; seq[i]; i++) { gameport_trigger(gameport); - if (seq[i] > 0) msleep(seq[i]); + if (seq[i] > 0) + msleep(seq[i]); if (seq[i] < 0) { mdelay(-seq[i]); udelay(-seq[i]*14); /* It looks like mdelay() is off by approx 1.4% */ @@ -397,42 +399,46 @@ static void adi_id_decode(struct adi *adi, struct adi_port *port) } } -static void adi_init_input(struct adi *adi, struct adi_port *port, int half) +static int adi_init_input(struct adi *adi, struct adi_port *port, int half) { - int i, t; + struct input_dev *input_dev; char buf[ADI_MAX_NAME_LENGTH]; + int i, t; - if (!adi->length) return; - - init_input_dev(&adi->dev); + adi->dev = input_dev = input_allocate_device(); + if (!input_dev) + return -ENOMEM; t = adi->id < ADI_ID_MAX ? adi->id : ADI_ID_MAX; snprintf(buf, ADI_MAX_PHYS_LENGTH, adi_names[t], adi->id); - snprintf(adi->name, ADI_MAX_NAME_LENGTH, "Logitech %s", buf); + snprintf(adi->name, ADI_MAX_NAME_LENGTH, "Logitech %s [%s]", buf, adi->cname); snprintf(adi->phys, ADI_MAX_PHYS_LENGTH, "%s/input%d", port->gameport->phys, half); adi->abs = adi_abs[t]; adi->key = adi_key[t]; - adi->dev.open = adi_open; - adi->dev.close = adi_close; + input_dev->name = adi->name; + input_dev->phys = adi->phys; + input_dev->id.bustype = BUS_GAMEPORT; + input_dev->id.vendor = GAMEPORT_ID_VENDOR_LOGITECH; + input_dev->id.product = adi->id; + input_dev->id.version = 0x0100; + input_dev->cdev.dev = &port->gameport->dev; + input_dev->private = port; - adi->dev.name = adi->name; - adi->dev.phys = adi->phys; - adi->dev.id.bustype = BUS_GAMEPORT; - adi->dev.id.vendor = GAMEPORT_ID_VENDOR_LOGITECH; - adi->dev.id.product = adi->id; - adi->dev.id.version = 0x0100; + input_dev->open = adi_open; + input_dev->close = adi_close; - adi->dev.private = port; - adi->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); for (i = 0; i < adi->axes10 + adi->axes8 + (adi->hats + (adi->pad != -1)) * 2; i++) - set_bit(adi->abs[i], adi->dev.absbit); + set_bit(adi->abs[i], input_dev->absbit); for (i = 0; i < adi->buttons; i++) - set_bit(adi->key[i], adi->dev.keybit); + set_bit(adi->key[i], input_dev->keybit); + + return 0; } static void adi_init_center(struct adi *adi) @@ -445,17 +451,17 @@ static void adi_init_center(struct adi *adi) for (i = 0; i < adi->axes10 + adi->axes8 + (adi->hats + (adi->pad != -1)) * 2; i++) { t = adi->abs[i]; - x = adi->dev.abs[t]; + x = adi->dev->abs[t]; if (t == ABS_THROTTLE || t == ABS_RUDDER || adi->id == ADI_ID_WGPE) x = i < adi->axes10 ? 512 : 128; if (i < adi->axes10) - input_set_abs_params(&adi->dev, t, 64, x * 2 - 64, 2, 16); + input_set_abs_params(adi->dev, t, 64, x * 2 - 64, 2, 16); else if (i < adi->axes10 + adi->axes8) - input_set_abs_params(&adi->dev, t, 48, x * 2 - 48, 1, 16); + input_set_abs_params(adi->dev, t, 48, x * 2 - 48, 1, 16); else - input_set_abs_params(&adi->dev, t, -1, 1, 0, 0); + input_set_abs_params(adi->dev, t, -1, 1, 0, 0); } } @@ -469,7 +475,8 @@ static int adi_connect(struct gameport *gameport, struct gameport_driver *drv) int i; int err; - if (!(port = kzalloc(sizeof(struct adi_port), GFP_KERNEL))) + port = kzalloc(sizeof(struct adi_port), GFP_KERNEL); + if (!port) return -ENOMEM; port->gameport = gameport; @@ -477,10 +484,8 @@ static int adi_connect(struct gameport *gameport, struct gameport_driver *drv) gameport_set_drvdata(gameport, port); err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW); - if (err) { - kfree(port); - return err; - } + if (err) + goto fail1; adi_init_digital(gameport); adi_read_packet(port); @@ -490,13 +495,18 @@ static int adi_connect(struct gameport *gameport, struct gameport_driver *drv) for (i = 0; i < 2; i++) { adi_id_decode(port->adi + i, port); - adi_init_input(port->adi + i, port, i); + + if (!port->adi[i].length) + continue; + + err = adi_init_input(port->adi + i, port, i); + if (err) + goto fail2; } if (!port->adi[0].length && !port->adi[1].length) { - gameport_close(gameport); - kfree(port); - return -ENODEV; + err = -ENODEV; + goto fail2; } gameport_set_poll_handler(gameport, adi_poll); @@ -511,12 +521,18 @@ static int adi_connect(struct gameport *gameport, struct gameport_driver *drv) for (i = 0; i < 2; i++) if (port->adi[i].length > 0) { adi_init_center(port->adi + i); - input_register_device(&port->adi[i].dev); - printk(KERN_INFO "input: %s [%s] on %s\n", - port->adi[i].name, port->adi[i].cname, gameport->phys); + input_register_device(port->adi[i].dev); } return 0; + + fail2: for (i = 0; i < 2; i++) + if (port->adi[i].dev) + input_free_device(port->adi[i].dev); + gameport_close(gameport); + fail1: gameport_set_drvdata(gameport, NULL); + kfree(port); + return err; } static void adi_disconnect(struct gameport *gameport) @@ -526,7 +542,7 @@ static void adi_disconnect(struct gameport *gameport) for (i = 0; i < 2; i++) if (port->adi[i].length > 0) - input_unregister_device(&port->adi[i].dev); + input_unregister_device(port->adi[i].dev); gameport_close(gameport); gameport_set_drvdata(gameport, NULL); kfree(port); diff --git a/drivers/input/joystick/amijoy.c b/drivers/input/joystick/amijoy.c index e996183c5b06..8558a99f6635 100644 --- a/drivers/input/joystick/amijoy.c +++ b/drivers/input/joystick/amijoy.c @@ -53,11 +53,9 @@ __obsolete_setup("amijoy="); static int amijoy_used; static DECLARE_MUTEX(amijoy_sem); -static struct input_dev amijoy_dev[2]; +static struct input_dev *amijoy_dev[2]; static char *amijoy_phys[2] = { "amijoy/input0", "amijoy/input1" }; -static char *amijoy_name = "Amiga joystick"; - static irqreturn_t amijoy_interrupt(int irq, void *dummy, struct pt_regs *fp) { int i, data = 0, button = 0; @@ -70,15 +68,15 @@ static irqreturn_t amijoy_interrupt(int irq, void *dummy, struct pt_regs *fp) case 1: data = ~custom.joy1dat; button = (~ciaa.pra >> 7) & 1; break; } - input_regs(amijoy_dev + i, fp); + input_regs(amijoy_dev[i], fp); - input_report_key(amijoy_dev + i, BTN_TRIGGER, button); + input_report_key(amijoy_dev[i], BTN_TRIGGER, button); - input_report_abs(amijoy_dev + i, ABS_X, ((data >> 1) & 1) - ((data >> 9) & 1)); + input_report_abs(amijoy_dev[i], ABS_X, ((data >> 1) & 1) - ((data >> 9) & 1)); data = ~(data ^ (data << 1)); - input_report_abs(amijoy_dev + i, ABS_Y, ((data >> 1) & 1) - ((data >> 9) & 1)); + input_report_abs(amijoy_dev[i], ABS_Y, ((data >> 1) & 1) - ((data >> 9) & 1)); - input_sync(amijoy_dev + i); + input_sync(amijoy_dev[i]); } return IRQ_HANDLED; } @@ -114,39 +112,52 @@ static void amijoy_close(struct input_dev *dev) static int __init amijoy_init(void) { int i, j; + int err; - for (i = 0; i < 2; i++) - if (amijoy[i]) { - if (!request_mem_region(CUSTOM_PHYSADDR+10+i*2, 2, - "amijoy [Denise]")) { - if (i == 1 && amijoy[0]) { - input_unregister_device(amijoy_dev); - release_mem_region(CUSTOM_PHYSADDR+10, 2); - } - return -EBUSY; - } + for (i = 0; i < 2; i++) { + if (!amijoy[i]) + continue; - amijoy_dev[i].open = amijoy_open; - amijoy_dev[i].close = amijoy_close; - amijoy_dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - amijoy_dev[i].absbit[0] = BIT(ABS_X) | BIT(ABS_Y); - amijoy_dev[i].keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); - for (j = 0; j < 2; j++) { - amijoy_dev[i].absmin[ABS_X + j] = -1; - amijoy_dev[i].absmax[ABS_X + j] = 1; - } + amijoy_dev[i] = input_allocate_device(); + if (!amijoy_dev[i]) { + err = -ENOMEM; + goto fail; + } - amijoy_dev[i].name = amijoy_name; - amijoy_dev[i].phys = amijoy_phys[i]; - amijoy_dev[i].id.bustype = BUS_AMIGA; - amijoy_dev[i].id.vendor = 0x0001; - amijoy_dev[i].id.product = 0x0003; - amijoy_dev[i].id.version = 0x0100; + if (!request_mem_region(CUSTOM_PHYSADDR + 10 + i * 2, 2, "amijoy [Denise]")) { + input_free_device(amijoy_dev[i]); + err = -EBUSY; + goto fail; + } - input_register_device(amijoy_dev + i); - printk(KERN_INFO "input: %s at joy%ddat\n", amijoy_name, i); + amijoy_dev[i]->name = "Amiga joystick"; + amijoy_dev[i]->phys = amijoy_phys[i]; + amijoy_dev[i]->id.bustype = BUS_AMIGA; + amijoy_dev[i]->id.vendor = 0x0001; + amijoy_dev[i]->id.product = 0x0003; + amijoy_dev[i]->id.version = 0x0100; + + amijoy_dev[i]->open = amijoy_open; + amijoy_dev[i]->close = amijoy_close; + + amijoy_dev[i]->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + amijoy_dev[i]->absbit[0] = BIT(ABS_X) | BIT(ABS_Y); + amijoy_dev[i]->keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); + for (j = 0; j < 2; j++) { + amijoy_dev[i]->absmin[ABS_X + j] = -1; + amijoy_dev[i]->absmax[ABS_X + j] = 1; } + + input_register_device(amijoy_dev[i]); + } return 0; + + fail: while (--i >= 0) + if (amijoy[i]) { + input_unregister_device(amijoy_dev[i]); + release_mem_region(CUSTOM_PHYSADDR + 10 + i * 2, 2); + } + return err; } static void __exit amijoy_exit(void) @@ -155,8 +166,8 @@ static void __exit amijoy_exit(void) for (i = 0; i < 2; i++) if (amijoy[i]) { - input_unregister_device(amijoy_dev + i); - release_mem_region(CUSTOM_PHYSADDR+10+i*2, 2); + input_unregister_device(amijoy_dev[i]); + release_mem_region(CUSTOM_PHYSADDR + 10 + i * 2, 2); } } diff --git a/drivers/input/joystick/analog.c b/drivers/input/joystick/analog.c index 64b1313a3c66..3121961e3e7c 100644 --- a/drivers/input/joystick/analog.c +++ b/drivers/input/joystick/analog.c @@ -38,6 +38,7 @@ #include <linux/init.h> #include <linux/input.h> #include <linux/gameport.h> +#include <linux/jiffies.h> #include <asm/timex.h> #define DRIVER_DESC "Analog joystick and gamepad driver" @@ -111,7 +112,7 @@ static short analog_joy_btn[] = { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN static unsigned char analog_chf[] = { 0xf, 0x0, 0x1, 0x9, 0x2, 0x4, 0xc, 0x8, 0x3, 0x5, 0xb, 0x7, 0xd, 0xe, 0xa, 0x6 }; struct analog { - struct input_dev dev; + struct input_dev *dev; int mask; short *buttons; char name[ANALOG_MAX_NAME_LENGTH]; @@ -182,7 +183,7 @@ static unsigned long analog_faketime = 0; static void analog_decode(struct analog *analog, int *axes, int *initial, int buttons) { - struct input_dev *dev = &analog->dev; + struct input_dev *dev = analog->dev; int i, j; if (analog->mask & ANALOG_HAT_FCS) @@ -428,27 +429,30 @@ static void analog_name(struct analog *analog) * analog_init_device() */ -static void analog_init_device(struct analog_port *port, struct analog *analog, int index) +static int analog_init_device(struct analog_port *port, struct analog *analog, int index) { + struct input_dev *input_dev; int i, j, t, v, w, x, y, z; analog_name(analog); sprintf(analog->phys, "%s/input%d", port->gameport->phys, index); analog->buttons = (analog->mask & ANALOG_GAMEPAD) ? analog_pad_btn : analog_joy_btn; - init_input_dev(&analog->dev); + analog->dev = input_dev = input_allocate_device(); + if (!input_dev) + return -ENOMEM; - analog->dev.name = analog->name; - analog->dev.phys = analog->phys; - analog->dev.id.bustype = BUS_GAMEPORT; - analog->dev.id.vendor = GAMEPORT_ID_VENDOR_ANALOG; - analog->dev.id.product = analog->mask >> 4; - analog->dev.id.version = 0x0100; + input_dev->name = analog->name; + input_dev->phys = analog->phys; + input_dev->id.bustype = BUS_GAMEPORT; + input_dev->id.vendor = GAMEPORT_ID_VENDOR_ANALOG; + input_dev->id.product = analog->mask >> 4; + input_dev->id.version = 0x0100; - analog->dev.open = analog_open; - analog->dev.close = analog_close; - analog->dev.private = port; - analog->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + input_dev->open = analog_open; + input_dev->close = analog_close; + input_dev->private = port; + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); for (i = j = 0; i < 4; i++) if (analog->mask & (1 << i)) { @@ -461,8 +465,6 @@ static void analog_init_device(struct analog_port *port, struct analog *analog, v = (x >> 3); w = (x >> 3); - set_bit(t, analog->dev.absbit); - if ((i == 2 || i == 3) && (j == 2 || j == 3) && (z > (y >> 3))) x = y; @@ -472,11 +474,7 @@ static void analog_init_device(struct analog_port *port, struct analog *analog, w = (x >> 4); } - analog->dev.absmax[t] = (x << 1) - v; - analog->dev.absmin[t] = v; - analog->dev.absfuzz[t] = port->fuzz; - analog->dev.absflat[t] = w; - + input_set_abs_params(input_dev, t, v, (x << 1) - v, port->fuzz, w); j++; } @@ -484,41 +482,30 @@ static void analog_init_device(struct analog_port *port, struct analog *analog, if (analog->mask & analog_exts[i]) for (x = 0; x < 2; x++) { t = analog_hats[j++]; - set_bit(t, analog->dev.absbit); - analog->dev.absmax[t] = 1; - analog->dev.absmin[t] = -1; + input_set_abs_params(input_dev, t, -1, 1, 0, 0); } for (i = j = 0; i < 4; i++) if (analog->mask & (0x10 << i)) - set_bit(analog->buttons[j++], analog->dev.keybit); + set_bit(analog->buttons[j++], input_dev->keybit); if (analog->mask & ANALOG_BTNS_CHF) for (i = 0; i < 2; i++) - set_bit(analog->buttons[j++], analog->dev.keybit); + set_bit(analog->buttons[j++], input_dev->keybit); if (analog->mask & ANALOG_HBTN_CHF) for (i = 0; i < 4; i++) - set_bit(analog->buttons[j++], analog->dev.keybit); + set_bit(analog->buttons[j++], input_dev->keybit); for (i = 0; i < 4; i++) if (analog->mask & (ANALOG_BTN_TL << i)) - set_bit(analog_pads[i], analog->dev.keybit); + set_bit(analog_pads[i], input_dev->keybit); analog_decode(analog, port->axes, port->initial, port->buttons); - input_register_device(&analog->dev); + input_register_device(analog->dev); - printk(KERN_INFO "input: %s at %s", analog->name, port->gameport->phys); - - if (port->cooked) - printk(" [ADC port]\n"); - else - printk(" [%s timer, %d %sHz clock, %d ns res]\n", TIME_NAME, - port->speed > 10000 ? (port->speed + 800) / 1000 : port->speed, - port->speed > 10000 ? "M" : "k", - port->speed > 10000 ? (port->loop * 1000) / (port->speed / 1000) - : (port->loop * 1000000) / port->speed); + return 0; } /* @@ -659,37 +646,41 @@ static int analog_connect(struct gameport *gameport, struct gameport_driver *drv return - ENOMEM; err = analog_init_port(gameport, drv, port); - if (err) { - kfree(port); - return err; - } + if (err) + goto fail1; err = analog_init_masks(port); - if (err) { - gameport_close(gameport); - gameport_set_drvdata(gameport, NULL); - kfree(port); - return err; - } + if (err) + goto fail2; gameport_set_poll_handler(gameport, analog_poll); gameport_set_poll_interval(gameport, 10); for (i = 0; i < 2; i++) - if (port->analog[i].mask) - analog_init_device(port, port->analog + i, i); + if (port->analog[i].mask) { + err = analog_init_device(port, port->analog + i, i); + if (err) + goto fail3; + } return 0; + + fail3: while (--i >= 0) + input_unregister_device(port->analog[i].dev); + fail2: gameport_close(gameport); + fail1: gameport_set_drvdata(gameport, NULL); + kfree(port); + return err; } static void analog_disconnect(struct gameport *gameport) { - int i; struct analog_port *port = gameport_get_drvdata(gameport); + int i; for (i = 0; i < 2; i++) if (port->analog[i].mask) - input_unregister_device(&port->analog[i].dev); + input_unregister_device(port->analog[i].dev); gameport_close(gameport); gameport_set_drvdata(gameport, NULL); printk(KERN_INFO "analog.c: %d out of %d reads (%d%%) on %s failed\n", diff --git a/drivers/input/joystick/cobra.c b/drivers/input/joystick/cobra.c index 0b2e9fa26579..1909f7ef340c 100644 --- a/drivers/input/joystick/cobra.c +++ b/drivers/input/joystick/cobra.c @@ -34,6 +34,7 @@ #include <linux/init.h> #include <linux/gameport.h> #include <linux/input.h> +#include <linux/jiffies.h> #define DRIVER_DESC "Creative Labs Blaster GamePad Cobra driver" @@ -44,13 +45,11 @@ MODULE_LICENSE("GPL"); #define COBRA_MAX_STROBE 45 /* 45 us max wait for first strobe */ #define COBRA_LENGTH 36 -static char* cobra_name = "Creative Labs Blaster GamePad Cobra"; - static int cobra_btn[] = { BTN_START, BTN_SELECT, BTN_TL, BTN_TR, BTN_X, BTN_Y, BTN_Z, BTN_A, BTN_B, BTN_C, BTN_TL2, BTN_TR2, 0 }; struct cobra { struct gameport *gameport; - struct input_dev dev[2]; + struct input_dev *dev[2]; int reads; int bads; unsigned char exists; @@ -128,7 +127,7 @@ static void cobra_poll(struct gameport *gameport) for (i = 0; i < 2; i++) if (cobra->exists & r & (1 << i)) { - dev = cobra->dev + i; + dev = cobra->dev[i]; input_report_abs(dev, ABS_X, ((data[i] >> 4) & 1) - ((data[i] >> 3) & 1)); input_report_abs(dev, ABS_Y, ((data[i] >> 2) & 1) - ((data[i] >> 1) & 1)); @@ -159,11 +158,13 @@ static void cobra_close(struct input_dev *dev) static int cobra_connect(struct gameport *gameport, struct gameport_driver *drv) { struct cobra *cobra; + struct input_dev *input_dev; unsigned int data[2]; int i, j; int err; - if (!(cobra = kzalloc(sizeof(struct cobra), GFP_KERNEL))) + cobra = kzalloc(sizeof(struct cobra), GFP_KERNEL); + if (!cobra) return -ENOMEM; cobra->gameport = gameport; @@ -191,38 +192,46 @@ static int cobra_connect(struct gameport *gameport, struct gameport_driver *drv) gameport_set_poll_handler(gameport, cobra_poll); gameport_set_poll_interval(gameport, 20); - for (i = 0; i < 2; i++) - if ((cobra->exists >> i) & 1) { - - sprintf(cobra->phys[i], "%s/input%d", gameport->phys, i); + for (i = 0; i < 2; i++) { + if (~(cobra->exists >> i) & 1) + continue; - cobra->dev[i].private = cobra; - cobra->dev[i].open = cobra_open; - cobra->dev[i].close = cobra_close; + cobra->dev[i] = input_dev = input_allocate_device(); + if (!input_dev) { + err = -ENOMEM; + goto fail3; + } - cobra->dev[i].name = cobra_name; - cobra->dev[i].phys = cobra->phys[i]; - cobra->dev[i].id.bustype = BUS_GAMEPORT; - cobra->dev[i].id.vendor = GAMEPORT_ID_VENDOR_CREATIVE; - cobra->dev[i].id.product = 0x0008; - cobra->dev[i].id.version = 0x0100; + sprintf(cobra->phys[i], "%s/input%d", gameport->phys, i); - cobra->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + input_dev->name = "Creative Labs Blaster GamePad Cobra"; + input_dev->phys = cobra->phys[i]; + input_dev->id.bustype = BUS_GAMEPORT; + input_dev->id.vendor = GAMEPORT_ID_VENDOR_CREATIVE; + input_dev->id.product = 0x0008; + input_dev->id.version = 0x0100; + input_dev->cdev.dev = &gameport->dev; + input_dev->private = cobra; - input_set_abs_params(&cobra->dev[i], ABS_X, -1, 1, 0, 0); - input_set_abs_params(&cobra->dev[i], ABS_Y, -1, 1, 0, 0); + input_dev->open = cobra_open; + input_dev->close = cobra_close; - for (j = 0; cobra_btn[j]; j++) - set_bit(cobra_btn[j], cobra->dev[i].keybit); + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + input_set_abs_params(input_dev, ABS_X, -1, 1, 0, 0); + input_set_abs_params(input_dev, ABS_Y, -1, 1, 0, 0); + for (j = 0; cobra_btn[j]; j++) + set_bit(cobra_btn[j], input_dev->keybit); - input_register_device(&cobra->dev[i]); - printk(KERN_INFO "input: %s on %s\n", cobra_name, gameport->phys); - } + input_register_device(cobra->dev[i]); + } return 0; -fail2: gameport_close(gameport); -fail1: gameport_set_drvdata(gameport, NULL); + fail3: for (i = 0; i < 2; i++) + if (cobra->dev[i]) + input_unregister_device(cobra->dev[i]); + fail2: gameport_close(gameport); + fail1: gameport_set_drvdata(gameport, NULL); kfree(cobra); return err; } @@ -234,7 +243,7 @@ static void cobra_disconnect(struct gameport *gameport) for (i = 0; i < 2; i++) if ((cobra->exists >> i) & 1) - input_unregister_device(cobra->dev + i); + input_unregister_device(cobra->dev[i]); gameport_close(gameport); gameport_set_drvdata(gameport, NULL); kfree(cobra); diff --git a/drivers/input/joystick/db9.c b/drivers/input/joystick/db9.c index 2a3e4bb2da50..499344c72756 100644 --- a/drivers/input/joystick/db9.c +++ b/drivers/input/joystick/db9.c @@ -43,25 +43,28 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); MODULE_DESCRIPTION("Atari, Amstrad, Commodore, Amiga, Sega, etc. joystick driver"); MODULE_LICENSE("GPL"); -static int db9[] __initdata = { -1, 0 }; -static int db9_nargs __initdata = 0; -module_param_array_named(dev, db9, int, &db9_nargs, 0); -MODULE_PARM_DESC(dev, "Describes first attached device (<parport#>,<type>)"); +struct db9_config { + int args[2]; + int nargs; +}; -static int db9_2[] __initdata = { -1, 0 }; -static int db9_nargs_2 __initdata = 0; -module_param_array_named(dev2, db9_2, int, &db9_nargs_2, 0); -MODULE_PARM_DESC(dev2, "Describes second attached device (<parport#>,<type>)"); +#define DB9_MAX_PORTS 3 +static struct db9_config db9[DB9_MAX_PORTS] __initdata; -static int db9_3[] __initdata = { -1, 0 }; -static int db9_nargs_3 __initdata = 0; -module_param_array_named(dev3, db9_3, int, &db9_nargs_3, 0); +module_param_array_named(dev, db9[0].args, int, &db9[0].nargs, 0); +MODULE_PARM_DESC(dev, "Describes first attached device (<parport#>,<type>)"); +module_param_array_named(dev2, db9[1].args, int, &db9[0].nargs, 0); +MODULE_PARM_DESC(dev2, "Describes second attached device (<parport#>,<type>)"); +module_param_array_named(dev3, db9[2].args, int, &db9[2].nargs, 0); MODULE_PARM_DESC(dev3, "Describes third attached device (<parport#>,<type>)"); __obsolete_setup("db9="); __obsolete_setup("db9_2="); __obsolete_setup("db9_3="); +#define DB9_ARG_PARPORT 0 +#define DB9_ARG_MODE 1 + #define DB9_MULTI_STICK 0x01 #define DB9_MULTI2_STICK 0x02 #define DB9_GENESIS_PAD 0x03 @@ -87,40 +90,53 @@ __obsolete_setup("db9_3="); #define DB9_NORMAL 0x0a #define DB9_NOSELECT 0x08 -#define DB9_MAX_DEVICES 2 - #define DB9_GENESIS6_DELAY 14 #define DB9_REFRESH_TIME HZ/100 +#define DB9_MAX_DEVICES 2 + +struct db9_mode_data { + const char *name; + const short *buttons; + int n_buttons; + int n_pads; + int n_axis; + int bidirectional; + int reverse; +}; + struct db9 { - struct input_dev dev[DB9_MAX_DEVICES]; + struct input_dev *dev[DB9_MAX_DEVICES]; struct timer_list timer; struct pardevice *pd; int mode; int used; struct semaphore sem; - char phys[2][32]; + char phys[DB9_MAX_DEVICES][32]; }; static struct db9 *db9_base[3]; -static short db9_multi_btn[] = { BTN_TRIGGER, BTN_THUMB }; -static short db9_genesis_btn[] = { BTN_START, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_MODE }; -static short db9_cd32_btn[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_START }; - -static char db9_buttons[DB9_MAX_PAD] = { 0, 1, 2, 4, 0, 6, 8, 9, 1, 1, 7, 9, 9 }; -static short *db9_btn[DB9_MAX_PAD] = { NULL, db9_multi_btn, db9_multi_btn, db9_genesis_btn, NULL, db9_genesis_btn, - db9_genesis_btn, db9_cd32_btn, db9_multi_btn, db9_multi_btn, db9_cd32_btn, - db9_cd32_btn, db9_cd32_btn }; -static char *db9_name[DB9_MAX_PAD] = { NULL, "Multisystem joystick", "Multisystem joystick (2 fire)", "Genesis pad", - NULL, "Genesis 5 pad", "Genesis 6 pad", "Saturn pad", "Multisystem (0.8.0.2) joystick", - "Multisystem (0.8.0.2-dual) joystick", "Amiga CD-32 pad", "Saturn dpp", "Saturn dpp dual" }; - -static const int db9_max_pads[DB9_MAX_PAD] = { 0, 1, 1, 1, 0, 1, 1, 6, 1, 2, 1, 6, 12 }; -static const int db9_num_axis[DB9_MAX_PAD] = { 0, 2, 2, 2, 0, 2, 2, 7, 2, 2, 2 ,7, 7 }; +static const short db9_multi_btn[] = { BTN_TRIGGER, BTN_THUMB }; +static const short db9_genesis_btn[] = { BTN_START, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_MODE }; +static const short db9_cd32_btn[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_START }; static const short db9_abs[] = { ABS_X, ABS_Y, ABS_RX, ABS_RY, ABS_RZ, ABS_Z, ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y }; -static const int db9_bidirectional[DB9_MAX_PAD] = { 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0 }; -static const int db9_reverse[DB9_MAX_PAD] = { 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0 }; + +static const struct db9_mode_data db9_modes[] = { + { NULL, NULL, 0, 0, 0, 0, 0 }, + { "Multisystem joystick", db9_multi_btn, 1, 1, 2, 1, 1 }, + { "Multisystem joystick (2 fire)", db9_multi_btn, 2, 1, 2, 1, 1 }, + { "Genesis pad", db9_genesis_btn, 4, 1, 2, 1, 1 }, + { NULL, NULL, 0, 0, 0, 0, 0 }, + { "Genesis 5 pad", db9_genesis_btn, 6, 1, 2, 1, 1 }, + { "Genesis 6 pad", db9_genesis_btn, 8, 1, 2, 1, 1 }, + { "Saturn pad", db9_cd32_btn, 9, 6, 7, 0, 1 }, + { "Multisystem (0.8.0.2) joystick", db9_multi_btn, 1, 1, 2, 1, 1 }, + { "Multisystem (0.8.0.2-dual) joystick", db9_multi_btn, 1, 2, 2, 1, 1 }, + { "Amiga CD-32 pad", db9_cd32_btn, 7, 1, 2, 1, 1 }, + { "Saturn dpp", db9_cd32_btn, 9, 6, 7, 0, 0 }, + { "Saturn dpp dual", db9_cd32_btn, 9, 12, 7, 0, 0 }, +}; /* * Saturn controllers @@ -342,7 +358,7 @@ static int db9_saturn(int mode, struct parport *port, struct input_dev *dev) default: return -1; } - max_pads = min(db9_max_pads[mode], DB9_MAX_DEVICES); + max_pads = min(db9_modes[mode].n_pads, DB9_MAX_DEVICES); for (tmp = 0, i = 0; i < n; i++) { id = db9_saturn_read_packet(port, data, type + i, 1); tmp = db9_saturn_report(id, data, dev, tmp, max_pads); @@ -354,17 +370,18 @@ static void db9_timer(unsigned long private) { struct db9 *db9 = (void *) private; struct parport *port = db9->pd->port; - struct input_dev *dev = db9->dev; + struct input_dev *dev = db9->dev[0]; + struct input_dev *dev2 = db9->dev[1]; int data, i; - switch(db9->mode) { + switch (db9->mode) { case DB9_MULTI_0802_2: data = parport_read_data(port) >> 3; - input_report_abs(dev + 1, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1)); - input_report_abs(dev + 1, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1)); - input_report_key(dev + 1, BTN_TRIGGER, ~data & DB9_FIRE1); + input_report_abs(dev2, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1)); + input_report_abs(dev2, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1)); + input_report_key(dev2, BTN_TRIGGER, ~data & DB9_FIRE1); case DB9_MULTI_0802: @@ -405,7 +422,7 @@ static void db9_timer(unsigned long private) input_report_key(dev, BTN_C, ~data & DB9_FIRE2); parport_write_control(port, DB9_NORMAL); - data=parport_read_data(port); + data = parport_read_data(port); input_report_key(dev, BTN_A, ~data & DB9_FIRE1); input_report_key(dev, BTN_START, ~data & DB9_FIRE2); @@ -414,7 +431,7 @@ static void db9_timer(unsigned long private) case DB9_GENESIS5_PAD: parport_write_control(port, DB9_NOSELECT); - data=parport_read_data(port); + data = parport_read_data(port); input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1)); input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1)); @@ -422,7 +439,7 @@ static void db9_timer(unsigned long private) input_report_key(dev, BTN_C, ~data & DB9_FIRE2); parport_write_control(port, DB9_NORMAL); - data=parport_read_data(port); + data = parport_read_data(port); input_report_key(dev, BTN_A, ~data & DB9_FIRE1); input_report_key(dev, BTN_X, ~data & DB9_FIRE2); @@ -434,7 +451,7 @@ static void db9_timer(unsigned long private) parport_write_control(port, DB9_NOSELECT); /* 1 */ udelay(DB9_GENESIS6_DELAY); - data=parport_read_data(port); + data = parport_read_data(port); input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1)); input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1)); @@ -443,7 +460,7 @@ static void db9_timer(unsigned long private) parport_write_control(port, DB9_NORMAL); udelay(DB9_GENESIS6_DELAY); - data=parport_read_data(port); + data = parport_read_data(port); input_report_key(dev, BTN_A, ~data & DB9_FIRE1); input_report_key(dev, BTN_START, ~data & DB9_FIRE2); @@ -477,7 +494,7 @@ static void db9_timer(unsigned long private) case DB9_CD32_PAD: - data=parport_read_data(port); + data = parport_read_data(port); input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1)); input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1)); @@ -489,7 +506,7 @@ static void db9_timer(unsigned long private) parport_write_control(port, 0x02); parport_write_control(port, 0x0a); input_report_key(dev, db9_cd32_btn[i], ~data & DB9_FIRE2); - } + } parport_write_control(port, 0x00); break; @@ -513,7 +530,7 @@ static int db9_open(struct input_dev *dev) if (!db9->used++) { parport_claim(db9->pd); parport_write_data(port, 0xff); - if (db9_reverse[db9->mode]) { + if (db9_modes[db9->mode].reverse) { parport_data_reverse(port); parport_write_control(port, DB9_NORMAL); } @@ -539,117 +556,160 @@ static void db9_close(struct input_dev *dev) up(&db9->sem); } -static struct db9 __init *db9_probe(int *config, int nargs) +static struct db9 __init *db9_probe(int parport, int mode) { struct db9 *db9; + const struct db9_mode_data *db9_mode; struct parport *pp; + struct pardevice *pd; + struct input_dev *input_dev; int i, j; + int err; - if (config[0] < 0) - return NULL; - - if (nargs < 2) { - printk(KERN_ERR "db9.c: Device type must be specified.\n"); - return NULL; + if (mode < 1 || mode >= DB9_MAX_PAD || !db9_modes[mode].n_buttons) { + printk(KERN_ERR "db9.c: Bad device type %d\n", mode); + err = -EINVAL; + goto err_out; } - if (config[1] < 1 || config[1] >= DB9_MAX_PAD || !db9_buttons[config[1]]) { - printk(KERN_ERR "db9.c: bad config\n"); - return NULL; - } + db9_mode = &db9_modes[mode]; - pp = parport_find_number(config[0]); + pp = parport_find_number(parport); if (!pp) { printk(KERN_ERR "db9.c: no such parport\n"); - return NULL; + err = -ENODEV; + goto err_out; } - if (db9_bidirectional[config[1]]) { - if (!(pp->modes & PARPORT_MODE_TRISTATE)) { - printk(KERN_ERR "db9.c: specified parport is not bidirectional\n"); - parport_put_port(pp); - return NULL; - } + if (db9_mode[mode].bidirectional && !(pp->modes & PARPORT_MODE_TRISTATE)) { + printk(KERN_ERR "db9.c: specified parport is not bidirectional\n"); + err = -EINVAL; + goto err_put_pp; + } + + pd = parport_register_device(pp, "db9", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL); + if (!pd) { + printk(KERN_ERR "db9.c: parport busy already - lp.o loaded?\n"); + err = -EBUSY; + goto err_put_pp; } - if (!(db9 = kzalloc(sizeof(struct db9), GFP_KERNEL))) { - parport_put_port(pp); - return NULL; + db9 = kzalloc(sizeof(struct db9), GFP_KERNEL); + if (!db9) { + printk(KERN_ERR "db9.c: Not enough memory\n"); + err = -ENOMEM; + goto err_unreg_pardev; } init_MUTEX(&db9->sem); - db9->mode = config[1]; + db9->pd = pd; + db9->mode = mode; init_timer(&db9->timer); db9->timer.data = (long) db9; db9->timer.function = db9_timer; - db9->pd = parport_register_device(pp, "db9", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL); - parport_put_port(pp); - - if (!db9->pd) { - printk(KERN_ERR "db9.c: parport busy already - lp.o loaded?\n"); - kfree(db9); - return NULL; - } + for (i = 0; i < (min(db9_mode->n_pads, DB9_MAX_DEVICES)); i++) { - for (i = 0; i < (min(db9_max_pads[db9->mode], DB9_MAX_DEVICES)); i++) { + db9->dev[i] = input_dev = input_allocate_device(); + if (!input_dev) { + printk(KERN_ERR "db9.c: Not enough memory for input device\n"); + err = -ENOMEM; + goto err_free_devs; + } sprintf(db9->phys[i], "%s/input%d", db9->pd->port->name, i); - db9->dev[i].private = db9; - db9->dev[i].open = db9_open; - db9->dev[i].close = db9_close; - - db9->dev[i].name = db9_name[db9->mode]; - db9->dev[i].phys = db9->phys[i]; - db9->dev[i].id.bustype = BUS_PARPORT; - db9->dev[i].id.vendor = 0x0002; - db9->dev[i].id.product = config[1]; - db9->dev[i].id.version = 0x0100; - - db9->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - for (j = 0; j < db9_buttons[db9->mode]; j++) - set_bit(db9_btn[db9->mode][j], db9->dev[i].keybit); - for (j = 0; j < db9_num_axis[db9->mode]; j++) { - set_bit(db9_abs[j], db9->dev[i].absbit); - if (j < 2) { - db9->dev[i].absmin[db9_abs[j]] = -1; - db9->dev[i].absmax[db9_abs[j]] = 1; - } else { - db9->dev[i].absmin[db9_abs[j]] = 1; - db9->dev[i].absmax[db9_abs[j]] = 255; - db9->dev[i].absflat[db9_abs[j]] = 0; - } + input_dev->name = db9_mode->name; + input_dev->phys = db9->phys[i]; + input_dev->id.bustype = BUS_PARPORT; + input_dev->id.vendor = 0x0002; + input_dev->id.product = mode; + input_dev->id.version = 0x0100; + input_dev->private = db9; + + input_dev->open = db9_open; + input_dev->close = db9_close; + + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + for (j = 0; j < db9_mode->n_buttons; j++) + set_bit(db9_mode->buttons[j], input_dev->keybit); + for (j = 0; j < db9_mode->n_axis; j++) { + if (j < 2) + input_set_abs_params(input_dev, db9_abs[j], -1, 1, 0, 0); + else + input_set_abs_params(input_dev, db9_abs[j], 1, 255, 0, 0); } - input_register_device(db9->dev + i); - printk(KERN_INFO "input: %s on %s\n", db9->dev[i].name, db9->pd->port->name); + + input_register_device(input_dev); } + parport_put_port(pp); return db9; + + err_free_devs: + while (--i >= 0) + input_unregister_device(db9->dev[i]); + kfree(db9); + err_unreg_pardev: + parport_unregister_device(pd); + err_put_pp: + parport_put_port(pp); + err_out: + return ERR_PTR(err); +} + +static void __exit db9_remove(struct db9 *db9) +{ + int i; + + for (i = 0; i < min(db9_modes[db9->mode].n_pads, DB9_MAX_DEVICES); i++) + input_unregister_device(db9->dev[i]); + parport_unregister_device(db9->pd); + kfree(db9); } static int __init db9_init(void) { - db9_base[0] = db9_probe(db9, db9_nargs); - db9_base[1] = db9_probe(db9_2, db9_nargs_2); - db9_base[2] = db9_probe(db9_3, db9_nargs_3); + int i; + int have_dev = 0; + int err = 0; + + for (i = 0; i < DB9_MAX_PORTS; i++) { + if (db9[i].nargs == 0 || db9[i].args[DB9_ARG_PARPORT] < 0) + continue; + + if (db9[i].nargs < 2) { + printk(KERN_ERR "db9.c: Device type must be specified.\n"); + err = -EINVAL; + break; + } + + db9_base[i] = db9_probe(db9[i].args[DB9_ARG_PARPORT], + db9[i].args[DB9_ARG_MODE]); + if (IS_ERR(db9_base[i])) { + err = PTR_ERR(db9_base[i]); + break; + } + + have_dev = 1; + } - if (db9_base[0] || db9_base[1] || db9_base[2]) - return 0; + if (err) { + while (--i >= 0) + db9_remove(db9_base[i]); + return err; + } - return -ENODEV; + return have_dev ? 0 : -ENODEV; } static void __exit db9_exit(void) { - int i, j; + int i; - for (i = 0; i < 3; i++) - if (db9_base[i]) { - for (j = 0; j < min(db9_max_pads[db9_base[i]->mode], DB9_MAX_DEVICES); j++) - input_unregister_device(db9_base[i]->dev + j); - parport_unregister_device(db9_base[i]->pd); - } + for (i = 0; i < DB9_MAX_PORTS; i++) + if (db9_base[i]) + db9_remove(db9_base[i]); } module_init(db9_init); diff --git a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c index 5427bf9fc862..7df2d82f2c83 100644 --- a/drivers/input/joystick/gamecon.c +++ b/drivers/input/joystick/gamecon.c @@ -41,20 +41,22 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); MODULE_DESCRIPTION("NES, SNES, N64, MultiSystem, PSX gamepad driver"); MODULE_LICENSE("GPL"); -static int gc[] __initdata = { -1, 0, 0, 0, 0, 0 }; -static int gc_nargs __initdata = 0; -module_param_array_named(map, gc, int, &gc_nargs, 0); -MODULE_PARM_DESC(map, "Describers first set of devices (<parport#>,<pad1>,<pad2>,..<pad5>)"); +#define GC_MAX_PORTS 3 +#define GC_MAX_DEVICES 5 -static int gc_2[] __initdata = { -1, 0, 0, 0, 0, 0 }; -static int gc_nargs_2 __initdata = 0; -module_param_array_named(map2, gc_2, int, &gc_nargs_2, 0); -MODULE_PARM_DESC(map2, "Describers second set of devices"); +struct gc_config { + int args[GC_MAX_DEVICES + 1]; + int nargs; +}; + +static struct gc_config gc[GC_MAX_PORTS] __initdata; -static int gc_3[] __initdata = { -1, 0, 0, 0, 0, 0 }; -static int gc_nargs_3 __initdata = 0; -module_param_array_named(map3, gc_3, int, &gc_nargs_3, 0); -MODULE_PARM_DESC(map3, "Describers third set of devices"); +module_param_array_named(map, gc[0].args, int, &gc[0].nargs, 0); +MODULE_PARM_DESC(map, "Describes first set of devices (<parport#>,<pad1>,<pad2>,..<pad5>)"); +module_param_array_named(map2, gc[1].args, int, &gc[1].nargs, 0); +MODULE_PARM_DESC(map2, "Describes second set of devices"); +module_param_array_named(map3, gc[2].args, int, &gc[2].nargs, 0); +MODULE_PARM_DESC(map3, "Describes third set of devices"); __obsolete_setup("gc="); __obsolete_setup("gc_2="); @@ -77,12 +79,12 @@ __obsolete_setup("gc_3="); struct gc { struct pardevice *pd; - struct input_dev dev[5]; + struct input_dev *dev[GC_MAX_DEVICES]; struct timer_list timer; unsigned char pads[GC_MAX + 1]; int used; struct semaphore sem; - char phys[5][32]; + char phys[GC_MAX_DEVICES][32]; }; static struct gc *gc_base[3]; @@ -330,7 +332,6 @@ static void gc_psx_read_packet(struct gc *gc, unsigned char data[5][GC_PSX_BYTES static void gc_timer(unsigned long private) { struct gc *gc = (void *) private; - struct input_dev *dev = gc->dev; unsigned char data[GC_MAX_LENGTH]; unsigned char data_psx[5][GC_PSX_BYTES]; int i, j, s; @@ -357,16 +358,16 @@ static void gc_timer(unsigned long private) if (data[31 - j] & s) axes[1] |= 1 << j; } - input_report_abs(dev + i, ABS_X, axes[0]); - input_report_abs(dev + i, ABS_Y, -axes[1]); + input_report_abs(gc->dev[i], ABS_X, axes[0]); + input_report_abs(gc->dev[i], ABS_Y, -axes[1]); - input_report_abs(dev + i, ABS_HAT0X, !(s & data[6]) - !(s & data[7])); - input_report_abs(dev + i, ABS_HAT0Y, !(s & data[4]) - !(s & data[5])); + input_report_abs(gc->dev[i], ABS_HAT0X, !(s & data[6]) - !(s & data[7])); + input_report_abs(gc->dev[i], ABS_HAT0Y, !(s & data[4]) - !(s & data[5])); for (j = 0; j < 10; j++) - input_report_key(dev + i, gc_n64_btn[j], s & data[gc_n64_bytes[j]]); + input_report_key(gc->dev[i], gc_n64_btn[j], s & data[gc_n64_bytes[j]]); - input_sync(dev + i); + input_sync(gc->dev[i]); } } } @@ -384,19 +385,19 @@ static void gc_timer(unsigned long private) s = gc_status_bit[i]; if (s & (gc->pads[GC_NES] | gc->pads[GC_SNES])) { - input_report_abs(dev + i, ABS_X, !(s & data[6]) - !(s & data[7])); - input_report_abs(dev + i, ABS_Y, !(s & data[4]) - !(s & data[5])); + input_report_abs(gc->dev[i], ABS_X, !(s & data[6]) - !(s & data[7])); + input_report_abs(gc->dev[i], ABS_Y, !(s & data[4]) - !(s & data[5])); } if (s & gc->pads[GC_NES]) for (j = 0; j < 4; j++) - input_report_key(dev + i, gc_snes_btn[j], s & data[gc_nes_bytes[j]]); + input_report_key(gc->dev[i], gc_snes_btn[j], s & data[gc_nes_bytes[j]]); if (s & gc->pads[GC_SNES]) for (j = 0; j < 8; j++) - input_report_key(dev + i, gc_snes_btn[j], s & data[gc_snes_bytes[j]]); + input_report_key(gc->dev[i], gc_snes_btn[j], s & data[gc_snes_bytes[j]]); - input_sync(dev + i); + input_sync(gc->dev[i]); } } @@ -413,15 +414,15 @@ static void gc_timer(unsigned long private) s = gc_status_bit[i]; if (s & (gc->pads[GC_MULTI] | gc->pads[GC_MULTI2])) { - input_report_abs(dev + i, ABS_X, !(s & data[2]) - !(s & data[3])); - input_report_abs(dev + i, ABS_Y, !(s & data[0]) - !(s & data[1])); - input_report_key(dev + i, BTN_TRIGGER, s & data[4]); + input_report_abs(gc->dev[i], ABS_X, !(s & data[2]) - !(s & data[3])); + input_report_abs(gc->dev[i], ABS_Y, !(s & data[0]) - !(s & data[1])); + input_report_key(gc->dev[i], BTN_TRIGGER, s & data[4]); } if (s & gc->pads[GC_MULTI2]) - input_report_key(dev + i, BTN_THUMB, s & data[5]); + input_report_key(gc->dev[i], BTN_THUMB, s & data[5]); - input_sync(dev + i); + input_sync(gc->dev[i]); } } @@ -438,44 +439,44 @@ static void gc_timer(unsigned long private) case GC_PSX_RUMBLE: - input_report_key(dev + i, BTN_THUMBL, ~data_psx[i][0] & 0x04); - input_report_key(dev + i, BTN_THUMBR, ~data_psx[i][0] & 0x02); + input_report_key(gc->dev[i], BTN_THUMBL, ~data_psx[i][0] & 0x04); + input_report_key(gc->dev[i], BTN_THUMBR, ~data_psx[i][0] & 0x02); case GC_PSX_NEGCON: case GC_PSX_ANALOG: - if(gc->pads[GC_DDR] & gc_status_bit[i]) { + if (gc->pads[GC_DDR] & gc_status_bit[i]) { for(j = 0; j < 4; j++) - input_report_key(dev + i, gc_psx_ddr_btn[j], ~data_psx[i][0] & (0x10 << j)); + input_report_key(gc->dev[i], gc_psx_ddr_btn[j], ~data_psx[i][0] & (0x10 << j)); } else { for (j = 0; j < 4; j++) - input_report_abs(dev + i, gc_psx_abs[j+2], data_psx[i][j + 2]); + input_report_abs(gc->dev[i], gc_psx_abs[j+2], data_psx[i][j + 2]); - input_report_abs(dev + i, ABS_X, 128 + !(data_psx[i][0] & 0x20) * 127 - !(data_psx[i][0] & 0x80) * 128); - input_report_abs(dev + i, ABS_Y, 128 + !(data_psx[i][0] & 0x40) * 127 - !(data_psx[i][0] & 0x10) * 128); + input_report_abs(gc->dev[i], ABS_X, 128 + !(data_psx[i][0] & 0x20) * 127 - !(data_psx[i][0] & 0x80) * 128); + input_report_abs(gc->dev[i], ABS_Y, 128 + !(data_psx[i][0] & 0x40) * 127 - !(data_psx[i][0] & 0x10) * 128); } for (j = 0; j < 8; j++) - input_report_key(dev + i, gc_psx_btn[j], ~data_psx[i][1] & (1 << j)); + input_report_key(gc->dev[i], gc_psx_btn[j], ~data_psx[i][1] & (1 << j)); - input_report_key(dev + i, BTN_START, ~data_psx[i][0] & 0x08); - input_report_key(dev + i, BTN_SELECT, ~data_psx[i][0] & 0x01); + input_report_key(gc->dev[i], BTN_START, ~data_psx[i][0] & 0x08); + input_report_key(gc->dev[i], BTN_SELECT, ~data_psx[i][0] & 0x01); - input_sync(dev + i); + input_sync(gc->dev[i]); break; case GC_PSX_NORMAL: - if(gc->pads[GC_DDR] & gc_status_bit[i]) { + if (gc->pads[GC_DDR] & gc_status_bit[i]) { for(j = 0; j < 4; j++) - input_report_key(dev + i, gc_psx_ddr_btn[j], ~data_psx[i][0] & (0x10 << j)); + input_report_key(gc->dev[i], gc_psx_ddr_btn[j], ~data_psx[i][0] & (0x10 << j)); } else { - input_report_abs(dev + i, ABS_X, 128 + !(data_psx[i][0] & 0x20) * 127 - !(data_psx[i][0] & 0x80) * 128); - input_report_abs(dev + i, ABS_Y, 128 + !(data_psx[i][0] & 0x40) * 127 - !(data_psx[i][0] & 0x10) * 128); + input_report_abs(gc->dev[i], ABS_X, 128 + !(data_psx[i][0] & 0x20) * 127 - !(data_psx[i][0] & 0x80) * 128); + input_report_abs(gc->dev[i], ABS_Y, 128 + !(data_psx[i][0] & 0x40) * 127 - !(data_psx[i][0] & 0x10) * 128); /* for some reason if the extra axes are left unset they drift */ /* for (j = 0; j < 4; j++) - input_report_abs(dev + i, gc_psx_abs[j+2], 128); + input_report_abs(gc->dev[i], gc_psx_abs[j+2], 128); * This needs to be debugged properly, * maybe fuzz processing needs to be done in input_sync() * --vojtech @@ -483,12 +484,12 @@ static void gc_timer(unsigned long private) } for (j = 0; j < 8; j++) - input_report_key(dev + i, gc_psx_btn[j], ~data_psx[i][1] & (1 << j)); + input_report_key(gc->dev[i], gc_psx_btn[j], ~data_psx[i][1] & (1 << j)); - input_report_key(dev + i, BTN_START, ~data_psx[i][0] & 0x08); - input_report_key(dev + i, BTN_SELECT, ~data_psx[i][0] & 0x01); + input_report_key(gc->dev[i], BTN_START, ~data_psx[i][0] & 0x08); + input_report_key(gc->dev[i], BTN_SELECT, ~data_psx[i][0] & 0x01); - input_sync(dev + i); + input_sync(gc->dev[i]); break; @@ -533,177 +534,212 @@ static void gc_close(struct input_dev *dev) up(&gc->sem); } -static struct gc __init *gc_probe(int *config, int nargs) +static int __init gc_setup_pad(struct gc *gc, int idx, int pad_type) { - struct gc *gc; - struct parport *pp; - int i, j; + struct input_dev *input_dev; + int i; - if (config[0] < 0) - return NULL; + if (!pad_type) + return 0; - if (nargs < 2) { - printk(KERN_ERR "gamecon.c: at least one device must be specified\n"); - return NULL; + if (pad_type < 1 || pad_type > GC_MAX) { + printk(KERN_WARNING "gamecon.c: Pad type %d unknown\n", pad_type); + return -EINVAL; } - pp = parport_find_number(config[0]); - - if (!pp) { - printk(KERN_ERR "gamecon.c: no such parport\n"); - return NULL; + gc->dev[idx] = input_dev = input_allocate_device(); + if (!input_dev) { + printk(KERN_ERR "gamecon.c: Not enough memory for input device\n"); + return -ENOMEM; } - if (!(gc = kzalloc(sizeof(struct gc), GFP_KERNEL))) { - parport_put_port(pp); - return NULL; + input_dev->name = gc_names[pad_type]; + input_dev->phys = gc->phys[idx]; + input_dev->id.bustype = BUS_PARPORT; + input_dev->id.vendor = 0x0001; + input_dev->id.product = pad_type; + input_dev->id.version = 0x0100; + input_dev->private = gc; + + input_dev->open = gc_open; + input_dev->close = gc_close; + + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + + for (i = 0; i < 2; i++) + input_set_abs_params(input_dev, ABS_X + i, -1, 1, 0, 0); + + gc->pads[0] |= gc_status_bit[idx]; + gc->pads[pad_type] |= gc_status_bit[idx]; + + switch (pad_type) { + + case GC_N64: + for (i = 0; i < 10; i++) + set_bit(gc_n64_btn[i], input_dev->keybit); + + for (i = 0; i < 2; i++) { + input_set_abs_params(input_dev, ABS_X + i, -127, 126, 0, 2); + input_set_abs_params(input_dev, ABS_HAT0X + i, -1, 1, 0, 0); + } + + break; + + case GC_SNES: + for (i = 4; i < 8; i++) + set_bit(gc_snes_btn[i], input_dev->keybit); + case GC_NES: + for (i = 0; i < 4; i++) + set_bit(gc_snes_btn[i], input_dev->keybit); + break; + + case GC_MULTI2: + set_bit(BTN_THUMB, input_dev->keybit); + case GC_MULTI: + set_bit(BTN_TRIGGER, input_dev->keybit); + break; + + case GC_PSX: + for (i = 0; i < 6; i++) + input_set_abs_params(input_dev, gc_psx_abs[i], 4, 252, 0, 2); + for (i = 0; i < 12; i++) + set_bit(gc_psx_btn[i], input_dev->keybit); + + break; + + case GC_DDR: + for (i = 0; i < 4; i++) + set_bit(gc_psx_ddr_btn[i], input_dev->keybit); + for (i = 0; i < 12; i++) + set_bit(gc_psx_btn[i], input_dev->keybit); + + break; } - init_MUTEX(&gc->sem); + return 0; +} - gc->pd = parport_register_device(pp, "gamecon", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL); +static struct gc __init *gc_probe(int parport, int *pads, int n_pads) +{ + struct gc *gc; + struct parport *pp; + struct pardevice *pd; + int i; + int err; - parport_put_port(pp); + pp = parport_find_number(parport); + if (!pp) { + printk(KERN_ERR "gamecon.c: no such parport\n"); + err = -EINVAL; + goto err_out; + } - if (!gc->pd) { + pd = parport_register_device(pp, "gamecon", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL); + if (!pd) { printk(KERN_ERR "gamecon.c: parport busy already - lp.o loaded?\n"); - kfree(gc); - return NULL; + err = -EBUSY; + goto err_put_pp; } - parport_claim(gc->pd); + gc = kzalloc(sizeof(struct gc), GFP_KERNEL); + if (!gc) { + printk(KERN_ERR "gamecon.c: Not enough memory\n"); + err = -ENOMEM; + goto err_unreg_pardev; + } + init_MUTEX(&gc->sem); + gc->pd = pd; init_timer(&gc->timer); gc->timer.data = (long) gc; gc->timer.function = gc_timer; - for (i = 0; i < nargs - 1; i++) { - - if (!config[i + 1]) + for (i = 0; i < n_pads; i++) { + if (!pads[i]) continue; - if (config[i + 1] < 1 || config[i + 1] > GC_MAX) { - printk(KERN_WARNING "gamecon.c: Pad type %d unknown\n", config[i + 1]); - continue; - } - - gc->dev[i].private = gc; - gc->dev[i].open = gc_open; - gc->dev[i].close = gc_close; + sprintf(gc->phys[i], "%s/input%d", gc->pd->port->name, i); + err = gc_setup_pad(gc, i, pads[i]); + if (err) + goto err_free_devs; - gc->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + input_register_device(gc->dev[i]); + } - for (j = 0; j < 2; j++) { - set_bit(ABS_X + j, gc->dev[i].absbit); - gc->dev[i].absmin[ABS_X + j] = -1; - gc->dev[i].absmax[ABS_X + j] = 1; - } + if (!gc->pads[0]) { + printk(KERN_ERR "gamecon.c: No valid devices specified\n"); + err = -EINVAL; + goto err_free_gc; + } - gc->pads[0] |= gc_status_bit[i]; - gc->pads[config[i + 1]] |= gc_status_bit[i]; + parport_put_port(pp); + return gc; - switch(config[i + 1]) { + err_free_devs: + while (--i >= 0) + input_unregister_device(gc->dev[i]); + err_free_gc: + kfree(gc); + err_unreg_pardev: + parport_unregister_device(pd); + err_put_pp: + parport_put_port(pp); + err_out: + return ERR_PTR(err); +} - case GC_N64: - for (j = 0; j < 10; j++) - set_bit(gc_n64_btn[j], gc->dev[i].keybit); - - for (j = 0; j < 2; j++) { - set_bit(ABS_X + j, gc->dev[i].absbit); - gc->dev[i].absmin[ABS_X + j] = -127; - gc->dev[i].absmax[ABS_X + j] = 126; - gc->dev[i].absflat[ABS_X + j] = 2; - set_bit(ABS_HAT0X + j, gc->dev[i].absbit); - gc->dev[i].absmin[ABS_HAT0X + j] = -1; - gc->dev[i].absmax[ABS_HAT0X + j] = 1; - } +static void __exit gc_remove(struct gc *gc) +{ + int i; - break; + for (i = 0; i < GC_MAX_DEVICES; i++) + if (gc->dev[i]) + input_unregister_device(gc->dev[i]); + parport_unregister_device(gc->pd); + kfree(gc); +} - case GC_SNES: - for (j = 4; j < 8; j++) - set_bit(gc_snes_btn[j], gc->dev[i].keybit); - case GC_NES: - for (j = 0; j < 4; j++) - set_bit(gc_snes_btn[j], gc->dev[i].keybit); - break; - - case GC_MULTI2: - set_bit(BTN_THUMB, gc->dev[i].keybit); - case GC_MULTI: - set_bit(BTN_TRIGGER, gc->dev[i].keybit); - break; - - case GC_PSX: - case GC_DDR: - if(config[i + 1] == GC_DDR) { - for (j = 0; j < 4; j++) - set_bit(gc_psx_ddr_btn[j], gc->dev[i].keybit); - } else { - for (j = 0; j < 6; j++) { - set_bit(gc_psx_abs[j], gc->dev[i].absbit); - gc->dev[i].absmin[gc_psx_abs[j]] = 4; - gc->dev[i].absmax[gc_psx_abs[j]] = 252; - gc->dev[i].absflat[gc_psx_abs[j]] = 2; - } - } +static int __init gc_init(void) +{ + int i; + int have_dev = 0; + int err = 0; - for (j = 0; j < 12; j++) - set_bit(gc_psx_btn[j], gc->dev[i].keybit); + for (i = 0; i < GC_MAX_PORTS; i++) { + if (gc[i].nargs == 0 || gc[i].args[0] < 0) + continue; - break; + if (gc[i].nargs < 2) { + printk(KERN_ERR "gamecon.c: at least one device must be specified\n"); + err = -EINVAL; + break; } - sprintf(gc->phys[i], "%s/input%d", gc->pd->port->name, i); + gc_base[i] = gc_probe(gc[i].args[0], gc[i].args + 1, gc[i].nargs - 1); + if (IS_ERR(gc_base[i])) { + err = PTR_ERR(gc_base[i]); + break; + } - gc->dev[i].name = gc_names[config[i + 1]]; - gc->dev[i].phys = gc->phys[i]; - gc->dev[i].id.bustype = BUS_PARPORT; - gc->dev[i].id.vendor = 0x0001; - gc->dev[i].id.product = config[i + 1]; - gc->dev[i].id.version = 0x0100; + have_dev = 1; } - parport_release(gc->pd); - - if (!gc->pads[0]) { - parport_unregister_device(gc->pd); - kfree(gc); - return NULL; + if (err) { + while (--i >= 0) + gc_remove(gc_base[i]); + return err; } - for (i = 0; i < 5; i++) - if (gc->pads[0] & gc_status_bit[i]) { - input_register_device(gc->dev + i); - printk(KERN_INFO "input: %s on %s\n", gc->dev[i].name, gc->pd->port->name); - } - - return gc; -} - -static int __init gc_init(void) -{ - gc_base[0] = gc_probe(gc, gc_nargs); - gc_base[1] = gc_probe(gc_2, gc_nargs_2); - gc_base[2] = gc_probe(gc_3, gc_nargs_3); - - if (gc_base[0] || gc_base[1] || gc_base[2]) - return 0; - - return -ENODEV; + return have_dev ? 0 : -ENODEV; } static void __exit gc_exit(void) { - int i, j; - - for (i = 0; i < 3; i++) - if (gc_base[i]) { - for (j = 0; j < 5; j++) - if (gc_base[i]->pads[0] & gc_status_bit[j]) - input_unregister_device(gc_base[i]->dev + j); - parport_unregister_device(gc_base[i]->pd); - } + int i; + + for (i = 0; i < GC_MAX_PORTS; i++) + if (gc_base[i]) + gc_remove(gc_base[i]); } module_init(gc_init); diff --git a/drivers/input/joystick/gf2k.c b/drivers/input/joystick/gf2k.c index 8e4f92b115e6..8a3ad455eb38 100644 --- a/drivers/input/joystick/gf2k.c +++ b/drivers/input/joystick/gf2k.c @@ -35,6 +35,7 @@ #include <linux/init.h> #include <linux/input.h> #include <linux/gameport.h> +#include <linux/jiffies.h> #define DRIVER_DESC "Genius Flight 2000 joystick driver" @@ -81,7 +82,7 @@ static short gf2k_seq_digital[] = { 590, 320, 860, 0 }; struct gf2k { struct gameport *gameport; - struct input_dev dev; + struct input_dev *dev; int reads; int bads; unsigned char id; @@ -175,7 +176,7 @@ static int gf2k_get_bits(unsigned char *buf, int pos, int num, int shift) static void gf2k_read(struct gf2k *gf2k, unsigned char *data) { - struct input_dev *dev = &gf2k->dev; + struct input_dev *dev = gf2k->dev; int i, t; for (i = 0; i < 4 && i < gf2k_axes[gf2k->id]; i++) @@ -239,13 +240,19 @@ static void gf2k_close(struct input_dev *dev) static int gf2k_connect(struct gameport *gameport, struct gameport_driver *drv) { struct gf2k *gf2k; + struct input_dev *input_dev; unsigned char data[GF2K_LENGTH]; int i, err; - if (!(gf2k = kzalloc(sizeof(struct gf2k), GFP_KERNEL))) - return -ENOMEM; + gf2k = kzalloc(sizeof(struct gf2k), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!gf2k || !input_dev) { + err = -ENOMEM; + goto fail1; + } gf2k->gameport = gameport; + gf2k->dev = input_dev; gameport_set_drvdata(gameport, gf2k); @@ -295,53 +302,52 @@ static int gf2k_connect(struct gameport *gameport, struct gameport_driver *drv) gf2k->length = gf2k_lens[gf2k->id]; - init_input_dev(&gf2k->dev); - - gf2k->dev.private = gf2k; - gf2k->dev.open = gf2k_open; - gf2k->dev.close = gf2k_close; - gf2k->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + input_dev->name = gf2k_names[gf2k->id]; + input_dev->phys = gf2k->phys; + input_dev->id.bustype = BUS_GAMEPORT; + input_dev->id.vendor = GAMEPORT_ID_VENDOR_GENIUS; + input_dev->id.product = gf2k->id; + input_dev->id.version = 0x0100; + input_dev->cdev.dev = &gameport->dev; + input_dev->private = gf2k; - gf2k->dev.name = gf2k_names[gf2k->id]; - gf2k->dev.phys = gf2k->phys; - gf2k->dev.id.bustype = BUS_GAMEPORT; - gf2k->dev.id.vendor = GAMEPORT_ID_VENDOR_GENIUS; - gf2k->dev.id.product = gf2k->id; - gf2k->dev.id.version = 0x0100; + input_dev->open = gf2k_open; + input_dev->close = gf2k_close; + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); for (i = 0; i < gf2k_axes[gf2k->id]; i++) - set_bit(gf2k_abs[i], gf2k->dev.absbit); + set_bit(gf2k_abs[i], input_dev->absbit); for (i = 0; i < gf2k_hats[gf2k->id]; i++) { - set_bit(ABS_HAT0X + i, gf2k->dev.absbit); - gf2k->dev.absmin[ABS_HAT0X + i] = -1; - gf2k->dev.absmax[ABS_HAT0X + i] = 1; + set_bit(ABS_HAT0X + i, input_dev->absbit); + input_dev->absmin[ABS_HAT0X + i] = -1; + input_dev->absmax[ABS_HAT0X + i] = 1; } for (i = 0; i < gf2k_joys[gf2k->id]; i++) - set_bit(gf2k_btn_joy[i], gf2k->dev.keybit); + set_bit(gf2k_btn_joy[i], input_dev->keybit); for (i = 0; i < gf2k_pads[gf2k->id]; i++) - set_bit(gf2k_btn_pad[i], gf2k->dev.keybit); + set_bit(gf2k_btn_pad[i], input_dev->keybit); gf2k_read_packet(gameport, gf2k->length, data); gf2k_read(gf2k, data); for (i = 0; i < gf2k_axes[gf2k->id]; i++) { - gf2k->dev.absmax[gf2k_abs[i]] = (i < 2) ? gf2k->dev.abs[gf2k_abs[i]] * 2 - 32 : - gf2k->dev.abs[gf2k_abs[0]] + gf2k->dev.abs[gf2k_abs[1]] - 32; - gf2k->dev.absmin[gf2k_abs[i]] = 32; - gf2k->dev.absfuzz[gf2k_abs[i]] = 8; - gf2k->dev.absflat[gf2k_abs[i]] = (i < 2) ? 24 : 0; + input_dev->absmax[gf2k_abs[i]] = (i < 2) ? input_dev->abs[gf2k_abs[i]] * 2 - 32 : + input_dev->abs[gf2k_abs[0]] + input_dev->abs[gf2k_abs[1]] - 32; + input_dev->absmin[gf2k_abs[i]] = 32; + input_dev->absfuzz[gf2k_abs[i]] = 8; + input_dev->absflat[gf2k_abs[i]] = (i < 2) ? 24 : 0; } - input_register_device(&gf2k->dev); - printk(KERN_INFO "input: %s on %s\n", gf2k_names[gf2k->id], gameport->phys); + input_register_device(gf2k->dev); return 0; -fail2: gameport_close(gameport); -fail1: gameport_set_drvdata(gameport, NULL); + fail2: gameport_close(gameport); + fail1: gameport_set_drvdata(gameport, NULL); + input_free_device(input_dev); kfree(gf2k); return err; } @@ -350,7 +356,7 @@ static void gf2k_disconnect(struct gameport *gameport) { struct gf2k *gf2k = gameport_get_drvdata(gameport); - input_unregister_device(&gf2k->dev); + input_unregister_device(gf2k->dev); gameport_close(gameport); gameport_set_drvdata(gameport, NULL); kfree(gf2k); diff --git a/drivers/input/joystick/grip.c b/drivers/input/joystick/grip.c index 9d3f910dd568..a936e7aedb10 100644 --- a/drivers/input/joystick/grip.c +++ b/drivers/input/joystick/grip.c @@ -34,6 +34,7 @@ #include <linux/slab.h> #include <linux/gameport.h> #include <linux/input.h> +#include <linux/jiffies.h> #define DRIVER_DESC "Gravis GrIP protocol joystick driver" @@ -55,7 +56,7 @@ MODULE_LICENSE("GPL"); struct grip { struct gameport *gameport; - struct input_dev dev[2]; + struct input_dev *dev[2]; unsigned char mode[2]; int reads; int bads; @@ -190,7 +191,7 @@ static void grip_poll(struct gameport *gameport) for (i = 0; i < 2; i++) { - dev = grip->dev + i; + dev = grip->dev[i]; grip->reads++; switch (grip->mode[i]) { @@ -297,6 +298,7 @@ static void grip_close(struct input_dev *dev) static int grip_connect(struct gameport *gameport, struct gameport_driver *drv) { struct grip *grip; + struct input_dev *input_dev; unsigned int data[GRIP_LENGTH_XT]; int i, j, t; int err; @@ -339,48 +341,56 @@ static int grip_connect(struct gameport *gameport, struct gameport_driver *drv) gameport_set_poll_handler(gameport, grip_poll); gameport_set_poll_interval(gameport, 20); - for (i = 0; i < 2; i++) - if (grip->mode[i]) { + for (i = 0; i < 2; i++) { + if (!grip->mode[i]) + continue; - sprintf(grip->phys[i], "%s/input%d", gameport->phys, i); + grip->dev[i] = input_dev = input_allocate_device(); + if (!input_dev) { + err = -ENOMEM; + goto fail3; + } - grip->dev[i].private = grip; + sprintf(grip->phys[i], "%s/input%d", gameport->phys, i); - grip->dev[i].open = grip_open; - grip->dev[i].close = grip_close; + input_dev->name = grip_name[grip->mode[i]]; + input_dev->phys = grip->phys[i]; + input_dev->id.bustype = BUS_GAMEPORT; + input_dev->id.vendor = GAMEPORT_ID_VENDOR_GRAVIS; + input_dev->id.product = grip->mode[i]; + input_dev->id.version = 0x0100; + input_dev->cdev.dev = &gameport->dev; + input_dev->private = grip; - grip->dev[i].name = grip_name[grip->mode[i]]; - grip->dev[i].phys = grip->phys[i]; - grip->dev[i].id.bustype = BUS_GAMEPORT; - grip->dev[i].id.vendor = GAMEPORT_ID_VENDOR_GRAVIS; - grip->dev[i].id.product = grip->mode[i]; - grip->dev[i].id.version = 0x0100; + input_dev->open = grip_open; + input_dev->close = grip_close; - grip->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - for (j = 0; (t = grip_abs[grip->mode[i]][j]) >= 0; j++) { + for (j = 0; (t = grip_abs[grip->mode[i]][j]) >= 0; j++) { - if (j < grip_cen[grip->mode[i]]) - input_set_abs_params(&grip->dev[i], t, 14, 52, 1, 2); - else if (j < grip_anx[grip->mode[i]]) - input_set_abs_params(&grip->dev[i], t, 3, 57, 1, 0); - else - input_set_abs_params(&grip->dev[i], t, -1, 1, 0, 0); - } + if (j < grip_cen[grip->mode[i]]) + input_set_abs_params(input_dev, t, 14, 52, 1, 2); + else if (j < grip_anx[grip->mode[i]]) + input_set_abs_params(input_dev, t, 3, 57, 1, 0); + else + input_set_abs_params(input_dev, t, -1, 1, 0, 0); + } - for (j = 0; (t = grip_btn[grip->mode[i]][j]) >= 0; j++) - if (t > 0) - set_bit(t, grip->dev[i].keybit); + for (j = 0; (t = grip_btn[grip->mode[i]][j]) >= 0; j++) + if (t > 0) + set_bit(t, input_dev->keybit); - printk(KERN_INFO "input: %s on %s\n", - grip_name[grip->mode[i]], gameport->phys); - input_register_device(grip->dev + i); - } + input_register_device(grip->dev[i]); + } return 0; -fail2: gameport_close(gameport); -fail1: gameport_set_drvdata(gameport, NULL); + fail3: for (i = 0; i < 2; i++) + if (grip->dev[i]) + input_unregister_device(grip->dev[i]); + fail2: gameport_close(gameport); + fail1: gameport_set_drvdata(gameport, NULL); kfree(grip); return err; } @@ -391,8 +401,8 @@ static void grip_disconnect(struct gameport *gameport) int i; for (i = 0; i < 2; i++) - if (grip->mode[i]) - input_unregister_device(grip->dev + i); + if (grip->dev[i]) + input_unregister_device(grip->dev[i]); gameport_close(gameport); gameport_set_drvdata(gameport, NULL); kfree(grip); diff --git a/drivers/input/joystick/grip_mp.c b/drivers/input/joystick/grip_mp.c index da17eee6f574..51a912222e85 100644 --- a/drivers/input/joystick/grip_mp.c +++ b/drivers/input/joystick/grip_mp.c @@ -19,6 +19,7 @@ #include <linux/input.h> #include <linux/delay.h> #include <linux/proc_fs.h> +#include <linux/jiffies.h> #define DRIVER_DESC "Gravis Grip Multiport driver" @@ -32,23 +33,37 @@ MODULE_LICENSE("GPL"); #define dbg(format, arg...) do {} while (0) #endif +#define GRIP_MAX_PORTS 4 /* * Grip multiport state */ +struct grip_port { + struct input_dev *dev; + int mode; + int registered; + + /* individual gamepad states */ + int buttons; + int xaxes; + int yaxes; + int dirty; /* has the state been updated? */ +}; + struct grip_mp { struct gameport *gameport; - struct input_dev dev[4]; - int mode[4]; - int registered[4]; + struct grip_port *port[GRIP_MAX_PORTS]; +// struct input_dev *dev[4]; +// int mode[4]; +// int registered[4]; int reads; int bads; /* individual gamepad states */ - int buttons[4]; - int xaxes[4]; - int yaxes[4]; - int dirty[4]; /* has the state been updated? */ +// int buttons[4]; +// int xaxes[4]; +// int yaxes[4]; +// int dirty[4]; /* has the state been updated? */ }; /* @@ -85,16 +100,16 @@ struct grip_mp { #define GRIP_MODE_GP 2 #define GRIP_MODE_C64 3 -static int grip_btn_gp[] = { BTN_TR, BTN_TL, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, -1 }; -static int grip_btn_c64[] = { BTN_JOYSTICK, -1 }; +static const int grip_btn_gp[] = { BTN_TR, BTN_TL, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, -1 }; +static const int grip_btn_c64[] = { BTN_JOYSTICK, -1 }; -static int grip_abs_gp[] = { ABS_X, ABS_Y, -1 }; -static int grip_abs_c64[] = { ABS_X, ABS_Y, -1 }; +static const int grip_abs_gp[] = { ABS_X, ABS_Y, -1 }; +static const int grip_abs_c64[] = { ABS_X, ABS_Y, -1 }; -static int *grip_abs[] = { NULL, NULL, grip_abs_gp, grip_abs_c64 }; -static int *grip_btn[] = { NULL, NULL, grip_btn_gp, grip_btn_c64 }; +static const int *grip_abs[] = { NULL, NULL, grip_abs_gp, grip_abs_c64 }; +static const int *grip_btn[] = { NULL, NULL, grip_btn_gp, grip_btn_c64 }; -static char *grip_name[] = { NULL, NULL, "Gravis Grip Pad", "Commodore 64 Joystick" }; +static const char *grip_name[] = { NULL, NULL, "Gravis Grip Pad", "Commodore 64 Joystick" }; static const int init_seq[] = { 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, @@ -104,9 +119,9 @@ static const int init_seq[] = { /* Maps multiport directional values to X,Y axis values (each axis encoded in 3 bits) */ -static int axis_map[] = { 5, 9, 1, 5, 6, 10, 2, 6, 4, 8, 0, 4, 5, 9, 1, 5 }; +static const int axis_map[] = { 5, 9, 1, 5, 6, 10, 2, 6, 4, 8, 0, 4, 5, 9, 1, 5 }; -static void register_slot(int i, struct grip_mp *grip); +static int register_slot(int i, struct grip_mp *grip); /* * Returns whether an odd or even number of bits are on in pkt. @@ -353,9 +368,10 @@ static int dig_mode_start(struct gameport *gameport, u32 *packet) static int get_and_decode_packet(struct grip_mp *grip, int flags) { + struct grip_port *port; u32 packet; int joytype = 0; - int slot = 0; + int slot; /* Get a packet and check for validity */ @@ -377,6 +393,8 @@ static int get_and_decode_packet(struct grip_mp *grip, int flags) if ((slot < 0) || (slot > 3)) return flags; + port = grip->port[slot]; + /* * Handle "reset" packets, which occur at startup, and when gamepads * are removed or plugged in. May contain configuration of a new gamepad. @@ -385,14 +403,14 @@ static int get_and_decode_packet(struct grip_mp *grip, int flags) joytype = (packet >> 16) & 0x1f; if (!joytype) { - if (grip->registered[slot]) { + if (port->registered) { printk(KERN_INFO "grip_mp: removing %s, slot %d\n", - grip_name[grip->mode[slot]], slot); - input_unregister_device(grip->dev + slot); - grip->registered[slot] = 0; + grip_name[port->mode], slot); + input_unregister_device(port->dev); + port->registered = 0; } dbg("Reset: grip multiport slot %d\n", slot); - grip->mode[slot] = GRIP_MODE_RESET; + port->mode = GRIP_MODE_RESET; flags |= IO_SLOT_CHANGE; return flags; } @@ -402,17 +420,17 @@ static int get_and_decode_packet(struct grip_mp *grip, int flags) if (joytype == 0x1f) { int dir = (packet >> 8) & 0xf; /* eight way directional value */ - grip->buttons[slot] = (~packet) & 0xff; - grip->yaxes[slot] = ((axis_map[dir] >> 2) & 3) - 1; - grip->xaxes[slot] = (axis_map[dir] & 3) - 1; - grip->dirty[slot] = 1; + port->buttons = (~packet) & 0xff; + port->yaxes = ((axis_map[dir] >> 2) & 3) - 1; + port->xaxes = (axis_map[dir] & 3) - 1; + port->dirty = 1; - if (grip->mode[slot] == GRIP_MODE_RESET) + if (port->mode == GRIP_MODE_RESET) flags |= IO_SLOT_CHANGE; - grip->mode[slot] = GRIP_MODE_GP; + port->mode = GRIP_MODE_GP; - if (!grip->registered[slot]) { + if (!port->registered) { dbg("New Grip pad in multiport slot %d.\n", slot); register_slot(slot, grip); } @@ -445,9 +463,9 @@ static int slots_valid(struct grip_mp *grip) return 0; for (slot = 0; slot < 4; slot++) { - if (grip->mode[slot] == GRIP_MODE_RESET) + if (grip->port[slot]->mode == GRIP_MODE_RESET) invalid = 1; - if (grip->mode[slot] != GRIP_MODE_NONE) + if (grip->port[slot]->mode != GRIP_MODE_NONE) active = 1; } @@ -484,7 +502,7 @@ static int multiport_init(struct grip_mp *grip) /* Get packets, store multiport state, and check state's validity */ for (tries = 0; tries < 4096; tries++) { - if ( slots_valid(grip) ) { + if (slots_valid(grip)) { initialized = 1; break; } @@ -499,24 +517,24 @@ static int multiport_init(struct grip_mp *grip) static void report_slot(struct grip_mp *grip, int slot) { - struct input_dev *dev = &(grip->dev[slot]); - int i, buttons = grip->buttons[slot]; + struct grip_port *port = grip->port[slot]; + int i; /* Store button states with linux input driver */ for (i = 0; i < 8; i++) - input_report_key(dev, grip_btn_gp[i], (buttons >> i) & 1); + input_report_key(port->dev, grip_btn_gp[i], (port->buttons >> i) & 1); /* Store axis states with linux driver */ - input_report_abs(dev, ABS_X, grip->xaxes[slot]); - input_report_abs(dev, ABS_Y, grip->yaxes[slot]); + input_report_abs(port->dev, ABS_X, port->xaxes); + input_report_abs(port->dev, ABS_Y, port->yaxes); /* Tell the receiver of the events to process them */ - input_sync(dev); + input_sync(port->dev); - grip->dirty[slot] = 0; + port->dirty = 0; } /* @@ -540,7 +558,7 @@ static void grip_poll(struct gameport *gameport) } for (i = 0; i < 4; i++) - if (grip->dirty[i]) + if (grip->port[i]->dirty) report_slot(grip, i); } @@ -571,35 +589,43 @@ static void grip_close(struct input_dev *dev) * Tell the linux input layer about a newly plugged-in gamepad. */ -static void register_slot(int slot, struct grip_mp *grip) +static int register_slot(int slot, struct grip_mp *grip) { + struct grip_port *port = grip->port[slot]; + struct input_dev *input_dev; int j, t; - grip->dev[slot].private = grip; - grip->dev[slot].open = grip_open; - grip->dev[slot].close = grip_close; - grip->dev[slot].name = grip_name[grip->mode[slot]]; - grip->dev[slot].id.bustype = BUS_GAMEPORT; - grip->dev[slot].id.vendor = GAMEPORT_ID_VENDOR_GRAVIS; - grip->dev[slot].id.product = 0x0100 + grip->mode[slot]; - grip->dev[slot].id.version = 0x0100; - grip->dev[slot].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + port->dev = input_dev = input_allocate_device(); + if (!input_dev) + return -ENOMEM; + + input_dev->name = grip_name[port->mode]; + input_dev->id.bustype = BUS_GAMEPORT; + input_dev->id.vendor = GAMEPORT_ID_VENDOR_GRAVIS; + input_dev->id.product = 0x0100 + port->mode; + input_dev->id.version = 0x0100; + input_dev->cdev.dev = &grip->gameport->dev; + input_dev->private = grip; + + input_dev->open = grip_open; + input_dev->close = grip_close; - for (j = 0; (t = grip_abs[grip->mode[slot]][j]) >= 0; j++) - input_set_abs_params(&grip->dev[slot], t, -1, 1, 0, 0); + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - for (j = 0; (t = grip_btn[grip->mode[slot]][j]) >= 0; j++) + for (j = 0; (t = grip_abs[port->mode][j]) >= 0; j++) + input_set_abs_params(input_dev, t, -1, 1, 0, 0); + + for (j = 0; (t = grip_btn[port->mode][j]) >= 0; j++) if (t > 0) - set_bit(t, grip->dev[slot].keybit); + set_bit(t, input_dev->keybit); - input_register_device(grip->dev + slot); - grip->registered[slot] = 1; + input_register_device(port->dev); + port->registered = 1; - if (grip->dirty[slot]) /* report initial state, if any */ + if (port->dirty) /* report initial state, if any */ report_slot(grip, slot); - printk(KERN_INFO "grip_mp: added %s, slot %d\n", - grip_name[grip->mode[slot]], slot); + return 0; } static int grip_connect(struct gameport *gameport, struct gameport_driver *drv) @@ -626,7 +652,7 @@ static int grip_connect(struct gameport *gameport, struct gameport_driver *drv) goto fail2; } - if (!grip->mode[0] && !grip->mode[1] && !grip->mode[2] && !grip->mode[3]) { + if (!grip->port[0]->mode && !grip->port[1]->mode && !grip->port[2]->mode && !grip->port[3]->mode) { /* nothing plugged in */ err = -ENODEV; goto fail2; @@ -646,8 +672,8 @@ static void grip_disconnect(struct gameport *gameport) int i; for (i = 0; i < 4; i++) - if (grip->registered[i]) - input_unregister_device(grip->dev + i); + if (grip->port[i]->registered) + input_unregister_device(grip->port[i]->dev); gameport_close(gameport); gameport_set_drvdata(gameport, NULL); kfree(grip); diff --git a/drivers/input/joystick/guillemot.c b/drivers/input/joystick/guillemot.c index 6a70ec429f06..6e2c721c26ba 100644 --- a/drivers/input/joystick/guillemot.c +++ b/drivers/input/joystick/guillemot.c @@ -35,6 +35,7 @@ #include <linux/init.h> #include <linux/gameport.h> #include <linux/input.h> +#include <linux/jiffies.h> #define DRIVER_DESC "Guillemot Digital joystick driver" @@ -67,7 +68,7 @@ struct guillemot_type { struct guillemot { struct gameport *gameport; - struct input_dev dev; + struct input_dev *dev; int bads; int reads; struct guillemot_type *type; @@ -123,7 +124,7 @@ static int guillemot_read_packet(struct gameport *gameport, u8 *data) static void guillemot_poll(struct gameport *gameport) { struct guillemot *guillemot = gameport_get_drvdata(gameport); - struct input_dev *dev = &guillemot->dev; + struct input_dev *dev = guillemot->dev; u8 data[GUILLEMOT_MAX_LENGTH]; int i; @@ -179,14 +180,20 @@ static void guillemot_close(struct input_dev *dev) static int guillemot_connect(struct gameport *gameport, struct gameport_driver *drv) { struct guillemot *guillemot; + struct input_dev *input_dev; u8 data[GUILLEMOT_MAX_LENGTH]; int i, t; int err; - if (!(guillemot = kzalloc(sizeof(struct guillemot), GFP_KERNEL))) - return -ENOMEM; + guillemot = kzalloc(sizeof(struct guillemot), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!guillemot || !input_dev) { + err = -ENOMEM; + goto fail1; + } guillemot->gameport = gameport; + guillemot->dev = input_dev; gameport_set_drvdata(gameport, guillemot); @@ -216,41 +223,40 @@ static int guillemot_connect(struct gameport *gameport, struct gameport_driver * gameport_set_poll_interval(gameport, 20); sprintf(guillemot->phys, "%s/input0", gameport->phys); - guillemot->type = guillemot_type + i; - guillemot->dev.private = guillemot; - guillemot->dev.open = guillemot_open; - guillemot->dev.close = guillemot_close; + input_dev->name = guillemot_type[i].name; + input_dev->phys = guillemot->phys; + input_dev->id.bustype = BUS_GAMEPORT; + input_dev->id.vendor = GAMEPORT_ID_VENDOR_GUILLEMOT; + input_dev->id.product = guillemot_type[i].id; + input_dev->id.version = (int)data[14] << 8 | data[15]; + input_dev->cdev.dev = &gameport->dev; + input_dev->private = guillemot; - guillemot->dev.name = guillemot_type[i].name; - guillemot->dev.phys = guillemot->phys; - guillemot->dev.id.bustype = BUS_GAMEPORT; - guillemot->dev.id.vendor = GAMEPORT_ID_VENDOR_GUILLEMOT; - guillemot->dev.id.product = guillemot_type[i].id; - guillemot->dev.id.version = (int)data[14] << 8 | data[15]; + input_dev->open = guillemot_open; + input_dev->close = guillemot_close; - guillemot->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); for (i = 0; (t = guillemot->type->abs[i]) >= 0; i++) - input_set_abs_params(&guillemot->dev, t, 0, 255, 0, 0); + input_set_abs_params(input_dev, t, 0, 255, 0, 0); if (guillemot->type->hat) { - input_set_abs_params(&guillemot->dev, ABS_HAT0X, -1, 1, 0, 0); - input_set_abs_params(&guillemot->dev, ABS_HAT0Y, -1, 1, 0, 0); + input_set_abs_params(input_dev, ABS_HAT0X, -1, 1, 0, 0); + input_set_abs_params(input_dev, ABS_HAT0Y, -1, 1, 0, 0); } for (i = 0; (t = guillemot->type->btn[i]) >= 0; i++) - set_bit(t, guillemot->dev.keybit); + set_bit(t, input_dev->keybit); - input_register_device(&guillemot->dev); - printk(KERN_INFO "input: %s ver %d.%02d on %s\n", - guillemot->type->name, data[14], data[15], gameport->phys); + input_register_device(guillemot->dev); return 0; fail2: gameport_close(gameport); fail1: gameport_set_drvdata(gameport, NULL); + input_free_device(input_dev); kfree(guillemot); return err; } @@ -260,7 +266,7 @@ static void guillemot_disconnect(struct gameport *gameport) struct guillemot *guillemot = gameport_get_drvdata(gameport); printk(KERN_INFO "guillemot.c: Failed %d reads out of %d on %s\n", guillemot->reads, guillemot->bads, guillemot->phys); - input_unregister_device(&guillemot->dev); + input_unregister_device(guillemot->dev); gameport_close(gameport); kfree(guillemot); } diff --git a/drivers/input/joystick/iforce/iforce-main.c b/drivers/input/joystick/iforce/iforce-main.c index e31b7b93fde2..64b9c31c47fc 100644 --- a/drivers/input/joystick/iforce/iforce-main.c +++ b/drivers/input/joystick/iforce/iforce-main.c @@ -144,7 +144,7 @@ static int iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect) int is_update; /* Check this effect type is supported by this device */ - if (!test_bit(effect->type, iforce->dev.ffbit)) + if (!test_bit(effect->type, iforce->dev->ffbit)) return -EINVAL; /* @@ -152,30 +152,31 @@ static int iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect) */ if (effect->id == -1) { - for (id=0; id < FF_EFFECTS_MAX; ++id) - if (!test_and_set_bit(FF_CORE_IS_USED, iforce->core_effects[id].flags)) break; + for (id = 0; id < FF_EFFECTS_MAX; ++id) + if (!test_and_set_bit(FF_CORE_IS_USED, iforce->core_effects[id].flags)) + break; - if ( id == FF_EFFECTS_MAX || id >= iforce->dev.ff_effects_max) + if (id == FF_EFFECTS_MAX || id >= iforce->dev->ff_effects_max) return -ENOMEM; effect->id = id; iforce->core_effects[id].owner = current->pid; - iforce->core_effects[id].flags[0] = (1<<FF_CORE_IS_USED); /* Only IS_USED bit must be set */ + iforce->core_effects[id].flags[0] = (1 << FF_CORE_IS_USED); /* Only IS_USED bit must be set */ is_update = FALSE; } else { /* We want to update an effect */ - if (!CHECK_OWNERSHIP(effect->id, iforce)) return -EACCES; + if (!CHECK_OWNERSHIP(effect->id, iforce)) + return -EACCES; /* Parameter type cannot be updated */ if (effect->type != iforce->core_effects[effect->id].effect.type) return -EINVAL; /* Check the effect is not already being updated */ - if (test_bit(FF_CORE_UPDATE, iforce->core_effects[effect->id].flags)) { + if (test_bit(FF_CORE_UPDATE, iforce->core_effects[effect->id].flags)) return -EAGAIN; - } is_update = TRUE; } @@ -339,15 +340,19 @@ void iforce_delete_device(struct iforce *iforce) int iforce_init_device(struct iforce *iforce) { + struct input_dev *input_dev; unsigned char c[] = "CEOV"; int i; + input_dev = input_allocate_device(); + if (input_dev) + return -ENOMEM; + init_waitqueue_head(&iforce->wait); spin_lock_init(&iforce->xmit_lock); init_MUTEX(&iforce->mem_mutex); iforce->xmit.buf = iforce->xmit_data; - - iforce->dev.ff_effects_max = 10; + iforce->dev = input_dev; /* * Input device fields. @@ -356,26 +361,27 @@ int iforce_init_device(struct iforce *iforce) switch (iforce->bus) { #ifdef CONFIG_JOYSTICK_IFORCE_USB case IFORCE_USB: - iforce->dev.id.bustype = BUS_USB; - iforce->dev.dev = &iforce->usbdev->dev; + input_dev->id.bustype = BUS_USB; + input_dev->cdev.dev = &iforce->usbdev->dev; break; #endif #ifdef CONFIG_JOYSTICK_IFORCE_232 case IFORCE_232: - iforce->dev.id.bustype = BUS_RS232; - iforce->dev.dev = &iforce->serio->dev; + input_dev->id.bustype = BUS_RS232; + input_dev->cdev.dev = &iforce->serio->dev; break; #endif } - iforce->dev.private = iforce; - iforce->dev.name = "Unknown I-Force device"; - iforce->dev.open = iforce_open; - iforce->dev.close = iforce_release; - iforce->dev.flush = iforce_flush; - iforce->dev.event = iforce_input_event; - iforce->dev.upload_effect = iforce_upload_effect; - iforce->dev.erase_effect = iforce_erase_effect; + input_dev->private = iforce; + input_dev->name = "Unknown I-Force device"; + input_dev->open = iforce_open; + input_dev->close = iforce_release; + input_dev->flush = iforce_flush; + input_dev->event = iforce_input_event; + input_dev->upload_effect = iforce_upload_effect; + input_dev->erase_effect = iforce_erase_effect; + input_dev->ff_effects_max = 10; /* * On-device memory allocation. @@ -399,7 +405,8 @@ int iforce_init_device(struct iforce *iforce) if (i == 20) { /* 5 seconds */ printk(KERN_ERR "iforce-main.c: Timeout waiting for response from device.\n"); - return -1; + input_free_device(input_dev); + return -ENODEV; } /* @@ -407,12 +414,12 @@ int iforce_init_device(struct iforce *iforce) */ if (!iforce_get_id_packet(iforce, "M")) - iforce->dev.id.vendor = (iforce->edata[2] << 8) | iforce->edata[1]; + input_dev->id.vendor = (iforce->edata[2] << 8) | iforce->edata[1]; else printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet M\n"); if (!iforce_get_id_packet(iforce, "P")) - iforce->dev.id.product = (iforce->edata[2] << 8) | iforce->edata[1]; + input_dev->id.product = (iforce->edata[2] << 8) | iforce->edata[1]; else printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet P\n"); @@ -422,15 +429,15 @@ int iforce_init_device(struct iforce *iforce) printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet B\n"); if (!iforce_get_id_packet(iforce, "N")) - iforce->dev.ff_effects_max = iforce->edata[1]; + iforce->dev->ff_effects_max = iforce->edata[1]; else printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet N\n"); /* Check if the device can store more effects than the driver can really handle */ - if (iforce->dev.ff_effects_max > FF_EFFECTS_MAX) { + if (iforce->dev->ff_effects_max > FF_EFFECTS_MAX) { printk(KERN_WARNING "input??: Device can handle %d effects, but N_EFFECTS_MAX is set to %d in iforce.h\n", - iforce->dev.ff_effects_max, FF_EFFECTS_MAX); - iforce->dev.ff_effects_max = FF_EFFECTS_MAX; + iforce->dev->ff_effects_max, FF_EFFECTS_MAX); + iforce->dev->ff_effects_max = FF_EFFECTS_MAX; } /* @@ -453,29 +460,28 @@ int iforce_init_device(struct iforce *iforce) */ for (i = 0; iforce_device[i].idvendor; i++) - if (iforce_device[i].idvendor == iforce->dev.id.vendor && - iforce_device[i].idproduct == iforce->dev.id.product) + if (iforce_device[i].idvendor == input_dev->id.vendor && + iforce_device[i].idproduct == input_dev->id.product) break; iforce->type = iforce_device + i; - iforce->dev.name = iforce->type->name; + input_dev->name = iforce->type->name; /* * Set input device bitfields and ranges. */ - iforce->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_FF) | BIT(EV_FF_STATUS); + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_FF) | BIT(EV_FF_STATUS); for (i = 0; iforce->type->btn[i] >= 0; i++) { signed short t = iforce->type->btn[i]; - set_bit(t, iforce->dev.keybit); + set_bit(t, input_dev->keybit); } - set_bit(BTN_DEAD, iforce->dev.keybit); + set_bit(BTN_DEAD, input_dev->keybit); for (i = 0; iforce->type->abs[i] >= 0; i++) { signed short t = iforce->type->abs[i]; - set_bit(t, iforce->dev.absbit); switch (t) { @@ -483,52 +489,42 @@ int iforce_init_device(struct iforce *iforce) case ABS_Y: case ABS_WHEEL: - iforce->dev.absmax[t] = 1920; - iforce->dev.absmin[t] = -1920; - iforce->dev.absflat[t] = 128; - iforce->dev.absfuzz[t] = 16; - - set_bit(t, iforce->dev.ffbit); + input_set_abs_params(input_dev, t, -1920, 1920, 16, 128); + set_bit(t, input_dev->ffbit); break; case ABS_THROTTLE: case ABS_GAS: case ABS_BRAKE: - iforce->dev.absmax[t] = 255; - iforce->dev.absmin[t] = 0; + input_set_abs_params(input_dev, t, 0, 255, 0, 0); break; case ABS_RUDDER: - iforce->dev.absmax[t] = 127; - iforce->dev.absmin[t] = -128; + input_set_abs_params(input_dev, t, -128, 127, 0, 0); break; case ABS_HAT0X: case ABS_HAT0Y: case ABS_HAT1X: case ABS_HAT1Y: - iforce->dev.absmax[t] = 1; - iforce->dev.absmin[t] = -1; + + input_set_abs_params(input_dev, t, -1, 1, 0, 0); break; } } for (i = 0; iforce->type->ff[i] >= 0; i++) - set_bit(iforce->type->ff[i], iforce->dev.ffbit); + set_bit(iforce->type->ff[i], input_dev->ffbit); /* * Register input device. */ - input_register_device(&iforce->dev); - - printk(KERN_DEBUG "iforce->dev.open = %p\n", iforce->dev.open); + input_register_device(iforce->dev); - printk(KERN_INFO "input: %s [%d effects, %ld bytes memory]\n", - iforce->dev.name, iforce->dev.ff_effects_max, - iforce->device_memory.end); + printk(KERN_DEBUG "iforce->dev->open = %p\n", iforce->dev->open); return 0; } diff --git a/drivers/input/joystick/iforce/iforce-packets.c b/drivers/input/joystick/iforce/iforce-packets.c index e5a31e55d3e2..4a2629243e19 100644 --- a/drivers/input/joystick/iforce/iforce-packets.c +++ b/drivers/input/joystick/iforce/iforce-packets.c @@ -139,7 +139,8 @@ printk(KERN_DEBUG "iforce-packets.c: control_playback %d %d\n", id, value); static int mark_core_as_ready(struct iforce *iforce, unsigned short addr) { int i; - for (i=0; i<iforce->dev.ff_effects_max; ++i) { + + for (i = 0; i < iforce->dev->ff_effects_max; ++i) { if (test_bit(FF_CORE_IS_USED, iforce->core_effects[i].flags) && (iforce->core_effects[i].mod1_chunk.start == addr || iforce->core_effects[i].mod2_chunk.start == addr)) { @@ -153,7 +154,7 @@ static int mark_core_as_ready(struct iforce *iforce, unsigned short addr) void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data, struct pt_regs *regs) { - struct input_dev *dev = &iforce->dev; + struct input_dev *dev = iforce->dev; int i; static int being_used = 0; diff --git a/drivers/input/joystick/iforce/iforce-serio.c b/drivers/input/joystick/iforce/iforce-serio.c index 11f51905cba7..64a78c515484 100644 --- a/drivers/input/joystick/iforce/iforce-serio.c +++ b/drivers/input/joystick/iforce/iforce-serio.c @@ -131,11 +131,10 @@ static int iforce_serio_connect(struct serio *serio, struct serio_driver *drv) struct iforce *iforce; int err; - if (!(iforce = kmalloc(sizeof(struct iforce), GFP_KERNEL))) + iforce = kzalloc(sizeof(struct iforce), GFP_KERNEL); + if (!iforce) return -ENOMEM; - memset(iforce, 0, sizeof(struct iforce)); - iforce->bus = IFORCE_232; iforce->serio = serio; @@ -148,7 +147,8 @@ static int iforce_serio_connect(struct serio *serio, struct serio_driver *drv) return err; } - if (iforce_init_device(iforce)) { + err = iforce_init_device(iforce); + if (err) { serio_close(serio); serio_set_drvdata(serio, NULL); kfree(iforce); @@ -162,7 +162,7 @@ static void iforce_serio_disconnect(struct serio *serio) { struct iforce *iforce = serio_get_drvdata(serio); - input_unregister_device(&iforce->dev); + input_unregister_device(iforce->dev); serio_close(serio); serio_set_drvdata(serio, NULL); kfree(iforce); diff --git a/drivers/input/joystick/iforce/iforce-usb.c b/drivers/input/joystick/iforce/iforce-usb.c index 58600f91eff5..64b4a3080985 100644 --- a/drivers/input/joystick/iforce/iforce-usb.c +++ b/drivers/input/joystick/iforce/iforce-usb.c @@ -135,28 +135,24 @@ static int iforce_usb_probe(struct usb_interface *intf, struct usb_host_interface *interface; struct usb_endpoint_descriptor *epirq, *epout; struct iforce *iforce; + int err = -ENOMEM; interface = intf->cur_altsetting; epirq = &interface->endpoint[0].desc; epout = &interface->endpoint[1].desc; - if (!(iforce = kmalloc(sizeof(struct iforce) + 32, GFP_KERNEL))) + if (!(iforce = kzalloc(sizeof(struct iforce) + 32, GFP_KERNEL))) goto fail; - memset(iforce, 0, sizeof(struct iforce)); - - if (!(iforce->irq = usb_alloc_urb(0, GFP_KERNEL))) { + if (!(iforce->irq = usb_alloc_urb(0, GFP_KERNEL))) goto fail; - } - if (!(iforce->out = usb_alloc_urb(0, GFP_KERNEL))) { + if (!(iforce->out = usb_alloc_urb(0, GFP_KERNEL))) goto fail; - } - if (!(iforce->ctrl = usb_alloc_urb(0, GFP_KERNEL))) { + if (!(iforce->ctrl = usb_alloc_urb(0, GFP_KERNEL))) goto fail; - } iforce->bus = IFORCE_USB; iforce->usbdev = dev; @@ -174,7 +170,9 @@ static int iforce_usb_probe(struct usb_interface *intf, usb_fill_control_urb(iforce->ctrl, dev, usb_rcvctrlpipe(dev, 0), (void*) &iforce->cr, iforce->edata, 16, iforce_usb_ctrl, iforce); - if (iforce_init_device(iforce)) goto fail; + err = iforce_init_device(iforce); + if (err) + goto fail; usb_set_intfdata(intf, iforce); return 0; @@ -187,7 +185,7 @@ fail: kfree(iforce); } - return -ENODEV; + return err; } /* Called by iforce_delete() */ @@ -211,7 +209,7 @@ static void iforce_usb_disconnect(struct usb_interface *intf) usb_set_intfdata(intf, NULL); if (iforce) { iforce->usbdev = NULL; - input_unregister_device(&iforce->dev); + input_unregister_device(iforce->dev); if (!open) { iforce_delete_device(iforce); diff --git a/drivers/input/joystick/iforce/iforce.h b/drivers/input/joystick/iforce/iforce.h index bce247bc300b..146f406b8f8a 100644 --- a/drivers/input/joystick/iforce/iforce.h +++ b/drivers/input/joystick/iforce/iforce.h @@ -117,7 +117,7 @@ struct iforce_device { }; struct iforce { - struct input_dev dev; /* Input device interface */ + struct input_dev *dev; /* Input device interface */ struct iforce_device *type; int bus; diff --git a/drivers/input/joystick/interact.c b/drivers/input/joystick/interact.c index d7b3472bd686..c4ed01758226 100644 --- a/drivers/input/joystick/interact.c +++ b/drivers/input/joystick/interact.c @@ -38,6 +38,7 @@ #include <linux/init.h> #include <linux/gameport.h> #include <linux/input.h> +#include <linux/jiffies.h> #define DRIVER_DESC "InterAct digital joystick driver" @@ -54,7 +55,7 @@ MODULE_LICENSE("GPL"); struct interact { struct gameport *gameport; - struct input_dev dev; + struct input_dev *dev; int bads; int reads; unsigned char type; @@ -130,7 +131,7 @@ static int interact_read_packet(struct gameport *gameport, int length, u32 *data static void interact_poll(struct gameport *gameport) { struct interact *interact = gameport_get_drvdata(gameport); - struct input_dev *dev = &interact->dev; + struct input_dev *dev = interact->dev; u32 data[3]; int i; @@ -208,14 +209,20 @@ static void interact_close(struct input_dev *dev) static int interact_connect(struct gameport *gameport, struct gameport_driver *drv) { struct interact *interact; + struct input_dev *input_dev; __u32 data[3]; int i, t; int err; - if (!(interact = kzalloc(sizeof(struct interact), GFP_KERNEL))) - return -ENOMEM; + interact = kzalloc(sizeof(struct interact), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!interact || !input_dev) { + err = -ENOMEM; + goto fail1; + } interact->gameport = gameport; + interact->dev = input_dev; gameport_set_drvdata(gameport, interact); @@ -249,41 +256,40 @@ static int interact_connect(struct gameport *gameport, struct gameport_driver *d interact->type = i; interact->length = interact_type[i].length; - interact->dev.private = interact; - interact->dev.open = interact_open; - interact->dev.close = interact_close; + input_dev->name = interact_type[i].name; + input_dev->phys = interact->phys; + input_dev->id.bustype = BUS_GAMEPORT; + input_dev->id.vendor = GAMEPORT_ID_VENDOR_INTERACT; + input_dev->id.product = interact_type[i].id; + input_dev->id.version = 0x0100; + input_dev->private = interact; - interact->dev.name = interact_type[i].name; - interact->dev.phys = interact->phys; - interact->dev.id.bustype = BUS_GAMEPORT; - interact->dev.id.vendor = GAMEPORT_ID_VENDOR_INTERACT; - interact->dev.id.product = interact_type[i].id; - interact->dev.id.version = 0x0100; + input_dev->open = interact_open; + input_dev->close = interact_close; - interact->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); for (i = 0; (t = interact_type[interact->type].abs[i]) >= 0; i++) { - set_bit(t, interact->dev.absbit); + set_bit(t, input_dev->absbit); if (i < interact_type[interact->type].b8) { - interact->dev.absmin[t] = 0; - interact->dev.absmax[t] = 255; + input_dev->absmin[t] = 0; + input_dev->absmax[t] = 255; } else { - interact->dev.absmin[t] = -1; - interact->dev.absmax[t] = 1; + input_dev->absmin[t] = -1; + input_dev->absmax[t] = 1; } } for (i = 0; (t = interact_type[interact->type].btn[i]) >= 0; i++) - set_bit(t, interact->dev.keybit); + set_bit(t, input_dev->keybit); - input_register_device(&interact->dev); - printk(KERN_INFO "input: %s on %s\n", - interact_type[interact->type].name, gameport->phys); + input_register_device(interact->dev); return 0; fail2: gameport_close(gameport); fail1: gameport_set_drvdata(gameport, NULL); + input_free_device(input_dev); kfree(interact); return err; } @@ -292,7 +298,7 @@ static void interact_disconnect(struct gameport *gameport) { struct interact *interact = gameport_get_drvdata(gameport); - input_unregister_device(&interact->dev); + input_unregister_device(interact->dev); gameport_close(gameport); gameport_set_drvdata(gameport, NULL); kfree(interact); diff --git a/drivers/input/joystick/joydump.c b/drivers/input/joystick/joydump.c index 4234ccaf9146..88ec5a918f2e 100644 --- a/drivers/input/joystick/joydump.c +++ b/drivers/input/joystick/joydump.c @@ -34,6 +34,7 @@ #include <linux/kernel.h> #include <linux/delay.h> #include <linux/init.h> +#include <linux/slab.h> #define DRIVER_DESC "Gameport data dumper module" diff --git a/drivers/input/joystick/magellan.c b/drivers/input/joystick/magellan.c index 1ba503627242..ca3cc2319d6a 100644 --- a/drivers/input/joystick/magellan.c +++ b/drivers/input/joystick/magellan.c @@ -49,14 +49,13 @@ MODULE_LICENSE("GPL"); static int magellan_buttons[] = { BTN_0, BTN_1, BTN_2, BTN_3, BTN_4, BTN_5, BTN_6, BTN_7, BTN_8 }; static int magellan_axes[] = { ABS_X, ABS_Y, ABS_Z, ABS_RX, ABS_RY, ABS_RZ }; -static char *magellan_name = "LogiCad3D Magellan / SpaceMouse"; /* * Per-Magellan data. */ struct magellan { - struct input_dev dev; + struct input_dev *dev; int idx; unsigned char data[MAGELLAN_MAX_LENGTH]; char phys[32]; @@ -85,7 +84,7 @@ static int magellan_crunch_nibbles(unsigned char *data, int count) static void magellan_process_packet(struct magellan* magellan, struct pt_regs *regs) { - struct input_dev *dev = &magellan->dev; + struct input_dev *dev = magellan->dev; unsigned char *data = magellan->data; int i, t; @@ -138,9 +137,9 @@ static void magellan_disconnect(struct serio *serio) { struct magellan* magellan = serio_get_drvdata(serio); - input_unregister_device(&magellan->dev); serio_close(serio); serio_set_drvdata(serio, NULL); + input_unregister_device(magellan->dev); kfree(magellan); } @@ -153,52 +152,48 @@ static void magellan_disconnect(struct serio *serio) static int magellan_connect(struct serio *serio, struct serio_driver *drv) { struct magellan *magellan; - int i, t; - int err; - - if (!(magellan = kmalloc(sizeof(struct magellan), GFP_KERNEL))) - return -ENOMEM; + struct input_dev *input_dev; + int err = -ENOMEM; + int i; - memset(magellan, 0, sizeof(struct magellan)); + magellan = kzalloc(sizeof(struct magellan), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!magellan || !input_dev) + goto fail; - magellan->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + magellan->dev = input_dev; + sprintf(magellan->phys, "%s/input0", serio->phys); - for (i = 0; i < 9; i++) - set_bit(magellan_buttons[i], magellan->dev.keybit); + input_dev->name = "LogiCad3D Magellan / SpaceMouse"; + input_dev->phys = magellan->phys; + input_dev->id.bustype = BUS_RS232; + input_dev->id.vendor = SERIO_MAGELLAN; + input_dev->id.product = 0x0001; + input_dev->id.version = 0x0100; + input_dev->cdev.dev = &serio->dev; + input_dev->private = magellan; - for (i = 0; i < 6; i++) { - t = magellan_axes[i]; - set_bit(t, magellan->dev.absbit); - magellan->dev.absmin[t] = -360; - magellan->dev.absmax[t] = 360; - } + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - sprintf(magellan->phys, "%s/input0", serio->phys); + for (i = 0; i < 9; i++) + set_bit(magellan_buttons[i], input_dev->keybit); - init_input_dev(&magellan->dev); - magellan->dev.private = magellan; - magellan->dev.name = magellan_name; - magellan->dev.phys = magellan->phys; - magellan->dev.id.bustype = BUS_RS232; - magellan->dev.id.vendor = SERIO_MAGELLAN; - magellan->dev.id.product = 0x0001; - magellan->dev.id.version = 0x0100; - magellan->dev.dev = &serio->dev; + for (i = 0; i < 6; i++) + input_set_abs_params(input_dev, magellan_axes[i], -360, 360, 0, 0); serio_set_drvdata(serio, magellan); err = serio_open(serio, drv); - if (err) { - serio_set_drvdata(serio, NULL); - kfree(magellan); - return err; - } - - input_register_device(&magellan->dev); - - printk(KERN_INFO "input: %s on %s\n", magellan_name, serio->phys); + if (err) + goto fail; + input_register_device(magellan->dev); return 0; + + fail: serio_set_drvdata(serio, NULL); + input_free_device(input_dev); + kfree(magellan); + return err; } /* diff --git a/drivers/input/joystick/sidewinder.c b/drivers/input/joystick/sidewinder.c index 9e0353721a35..78dd163cd702 100644 --- a/drivers/input/joystick/sidewinder.c +++ b/drivers/input/joystick/sidewinder.c @@ -33,6 +33,7 @@ #include <linux/init.h> #include <linux/input.h> #include <linux/gameport.h> +#include <linux/jiffies.h> #define DRIVER_DESC "Microsoft SideWinder joystick family driver" @@ -113,7 +114,7 @@ static struct { struct sw { struct gameport *gameport; - struct input_dev dev[4]; + struct input_dev *dev[4]; char name[64]; char phys[4][32]; int length; @@ -301,7 +302,7 @@ static int sw_check(__u64 t) static int sw_parse(unsigned char *buf, struct sw *sw) { int hat, i, j; - struct input_dev *dev = sw->dev; + struct input_dev *dev; switch (sw->type) { @@ -310,6 +311,8 @@ static int sw_parse(unsigned char *buf, struct sw *sw) if (sw_check(GB(0,64)) || (hat = (GB(6,1) << 3) | GB(60,3)) > 8) return -1; + dev = sw->dev[0]; + input_report_abs(dev, ABS_X, (GB( 3,3) << 7) | GB(16,7)); input_report_abs(dev, ABS_Y, (GB( 0,3) << 7) | GB(24,7)); input_report_abs(dev, ABS_RZ, (GB(35,2) << 7) | GB(40,7)); @@ -335,13 +338,13 @@ static int sw_parse(unsigned char *buf, struct sw *sw) if (sw_parity(GB(i*15,15))) return -1; - input_report_abs(dev + i, ABS_X, GB(i*15+3,1) - GB(i*15+2,1)); - input_report_abs(dev + i, ABS_Y, GB(i*15+0,1) - GB(i*15+1,1)); + input_report_abs(sw->dev[i], ABS_X, GB(i*15+3,1) - GB(i*15+2,1)); + input_report_abs(sw->dev[i], ABS_Y, GB(i*15+0,1) - GB(i*15+1,1)); for (j = 0; j < 10; j++) - input_report_key(dev + i, sw_btn[SW_ID_GP][j], !GB(i*15+j+4,1)); + input_report_key(sw->dev[i], sw_btn[SW_ID_GP][j], !GB(i*15+j+4,1)); - input_sync(dev + i); + input_sync(sw->dev[i]); } return 0; @@ -352,6 +355,7 @@ static int sw_parse(unsigned char *buf, struct sw *sw) if (!sw_parity(GB(0,48)) || (hat = GB(42,4)) > 8) return -1; + dev = sw->dev[0]; input_report_abs(dev, ABS_X, GB( 9,10)); input_report_abs(dev, ABS_Y, GB(19,10)); input_report_abs(dev, ABS_RZ, GB(36, 6)); @@ -372,6 +376,7 @@ static int sw_parse(unsigned char *buf, struct sw *sw) if (!sw_parity(GB(0,43)) || (hat = GB(28,4)) > 8) return -1; + dev = sw->dev[0]; input_report_abs(dev, ABS_X, GB( 0,10)); input_report_abs(dev, ABS_Y, GB(16,10)); input_report_abs(dev, ABS_THROTTLE, GB(32, 6)); @@ -396,6 +401,7 @@ static int sw_parse(unsigned char *buf, struct sw *sw) if (!sw_parity(GB(0,33))) return -1; + dev = sw->dev[0]; input_report_abs(dev, ABS_RX, GB( 0,10)); input_report_abs(dev, ABS_RUDDER, GB(10, 6)); input_report_abs(dev, ABS_THROTTLE, GB(16, 6)); @@ -581,6 +587,7 @@ static int sw_guess_mode(unsigned char *buf, int len) static int sw_connect(struct gameport *gameport, struct gameport_driver *drv) { struct sw *sw; + struct input_dev *input_dev; int i, j, k, l; int err; unsigned char *buf = NULL; /* [SW_LENGTH] */ @@ -729,42 +736,50 @@ static int sw_connect(struct gameport *gameport, struct gameport_driver *drv) sprintf(sw->name, "Microsoft SideWinder %s", sw_name[sw->type]); sprintf(sw->phys[i], "%s/input%d", gameport->phys, i); - sw->dev[i].private = sw; + input_dev = input_allocate_device(); + if (!input_dev) { + err = -ENOMEM; + goto fail3; + } - sw->dev[i].open = sw_open; - sw->dev[i].close = sw_close; + input_dev->name = sw->name; + input_dev->phys = sw->phys[i]; + input_dev->id.bustype = BUS_GAMEPORT; + input_dev->id.vendor = GAMEPORT_ID_VENDOR_MICROSOFT; + input_dev->id.product = sw->type; + input_dev->id.version = 0x0100; + input_dev->cdev.dev = &gameport->dev; + input_dev->private = sw; - sw->dev[i].name = sw->name; - sw->dev[i].phys = sw->phys[i]; - sw->dev[i].id.bustype = BUS_GAMEPORT; - sw->dev[i].id.vendor = GAMEPORT_ID_VENDOR_MICROSOFT; - sw->dev[i].id.product = sw->type; - sw->dev[i].id.version = 0x0100; + input_dev->open = sw_open; + input_dev->close = sw_close; - sw->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); for (j = 0; (bits = sw_bit[sw->type][j]); j++) { code = sw_abs[sw->type][j]; - set_bit(code, sw->dev[i].absbit); - sw->dev[i].absmax[code] = (1 << bits) - 1; - sw->dev[i].absmin[code] = (bits == 1) ? -1 : 0; - sw->dev[i].absfuzz[code] = ((bits >> 1) >= 2) ? (1 << ((bits >> 1) - 2)) : 0; + set_bit(code, input_dev->absbit); + input_dev->absmax[code] = (1 << bits) - 1; + input_dev->absmin[code] = (bits == 1) ? -1 : 0; + input_dev->absfuzz[code] = ((bits >> 1) >= 2) ? (1 << ((bits >> 1) - 2)) : 0; if (code != ABS_THROTTLE) - sw->dev[i].absflat[code] = (bits >= 5) ? (1 << (bits - 5)) : 0; + input_dev->absflat[code] = (bits >= 5) ? (1 << (bits - 5)) : 0; } for (j = 0; (code = sw_btn[sw->type][j]); j++) - set_bit(code, sw->dev[i].keybit); + set_bit(code, input_dev->keybit); + + dbg("%s%s [%d-bit id %d data %d]\n", sw->name, comment, m, l, k); - input_register_device(sw->dev + i); - printk(KERN_INFO "input: %s%s on %s [%d-bit id %d data %d]\n", - sw->name, comment, gameport->phys, m, l, k); + input_register_device(sw->dev[i]); } return 0; -fail2: gameport_close(gameport); -fail1: gameport_set_drvdata(gameport, NULL); + fail3: while (--i >= 0) + input_unregister_device(sw->dev[i]); + fail2: gameport_close(gameport); + fail1: gameport_set_drvdata(gameport, NULL); kfree(sw); kfree(buf); kfree(idbuf); @@ -777,7 +792,7 @@ static void sw_disconnect(struct gameport *gameport) int i; for (i = 0; i < sw->number; i++) - input_unregister_device(sw->dev + i); + input_unregister_device(sw->dev[i]); gameport_close(gameport); gameport_set_drvdata(gameport, NULL); kfree(sw); diff --git a/drivers/input/joystick/spaceball.c b/drivers/input/joystick/spaceball.c index a436f2220856..d6f8db8ec3fd 100644 --- a/drivers/input/joystick/spaceball.c +++ b/drivers/input/joystick/spaceball.c @@ -70,8 +70,7 @@ static char *spaceball_names[] = { */ struct spaceball { - struct input_dev dev; - struct serio *serio; + struct input_dev *dev; int idx; int escape; unsigned char data[SPACEBALL_MAX_LENGTH]; @@ -85,7 +84,7 @@ struct spaceball { static void spaceball_process_packet(struct spaceball* spaceball, struct pt_regs *regs) { - struct input_dev *dev = &spaceball->dev; + struct input_dev *dev = spaceball->dev; unsigned char *data = spaceball->data; int i; @@ -193,9 +192,9 @@ static void spaceball_disconnect(struct serio *serio) { struct spaceball* spaceball = serio_get_drvdata(serio); - input_unregister_device(&spaceball->dev); serio_close(serio); serio_set_drvdata(serio, NULL); + input_unregister_device(spaceball->dev); kfree(spaceball); } @@ -208,69 +207,62 @@ static void spaceball_disconnect(struct serio *serio) static int spaceball_connect(struct serio *serio, struct serio_driver *drv) { struct spaceball *spaceball; - int i, t, id; - int err; + struct input_dev *input_dev; + int err = -ENOMEM; + int i, id; if ((id = serio->id.id) > SPACEBALL_MAX_ID) return -ENODEV; - if (!(spaceball = kmalloc(sizeof(struct spaceball), GFP_KERNEL))) - return - ENOMEM; + spaceball = kmalloc(sizeof(struct spaceball), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!spaceball || !input_dev) + goto fail; - memset(spaceball, 0, sizeof(struct spaceball)); + spaceball->dev = input_dev; + sprintf(spaceball->phys, "%s/input0", serio->phys); + + input_dev->name = spaceball_names[id]; + input_dev->phys = spaceball->phys; + input_dev->id.bustype = BUS_RS232; + input_dev->id.vendor = SERIO_SPACEBALL; + input_dev->id.product = id; + input_dev->id.version = 0x0100; + input_dev->cdev.dev = &serio->dev; + input_dev->private = spaceball; - spaceball->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); switch (id) { case SPACEBALL_4000FLX: case SPACEBALL_4000FLX_L: - spaceball->dev.keybit[LONG(BTN_0)] |= BIT(BTN_9); - spaceball->dev.keybit[LONG(BTN_A)] |= BIT(BTN_A) | BIT(BTN_B) | BIT(BTN_C) | BIT(BTN_MODE); + input_dev->keybit[LONG(BTN_0)] |= BIT(BTN_9); + input_dev->keybit[LONG(BTN_A)] |= BIT(BTN_A) | BIT(BTN_B) | BIT(BTN_C) | BIT(BTN_MODE); default: - spaceball->dev.keybit[LONG(BTN_0)] |= BIT(BTN_2) | BIT(BTN_3) | BIT(BTN_4) + input_dev->keybit[LONG(BTN_0)] |= BIT(BTN_2) | BIT(BTN_3) | BIT(BTN_4) | BIT(BTN_5) | BIT(BTN_6) | BIT(BTN_7) | BIT(BTN_8); case SPACEBALL_3003C: - spaceball->dev.keybit[LONG(BTN_0)] |= BIT(BTN_1) | BIT(BTN_8); + input_dev->keybit[LONG(BTN_0)] |= BIT(BTN_1) | BIT(BTN_8); } - for (i = 0; i < 6; i++) { - t = spaceball_axes[i]; - set_bit(t, spaceball->dev.absbit); - spaceball->dev.absmin[t] = i < 3 ? -8000 : -1600; - spaceball->dev.absmax[t] = i < 3 ? 8000 : 1600; - spaceball->dev.absflat[t] = i < 3 ? 40 : 8; - spaceball->dev.absfuzz[t] = i < 3 ? 8 : 2; + for (i = 0; i < 3; i++) { + input_set_abs_params(input_dev, ABS_X + i, -8000, 8000, 8, 40); + input_set_abs_params(input_dev, ABS_RX + i, -1600, 1600, 2, 8); } - spaceball->serio = serio; - spaceball->dev.private = spaceball; - - sprintf(spaceball->phys, "%s/input0", serio->phys); - - init_input_dev(&spaceball->dev); - spaceball->dev.name = spaceball_names[id]; - spaceball->dev.phys = spaceball->phys; - spaceball->dev.id.bustype = BUS_RS232; - spaceball->dev.id.vendor = SERIO_SPACEBALL; - spaceball->dev.id.product = id; - spaceball->dev.id.version = 0x0100; - spaceball->dev.dev = &serio->dev; - serio_set_drvdata(serio, spaceball); err = serio_open(serio, drv); - if (err) { - serio_set_drvdata(serio, NULL); - kfree(spaceball); - return err; - } - - input_register_device(&spaceball->dev); - - printk(KERN_INFO "input: %s on serio%s\n", - spaceball_names[id], serio->phys); + if (err) + goto fail; + input_register_device(spaceball->dev); return 0; + + fail: serio_set_drvdata(serio, NULL); + input_free_device(input_dev); + kfree(spaceball); + return err; } /* diff --git a/drivers/input/joystick/spaceorb.c b/drivers/input/joystick/spaceorb.c index 01fd2e4791ae..7c123a01c58e 100644 --- a/drivers/input/joystick/spaceorb.c +++ b/drivers/input/joystick/spaceorb.c @@ -52,15 +52,13 @@ MODULE_LICENSE("GPL"); static int spaceorb_buttons[] = { BTN_TL, BTN_TR, BTN_Y, BTN_X, BTN_B, BTN_A }; static int spaceorb_axes[] = { ABS_X, ABS_Y, ABS_Z, ABS_RX, ABS_RY, ABS_RZ }; -static char *spaceorb_name = "SpaceTec SpaceOrb 360 / Avenger"; /* * Per-Orb data. */ struct spaceorb { - struct input_dev dev; - struct serio *serio; + struct input_dev *dev; int idx; unsigned char data[SPACEORB_MAX_LENGTH]; char phys[32]; @@ -78,7 +76,7 @@ static unsigned char *spaceorb_errors[] = { "EEPROM storing 0 failed", "Receive static void spaceorb_process_packet(struct spaceorb *spaceorb, struct pt_regs *regs) { - struct input_dev *dev = &spaceorb->dev; + struct input_dev *dev = spaceorb->dev; unsigned char *data = spaceorb->data; unsigned char c = 0; int axes[6]; @@ -95,8 +93,8 @@ static void spaceorb_process_packet(struct spaceorb *spaceorb, struct pt_regs *r case 'R': /* Reset packet */ spaceorb->data[spaceorb->idx - 1] = 0; for (i = 1; i < spaceorb->idx && spaceorb->data[i] == ' '; i++); - printk(KERN_INFO "input: %s [%s] on %s\n", - spaceorb_name, spaceorb->data + i, spaceorb->serio->phys); + printk(KERN_INFO "input: %s [%s] is %s\n", + dev->name, spaceorb->data + i, spaceorb->phys); break; case 'D': /* Ball + button data */ @@ -123,7 +121,7 @@ static void spaceorb_process_packet(struct spaceorb *spaceorb, struct pt_regs *r case 'E': /* Error packet */ if (spaceorb->idx != 4) return; - printk(KERN_ERR "joy-spaceorb: Device error. [ "); + printk(KERN_ERR "spaceorb: Device error. [ "); for (i = 0; i < 7; i++) if (data[1] & (1 << i)) printk("%s ", spaceorb_errors[i]); printk("]\n"); break; @@ -154,9 +152,9 @@ static void spaceorb_disconnect(struct serio *serio) { struct spaceorb* spaceorb = serio_get_drvdata(serio); - input_unregister_device(&spaceorb->dev); serio_close(serio); serio_set_drvdata(serio, NULL); + input_unregister_device(spaceorb->dev); kfree(spaceorb); } @@ -169,52 +167,48 @@ static void spaceorb_disconnect(struct serio *serio) static int spaceorb_connect(struct serio *serio, struct serio_driver *drv) { struct spaceorb *spaceorb; - int i, t; - int err; - - if (!(spaceorb = kmalloc(sizeof(struct spaceorb), GFP_KERNEL))) - return -ENOMEM; - - memset(spaceorb, 0, sizeof(struct spaceorb)); + struct input_dev *input_dev; + int err = -ENOMEM; + int i; - spaceorb->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + spaceorb = kzalloc(sizeof(struct spaceorb), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!spaceorb || !input_dev) + goto fail; - for (i = 0; i < 6; i++) - set_bit(spaceorb_buttons[i], spaceorb->dev.keybit); + spaceorb->dev = input_dev; + sprintf(spaceorb->phys, "%s/input0", serio->phys); - for (i = 0; i < 6; i++) { - t = spaceorb_axes[i]; - set_bit(t, spaceorb->dev.absbit); - spaceorb->dev.absmin[t] = -508; - spaceorb->dev.absmax[t] = 508; - } + input_dev->name = "SpaceTec SpaceOrb 360 / Avenger"; + input_dev->phys = spaceorb->phys; + input_dev->id.bustype = BUS_RS232; + input_dev->id.vendor = SERIO_SPACEORB; + input_dev->id.product = 0x0001; + input_dev->id.version = 0x0100; + input_dev->cdev.dev = &serio->dev; + input_dev->private = spaceorb; - spaceorb->serio = serio; - spaceorb->dev.private = spaceorb; + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - sprintf(spaceorb->phys, "%s/input0", serio->phys); + for (i = 0; i < 6; i++) + set_bit(spaceorb_buttons[i], input_dev->keybit); - init_input_dev(&spaceorb->dev); - spaceorb->dev.name = spaceorb_name; - spaceorb->dev.phys = spaceorb->phys; - spaceorb->dev.id.bustype = BUS_RS232; - spaceorb->dev.id.vendor = SERIO_SPACEORB; - spaceorb->dev.id.product = 0x0001; - spaceorb->dev.id.version = 0x0100; - spaceorb->dev.dev = &serio->dev; + for (i = 0; i < 6; i++) + input_set_abs_params(input_dev, spaceorb_axes[i], -508, 508, 0, 0); serio_set_drvdata(serio, spaceorb); err = serio_open(serio, drv); - if (err) { - serio_set_drvdata(serio, NULL); - kfree(spaceorb); - return err; - } - - input_register_device(&spaceorb->dev); + if (err) + goto fail; + input_register_device(spaceorb->dev); return 0; + + fail: serio_set_drvdata(serio, NULL); + input_free_device(input_dev); + kfree(spaceorb); + return err; } /* diff --git a/drivers/input/joystick/stinger.c b/drivers/input/joystick/stinger.c index 6f6e6753d590..0a9ed1d30636 100644 --- a/drivers/input/joystick/stinger.c +++ b/drivers/input/joystick/stinger.c @@ -48,14 +48,12 @@ MODULE_LICENSE("GPL"); #define STINGER_MAX_LENGTH 8 -static char *stinger_name = "Gravis Stinger"; - /* * Per-Stinger data. */ struct stinger { - struct input_dev dev; + struct input_dev *dev; int idx; unsigned char data[STINGER_MAX_LENGTH]; char phys[32]; @@ -68,7 +66,7 @@ struct stinger { static void stinger_process_packet(struct stinger *stinger, struct pt_regs *regs) { - struct input_dev *dev = &stinger->dev; + struct input_dev *dev = stinger->dev; unsigned char *data = stinger->data; if (!stinger->idx) return; @@ -126,9 +124,9 @@ static void stinger_disconnect(struct serio *serio) { struct stinger *stinger = serio_get_drvdata(serio); - input_unregister_device(&stinger->dev); serio_close(serio); serio_set_drvdata(serio, NULL); + input_unregister_device(stinger->dev); kfree(stinger); } @@ -141,53 +139,46 @@ static void stinger_disconnect(struct serio *serio) static int stinger_connect(struct serio *serio, struct serio_driver *drv) { struct stinger *stinger; - int i; - int err; - - if (!(stinger = kmalloc(sizeof(struct stinger), GFP_KERNEL))) - return -ENOMEM; - - memset(stinger, 0, sizeof(struct stinger)); + struct input_dev *input_dev; + int err = -ENOMEM; - stinger->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - stinger->dev.keybit[LONG(BTN_A)] = BIT(BTN_A) | BIT(BTN_B) | BIT(BTN_C) | BIT(BTN_X) | \ - BIT(BTN_Y) | BIT(BTN_Z) | BIT(BTN_TL) | BIT(BTN_TR) | \ - BIT(BTN_START) | BIT(BTN_SELECT); - stinger->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y); + stinger = kmalloc(sizeof(struct stinger), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!stinger || !input_dev) + goto fail; + stinger->dev = input_dev; sprintf(stinger->phys, "%s/serio0", serio->phys); - init_input_dev(&stinger->dev); - stinger->dev.name = stinger_name; - stinger->dev.phys = stinger->phys; - stinger->dev.id.bustype = BUS_RS232; - stinger->dev.id.vendor = SERIO_STINGER; - stinger->dev.id.product = 0x0001; - stinger->dev.id.version = 0x0100; - stinger->dev.dev = &serio->dev; - - for (i = 0; i < 2; i++) { - stinger->dev.absmax[ABS_X+i] = 64; - stinger->dev.absmin[ABS_X+i] = -64; - stinger->dev.absflat[ABS_X+i] = 4; - } - - stinger->dev.private = stinger; + input_dev->name = "Gravis Stinger"; + input_dev->phys = stinger->phys; + input_dev->id.bustype = BUS_RS232; + input_dev->id.vendor = SERIO_STINGER; + input_dev->id.product = 0x0001; + input_dev->id.version = 0x0100; + input_dev->cdev.dev = &serio->dev; + input_dev->private = stinger; + + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + input_dev->keybit[LONG(BTN_A)] = BIT(BTN_A) | BIT(BTN_B) | BIT(BTN_C) | BIT(BTN_X) | + BIT(BTN_Y) | BIT(BTN_Z) | BIT(BTN_TL) | BIT(BTN_TR) | + BIT(BTN_START) | BIT(BTN_SELECT); + input_set_abs_params(input_dev, ABS_X, -64, 64, 0, 4); + input_set_abs_params(input_dev, ABS_Y, -64, 64, 0, 4); serio_set_drvdata(serio, stinger); err = serio_open(serio, drv); - if (err) { - serio_set_drvdata(serio, NULL); - kfree(stinger); - return err; - } - - input_register_device(&stinger->dev); - - printk(KERN_INFO "input: %s on %s\n", stinger_name, serio->phys); + if (err) + goto fail; + input_register_device(stinger->dev); return 0; + + fail: serio_set_drvdata(serio, NULL); + input_free_device(input_dev); + kfree(stinger); + return err; } /* diff --git a/drivers/input/joystick/tmdc.c b/drivers/input/joystick/tmdc.c index 7431efc4330e..60e2aac7d06e 100644 --- a/drivers/input/joystick/tmdc.c +++ b/drivers/input/joystick/tmdc.c @@ -38,6 +38,7 @@ #include <linux/init.h> #include <linux/gameport.h> #include <linux/input.h> +#include <linux/jiffies.h> #define DRIVER_DESC "ThrustMaster DirectConnect joystick driver" @@ -63,37 +64,70 @@ MODULE_LICENSE("GPL"); #define TMDC_ABS_HAT 4 #define TMDC_BTN 16 -static unsigned char tmdc_byte_a[16] = { 0, 1, 3, 4, 6, 7 }; -static unsigned char tmdc_byte_d[16] = { 2, 5, 8, 9 }; +static const unsigned char tmdc_byte_a[16] = { 0, 1, 3, 4, 6, 7 }; +static const unsigned char tmdc_byte_d[16] = { 2, 5, 8, 9 }; -static signed char tmdc_abs[TMDC_ABS] = +static const signed char tmdc_abs[TMDC_ABS] = { ABS_X, ABS_Y, ABS_RUDDER, ABS_THROTTLE, ABS_RX, ABS_RY, ABS_RZ }; -static signed char tmdc_abs_hat[TMDC_ABS_HAT] = +static const signed char tmdc_abs_hat[TMDC_ABS_HAT] = { ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y }; -static signed char tmdc_abs_at[TMDC_ABS] = +static const signed char tmdc_abs_at[TMDC_ABS] = { ABS_X, ABS_Y, ABS_RUDDER, -1, ABS_THROTTLE }; -static signed char tmdc_abs_fm[TMDC_ABS] = +static const signed char tmdc_abs_fm[TMDC_ABS] = { ABS_RX, ABS_RY, ABS_X, ABS_Y }; -static short tmdc_btn_pad[TMDC_BTN] = +static const short tmdc_btn_pad[TMDC_BTN] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_START, BTN_SELECT, BTN_TL, BTN_TR }; -static short tmdc_btn_joy[TMDC_BTN] = +static const short tmdc_btn_joy[TMDC_BTN] = { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_THUMB2, BTN_PINKIE, BTN_BASE3, BTN_BASE4, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z }; -static short tmdc_btn_fm[TMDC_BTN] = +static const short tmdc_btn_fm[TMDC_BTN] = { BTN_TRIGGER, BTN_C, BTN_B, BTN_A, BTN_THUMB, BTN_X, BTN_Y, BTN_Z, BTN_TOP, BTN_TOP2 }; -static short tmdc_btn_at[TMDC_BTN] = +static const short tmdc_btn_at[TMDC_BTN] = { BTN_TRIGGER, BTN_THUMB2, BTN_PINKIE, BTN_THUMB, BTN_BASE6, BTN_BASE5, BTN_BASE4, BTN_BASE3, BTN_BASE2, BTN_BASE }; -static struct { +static const struct { int x; int y; } tmdc_hat_to_axis[] = {{ 0, 0}, { 1, 0}, { 0,-1}, {-1, 0}, { 0, 1}}; +static const struct tmdc_model { + unsigned char id; + const char *name; + char abs; + char hats; + char btnc[4]; + char btno[4]; + const signed char *axes; + const short *buttons; +} tmdc_models[] = { + { 1, "ThrustMaster Millenium 3D Inceptor", 6, 2, { 4, 2 }, { 4, 6 }, tmdc_abs, tmdc_btn_joy }, + { 3, "ThrustMaster Rage 3D Gamepad", 2, 0, { 8, 2 }, { 0, 0 }, tmdc_abs, tmdc_btn_pad }, + { 4, "ThrustMaster Attack Throttle", 5, 2, { 4, 6 }, { 4, 2 }, tmdc_abs_at, tmdc_btn_at }, + { 8, "ThrustMaster FragMaster", 4, 0, { 8, 2 }, { 0, 0 }, tmdc_abs_fm, tmdc_btn_fm }, + { 163, "Thrustmaster Fusion GamePad", 2, 0, { 8, 2 }, { 0, 0 }, tmdc_abs, tmdc_btn_pad }, + { 0, "Unknown %d-axis, %d-button TM device %d", 0, 0, { 0, 0 }, { 0, 0 }, tmdc_abs, tmdc_btn_joy } +}; + + +struct tmdc_port { + struct input_dev *dev; + char name[64]; + char phys[32]; + int mode; + const signed char *abs; + const short *btn; + unsigned char absc; + unsigned char btnc[4]; + unsigned char btno[4]; +}; + struct tmdc { struct gameport *gameport; - struct input_dev dev[2]; + struct tmdc_port *port[2]; +#if 0 + struct input_dev *dev[2]; char name[2][64]; char phys[2][32]; int mode[2]; @@ -102,6 +136,7 @@ struct tmdc { unsigned char absc[2]; unsigned char btnc[2][4]; unsigned char btno[2][4]; +#endif int reads; int bads; unsigned char exists; @@ -156,6 +191,50 @@ static int tmdc_read_packet(struct gameport *gameport, unsigned char data[2][TMD return (i[0] == TMDC_MAX_LENGTH) | ((i[1] == TMDC_MAX_LENGTH) << 1); } +static int tmdc_parse_packet(struct tmdc_port *port, unsigned char *data) +{ + int i, k, l; + + if (data[TMDC_BYTE_ID] != port->mode) + return -1; + + for (i = 0; i < port->absc; i++) { + if (port->abs[i] < 0) + return 0; + + input_report_abs(port->dev, port->abs[i], data[tmdc_byte_a[i]]); + } + + switch (port->mode) { + + case TMDC_MODE_M3DI: + + i = tmdc_byte_d[0]; + input_report_abs(port->dev, ABS_HAT0X, ((data[i] >> 3) & 1) - ((data[i] >> 1) & 1)); + input_report_abs(port->dev, ABS_HAT0Y, ((data[i] >> 2) & 1) - ( data[i] & 1)); + break; + + case TMDC_MODE_AT: + + i = tmdc_byte_a[3]; + input_report_abs(port->dev, ABS_HAT0X, tmdc_hat_to_axis[(data[i] - 141) / 25].x); + input_report_abs(port->dev, ABS_HAT0Y, tmdc_hat_to_axis[(data[i] - 141) / 25].y); + break; + + } + + for (k = l = 0; k < 4; k++) { + for (i = 0; i < port->btnc[k]; i++) + input_report_key(port->dev, port->btn[i + l], + ((data[tmdc_byte_d[k]] >> (i + port->btno[k])) & 1)); + l += port->btnc[k]; + } + + input_sync(port->dev); + + return 0; +} + /* * tmdc_poll() reads and analyzes ThrustMaster joystick data. */ @@ -164,57 +243,21 @@ static void tmdc_poll(struct gameport *gameport) { unsigned char data[2][TMDC_MAX_LENGTH]; struct tmdc *tmdc = gameport_get_drvdata(gameport); - struct input_dev *dev; unsigned char r, bad = 0; - int i, j, k, l; + int i; tmdc->reads++; if ((r = tmdc_read_packet(tmdc->gameport, data)) != tmdc->exists) bad = 1; - else - - for (j = 0; j < 2; j++) - if (r & (1 << j) & tmdc->exists) { - - if (data[j][TMDC_BYTE_ID] != tmdc->mode[j]) { - bad = 1; - continue; - } - - dev = tmdc->dev + j; - - for (i = 0; i < tmdc->absc[j]; i++) { - if (tmdc->abs[j][i] < 0) continue; - input_report_abs(dev, tmdc->abs[j][i], data[j][tmdc_byte_a[i]]); - } - - switch (tmdc->mode[j]) { + else { + for (i = 0; i < 2; i++) { + if (r & (1 << i) & tmdc->exists) { - case TMDC_MODE_M3DI: - - i = tmdc_byte_d[0]; - input_report_abs(dev, ABS_HAT0X, ((data[j][i] >> 3) & 1) - ((data[j][i] >> 1) & 1)); - input_report_abs(dev, ABS_HAT0Y, ((data[j][i] >> 2) & 1) - ( data[j][i] & 1)); - break; - - case TMDC_MODE_AT: - - i = tmdc_byte_a[3]; - input_report_abs(dev, ABS_HAT0X, tmdc_hat_to_axis[(data[j][i] - 141) / 25].x); - input_report_abs(dev, ABS_HAT0Y, tmdc_hat_to_axis[(data[j][i] - 141) / 25].y); - break; - - } - - for (k = l = 0; k < 4; k++) { - for (i = 0; i < tmdc->btnc[j][k]; i++) - input_report_key(dev, tmdc->btn[j][i + l], - ((data[j][tmdc_byte_d[k]] >> (i + tmdc->btno[j][k])) & 1)); - l += tmdc->btnc[j][k]; + if (tmdc_parse_packet(tmdc->port[i], data[i])) + bad = 1; } - - input_sync(dev); + } } tmdc->bads += bad; @@ -235,31 +278,89 @@ static void tmdc_close(struct input_dev *dev) gameport_stop_polling(tmdc->gameport); } +static int tmdc_setup_port(struct tmdc *tmdc, int idx, unsigned char *data) +{ + const struct tmdc_model *model; + struct tmdc_port *port; + struct input_dev *input_dev; + int i, j, b = 0; + + tmdc->port[idx] = port = kzalloc(sizeof (struct tmdc_port), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!port || !input_dev) { + kfree(port); + input_free_device(input_dev); + return -ENOMEM; + } + + port->mode = data[TMDC_BYTE_ID]; + + for (model = tmdc_models; model->id && model->id != port->mode; model++) + /* empty */; + + port->abs = model->axes; + port->btn = model->buttons; + + if (!model->id) { + port->absc = data[TMDC_BYTE_DEF] >> 4; + for (i = 0; i < 4; i++) + port->btnc[i] = i < (data[TMDC_BYTE_DEF] & 0xf) ? 8 : 0; + } else { + port->absc = model->abs; + for (i = 0; i < 4; i++) + port->btnc[i] = model->btnc[i]; + } + + for (i = 0; i < 4; i++) + port->btno[i] = model->btno[i]; + + snprintf(port->name, sizeof(port->name), model->name, + port->absc, (data[TMDC_BYTE_DEF] & 0xf) << 3, port->mode); + snprintf(port->phys, sizeof(port->phys), "%s/input%d", tmdc->gameport->phys, i); + + port->dev = input_dev; + + input_dev->name = port->name; + input_dev->phys = port->phys; + input_dev->id.bustype = BUS_GAMEPORT; + input_dev->id.vendor = GAMEPORT_ID_VENDOR_THRUSTMASTER; + input_dev->id.product = model->id; + input_dev->id.version = 0x0100; + input_dev->cdev.dev = &tmdc->gameport->dev; + input_dev->private = tmdc; + + input_dev->open = tmdc_open; + input_dev->close = tmdc_close; + + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + + for (i = 0; i < port->absc && i < TMDC_ABS; i++) + if (port->abs[i] >= 0) + input_set_abs_params(input_dev, port->abs[i], 8, 248, 2, 4); + + for (i = 0; i < model->hats && i < TMDC_ABS_HAT; i++) + input_set_abs_params(input_dev, tmdc_abs_hat[i], -1, 1, 0, 0); + + for (i = 0; i < 4; i++) { + for (j = 0; j < port->btnc[i] && j < TMDC_BTN; j++) + set_bit(port->btn[j + b], input_dev->keybit); + b += port->btnc[i]; + } + + input_register_device(port->dev); + + return 0; +} + /* * tmdc_probe() probes for ThrustMaster type joysticks. */ static int tmdc_connect(struct gameport *gameport, struct gameport_driver *drv) { - static struct models { - unsigned char id; - char *name; - char abs; - char hats; - char btnc[4]; - char btno[4]; - signed char *axes; - short *buttons; - } models[] = { { 1, "ThrustMaster Millenium 3D Inceptor", 6, 2, { 4, 2 }, { 4, 6 }, tmdc_abs, tmdc_btn_joy }, - { 3, "ThrustMaster Rage 3D Gamepad", 2, 0, { 8, 2 }, { 0, 0 }, tmdc_abs, tmdc_btn_pad }, - { 4, "ThrustMaster Attack Throttle", 5, 2, { 4, 6 }, { 4, 2 }, tmdc_abs_at, tmdc_btn_at }, - { 8, "ThrustMaster FragMaster", 4, 0, { 8, 2 }, { 0, 0 }, tmdc_abs_fm, tmdc_btn_fm }, - { 163, "Thrustmaster Fusion GamePad", 2, 0, { 8, 2 }, { 0, 0 }, tmdc_abs, tmdc_btn_pad }, - { 0, "Unknown %d-axis, %d-button TM device %d", 0, 0, { 0, 0 }, { 0, 0 }, tmdc_abs, tmdc_btn_joy }}; - unsigned char data[2][TMDC_MAX_LENGTH]; struct tmdc *tmdc; - int i, j, k, l, m; + int i; int err; if (!(tmdc = kzalloc(sizeof(struct tmdc), GFP_KERNEL))) @@ -281,68 +382,25 @@ static int tmdc_connect(struct gameport *gameport, struct gameport_driver *drv) gameport_set_poll_handler(gameport, tmdc_poll); gameport_set_poll_interval(gameport, 20); - for (j = 0; j < 2; j++) - if (tmdc->exists & (1 << j)) { + for (i = 0; i < 2; i++) { + if (tmdc->exists & (1 << i)) { - tmdc->mode[j] = data[j][TMDC_BYTE_ID]; - - for (m = 0; models[m].id && models[m].id != tmdc->mode[j]; m++); - - tmdc->abs[j] = models[m].axes; - tmdc->btn[j] = models[m].buttons; - - if (!models[m].id) { - models[m].abs = data[j][TMDC_BYTE_DEF] >> 4; - for (k = 0; k < 4; k++) - models[m].btnc[k] = k < (data[j][TMDC_BYTE_DEF] & 0xf) ? 8 : 0; - } - - tmdc->absc[j] = models[m].abs; - for (k = 0; k < 4; k++) { - tmdc->btnc[j][k] = models[m].btnc[k]; - tmdc->btno[j][k] = models[m].btno[k]; - } - - sprintf(tmdc->name[j], models[m].name, models[m].abs, - (data[j][TMDC_BYTE_DEF] & 0xf) << 3, tmdc->mode[j]); - - sprintf(tmdc->phys[j], "%s/input%d", gameport->phys, j); - - tmdc->dev[j].private = tmdc; - tmdc->dev[j].open = tmdc_open; - tmdc->dev[j].close = tmdc_close; - - tmdc->dev[j].name = tmdc->name[j]; - tmdc->dev[j].phys = tmdc->phys[j]; - tmdc->dev[j].id.bustype = BUS_GAMEPORT; - tmdc->dev[j].id.vendor = GAMEPORT_ID_VENDOR_THRUSTMASTER; - tmdc->dev[j].id.product = models[m].id; - tmdc->dev[j].id.version = 0x0100; - - tmdc->dev[j].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - - for (i = 0; i < models[m].abs && i < TMDC_ABS; i++) - if (tmdc->abs[j][i] >= 0) - input_set_abs_params(&tmdc->dev[j], tmdc->abs[j][i], 8, 248, 2, 4); - - for (i = 0; i < models[m].hats && i < TMDC_ABS_HAT; i++) - input_set_abs_params(&tmdc->dev[j], tmdc_abs_hat[i], -1, 1, 0, 0); - - - for (k = l = 0; k < 4; k++) { - for (i = 0; i < models[m].btnc[k] && i < TMDC_BTN; i++) - set_bit(tmdc->btn[j][i + l], tmdc->dev[j].keybit); - l += models[m].btnc[k]; - } - - input_register_device(tmdc->dev + j); - printk(KERN_INFO "input: %s on %s\n", tmdc->name[j], gameport->phys); + err = tmdc_setup_port(tmdc, i, data[i]); + if (err) + goto fail3; } + } return 0; -fail2: gameport_close(gameport); -fail1: gameport_set_drvdata(gameport, NULL); + fail3: while (--i >= 0) { + if (tmdc->port[i]) { + input_unregister_device(tmdc->port[i]->dev); + kfree(tmdc->port[i]); + } + } + fail2: gameport_close(gameport); + fail1: gameport_set_drvdata(gameport, NULL); kfree(tmdc); return err; } @@ -352,9 +410,12 @@ static void tmdc_disconnect(struct gameport *gameport) struct tmdc *tmdc = gameport_get_drvdata(gameport); int i; - for (i = 0; i < 2; i++) - if (tmdc->exists & (1 << i)) - input_unregister_device(tmdc->dev + i); + for (i = 0; i < 2; i++) { + if (tmdc->port[i]) { + input_unregister_device(tmdc->port[i]->dev); + kfree(tmdc->port[i]); + } + } gameport_close(gameport); gameport_set_drvdata(gameport, NULL); kfree(tmdc); diff --git a/drivers/input/joystick/turbografx.c b/drivers/input/joystick/turbografx.c index 0c5b9c8297cd..7e9764937d06 100644 --- a/drivers/input/joystick/turbografx.c +++ b/drivers/input/joystick/turbografx.c @@ -42,19 +42,21 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); MODULE_DESCRIPTION("TurboGraFX parallel port interface driver"); MODULE_LICENSE("GPL"); -static int tgfx[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 }; -static int tgfx_nargs __initdata = 0; -module_param_array_named(map, tgfx, int, &tgfx_nargs, 0); -MODULE_PARM_DESC(map, "Describes first set of devices (<parport#>,<js1>,<js2>,..<js7>"); +#define TGFX_MAX_PORTS 3 +#define TGFX_MAX_DEVICES 7 -static int tgfx_2[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 }; -static int tgfx_nargs_2 __initdata = 0; -module_param_array_named(map2, tgfx_2, int, &tgfx_nargs_2, 0); -MODULE_PARM_DESC(map2, "Describes second set of devices"); +struct tgfx_config { + int args[TGFX_MAX_DEVICES + 1]; + int nargs; +}; + +static struct tgfx_config tgfx[TGFX_MAX_PORTS] __initdata; -static int tgfx_3[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 }; -static int tgfx_nargs_3 __initdata = 0; -module_param_array_named(map3, tgfx_3, int, &tgfx_nargs_3, 0); +module_param_array_named(map, tgfx[0].args, int, &tgfx[0].nargs, 0); +MODULE_PARM_DESC(map, "Describes first set of devices (<parport#>,<js1>,<js2>,..<js7>"); +module_param_array_named(map2, tgfx[1].args, int, &tgfx[1].nargs, 0); +MODULE_PARM_DESC(map2, "Describes second set of devices"); +module_param_array_named(map3, tgfx[2].args, int, &tgfx[2].nargs, 0); MODULE_PARM_DESC(map3, "Describes third set of devices"); __obsolete_setup("tgfx="); @@ -75,17 +77,17 @@ __obsolete_setup("tgfx_3="); #define TGFX_TOP2 0x08 static int tgfx_buttons[] = { BTN_TRIGGER, BTN_THUMB, BTN_THUMB2, BTN_TOP, BTN_TOP2 }; -static char *tgfx_name = "TurboGraFX Multisystem joystick"; static struct tgfx { struct pardevice *pd; struct timer_list timer; - struct input_dev dev[7]; - char phys[7][32]; + struct input_dev *dev[TGFX_MAX_DEVICES]; + char name[TGFX_MAX_DEVICES][64]; + char phys[TGFX_MAX_DEVICES][32]; int sticks; int used; struct semaphore sem; -} *tgfx_base[3]; +} *tgfx_base[TGFX_MAX_PORTS]; /* * tgfx_timer() reads and analyzes TurboGraFX joystick data. @@ -100,7 +102,7 @@ static void tgfx_timer(unsigned long private) for (i = 0; i < 7; i++) if (tgfx->sticks & (1 << i)) { - dev = tgfx->dev + i; + dev = tgfx->dev[i]; parport_write_data(tgfx->pd->port, ~(1 << i)); data1 = parport_read_status(tgfx->pd->port) ^ 0x7f; @@ -153,118 +155,165 @@ static void tgfx_close(struct input_dev *dev) up(&tgfx->sem); } + + /* * tgfx_probe() probes for tg gamepads. */ -static struct tgfx __init *tgfx_probe(int *config, int nargs) +static struct tgfx __init *tgfx_probe(int parport, int *n_buttons, int n_devs) { struct tgfx *tgfx; + struct input_dev *input_dev; struct parport *pp; + struct pardevice *pd; int i, j; + int err; - if (config[0] < 0) - return NULL; - - if (nargs < 2) { - printk(KERN_ERR "turbografx.c: at least one joystick must be specified\n"); - return NULL; - } - - pp = parport_find_number(config[0]); - + pp = parport_find_number(parport); if (!pp) { printk(KERN_ERR "turbografx.c: no such parport\n"); - return NULL; + err = -EINVAL; + goto err_out; } - if (!(tgfx = kzalloc(sizeof(struct tgfx), GFP_KERNEL))) { - parport_put_port(pp); - return NULL; + pd = parport_register_device(pp, "turbografx", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL); + if (!pd) { + printk(KERN_ERR "turbografx.c: parport busy already - lp.o loaded?\n"); + err = -EBUSY; + goto err_put_pp; } - init_MUTEX(&tgfx->sem); - - tgfx->pd = parport_register_device(pp, "turbografx", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL); - - parport_put_port(pp); - - if (!tgfx->pd) { - printk(KERN_ERR "turbografx.c: parport busy already - lp.o loaded?\n"); - kfree(tgfx); - return NULL; + tgfx = kzalloc(sizeof(struct tgfx), GFP_KERNEL); + if (!tgfx) { + printk(KERN_ERR "turbografx.c: Not enough memory\n"); + err = -ENOMEM; + goto err_unreg_pardev; } + init_MUTEX(&tgfx->sem); + tgfx->pd = pd; init_timer(&tgfx->timer); tgfx->timer.data = (long) tgfx; tgfx->timer.function = tgfx_timer; - tgfx->sticks = 0; + for (i = 0; i < n_devs; i++) { + if (n_buttons[i] < 1) + continue; - for (i = 0; i < nargs - 1; i++) - if (config[i+1] > 0 && config[i+1] < 6) { - - tgfx->sticks |= (1 << i); + if (n_buttons[i] > 6) { + printk(KERN_ERR "turbografx.c: Invalid number of buttons %d\n", n_buttons[i]); + err = -EINVAL; + goto err_free_devs; + } - tgfx->dev[i].private = tgfx; - tgfx->dev[i].open = tgfx_open; - tgfx->dev[i].close = tgfx_close; + tgfx->dev[i] = input_dev = input_allocate_device(); + if (!input_dev) { + printk(KERN_ERR "turbografx.c: Not enough memory for input device\n"); + err = -ENOMEM; + goto err_free_devs; + } - sprintf(tgfx->phys[i], "%s/input0", tgfx->pd->port->name); + tgfx->sticks |= (1 << i); + snprintf(tgfx->name[i], sizeof(tgfx->name[i]), + "TurboGraFX %d-button Multisystem joystick", n_buttons[i]); + snprintf(tgfx->phys[i], sizeof(tgfx->phys[i]), + "%s/input%d", tgfx->pd->port->name, i); - tgfx->dev[i].name = tgfx_name; - tgfx->dev[i].phys = tgfx->phys[i]; - tgfx->dev[i].id.bustype = BUS_PARPORT; - tgfx->dev[i].id.vendor = 0x0003; - tgfx->dev[i].id.product = config[i+1]; - tgfx->dev[i].id.version = 0x0100; + input_dev->name = tgfx->name[i]; + input_dev->phys = tgfx->phys[i]; + input_dev->id.bustype = BUS_PARPORT; + input_dev->id.vendor = 0x0003; + input_dev->id.product = n_buttons[i]; + input_dev->id.version = 0x0100; - tgfx->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - tgfx->dev[i].absbit[0] = BIT(ABS_X) | BIT(ABS_Y); + input_dev->private = tgfx; + input_dev->open = tgfx_open; + input_dev->close = tgfx_close; - for (j = 0; j < config[i+1]; j++) - set_bit(tgfx_buttons[j], tgfx->dev[i].keybit); + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + input_set_abs_params(input_dev, ABS_X, -1, 1, 0, 0); + input_set_abs_params(input_dev, ABS_Y, -1, 1, 0, 0); - tgfx->dev[i].absmin[ABS_X] = -1; tgfx->dev[i].absmax[ABS_X] = 1; - tgfx->dev[i].absmin[ABS_Y] = -1; tgfx->dev[i].absmax[ABS_Y] = 1; + for (j = 0; j < n_buttons[i]; j++) + set_bit(tgfx_buttons[j], input_dev->keybit); - input_register_device(tgfx->dev + i); - printk(KERN_INFO "input: %d-button Multisystem joystick on %s\n", - config[i+1], tgfx->pd->port->name); - } + input_register_device(tgfx->dev[i]); + } if (!tgfx->sticks) { - parport_unregister_device(tgfx->pd); - kfree(tgfx); - return NULL; + printk(KERN_ERR "turbografx.c: No valid devices specified\n"); + err = -EINVAL; + goto err_free_tgfx; } return tgfx; + + err_free_devs: + while (--i >= 0) + input_unregister_device(tgfx->dev[i]); + err_free_tgfx: + kfree(tgfx); + err_unreg_pardev: + parport_unregister_device(pd); + err_put_pp: + parport_put_port(pp); + err_out: + return ERR_PTR(err); +} + +static void __exit tgfx_remove(struct tgfx *tgfx) +{ + int i; + + for (i = 0; i < TGFX_MAX_DEVICES; i++) + if (tgfx->dev[i]) + input_unregister_device(tgfx->dev[i]); + parport_unregister_device(tgfx->pd); + kfree(tgfx); } static int __init tgfx_init(void) { - tgfx_base[0] = tgfx_probe(tgfx, tgfx_nargs); - tgfx_base[1] = tgfx_probe(tgfx_2, tgfx_nargs_2); - tgfx_base[2] = tgfx_probe(tgfx_3, tgfx_nargs_3); + int i; + int have_dev = 0; + int err = 0; + + for (i = 0; i < TGFX_MAX_PORTS; i++) { + if (tgfx[i].nargs == 0 || tgfx[i].args[0] < 0) + continue; + + if (tgfx[i].nargs < 2) { + printk(KERN_ERR "turbografx.c: at least one joystick must be specified\n"); + err = -EINVAL; + break; + } + + tgfx_base[i] = tgfx_probe(tgfx[i].args[0], tgfx[i].args + 1, tgfx[i].nargs - 1); + if (IS_ERR(tgfx_base[i])) { + err = PTR_ERR(tgfx_base[i]); + break; + } + + have_dev = 1; + } - if (tgfx_base[0] || tgfx_base[1] || tgfx_base[2]) - return 0; + if (err) { + while (--i >= 0) + tgfx_remove(tgfx_base[i]); + return err; + } - return -ENODEV; + return have_dev ? 0 : -ENODEV; } static void __exit tgfx_exit(void) { - int i, j; + int i; - for (i = 0; i < 3; i++) - if (tgfx_base[i]) { - for (j = 0; j < 7; j++) - if (tgfx_base[i]->sticks & (1 << j)) - input_unregister_device(tgfx_base[i]->dev + j); - parport_unregister_device(tgfx_base[i]->pd); - } + for (i = 0; i < TGFX_MAX_PORTS; i++) + if (tgfx_base[i]) + tgfx_remove(tgfx_base[i]); } module_init(tgfx_init); diff --git a/drivers/input/joystick/twidjoy.c b/drivers/input/joystick/twidjoy.c index 0379bc166525..cd3a1e742a30 100644 --- a/drivers/input/joystick/twidjoy.c +++ b/drivers/input/joystick/twidjoy.c @@ -69,8 +69,6 @@ MODULE_LICENSE("GPL"); #define TWIDJOY_MAX_LENGTH 5 -static char *twidjoy_name = "Handykey Twiddler"; - static struct twidjoy_button_spec { int bitshift; int bitmask; @@ -95,7 +93,7 @@ twidjoy_buttons[] = { */ struct twidjoy { - struct input_dev dev; + struct input_dev *dev; int idx; unsigned char data[TWIDJOY_MAX_LENGTH]; char phys[32]; @@ -108,37 +106,33 @@ struct twidjoy { static void twidjoy_process_packet(struct twidjoy *twidjoy, struct pt_regs *regs) { - if (twidjoy->idx == TWIDJOY_MAX_LENGTH) { - struct input_dev *dev = &twidjoy->dev; - unsigned char *data = twidjoy->data; - struct twidjoy_button_spec *bp; - int button_bits, abs_x, abs_y; - - button_bits = ((data[1] & 0x7f) << 7) | (data[0] & 0x7f); + struct input_dev *dev = twidjoy->dev; + unsigned char *data = twidjoy->data; + struct twidjoy_button_spec *bp; + int button_bits, abs_x, abs_y; - input_regs(dev, regs); + button_bits = ((data[1] & 0x7f) << 7) | (data[0] & 0x7f); - for (bp = twidjoy_buttons; bp->bitmask; bp++) { - int value = (button_bits & (bp->bitmask << bp->bitshift)) >> bp->bitshift; - int i; + input_regs(dev, regs); - for (i = 0; i < bp->bitmask; i++) - input_report_key(dev, bp->buttons[i], i+1 == value); - } + for (bp = twidjoy_buttons; bp->bitmask; bp++) { + int value = (button_bits & (bp->bitmask << bp->bitshift)) >> bp->bitshift; + int i; - abs_x = ((data[4] & 0x07) << 5) | ((data[3] & 0x7C) >> 2); - if (data[4] & 0x08) abs_x -= 256; + for (i = 0; i < bp->bitmask; i++) + input_report_key(dev, bp->buttons[i], i+1 == value); + } - abs_y = ((data[3] & 0x01) << 7) | ((data[2] & 0x7F) >> 0); - if (data[3] & 0x02) abs_y -= 256; + abs_x = ((data[4] & 0x07) << 5) | ((data[3] & 0x7C) >> 2); + if (data[4] & 0x08) abs_x -= 256; - input_report_abs(dev, ABS_X, -abs_x); - input_report_abs(dev, ABS_Y, +abs_y); + abs_y = ((data[3] & 0x01) << 7) | ((data[2] & 0x7F) >> 0); + if (data[3] & 0x02) abs_y -= 256; - input_sync(dev); - } + input_report_abs(dev, ABS_X, -abs_x); + input_report_abs(dev, ABS_Y, +abs_y); - return; + input_sync(dev); } /* @@ -179,9 +173,9 @@ static void twidjoy_disconnect(struct serio *serio) { struct twidjoy *twidjoy = serio_get_drvdata(serio); - input_unregister_device(&twidjoy->dev); serio_close(serio); serio_set_drvdata(serio, NULL); + input_unregister_device(twidjoy->dev); kfree(twidjoy); } @@ -195,59 +189,49 @@ static int twidjoy_connect(struct serio *serio, struct serio_driver *drv) { struct twidjoy_button_spec *bp; struct twidjoy *twidjoy; + struct input_dev *input_dev; + int err = -ENOMEM; int i; - int err; - - if (!(twidjoy = kmalloc(sizeof(struct twidjoy), GFP_KERNEL))) - return -ENOMEM; - memset(twidjoy, 0, sizeof(struct twidjoy)); + twidjoy = kzalloc(sizeof(struct twidjoy), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!twidjoy || !input_dev) + goto fail; + twidjoy->dev = input_dev; sprintf(twidjoy->phys, "%s/input0", serio->phys); - init_input_dev(&twidjoy->dev); - twidjoy->dev.name = twidjoy_name; - twidjoy->dev.phys = twidjoy->phys; - twidjoy->dev.id.bustype = BUS_RS232; - twidjoy->dev.id.vendor = SERIO_TWIDJOY; - twidjoy->dev.id.product = 0x0001; - twidjoy->dev.id.version = 0x0100; - twidjoy->dev.dev = &serio->dev; - - twidjoy->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - - for (bp = twidjoy_buttons; bp->bitmask; bp++) { + input_dev->name = "Handykey Twiddler"; + input_dev->phys = twidjoy->phys; + input_dev->id.bustype = BUS_RS232; + input_dev->id.vendor = SERIO_TWIDJOY; + input_dev->id.product = 0x0001; + input_dev->id.version = 0x0100; + input_dev->cdev.dev = &serio->dev; + input_dev->private = twidjoy; + + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + input_dev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y); + input_set_abs_params(input_dev, ABS_X, -50, 50, 4, 4); + input_set_abs_params(input_dev, ABS_Y, -50, 50, 4, 4); + + for (bp = twidjoy_buttons; bp->bitmask; bp++) for (i = 0; i < bp->bitmask; i++) - set_bit(bp->buttons[i], twidjoy->dev.keybit); - } - - twidjoy->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y); - - for (i = 0; i < 2; i++) { - twidjoy->dev.absmax[ABS_X+i] = 50; - twidjoy->dev.absmin[ABS_X+i] = -50; - - /* TODO: arndt 20010708: Are these values appropriate? */ - twidjoy->dev.absfuzz[ABS_X+i] = 4; - twidjoy->dev.absflat[ABS_X+i] = 4; - } - - twidjoy->dev.private = twidjoy; + set_bit(bp->buttons[i], input_dev->keybit); serio_set_drvdata(serio, twidjoy); err = serio_open(serio, drv); - if (err) { - serio_set_drvdata(serio, NULL); - kfree(twidjoy); - return err; - } - - input_register_device(&twidjoy->dev); - - printk(KERN_INFO "input: %s on %s\n", twidjoy_name, serio->phys); + if (err) + goto fail; + input_register_device(twidjoy->dev); return 0; + + fail: serio_set_drvdata(serio, NULL); + input_free_device(input_dev); + kfree(twidjoy); + return err; } /* diff --git a/drivers/input/joystick/warrior.c b/drivers/input/joystick/warrior.c index 6976a219504c..99a642d2a1fe 100644 --- a/drivers/input/joystick/warrior.c +++ b/drivers/input/joystick/warrior.c @@ -47,14 +47,13 @@ MODULE_LICENSE("GPL"); #define WARRIOR_MAX_LENGTH 16 static char warrior_lengths[] = { 0, 4, 12, 3, 4, 4, 0, 0 }; -static char *warrior_name = "Logitech WingMan Warrior"; /* * Per-Warrior data. */ struct warrior { - struct input_dev dev; + struct input_dev *dev; int idx, len; unsigned char data[WARRIOR_MAX_LENGTH]; char phys[32]; @@ -67,7 +66,7 @@ struct warrior { static void warrior_process_packet(struct warrior *warrior, struct pt_regs *regs) { - struct input_dev *dev = &warrior->dev; + struct input_dev *dev = warrior->dev; unsigned char *data = warrior->data; if (!warrior->idx) return; @@ -131,9 +130,9 @@ static void warrior_disconnect(struct serio *serio) { struct warrior *warrior = serio_get_drvdata(serio); - input_unregister_device(&warrior->dev); serio_close(serio); serio_set_drvdata(serio, NULL); + input_unregister_device(warrior->dev); kfree(warrior); } @@ -146,60 +145,48 @@ static void warrior_disconnect(struct serio *serio) static int warrior_connect(struct serio *serio, struct serio_driver *drv) { struct warrior *warrior; - int i; - int err; + struct input_dev *input_dev; + int err = -ENOMEM; - if (!(warrior = kmalloc(sizeof(struct warrior), GFP_KERNEL))) - return -ENOMEM; - - memset(warrior, 0, sizeof(struct warrior)); - - warrior->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_ABS); - warrior->dev.keybit[LONG(BTN_TRIGGER)] = BIT(BTN_TRIGGER) | BIT(BTN_THUMB) | BIT(BTN_TOP) | BIT(BTN_TOP2); - warrior->dev.relbit[0] = BIT(REL_DIAL); - warrior->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_THROTTLE) | BIT(ABS_HAT0X) | BIT(ABS_HAT0Y); + warrior = kzalloc(sizeof(struct warrior), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!warrior || !input_dev) + goto fail; + warrior->dev = input_dev; sprintf(warrior->phys, "%s/input0", serio->phys); - init_input_dev(&warrior->dev); - warrior->dev.name = warrior_name; - warrior->dev.phys = warrior->phys; - warrior->dev.id.bustype = BUS_RS232; - warrior->dev.id.vendor = SERIO_WARRIOR; - warrior->dev.id.product = 0x0001; - warrior->dev.id.version = 0x0100; - warrior->dev.dev = &serio->dev; - - for (i = 0; i < 2; i++) { - warrior->dev.absmax[ABS_X+i] = -64; - warrior->dev.absmin[ABS_X+i] = 64; - warrior->dev.absflat[ABS_X+i] = 8; - } - - warrior->dev.absmax[ABS_THROTTLE] = -112; - warrior->dev.absmin[ABS_THROTTLE] = 112; - - for (i = 0; i < 2; i++) { - warrior->dev.absmax[ABS_HAT0X+i] = -1; - warrior->dev.absmin[ABS_HAT0X+i] = 1; - } - - warrior->dev.private = warrior; + input_dev->name = "Logitech WingMan Warrior"; + input_dev->phys = warrior->phys; + input_dev->id.bustype = BUS_RS232; + input_dev->id.vendor = SERIO_WARRIOR; + input_dev->id.product = 0x0001; + input_dev->id.version = 0x0100; + input_dev->cdev.dev = &serio->dev; + input_dev->private = warrior; + + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_ABS); + input_dev->keybit[LONG(BTN_TRIGGER)] = BIT(BTN_TRIGGER) | BIT(BTN_THUMB) | BIT(BTN_TOP) | BIT(BTN_TOP2); + input_dev->relbit[0] = BIT(REL_DIAL); + input_set_abs_params(input_dev, ABS_X, -64, 64, 0, 8); + input_set_abs_params(input_dev, ABS_Y, -64, 64, 0, 8); + input_set_abs_params(input_dev, ABS_THROTTLE, -112, 112, 0, 0); + input_set_abs_params(input_dev, ABS_HAT0X, -1, 1, 0, 0); + input_set_abs_params(input_dev, ABS_HAT0X, -1, 1, 0, 0); serio_set_drvdata(serio, warrior); err = serio_open(serio, drv); - if (err) { - serio_set_drvdata(serio, NULL); - kfree(warrior); - return err; - } - - input_register_device(&warrior->dev); - - printk(KERN_INFO "input: Logitech WingMan Warrior on %s\n", serio->phys); + if (err) + goto fail; + input_register_device(warrior->dev); return 0; + + fail: serio_set_drvdata(serio, NULL); + input_free_device(input_dev); + kfree(warrior); + return err; } /* diff --git a/drivers/input/keyboard/amikbd.c b/drivers/input/keyboard/amikbd.c index 4e8e8ea214ab..4c8fb1f8631f 100644 --- a/drivers/input/keyboard/amikbd.c +++ b/drivers/input/keyboard/amikbd.c @@ -155,10 +155,7 @@ static const char *amikbd_messages[8] = { [7] = KERN_WARNING "amikbd: keyboard interrupt\n" }; -static struct input_dev amikbd_dev; - -static char *amikbd_name = "Amiga keyboard"; -static char *amikbd_phys = "amikbd/input0"; +static struct input_dev *amikbd_dev; static irqreturn_t amikbd_interrupt(int irq, void *dummy, struct pt_regs *fp) { @@ -176,16 +173,16 @@ static irqreturn_t amikbd_interrupt(int irq, void *dummy, struct pt_regs *fp) scancode = amikbd_keycode[scancode]; - input_regs(&amikbd_dev, fp); + input_regs(amikbd_dev, fp); if (scancode == KEY_CAPSLOCK) { /* CapsLock is a toggle switch key on Amiga */ - input_report_key(&amikbd_dev, scancode, 1); - input_report_key(&amikbd_dev, scancode, 0); - input_sync(&amikbd_dev); + input_report_key(amikbd_dev, scancode, 1); + input_report_key(amikbd_dev, scancode, 0); } else { - input_report_key(&amikbd_dev, scancode, down); - input_sync(&amikbd_dev); + input_report_key(amikbd_dev, scancode, down); } + + input_sync(amikbd_dev); } else /* scancodes >= 0x78 are error codes */ printk(amikbd_messages[scancode - 0x78]); @@ -202,39 +199,41 @@ static int __init amikbd_init(void) if (!request_mem_region(CIAA_PHYSADDR-1+0xb00, 0x100, "amikeyb")) return -EBUSY; - init_input_dev(&amikbd_dev); - - amikbd_dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP); - amikbd_dev.keycode = amikbd_keycode; - amikbd_dev.keycodesize = sizeof(unsigned char); - amikbd_dev.keycodemax = ARRAY_SIZE(amikbd_keycode); + amikbd_dev = input_allocate_device(); + if (!amikbd_dev) { + printk(KERN_ERR "amikbd: not enough memory for input device\n"); + release_mem_region(CIAA_PHYSADDR - 1 + 0xb00, 0x100); + return -ENOMEM; + } + + amikbd_dev->name = "Amiga Keyboard"; + amikbd_dev->phys = "amikbd/input0"; + amikbd_dev->id.bustype = BUS_AMIGA; + amikbd_dev->id.vendor = 0x0001; + amikbd_dev->id.product = 0x0001; + amikbd_dev->id.version = 0x0100; + + amikbd_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP); + amikbd_dev->keycode = amikbd_keycode; + amikbd_dev->keycodesize = sizeof(unsigned char); + amikbd_dev->keycodemax = ARRAY_SIZE(amikbd_keycode); for (i = 0; i < 0x78; i++) if (amikbd_keycode[i]) - set_bit(amikbd_keycode[i], amikbd_dev.keybit); + set_bit(amikbd_keycode[i], amikbd_dev->keybit); ciaa.cra &= ~0x41; /* serial data in, turn off TA */ request_irq(IRQ_AMIGA_CIAA_SP, amikbd_interrupt, 0, "amikbd", amikbd_interrupt); - amikbd_dev.name = amikbd_name; - amikbd_dev.phys = amikbd_phys; - amikbd_dev.id.bustype = BUS_AMIGA; - amikbd_dev.id.vendor = 0x0001; - amikbd_dev.id.product = 0x0001; - amikbd_dev.id.version = 0x0100; - - input_register_device(&amikbd_dev); - - printk(KERN_INFO "input: %s\n", amikbd_name); - + input_register_device(amikbd_dev); return 0; } static void __exit amikbd_exit(void) { - input_unregister_device(&amikbd_dev); free_irq(IRQ_AMIGA_CIAA_SP, amikbd_interrupt); - release_mem_region(CIAA_PHYSADDR-1+0xb00, 0x100); + input_unregister_device(amikbd_dev); + release_mem_region(CIAA_PHYSADDR - 1 + 0xb00, 0x100); } module_init(amikbd_init); diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index 1ad8c2ee7dbf..820c7fd9a604 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c @@ -185,12 +185,12 @@ static struct { struct atkbd { - struct ps2dev ps2dev; + struct ps2dev ps2dev; + struct input_dev *dev; /* Written only during init */ char name[64]; char phys[32]; - struct input_dev dev; unsigned short id; unsigned char keycode[512]; @@ -290,7 +290,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, if (!atkbd->enabled) goto out; - input_event(&atkbd->dev, EV_MSC, MSC_RAW, code); + input_event(atkbd->dev, EV_MSC, MSC_RAW, code); if (atkbd->translated) { @@ -326,10 +326,10 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, atkbd->release = 1; goto out; case ATKBD_RET_HANGUEL: - atkbd_report_key(&atkbd->dev, regs, KEY_HANGUEL, 3); + atkbd_report_key(atkbd->dev, regs, KEY_HANGUEL, 3); goto out; case ATKBD_RET_HANJA: - atkbd_report_key(&atkbd->dev, regs, KEY_HANJA, 3); + atkbd_report_key(atkbd->dev, regs, KEY_HANJA, 3); goto out; case ATKBD_RET_ERR: printk(KERN_DEBUG "atkbd.c: Keyboard on %s reports too many keys pressed.\n", serio->phys); @@ -345,7 +345,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, } if (atkbd->keycode[code] != ATKBD_KEY_NULL) - input_event(&atkbd->dev, EV_MSC, MSC_SCAN, code); + input_event(atkbd->dev, EV_MSC, MSC_SCAN, code); switch (atkbd->keycode[code]) { case ATKBD_KEY_NULL: @@ -365,7 +365,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, "to make it known.\n", code & 0x80 ? "e0" : "", code & 0x7f); } - input_sync(&atkbd->dev); + input_sync(atkbd->dev); break; case ATKBD_SCR_1: scroll = 1 - atkbd->release * 2; @@ -390,7 +390,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, break; default: value = atkbd->release ? 0 : - (1 + (!atkbd->softrepeat && test_bit(atkbd->keycode[code], atkbd->dev.key))); + (1 + (!atkbd->softrepeat && test_bit(atkbd->keycode[code], atkbd->dev->key))); switch (value) { /* Workaround Toshiba laptop multiple keypress */ case 0: @@ -398,7 +398,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, break; case 1: atkbd->last = code; - atkbd->time = jiffies + msecs_to_jiffies(atkbd->dev.rep[REP_DELAY]) / 2; + atkbd->time = jiffies + msecs_to_jiffies(atkbd->dev->rep[REP_DELAY]) / 2; break; case 2: if (!time_after(jiffies, atkbd->time) && atkbd->last == code) @@ -406,16 +406,16 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, break; } - atkbd_report_key(&atkbd->dev, regs, atkbd->keycode[code], value); + atkbd_report_key(atkbd->dev, regs, atkbd->keycode[code], value); } if (atkbd->scroll) { - input_regs(&atkbd->dev, regs); + input_regs(atkbd->dev, regs); if (click != -1) - input_report_key(&atkbd->dev, BTN_MIDDLE, click); - input_report_rel(&atkbd->dev, REL_WHEEL, scroll); - input_report_rel(&atkbd->dev, REL_HWHEEL, hscroll); - input_sync(&atkbd->dev); + input_report_key(atkbd->dev, BTN_MIDDLE, click); + input_report_rel(atkbd->dev, REL_WHEEL, scroll); + input_report_rel(atkbd->dev, REL_HWHEEL, hscroll); + input_sync(atkbd->dev); } atkbd->release = 0; @@ -463,7 +463,6 @@ static int atkbd_event(struct input_dev *dev, unsigned int type, unsigned int co return 0; - case EV_REP: if (atkbd->softrepeat) return 0; @@ -693,7 +692,7 @@ static void atkbd_disconnect(struct serio *serio) device_remove_file(&serio->dev, &atkbd_attr_softrepeat); device_remove_file(&serio->dev, &atkbd_attr_softraw); - input_unregister_device(&atkbd->dev); + input_unregister_device(atkbd->dev); serio_close(serio); serio_set_drvdata(serio, NULL); kfree(atkbd); @@ -701,7 +700,7 @@ static void atkbd_disconnect(struct serio *serio) /* - * atkbd_set_device_attrs() initializes keyboard's keycode table + * atkbd_set_keycode_table() initializes keyboard's keycode table * according to the selected scancode set */ @@ -737,53 +736,58 @@ static void atkbd_set_keycode_table(struct atkbd *atkbd) static void atkbd_set_device_attrs(struct atkbd *atkbd) { + struct input_dev *input_dev = atkbd->dev; int i; - memset(&atkbd->dev, 0, sizeof(struct input_dev)); + if (atkbd->extra) + sprintf(atkbd->name, "AT Set 2 Extra keyboard"); + else + sprintf(atkbd->name, "AT %s Set %d keyboard", + atkbd->translated ? "Translated" : "Raw", atkbd->set); - init_input_dev(&atkbd->dev); + sprintf(atkbd->phys, "%s/input0", atkbd->ps2dev.serio->phys); - atkbd->dev.name = atkbd->name; - atkbd->dev.phys = atkbd->phys; - atkbd->dev.id.bustype = BUS_I8042; - atkbd->dev.id.vendor = 0x0001; - atkbd->dev.id.product = atkbd->translated ? 1 : atkbd->set; - atkbd->dev.id.version = atkbd->id; - atkbd->dev.event = atkbd_event; - atkbd->dev.private = atkbd; - atkbd->dev.dev = &atkbd->ps2dev.serio->dev; + input_dev->name = atkbd->name; + input_dev->phys = atkbd->phys; + input_dev->id.bustype = BUS_I8042; + input_dev->id.vendor = 0x0001; + input_dev->id.product = atkbd->translated ? 1 : atkbd->set; + input_dev->id.version = atkbd->id; + input_dev->event = atkbd_event; + input_dev->private = atkbd; + input_dev->cdev.dev = &atkbd->ps2dev.serio->dev; - atkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_MSC); + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_MSC); if (atkbd->write) { - atkbd->dev.evbit[0] |= BIT(EV_LED); - atkbd->dev.ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL); + input_dev->evbit[0] |= BIT(EV_LED); + input_dev->ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL); } if (atkbd->extra) - atkbd->dev.ledbit[0] |= BIT(LED_COMPOSE) | BIT(LED_SUSPEND) | + input_dev->ledbit[0] |= BIT(LED_COMPOSE) | BIT(LED_SUSPEND) | BIT(LED_SLEEP) | BIT(LED_MUTE) | BIT(LED_MISC); if (!atkbd->softrepeat) { - atkbd->dev.rep[REP_DELAY] = 250; - atkbd->dev.rep[REP_PERIOD] = 33; + input_dev->rep[REP_DELAY] = 250; + input_dev->rep[REP_PERIOD] = 33; } - atkbd->dev.mscbit[0] = atkbd->softraw ? BIT(MSC_SCAN) : BIT(MSC_RAW) | BIT(MSC_SCAN); + input_dev->mscbit[0] = atkbd->softraw ? BIT(MSC_SCAN) : BIT(MSC_RAW) | BIT(MSC_SCAN); if (atkbd->scroll) { - atkbd->dev.evbit[0] |= BIT(EV_REL); - atkbd->dev.relbit[0] = BIT(REL_WHEEL) | BIT(REL_HWHEEL); - set_bit(BTN_MIDDLE, atkbd->dev.keybit); + input_dev->evbit[0] |= BIT(EV_REL); + input_dev->relbit[0] = BIT(REL_WHEEL) | BIT(REL_HWHEEL); + set_bit(BTN_MIDDLE, input_dev->keybit); } - atkbd->dev.keycode = atkbd->keycode; - atkbd->dev.keycodesize = sizeof(unsigned char); - atkbd->dev.keycodemax = ARRAY_SIZE(atkbd_set2_keycode); + input_dev->keycode = atkbd->keycode; + input_dev->keycodesize = sizeof(unsigned char); + input_dev->keycodemax = ARRAY_SIZE(atkbd_set2_keycode); for (i = 0; i < 512; i++) if (atkbd->keycode[i] && atkbd->keycode[i] < ATKBD_SPECIAL) - set_bit(atkbd->keycode[i], atkbd->dev.keybit); + set_bit(atkbd->keycode[i], input_dev->keybit); } /* @@ -796,13 +800,15 @@ static void atkbd_set_device_attrs(struct atkbd *atkbd) static int atkbd_connect(struct serio *serio, struct serio_driver *drv) { struct atkbd *atkbd; - int err; - - if (!(atkbd = kmalloc(sizeof(struct atkbd), GFP_KERNEL))) - return - ENOMEM; + struct input_dev *dev; + int err = -ENOMEM; - memset(atkbd, 0, sizeof(struct atkbd)); + atkbd = kzalloc(sizeof(struct atkbd), GFP_KERNEL); + dev = input_allocate_device(); + if (!atkbd || !dev) + goto fail; + atkbd->dev = dev; ps2_init(&atkbd->ps2dev, serio); switch (serio->id.type) { @@ -828,19 +834,15 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv) serio_set_drvdata(serio, atkbd); err = serio_open(serio, drv); - if (err) { - serio_set_drvdata(serio, NULL); - kfree(atkbd); - return err; - } + if (err) + goto fail; if (atkbd->write) { if (atkbd_probe(atkbd)) { serio_close(serio); - serio_set_drvdata(serio, NULL); - kfree(atkbd); - return -ENODEV; + err = -ENODEV; + goto fail; } atkbd->set = atkbd_select_set(atkbd, atkbd_set, atkbd_extra); @@ -851,19 +853,9 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv) atkbd->id = 0xab00; } - if (atkbd->extra) - sprintf(atkbd->name, "AT Set 2 Extra keyboard"); - else - sprintf(atkbd->name, "AT %s Set %d keyboard", - atkbd->translated ? "Translated" : "Raw", atkbd->set); - - sprintf(atkbd->phys, "%s/input0", serio->phys); - atkbd_set_keycode_table(atkbd); atkbd_set_device_attrs(atkbd); - input_register_device(&atkbd->dev); - device_create_file(&serio->dev, &atkbd_attr_extra); device_create_file(&serio->dev, &atkbd_attr_scroll); device_create_file(&serio->dev, &atkbd_attr_set); @@ -872,9 +864,14 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv) atkbd_enable(atkbd); - printk(KERN_INFO "input: %s on %s\n", atkbd->name, serio->phys); + input_register_device(atkbd->dev); return 0; + + fail: serio_set_drvdata(serio, NULL); + input_free_device(dev); + kfree(atkbd); + return err; } /* @@ -896,9 +893,9 @@ static int atkbd_reconnect(struct serio *serio) atkbd_disable(atkbd); if (atkbd->write) { - param[0] = (test_bit(LED_SCROLLL, atkbd->dev.led) ? 1 : 0) - | (test_bit(LED_NUML, atkbd->dev.led) ? 2 : 0) - | (test_bit(LED_CAPSL, atkbd->dev.led) ? 4 : 0); + param[0] = (test_bit(LED_SCROLLL, atkbd->dev->led) ? 1 : 0) + | (test_bit(LED_NUML, atkbd->dev->led) ? 2 : 0) + | (test_bit(LED_CAPSL, atkbd->dev->led) ? 4 : 0); if (atkbd_probe(atkbd)) return -1; @@ -1008,6 +1005,7 @@ static ssize_t atkbd_show_extra(struct atkbd *atkbd, char *buf) static ssize_t atkbd_set_extra(struct atkbd *atkbd, const char *buf, size_t count) { + struct input_dev *new_dev; unsigned long value; char *rest; @@ -1019,12 +1017,19 @@ static ssize_t atkbd_set_extra(struct atkbd *atkbd, const char *buf, size_t coun return -EINVAL; if (atkbd->extra != value) { - /* unregister device as it's properties will change */ - input_unregister_device(&atkbd->dev); + /* + * Since device's properties will change we need to + * unregister old device. But allocate new one first + * to make sure we have it. + */ + if (!(new_dev = input_allocate_device())) + return -ENOMEM; + input_unregister_device(atkbd->dev); + atkbd->dev = new_dev; atkbd->set = atkbd_select_set(atkbd, atkbd->set, value); atkbd_activate(atkbd); atkbd_set_device_attrs(atkbd); - input_register_device(&atkbd->dev); + input_register_device(atkbd->dev); } return count; } @@ -1036,6 +1041,7 @@ static ssize_t atkbd_show_scroll(struct atkbd *atkbd, char *buf) static ssize_t atkbd_set_scroll(struct atkbd *atkbd, const char *buf, size_t count) { + struct input_dev *new_dev; unsigned long value; char *rest; @@ -1044,12 +1050,14 @@ static ssize_t atkbd_set_scroll(struct atkbd *atkbd, const char *buf, size_t cou return -EINVAL; if (atkbd->scroll != value) { - /* unregister device as it's properties will change */ - input_unregister_device(&atkbd->dev); + if (!(new_dev = input_allocate_device())) + return -ENOMEM; + input_unregister_device(atkbd->dev); + atkbd->dev = new_dev; atkbd->scroll = value; atkbd_set_keycode_table(atkbd); atkbd_set_device_attrs(atkbd); - input_register_device(&atkbd->dev); + input_register_device(atkbd->dev); } return count; } @@ -1061,6 +1069,7 @@ static ssize_t atkbd_show_set(struct atkbd *atkbd, char *buf) static ssize_t atkbd_set_set(struct atkbd *atkbd, const char *buf, size_t count) { + struct input_dev *new_dev; unsigned long value; char *rest; @@ -1072,13 +1081,15 @@ static ssize_t atkbd_set_set(struct atkbd *atkbd, const char *buf, size_t count) return -EINVAL; if (atkbd->set != value) { - /* unregister device as it's properties will change */ - input_unregister_device(&atkbd->dev); + if (!(new_dev = input_allocate_device())) + return -ENOMEM; + input_unregister_device(atkbd->dev); + atkbd->dev = new_dev; atkbd->set = atkbd_select_set(atkbd, value, atkbd->extra); atkbd_activate(atkbd); atkbd_set_keycode_table(atkbd); atkbd_set_device_attrs(atkbd); - input_register_device(&atkbd->dev); + input_register_device(atkbd->dev); } return count; } @@ -1090,6 +1101,7 @@ static ssize_t atkbd_show_softrepeat(struct atkbd *atkbd, char *buf) static ssize_t atkbd_set_softrepeat(struct atkbd *atkbd, const char *buf, size_t count) { + struct input_dev *new_dev; unsigned long value; char *rest; @@ -1101,15 +1113,16 @@ static ssize_t atkbd_set_softrepeat(struct atkbd *atkbd, const char *buf, size_t return -EINVAL; if (atkbd->softrepeat != value) { - /* unregister device as it's properties will change */ - input_unregister_device(&atkbd->dev); + if (!(new_dev = input_allocate_device())) + return -ENOMEM; + input_unregister_device(atkbd->dev); + atkbd->dev = new_dev; atkbd->softrepeat = value; if (atkbd->softrepeat) atkbd->softraw = 1; atkbd_set_device_attrs(atkbd); - input_register_device(&atkbd->dev); + input_register_device(atkbd->dev); } - return count; } @@ -1121,6 +1134,7 @@ static ssize_t atkbd_show_softraw(struct atkbd *atkbd, char *buf) static ssize_t atkbd_set_softraw(struct atkbd *atkbd, const char *buf, size_t count) { + struct input_dev *new_dev; unsigned long value; char *rest; @@ -1129,11 +1143,13 @@ static ssize_t atkbd_set_softraw(struct atkbd *atkbd, const char *buf, size_t co return -EINVAL; if (atkbd->softraw != value) { - /* unregister device as it's properties will change */ - input_unregister_device(&atkbd->dev); + if (!(new_dev = input_allocate_device())) + return -ENOMEM; + input_unregister_device(atkbd->dev); + atkbd->dev = new_dev; atkbd->softraw = value; atkbd_set_device_attrs(atkbd); - input_register_device(&atkbd->dev); + input_register_device(atkbd->dev); } return count; } diff --git a/drivers/input/keyboard/corgikbd.c b/drivers/input/keyboard/corgikbd.c index cd4b6e795013..3210d298b3bc 100644 --- a/drivers/input/keyboard/corgikbd.c +++ b/drivers/input/keyboard/corgikbd.c @@ -70,8 +70,7 @@ static unsigned char corgikbd_keycode[NR_SCANCODES] = { struct corgikbd { unsigned char keycode[ARRAY_SIZE(corgikbd_keycode)]; - struct input_dev input; - char phys[32]; + struct input_dev *input; spinlock_t lock; struct timer_list timer; @@ -147,7 +146,7 @@ static void corgikbd_scankeyboard(struct corgikbd *corgikbd_data, struct pt_regs spin_lock_irqsave(&corgikbd_data->lock, flags); if (regs) - input_regs(&corgikbd_data->input, regs); + input_regs(corgikbd_data->input, regs); num_pressed = 0; for (col = 0; col < KB_COLS; col++) { @@ -169,14 +168,14 @@ static void corgikbd_scankeyboard(struct corgikbd *corgikbd_data, struct pt_regs scancode = SCANCODE(row, col); pressed = rowd & KB_ROWMASK(row); - input_report_key(&corgikbd_data->input, corgikbd_data->keycode[scancode], pressed); + input_report_key(corgikbd_data->input, corgikbd_data->keycode[scancode], pressed); if (pressed) num_pressed++; if (pressed && (corgikbd_data->keycode[scancode] == CORGI_KEY_OFF) && time_after(jiffies, corgikbd_data->suspend_jiffies + HZ)) { - input_event(&corgikbd_data->input, EV_PWR, CORGI_KEY_OFF, 1); + input_event(corgikbd_data->input, EV_PWR, CORGI_KEY_OFF, 1); corgikbd_data->suspend_jiffies=jiffies; } } @@ -185,7 +184,7 @@ static void corgikbd_scankeyboard(struct corgikbd *corgikbd_data, struct pt_regs corgikbd_activate_all(); - input_sync(&corgikbd_data->input); + input_sync(corgikbd_data->input); /* if any keys are pressed, enable the timer */ if (num_pressed) @@ -249,9 +248,9 @@ static void corgikbd_hinge_timer(unsigned long data) if (hinge_count >= HINGE_STABLE_COUNT) { spin_lock_irqsave(&corgikbd_data->lock, flags); - input_report_switch(&corgikbd_data->input, SW_0, ((sharpsl_hinge_state & CORGI_SCP_SWA) != 0)); - input_report_switch(&corgikbd_data->input, SW_1, ((sharpsl_hinge_state & CORGI_SCP_SWB) != 0)); - input_sync(&corgikbd_data->input); + input_report_switch(corgikbd_data->input, SW_0, ((sharpsl_hinge_state & CORGI_SCP_SWA) != 0)); + input_report_switch(corgikbd_data->input, SW_1, ((sharpsl_hinge_state & CORGI_SCP_SWB) != 0)); + input_sync(corgikbd_data->input); spin_unlock_irqrestore(&corgikbd_data->lock, flags); } @@ -260,24 +259,22 @@ static void corgikbd_hinge_timer(unsigned long data) } #ifdef CONFIG_PM -static int corgikbd_suspend(struct device *dev, pm_message_t state, uint32_t level) +static int corgikbd_suspend(struct device *dev, pm_message_t state) { - if (level == SUSPEND_POWER_DOWN) { - struct corgikbd *corgikbd = dev_get_drvdata(dev); - corgikbd->suspended = 1; - } + struct corgikbd *corgikbd = dev_get_drvdata(dev); + corgikbd->suspended = 1; + return 0; } -static int corgikbd_resume(struct device *dev, uint32_t level) +static int corgikbd_resume(struct device *dev) { - if (level == RESUME_POWER_ON) { - struct corgikbd *corgikbd = dev_get_drvdata(dev); + struct corgikbd *corgikbd = dev_get_drvdata(dev); + + /* Upon resume, ignore the suspend key for a short while */ + corgikbd->suspend_jiffies=jiffies; + corgikbd->suspended = 0; - /* Upon resume, ignore the suspend key for a short while */ - corgikbd->suspend_jiffies=jiffies; - corgikbd->suspended = 0; - } return 0; } #else @@ -287,16 +284,21 @@ static int corgikbd_resume(struct device *dev, uint32_t level) static int __init corgikbd_probe(struct device *dev) { - int i; struct corgikbd *corgikbd; + struct input_dev *input_dev; + int i; corgikbd = kzalloc(sizeof(struct corgikbd), GFP_KERNEL); - if (!corgikbd) + input_dev = input_allocate_device(); + if (!corgikbd || !input_dev) { + kfree(corgikbd); + input_free_device(input_dev); return -ENOMEM; + } - dev_set_drvdata(dev,corgikbd); - strcpy(corgikbd->phys, "corgikbd/input0"); + dev_set_drvdata(dev, corgikbd); + corgikbd->input = input_dev; spin_lock_init(&corgikbd->lock); /* Init Keyboard rescan timer */ @@ -311,28 +313,30 @@ static int __init corgikbd_probe(struct device *dev) corgikbd->suspend_jiffies=jiffies; - init_input_dev(&corgikbd->input); - corgikbd->input.private = corgikbd; - corgikbd->input.name = "Corgi Keyboard"; - corgikbd->input.dev = dev; - corgikbd->input.phys = corgikbd->phys; - corgikbd->input.id.bustype = BUS_HOST; - corgikbd->input.id.vendor = 0x0001; - corgikbd->input.id.product = 0x0001; - corgikbd->input.id.version = 0x0100; - corgikbd->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_PWR) | BIT(EV_SW); - corgikbd->input.keycode = corgikbd->keycode; - corgikbd->input.keycodesize = sizeof(unsigned char); - corgikbd->input.keycodemax = ARRAY_SIZE(corgikbd_keycode); - memcpy(corgikbd->keycode, corgikbd_keycode, sizeof(corgikbd->keycode)); + + input_dev->name = "Corgi Keyboard"; + input_dev->phys = "corgikbd/input0"; + input_dev->id.bustype = BUS_HOST; + input_dev->id.vendor = 0x0001; + input_dev->id.product = 0x0001; + input_dev->id.version = 0x0100; + input_dev->cdev.dev = dev; + input_dev->private = corgikbd; + + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_PWR) | BIT(EV_SW); + input_dev->keycode = corgikbd->keycode; + input_dev->keycodesize = sizeof(unsigned char); + input_dev->keycodemax = ARRAY_SIZE(corgikbd_keycode); + for (i = 0; i < ARRAY_SIZE(corgikbd_keycode); i++) - set_bit(corgikbd->keycode[i], corgikbd->input.keybit); - clear_bit(0, corgikbd->input.keybit); - set_bit(SW_0, corgikbd->input.swbit); - set_bit(SW_1, corgikbd->input.swbit); + set_bit(corgikbd->keycode[i], input_dev->keybit); + clear_bit(0, input_dev->keybit); + set_bit(SW_0, input_dev->swbit); + set_bit(SW_1, input_dev->swbit); + + input_register_device(corgikbd->input); - input_register_device(&corgikbd->input); mod_timer(&corgikbd->htimer, jiffies + HINGE_SCAN_INTERVAL); /* Setup sense interrupts - RisingEdge Detect, sense lines as inputs */ @@ -349,8 +353,6 @@ static int __init corgikbd_probe(struct device *dev) for (i = 0; i < CORGI_KEY_STROBE_NUM; i++) pxa_gpio_mode(CORGI_GPIO_KEY_STROBE(i) | GPIO_OUT | GPIO_DFLT_HIGH); - printk(KERN_INFO "input: Corgi Keyboard Registered\n"); - return 0; } @@ -365,7 +367,7 @@ static int corgikbd_remove(struct device *dev) del_timer_sync(&corgikbd->htimer); del_timer_sync(&corgikbd->timer); - input_unregister_device(&corgikbd->input); + input_unregister_device(corgikbd->input); kfree(corgikbd); diff --git a/drivers/input/keyboard/hil_kbd.c b/drivers/input/keyboard/hil_kbd.c index ef78bffed5e7..0a90962c38e7 100644 --- a/drivers/input/keyboard/hil_kbd.c +++ b/drivers/input/keyboard/hil_kbd.c @@ -204,7 +204,7 @@ static irqreturn_t hil_kbd_interrupt(struct serio *serio, hil_packet packet; int idx; - kbd = (struct hil_kbd *)serio->private; + kbd = serio_get_drvdata(serio); if (kbd == NULL) { BUG(); return IRQ_HANDLED; @@ -234,7 +234,7 @@ static void hil_kbd_disconnect(struct serio *serio) { struct hil_kbd *kbd; - kbd = (struct hil_kbd *)serio->private; + kbd = serio_get_drvdata(serio); if (kbd == NULL) { BUG(); return; @@ -245,20 +245,20 @@ static void hil_kbd_disconnect(struct serio *serio) kfree(kbd); } -static void hil_kbd_connect(struct serio *serio, struct serio_driver *drv) +static int hil_kbd_connect(struct serio *serio, struct serio_driver *drv) { struct hil_kbd *kbd; uint8_t did, *idd; int i; - if (serio->type != (SERIO_HIL_MLC | SERIO_HIL)) return; - - if (!(kbd = kmalloc(sizeof(struct hil_kbd), GFP_KERNEL))) return; + kbd = kmalloc(sizeof(*kbd), GFP_KERNEL); + if (!kbd) + return -ENOMEM; memset(kbd, 0, sizeof(struct hil_kbd)); if (serio_open(serio, drv)) goto bail0; - serio->private = kbd; + serio_set_drvdata(serio, kbd); kbd->serio = serio; kbd->dev.private = kbd; @@ -342,19 +342,31 @@ static void hil_kbd_connect(struct serio *serio, struct serio_driver *drv) down(&(kbd->sem)); up(&(kbd->sem)); - return; + return 0; bail1: serio_close(serio); bail0: kfree(kbd); + serio_set_drvdata(serio, NULL); + return -EIO; } +static struct serio_device_id hil_kbd_ids[] = { + { + .type = SERIO_HIL_MLC, + .proto = SERIO_HIL, + .id = SERIO_ANY, + .extra = SERIO_ANY, + }, + { 0 } +}; struct serio_driver hil_kbd_serio_drv = { .driver = { .name = "hil_kbd", }, .description = "HP HIL keyboard driver", + .id_table = hil_kbd_ids, .connect = hil_kbd_connect, .disconnect = hil_kbd_disconnect, .interrupt = hil_kbd_interrupt diff --git a/drivers/input/keyboard/hilkbd.c b/drivers/input/keyboard/hilkbd.c index eecb77db0847..e95bc052e32a 100644 --- a/drivers/input/keyboard/hilkbd.c +++ b/drivers/input/keyboard/hilkbd.c @@ -22,7 +22,7 @@ #include <linux/errno.h> #include <linux/input.h> #include <linux/init.h> -#include <linux/irq.h> +#include <linux/interrupt.h> #include <linux/hil.h> #include <linux/spinlock.h> @@ -278,11 +278,11 @@ static int __init hil_init_chip(struct parisc_device *dev) { if (!dev->irq) { - printk(KERN_WARNING "HIL: IRQ not found for HIL bus at 0x%08lx\n", dev->hpa); + printk(KERN_WARNING "HIL: IRQ not found for HIL bus at 0x%08lx\n", dev->hpa.start); return -ENODEV; } - hil_base = dev->hpa; + hil_base = dev->hpa.start; hil_irq = dev->irq; hil_dev.dev_id = dev; @@ -299,7 +299,7 @@ static struct parisc_device_id hil_tbl[] = { MODULE_DEVICE_TABLE(parisc, hil_tbl); static struct parisc_driver hil_driver = { - .name = "HIL", + .name = "hil", .id_table = hil_tbl, .probe = hil_init_chip, }; diff --git a/drivers/input/keyboard/lkkbd.c b/drivers/input/keyboard/lkkbd.c index 098963c7cdd6..7f06780a437f 100644 --- a/drivers/input/keyboard/lkkbd.c +++ b/drivers/input/keyboard/lkkbd.c @@ -102,7 +102,7 @@ static int ctrlclick_volume = 100; /* % */ module_param (ctrlclick_volume, int, 0); MODULE_PARM_DESC (ctrlclick_volume, "Ctrlclick volume (in %), default is 100%"); -static int lk201_compose_is_alt = 0; +static int lk201_compose_is_alt; module_param (lk201_compose_is_alt, int, 0); MODULE_PARM_DESC (lk201_compose_is_alt, "If set non-zero, LK201' Compose key " "will act as an Alt key"); @@ -274,7 +274,7 @@ static lk_keycode_t lkkbd_keycode[LK_NUM_KEYCODES] = { }; #define CHECK_LED(LED, BITS) do { \ - if (test_bit (LED, lk->dev.led)) \ + if (test_bit (LED, lk->dev->led)) \ leds_on |= BITS; \ else \ leds_off |= BITS; \ @@ -287,7 +287,7 @@ struct lkkbd { lk_keycode_t keycode[LK_NUM_KEYCODES]; int ignore_bytes; unsigned char id[LK_NUM_IGNORE_BYTES]; - struct input_dev dev; + struct input_dev *dev; struct serio *serio; struct work_struct tq; char name[64]; @@ -423,8 +423,7 @@ lkkbd_interrupt (struct serio *serio, unsigned char data, unsigned int flags, DBG (KERN_INFO "Got byte 0x%02x\n", data); if (lk->ignore_bytes > 0) { - DBG (KERN_INFO "Ignoring a byte on %s\n", - lk->name); + DBG (KERN_INFO "Ignoring a byte on %s\n", lk->name); lk->id[LK_NUM_IGNORE_BYTES - lk->ignore_bytes--] = data; if (lk->ignore_bytes == 0) @@ -435,14 +434,14 @@ lkkbd_interrupt (struct serio *serio, unsigned char data, unsigned int flags, switch (data) { case LK_ALL_KEYS_UP: - input_regs (&lk->dev, regs); + input_regs (lk->dev, regs); for (i = 0; i < ARRAY_SIZE (lkkbd_keycode); i++) if (lk->keycode[i] != KEY_RESERVED) - input_report_key (&lk->dev, lk->keycode[i], 0); - input_sync (&lk->dev); + input_report_key (lk->dev, lk->keycode[i], 0); + input_sync (lk->dev); break; case LK_METRONOME: - DBG (KERN_INFO "Got LK_METRONOME and don't " + DBG (KERN_INFO "Got %#d and don't " "know how to handle...\n"); break; case LK_OUTPUT_ERROR: @@ -482,12 +481,12 @@ lkkbd_interrupt (struct serio *serio, unsigned char data, unsigned int flags, default: if (lk->keycode[data] != KEY_RESERVED) { - input_regs (&lk->dev, regs); - if (!test_bit (lk->keycode[data], lk->dev.key)) - input_report_key (&lk->dev, lk->keycode[data], 1); + input_regs (lk->dev, regs); + if (!test_bit (lk->keycode[data], lk->dev->key)) + input_report_key (lk->dev, lk->keycode[data], 1); else - input_report_key (&lk->dev, lk->keycode[data], 0); - input_sync (&lk->dev); + input_report_key (lk->dev, lk->keycode[data], 0); + input_sync (lk->dev); } else printk (KERN_WARNING "%s: Unknown key with " "scancode 0x%02x on %s.\n", @@ -605,7 +604,7 @@ lkkbd_reinit (void *data) lk->serio->write (lk->serio, volume_to_hw (lk->bell_volume)); /* Enable/disable keyclick (and possibly set volume) */ - if (test_bit (SND_CLICK, lk->dev.snd)) { + if (test_bit (SND_CLICK, lk->dev->snd)) { lk->serio->write (lk->serio, LK_CMD_ENABLE_KEYCLICK); lk->serio->write (lk->serio, volume_to_hw (lk->keyclick_volume)); lk->serio->write (lk->serio, LK_CMD_ENABLE_CTRCLICK); @@ -616,7 +615,7 @@ lkkbd_reinit (void *data) } /* Sound the bell if needed */ - if (test_bit (SND_BELL, lk->dev.snd)) + if (test_bit (SND_BELL, lk->dev->snd)) lk->serio->write (lk->serio, LK_CMD_SOUND_BELL); } @@ -627,71 +626,70 @@ static int lkkbd_connect (struct serio *serio, struct serio_driver *drv) { struct lkkbd *lk; + struct input_dev *input_dev; int i; int err; - if (!(lk = kmalloc (sizeof (struct lkkbd), GFP_KERNEL))) - return -ENOMEM; - - memset (lk, 0, sizeof (struct lkkbd)); - - init_input_dev (&lk->dev); - set_bit (EV_KEY, lk->dev.evbit); - set_bit (EV_LED, lk->dev.evbit); - set_bit (EV_SND, lk->dev.evbit); - set_bit (EV_REP, lk->dev.evbit); - set_bit (LED_CAPSL, lk->dev.ledbit); - set_bit (LED_SLEEP, lk->dev.ledbit); - set_bit (LED_COMPOSE, lk->dev.ledbit); - set_bit (LED_SCROLLL, lk->dev.ledbit); - set_bit (SND_BELL, lk->dev.sndbit); - set_bit (SND_CLICK, lk->dev.sndbit); + lk = kzalloc (sizeof (struct lkkbd), GFP_KERNEL); + input_dev = input_allocate_device (); + if (!lk || !input_dev) { + err = -ENOMEM; + goto fail; + } lk->serio = serio; - + lk->dev = input_dev; INIT_WORK (&lk->tq, lkkbd_reinit, lk); - lk->bell_volume = bell_volume; lk->keyclick_volume = keyclick_volume; lk->ctrlclick_volume = ctrlclick_volume; + memcpy (lk->keycode, lkkbd_keycode, sizeof (lk_keycode_t) * LK_NUM_KEYCODES); - lk->dev.keycode = lk->keycode; - lk->dev.keycodesize = sizeof (lk_keycode_t); - lk->dev.keycodemax = LK_NUM_KEYCODES; - - lk->dev.event = lkkbd_event; - lk->dev.private = lk; + strlcpy (lk->name, "DEC LK keyboard", sizeof(lk->name)); + snprintf (lk->phys, sizeof(lk->phys), "%s/input0", serio->phys); + + input_dev->name = lk->name; + input_dev->phys = lk->phys; + input_dev->id.bustype = BUS_RS232; + input_dev->id.vendor = SERIO_LKKBD; + input_dev->id.product = 0; + input_dev->id.version = 0x0100; + input_dev->cdev.dev = &serio->dev; + input_dev->event = lkkbd_event; + input_dev->private = lk; + + set_bit (EV_KEY, input_dev->evbit); + set_bit (EV_LED, input_dev->evbit); + set_bit (EV_SND, input_dev->evbit); + set_bit (EV_REP, input_dev->evbit); + set_bit (LED_CAPSL, input_dev->ledbit); + set_bit (LED_SLEEP, input_dev->ledbit); + set_bit (LED_COMPOSE, input_dev->ledbit); + set_bit (LED_SCROLLL, input_dev->ledbit); + set_bit (SND_BELL, input_dev->sndbit); + set_bit (SND_CLICK, input_dev->sndbit); + + input_dev->keycode = lk->keycode; + input_dev->keycodesize = sizeof (lk_keycode_t); + input_dev->keycodemax = LK_NUM_KEYCODES; + for (i = 0; i < LK_NUM_KEYCODES; i++) + set_bit (lk->keycode[i], input_dev->keybit); serio_set_drvdata (serio, lk); err = serio_open (serio, drv); - if (err) { - serio_set_drvdata (serio, NULL); - kfree (lk); - return err; - } + if (err) + goto fail; - sprintf (lk->name, "DEC LK keyboard"); - sprintf (lk->phys, "%s/input0", serio->phys); - - memcpy (lk->keycode, lkkbd_keycode, sizeof (lk_keycode_t) * LK_NUM_KEYCODES); - for (i = 0; i < LK_NUM_KEYCODES; i++) - set_bit (lk->keycode[i], lk->dev.keybit); - - lk->dev.name = lk->name; - lk->dev.phys = lk->phys; - lk->dev.id.bustype = BUS_RS232; - lk->dev.id.vendor = SERIO_LKKBD; - lk->dev.id.product = 0; - lk->dev.id.version = 0x0100; - lk->dev.dev = &serio->dev; - - input_register_device (&lk->dev); - - printk (KERN_INFO "input: %s on %s, initiating reset\n", lk->name, serio->phys); + input_register_device (lk->dev); lk->serio->write (lk->serio, LK_CMD_POWERCYCLE_RESET); return 0; + + fail: serio_set_drvdata (serio, NULL); + input_free_device (input_dev); + kfree (lk); + return err; } /* @@ -702,9 +700,11 @@ lkkbd_disconnect (struct serio *serio) { struct lkkbd *lk = serio_get_drvdata (serio); - input_unregister_device (&lk->dev); + input_get_device (lk->dev); + input_unregister_device (lk->dev); serio_close (serio); serio_set_drvdata (serio, NULL); + input_put_device (lk->dev); kfree (lk); } diff --git a/drivers/input/keyboard/maple_keyb.c b/drivers/input/keyboard/maple_keyb.c index eecbde294f1f..cc6aaf9e85be 100644 --- a/drivers/input/keyboard/maple_keyb.c +++ b/drivers/input/keyboard/maple_keyb.c @@ -37,7 +37,7 @@ static unsigned char dc_kbd_keycode[256] = { struct dc_kbd { - struct input_dev dev; + struct input_dev *dev; unsigned char new[8]; unsigned char old[8]; }; @@ -46,30 +46,24 @@ struct dc_kbd { static void dc_scan_kbd(struct dc_kbd *kbd) { int i; - struct input_dev *dev = &kbd->dev; + struct input_dev *dev = kbd->dev; - for(i=0; i<8; i++) - input_report_key(dev, - dc_kbd_keycode[i+224], - (kbd->new[0]>>i)&1); + for (i = 0; i < 8; i++) + input_report_key(dev, dc_kbd_keycode[i + 224], (kbd->new[0] >> i) & 1); - for(i=2; i<8; i++) { + for (i = 2; i < 8; i++) { - if(kbd->old[i]>3&&memscan(kbd->new+2, kbd->old[i], 6)==NULL) { - if(dc_kbd_keycode[kbd->old[i]]) - input_report_key(dev, - dc_kbd_keycode[kbd->old[i]], - 0); + if (kbd->old[i] > 3 && memscan(kbd->new + 2, kbd->old[i], 6) == NULL) { + if (dc_kbd_keycode[kbd->old[i]]) + input_report_key(dev, dc_kbd_keycode[kbd->old[i]], 0); else printk("Unknown key (scancode %#x) released.", kbd->old[i]); } - if(kbd->new[i]>3&&memscan(kbd->old+2, kbd->new[i], 6)!=NULL) { + if (kbd->new[i] > 3 && memscan(kbd->old + 2, kbd->new[i], 6) != NULL) { if(dc_kbd_keycode[kbd->new[i]]) - input_report_key(dev, - dc_kbd_keycode[kbd->new[i]], - 1); + input_report_key(dev, dc_kbd_keycode[kbd->new[i]], 1); else printk("Unknown key (scancode %#x) pressed.", kbd->new[i]); @@ -89,43 +83,39 @@ static void dc_kbd_callback(struct mapleq *mq) unsigned long *buf = mq->recvbuf; if (buf[1] == mapledev->function) { - memcpy(kbd->new, buf+2, 8); + memcpy(kbd->new, buf + 2, 8); dc_scan_kbd(kbd); } } static int dc_kbd_connect(struct maple_device *dev) { - int i; - unsigned long data = be32_to_cpu(dev->devinfo.function_data[0]); struct dc_kbd *kbd; + struct input_dev *input_dev; + unsigned long data = be32_to_cpu(dev->devinfo.function_data[0]); + int i; - if (!(kbd = kmalloc(sizeof(struct dc_kbd), GFP_KERNEL))) - return -1; - memset(kbd, 0, sizeof(struct dc_kbd)); - - dev->private_data = kbd; - - kbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP); - - init_input_dev(&kbd->dev); - - for (i=0; i<255; i++) - set_bit(dc_kbd_keycode[i], kbd->dev.keybit); - - clear_bit(0, kbd->dev.keybit); + dev->private_data = kbd = kzalloc(sizeof(struct dc_kbd), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!kbd || !input_dev) { + kfree(kbd); + input_free_device(input_dev); + return -ENOMEM; + } - kbd->dev.private = kbd; + kbd->dev = input_dev; - kbd->dev.name = dev->product_name; - kbd->dev.id.bustype = BUS_MAPLE; + input_dev->name = dev->product_name; + input_dev->id.bustype = BUS_MAPLE; + input_dev->private = kbd; + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP); + for (i = 0; i < 255; i++) + set_bit(dc_kbd_keycode[i], input_dev->keybit); + clear_bit(0, input_dev->keybit); - input_register_device(&kbd->dev); + input_register_device(kbd->dev); maple_getcond_callback(dev, dc_kbd_callback, 1, MAPLE_FUNC_KEYBOARD); - - printk(KERN_INFO "input: keyboard(0x%lx): %s\n", data, kbd->dev.name); - return 0; } @@ -134,7 +124,7 @@ static void dc_kbd_disconnect(struct maple_device *dev) { struct dc_kbd *kbd = dev->private_data; - input_unregister_device(&kbd->dev); + input_unregister_device(kbd->dev); kfree(kbd); } diff --git a/drivers/input/keyboard/newtonkbd.c b/drivers/input/keyboard/newtonkbd.c index 2e8ce1613eec..d10983c521e6 100644 --- a/drivers/input/keyboard/newtonkbd.c +++ b/drivers/input/keyboard/newtonkbd.c @@ -57,11 +57,9 @@ static unsigned char nkbd_keycode[128] = { KEY_LEFT, KEY_RIGHT, KEY_DOWN, KEY_UP, 0 }; -static char *nkbd_name = "Newton Keyboard"; - struct nkbd { unsigned char keycode[128]; - struct input_dev dev; + struct input_dev *dev; struct serio *serio; char phys[32]; }; @@ -73,13 +71,13 @@ static irqreturn_t nkbd_interrupt(struct serio *serio, /* invalid scan codes are probably the init sequence, so we ignore them */ if (nkbd->keycode[data & NKBD_KEY]) { - input_regs(&nkbd->dev, regs); - input_report_key(&nkbd->dev, nkbd->keycode[data & NKBD_KEY], data & NKBD_PRESS); - input_sync(&nkbd->dev); + input_regs(nkbd->dev, regs); + input_report_key(nkbd->dev, nkbd->keycode[data & NKBD_KEY], data & NKBD_PRESS); + input_sync(nkbd->dev); } else if (data == 0xe7) /* end of init sequence */ - printk(KERN_INFO "input: %s on %s\n", nkbd_name, serio->phys); + printk(KERN_INFO "input: %s on %s\n", nkbd->dev->name, serio->phys); return IRQ_HANDLED; } @@ -87,62 +85,59 @@ static irqreturn_t nkbd_interrupt(struct serio *serio, static int nkbd_connect(struct serio *serio, struct serio_driver *drv) { struct nkbd *nkbd; + struct input_dev *input_dev; + int err = -ENOMEM; int i; - int err; - - if (!(nkbd = kmalloc(sizeof(struct nkbd), GFP_KERNEL))) - return -ENOMEM; - - memset(nkbd, 0, sizeof(struct nkbd)); - nkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP); + nkbd = kzalloc(sizeof(struct nkbd), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!nkbd || !input_dev) + goto fail; nkbd->serio = serio; + nkbd->dev = input_dev; + sprintf(nkbd->phys, "%s/input0", serio->phys); + memcpy(nkbd->keycode, nkbd_keycode, sizeof(nkbd->keycode)); - init_input_dev(&nkbd->dev); - nkbd->dev.keycode = nkbd->keycode; - nkbd->dev.keycodesize = sizeof(unsigned char); - nkbd->dev.keycodemax = ARRAY_SIZE(nkbd_keycode); - nkbd->dev.private = nkbd; + input_dev->name = "Newton Keyboard"; + input_dev->phys = nkbd->phys; + input_dev->id.bustype = BUS_RS232; + input_dev->id.vendor = SERIO_NEWTON; + input_dev->id.product = 0x0001; + input_dev->id.version = 0x0100; + input_dev->cdev.dev = &serio->dev; + input_dev->private = nkbd; + + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP); + input_dev->keycode = nkbd->keycode; + input_dev->keycodesize = sizeof(unsigned char); + input_dev->keycodemax = ARRAY_SIZE(nkbd_keycode); + for (i = 0; i < 128; i++) + set_bit(nkbd->keycode[i], input_dev->keybit); + clear_bit(0, input_dev->keybit); serio_set_drvdata(serio, nkbd); err = serio_open(serio, drv); - if (err) { - serio_set_drvdata(serio, NULL); - kfree(nkbd); - return err; - } - - memcpy(nkbd->keycode, nkbd_keycode, sizeof(nkbd->keycode)); - for (i = 0; i < 128; i++) - set_bit(nkbd->keycode[i], nkbd->dev.keybit); - clear_bit(0, nkbd->dev.keybit); - - sprintf(nkbd->phys, "%s/input0", serio->phys); - - nkbd->dev.name = nkbd_name; - nkbd->dev.phys = nkbd->phys; - nkbd->dev.id.bustype = BUS_RS232; - nkbd->dev.id.vendor = SERIO_NEWTON; - nkbd->dev.id.product = 0x0001; - nkbd->dev.id.version = 0x0100; - nkbd->dev.dev = &serio->dev; - - input_register_device(&nkbd->dev); - - printk(KERN_INFO "input: %s on %s\n", nkbd_name, serio->phys); + if (err) + goto fail; + input_register_device(nkbd->dev); return 0; + + fail: serio_set_drvdata(serio, NULL); + input_free_device(input_dev); + kfree(nkbd); + return err; } static void nkbd_disconnect(struct serio *serio) { struct nkbd *nkbd = serio_get_drvdata(serio); - input_unregister_device(&nkbd->dev); serio_close(serio); serio_set_drvdata(serio, NULL); + input_unregister_device(nkbd->dev); kfree(nkbd); } diff --git a/drivers/input/keyboard/spitzkbd.c b/drivers/input/keyboard/spitzkbd.c index 344f46005401..cee9c734a048 100644 --- a/drivers/input/keyboard/spitzkbd.c +++ b/drivers/input/keyboard/spitzkbd.c @@ -85,7 +85,7 @@ static int spitz_senses[] = { struct spitzkbd { unsigned char keycode[ARRAY_SIZE(spitzkbd_keycode)]; - struct input_dev input; + struct input_dev *input; char phys[32]; spinlock_t lock; @@ -187,8 +187,7 @@ static void spitzkbd_scankeyboard(struct spitzkbd *spitzkbd_data, struct pt_regs spin_lock_irqsave(&spitzkbd_data->lock, flags); - if (regs) - input_regs(&spitzkbd_data->input, regs); + input_regs(spitzkbd_data->input, regs); num_pressed = 0; for (col = 0; col < KB_COLS; col++) { @@ -210,7 +209,7 @@ static void spitzkbd_scankeyboard(struct spitzkbd *spitzkbd_data, struct pt_regs scancode = SCANCODE(row, col); pressed = rowd & KB_ROWMASK(row); - input_report_key(&spitzkbd_data->input, spitzkbd_data->keycode[scancode], pressed); + input_report_key(spitzkbd_data->input, spitzkbd_data->keycode[scancode], pressed); if (pressed) num_pressed++; @@ -220,15 +219,15 @@ static void spitzkbd_scankeyboard(struct spitzkbd *spitzkbd_data, struct pt_regs spitzkbd_activate_all(); - input_report_key(&spitzkbd_data->input, SPITZ_KEY_SYNC, (GPLR(SPITZ_GPIO_SYNC) & GPIO_bit(SPITZ_GPIO_SYNC)) != 0 ); - input_report_key(&spitzkbd_data->input, KEY_SUSPEND, pwrkey); + input_report_key(spitzkbd_data->input, SPITZ_KEY_SYNC, (GPLR(SPITZ_GPIO_SYNC) & GPIO_bit(SPITZ_GPIO_SYNC)) != 0 ); + input_report_key(spitzkbd_data->input, KEY_SUSPEND, pwrkey); if (pwrkey && time_after(jiffies, spitzkbd_data->suspend_jiffies + msecs_to_jiffies(1000))) { - input_event(&spitzkbd_data->input, EV_PWR, KEY_SUSPEND, 1); + input_event(spitzkbd_data->input, EV_PWR, KEY_SUSPEND, 1); spitzkbd_data->suspend_jiffies = jiffies; } - input_sync(&spitzkbd_data->input); + input_sync(spitzkbd_data->input); /* if any keys are pressed, enable the timer */ if (num_pressed) @@ -259,6 +258,7 @@ static irqreturn_t spitzkbd_interrupt(int irq, void *dev_id, struct pt_regs *reg static void spitzkbd_timer_callback(unsigned long data) { struct spitzkbd *spitzkbd_data = (struct spitzkbd *) data; + spitzkbd_scankeyboard(spitzkbd_data, NULL); } @@ -298,9 +298,9 @@ static void spitzkbd_hinge_timer(unsigned long data) if (hinge_count >= HINGE_STABLE_COUNT) { spin_lock_irqsave(&spitzkbd_data->lock, flags); - input_report_switch(&spitzkbd_data->input, SW_0, ((GPLR(SPITZ_GPIO_SWA) & GPIO_bit(SPITZ_GPIO_SWA)) != 0)); - input_report_switch(&spitzkbd_data->input, SW_1, ((GPLR(SPITZ_GPIO_SWB) & GPIO_bit(SPITZ_GPIO_SWB)) != 0)); - input_sync(&spitzkbd_data->input); + input_report_switch(spitzkbd_data->input, SW_0, ((GPLR(SPITZ_GPIO_SWA) & GPIO_bit(SPITZ_GPIO_SWA)) != 0)); + input_report_switch(spitzkbd_data->input, SW_1, ((GPLR(SPITZ_GPIO_SWB) & GPIO_bit(SPITZ_GPIO_SWB)) != 0)); + input_sync(spitzkbd_data->input); spin_unlock_irqrestore(&spitzkbd_data->lock, flags); } else { @@ -309,34 +309,32 @@ static void spitzkbd_hinge_timer(unsigned long data) } #ifdef CONFIG_PM -static int spitzkbd_suspend(struct device *dev, pm_message_t state, uint32_t level) +static int spitzkbd_suspend(struct device *dev, pm_message_t state) { - if (level == SUSPEND_POWER_DOWN) { - int i; - struct spitzkbd *spitzkbd = dev_get_drvdata(dev); - spitzkbd->suspended = 1; - - /* Set Strobe lines as inputs - *except* strobe line 0 leave this - enabled so we can detect a power button press for resume */ - for (i = 1; i < SPITZ_KEY_STROBE_NUM; i++) - pxa_gpio_mode(spitz_strobes[i] | GPIO_IN); - } + int i; + struct spitzkbd *spitzkbd = dev_get_drvdata(dev); + spitzkbd->suspended = 1; + + /* Set Strobe lines as inputs - *except* strobe line 0 leave this + enabled so we can detect a power button press for resume */ + for (i = 1; i < SPITZ_KEY_STROBE_NUM; i++) + pxa_gpio_mode(spitz_strobes[i] | GPIO_IN); + return 0; } -static int spitzkbd_resume(struct device *dev, uint32_t level) +static int spitzkbd_resume(struct device *dev) { - if (level == RESUME_POWER_ON) { - int i; - struct spitzkbd *spitzkbd = dev_get_drvdata(dev); + int i; + struct spitzkbd *spitzkbd = dev_get_drvdata(dev); - for (i = 0; i < SPITZ_KEY_STROBE_NUM; i++) - pxa_gpio_mode(spitz_strobes[i] | GPIO_OUT | GPIO_DFLT_HIGH); + for (i = 0; i < SPITZ_KEY_STROBE_NUM; i++) + pxa_gpio_mode(spitz_strobes[i] | GPIO_OUT | GPIO_DFLT_HIGH); + + /* Upon resume, ignore the suspend key for a short while */ + spitzkbd->suspend_jiffies = jiffies; + spitzkbd->suspended = 0; - /* Upon resume, ignore the suspend key for a short while */ - spitzkbd->suspend_jiffies = jiffies; - spitzkbd->suspended = 0; - } return 0; } #else @@ -346,14 +344,21 @@ static int spitzkbd_resume(struct device *dev, uint32_t level) static int __init spitzkbd_probe(struct device *dev) { - int i; struct spitzkbd *spitzkbd; + struct input_dev *input_dev; + int i; spitzkbd = kzalloc(sizeof(struct spitzkbd), GFP_KERNEL); if (!spitzkbd) return -ENOMEM; - dev_set_drvdata(dev,spitzkbd); + input_dev = input_allocate_device(); + if (!input_dev) { + kfree(spitzkbd); + return -ENOMEM; + } + + dev_set_drvdata(dev, spitzkbd); strcpy(spitzkbd->phys, "spitzkbd/input0"); spin_lock_init(&spitzkbd->lock); @@ -368,30 +373,34 @@ static int __init spitzkbd_probe(struct device *dev) spitzkbd->htimer.function = spitzkbd_hinge_timer; spitzkbd->htimer.data = (unsigned long) spitzkbd; - spitzkbd->suspend_jiffies=jiffies; - - init_input_dev(&spitzkbd->input); - spitzkbd->input.private = spitzkbd; - spitzkbd->input.name = "Spitz Keyboard"; - spitzkbd->input.dev = dev; - spitzkbd->input.phys = spitzkbd->phys; - spitzkbd->input.id.bustype = BUS_HOST; - spitzkbd->input.id.vendor = 0x0001; - spitzkbd->input.id.product = 0x0001; - spitzkbd->input.id.version = 0x0100; - spitzkbd->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_PWR) | BIT(EV_SW); - spitzkbd->input.keycode = spitzkbd->keycode; - spitzkbd->input.keycodesize = sizeof(unsigned char); - spitzkbd->input.keycodemax = ARRAY_SIZE(spitzkbd_keycode); + spitzkbd->suspend_jiffies = jiffies; + + spitzkbd->input = input_dev; + + input_dev->private = spitzkbd; + input_dev->name = "Spitz Keyboard"; + input_dev->phys = spitzkbd->phys; + input_dev->cdev.dev = dev; + + input_dev->id.bustype = BUS_HOST; + input_dev->id.vendor = 0x0001; + input_dev->id.product = 0x0001; + input_dev->id.version = 0x0100; + + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_PWR) | BIT(EV_SW); + input_dev->keycode = spitzkbd->keycode; + input_dev->keycodesize = sizeof(unsigned char); + input_dev->keycodemax = ARRAY_SIZE(spitzkbd_keycode); memcpy(spitzkbd->keycode, spitzkbd_keycode, sizeof(spitzkbd->keycode)); for (i = 0; i < ARRAY_SIZE(spitzkbd_keycode); i++) - set_bit(spitzkbd->keycode[i], spitzkbd->input.keybit); - clear_bit(0, spitzkbd->input.keybit); - set_bit(SW_0, spitzkbd->input.swbit); - set_bit(SW_1, spitzkbd->input.swbit); + set_bit(spitzkbd->keycode[i], input_dev->keybit); + clear_bit(0, input_dev->keybit); + set_bit(SW_0, input_dev->swbit); + set_bit(SW_1, input_dev->swbit); + + input_register_device(input_dev); - input_register_device(&spitzkbd->input); mod_timer(&spitzkbd->htimer, jiffies + msecs_to_jiffies(HINGE_SCAN_INTERVAL)); /* Setup sense interrupts - RisingEdge Detect, sense lines as inputs */ @@ -444,7 +453,7 @@ static int spitzkbd_remove(struct device *dev) del_timer_sync(&spitzkbd->htimer); del_timer_sync(&spitzkbd->timer); - input_unregister_device(&spitzkbd->input); + input_unregister_device(spitzkbd->input); kfree(spitzkbd); diff --git a/drivers/input/keyboard/sunkbd.c b/drivers/input/keyboard/sunkbd.c index 4bae5d89348d..b15b6d8d4f83 100644 --- a/drivers/input/keyboard/sunkbd.c +++ b/drivers/input/keyboard/sunkbd.c @@ -76,13 +76,14 @@ static unsigned char sunkbd_keycode[128] = { struct sunkbd { unsigned char keycode[128]; - struct input_dev dev; + struct input_dev *dev; struct serio *serio; struct work_struct tq; wait_queue_head_t wait; char name[64]; char phys[32]; char type; + unsigned char enabled; volatile s8 reset; volatile s8 layout; }; @@ -124,10 +125,13 @@ static irqreturn_t sunkbd_interrupt(struct serio *serio, break; default: + if (!sunkbd->enabled) + break; + if (sunkbd->keycode[data & SUNKBD_KEY]) { - input_regs(&sunkbd->dev, regs); - input_report_key(&sunkbd->dev, sunkbd->keycode[data & SUNKBD_KEY], !(data & SUNKBD_RELEASE)); - input_sync(&sunkbd->dev); + input_regs(sunkbd->dev, regs); + input_report_key(sunkbd->dev, sunkbd->keycode[data & SUNKBD_KEY], !(data & SUNKBD_RELEASE)); + input_sync(sunkbd->dev); } else { printk(KERN_WARNING "sunkbd.c: Unknown key (scancode %#x) %s.\n", data & SUNKBD_KEY, data & SUNKBD_RELEASE ? "released" : "pressed"); @@ -184,7 +188,7 @@ static int sunkbd_initialize(struct sunkbd *sunkbd) sunkbd->reset = -2; sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_RESET); wait_event_interruptible_timeout(sunkbd->wait, sunkbd->reset >= 0, HZ); - if (sunkbd->reset <0) + if (sunkbd->reset < 0) return -1; sunkbd->type = sunkbd->reset; @@ -213,10 +217,17 @@ static void sunkbd_reinit(void *data) sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_SETLED); sunkbd->serio->write(sunkbd->serio, - (!!test_bit(LED_CAPSL, sunkbd->dev.led) << 3) | (!!test_bit(LED_SCROLLL, sunkbd->dev.led) << 2) | - (!!test_bit(LED_COMPOSE, sunkbd->dev.led) << 1) | !!test_bit(LED_NUML, sunkbd->dev.led)); - sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_NOCLICK - !!test_bit(SND_CLICK, sunkbd->dev.snd)); - sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_BELLOFF - !!test_bit(SND_BELL, sunkbd->dev.snd)); + (!!test_bit(LED_CAPSL, sunkbd->dev->led) << 3) | (!!test_bit(LED_SCROLLL, sunkbd->dev->led) << 2) | + (!!test_bit(LED_COMPOSE, sunkbd->dev->led) << 1) | !!test_bit(LED_NUML, sunkbd->dev->led)); + sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_NOCLICK - !!test_bit(SND_CLICK, sunkbd->dev->snd)); + sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_BELLOFF - !!test_bit(SND_BELL, sunkbd->dev->snd)); +} + +static void sunkbd_enable(struct sunkbd *sunkbd, int enable) +{ + serio_pause_rx(sunkbd->serio); + sunkbd->enabled = 1; + serio_continue_rx(sunkbd->serio); } /* @@ -226,70 +237,64 @@ static void sunkbd_reinit(void *data) static int sunkbd_connect(struct serio *serio, struct serio_driver *drv) { struct sunkbd *sunkbd; + struct input_dev *input_dev; + int err = -ENOMEM; int i; - int err; - - if (!(sunkbd = kmalloc(sizeof(struct sunkbd), GFP_KERNEL))) - return -ENOMEM; - memset(sunkbd, 0, sizeof(struct sunkbd)); - - init_input_dev(&sunkbd->dev); - init_waitqueue_head(&sunkbd->wait); - - sunkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_SND) | BIT(EV_REP); - sunkbd->dev.ledbit[0] = BIT(LED_CAPSL) | BIT(LED_COMPOSE) | BIT(LED_SCROLLL) | BIT(LED_NUML); - sunkbd->dev.sndbit[0] = BIT(SND_CLICK) | BIT(SND_BELL); + sunkbd = kzalloc(sizeof(struct sunkbd), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!sunkbd || !input_dev) + goto fail; sunkbd->serio = serio; - + sunkbd->dev = input_dev; + init_waitqueue_head(&sunkbd->wait); INIT_WORK(&sunkbd->tq, sunkbd_reinit, sunkbd); - - sunkbd->dev.keycode = sunkbd->keycode; - sunkbd->dev.keycodesize = sizeof(unsigned char); - sunkbd->dev.keycodemax = ARRAY_SIZE(sunkbd_keycode); - - sunkbd->dev.event = sunkbd_event; - sunkbd->dev.private = sunkbd; + snprintf(sunkbd->phys, sizeof(sunkbd->phys), "%s/input0", serio->phys); serio_set_drvdata(serio, sunkbd); err = serio_open(serio, drv); - if (err) { - serio_set_drvdata(serio, NULL); - kfree(sunkbd); - return err; - } + if (err) + goto fail; if (sunkbd_initialize(sunkbd) < 0) { serio_close(serio); - serio_set_drvdata(serio, NULL); - kfree(sunkbd); - return -ENODEV; + goto fail; } sprintf(sunkbd->name, "Sun Type %d keyboard", sunkbd->type); - memcpy(sunkbd->keycode, sunkbd_keycode, sizeof(sunkbd->keycode)); - for (i = 0; i < 128; i++) - set_bit(sunkbd->keycode[i], sunkbd->dev.keybit); - clear_bit(0, sunkbd->dev.keybit); - - sprintf(sunkbd->phys, "%s/input0", serio->phys); - - sunkbd->dev.name = sunkbd->name; - sunkbd->dev.phys = sunkbd->phys; - sunkbd->dev.id.bustype = BUS_RS232; - sunkbd->dev.id.vendor = SERIO_SUNKBD; - sunkbd->dev.id.product = sunkbd->type; - sunkbd->dev.id.version = 0x0100; - sunkbd->dev.dev = &serio->dev; - input_register_device(&sunkbd->dev); - - printk(KERN_INFO "input: %s on %s\n", sunkbd->name, serio->phys); + input_dev->name = sunkbd->name; + input_dev->phys = sunkbd->phys; + input_dev->id.bustype = BUS_RS232; + input_dev->id.vendor = SERIO_SUNKBD; + input_dev->id.product = sunkbd->type; + input_dev->id.version = 0x0100; + input_dev->cdev.dev = &serio->dev; + input_dev->private = sunkbd; + input_dev->event = sunkbd_event; + + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_SND) | BIT(EV_REP); + input_dev->ledbit[0] = BIT(LED_CAPSL) | BIT(LED_COMPOSE) | BIT(LED_SCROLLL) | BIT(LED_NUML); + input_dev->sndbit[0] = BIT(SND_CLICK) | BIT(SND_BELL); + + input_dev->keycode = sunkbd->keycode; + input_dev->keycodesize = sizeof(unsigned char); + input_dev->keycodemax = ARRAY_SIZE(sunkbd_keycode); + for (i = 0; i < 128; i++) + set_bit(sunkbd->keycode[i], input_dev->keybit); + clear_bit(0, input_dev->keybit); + sunkbd_enable(sunkbd, 1); + input_register_device(sunkbd->dev); return 0; + + fail: serio_set_drvdata(serio, NULL); + input_free_device(input_dev); + kfree(sunkbd); + return err; } /* @@ -299,7 +304,9 @@ static int sunkbd_connect(struct serio *serio, struct serio_driver *drv) static void sunkbd_disconnect(struct serio *serio) { struct sunkbd *sunkbd = serio_get_drvdata(serio); - input_unregister_device(&sunkbd->dev); + + sunkbd_enable(sunkbd, 0); + input_unregister_device(sunkbd->dev); serio_close(serio); serio_set_drvdata(serio, NULL); kfree(sunkbd); diff --git a/drivers/input/keyboard/xtkbd.c b/drivers/input/keyboard/xtkbd.c index 19eaec7789d1..4135e3e16c51 100644 --- a/drivers/input/keyboard/xtkbd.c +++ b/drivers/input/keyboard/xtkbd.c @@ -56,11 +56,9 @@ static unsigned char xtkbd_keycode[256] = { 106 }; -static char *xtkbd_name = "XT Keyboard"; - struct xtkbd { unsigned char keycode[256]; - struct input_dev dev; + struct input_dev *dev; struct serio *serio; char phys[32]; }; @@ -77,9 +75,9 @@ static irqreturn_t xtkbd_interrupt(struct serio *serio, default: if (xtkbd->keycode[data & XTKBD_KEY]) { - input_regs(&xtkbd->dev, regs); - input_report_key(&xtkbd->dev, xtkbd->keycode[data & XTKBD_KEY], !(data & XTKBD_RELEASE)); - input_sync(&xtkbd->dev); + input_regs(xtkbd->dev, regs); + input_report_key(xtkbd->dev, xtkbd->keycode[data & XTKBD_KEY], !(data & XTKBD_RELEASE)); + input_sync(xtkbd->dev); } else { printk(KERN_WARNING "xtkbd.c: Unknown key (scancode %#x) %s.\n", data & XTKBD_KEY, data & XTKBD_RELEASE ? "released" : "pressed"); @@ -91,62 +89,60 @@ static irqreturn_t xtkbd_interrupt(struct serio *serio, static int xtkbd_connect(struct serio *serio, struct serio_driver *drv) { struct xtkbd *xtkbd; + struct input_dev *input_dev; + int err = -ENOMEM; int i; - int err; - - if (!(xtkbd = kmalloc(sizeof(struct xtkbd), GFP_KERNEL))) - return -ENOMEM; - - memset(xtkbd, 0, sizeof(struct xtkbd)); - xtkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP); + xtkbd = kmalloc(sizeof(struct xtkbd), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!xtkbd || !input_dev) + goto fail; xtkbd->serio = serio; + xtkbd->dev = input_dev; + sprintf(xtkbd->phys, "%s/input0", serio->phys); + memcpy(xtkbd->keycode, xtkbd_keycode, sizeof(xtkbd->keycode)); - init_input_dev(&xtkbd->dev); - xtkbd->dev.keycode = xtkbd->keycode; - xtkbd->dev.keycodesize = sizeof(unsigned char); - xtkbd->dev.keycodemax = ARRAY_SIZE(xtkbd_keycode); - xtkbd->dev.private = xtkbd; - - serio_set_drvdata(serio, xtkbd); + input_dev->name = "XT Keyboard"; + input_dev->phys = xtkbd->phys; + input_dev->id.bustype = BUS_XTKBD; + input_dev->id.vendor = 0x0001; + input_dev->id.product = 0x0001; + input_dev->id.version = 0x0100; + input_dev->cdev.dev = &serio->dev; + input_dev->private = xtkbd; - err = serio_open(serio, drv); - if (err) { - serio_set_drvdata(serio, NULL); - kfree(xtkbd); - return err; - } + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP); + input_dev->keycode = xtkbd->keycode; + input_dev->keycodesize = sizeof(unsigned char); + input_dev->keycodemax = ARRAY_SIZE(xtkbd_keycode); - memcpy(xtkbd->keycode, xtkbd_keycode, sizeof(xtkbd->keycode)); for (i = 0; i < 255; i++) - set_bit(xtkbd->keycode[i], xtkbd->dev.keybit); - clear_bit(0, xtkbd->dev.keybit); - - sprintf(xtkbd->phys, "%s/input0", serio->phys); - - xtkbd->dev.name = xtkbd_name; - xtkbd->dev.phys = xtkbd->phys; - xtkbd->dev.id.bustype = BUS_XTKBD; - xtkbd->dev.id.vendor = 0x0001; - xtkbd->dev.id.product = 0x0001; - xtkbd->dev.id.version = 0x0100; - xtkbd->dev.dev = &serio->dev; + set_bit(xtkbd->keycode[i], input_dev->keybit); + clear_bit(0, input_dev->keybit); - input_register_device(&xtkbd->dev); + serio_set_drvdata(serio, xtkbd); - printk(KERN_INFO "input: %s on %s\n", xtkbd_name, serio->phys); + err = serio_open(serio, drv); + if (err) + goto fail; + input_register_device(xtkbd->dev); return 0; + + fail: serio_set_drvdata(serio, NULL); + input_free_device(input_dev); + kfree(xtkbd); + return err; } static void xtkbd_disconnect(struct serio *serio) { struct xtkbd *xtkbd = serio_get_drvdata(serio); - input_unregister_device(&xtkbd->dev); serio_close(serio); serio_set_drvdata(serio, NULL); + input_unregister_device(xtkbd->dev); kfree(xtkbd); } diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index bb934e6d9636..b3eaac1b35b6 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -14,7 +14,7 @@ if INPUT_MISC config INPUT_PCSPKR tristate "PC Speaker support" - depends on ALPHA || X86 || X86_64 || MIPS || PPC_PREP || PPC_CHRP || PPC_PSERIES + depends on ALPHA || X86 || MIPS || PPC_PREP || PPC_CHRP || PPC_PSERIES help Say Y here if you want the standard PC Speaker to be used for bells and whistles. diff --git a/drivers/input/misc/m68kspkr.c b/drivers/input/misc/m68kspkr.c index 64abdd98d482..04489ad7702a 100644 --- a/drivers/input/misc/m68kspkr.c +++ b/drivers/input/misc/m68kspkr.c @@ -24,9 +24,7 @@ MODULE_AUTHOR("Richard Zidlicky <rz@linux-m68k.org>"); MODULE_DESCRIPTION("m68k beeper driver"); MODULE_LICENSE("GPL"); -static char m68kspkr_name[] = "m68k beeper"; -static char m68kspkr_phys[] = "m68k/generic"; -static struct input_dev m68kspkr_dev; +static struct input_dev *m68kspkr_dev; static int m68kspkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { @@ -51,32 +49,34 @@ static int m68kspkr_event(struct input_dev *dev, unsigned int type, unsigned int static int __init m68kspkr_init(void) { - if (!mach_beep){ - printk("%s: no lowlevel beep support\n", m68kspkr_name); - return -1; + if (!mach_beep) { + printk(KERN_INFO "m68kspkr: no lowlevel beep support\n"); + return -ENODEV; } - m68kspkr_dev.evbit[0] = BIT(EV_SND); - m68kspkr_dev.sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE); - m68kspkr_dev.event = m68kspkr_event; + m68kspkr_dev = input_allocate_device(); + if (!m68kspkr_dev) + return -ENOMEM; - m68kspkr_dev.name = m68kspkr_name; - m68kspkr_dev.phys = m68kspkr_phys; - m68kspkr_dev.id.bustype = BUS_HOST; - m68kspkr_dev.id.vendor = 0x001f; - m68kspkr_dev.id.product = 0x0001; - m68kspkr_dev.id.version = 0x0100; + m68kspkr_dev->name = "m68k beeper"; + m68kspkr_dev->phys = "m68k/generic"; + m68kspkr_dev->id.bustype = BUS_HOST; + m68kspkr_dev->id.vendor = 0x001f; + m68kspkr_dev->id.product = 0x0001; + m68kspkr_dev->id.version = 0x0100; - input_register_device(&m68kspkr_dev); + m68kspkr_dev->evbit[0] = BIT(EV_SND); + m68kspkr_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE); + m68kspkr_dev->event = m68kspkr_event; - printk(KERN_INFO "input: %s\n", m68kspkr_name); + input_register_device(m68kspkr_dev); return 0; } static void __exit m68kspkr_exit(void) { - input_unregister_device(&m68kspkr_dev); + input_unregister_device(m68kspkr_dev); } module_init(m68kspkr_init); diff --git a/drivers/input/misc/pcspkr.c b/drivers/input/misc/pcspkr.c index 3013194f462b..e34633c37fdd 100644 --- a/drivers/input/misc/pcspkr.c +++ b/drivers/input/misc/pcspkr.c @@ -23,9 +23,7 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); MODULE_DESCRIPTION("PC Speaker beeper driver"); MODULE_LICENSE("GPL"); -static char pcspkr_name[] = "PC Speaker"; -static char pcspkr_phys[] = "isa0061/input0"; -static struct input_dev pcspkr_dev; +static struct input_dev *pcspkr_dev; static DEFINE_SPINLOCK(i8253_beep_lock); @@ -68,27 +66,29 @@ static int pcspkr_event(struct input_dev *dev, unsigned int type, unsigned int c static int __init pcspkr_init(void) { - pcspkr_dev.evbit[0] = BIT(EV_SND); - pcspkr_dev.sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE); - pcspkr_dev.event = pcspkr_event; + pcspkr_dev = input_allocate_device(); + if (!pcspkr_dev) + return -ENOMEM; - pcspkr_dev.name = pcspkr_name; - pcspkr_dev.phys = pcspkr_phys; - pcspkr_dev.id.bustype = BUS_ISA; - pcspkr_dev.id.vendor = 0x001f; - pcspkr_dev.id.product = 0x0001; - pcspkr_dev.id.version = 0x0100; + pcspkr_dev->name = "PC Speaker"; + pcspkr_dev->name = "isa0061/input0"; + pcspkr_dev->id.bustype = BUS_ISA; + pcspkr_dev->id.vendor = 0x001f; + pcspkr_dev->id.product = 0x0001; + pcspkr_dev->id.version = 0x0100; - input_register_device(&pcspkr_dev); + pcspkr_dev->evbit[0] = BIT(EV_SND); + pcspkr_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE); + pcspkr_dev->event = pcspkr_event; - printk(KERN_INFO "input: %s\n", pcspkr_name); + input_register_device(pcspkr_dev); return 0; } static void __exit pcspkr_exit(void) { - input_unregister_device(&pcspkr_dev); + input_unregister_device(pcspkr_dev); /* turn off the speaker */ pcspkr_event(NULL, EV_SND, SND_BELL, 0); } diff --git a/drivers/input/misc/sparcspkr.c b/drivers/input/misc/sparcspkr.c index cdc3fb3d5f46..29d97b12be7a 100644 --- a/drivers/input/misc/sparcspkr.c +++ b/drivers/input/misc/sparcspkr.c @@ -17,28 +17,24 @@ #endif MODULE_AUTHOR("David S. Miller <davem@redhat.com>"); -MODULE_DESCRIPTION("PC Speaker beeper driver"); +MODULE_DESCRIPTION("Sparc Speaker beeper driver"); MODULE_LICENSE("GPL"); static unsigned long beep_iobase; - -static char *sparcspkr_isa_name = "Sparc ISA Speaker"; -static char *sparcspkr_ebus_name = "Sparc EBUS Speaker"; -static char *sparcspkr_phys = "sparc/input0"; -static struct input_dev sparcspkr_dev; +static struct input_dev *sparcspkr_dev; DEFINE_SPINLOCK(beep_lock); static void __init init_sparcspkr_struct(void) { - sparcspkr_dev.evbit[0] = BIT(EV_SND); - sparcspkr_dev.sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE); - - sparcspkr_dev.phys = sparcspkr_phys; - sparcspkr_dev.id.bustype = BUS_ISA; - sparcspkr_dev.id.vendor = 0x001f; - sparcspkr_dev.id.product = 0x0001; - sparcspkr_dev.id.version = 0x0100; + sparcspkr_dev->evbit[0] = BIT(EV_SND); + sparcspkr_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE); + + sparcspkr_dev->phys = "sparc/input0"; + sparcspkr_dev->id.bustype = BUS_ISA; + sparcspkr_dev->id.vendor = 0x001f; + sparcspkr_dev->id.product = 0x0001; + sparcspkr_dev->id.version = 0x0100; } static int ebus_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) @@ -84,14 +80,15 @@ static int __init init_ebus_beep(struct linux_ebus_device *edev) { beep_iobase = edev->resource[0].start; - init_sparcspkr_struct(); + sparcspkr_dev = input_allocate_device(); + if (!sparcspkr_dev) + return -ENOMEM; - sparcspkr_dev.name = sparcspkr_ebus_name; - sparcspkr_dev.event = ebus_spkr_event; + sparcspkr_dev->name = "Sparc EBUS Speaker"; + sparcspkr_dev->event = ebus_spkr_event; - input_register_device(&sparcspkr_dev); + input_register_device(sparcspkr_dev); - printk(KERN_INFO "input: %s\n", sparcspkr_ebus_name); return 0; } @@ -137,15 +134,17 @@ static int __init init_isa_beep(struct sparc_isa_device *isa_dev) { beep_iobase = isa_dev->resource.start; + sparcspkr_dev = input_allocate_device(); + if (!sparcspkr_dev) + return -ENOMEM; + init_sparcspkr_struct(); - sparcspkr_dev.name = sparcspkr_isa_name; - sparcspkr_dev.event = isa_spkr_event; - sparcspkr_dev.id.bustype = BUS_ISA; + sparcspkr_dev->name = "Sparc ISA Speaker"; + sparcspkr_dev->event = isa_spkr_event; - input_register_device(&sparcspkr_dev); + input_register_device(sparcspkr_dev); - printk(KERN_INFO "input: %s\n", sparcspkr_isa_name); return 0; } #endif @@ -182,7 +181,7 @@ static int __init sparcspkr_init(void) static void __exit sparcspkr_exit(void) { - input_unregister_device(&sparcspkr_dev); + input_unregister_device(sparcspkr_dev); } module_init(sparcspkr_init); diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index b20783f9748a..4acc7fd4cd0f 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -79,8 +79,8 @@ static void alps_process_packet(struct psmouse *psmouse, struct pt_regs *regs) { struct alps_data *priv = psmouse->private; unsigned char *packet = psmouse->packet; - struct input_dev *dev = &psmouse->dev; - struct input_dev *dev2 = &priv->dev2; + struct input_dev *dev = psmouse->dev; + struct input_dev *dev2 = priv->dev2; int x, y, z, ges, fin, left, right, middle; int back = 0, forward = 0; @@ -379,20 +379,24 @@ static int alps_reconnect(struct psmouse *psmouse) static void alps_disconnect(struct psmouse *psmouse) { struct alps_data *priv = psmouse->private; + psmouse_reset(psmouse); - input_unregister_device(&priv->dev2); + input_unregister_device(priv->dev2); kfree(priv); } int alps_init(struct psmouse *psmouse) { struct alps_data *priv; + struct input_dev *dev1 = psmouse->dev, *dev2; int version; - psmouse->private = priv = kmalloc(sizeof(struct alps_data), GFP_KERNEL); - if (!priv) + psmouse->private = priv = kzalloc(sizeof(struct alps_data), GFP_KERNEL); + dev2 = input_allocate_device(); + if (!priv || !dev2) goto init_fail; - memset(priv, 0, sizeof(struct alps_data)); + + priv->dev2 = dev2; if (!(priv->i = alps_get_model(psmouse, &version))) goto init_fail; @@ -411,41 +415,39 @@ int alps_init(struct psmouse *psmouse) if ((priv->i->flags & ALPS_PASS) && alps_passthrough_mode(psmouse, 0)) goto init_fail; - psmouse->dev.evbit[LONG(EV_KEY)] |= BIT(EV_KEY); - psmouse->dev.keybit[LONG(BTN_TOUCH)] |= BIT(BTN_TOUCH); - psmouse->dev.keybit[LONG(BTN_TOOL_FINGER)] |= BIT(BTN_TOOL_FINGER); - psmouse->dev.keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); + dev1->evbit[LONG(EV_KEY)] |= BIT(EV_KEY); + dev1->keybit[LONG(BTN_TOUCH)] |= BIT(BTN_TOUCH); + dev1->keybit[LONG(BTN_TOOL_FINGER)] |= BIT(BTN_TOOL_FINGER); + dev1->keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); - psmouse->dev.evbit[LONG(EV_ABS)] |= BIT(EV_ABS); - input_set_abs_params(&psmouse->dev, ABS_X, 0, 1023, 0, 0); - input_set_abs_params(&psmouse->dev, ABS_Y, 0, 767, 0, 0); - input_set_abs_params(&psmouse->dev, ABS_PRESSURE, 0, 127, 0, 0); + dev1->evbit[LONG(EV_ABS)] |= BIT(EV_ABS); + input_set_abs_params(dev1, ABS_X, 0, 1023, 0, 0); + input_set_abs_params(dev1, ABS_Y, 0, 767, 0, 0); + input_set_abs_params(dev1, ABS_PRESSURE, 0, 127, 0, 0); if (priv->i->flags & ALPS_WHEEL) { - psmouse->dev.evbit[LONG(EV_REL)] |= BIT(EV_REL); - psmouse->dev.relbit[LONG(REL_WHEEL)] |= BIT(REL_WHEEL); + dev1->evbit[LONG(EV_REL)] |= BIT(EV_REL); + dev1->relbit[LONG(REL_WHEEL)] |= BIT(REL_WHEEL); } if (priv->i->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) { - psmouse->dev.keybit[LONG(BTN_FORWARD)] |= BIT(BTN_FORWARD); - psmouse->dev.keybit[LONG(BTN_BACK)] |= BIT(BTN_BACK); + dev1->keybit[LONG(BTN_FORWARD)] |= BIT(BTN_FORWARD); + dev1->keybit[LONG(BTN_BACK)] |= BIT(BTN_BACK); } sprintf(priv->phys, "%s/input1", psmouse->ps2dev.serio->phys); - priv->dev2.phys = priv->phys; - priv->dev2.name = (priv->i->flags & ALPS_DUALPOINT) ? "DualPoint Stick" : "PS/2 Mouse"; - priv->dev2.id.bustype = BUS_I8042; - priv->dev2.id.vendor = 0x0002; - priv->dev2.id.product = PSMOUSE_ALPS; - priv->dev2.id.version = 0x0000; - - priv->dev2.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); - priv->dev2.relbit[LONG(REL_X)] |= BIT(REL_X) | BIT(REL_Y); - priv->dev2.keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); + dev2->phys = priv->phys; + dev2->name = (priv->i->flags & ALPS_DUALPOINT) ? "DualPoint Stick" : "PS/2 Mouse"; + dev2->id.bustype = BUS_I8042; + dev2->id.vendor = 0x0002; + dev2->id.product = PSMOUSE_ALPS; + dev2->id.version = 0x0000; - input_register_device(&priv->dev2); + dev2->evbit[0] = BIT(EV_KEY) | BIT(EV_REL); + dev2->relbit[LONG(REL_X)] |= BIT(REL_X) | BIT(REL_Y); + dev2->keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); - printk(KERN_INFO "input: %s on %s\n", priv->dev2.name, psmouse->ps2dev.serio->phys); + input_register_device(priv->dev2); psmouse->protocol_handler = alps_process_byte; psmouse->disconnect = alps_disconnect; @@ -455,6 +457,7 @@ int alps_init(struct psmouse *psmouse) return 0; init_fail: + input_free_device(dev2); kfree(priv); return -1; } diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h index aba103dd65b7..e428f8d5d12e 100644 --- a/drivers/input/mouse/alps.h +++ b/drivers/input/mouse/alps.h @@ -22,7 +22,7 @@ struct alps_model_info { }; struct alps_data { - struct input_dev dev2; /* Relative device */ + struct input_dev *dev2; /* Relative device */ char name[32]; /* Name */ char phys[32]; /* Phys */ struct alps_model_info *i; /* Info */ diff --git a/drivers/input/mouse/amimouse.c b/drivers/input/mouse/amimouse.c index e994849efb8f..d13d4c8fe3c5 100644 --- a/drivers/input/mouse/amimouse.c +++ b/drivers/input/mouse/amimouse.c @@ -34,10 +34,7 @@ MODULE_DESCRIPTION("Amiga mouse driver"); MODULE_LICENSE("GPL"); static int amimouse_lastx, amimouse_lasty; -static struct input_dev amimouse_dev; - -static char *amimouse_name = "Amiga mouse"; -static char *amimouse_phys = "amimouse/input0"; +static struct input_dev *amimouse_dev; static irqreturn_t amimouse_interrupt(int irq, void *dummy, struct pt_regs *fp) { @@ -62,16 +59,16 @@ static irqreturn_t amimouse_interrupt(int irq, void *dummy, struct pt_regs *fp) potgor = custom.potgor; - input_regs(&amimouse_dev, fp); + input_regs(amimouse_dev, fp); - input_report_rel(&amimouse_dev, REL_X, dx); - input_report_rel(&amimouse_dev, REL_Y, dy); + input_report_rel(amimouse_dev, REL_X, dx); + input_report_rel(amimouse_dev, REL_Y, dy); - input_report_key(&amimouse_dev, BTN_LEFT, ciaa.pra & 0x40); - input_report_key(&amimouse_dev, BTN_MIDDLE, potgor & 0x0100); - input_report_key(&amimouse_dev, BTN_RIGHT, potgor & 0x0400); + input_report_key(amimouse_dev, BTN_LEFT, ciaa.pra & 0x40); + input_report_key(amimouse_dev, BTN_MIDDLE, potgor & 0x0100); + input_report_key(amimouse_dev, BTN_RIGHT, potgor & 0x0400); - input_sync(&amimouse_dev); + input_sync(amimouse_dev); return IRQ_HANDLED; } @@ -103,28 +100,30 @@ static int __init amimouse_init(void) if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(AMI_MOUSE)) return -ENODEV; - amimouse_dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); - amimouse_dev.relbit[0] = BIT(REL_X) | BIT(REL_Y); - amimouse_dev.keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); - amimouse_dev.open = amimouse_open; - amimouse_dev.close = amimouse_close; + if (!(amimouse_dev = input_allocate_device())) + return -ENOMEM; + + amimouse_dev->name = "Amiga mouse"; + amimouse_dev->phys = "amimouse/input0"; + amimouse_dev->id.bustype = BUS_AMIGA; + amimouse_dev->id.vendor = 0x0001; + amimouse_dev->id.product = 0x0002; + amimouse_dev->id.version = 0x0100; - amimouse_dev.name = amimouse_name; - amimouse_dev.phys = amimouse_phys; - amimouse_dev.id.bustype = BUS_AMIGA; - amimouse_dev.id.vendor = 0x0001; - amimouse_dev.id.product = 0x0002; - amimouse_dev.id.version = 0x0100; + amimouse_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL); + amimouse_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y); + amimouse_dev->keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); + amimouse_dev->open = amimouse_open; + amimouse_dev->close = amimouse_close; - input_register_device(&amimouse_dev); + input_register_device(amimouse_dev); - printk(KERN_INFO "input: %s at joy0dat\n", amimouse_name); return 0; } static void __exit amimouse_exit(void) { - input_unregister_device(&amimouse_dev); + input_unregister_device(amimouse_dev); } module_init(amimouse_init); diff --git a/drivers/input/mouse/hil_ptr.c b/drivers/input/mouse/hil_ptr.c index bc22849c6c79..c2bf2ed07dc6 100644 --- a/drivers/input/mouse/hil_ptr.c +++ b/drivers/input/mouse/hil_ptr.c @@ -196,7 +196,7 @@ static irqreturn_t hil_ptr_interrupt(struct serio *serio, hil_packet packet; int idx; - ptr = (struct hil_ptr *)serio->private; + ptr = serio_get_drvdata(serio); if (ptr == NULL) { BUG(); return IRQ_HANDLED; @@ -227,7 +227,7 @@ static void hil_ptr_disconnect(struct serio *serio) { struct hil_ptr *ptr; - ptr = (struct hil_ptr *)serio->private; + ptr = serio_get_drvdata(serio); if (ptr == NULL) { BUG(); return; @@ -238,21 +238,19 @@ static void hil_ptr_disconnect(struct serio *serio) kfree(ptr); } -static void hil_ptr_connect(struct serio *serio, struct serio_driver *driver) +static int hil_ptr_connect(struct serio *serio, struct serio_driver *driver) { struct hil_ptr *ptr; char *txt; unsigned int i, naxsets, btntype; uint8_t did, *idd; - if (serio->type != (SERIO_HIL_MLC | SERIO_HIL)) return; - - if (!(ptr = kmalloc(sizeof(struct hil_ptr), GFP_KERNEL))) return; + if (!(ptr = kmalloc(sizeof(struct hil_ptr), GFP_KERNEL))) return -ENOMEM; memset(ptr, 0, sizeof(struct hil_ptr)); if (serio_open(serio, driver)) goto bail0; - serio->private = ptr; + serio_set_drvdata(serio, ptr); ptr->serio = serio; ptr->dev.private = ptr; @@ -380,23 +378,34 @@ static void hil_ptr_connect(struct serio *serio, struct serio_driver *driver) (btntype == BTN_MOUSE) ? "HIL mouse":"HIL tablet or touchpad", did); - return; + return 0; bail1: serio_close(serio); bail0: kfree(ptr); - return; + serio_set_drvdata(serio, NULL); + return -ENODEV; } +static struct serio_device_id hil_ptr_ids[] = { + { + .type = SERIO_HIL_MLC, + .proto = SERIO_HIL, + .id = SERIO_ANY, + .extra = SERIO_ANY, + }, + { 0 } +}; static struct serio_driver hil_ptr_serio_driver = { .driver = { .name = "hil_ptr", }, .description = "HP HIL mouse/tablet driver", - .connect = hil_ptr_connect, - .disconnect = hil_ptr_disconnect, - .interrupt = hil_ptr_interrupt + .id_table = hil_ptr_ids, + .connect = hil_ptr_connect, + .disconnect = hil_ptr_disconnect, + .interrupt = hil_ptr_interrupt }; static int __init hil_ptr_init(void) diff --git a/drivers/input/mouse/inport.c b/drivers/input/mouse/inport.c index 1f62c0134010..afc66f56df43 100644 --- a/drivers/input/mouse/inport.c +++ b/drivers/input/mouse/inport.c @@ -87,40 +87,7 @@ MODULE_PARM_DESC(irq, "IRQ number (5=default)"); __obsolete_setup("inport_irq="); -static irqreturn_t inport_interrupt(int irq, void *dev_id, struct pt_regs *regs); - -static int inport_open(struct input_dev *dev) -{ - if (request_irq(inport_irq, inport_interrupt, 0, "inport", NULL)) - return -EBUSY; - outb(INPORT_REG_MODE, INPORT_CONTROL_PORT); - outb(INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT); - - return 0; -} - -static void inport_close(struct input_dev *dev) -{ - outb(INPORT_REG_MODE, INPORT_CONTROL_PORT); - outb(INPORT_MODE_BASE, INPORT_DATA_PORT); - free_irq(inport_irq, NULL); -} - -static struct input_dev inport_dev = { - .evbit = { BIT(EV_KEY) | BIT(EV_REL) }, - .keybit = { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT) }, - .relbit = { BIT(REL_X) | BIT(REL_Y) }, - .open = inport_open, - .close = inport_close, - .name = INPORT_NAME, - .phys = "isa023c/input0", - .id = { - .bustype = BUS_ISA, - .vendor = INPORT_VENDOR, - .product = 0x0001, - .version = 0x0100, - }, -}; +static struct input_dev *inport_dev; static irqreturn_t inport_interrupt(int irq, void *dev_id, struct pt_regs *regs) { @@ -129,31 +96,48 @@ static irqreturn_t inport_interrupt(int irq, void *dev_id, struct pt_regs *regs) outb(INPORT_REG_MODE, INPORT_CONTROL_PORT); outb(INPORT_MODE_HOLD | INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT); - input_regs(&inport_dev, regs); + input_regs(inport_dev, regs); outb(INPORT_REG_X, INPORT_CONTROL_PORT); - input_report_rel(&inport_dev, REL_X, inb(INPORT_DATA_PORT)); + input_report_rel(inport_dev, REL_X, inb(INPORT_DATA_PORT)); outb(INPORT_REG_Y, INPORT_CONTROL_PORT); - input_report_rel(&inport_dev, REL_Y, inb(INPORT_DATA_PORT)); + input_report_rel(inport_dev, REL_Y, inb(INPORT_DATA_PORT)); outb(INPORT_REG_BTNS, INPORT_CONTROL_PORT); buttons = inb(INPORT_DATA_PORT); - input_report_key(&inport_dev, BTN_MIDDLE, buttons & 1); - input_report_key(&inport_dev, BTN_LEFT, buttons & 2); - input_report_key(&inport_dev, BTN_RIGHT, buttons & 4); + input_report_key(inport_dev, BTN_MIDDLE, buttons & 1); + input_report_key(inport_dev, BTN_LEFT, buttons & 2); + input_report_key(inport_dev, BTN_RIGHT, buttons & 4); outb(INPORT_REG_MODE, INPORT_CONTROL_PORT); outb(INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT); - input_sync(&inport_dev); + input_sync(inport_dev); return IRQ_HANDLED; } +static int inport_open(struct input_dev *dev) +{ + if (request_irq(inport_irq, inport_interrupt, 0, "inport", NULL)) + return -EBUSY; + outb(INPORT_REG_MODE, INPORT_CONTROL_PORT); + outb(INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT); + + return 0; +} + +static void inport_close(struct input_dev *dev) +{ + outb(INPORT_REG_MODE, INPORT_CONTROL_PORT); + outb(INPORT_MODE_BASE, INPORT_DATA_PORT); + free_irq(inport_irq, NULL); +} + static int __init inport_init(void) { - unsigned char a,b,c; + unsigned char a, b, c; if (!request_region(INPORT_BASE, INPORT_EXTENT, "inport")) { printk(KERN_ERR "inport.c: Can't allocate ports at %#x\n", INPORT_BASE); @@ -163,26 +147,44 @@ static int __init inport_init(void) a = inb(INPORT_SIGNATURE_PORT); b = inb(INPORT_SIGNATURE_PORT); c = inb(INPORT_SIGNATURE_PORT); - if (( a == b ) || ( a != c )) { + if (a == b || a != c) { release_region(INPORT_BASE, INPORT_EXTENT); printk(KERN_ERR "inport.c: Didn't find InPort mouse at %#x\n", INPORT_BASE); return -ENODEV; } + if (!(inport_dev = input_allocate_device())) { + printk(KERN_ERR "inport.c: Not enough memory for input device\n"); + release_region(INPORT_BASE, INPORT_EXTENT); + return -ENOMEM; + } + + inport_dev->name = INPORT_NAME; + inport_dev->phys = "isa023c/input0"; + inport_dev->id.bustype = BUS_ISA; + inport_dev->id.vendor = INPORT_VENDOR; + inport_dev->id.product = 0x0001; + inport_dev->id.version = 0x0100; + + inport_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL); + inport_dev->keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); + inport_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y); + + inport_dev->open = inport_open; + inport_dev->close = inport_close; + outb(INPORT_RESET, INPORT_CONTROL_PORT); outb(INPORT_REG_MODE, INPORT_CONTROL_PORT); outb(INPORT_MODE_BASE, INPORT_DATA_PORT); - input_register_device(&inport_dev); - - printk(KERN_INFO "input: " INPORT_NAME " at %#x irq %d\n", INPORT_BASE, inport_irq); + input_register_device(inport_dev); return 0; } static void __exit inport_exit(void) { - input_unregister_device(&inport_dev); + input_unregister_device(inport_dev); release_region(INPORT_BASE, INPORT_EXTENT); } diff --git a/drivers/input/mouse/lifebook.c b/drivers/input/mouse/lifebook.c index bd9df9b28325..55991424ac91 100644 --- a/drivers/input/mouse/lifebook.c +++ b/drivers/input/mouse/lifebook.c @@ -34,7 +34,7 @@ static struct dmi_system_id lifebook_dmi_table[] = { static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse, struct pt_regs *regs) { unsigned char *packet = psmouse->packet; - struct input_dev *dev = &psmouse->dev; + struct input_dev *dev = psmouse->dev; if (psmouse->pktcnt != 3) return PSMOUSE_GOOD_DATA; @@ -113,15 +113,17 @@ int lifebook_detect(struct psmouse *psmouse, int set_properties) int lifebook_init(struct psmouse *psmouse) { + struct input_dev *input_dev = psmouse->dev; + if (lifebook_absolute_mode(psmouse)) return -1; - psmouse->dev.evbit[0] = BIT(EV_ABS) | BIT(EV_KEY) | BIT(EV_REL); - psmouse->dev.keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); - psmouse->dev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); - psmouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y); - input_set_abs_params(&psmouse->dev, ABS_X, 0, 1024, 0, 0); - input_set_abs_params(&psmouse->dev, ABS_Y, 0, 1024, 0, 0); + input_dev->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY) | BIT(EV_REL); + input_dev->keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); + input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); + input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y); + input_set_abs_params(input_dev, ABS_X, 0, 1024, 0, 0); + input_set_abs_params(input_dev, ABS_Y, 0, 1024, 0, 0); psmouse->protocol_handler = lifebook_process_byte; psmouse->set_resolution = lifebook_set_resolution; diff --git a/drivers/input/mouse/logibm.c b/drivers/input/mouse/logibm.c index 8b5243167227..9c7ce38806d7 100644 --- a/drivers/input/mouse/logibm.c +++ b/drivers/input/mouse/logibm.c @@ -77,39 +77,7 @@ MODULE_PARM_DESC(irq, "IRQ number (5=default)"); __obsolete_setup("logibm_irq="); -static irqreturn_t logibm_interrupt(int irq, void *dev_id, struct pt_regs *regs); - -static int logibm_open(struct input_dev *dev) -{ - if (request_irq(logibm_irq, logibm_interrupt, 0, "logibm", NULL)) { - printk(KERN_ERR "logibm.c: Can't allocate irq %d\n", logibm_irq); - return -EBUSY; - } - outb(LOGIBM_ENABLE_IRQ, LOGIBM_CONTROL_PORT); - return 0; -} - -static void logibm_close(struct input_dev *dev) -{ - outb(LOGIBM_DISABLE_IRQ, LOGIBM_CONTROL_PORT); - free_irq(logibm_irq, NULL); -} - -static struct input_dev logibm_dev = { - .evbit = { BIT(EV_KEY) | BIT(EV_REL) }, - .keybit = { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT) }, - .relbit = { BIT(REL_X) | BIT(REL_Y) }, - .open = logibm_open, - .close = logibm_close, - .name = "Logitech bus mouse", - .phys = "isa023c/input0", - .id = { - .bustype = BUS_ISA, - .vendor = 0x0003, - .product = 0x0001, - .version = 0x0100, - }, -}; +static struct input_dev *logibm_dev; static irqreturn_t logibm_interrupt(int irq, void *dev_id, struct pt_regs *regs) { @@ -127,18 +95,34 @@ static irqreturn_t logibm_interrupt(int irq, void *dev_id, struct pt_regs *regs) dy |= (buttons & 0xf) << 4; buttons = ~buttons >> 5; - input_regs(&logibm_dev, regs); - input_report_rel(&logibm_dev, REL_X, dx); - input_report_rel(&logibm_dev, REL_Y, dy); - input_report_key(&logibm_dev, BTN_RIGHT, buttons & 1); - input_report_key(&logibm_dev, BTN_MIDDLE, buttons & 2); - input_report_key(&logibm_dev, BTN_LEFT, buttons & 4); - input_sync(&logibm_dev); + input_regs(logibm_dev, regs); + input_report_rel(logibm_dev, REL_X, dx); + input_report_rel(logibm_dev, REL_Y, dy); + input_report_key(logibm_dev, BTN_RIGHT, buttons & 1); + input_report_key(logibm_dev, BTN_MIDDLE, buttons & 2); + input_report_key(logibm_dev, BTN_LEFT, buttons & 4); + input_sync(logibm_dev); outb(LOGIBM_ENABLE_IRQ, LOGIBM_CONTROL_PORT); return IRQ_HANDLED; } +static int logibm_open(struct input_dev *dev) +{ + if (request_irq(logibm_irq, logibm_interrupt, 0, "logibm", NULL)) { + printk(KERN_ERR "logibm.c: Can't allocate irq %d\n", logibm_irq); + return -EBUSY; + } + outb(LOGIBM_ENABLE_IRQ, LOGIBM_CONTROL_PORT); + return 0; +} + +static void logibm_close(struct input_dev *dev) +{ + outb(LOGIBM_DISABLE_IRQ, LOGIBM_CONTROL_PORT); + free_irq(logibm_irq, NULL); +} + static int __init logibm_init(void) { if (!request_region(LOGIBM_BASE, LOGIBM_EXTENT, "logibm")) { @@ -159,16 +143,34 @@ static int __init logibm_init(void) outb(LOGIBM_DEFAULT_MODE, LOGIBM_CONFIG_PORT); outb(LOGIBM_DISABLE_IRQ, LOGIBM_CONTROL_PORT); - input_register_device(&logibm_dev); + if (!(logibm_dev = input_allocate_device())) { + printk(KERN_ERR "logibm.c: Not enough memory for input device\n"); + release_region(LOGIBM_BASE, LOGIBM_EXTENT); + return -ENOMEM; + } + + logibm_dev->name = "Logitech bus mouse"; + logibm_dev->phys = "isa023c/input0"; + logibm_dev->id.bustype = BUS_ISA; + logibm_dev->id.vendor = 0x0003; + logibm_dev->id.product = 0x0001; + logibm_dev->id.version = 0x0100; + + logibm_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL); + logibm_dev->keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); + logibm_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y); + + logibm_dev->open = logibm_open; + logibm_dev->close = logibm_close; - printk(KERN_INFO "input: Logitech bus mouse at %#x irq %d\n", LOGIBM_BASE, logibm_irq); + input_register_device(logibm_dev); return 0; } static void __exit logibm_exit(void) { - input_unregister_device(&logibm_dev); + input_unregister_device(logibm_dev); release_region(LOGIBM_BASE, LOGIBM_EXTENT); } diff --git a/drivers/input/mouse/logips2pp.c b/drivers/input/mouse/logips2pp.c index 7df96525222e..0f69ff46c1ae 100644 --- a/drivers/input/mouse/logips2pp.c +++ b/drivers/input/mouse/logips2pp.c @@ -40,7 +40,7 @@ struct ps2pp_info { static psmouse_ret_t ps2pp_process_byte(struct psmouse *psmouse, struct pt_regs *regs) { - struct input_dev *dev = &psmouse->dev; + struct input_dev *dev = psmouse->dev; unsigned char *packet = psmouse->packet; if (psmouse->pktcnt < 3) @@ -257,25 +257,27 @@ static struct ps2pp_info *get_model_info(unsigned char model) static void ps2pp_set_model_properties(struct psmouse *psmouse, struct ps2pp_info *model_info, int using_ps2pp) { + struct input_dev *input_dev = psmouse->dev; + if (model_info->features & PS2PP_SIDE_BTN) - set_bit(BTN_SIDE, psmouse->dev.keybit); + set_bit(BTN_SIDE, input_dev->keybit); if (model_info->features & PS2PP_EXTRA_BTN) - set_bit(BTN_EXTRA, psmouse->dev.keybit); + set_bit(BTN_EXTRA, input_dev->keybit); if (model_info->features & PS2PP_TASK_BTN) - set_bit(BTN_TASK, psmouse->dev.keybit); + set_bit(BTN_TASK, input_dev->keybit); if (model_info->features & PS2PP_NAV_BTN) { - set_bit(BTN_FORWARD, psmouse->dev.keybit); - set_bit(BTN_BACK, psmouse->dev.keybit); + set_bit(BTN_FORWARD, input_dev->keybit); + set_bit(BTN_BACK, input_dev->keybit); } if (model_info->features & PS2PP_WHEEL) - set_bit(REL_WHEEL, psmouse->dev.relbit); + set_bit(REL_WHEEL, input_dev->relbit); if (model_info->features & PS2PP_HWHEEL) - set_bit(REL_HWHEEL, psmouse->dev.relbit); + set_bit(REL_HWHEEL, input_dev->relbit); switch (model_info->kind) { case PS2PP_KIND_WHEEL: @@ -387,7 +389,7 @@ int ps2pp_init(struct psmouse *psmouse, int set_properties) } if (buttons < 3) - clear_bit(BTN_MIDDLE, psmouse->dev.keybit); + clear_bit(BTN_MIDDLE, psmouse->dev->keybit); if (model_info) ps2pp_set_model_properties(psmouse, model_info, use_ps2pp); diff --git a/drivers/input/mouse/maplemouse.c b/drivers/input/mouse/maplemouse.c index e90c60cbbf05..b5b34fe4fee8 100644 --- a/drivers/input/mouse/maplemouse.c +++ b/drivers/input/mouse/maplemouse.c @@ -41,13 +41,12 @@ static int dc_mouse_connect(struct maple_device *dev) unsigned long data = be32_to_cpu(dev->devinfo.function_data[0]); struct input_dev *input_dev; - if (!(input_dev = kmalloc(sizeof(struct input_dev), GFP_KERNEL))) - return -1; + dev->private_data = input_dev = input_allocate_device(); + if (!input_dev) + return -ENOMEM; dev->private_data = input_dev; - memset(input_dev, 0, sizeof(struct dc_mouse)); - init_input_dev(input_dev); input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL); input_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE); input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y) | BIT(REL_WHEEL); @@ -59,8 +58,6 @@ static int dc_mouse_connect(struct maple_device *dev) maple_getcond_callback(dev, dc_mouse_callback, 1, MAPLE_FUNC_MOUSE); - printk(KERN_INFO "input: mouse(0x%lx): %s\n", data, input_dev->name); - return 0; } @@ -70,7 +67,6 @@ static void dc_mouse_disconnect(struct maple_device *dev) struct input_dev *input_dev = dev->private_data; input_unregister_device(input_dev); - kfree(input_dev); } diff --git a/drivers/input/mouse/pc110pad.c b/drivers/input/mouse/pc110pad.c index 93393d5c0078..d284ea712151 100644 --- a/drivers/input/mouse/pc110pad.c +++ b/drivers/input/mouse/pc110pad.c @@ -53,13 +53,10 @@ MODULE_LICENSE("GPL"); static int pc110pad_irq = 10; static int pc110pad_io = 0x15e0; -static struct input_dev pc110pad_dev; +static struct input_dev *pc110pad_dev; static int pc110pad_data[3]; static int pc110pad_count; -static char *pc110pad_name = "IBM PC110 TouchPad"; -static char *pc110pad_phys = "isa15e0/input0"; - static irqreturn_t pc110pad_interrupt(int irq, void *ptr, struct pt_regs *regs) { int value = inb_p(pc110pad_io); @@ -74,14 +71,14 @@ static irqreturn_t pc110pad_interrupt(int irq, void *ptr, struct pt_regs *regs) if (pc110pad_count < 3) return IRQ_HANDLED; - input_regs(&pc110pad_dev, regs); - input_report_key(&pc110pad_dev, BTN_TOUCH, + input_regs(pc110pad_dev, regs); + input_report_key(pc110pad_dev, BTN_TOUCH, pc110pad_data[0] & 0x01); - input_report_abs(&pc110pad_dev, ABS_X, + input_report_abs(pc110pad_dev, ABS_X, pc110pad_data[1] | ((pc110pad_data[0] << 3) & 0x80) | ((pc110pad_data[0] << 1) & 0x100)); - input_report_abs(&pc110pad_dev, ABS_Y, + input_report_abs(pc110pad_dev, ABS_Y, pc110pad_data[2] | ((pc110pad_data[0] << 4) & 0x80)); - input_sync(&pc110pad_dev); + input_sync(pc110pad_dev); pc110pad_count = 0; return IRQ_HANDLED; @@ -94,9 +91,9 @@ static void pc110pad_close(struct input_dev *dev) static int pc110pad_open(struct input_dev *dev) { - pc110pad_interrupt(0,NULL,NULL); - pc110pad_interrupt(0,NULL,NULL); - pc110pad_interrupt(0,NULL,NULL); + pc110pad_interrupt(0, NULL, NULL); + pc110pad_interrupt(0, NULL, NULL); + pc110pad_interrupt(0, NULL, NULL); outb(PC110PAD_ON, pc110pad_io + 2); pc110pad_count = 0; @@ -127,45 +124,46 @@ static int __init pc110pad_init(void) outb(PC110PAD_OFF, pc110pad_io + 2); - if (request_irq(pc110pad_irq, pc110pad_interrupt, 0, "pc110pad", NULL)) - { + if (request_irq(pc110pad_irq, pc110pad_interrupt, 0, "pc110pad", NULL)) { release_region(pc110pad_io, 4); printk(KERN_ERR "pc110pad: Unable to get irq %d.\n", pc110pad_irq); return -EBUSY; } - pc110pad_dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - pc110pad_dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y); - pc110pad_dev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); + if (!(pc110pad_dev = input_allocate_device())) { + free_irq(pc110pad_irq, NULL); + release_region(pc110pad_io, 4); + printk(KERN_ERR "pc110pad: Not enough memory.\n"); + return -ENOMEM; + } - pc110pad_dev.absmax[ABS_X] = 0x1ff; - pc110pad_dev.absmax[ABS_Y] = 0x0ff; + pc110pad_dev->name = "IBM PC110 TouchPad"; + pc110pad_dev->phys = "isa15e0/input0"; + pc110pad_dev->id.bustype = BUS_ISA; + pc110pad_dev->id.vendor = 0x0003; + pc110pad_dev->id.product = 0x0001; + pc110pad_dev->id.version = 0x0100; - pc110pad_dev.open = pc110pad_open; - pc110pad_dev.close = pc110pad_close; + pc110pad_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + pc110pad_dev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y); + pc110pad_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); - pc110pad_dev.name = pc110pad_name; - pc110pad_dev.phys = pc110pad_phys; - pc110pad_dev.id.bustype = BUS_ISA; - pc110pad_dev.id.vendor = 0x0003; - pc110pad_dev.id.product = 0x0001; - pc110pad_dev.id.version = 0x0100; + pc110pad_dev->absmax[ABS_X] = 0x1ff; + pc110pad_dev->absmax[ABS_Y] = 0x0ff; - input_register_device(&pc110pad_dev); + pc110pad_dev->open = pc110pad_open; + pc110pad_dev->close = pc110pad_close; - printk(KERN_INFO "input: %s at %#x irq %d\n", - pc110pad_name, pc110pad_io, pc110pad_irq); + input_register_device(pc110pad_dev); return 0; } static void __exit pc110pad_exit(void) { - input_unregister_device(&pc110pad_dev); - outb(PC110PAD_OFF, pc110pad_io + 2); - free_irq(pc110pad_irq, NULL); + input_unregister_device(pc110pad_dev); release_region(pc110pad_io, 4); } diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index af24313ff5bb..6ee9999a2eaa 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -114,7 +114,7 @@ struct psmouse_protocol { static psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse, struct pt_regs *regs) { - struct input_dev *dev = &psmouse->dev; + struct input_dev *dev = psmouse->dev; unsigned char *packet = psmouse->packet; if (psmouse->pktcnt < psmouse->pktsize) @@ -333,12 +333,11 @@ static int genius_detect(struct psmouse *psmouse, int set_properties) return -1; if (set_properties) { - set_bit(BTN_EXTRA, psmouse->dev.keybit); - set_bit(BTN_SIDE, psmouse->dev.keybit); - set_bit(REL_WHEEL, psmouse->dev.relbit); + set_bit(BTN_EXTRA, psmouse->dev->keybit); + set_bit(BTN_SIDE, psmouse->dev->keybit); + set_bit(REL_WHEEL, psmouse->dev->relbit); psmouse->vendor = "Genius"; - psmouse->name = "Wheel Mouse"; psmouse->pktsize = 4; } @@ -365,8 +364,8 @@ static int intellimouse_detect(struct psmouse *psmouse, int set_properties) return -1; if (set_properties) { - set_bit(BTN_MIDDLE, psmouse->dev.keybit); - set_bit(REL_WHEEL, psmouse->dev.relbit); + set_bit(BTN_MIDDLE, psmouse->dev->keybit); + set_bit(REL_WHEEL, psmouse->dev->relbit); if (!psmouse->vendor) psmouse->vendor = "Generic"; if (!psmouse->name) psmouse->name = "Wheel Mouse"; @@ -398,10 +397,10 @@ static int im_explorer_detect(struct psmouse *psmouse, int set_properties) return -1; if (set_properties) { - set_bit(BTN_MIDDLE, psmouse->dev.keybit); - set_bit(REL_WHEEL, psmouse->dev.relbit); - set_bit(BTN_SIDE, psmouse->dev.keybit); - set_bit(BTN_EXTRA, psmouse->dev.keybit); + set_bit(BTN_MIDDLE, psmouse->dev->keybit); + set_bit(REL_WHEEL, psmouse->dev->relbit); + set_bit(BTN_SIDE, psmouse->dev->keybit); + set_bit(BTN_EXTRA, psmouse->dev->keybit); if (!psmouse->vendor) psmouse->vendor = "Generic"; if (!psmouse->name) psmouse->name = "Explorer Mouse"; @@ -433,7 +432,7 @@ static int thinking_detect(struct psmouse *psmouse, int set_properties) return -1; if (set_properties) { - set_bit(BTN_EXTRA, psmouse->dev.keybit); + set_bit(BTN_EXTRA, psmouse->dev->keybit); psmouse->vendor = "Kensington"; psmouse->name = "ThinkingMouse"; @@ -839,9 +838,9 @@ static void psmouse_disconnect(struct serio *serio) psmouse_set_state(psmouse, PSMOUSE_IGNORE); - input_unregister_device(&psmouse->dev); serio_close(serio); serio_set_drvdata(serio, NULL); + input_unregister_device(psmouse->dev); kfree(psmouse); if (parent) @@ -852,16 +851,14 @@ static void psmouse_disconnect(struct serio *serio) static int psmouse_switch_protocol(struct psmouse *psmouse, struct psmouse_protocol *proto) { - memset(&psmouse->dev, 0, sizeof(struct input_dev)); + struct input_dev *input_dev = psmouse->dev; - init_input_dev(&psmouse->dev); + input_dev->private = psmouse; + input_dev->cdev.dev = &psmouse->ps2dev.serio->dev; - psmouse->dev.private = psmouse; - psmouse->dev.dev = &psmouse->ps2dev.serio->dev; - - psmouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); - psmouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); - psmouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y); + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL); + input_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); + input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y); psmouse->set_rate = psmouse_set_rate; psmouse->set_resolution = psmouse_set_resolution; @@ -883,12 +880,12 @@ static int psmouse_switch_protocol(struct psmouse *psmouse, struct psmouse_proto sprintf(psmouse->devname, "%s %s %s", psmouse_protocol_by_type(psmouse->type)->name, psmouse->vendor, psmouse->name); - psmouse->dev.name = psmouse->devname; - psmouse->dev.phys = psmouse->phys; - psmouse->dev.id.bustype = BUS_I8042; - psmouse->dev.id.vendor = 0x0002; - psmouse->dev.id.product = psmouse->type; - psmouse->dev.id.version = psmouse->model; + input_dev->name = psmouse->devname; + input_dev->phys = psmouse->phys; + input_dev->id.bustype = BUS_I8042; + input_dev->id.vendor = 0x0002; + input_dev->id.product = psmouse->type; + input_dev->id.version = psmouse->model; return 0; } @@ -900,7 +897,8 @@ static int psmouse_switch_protocol(struct psmouse *psmouse, struct psmouse_proto static int psmouse_connect(struct serio *serio, struct serio_driver *drv) { struct psmouse *psmouse, *parent = NULL; - int retval; + struct input_dev *input_dev; + int retval = -ENOMEM; down(&psmouse_sem); @@ -913,12 +911,13 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv) psmouse_deactivate(parent); } - if (!(psmouse = kzalloc(sizeof(struct psmouse), GFP_KERNEL))) { - retval = -ENOMEM; + psmouse = kzalloc(sizeof(struct psmouse), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!psmouse || !input_dev) goto out; - } ps2_init(&psmouse->ps2dev, serio); + psmouse->dev = input_dev; sprintf(psmouse->phys, "%s/input0", serio->phys); psmouse_set_state(psmouse, PSMOUSE_INITIALIZING); @@ -926,16 +925,11 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv) serio_set_drvdata(serio, psmouse); retval = serio_open(serio, drv); - if (retval) { - serio_set_drvdata(serio, NULL); - kfree(psmouse); + if (retval) goto out; - } if (psmouse_probe(psmouse) < 0) { serio_close(serio); - serio_set_drvdata(serio, NULL); - kfree(psmouse); retval = -ENODEV; goto out; } @@ -947,13 +941,11 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv) psmouse_switch_protocol(psmouse, NULL); - input_register_device(&psmouse->dev); - printk(KERN_INFO "input: %s on %s\n", psmouse->devname, serio->phys); - psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); - psmouse_initialize(psmouse); + input_register_device(psmouse->dev); + if (parent && parent->pt_activate) parent->pt_activate(parent); @@ -964,6 +956,12 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv) retval = 0; out: + if (retval) { + serio_set_drvdata(serio, NULL); + input_free_device(input_dev); + kfree(psmouse); + } + /* If this is a pass-through port the parent needs to be re-activated */ if (parent) psmouse_activate(parent); @@ -1161,6 +1159,7 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, co { struct serio *serio = psmouse->ps2dev.serio; struct psmouse *parent = NULL; + struct input_dev *new_dev; struct psmouse_protocol *proto; int retry = 0; @@ -1170,9 +1169,13 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, co if (psmouse->type == proto->type) return count; + if (!(new_dev = input_allocate_device())) + return -ENOMEM; + while (serio->child) { if (++retry > 3) { printk(KERN_WARNING "psmouse: failed to destroy child port, protocol change aborted.\n"); + input_free_device(new_dev); return -EIO; } @@ -1182,11 +1185,15 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, co serio_pin_driver_uninterruptible(serio); down(&psmouse_sem); - if (serio->drv != &psmouse_drv) + if (serio->drv != &psmouse_drv) { + input_free_device(new_dev); return -ENODEV; + } - if (psmouse->type == proto->type) + if (psmouse->type == proto->type) { + input_free_device(new_dev); return count; /* switched by other thread */ + } } if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) { @@ -1199,8 +1206,9 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, co psmouse->disconnect(psmouse); psmouse_set_state(psmouse, PSMOUSE_IGNORE); - input_unregister_device(&psmouse->dev); + input_unregister_device(psmouse->dev); + psmouse->dev = new_dev; psmouse_set_state(psmouse, PSMOUSE_INITIALIZING); if (psmouse_switch_protocol(psmouse, proto) < 0) { @@ -1212,8 +1220,7 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, co psmouse_initialize(psmouse); psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); - input_register_device(&psmouse->dev); - printk(KERN_INFO "input: %s on %s\n", psmouse->devname, serio->phys); + input_register_device(psmouse->dev); if (parent && parent->pt_activate) parent->pt_activate(parent); diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h index 45d2bd774f00..7c4192bd1279 100644 --- a/drivers/input/mouse/psmouse.h +++ b/drivers/input/mouse/psmouse.h @@ -36,7 +36,7 @@ typedef enum { struct psmouse { void *private; - struct input_dev dev; + struct input_dev *dev; struct ps2dev ps2dev; char *vendor; char *name; diff --git a/drivers/input/mouse/rpcmouse.c b/drivers/input/mouse/rpcmouse.c index 8fe1212b8fd7..09b6ffdb7582 100644 --- a/drivers/input/mouse/rpcmouse.c +++ b/drivers/input/mouse/rpcmouse.c @@ -34,20 +34,7 @@ MODULE_DESCRIPTION("Acorn RiscPC mouse driver"); MODULE_LICENSE("GPL"); static short rpcmouse_lastx, rpcmouse_lasty; - -static struct input_dev rpcmouse_dev = { - .evbit = { BIT(EV_KEY) | BIT(EV_REL) }, - .keybit = { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT) }, - .relbit = { BIT(REL_X) | BIT(REL_Y) }, - .name = "Acorn RiscPC Mouse", - .phys = "rpcmouse/input0", - .id = { - .bustype = BUS_HOST, - .vendor = 0x0005, - .product = 0x0001, - .version = 0x0100, - }, -}; +static struct input_dev *rpcmouse_dev; static irqreturn_t rpcmouse_irq(int irq, void *dev_id, struct pt_regs *regs) { @@ -78,29 +65,41 @@ static irqreturn_t rpcmouse_irq(int irq, void *dev_id, struct pt_regs *regs) return IRQ_HANDLED; } + static int __init rpcmouse_init(void) { - init_input_dev(&rpcmouse_dev); + if (!(rpcmouse_dev = input_allocate_device())) + return -ENOMEM; + + rpcmouse_dev->name = "Acorn RiscPC Mouse"; + rpcmouse_dev->phys = "rpcmouse/input0"; + rpcmouse_dev->id.bustype = BUS_HOST; + rpcmouse_dev->id.vendor = 0x0005; + rpcmouse_dev->id.product = 0x0001; + rpcmouse_dev->id.version = 0x0100; + + rpcmouse_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL); + rpcmouse_dev->keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); + rpcmouse_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y); rpcmouse_lastx = (short) iomd_readl(IOMD_MOUSEX); rpcmouse_lasty = (short) iomd_readl(IOMD_MOUSEY); - if (request_irq(IRQ_VSYNCPULSE, rpcmouse_irq, SA_SHIRQ, "rpcmouse", &rpcmouse_dev)) { + if (request_irq(IRQ_VSYNCPULSE, rpcmouse_irq, SA_SHIRQ, "rpcmouse", rpcmouse_dev)) { printk(KERN_ERR "rpcmouse: unable to allocate VSYNC interrupt\n"); - return -1; + input_free_device(rpcmouse_dev); + return -EBUSY; } - input_register_device(&rpcmouse_dev); - - printk(KERN_INFO "input: Acorn RiscPC mouse\n"); + input_register_device(rpcmouse_dev); return 0; } static void __exit rpcmouse_exit(void) { - input_unregister_device(&rpcmouse_dev); - free_irq(IRQ_VSYNCPULSE, &rpcmouse_dev); + free_irq(IRQ_VSYNCPULSE, rpcmouse_dev); + input_unregister_device(rpcmouse_dev); } module_init(rpcmouse_init); diff --git a/drivers/input/mouse/sermouse.c b/drivers/input/mouse/sermouse.c index d12b93ae3900..4bf584364d28 100644 --- a/drivers/input/mouse/sermouse.c +++ b/drivers/input/mouse/sermouse.c @@ -48,7 +48,7 @@ static char *sermouse_protocols[] = { "None", "Mouse Systems Mouse", "Sun Mouse" "Logitech MZ++ Mouse"}; struct sermouse { - struct input_dev dev; + struct input_dev *dev; signed char buf[8]; unsigned char count; unsigned char type; @@ -64,7 +64,7 @@ struct sermouse { static void sermouse_process_msc(struct sermouse *sermouse, signed char data, struct pt_regs *regs) { - struct input_dev *dev = &sermouse->dev; + struct input_dev *dev = sermouse->dev; signed char *buf = sermouse->buf; input_regs(dev, regs); @@ -107,7 +107,7 @@ static void sermouse_process_msc(struct sermouse *sermouse, signed char data, st static void sermouse_process_ms(struct sermouse *sermouse, signed char data, struct pt_regs *regs) { - struct input_dev *dev = &sermouse->dev; + struct input_dev *dev = sermouse->dev; signed char *buf = sermouse->buf; if (data & 0x40) sermouse->count = 0; @@ -230,9 +230,9 @@ static void sermouse_disconnect(struct serio *serio) { struct sermouse *sermouse = serio_get_drvdata(serio); - input_unregister_device(&sermouse->dev); serio_close(serio); serio_set_drvdata(serio, NULL); + input_unregister_device(sermouse->dev); kfree(sermouse); } @@ -244,56 +244,52 @@ static void sermouse_disconnect(struct serio *serio) static int sermouse_connect(struct serio *serio, struct serio_driver *drv) { struct sermouse *sermouse; - unsigned char c; - int err; + struct input_dev *input_dev; + unsigned char c = serio->id.extra; + int err = -ENOMEM; - if (!serio->id.proto || serio->id.proto > SERIO_MZPP) - return -ENODEV; - - if (!(sermouse = kmalloc(sizeof(struct sermouse), GFP_KERNEL))) - return -ENOMEM; - - memset(sermouse, 0, sizeof(struct sermouse)); - - init_input_dev(&sermouse->dev); - sermouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); - sermouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT); - sermouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y); - sermouse->dev.private = sermouse; - - sermouse->type = serio->id.proto; - c = serio->id.extra; - - if (c & 0x01) set_bit(BTN_MIDDLE, sermouse->dev.keybit); - if (c & 0x02) set_bit(BTN_SIDE, sermouse->dev.keybit); - if (c & 0x04) set_bit(BTN_EXTRA, sermouse->dev.keybit); - if (c & 0x10) set_bit(REL_WHEEL, sermouse->dev.relbit); - if (c & 0x20) set_bit(REL_HWHEEL, sermouse->dev.relbit); + sermouse = kzalloc(sizeof(struct sermouse), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!sermouse || !input_dev) + goto fail; + sermouse->dev = input_dev; sprintf(sermouse->phys, "%s/input0", serio->phys); + sermouse->type = serio->id.proto; - sermouse->dev.name = sermouse_protocols[sermouse->type]; - sermouse->dev.phys = sermouse->phys; - sermouse->dev.id.bustype = BUS_RS232; - sermouse->dev.id.vendor = sermouse->type; - sermouse->dev.id.product = c; - sermouse->dev.id.version = 0x0100; - sermouse->dev.dev = &serio->dev; + input_dev->name = sermouse_protocols[sermouse->type]; + input_dev->phys = sermouse->phys; + input_dev->id.bustype = BUS_RS232; + input_dev->id.vendor = sermouse->type; + input_dev->id.product = c; + input_dev->id.version = 0x0100; + input_dev->cdev.dev = &serio->dev; + + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL); + input_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT); + input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y); + input_dev->private = sermouse; + + if (c & 0x01) set_bit(BTN_MIDDLE, input_dev->keybit); + if (c & 0x02) set_bit(BTN_SIDE, input_dev->keybit); + if (c & 0x04) set_bit(BTN_EXTRA, input_dev->keybit); + if (c & 0x10) set_bit(REL_WHEEL, input_dev->relbit); + if (c & 0x20) set_bit(REL_HWHEEL, input_dev->relbit); serio_set_drvdata(serio, sermouse); err = serio_open(serio, drv); - if (err) { - serio_set_drvdata(serio, NULL); - kfree(sermouse); - return err; - } - - input_register_device(&sermouse->dev); + if (err) + goto fail; - printk(KERN_INFO "input: %s on %s\n", sermouse_protocols[sermouse->type], serio->phys); + input_register_device(sermouse->dev); return 0; + + fail: serio_set_drvdata(serio, NULL); + input_free_device(input_dev); + kfree(sermouse); + return err; } static struct serio_device_id sermouse_serio_ids[] = { diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 029309422409..97cdfd6acaca 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -342,7 +342,7 @@ static void synaptics_parse_hw_state(unsigned char buf[], struct synaptics_data */ static void synaptics_process_packet(struct psmouse *psmouse) { - struct input_dev *dev = &psmouse->dev; + struct input_dev *dev = psmouse->dev; struct synaptics_data *priv = psmouse->private; struct synaptics_hw_state hw; int num_fingers; @@ -473,7 +473,7 @@ static unsigned char synaptics_detect_pkt_type(struct psmouse *psmouse) static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs) { - struct input_dev *dev = &psmouse->dev; + struct input_dev *dev = psmouse->dev; struct synaptics_data *priv = psmouse->private; input_regs(dev, regs); @@ -645,7 +645,7 @@ int synaptics_init(struct psmouse *psmouse) SYN_ID_MAJOR(priv->identity), SYN_ID_MINOR(priv->identity), priv->model_id, priv->capabilities, priv->ext_cap); - set_input_params(&psmouse->dev, priv); + set_input_params(psmouse->dev, priv); psmouse->protocol_handler = synaptics_process_byte; psmouse->set_rate = synaptics_set_rate; diff --git a/drivers/input/mouse/vsxxxaa.c b/drivers/input/mouse/vsxxxaa.c index f024be9b44d2..36e9442a16b2 100644 --- a/drivers/input/mouse/vsxxxaa.c +++ b/drivers/input/mouse/vsxxxaa.c @@ -112,7 +112,7 @@ MODULE_LICENSE ("GPL"); struct vsxxxaa { - struct input_dev dev; + struct input_dev *dev; struct serio *serio; #define BUFLEN 15 /* At least 5 is needed for a full tablet packet */ unsigned char buf[BUFLEN]; @@ -211,7 +211,7 @@ vsxxxaa_smells_like_packet (struct vsxxxaa *mouse, unsigned char type, size_t le static void vsxxxaa_handle_REL_packet (struct vsxxxaa *mouse, struct pt_regs *regs) { - struct input_dev *dev = &mouse->dev; + struct input_dev *dev = mouse->dev; unsigned char *buf = mouse->buf; int left, middle, right; int dx, dy; @@ -269,7 +269,7 @@ vsxxxaa_handle_REL_packet (struct vsxxxaa *mouse, struct pt_regs *regs) static void vsxxxaa_handle_ABS_packet (struct vsxxxaa *mouse, struct pt_regs *regs) { - struct input_dev *dev = &mouse->dev; + struct input_dev *dev = mouse->dev; unsigned char *buf = mouse->buf; int left, middle, right, touch; int x, y; @@ -323,7 +323,7 @@ vsxxxaa_handle_ABS_packet (struct vsxxxaa *mouse, struct pt_regs *regs) static void vsxxxaa_handle_POR_packet (struct vsxxxaa *mouse, struct pt_regs *regs) { - struct input_dev *dev = &mouse->dev; + struct input_dev *dev = mouse->dev; unsigned char *buf = mouse->buf; int left, middle, right; unsigned char error; @@ -483,9 +483,9 @@ vsxxxaa_disconnect (struct serio *serio) { struct vsxxxaa *mouse = serio_get_drvdata (serio); - input_unregister_device (&mouse->dev); serio_close (serio); serio_set_drvdata (serio, NULL); + input_unregister_device (mouse->dev); kfree (mouse); } @@ -493,61 +493,57 @@ static int vsxxxaa_connect (struct serio *serio, struct serio_driver *drv) { struct vsxxxaa *mouse; - int err; + struct input_dev *input_dev; + int err = -ENOMEM; - if (!(mouse = kmalloc (sizeof (struct vsxxxaa), GFP_KERNEL))) - return -ENOMEM; - - memset (mouse, 0, sizeof (struct vsxxxaa)); - - init_input_dev (&mouse->dev); - set_bit (EV_KEY, mouse->dev.evbit); /* We have buttons */ - set_bit (EV_REL, mouse->dev.evbit); - set_bit (EV_ABS, mouse->dev.evbit); - set_bit (BTN_LEFT, mouse->dev.keybit); /* We have 3 buttons */ - set_bit (BTN_MIDDLE, mouse->dev.keybit); - set_bit (BTN_RIGHT, mouse->dev.keybit); - set_bit (BTN_TOUCH, mouse->dev.keybit); /* ...and Tablet */ - set_bit (REL_X, mouse->dev.relbit); - set_bit (REL_Y, mouse->dev.relbit); - set_bit (ABS_X, mouse->dev.absbit); - set_bit (ABS_Y, mouse->dev.absbit); - - mouse->dev.absmin[ABS_X] = 0; - mouse->dev.absmax[ABS_X] = 1023; - mouse->dev.absmin[ABS_Y] = 0; - mouse->dev.absmax[ABS_Y] = 1023; - - mouse->dev.private = mouse; + mouse = kzalloc (sizeof (struct vsxxxaa), GFP_KERNEL); + input_dev = input_allocate_device (); + if (!mouse || !input_dev) + goto fail; + mouse->dev = input_dev; + mouse->serio = serio; sprintf (mouse->name, "DEC VSXXX-AA/-GA mouse or VSXXX-AB digitizer"); sprintf (mouse->phys, "%s/input0", serio->phys); - mouse->dev.name = mouse->name; - mouse->dev.phys = mouse->phys; - mouse->dev.id.bustype = BUS_RS232; - mouse->dev.dev = &serio->dev; - mouse->serio = serio; + + input_dev->name = mouse->name; + input_dev->phys = mouse->phys; + input_dev->id.bustype = BUS_RS232; + input_dev->cdev.dev = &serio->dev; + input_dev->private = mouse; + + set_bit (EV_KEY, input_dev->evbit); /* We have buttons */ + set_bit (EV_REL, input_dev->evbit); + set_bit (EV_ABS, input_dev->evbit); + set_bit (BTN_LEFT, input_dev->keybit); /* We have 3 buttons */ + set_bit (BTN_MIDDLE, input_dev->keybit); + set_bit (BTN_RIGHT, input_dev->keybit); + set_bit (BTN_TOUCH, input_dev->keybit); /* ...and Tablet */ + set_bit (REL_X, input_dev->relbit); + set_bit (REL_Y, input_dev->relbit); + input_set_abs_params (input_dev, ABS_X, 0, 1023, 0, 0); + input_set_abs_params (input_dev, ABS_Y, 0, 1023, 0, 0); serio_set_drvdata (serio, mouse); err = serio_open (serio, drv); - if (err) { - serio_set_drvdata (serio, NULL); - kfree (mouse); - return err; - } + if (err) + goto fail; /* * Request selftest. Standard packet format and differential * mode will be requested after the device ID'ed successfully. */ - mouse->serio->write (mouse->serio, 'T'); /* Test */ - - input_register_device (&mouse->dev); + serio->write (serio, 'T'); /* Test */ - printk (KERN_INFO "input: %s on %s\n", mouse->name, mouse->phys); + input_register_device (input_dev); return 0; + + fail: serio_set_drvdata (serio, NULL); + input_free_device (input_dev); + kfree (mouse); + return err; } static struct serio_device_id vsxxaa_serio_ids[] = { diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c index c6194a9dd174..2d0af44ac4b9 100644 --- a/drivers/input/mousedev.c +++ b/drivers/input/mousedev.c @@ -9,7 +9,7 @@ * the Free Software Foundation. */ -#define MOUSEDEV_MINOR_BASE 32 +#define MOUSEDEV_MINOR_BASE 32 #define MOUSEDEV_MINORS 32 #define MOUSEDEV_MIX 31 @@ -24,7 +24,6 @@ #include <linux/random.h> #include <linux/major.h> #include <linux/device.h> -#include <linux/devfs_fs_kernel.h> #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX #include <linux/miscdevice.h> #endif @@ -621,6 +620,7 @@ static struct file_operations mousedev_fops = { static struct input_handle *mousedev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id) { struct mousedev *mousedev; + struct class_device *cdev; int minor = 0; for (minor = 0; minor < MOUSEDEV_MINORS && mousedev_table[minor]; minor++); @@ -649,11 +649,13 @@ static struct input_handle *mousedev_connect(struct input_handler *handler, stru mousedev_table[minor] = mousedev; - devfs_mk_cdev(MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor), - S_IFCHR|S_IRUGO|S_IWUSR, "input/mouse%d", minor); - class_device_create(input_class, + cdev = class_device_create(&input_class, &dev->cdev, MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor), - dev->dev, "mouse%d", minor); + dev->cdev.dev, mousedev->name); + + /* temporary symlink to keep userspace happy */ + sysfs_create_link(&input_class.subsys.kset.kobj, &cdev->kobj, + mousedev->name); return &mousedev->handle; } @@ -663,9 +665,9 @@ static void mousedev_disconnect(struct input_handle *handle) struct mousedev *mousedev = handle->private; struct mousedev_list *list; - class_device_destroy(input_class, + sysfs_remove_link(&input_class.subsys.kset.kobj, mousedev->name); + class_device_destroy(&input_class, MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + mousedev->minor)); - devfs_remove("input/mouse%d", mousedev->minor); mousedev->exist = 0; if (mousedev->open) { @@ -738,9 +740,7 @@ static int __init mousedev_init(void) mousedev_mix.exist = 1; mousedev_mix.minor = MOUSEDEV_MIX; - devfs_mk_cdev(MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX), - S_IFCHR|S_IRUGO|S_IWUSR, "input/mice"); - class_device_create(input_class, + class_device_create(&input_class, NULL, MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX), NULL, "mice"); #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX @@ -759,8 +759,7 @@ static void __exit mousedev_exit(void) if (psaux_registered) misc_deregister(&psaux_mouse); #endif - devfs_remove("input/mice"); - class_device_destroy(input_class, + class_device_destroy(&input_class, MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX)); input_unregister_handler(&mousedev_handler); } diff --git a/drivers/input/serio/gscps2.c b/drivers/input/serio/gscps2.c index 897e4c12b642..a7b0de0f92b2 100644 --- a/drivers/input/serio/gscps2.c +++ b/drivers/input/serio/gscps2.c @@ -211,9 +211,6 @@ static void gscps2_reset(struct gscps2port *ps2port) writeb(0xff, addr+GSC_RESET); gscps2_flush(ps2port); spin_unlock_irqrestore(&ps2port->lock, flags); - - /* enable it */ - gscps2_enable(ps2port, ENABLE); } static LIST_HEAD(ps2port_list); @@ -307,6 +304,9 @@ static int gscps2_open(struct serio *port) gscps2_reset(ps2port); + /* enable it */ + gscps2_enable(ps2port, ENABLE); + gscps2_interrupt(0, NULL, NULL); return 0; @@ -331,7 +331,7 @@ static int __init gscps2_probe(struct parisc_device *dev) { struct gscps2port *ps2port; struct serio *serio; - unsigned long hpa = dev->hpa; + unsigned long hpa = dev->hpa.start; int ret; if (!dev->irq) @@ -370,8 +370,6 @@ static int __init gscps2_probe(struct parisc_device *dev) serio->port_data = ps2port; serio->dev.parent = &dev->dev; - list_add_tail(&ps2port->node, &ps2port_list); - ret = -EBUSY; if (request_irq(dev->irq, gscps2_interrupt, SA_SHIRQ, ps2port->port->name, ps2port)) goto fail_miserably; @@ -396,15 +394,16 @@ static int __init gscps2_probe(struct parisc_device *dev) serio_register_port(ps2port->port); + list_add_tail(&ps2port->node, &ps2port_list); + return 0; fail: free_irq(dev->irq, ps2port); fail_miserably: - list_del(&ps2port->node); iounmap(ps2port->addr); - release_mem_region(dev->hpa, GSC_STATUS + 4); + release_mem_region(dev->hpa.start, GSC_STATUS + 4); fail_nomem: kfree(ps2port); @@ -444,7 +443,7 @@ static struct parisc_device_id gscps2_device_tbl[] = { }; static struct parisc_driver parisc_ps2_driver = { - .name = "GSC PS2", + .name = "gsc_ps2", .id_table = gscps2_device_tbl, .probe = gscps2_probe, .remove = gscps2_remove, diff --git a/drivers/input/serio/hil_mlc.c b/drivers/input/serio/hil_mlc.c index c243cb6fdfc4..5704204964a3 100644 --- a/drivers/input/serio/hil_mlc.c +++ b/drivers/input/serio/hil_mlc.c @@ -801,7 +801,8 @@ static int hil_mlc_serio_open(struct serio *serio) { struct hil_mlc_serio_map *map; struct hil_mlc *mlc; - if (serio->private != NULL) return -EBUSY; + if (serio_get_drvdata(serio) != NULL) + return -EBUSY; map = serio->port_data; if (map == NULL) { @@ -832,11 +833,18 @@ static void hil_mlc_serio_close(struct serio *serio) { return; } - serio->private = NULL; + serio_set_drvdata(serio, NULL); serio->drv = NULL; /* TODO wake up interruptable */ } +static struct serio_device_id hil_mlc_serio_id = { + .type = SERIO_HIL_MLC, + .proto = SERIO_HIL, + .extra = SERIO_ANY, + .id = SERIO_ANY, +}; + int hil_mlc_register(hil_mlc *mlc) { int i; unsigned long flags; @@ -867,7 +875,7 @@ int hil_mlc_register(hil_mlc *mlc) { mlc_serio = kmalloc(sizeof(*mlc_serio), GFP_KERNEL); mlc->serio[i] = mlc_serio; memset(mlc_serio, 0, sizeof(*mlc_serio)); - mlc_serio->type = SERIO_HIL | SERIO_HIL_MLC; + mlc_serio->id = hil_mlc_serio_id; mlc_serio->write = hil_mlc_serio_write; mlc_serio->open = hil_mlc_serio_open; mlc_serio->close = hil_mlc_serio_close; diff --git a/drivers/input/serio/hp_sdc.c b/drivers/input/serio/hp_sdc.c index 7629452dd64b..a10348bb25e9 100644 --- a/drivers/input/serio/hp_sdc.c +++ b/drivers/input/serio/hp_sdc.c @@ -764,7 +764,7 @@ MODULE_DEVICE_TABLE(parisc, hp_sdc_tbl); static int __init hp_sdc_init_hppa(struct parisc_device *d); static struct parisc_driver hp_sdc_driver = { - .name = "HP SDC", + .name = "hp_sdc", .id_table = hp_sdc_tbl, .probe = hp_sdc_init_hppa, }; @@ -875,9 +875,9 @@ static int __init hp_sdc_init_hppa(struct parisc_device *d) hp_sdc.dev = d; hp_sdc.irq = d->irq; hp_sdc.nmi = d->aux_irq; - hp_sdc.base_io = d->hpa; - hp_sdc.data_io = d->hpa + 0x800; - hp_sdc.status_io = d->hpa + 0x801; + hp_sdc.base_io = d->hpa.start; + hp_sdc.data_io = d->hpa.start + 0x800; + hp_sdc.status_io = d->hpa.start + 0x801; return hp_sdc_init(); } diff --git a/drivers/input/serio/hp_sdc_mlc.c b/drivers/input/serio/hp_sdc_mlc.c index e3c44ffae674..1c9426fd5205 100644 --- a/drivers/input/serio/hp_sdc_mlc.c +++ b/drivers/input/serio/hp_sdc_mlc.c @@ -40,6 +40,7 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/string.h> +#include <asm/semaphore.h> #define PREFIX "HP SDC MLC: " diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index 40d451ce07ff..4bc40f159996 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -911,12 +911,10 @@ static long i8042_panic_blink(long count) * Here we try to restore the original BIOS settings */ -static int i8042_suspend(struct device *dev, pm_message_t state, u32 level) +static int i8042_suspend(struct device *dev, pm_message_t state) { - if (level == SUSPEND_DISABLE) { - del_timer_sync(&i8042_timer); - i8042_controller_reset(); - } + del_timer_sync(&i8042_timer); + i8042_controller_reset(); return 0; } @@ -926,13 +924,10 @@ static int i8042_suspend(struct device *dev, pm_message_t state, u32 level) * Here we try to reset everything back to a state in which suspended */ -static int i8042_resume(struct device *dev, u32 level) +static int i8042_resume(struct device *dev) { int i; - if (level != RESUME_ENABLE) - return 0; - if (i8042_ctl_test()) return -1; diff --git a/drivers/input/touchscreen/corgi_ts.c b/drivers/input/touchscreen/corgi_ts.c index 4c7fbe550365..0ba3e6562bff 100644 --- a/drivers/input/touchscreen/corgi_ts.c +++ b/drivers/input/touchscreen/corgi_ts.c @@ -41,8 +41,7 @@ struct ts_event { }; struct corgi_ts { - char phys[32]; - struct input_dev input; + struct input_dev *input; struct timer_list timer; struct ts_event tc; int pendown; @@ -182,14 +181,12 @@ static void new_data(struct corgi_ts *corgi_ts, struct pt_regs *regs) if (!corgi_ts->tc.pressure && corgi_ts->pendown == 0) return; - if (regs) - input_regs(&corgi_ts->input, regs); - - input_report_abs(&corgi_ts->input, ABS_X, corgi_ts->tc.x); - input_report_abs(&corgi_ts->input, ABS_Y, corgi_ts->tc.y); - input_report_abs(&corgi_ts->input, ABS_PRESSURE, corgi_ts->tc.pressure); - input_report_key(&corgi_ts->input, BTN_TOUCH, (corgi_ts->pendown != 0)); - input_sync(&corgi_ts->input); + input_regs(corgi_ts->input, regs); + input_report_abs(corgi_ts->input, ABS_X, corgi_ts->tc.x); + input_report_abs(corgi_ts->input, ABS_Y, corgi_ts->tc.y); + input_report_abs(corgi_ts->input, ABS_PRESSURE, corgi_ts->tc.pressure); + input_report_key(corgi_ts->input, BTN_TOUCH, (corgi_ts->pendown != 0)); + input_sync(corgi_ts->input); } static void ts_interrupt_main(struct corgi_ts *corgi_ts, int isTimer, struct pt_regs *regs) @@ -234,34 +231,32 @@ static irqreturn_t ts_interrupt(int irq, void *dev_id, struct pt_regs *regs) } #ifdef CONFIG_PM -static int corgits_suspend(struct device *dev, pm_message_t state, uint32_t level) +static int corgits_suspend(struct device *dev, pm_message_t state) { - if (level == SUSPEND_POWER_DOWN) { - struct corgi_ts *corgi_ts = dev_get_drvdata(dev); - - if (corgi_ts->pendown) { - del_timer_sync(&corgi_ts->timer); - corgi_ts->tc.pressure = 0; - new_data(corgi_ts, NULL); - corgi_ts->pendown = 0; - } - corgi_ts->power_mode = PWR_MODE_SUSPEND; + struct corgi_ts *corgi_ts = dev_get_drvdata(dev); - corgi_ssp_ads7846_putget((1u << ADSCTRL_ADR_SH) | ADSCTRL_STS); + if (corgi_ts->pendown) { + del_timer_sync(&corgi_ts->timer); + corgi_ts->tc.pressure = 0; + new_data(corgi_ts, NULL); + corgi_ts->pendown = 0; } + corgi_ts->power_mode = PWR_MODE_SUSPEND; + + corgi_ssp_ads7846_putget((1u << ADSCTRL_ADR_SH) | ADSCTRL_STS); + return 0; } -static int corgits_resume(struct device *dev, uint32_t level) +static int corgits_resume(struct device *dev) { - if (level == RESUME_POWER_ON) { - struct corgi_ts *corgi_ts = dev_get_drvdata(dev); + struct corgi_ts *corgi_ts = dev_get_drvdata(dev); + + corgi_ssp_ads7846_putget((4u << ADSCTRL_ADR_SH) | ADSCTRL_STS); + /* Enable Falling Edge */ + set_irq_type(corgi_ts->irq_gpio, IRQT_FALLING); + corgi_ts->power_mode = PWR_MODE_ACTIVE; - corgi_ssp_ads7846_putget((4u << ADSCTRL_ADR_SH) | ADSCTRL_STS); - /* Enable Falling Edge */ - set_irq_type(corgi_ts->irq_gpio, IRQT_FALLING); - corgi_ts->power_mode = PWR_MODE_ACTIVE; - } return 0; } #else @@ -273,39 +268,44 @@ static int __init corgits_probe(struct device *dev) { struct corgi_ts *corgi_ts; struct platform_device *pdev = to_platform_device(dev); + struct input_dev *input_dev; + int err = -ENOMEM; - if (!(corgi_ts = kmalloc(sizeof(struct corgi_ts), GFP_KERNEL))) - return -ENOMEM; + corgi_ts = kzalloc(sizeof(struct corgi_ts), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!corgi_ts || !input_dev) + goto fail; dev_set_drvdata(dev, corgi_ts); - memset(corgi_ts, 0, sizeof(struct corgi_ts)); - corgi_ts->machinfo = dev->platform_data; corgi_ts->irq_gpio = platform_get_irq(pdev, 0); if (corgi_ts->irq_gpio < 0) { - kfree(corgi_ts); - return -ENODEV; + err = -ENODEV; + goto fail; } - init_input_dev(&corgi_ts->input); - corgi_ts->input.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - corgi_ts->input.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); - input_set_abs_params(&corgi_ts->input, ABS_X, X_AXIS_MIN, X_AXIS_MAX, 0, 0); - input_set_abs_params(&corgi_ts->input, ABS_Y, Y_AXIS_MIN, Y_AXIS_MAX, 0, 0); - input_set_abs_params(&corgi_ts->input, ABS_PRESSURE, PRESSURE_MIN, PRESSURE_MAX, 0, 0); + corgi_ts->input = input_dev; - strcpy(corgi_ts->phys, "corgits/input0"); + init_timer(&corgi_ts->timer); + corgi_ts->timer.data = (unsigned long) corgi_ts; + corgi_ts->timer.function = corgi_ts_timer; - corgi_ts->input.private = corgi_ts; - corgi_ts->input.name = "Corgi Touchscreen"; - corgi_ts->input.dev = dev; - corgi_ts->input.phys = corgi_ts->phys; - corgi_ts->input.id.bustype = BUS_HOST; - corgi_ts->input.id.vendor = 0x0001; - corgi_ts->input.id.product = 0x0002; - corgi_ts->input.id.version = 0x0100; + input_dev->name = "Corgi Touchscreen"; + input_dev->phys = "corgits/input0"; + input_dev->id.bustype = BUS_HOST; + input_dev->id.vendor = 0x0001; + input_dev->id.product = 0x0002; + input_dev->id.version = 0x0100; + input_dev->cdev.dev = dev; + input_dev->private = corgi_ts; + + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); + input_set_abs_params(input_dev, ABS_X, X_AXIS_MIN, X_AXIS_MAX, 0, 0); + input_set_abs_params(input_dev, ABS_Y, Y_AXIS_MIN, Y_AXIS_MAX, 0, 0); + input_set_abs_params(input_dev, ABS_PRESSURE, PRESSURE_MIN, PRESSURE_MAX, 0, 0); pxa_gpio_mode(IRQ_TO_GPIO(corgi_ts->irq_gpio) | GPIO_IN); @@ -319,25 +319,24 @@ static int __init corgits_probe(struct device *dev) corgi_ssp_ads7846_putget((5u << ADSCTRL_ADR_SH) | ADSCTRL_STS); mdelay(5); - init_timer(&corgi_ts->timer); - corgi_ts->timer.data = (unsigned long) corgi_ts; - corgi_ts->timer.function = corgi_ts_timer; - - input_register_device(&corgi_ts->input); - corgi_ts->power_mode = PWR_MODE_ACTIVE; - if (request_irq(corgi_ts->irq_gpio, ts_interrupt, SA_INTERRUPT, "ts", corgi_ts)) { - input_unregister_device(&corgi_ts->input); - kfree(corgi_ts); - return -EBUSY; + err = -EBUSY; + goto fail; } + input_register_device(corgi_ts->input); + + corgi_ts->power_mode = PWR_MODE_ACTIVE; + /* Enable Falling Edge */ set_irq_type(corgi_ts->irq_gpio, IRQT_FALLING); - printk(KERN_INFO "input: Corgi Touchscreen Registered\n"); - return 0; + + fail: input_free_device(input_dev); + kfree(corgi_ts); + return err; + } static int corgits_remove(struct device *dev) @@ -347,7 +346,7 @@ static int corgits_remove(struct device *dev) free_irq(corgi_ts->irq_gpio, NULL); del_timer_sync(&corgi_ts->timer); corgi_ts->machinfo->put_hsync(); - input_unregister_device(&corgi_ts->input); + input_unregister_device(corgi_ts->input); kfree(corgi_ts); return 0; } diff --git a/drivers/input/touchscreen/elo.c b/drivers/input/touchscreen/elo.c index 3cdc9cab688d..c86a2eb310fd 100644 --- a/drivers/input/touchscreen/elo.c +++ b/drivers/input/touchscreen/elo.c @@ -36,14 +36,12 @@ MODULE_LICENSE("GPL"); #define ELO_MAX_LENGTH 10 -static char *elo_name = "Elo Serial TouchScreen"; - /* * Per-touchscreen data. */ struct elo { - struct input_dev dev; + struct input_dev *dev; struct serio *serio; int id; int idx; @@ -54,7 +52,7 @@ struct elo { static void elo_process_data_10(struct elo* elo, unsigned char data, struct pt_regs *regs) { - struct input_dev *dev = &elo->dev; + struct input_dev *dev = elo->dev; elo->csum += elo->data[elo->idx] = data; @@ -80,7 +78,7 @@ static void elo_process_data_10(struct elo* elo, unsigned char data, struct pt_r input_report_abs(dev, ABS_X, (elo->data[4] << 8) | elo->data[3]); input_report_abs(dev, ABS_Y, (elo->data[6] << 8) | elo->data[5]); input_report_abs(dev, ABS_PRESSURE, (elo->data[8] << 8) | elo->data[7]); - input_report_key(dev, BTN_TOUCH, elo->data[2] & 3); + input_report_key(dev, BTN_TOUCH, elo->data[8] || elo->data[7]); input_sync(dev); } elo->idx = 0; @@ -91,7 +89,7 @@ static void elo_process_data_10(struct elo* elo, unsigned char data, struct pt_r static void elo_process_data_6(struct elo* elo, unsigned char data, struct pt_regs *regs) { - struct input_dev *dev = &elo->dev; + struct input_dev *dev = elo->dev; elo->data[elo->idx] = data; @@ -129,7 +127,7 @@ static void elo_process_data_6(struct elo* elo, unsigned char data, struct pt_re case 5: if ((data & 0xf0) == 0) { input_report_abs(dev, ABS_PRESSURE, elo->data[5]); - input_report_key(dev, BTN_TOUCH, elo->data[5]); + input_report_key(dev, BTN_TOUCH, !!elo->data[5]); } input_sync(dev); elo->idx = 0; @@ -139,7 +137,7 @@ static void elo_process_data_6(struct elo* elo, unsigned char data, struct pt_re static void elo_process_data_3(struct elo* elo, unsigned char data, struct pt_regs *regs) { - struct input_dev *dev = &elo->dev; + struct input_dev *dev = elo->dev; elo->data[elo->idx] = data; @@ -191,7 +189,7 @@ static void elo_disconnect(struct serio *serio) { struct elo* elo = serio_get_drvdata(serio); - input_unregister_device(&elo->dev); + input_unregister_device(elo->dev); serio_close(serio); serio_set_drvdata(serio, NULL); kfree(elo); @@ -206,67 +204,68 @@ static void elo_disconnect(struct serio *serio) static int elo_connect(struct serio *serio, struct serio_driver *drv) { struct elo *elo; + struct input_dev *input_dev; int err; - if (!(elo = kmalloc(sizeof(struct elo), GFP_KERNEL))) - return -ENOMEM; + elo = kzalloc(sizeof(struct elo), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!elo || !input_dev) { + err = -ENOMEM; + goto fail; + } - memset(elo, 0, sizeof(struct elo)); + elo->serio = serio; + elo->id = serio->id.id; + elo->dev = input_dev; + snprintf(elo->phys, sizeof(elo->phys), "%s/input0", serio->phys); - init_input_dev(&elo->dev); - elo->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - elo->dev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); + input_dev->private = elo; + input_dev->name = "Elo Serial TouchScreen"; + input_dev->phys = elo->phys; + input_dev->id.bustype = BUS_RS232; + input_dev->id.vendor = SERIO_ELO; + input_dev->id.product = elo->id; + input_dev->id.version = 0x0100; + input_dev->cdev.dev = &serio->dev; - elo->id = serio->id.id; + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); switch (elo->id) { case 0: /* 10-byte protocol */ - input_set_abs_params(&elo->dev, ABS_X, 96, 4000, 0, 0); - input_set_abs_params(&elo->dev, ABS_Y, 96, 4000, 0, 0); - input_set_abs_params(&elo->dev, ABS_PRESSURE, 0, 255, 0, 0); + input_set_abs_params(input_dev, ABS_X, 96, 4000, 0, 0); + input_set_abs_params(input_dev, ABS_Y, 96, 4000, 0, 0); + input_set_abs_params(input_dev, ABS_PRESSURE, 0, 255, 0, 0); break; case 1: /* 6-byte protocol */ - input_set_abs_params(&elo->dev, ABS_PRESSURE, 0, 15, 0, 0); + input_set_abs_params(input_dev, ABS_PRESSURE, 0, 15, 0, 0); case 2: /* 4-byte protocol */ - input_set_abs_params(&elo->dev, ABS_X, 96, 4000, 0, 0); - input_set_abs_params(&elo->dev, ABS_Y, 96, 4000, 0, 0); + input_set_abs_params(input_dev, ABS_X, 96, 4000, 0, 0); + input_set_abs_params(input_dev, ABS_Y, 96, 4000, 0, 0); break; case 3: /* 3-byte protocol */ - input_set_abs_params(&elo->dev, ABS_X, 0, 255, 0, 0); - input_set_abs_params(&elo->dev, ABS_Y, 0, 255, 0, 0); + input_set_abs_params(input_dev, ABS_X, 0, 255, 0, 0); + input_set_abs_params(input_dev, ABS_Y, 0, 255, 0, 0); break; } - elo->serio = serio; - - sprintf(elo->phys, "%s/input0", serio->phys); - - elo->dev.private = elo; - elo->dev.name = elo_name; - elo->dev.phys = elo->phys; - elo->dev.id.bustype = BUS_RS232; - elo->dev.id.vendor = SERIO_ELO; - elo->dev.id.product = elo->id; - elo->dev.id.version = 0x0100; - serio_set_drvdata(serio, elo); err = serio_open(serio, drv); - if (err) { - serio_set_drvdata(serio, NULL); - kfree(elo); - return err; - } - - input_register_device(&elo->dev); - - printk(KERN_INFO "input: %s on %s\n", elo_name, serio->phys); + if (err) + goto fail; + input_register_device(elo->dev); return 0; + + fail: serio_set_drvdata(serio, NULL); + input_free_device(input_dev); + kfree(elo); + return err; } /* diff --git a/drivers/input/touchscreen/gunze.c b/drivers/input/touchscreen/gunze.c index 53a27e43dd23..466da190ceec 100644 --- a/drivers/input/touchscreen/gunze.c +++ b/drivers/input/touchscreen/gunze.c @@ -48,14 +48,12 @@ MODULE_LICENSE("GPL"); #define GUNZE_MAX_LENGTH 10 -static char *gunze_name = "Gunze AHL-51S TouchScreen"; - /* * Per-touchscreen data. */ struct gunze { - struct input_dev dev; + struct input_dev *dev; struct serio *serio; int idx; unsigned char data[GUNZE_MAX_LENGTH]; @@ -64,7 +62,7 @@ struct gunze { static void gunze_process_packet(struct gunze* gunze, struct pt_regs *regs) { - struct input_dev *dev = &gunze->dev; + struct input_dev *dev = gunze->dev; if (gunze->idx != GUNZE_MAX_LENGTH || gunze->data[5] != ',' || (gunze->data[0] != 'T' && gunze->data[0] != 'R')) { @@ -100,11 +98,13 @@ static irqreturn_t gunze_interrupt(struct serio *serio, static void gunze_disconnect(struct serio *serio) { - struct gunze* gunze = serio_get_drvdata(serio); + struct gunze *gunze = serio_get_drvdata(serio); - input_unregister_device(&gunze->dev); + input_get_device(gunze->dev); + input_unregister_device(gunze->dev); serio_close(serio); serio_set_drvdata(serio, NULL); + input_put_device(gunze->dev); kfree(gunze); } @@ -117,45 +117,45 @@ static void gunze_disconnect(struct serio *serio) static int gunze_connect(struct serio *serio, struct serio_driver *drv) { struct gunze *gunze; + struct input_dev *input_dev; int err; - if (!(gunze = kmalloc(sizeof(struct gunze), GFP_KERNEL))) - return -ENOMEM; - - memset(gunze, 0, sizeof(struct gunze)); - - init_input_dev(&gunze->dev); - gunze->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - gunze->dev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); - input_set_abs_params(&gunze->dev, ABS_X, 24, 1000, 0, 0); - input_set_abs_params(&gunze->dev, ABS_Y, 24, 1000, 0, 0); + gunze = kzalloc(sizeof(struct gunze), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!gunze || !input_dev) { + err = -ENOMEM; + goto fail; + } gunze->serio = serio; - + gunze->dev = input_dev; sprintf(gunze->phys, "%s/input0", serio->phys); - gunze->dev.private = gunze; - gunze->dev.name = gunze_name; - gunze->dev.phys = gunze->phys; - gunze->dev.id.bustype = BUS_RS232; - gunze->dev.id.vendor = SERIO_GUNZE; - gunze->dev.id.product = 0x0051; - gunze->dev.id.version = 0x0100; + input_dev->private = gunze; + input_dev->name = "Gunze AHL-51S TouchScreen"; + input_dev->phys = gunze->phys; + input_dev->id.bustype = BUS_RS232; + input_dev->id.vendor = SERIO_GUNZE; + input_dev->id.product = 0x0051; + input_dev->id.version = 0x0100; + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); + input_set_abs_params(input_dev, ABS_X, 24, 1000, 0, 0); + input_set_abs_params(input_dev, ABS_Y, 24, 1000, 0, 0); serio_set_drvdata(serio, gunze); err = serio_open(serio, drv); - if (err) { - serio_set_drvdata(serio, NULL); - kfree(gunze); - return err; - } - - input_register_device(&gunze->dev); - - printk(KERN_INFO "input: %s on %s\n", gunze_name, serio->phys); + if (err) + goto fail; + input_register_device(gunze->dev); return 0; + + fail: serio_set_drvdata(serio, NULL); + input_free_device(input_dev); + kfree(gunze); + return err; } /* diff --git a/drivers/input/touchscreen/h3600_ts_input.c b/drivers/input/touchscreen/h3600_ts_input.c index bcfa1e36f957..a18d56bdafd9 100644 --- a/drivers/input/touchscreen/h3600_ts_input.c +++ b/drivers/input/touchscreen/h3600_ts_input.c @@ -39,7 +39,6 @@ #include <linux/serio.h> #include <linux/init.h> #include <linux/delay.h> -#include <linux/pm.h> /* SA1100 serial defines */ #include <asm/arch/hardware.h> @@ -93,16 +92,12 @@ MODULE_LICENSE("GPL"); #define H3600_SCANCODE_LEFT 8 /* 8 -> left */ #define H3600_SCANCODE_DOWN 9 /* 9 -> down */ -static char *h3600_name = "H3600 TouchScreen"; - /* * Per-touchscreen data. */ struct h3600_dev { - struct input_dev dev; - struct pm_dev *pm_dev; + struct input_dev *dev; struct serio *serio; - struct pm_dev *pm_dev; unsigned char event; /* event ID from packet */ unsigned char chksum; unsigned char len; @@ -163,33 +158,6 @@ unsigned int h3600_flite_power(struct input_dev *dev, enum flite_pwr pwr) return 0; } -static int suspended = 0; -static int h3600ts_pm_callback(struct pm_dev *pm_dev, pm_request_t req, - void *data) -{ - struct input_dev *dev = (struct input_dev *) data; - - switch (req) { - case PM_SUSPEND: /* enter D1-D3 */ - suspended = 1; - h3600_flite_power(dev, FLITE_PWR_OFF); - break; - case PM_BLANK: - if (!suspended) - h3600_flite_power(dev, FLITE_PWR_OFF); - break; - case PM_RESUME: /* enter D0 */ - /* same as unblank */ - case PM_UNBLANK: - if (suspended) { - //initSerial(); - suspended = 0; - } - h3600_flite_power(dev, FLITE_PWR_ON); - break; - } - return 0; -} #endif /* @@ -199,7 +167,7 @@ static int h3600ts_pm_callback(struct pm_dev *pm_dev, pm_request_t req, */ static void h3600ts_process_packet(struct h3600_dev *ts, struct pt_regs *regs) { - struct input_dev *dev = &ts->dev; + struct input_dev *dev = ts->dev; static int touched = 0; int key, down = 0; @@ -295,6 +263,7 @@ static void h3600ts_process_packet(struct h3600_dev *ts, struct pt_regs *regs) static int h3600ts_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { +#if 0 struct h3600_dev *ts = dev->private; switch (type) { @@ -304,6 +273,8 @@ static int h3600ts_event(struct input_dev *dev, unsigned int type, } } return -1; +#endif + return 0; } /* @@ -380,14 +351,48 @@ static irqreturn_t h3600ts_interrupt(struct serio *serio, unsigned char data, static int h3600ts_connect(struct serio *serio, struct serio_driver *drv) { struct h3600_dev *ts; + struct input_dev *input_dev; int err; - if (!(ts = kmalloc(sizeof(struct h3600_dev), GFP_KERNEL))) - return -ENOMEM; + ts = kzalloc(sizeof(struct h3600_dev), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!ts || !input_dev) { + err = -ENOMEM; + goto fail1; + } - memset(ts, 0, sizeof(struct h3600_dev)); + ts->serio = serio; + ts->dev = input_dev; + sprintf(ts->phys, "%s/input0", serio->phys); - init_input_dev(&ts->dev); + input_dev->name = "H3600 TouchScreen"; + input_dev->phys = ts->phys; + input_dev->id.bustype = BUS_RS232; + input_dev->id.vendor = SERIO_H3600; + input_dev->id.product = 0x0666; /* FIXME !!! We can ask the hardware */ + input_dev->id.version = 0x0100; + input_dev->cdev.dev = &serio->dev; + input_dev->private = ts; + + input_dev->event = h3600ts_event; + + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_LED) | BIT(EV_PWR); + input_dev->ledbit[0] = BIT(LED_SLEEP); + input_set_abs_params(input_dev, ABS_X, 60, 985, 0, 0); + input_set_abs_params(input_dev, ABS_Y, 35, 1024, 0, 0); + + set_bit(KEY_RECORD, input_dev->keybit); + set_bit(KEY_Q, input_dev->keybit); + set_bit(KEY_PROG1, input_dev->keybit); + set_bit(KEY_PROG2, input_dev->keybit); + set_bit(KEY_PROG3, input_dev->keybit); + set_bit(KEY_UP, input_dev->keybit); + set_bit(KEY_RIGHT, input_dev->keybit); + set_bit(KEY_LEFT, input_dev->keybit); + set_bit(KEY_DOWN, input_dev->keybit); + set_bit(KEY_ENTER, input_dev->keybit); + set_bit(KEY_SUSPEND, input_dev->keybit); + set_bit(BTN_TOUCH, input_dev->keybit); /* Device specific stuff */ set_GPIO_IRQ_edge(GPIO_BITSY_ACTION_BUTTON, GPIO_BOTH_EDGES); @@ -397,73 +402,35 @@ static int h3600ts_connect(struct serio *serio, struct serio_driver *drv) SA_SHIRQ | SA_INTERRUPT | SA_SAMPLE_RANDOM, "h3600_action", &ts->dev)) { printk(KERN_ERR "h3600ts.c: Could not allocate Action Button IRQ!\n"); - kfree(ts); - return -EBUSY; + err = -EBUSY; + goto fail2; } if (request_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, npower_button_handler, SA_SHIRQ | SA_INTERRUPT | SA_SAMPLE_RANDOM, "h3600_suspend", &ts->dev)) { - free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, &ts->dev); printk(KERN_ERR "h3600ts.c: Could not allocate Power Button IRQ!\n"); - kfree(ts); - return -EBUSY; + err = -EBUSY; + goto fail3; } - /* Now we have things going we setup our input device */ - ts->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_LED) | BIT(EV_PWR); - ts->dev.ledbit[0] = BIT(LED_SLEEP); - input_set_abs_params(&ts->dev, ABS_X, 60, 985, 0, 0); - input_set_abs_params(&ts->dev, ABS_Y, 35, 1024, 0, 0); - - set_bit(KEY_RECORD, ts->dev.keybit); - set_bit(KEY_Q, ts->dev.keybit); - set_bit(KEY_PROG1, ts->dev.keybit); - set_bit(KEY_PROG2, ts->dev.keybit); - set_bit(KEY_PROG3, ts->dev.keybit); - set_bit(KEY_UP, ts->dev.keybit); - set_bit(KEY_RIGHT, ts->dev.keybit); - set_bit(KEY_LEFT, ts->dev.keybit); - set_bit(KEY_DOWN, ts->dev.keybit); - set_bit(KEY_ENTER, ts->dev.keybit); - ts->dev.keybit[LONG(BTN_TOUCH)] |= BIT(BTN_TOUCH); - ts->dev.keybit[LONG(KEY_SUSPEND)] |= BIT(KEY_SUSPEND); - - ts->serio = serio; - - sprintf(ts->phys, "%s/input0", serio->phys); - - ts->dev.event = h3600ts_event; - ts->dev.private = ts; - ts->dev.name = h3600_name; - ts->dev.phys = ts->phys; - ts->dev.id.bustype = BUS_RS232; - ts->dev.id.vendor = SERIO_H3600; - ts->dev.id.product = 0x0666; /* FIXME !!! We can ask the hardware */ - ts->dev.id.version = 0x0100; - serio_set_drvdata(serio, ts); err = serio_open(serio, drv); - if (err) { - free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, ts); - free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, ts); - serio_set_drvdata(serio, NULL); - kfree(ts); + if (err) return err; - } //h3600_flite_control(1, 25); /* default brightness */ -#ifdef CONFIG_PM - ts->pm_dev = pm_register(PM_ILLUMINATION_DEV, PM_SYS_LIGHT, - h3600ts_pm_callback); - printk("registered pm callback\n"); -#endif - input_register_device(&ts->dev); - - printk(KERN_INFO "input: %s on %s\n", h3600_name, serio->phys); + input_register_device(ts->dev); return 0; + +fail3: free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, ts->dev); +fail2: free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, ts->dev); +fail1: serio_set_drvdata(serio, NULL); + input_free_device(input_dev); + kfree(ts); + return err; } /* @@ -476,9 +443,11 @@ static void h3600ts_disconnect(struct serio *serio) free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, &ts->dev); free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, &ts->dev); - input_unregister_device(&ts->dev); + input_get_device(ts->dev); + input_unregister_device(ts->dev); serio_close(serio); serio_set_drvdata(serio, NULL); + input_put_device(ts->dev); kfree(ts); } diff --git a/drivers/input/touchscreen/hp680_ts_input.c b/drivers/input/touchscreen/hp680_ts_input.c index 7e1404441eca..957dd5a1b15e 100644 --- a/drivers/input/touchscreen/hp680_ts_input.c +++ b/drivers/input/touchscreen/hp680_ts_input.c @@ -21,10 +21,8 @@ static void do_softint(void *data); -static struct input_dev hp680_ts_dev; +static struct input_dev *hp680_ts_dev; static DECLARE_WORK(work, do_softint, 0); -static char *hp680_ts_name = "HP Jornada touchscreen"; -static char *hp680_ts_phys = "input0"; static void do_softint(void *data) { @@ -58,14 +56,14 @@ static void do_softint(void *data) } if (touched) { - input_report_key(&hp680_ts_dev, BTN_TOUCH, 1); - input_report_abs(&hp680_ts_dev, ABS_X, absx); - input_report_abs(&hp680_ts_dev, ABS_Y, absy); + input_report_key(hp680_ts_dev, BTN_TOUCH, 1); + input_report_abs(hp680_ts_dev, ABS_X, absx); + input_report_abs(hp680_ts_dev, ABS_Y, absy); } else { - input_report_key(&hp680_ts_dev, BTN_TOUCH, 0); + input_report_key(hp680_ts_dev, BTN_TOUCH, 0); } - input_sync(&hp680_ts_dev); + input_sync(hp680_ts_dev); enable_irq(HP680_TS_IRQ); } @@ -92,27 +90,29 @@ static int __init hp680_ts_init(void) scpcr |= SCPCR_TS_ENABLE; ctrl_outw(scpcr, SCPCR); - memset(&hp680_ts_dev, 0, sizeof(hp680_ts_dev)); - init_input_dev(&hp680_ts_dev); + hp680_ts_dev = input_allocate_device(); + if (!hp680_ts_dev) + return -ENOMEM; - hp680_ts_dev.evbit[0] = BIT(EV_ABS) | BIT(EV_KEY); - hp680_ts_dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y); - hp680_ts_dev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); + hp680_ts_dev->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY); + hp680_ts_dev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y); + hp680_ts_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); - hp680_ts_dev.absmin[ABS_X] = HP680_TS_ABS_X_MIN; - hp680_ts_dev.absmin[ABS_Y] = HP680_TS_ABS_Y_MIN; - hp680_ts_dev.absmax[ABS_X] = HP680_TS_ABS_X_MAX; - hp680_ts_dev.absmax[ABS_Y] = HP680_TS_ABS_Y_MAX; + hp680_ts_dev->absmin[ABS_X] = HP680_TS_ABS_X_MIN; + hp680_ts_dev->absmin[ABS_Y] = HP680_TS_ABS_Y_MIN; + hp680_ts_dev->absmax[ABS_X] = HP680_TS_ABS_X_MAX; + hp680_ts_dev->absmax[ABS_Y] = HP680_TS_ABS_Y_MAX; - hp680_ts_dev.name = hp680_ts_name; - hp680_ts_dev.phys = hp680_ts_phys; - input_register_device(&hp680_ts_dev); + hp680_ts_dev->name = "HP Jornada touchscreen"; + hp680_ts_dev->phys = "hp680_ts/input0"; - if (request_irq - (HP680_TS_IRQ, hp680_ts_interrupt, SA_INTERRUPT, MODNAME, 0) < 0) { - printk(KERN_ERR "hp680_touchscreen.c : Can't allocate irq %d\n", + input_register_device(hp680_ts_dev); + + if (request_irq(HP680_TS_IRQ, hp680_ts_interrupt, + SA_INTERRUPT, MODNAME, 0) < 0) { + printk(KERN_ERR "hp680_touchscreen.c: Can't allocate irq %d\n", HP680_TS_IRQ); - input_unregister_device(&hp680_ts_dev); + input_unregister_device(hp680_ts_dev); return -EBUSY; } @@ -124,7 +124,7 @@ static void __exit hp680_ts_exit(void) free_irq(HP680_TS_IRQ, 0); cancel_delayed_work(&work); flush_scheduled_work(); - input_unregister_device(&hp680_ts_dev); + input_unregister_device(hp680_ts_dev); } module_init(hp680_ts_init); diff --git a/drivers/input/touchscreen/mk712.c b/drivers/input/touchscreen/mk712.c index afaaebe5225b..4844d250a5eb 100644 --- a/drivers/input/touchscreen/mk712.c +++ b/drivers/input/touchscreen/mk712.c @@ -77,7 +77,7 @@ MODULE_PARM_DESC(irq, "IRQ of MK712 touchscreen controller"); #define MK712_READ_ONE_POINT 0x20 #define MK712_POWERUP 0x40 -static struct input_dev mk712_dev; +static struct input_dev *mk712_dev; static DEFINE_SPINLOCK(mk712_lock); static irqreturn_t mk712_interrupt(int irq, void *dev_id, struct pt_regs *regs) @@ -88,7 +88,7 @@ static irqreturn_t mk712_interrupt(int irq, void *dev_id, struct pt_regs *regs) static unsigned short last_y; spin_lock(&mk712_lock); - input_regs(&mk712_dev, regs); + input_regs(mk712_dev, regs); status = inb(mk712_io + MK712_STATUS); @@ -100,7 +100,7 @@ static irqreturn_t mk712_interrupt(int irq, void *dev_id, struct pt_regs *regs) if (~status & MK712_STATUS_TOUCH) { debounce = 1; - input_report_key(&mk712_dev, BTN_TOUCH, 0); + input_report_key(mk712_dev, BTN_TOUCH, 0); goto end; } @@ -110,15 +110,15 @@ static irqreturn_t mk712_interrupt(int irq, void *dev_id, struct pt_regs *regs) goto end; } - input_report_key(&mk712_dev, BTN_TOUCH, 1); - input_report_abs(&mk712_dev, ABS_X, last_x); - input_report_abs(&mk712_dev, ABS_Y, last_y); + input_report_key(mk712_dev, BTN_TOUCH, 1); + input_report_abs(mk712_dev, ABS_X, last_x); + input_report_abs(mk712_dev, ABS_Y, last_y); end: last_x = inw(mk712_io + MK712_X) & 0x0fff; last_y = inw(mk712_io + MK712_Y) & 0x0fff; - input_sync(&mk712_dev); + input_sync(mk712_dev); spin_unlock(&mk712_lock); return IRQ_HANDLED; } @@ -154,30 +154,11 @@ static void mk712_close(struct input_dev *dev) spin_unlock_irqrestore(&mk712_lock, flags); } -static struct input_dev mk712_dev = { - .evbit = { BIT(EV_KEY) | BIT(EV_ABS) }, - .keybit = { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) }, - .absbit = { BIT(ABS_X) | BIT(ABS_Y) }, - .open = mk712_open, - .close = mk712_close, - .name = "ICS MicroClock MK712 TouchScreen", - .phys = "isa0260/input0", - .absmin = { [ABS_X] = 0, [ABS_Y] = 0 }, - .absmax = { [ABS_X] = 0xfff, [ABS_Y] = 0xfff }, - .absfuzz = { [ABS_X] = 88, [ABS_Y] = 88 }, - .id = { - .bustype = BUS_ISA, - .vendor = 0x0005, - .product = 0x0001, - .version = 0x0100, - }, -}; - int __init mk712_init(void) { + int err; - if(!request_region(mk712_io, 8, "mk712")) - { + if (!request_region(mk712_io, 8, "mk712")) { printk(KERN_WARNING "mk712: unable to get IO region\n"); return -ENODEV; } @@ -188,28 +169,49 @@ int __init mk712_init(void) (inw(mk712_io + MK712_Y) & 0xf000) || (inw(mk712_io + MK712_STATUS) & 0xf333)) { printk(KERN_WARNING "mk712: device not present\n"); - release_region(mk712_io, 8); - return -ENODEV; + err = -ENODEV; + goto fail; } - if(request_irq(mk712_irq, mk712_interrupt, 0, "mk712", &mk712_dev)) - { - printk(KERN_WARNING "mk712: unable to get IRQ\n"); - release_region(mk712_io, 8); - return -EBUSY; + if (!(mk712_dev = input_allocate_device())) { + printk(KERN_ERR "mk712: not enough memory\n"); + err = -ENOMEM; + goto fail; } - input_register_device(&mk712_dev); + mk712_dev->name = "ICS MicroClock MK712 TouchScreen"; + mk712_dev->phys = "isa0260/input0"; + mk712_dev->id.bustype = BUS_ISA; + mk712_dev->id.vendor = 0x0005; + mk712_dev->id.product = 0x0001; + mk712_dev->id.version = 0x0100; + + mk712_dev->open = mk712_open; + mk712_dev->close = mk712_close; - printk(KERN_INFO "input: ICS MicroClock MK712 TouchScreen at %#x irq %d\n", mk712_io, mk712_irq); + mk712_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + mk712_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); + input_set_abs_params(mk712_dev, ABS_X, 0, 0xfff, 88, 0); + input_set_abs_params(mk712_dev, ABS_Y, 0, 0xfff, 88, 0); + if (request_irq(mk712_irq, mk712_interrupt, 0, "mk712", mk712_dev)) { + printk(KERN_WARNING "mk712: unable to get IRQ\n"); + err = -EBUSY; + goto fail; + } + + input_register_device(mk712_dev); return 0; + + fail: input_free_device(mk712_dev); + release_region(mk712_io, 8); + return err; } static void __exit mk712_exit(void) { - input_unregister_device(&mk712_dev); - free_irq(mk712_irq, &mk712_dev); + input_unregister_device(mk712_dev); + free_irq(mk712_irq, mk712_dev); release_region(mk712_io, 8); } diff --git a/drivers/input/touchscreen/mtouch.c b/drivers/input/touchscreen/mtouch.c index aa8ee7842179..1d0d37eeef6e 100644 --- a/drivers/input/touchscreen/mtouch.c +++ b/drivers/input/touchscreen/mtouch.c @@ -51,14 +51,12 @@ MODULE_LICENSE("GPL"); #define MTOUCH_GET_YC(data) (((data[4])<<7) | data[3]) #define MTOUCH_GET_TOUCHED(data) (MTOUCH_FORMAT_TABLET_TOUCH_BIT & data[0]) -static char *mtouch_name = "MicroTouch Serial TouchScreen"; - /* * Per-touchscreen data. */ struct mtouch { - struct input_dev dev; + struct input_dev *dev; struct serio *serio; int idx; unsigned char data[MTOUCH_MAX_LENGTH]; @@ -67,7 +65,7 @@ struct mtouch { static void mtouch_process_format_tablet(struct mtouch *mtouch, struct pt_regs *regs) { - struct input_dev *dev = &mtouch->dev; + struct input_dev *dev = mtouch->dev; if (MTOUCH_FORMAT_TABLET_LENGTH == ++mtouch->idx) { input_regs(dev, regs); @@ -116,9 +114,11 @@ static void mtouch_disconnect(struct serio *serio) { struct mtouch* mtouch = serio_get_drvdata(serio); - input_unregister_device(&mtouch->dev); + input_get_device(mtouch->dev); + input_unregister_device(mtouch->dev); serio_close(serio); serio_set_drvdata(serio, NULL); + input_put_device(mtouch->dev); kfree(mtouch); } @@ -131,46 +131,46 @@ static void mtouch_disconnect(struct serio *serio) static int mtouch_connect(struct serio *serio, struct serio_driver *drv) { struct mtouch *mtouch; + struct input_dev *input_dev; int err; - if (!(mtouch = kmalloc(sizeof(*mtouch), GFP_KERNEL))) - return -ENOMEM; - - memset(mtouch, 0, sizeof(*mtouch)); - - init_input_dev(&mtouch->dev); - mtouch->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - mtouch->dev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); - - input_set_abs_params(&mtouch->dev, ABS_X, MTOUCH_MIN_XC, MTOUCH_MAX_XC, 0, 0); - input_set_abs_params(&mtouch->dev, ABS_Y, MTOUCH_MIN_YC, MTOUCH_MAX_YC, 0, 0); + mtouch = kzalloc(sizeof(struct mtouch), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!mtouch || !input_dev) { + err = -ENOMEM; + goto fail; + } mtouch->serio = serio; - + mtouch->dev = input_dev; sprintf(mtouch->phys, "%s/input0", serio->phys); - mtouch->dev.private = mtouch; - mtouch->dev.name = mtouch_name; - mtouch->dev.phys = mtouch->phys; - mtouch->dev.id.bustype = BUS_RS232; - mtouch->dev.id.vendor = SERIO_MICROTOUCH; - mtouch->dev.id.product = 0; - mtouch->dev.id.version = 0x0100; + input_dev->private = mtouch; + input_dev->name = "MicroTouch Serial TouchScreen"; + input_dev->phys = mtouch->phys; + input_dev->id.bustype = BUS_RS232; + input_dev->id.vendor = SERIO_MICROTOUCH; + input_dev->id.product = 0; + input_dev->id.version = 0x0100; + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); + input_set_abs_params(mtouch->dev, ABS_X, MTOUCH_MIN_XC, MTOUCH_MAX_XC, 0, 0); + input_set_abs_params(mtouch->dev, ABS_Y, MTOUCH_MIN_YC, MTOUCH_MAX_YC, 0, 0); serio_set_drvdata(serio, mtouch); err = serio_open(serio, drv); - if (err) { - serio_set_drvdata(serio, NULL); - kfree(mtouch); - return err; - } - - input_register_device(&mtouch->dev); + if (err) + goto fail; - printk(KERN_INFO "input: %s on %s\n", mtouch->dev.name, serio->phys); + input_register_device(mtouch->dev); return 0; + + fail: serio_set_drvdata(serio, NULL); + input_free_device(input_dev); + kfree(mtouch); + return err; } /* diff --git a/drivers/input/tsdev.c b/drivers/input/tsdev.c index 50c63a155156..ca1547929d62 100644 --- a/drivers/input/tsdev.c +++ b/drivers/input/tsdev.c @@ -53,7 +53,6 @@ #include <linux/random.h> #include <linux/time.h> #include <linux/device.h> -#include <linux/devfs_fs_kernel.h> #ifndef CONFIG_INPUT_TSDEV_SCREEN_X #define CONFIG_INPUT_TSDEV_SCREEN_X 240 @@ -369,6 +368,7 @@ static struct input_handle *tsdev_connect(struct input_handler *handler, struct input_device_id *id) { struct tsdev *tsdev; + struct class_device *cdev; int minor, delta; for (minor = 0; minor < TSDEV_MINORS/2 && tsdev_table[minor]; @@ -410,13 +410,13 @@ static struct input_handle *tsdev_connect(struct input_handler *handler, tsdev_table[minor] = tsdev; - devfs_mk_cdev(MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor), - S_IFCHR|S_IRUGO|S_IWUSR, "input/ts%d", minor); - devfs_mk_cdev(MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor + TSDEV_MINORS/2), - S_IFCHR|S_IRUGO|S_IWUSR, "input/tsraw%d", minor); - class_device_create(input_class, + cdev = class_device_create(&input_class, &dev->cdev, MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor), - dev->dev, "ts%d", minor); + dev->cdev.dev, tsdev->name); + + /* temporary symlink to keep userspace happy */ + sysfs_create_link(&input_class.subsys.kset.kobj, &cdev->kobj, + tsdev->name); return &tsdev->handle; } @@ -426,10 +426,9 @@ static void tsdev_disconnect(struct input_handle *handle) struct tsdev *tsdev = handle->private; struct tsdev_list *list; - class_device_destroy(input_class, + sysfs_remove_link(&input_class.subsys.kset.kobj, tsdev->name); + class_device_destroy(&input_class, MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + tsdev->minor)); - devfs_remove("input/ts%d", tsdev->minor); - devfs_remove("input/tsraw%d", tsdev->minor); tsdev->exist = 0; if (tsdev->open) { diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c index 04fb606b5ddd..11ae0fddea04 100644 --- a/drivers/isdn/capi/capi.c +++ b/drivers/isdn/capi/capi.c @@ -1505,7 +1505,7 @@ static int __init capi_init(void) return PTR_ERR(capi_class); } - class_device_create(capi_class, MKDEV(capi_major, 0), NULL, "capi"); + class_device_create(capi_class, NULL, MKDEV(capi_major, 0), NULL, "capi"); devfs_mk_cdev(MKDEV(capi_major, 0), S_IFCHR | S_IRUSR | S_IWUSR, "isdn/capi20"); diff --git a/drivers/isdn/capi/capifs.c b/drivers/isdn/capi/capifs.c index 3abd7fc6e5ef..7b564c0dd996 100644 --- a/drivers/isdn/capi/capifs.c +++ b/drivers/isdn/capi/capifs.c @@ -15,6 +15,7 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/ctype.h> +#include <linux/sched.h> /* current */ MODULE_DESCRIPTION("CAPI4Linux: /dev/capi/ filesystem"); MODULE_AUTHOR("Carsten Paeth"); diff --git a/drivers/isdn/hisax/hfc4s8s_l1.c b/drivers/isdn/hisax/hfc4s8s_l1.c index 7333377ab31d..e3866b0a97fd 100644 --- a/drivers/isdn/hisax/hfc4s8s_l1.c +++ b/drivers/isdn/hisax/hfc4s8s_l1.c @@ -1063,7 +1063,7 @@ tx_b_frame(struct hfc4s8s_btype *bch) Write_hfc8(l1->hw, A_INC_RES_FIFO, 1); } ack_len += skb->truesize; - bch->tx_skb = 0; + bch->tx_skb = NULL; bch->tx_cnt = 0; dev_kfree_skb(skb); } else @@ -1659,10 +1659,10 @@ hfc4s8s_remove(struct pci_dev *pdev) } static struct pci_driver hfc4s8s_driver = { - name:"hfc4s8s_l1", - probe:hfc4s8s_probe, - remove:__devexit_p(hfc4s8s_remove), - id_table:hfc4s8s_ids, + .name = "hfc4s8s_l1", + .probe = hfc4s8s_probe, + .remove = __devexit_p(hfc4s8s_remove), + .id_table = hfc4s8s_ids, }; /**********************/ diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c index c0dc1e3fa58b..d2ead1776c16 100644 --- a/drivers/macintosh/adb.c +++ b/drivers/macintosh/adb.c @@ -905,5 +905,5 @@ adbdev_init(void) adb_dev_class = class_create(THIS_MODULE, "adb"); if (IS_ERR(adb_dev_class)) return; - class_device_create(adb_dev_class, MKDEV(ADB_MAJOR, 0), NULL, "adb"); + class_device_create(adb_dev_class, NULL, MKDEV(ADB_MAJOR, 0), NULL, "adb"); } diff --git a/drivers/macintosh/adbhid.c b/drivers/macintosh/adbhid.c index db654e8bd67e..cdb6d0283195 100644 --- a/drivers/macintosh/adbhid.c +++ b/drivers/macintosh/adbhid.c @@ -206,7 +206,7 @@ u8 adb_to_linux_keycodes[128] = { }; struct adbhid { - struct input_dev input; + struct input_dev *input; int id; int default_id; int original_handler_id; @@ -291,10 +291,10 @@ adbhid_input_keycode(int id, int keycode, int repeat, struct pt_regs *regs) switch (keycode) { case ADB_KEY_CAPSLOCK: /* Generate down/up events for CapsLock everytime. */ - input_regs(&ahid->input, regs); - input_report_key(&ahid->input, KEY_CAPSLOCK, 1); - input_report_key(&ahid->input, KEY_CAPSLOCK, 0); - input_sync(&ahid->input); + input_regs(ahid->input, regs); + input_report_key(ahid->input, KEY_CAPSLOCK, 1); + input_report_key(ahid->input, KEY_CAPSLOCK, 0); + input_sync(ahid->input); return; #ifdef CONFIG_PPC_PMAC case ADB_KEY_POWER_OLD: /* Power key on PBook 3400 needs remapping */ @@ -347,10 +347,10 @@ adbhid_input_keycode(int id, int keycode, int repeat, struct pt_regs *regs) } if (adbhid[id]->keycode[keycode]) { - input_regs(&adbhid[id]->input, regs); - input_report_key(&adbhid[id]->input, + input_regs(adbhid[id]->input, regs); + input_report_key(adbhid[id]->input, adbhid[id]->keycode[keycode], !up_flag); - input_sync(&adbhid[id]->input); + input_sync(adbhid[id]->input); } else printk(KERN_INFO "Unhandled ADB key (scancode %#02x) %s.\n", keycode, up_flag ? "released" : "pressed"); @@ -441,20 +441,20 @@ adbhid_mouse_input(unsigned char *data, int nb, struct pt_regs *regs, int autopo break; } - input_regs(&adbhid[id]->input, regs); + input_regs(adbhid[id]->input, regs); - input_report_key(&adbhid[id]->input, BTN_LEFT, !((data[1] >> 7) & 1)); - input_report_key(&adbhid[id]->input, BTN_MIDDLE, !((data[2] >> 7) & 1)); + input_report_key(adbhid[id]->input, BTN_LEFT, !((data[1] >> 7) & 1)); + input_report_key(adbhid[id]->input, BTN_MIDDLE, !((data[2] >> 7) & 1)); if (nb >= 4 && adbhid[id]->mouse_kind != ADBMOUSE_TRACKPAD) - input_report_key(&adbhid[id]->input, BTN_RIGHT, !((data[3] >> 7) & 1)); + input_report_key(adbhid[id]->input, BTN_RIGHT, !((data[3] >> 7) & 1)); - input_report_rel(&adbhid[id]->input, REL_X, + input_report_rel(adbhid[id]->input, REL_X, ((data[2]&0x7f) < 64 ? (data[2]&0x7f) : (data[2]&0x7f)-128 )); - input_report_rel(&adbhid[id]->input, REL_Y, + input_report_rel(adbhid[id]->input, REL_Y, ((data[1]&0x7f) < 64 ? (data[1]&0x7f) : (data[1]&0x7f)-128 )); - input_sync(&adbhid[id]->input); + input_sync(adbhid[id]->input); } static void @@ -467,7 +467,7 @@ adbhid_buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int auto return; } - input_regs(&adbhid[id]->input, regs); + input_regs(adbhid[id]->input, regs); switch (adbhid[id]->original_handler_id) { default: @@ -477,19 +477,19 @@ adbhid_buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int auto switch (data[1] & 0x0f) { case 0x0: /* microphone */ - input_report_key(&adbhid[id]->input, KEY_SOUND, down); + input_report_key(adbhid[id]->input, KEY_SOUND, down); break; case 0x1: /* mute */ - input_report_key(&adbhid[id]->input, KEY_MUTE, down); + input_report_key(adbhid[id]->input, KEY_MUTE, down); break; case 0x2: /* volume decrease */ - input_report_key(&adbhid[id]->input, KEY_VOLUMEDOWN, down); + input_report_key(adbhid[id]->input, KEY_VOLUMEDOWN, down); break; case 0x3: /* volume increase */ - input_report_key(&adbhid[id]->input, KEY_VOLUMEUP, down); + input_report_key(adbhid[id]->input, KEY_VOLUMEUP, down); break; default: @@ -513,19 +513,19 @@ adbhid_buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int auto switch (data[1] & 0x0f) { case 0x8: /* mute */ - input_report_key(&adbhid[id]->input, KEY_MUTE, down); + input_report_key(adbhid[id]->input, KEY_MUTE, down); break; case 0x7: /* volume decrease */ - input_report_key(&adbhid[id]->input, KEY_VOLUMEDOWN, down); + input_report_key(adbhid[id]->input, KEY_VOLUMEDOWN, down); break; case 0x6: /* volume increase */ - input_report_key(&adbhid[id]->input, KEY_VOLUMEUP, down); + input_report_key(adbhid[id]->input, KEY_VOLUMEUP, down); break; case 0xb: /* eject */ - input_report_key(&adbhid[id]->input, KEY_EJECTCD, down); + input_report_key(adbhid[id]->input, KEY_EJECTCD, down); break; case 0xa: /* brightness decrease */ @@ -539,7 +539,7 @@ adbhid_buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int auto } } #endif /* CONFIG_PMAC_BACKLIGHT */ - input_report_key(&adbhid[id]->input, KEY_BRIGHTNESSDOWN, down); + input_report_key(adbhid[id]->input, KEY_BRIGHTNESSDOWN, down); break; case 0x9: /* brightness increase */ @@ -553,19 +553,19 @@ adbhid_buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int auto } } #endif /* CONFIG_PMAC_BACKLIGHT */ - input_report_key(&adbhid[id]->input, KEY_BRIGHTNESSUP, down); + input_report_key(adbhid[id]->input, KEY_BRIGHTNESSUP, down); break; case 0xc: /* videomode switch */ - input_report_key(&adbhid[id]->input, KEY_SWITCHVIDEOMODE, down); + input_report_key(adbhid[id]->input, KEY_SWITCHVIDEOMODE, down); break; case 0xd: /* keyboard illumination toggle */ - input_report_key(&adbhid[id]->input, KEY_KBDILLUMTOGGLE, down); + input_report_key(adbhid[id]->input, KEY_KBDILLUMTOGGLE, down); break; case 0xe: /* keyboard illumination decrease */ - input_report_key(&adbhid[id]->input, KEY_KBDILLUMDOWN, down); + input_report_key(adbhid[id]->input, KEY_KBDILLUMDOWN, down); break; case 0xf: @@ -573,7 +573,7 @@ adbhid_buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int auto case 0x8f: case 0x0f: /* keyboard illumination increase */ - input_report_key(&adbhid[id]->input, KEY_KBDILLUMUP, down); + input_report_key(adbhid[id]->input, KEY_KBDILLUMUP, down); break; case 0x7f: @@ -596,7 +596,7 @@ adbhid_buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int auto break; } - input_sync(&adbhid[id]->input); + input_sync(adbhid[id]->input); } static struct adb_request led_request; @@ -683,7 +683,7 @@ adb_message_handler(struct notifier_block *this, unsigned long code, void *x) int i; for (i = 1; i < 16; i++) { if (adbhid[i]) - del_timer_sync(&adbhid[i]->input.timer); + del_timer_sync(&adbhid[i]->input->timer); } } @@ -699,153 +699,163 @@ adb_message_handler(struct notifier_block *this, unsigned long code, void *x) return NOTIFY_DONE; } -static void +static int adbhid_input_register(int id, int default_id, int original_handler_id, int current_handler_id, int mouse_kind) { + struct adbhid *hid; + struct input_dev *input_dev; + int err; int i; if (adbhid[id]) { printk(KERN_ERR "Trying to reregister ADB HID on ID %d\n", id); - return; + return -EEXIST; } - if (!(adbhid[id] = kmalloc(sizeof(struct adbhid), GFP_KERNEL))) - return; - - memset(adbhid[id], 0, sizeof(struct adbhid)); - sprintf(adbhid[id]->phys, "adb%d:%d.%02x/input", id, default_id, original_handler_id); + adbhid[id] = hid = kzalloc(sizeof(struct adbhid), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!hid || !input_dev) { + err = -ENOMEM; + goto fail; - init_input_dev(&adbhid[id]->input); + } - adbhid[id]->id = default_id; - adbhid[id]->original_handler_id = original_handler_id; - adbhid[id]->current_handler_id = current_handler_id; - adbhid[id]->mouse_kind = mouse_kind; - adbhid[id]->flags = 0; - adbhid[id]->input.private = adbhid[id]; - adbhid[id]->input.name = adbhid[id]->name; - adbhid[id]->input.phys = adbhid[id]->phys; - adbhid[id]->input.id.bustype = BUS_ADB; - adbhid[id]->input.id.vendor = 0x0001; - adbhid[id]->input.id.product = (id << 12) | (default_id << 8) | original_handler_id; - adbhid[id]->input.id.version = 0x0100; + sprintf(hid->phys, "adb%d:%d.%02x/input", id, default_id, original_handler_id); + + hid->id = default_id; + hid->original_handler_id = original_handler_id; + hid->current_handler_id = current_handler_id; + hid->mouse_kind = mouse_kind; + hid->flags = 0; + input_dev->private = hid; + input_dev->name = hid->name; + input_dev->phys = hid->phys; + input_dev->id.bustype = BUS_ADB; + input_dev->id.vendor = 0x0001; + input_dev->id.product = (id << 12) | (default_id << 8) | original_handler_id; + input_dev->id.version = 0x0100; switch (default_id) { case ADB_KEYBOARD: - if (!(adbhid[id]->keycode = kmalloc(sizeof(adb_to_linux_keycodes), GFP_KERNEL))) { - kfree(adbhid[id]); - return; + hid->keycode = kmalloc(sizeof(adb_to_linux_keycodes), GFP_KERNEL); + if (!hid->keycode) { + err = -ENOMEM; + goto fail; } - sprintf(adbhid[id]->name, "ADB keyboard"); + sprintf(hid->name, "ADB keyboard"); - memcpy(adbhid[id]->keycode, adb_to_linux_keycodes, sizeof(adb_to_linux_keycodes)); + memcpy(hid->keycode, adb_to_linux_keycodes, sizeof(adb_to_linux_keycodes)); printk(KERN_INFO "Detected ADB keyboard, type "); switch (original_handler_id) { default: printk("<unknown>.\n"); - adbhid[id]->input.id.version = ADB_KEYBOARD_UNKNOWN; + input_dev->id.version = ADB_KEYBOARD_UNKNOWN; break; case 0x01: case 0x02: case 0x03: case 0x06: case 0x08: case 0x0C: case 0x10: case 0x18: case 0x1B: case 0x1C: case 0xC0: case 0xC3: case 0xC6: printk("ANSI.\n"); - adbhid[id]->input.id.version = ADB_KEYBOARD_ANSI; + input_dev->id.version = ADB_KEYBOARD_ANSI; break; case 0x04: case 0x05: case 0x07: case 0x09: case 0x0D: case 0x11: case 0x14: case 0x19: case 0x1D: case 0xC1: case 0xC4: case 0xC7: printk("ISO, swapping keys.\n"); - adbhid[id]->input.id.version = ADB_KEYBOARD_ISO; - i = adbhid[id]->keycode[10]; - adbhid[id]->keycode[10] = adbhid[id]->keycode[50]; - adbhid[id]->keycode[50] = i; + input_dev->id.version = ADB_KEYBOARD_ISO; + i = hid->keycode[10]; + hid->keycode[10] = hid->keycode[50]; + hid->keycode[50] = i; break; case 0x12: case 0x15: case 0x16: case 0x17: case 0x1A: case 0x1E: case 0xC2: case 0xC5: case 0xC8: case 0xC9: printk("JIS.\n"); - adbhid[id]->input.id.version = ADB_KEYBOARD_JIS; + input_dev->id.version = ADB_KEYBOARD_JIS; break; } for (i = 0; i < 128; i++) - if (adbhid[id]->keycode[i]) - set_bit(adbhid[id]->keycode[i], adbhid[id]->input.keybit); - - adbhid[id]->input.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP); - adbhid[id]->input.ledbit[0] = BIT(LED_SCROLLL) | BIT(LED_CAPSL) | BIT(LED_NUML); - adbhid[id]->input.event = adbhid_kbd_event; - adbhid[id]->input.keycodemax = 127; - adbhid[id]->input.keycodesize = 1; + if (hid->keycode[i]) + set_bit(hid->keycode[i], input_dev->keybit); + + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP); + input_dev->ledbit[0] = BIT(LED_SCROLLL) | BIT(LED_CAPSL) | BIT(LED_NUML); + input_dev->event = adbhid_kbd_event; + input_dev->keycodemax = 127; + input_dev->keycodesize = 1; break; case ADB_MOUSE: - sprintf(adbhid[id]->name, "ADB mouse"); + sprintf(hid->name, "ADB mouse"); - adbhid[id]->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); - adbhid[id]->input.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); - adbhid[id]->input.relbit[0] = BIT(REL_X) | BIT(REL_Y); + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL); + input_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); + input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y); break; case ADB_MISC: switch (original_handler_id) { case 0x02: /* Adjustable keyboard button device */ - sprintf(adbhid[id]->name, "ADB adjustable keyboard buttons"); - adbhid[id]->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REP); - set_bit(KEY_SOUND, adbhid[id]->input.keybit); - set_bit(KEY_MUTE, adbhid[id]->input.keybit); - set_bit(KEY_VOLUMEUP, adbhid[id]->input.keybit); - set_bit(KEY_VOLUMEDOWN, adbhid[id]->input.keybit); + sprintf(hid->name, "ADB adjustable keyboard buttons"); + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP); + set_bit(KEY_SOUND, input_dev->keybit); + set_bit(KEY_MUTE, input_dev->keybit); + set_bit(KEY_VOLUMEUP, input_dev->keybit); + set_bit(KEY_VOLUMEDOWN, input_dev->keybit); break; case 0x1f: /* Powerbook button device */ - sprintf(adbhid[id]->name, "ADB Powerbook buttons"); - adbhid[id]->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REP); - set_bit(KEY_MUTE, adbhid[id]->input.keybit); - set_bit(KEY_VOLUMEUP, adbhid[id]->input.keybit); - set_bit(KEY_VOLUMEDOWN, adbhid[id]->input.keybit); - set_bit(KEY_BRIGHTNESSUP, adbhid[id]->input.keybit); - set_bit(KEY_BRIGHTNESSDOWN, adbhid[id]->input.keybit); - set_bit(KEY_EJECTCD, adbhid[id]->input.keybit); - set_bit(KEY_SWITCHVIDEOMODE, adbhid[id]->input.keybit); - set_bit(KEY_KBDILLUMTOGGLE, adbhid[id]->input.keybit); - set_bit(KEY_KBDILLUMDOWN, adbhid[id]->input.keybit); - set_bit(KEY_KBDILLUMUP, adbhid[id]->input.keybit); + sprintf(hid->name, "ADB Powerbook buttons"); + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP); + set_bit(KEY_MUTE, input_dev->keybit); + set_bit(KEY_VOLUMEUP, input_dev->keybit); + set_bit(KEY_VOLUMEDOWN, input_dev->keybit); + set_bit(KEY_BRIGHTNESSUP, input_dev->keybit); + set_bit(KEY_BRIGHTNESSDOWN, input_dev->keybit); + set_bit(KEY_EJECTCD, input_dev->keybit); + set_bit(KEY_SWITCHVIDEOMODE, input_dev->keybit); + set_bit(KEY_KBDILLUMTOGGLE, input_dev->keybit); + set_bit(KEY_KBDILLUMDOWN, input_dev->keybit); + set_bit(KEY_KBDILLUMUP, input_dev->keybit); break; } - if (adbhid[id]->name[0]) + if (hid->name[0]) break; /* else fall through */ default: printk(KERN_INFO "Trying to register unknown ADB device to input layer.\n"); - kfree(adbhid[id]); - return; + err = -ENODEV; + goto fail; } - adbhid[id]->input.keycode = adbhid[id]->keycode; - - input_register_device(&adbhid[id]->input); + input_dev->keycode = hid->keycode; - printk(KERN_INFO "input: %s on %s\n", - adbhid[id]->name, adbhid[id]->phys); + input_register_device(input_dev); if (default_id == ADB_KEYBOARD) { /* HACK WARNING!! This should go away as soon there is an utility * to control that for event devices. */ - adbhid[id]->input.rep[REP_DELAY] = 500; /* input layer default: 250 */ - adbhid[id]->input.rep[REP_PERIOD] = 66; /* input layer default: 33 */ + input_dev->rep[REP_DELAY] = 500; /* input layer default: 250 */ + input_dev->rep[REP_PERIOD] = 66; /* input layer default: 33 */ } + + return 0; + + fail: input_free_device(input_dev); + kfree(hid); + adbhid[id] = NULL; + return err; } static void adbhid_input_unregister(int id) { - input_unregister_device(&adbhid[id]->input); + input_unregister_device(adbhid[id]->input); if (adbhid[id]->keycode) kfree(adbhid[id]->keycode); kfree(adbhid[id]); @@ -858,7 +868,7 @@ adbhid_input_reregister(int id, int default_id, int org_handler_id, int cur_handler_id, int mk) { if (adbhid[id]) { - if (adbhid[id]->input.id.product != + if (adbhid[id]->input->id.product != ((id << 12)|(default_id << 8)|org_handler_id)) { adbhid_input_unregister(id); adbhid_input_register(id, default_id, org_handler_id, diff --git a/drivers/macintosh/mac_hid.c b/drivers/macintosh/mac_hid.c index 5ad3a5a9eb7f..a66636116f0b 100644 --- a/drivers/macintosh/mac_hid.c +++ b/drivers/macintosh/mac_hid.c @@ -16,8 +16,8 @@ #include <linux/module.h> -static struct input_dev emumousebtn; -static void emumousebtn_input_register(void); +static struct input_dev *emumousebtn; +static int emumousebtn_input_register(void); static int mouse_emulate_buttons = 0; static int mouse_button2_keycode = KEY_RIGHTCTRL; /* right control key */ static int mouse_button3_keycode = KEY_RIGHTALT; /* right option key */ @@ -90,10 +90,10 @@ int mac_hid_mouse_emulate_buttons(int caller, unsigned int keycode, int down) && (keycode == mouse_button2_keycode || keycode == mouse_button3_keycode)) { if (mouse_emulate_buttons == 1) { - input_report_key(&emumousebtn, + input_report_key(emumousebtn, keycode == mouse_button2_keycode ? BTN_MIDDLE : BTN_RIGHT, down); - input_sync(&emumousebtn); + input_sync(emumousebtn); return 1; } mouse_last_keycode = down ? keycode : 0; @@ -105,30 +105,34 @@ int mac_hid_mouse_emulate_buttons(int caller, unsigned int keycode, int down) EXPORT_SYMBOL(mac_hid_mouse_emulate_buttons); -static void emumousebtn_input_register(void) +static int emumousebtn_input_register(void) { - emumousebtn.name = "Macintosh mouse button emulation"; + emumousebtn = input_allocate_device(); + if (!emumousebtn) + return -ENOMEM; - init_input_dev(&emumousebtn); + emumousebtn->name = "Macintosh mouse button emulation"; + emumousebtn->id.bustype = BUS_ADB; + emumousebtn->id.vendor = 0x0001; + emumousebtn->id.product = 0x0001; + emumousebtn->id.version = 0x0100; - emumousebtn.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); - emumousebtn.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); - emumousebtn.relbit[0] = BIT(REL_X) | BIT(REL_Y); + emumousebtn->evbit[0] = BIT(EV_KEY) | BIT(EV_REL); + emumousebtn->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); + emumousebtn->relbit[0] = BIT(REL_X) | BIT(REL_Y); - emumousebtn.id.bustype = BUS_ADB; - emumousebtn.id.vendor = 0x0001; - emumousebtn.id.product = 0x0001; - emumousebtn.id.version = 0x0100; + input_register_device(emumousebtn); - input_register_device(&emumousebtn); - - printk(KERN_INFO "input: Macintosh mouse button emulation\n"); + return 0; } int __init mac_hid_init(void) { + int err; - emumousebtn_input_register(); + err = emumousebtn_input_register(); + if (err) + return err; #if defined(CONFIG_SYSCTL) mac_hid_sysctl_header = register_sysctl_table(mac_hid_root_dir, 1); diff --git a/drivers/macintosh/macio_asic.c b/drivers/macintosh/macio_asic.c index 1ee003346923..c34c96d18907 100644 --- a/drivers/macintosh/macio_asic.c +++ b/drivers/macintosh/macio_asic.c @@ -17,6 +17,8 @@ #include <linux/pci_ids.h> #include <linux/init.h> #include <linux/module.h> +#include <linux/slab.h> + #include <asm/machdep.h> #include <asm/macio.h> #include <asm/pmac_feature.h> diff --git a/drivers/mca/mca-device.c b/drivers/mca/mca-device.c index 76d430aa243f..e7adf89fae41 100644 --- a/drivers/mca/mca-device.c +++ b/drivers/mca/mca-device.c @@ -29,6 +29,7 @@ #include <linux/module.h> #include <linux/device.h> #include <linux/mca.h> +#include <linux/string.h> /** * mca_device_read_stored_pos - read POS register from stored data diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 2fba2bbe72d8..01654fcabc52 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -91,7 +91,7 @@ int bitmap_active(struct bitmap *bitmap) #define WRITE_POOL_SIZE 256 /* mempool for queueing pending writes on the bitmap file */ -static void *write_pool_alloc(unsigned int gfp_flags, void *data) +static void *write_pool_alloc(gfp_t gfp_flags, void *data) { return kmalloc(sizeof(struct page_list), gfp_flags); } diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index b6148f6f7836..cf6631056683 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -15,7 +15,7 @@ #include <linux/crypto.h> #include <linux/workqueue.h> #include <asm/atomic.h> -#include <asm/scatterlist.h> +#include <linux/scatterlist.h> #include <asm/page.h> #include "dm.h" @@ -164,9 +164,7 @@ static int crypt_iv_essiv_ctr(struct crypt_config *cc, struct dm_target *ti, return -ENOMEM; } - sg.page = virt_to_page(cc->key); - sg.offset = offset_in_page(cc->key); - sg.length = cc->key_size; + sg_set_buf(&sg, cc->key, cc->key_size); crypto_digest_digest(hash_tfm, &sg, 1, salt); crypto_free_tfm(hash_tfm); @@ -207,14 +205,12 @@ static void crypt_iv_essiv_dtr(struct crypt_config *cc) static int crypt_iv_essiv_gen(struct crypt_config *cc, u8 *iv, sector_t sector) { - struct scatterlist sg = { NULL, }; + struct scatterlist sg; memset(iv, 0, cc->iv_size); *(u64 *)iv = cpu_to_le64(sector); - sg.page = virt_to_page(iv); - sg.offset = offset_in_page(iv); - sg.length = cc->iv_size; + sg_set_buf(&sg, iv, cc->iv_size); crypto_cipher_encrypt((struct crypto_tfm *)cc->iv_gen_private, &sg, &sg, cc->iv_size); @@ -331,7 +327,7 @@ crypt_alloc_buffer(struct crypt_config *cc, unsigned int size, { struct bio *bio; unsigned int nr_iovecs = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; - int gfp_mask = GFP_NOIO | __GFP_HIGHMEM; + gfp_t gfp_mask = GFP_NOIO | __GFP_HIGHMEM; unsigned int i; /* diff --git a/drivers/media/common/ir-common.c b/drivers/media/common/ir-common.c index a0e700d7a4a4..31fccb4f05d6 100644 --- a/drivers/media/common/ir-common.c +++ b/drivers/media/common/ir-common.c @@ -22,6 +22,7 @@ #include <linux/module.h> #include <linux/moduleparam.h> +#include <linux/string.h> #include <media/ir-common.h> /* -------------------------------------------------------------------------- */ @@ -252,7 +253,6 @@ void ir_input_init(struct input_dev *dev, struct ir_input_state *ir, if (ir_codes) memcpy(ir->ir_codes, ir_codes, sizeof(ir->ir_codes)); - init_input_dev(dev); dev->keycode = ir->ir_codes; dev->keycodesize = sizeof(IR_KEYTAB_TYPE); dev->keycodemax = IR_KEYTAB_SIZE; diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c index 6db0929ef53d..a1607e7d6d6b 100644 --- a/drivers/media/dvb/cinergyT2/cinergyT2.c +++ b/drivers/media/dvb/cinergyT2/cinergyT2.c @@ -137,7 +137,8 @@ struct cinergyt2 { struct urb *stream_urb [STREAM_URB_COUNT]; #ifdef ENABLE_RC - struct input_dev rc_input_dev; + struct input_dev *rc_input_dev; + char phys[64]; struct work_struct rc_query_work; int rc_input_event; u32 rc_last_code; @@ -683,6 +684,7 @@ static struct dvb_device cinergyt2_fe_template = { }; #ifdef ENABLE_RC + static void cinergyt2_query_rc (void *data) { struct cinergyt2 *cinergyt2 = data; @@ -703,7 +705,7 @@ static void cinergyt2_query_rc (void *data) /* stop key repeat */ if (cinergyt2->rc_input_event != KEY_MAX) { dprintk(1, "rc_input_event=%d Up\n", cinergyt2->rc_input_event); - input_report_key(&cinergyt2->rc_input_dev, + input_report_key(cinergyt2->rc_input_dev, cinergyt2->rc_input_event, 0); cinergyt2->rc_input_event = KEY_MAX; } @@ -722,7 +724,7 @@ static void cinergyt2_query_rc (void *data) /* keyrepeat bit -> just repeat last rc_input_event */ } else { cinergyt2->rc_input_event = KEY_MAX; - for (i = 0; i < sizeof(rc_keys) / sizeof(rc_keys[0]); i += 3) { + for (i = 0; i < ARRAY_SIZE(rc_keys); i += 3) { if (rc_keys[i + 0] == rc_events[n].type && rc_keys[i + 1] == le32_to_cpu(rc_events[n].value)) { cinergyt2->rc_input_event = rc_keys[i + 2]; @@ -736,11 +738,11 @@ static void cinergyt2_query_rc (void *data) cinergyt2->rc_last_code != ~0) { /* emit a key-up so the double event is recognized */ dprintk(1, "rc_input_event=%d UP\n", cinergyt2->rc_input_event); - input_report_key(&cinergyt2->rc_input_dev, + input_report_key(cinergyt2->rc_input_dev, cinergyt2->rc_input_event, 0); } dprintk(1, "rc_input_event=%d\n", cinergyt2->rc_input_event); - input_report_key(&cinergyt2->rc_input_dev, + input_report_key(cinergyt2->rc_input_dev, cinergyt2->rc_input_event, 1); cinergyt2->rc_last_code = rc_events[n].value; } @@ -752,7 +754,59 @@ out: up(&cinergyt2->sem); } -#endif + +static int cinergyt2_register_rc(struct cinergyt2 *cinergyt2) +{ + struct input_dev *input_dev; + int i; + + cinergyt2->rc_input_dev = input_dev = input_allocate_device(); + if (!input_dev) + return -ENOMEM; + + usb_make_path(cinergyt2->udev, cinergyt2->phys, sizeof(cinergyt2->phys)); + strlcat(cinergyt2->phys, "/input0", sizeof(cinergyt2->phys)); + cinergyt2->rc_input_event = KEY_MAX; + cinergyt2->rc_last_code = ~0; + INIT_WORK(&cinergyt2->rc_query_work, cinergyt2_query_rc, cinergyt2); + + input_dev->name = DRIVER_NAME " remote control"; + input_dev->phys = cinergyt2->phys; + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP); + for (i = 0; ARRAY_SIZE(rc_keys); i += 3) + set_bit(rc_keys[i + 2], input_dev->keybit); + input_dev->keycodesize = 0; + input_dev->keycodemax = 0; + + input_register_device(cinergyt2->rc_input_dev); + schedule_delayed_work(&cinergyt2->rc_query_work, HZ/2); +} + +static void cinergyt2_unregister_rc(struct cinergyt2 *cinergyt2) +{ + cancel_delayed_work(&cinergyt2->rc_query_work); + flush_scheduled_work(); + input_unregister_device(cinergyt2->rc_input_dev); +} + +static inline void cinergyt2_suspend_rc(struct cinergyt2 *cinergyt2) +{ + cancel_delayed_work(&cinergyt2->rc_query_work); +} + +static inline void cinergyt2_resume_rc(struct cinergyt2 *cinergyt2) +{ + schedule_delayed_work(&cinergyt2->rc_query_work, HZ/2); +} + +#else + +static inline int cinergyt2_register_rc(struct cinergyt2 *cinergyt2) { return 0; } +static inline void cinergyt2_unregister_rc(struct cinergyt2 *cinergyt2) { } +static inline void cinergyt2_suspend_rc(struct cinergyt2 *cinergyt2) { } +static inline void cinergyt2_resume_rc(struct cinergyt2 *cinergyt2) { } + +#endif /* ENABLE_RC */ static void cinergyt2_query (void *data) { @@ -789,9 +843,6 @@ static int cinergyt2_probe (struct usb_interface *intf, { struct cinergyt2 *cinergyt2; int err; -#ifdef ENABLE_RC - int i; -#endif if (!(cinergyt2 = kmalloc (sizeof(struct cinergyt2), GFP_KERNEL))) { dprintk(1, "out of memory?!?\n"); @@ -846,30 +897,17 @@ static int cinergyt2_probe (struct usb_interface *intf, &cinergyt2_fe_template, cinergyt2, DVB_DEVICE_FRONTEND); -#ifdef ENABLE_RC - cinergyt2->rc_input_dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP); - cinergyt2->rc_input_dev.keycodesize = 0; - cinergyt2->rc_input_dev.keycodemax = 0; - cinergyt2->rc_input_dev.name = DRIVER_NAME " remote control"; - - for (i = 0; i < sizeof(rc_keys) / sizeof(rc_keys[0]); i += 3) - set_bit(rc_keys[i + 2], cinergyt2->rc_input_dev.keybit); - - input_register_device(&cinergyt2->rc_input_dev); - - cinergyt2->rc_input_event = KEY_MAX; - cinergyt2->rc_last_code = ~0; + err = cinergyt2_register_rc(cinergyt2); + if (err) + goto bailout; - INIT_WORK(&cinergyt2->rc_query_work, cinergyt2_query_rc, cinergyt2); - schedule_delayed_work(&cinergyt2->rc_query_work, HZ/2); -#endif return 0; bailout: dvb_dmxdev_release(&cinergyt2->dmxdev); dvb_dmx_release(&cinergyt2->demux); - dvb_unregister_adapter (&cinergyt2->adapter); - cinergyt2_free_stream_urbs (cinergyt2); + dvb_unregister_adapter(&cinergyt2->adapter); + cinergyt2_free_stream_urbs(cinergyt2); kfree(cinergyt2); return -ENOMEM; } @@ -881,11 +919,7 @@ static void cinergyt2_disconnect (struct usb_interface *intf) if (down_interruptible(&cinergyt2->sem)) return; -#ifdef ENABLE_RC - cancel_delayed_work(&cinergyt2->rc_query_work); - flush_scheduled_work(); - input_unregister_device(&cinergyt2->rc_input_dev); -#endif + cinergyt2_unregister_rc(cinergyt2); cinergyt2->demux.dmx.close(&cinergyt2->demux.dmx); dvb_net_release(&cinergyt2->dvbnet); @@ -908,9 +942,8 @@ static int cinergyt2_suspend (struct usb_interface *intf, pm_message_t state) if (state.event > PM_EVENT_ON) { struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf); -#ifdef ENABLE_RC - cancel_delayed_work(&cinergyt2->rc_query_work); -#endif + + cinergyt2_suspend_rc(cinergyt2); cancel_delayed_work(&cinergyt2->query_work); if (cinergyt2->streaming) cinergyt2_stop_stream_xfer(cinergyt2); @@ -938,9 +971,8 @@ static int cinergyt2_resume (struct usb_interface *intf) schedule_delayed_work(&cinergyt2->query_work, HZ/2); } -#ifdef ENABLE_RC - schedule_delayed_work(&cinergyt2->rc_query_work, HZ/2); -#endif + cinergyt2_resume_rc(cinergyt2); + up(&cinergyt2->sem); return 0; } diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c index 88757e2634e5..2aa767f9bd7d 100644 --- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c +++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c @@ -36,6 +36,7 @@ #include <linux/vmalloc.h> #include <linux/delay.h> #include <linux/rwsem.h> +#include <linux/sched.h> #include "dvb_ca_en50221.h" #include "dvb_ringbuffer.h" diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c index 4b7adca3e286..477b4fa56430 100644 --- a/drivers/media/dvb/dvb-core/dvbdev.c +++ b/drivers/media/dvb/dvb-core/dvbdev.c @@ -235,7 +235,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, S_IFCHR | S_IRUSR | S_IWUSR, "dvb/adapter%d/%s%d", adap->num, dnames[type], id); - class_device_create(dvb_class, MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)), + class_device_create(dvb_class, NULL, MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)), NULL, "dvb%d.%s%d", adap->num, dnames[type], id); dprintk("DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n", diff --git a/drivers/media/dvb/dvb-usb/dtt200u.c b/drivers/media/dvb/dvb-usb/dtt200u.c index 5aa12ebab34f..b595476332cd 100644 --- a/drivers/media/dvb/dvb-usb/dtt200u.c +++ b/drivers/media/dvb/dvb-usb/dtt200u.c @@ -151,7 +151,7 @@ static struct dvb_usb_properties dtt200u_properties = { .cold_ids = { &dtt200u_usb_table[0], NULL }, .warm_ids = { &dtt200u_usb_table[1], NULL }, }, - { 0 }, + { NULL }, } }; @@ -192,7 +192,7 @@ static struct dvb_usb_properties wt220u_properties = { .cold_ids = { &dtt200u_usb_table[2], NULL }, .warm_ids = { &dtt200u_usb_table[3], NULL }, }, - { 0 }, + { NULL }, } }; diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c index fc7800f1743e..e5c6d9835e06 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c @@ -39,9 +39,9 @@ static void dvb_usb_read_remote_control(void *data) d->last_event = event; case REMOTE_KEY_REPEAT: deb_rc("key repeated\n"); - input_event(&d->rc_input_dev, EV_KEY, d->last_event, 1); - input_event(&d->rc_input_dev, EV_KEY, d->last_event, 0); - input_sync(&d->rc_input_dev); + input_event(d->rc_input_dev, EV_KEY, event, 1); + input_event(d->rc_input_dev, EV_KEY, d->last_event, 0); + input_sync(d->rc_input_dev); break; default: break; @@ -53,8 +53,8 @@ static void dvb_usb_read_remote_control(void *data) deb_rc("NO KEY PRESSED\n"); if (d->last_state != REMOTE_NO_KEY_PRESSED) { deb_rc("releasing event %d\n",d->last_event); - input_event(&d->rc_input_dev, EV_KEY, d->last_event, 0); - input_sync(&d->rc_input_dev); + input_event(d->rc_input_dev, EV_KEY, d->last_event, 0); + input_sync(d->rc_input_dev); } d->last_state = REMOTE_NO_KEY_PRESSED; d->last_event = 0; @@ -63,8 +63,8 @@ static void dvb_usb_read_remote_control(void *data) deb_rc("KEY PRESSED\n"); deb_rc("pressing event %d\n",event); - input_event(&d->rc_input_dev, EV_KEY, event, 1); - input_sync(&d->rc_input_dev); + input_event(d->rc_input_dev, EV_KEY, event, 1); + input_sync(d->rc_input_dev); d->last_event = event; d->last_state = REMOTE_KEY_PRESSED; @@ -73,8 +73,8 @@ static void dvb_usb_read_remote_control(void *data) deb_rc("KEY_REPEAT\n"); if (d->last_state != REMOTE_NO_KEY_PRESSED) { deb_rc("repeating event %d\n",d->last_event); - input_event(&d->rc_input_dev, EV_KEY, d->last_event, 2); - input_sync(&d->rc_input_dev); + input_event(d->rc_input_dev, EV_KEY, d->last_event, 2); + input_sync(d->rc_input_dev); d->last_state = REMOTE_KEY_REPEAT; } default: @@ -89,24 +89,30 @@ schedule: int dvb_usb_remote_init(struct dvb_usb_device *d) { int i; + if (d->props.rc_key_map == NULL || d->props.rc_query == NULL || dvb_usb_disable_rc_polling) return 0; - /* Initialise the remote-control structures.*/ - init_input_dev(&d->rc_input_dev); + usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys)); + strlcpy(d->rc_phys, "/ir0", sizeof(d->rc_phys)); + + d->rc_input_dev = input_allocate_device(); + if (!d->rc_input_dev) + return -ENOMEM; - d->rc_input_dev.evbit[0] = BIT(EV_KEY); - d->rc_input_dev.keycodesize = sizeof(unsigned char); - d->rc_input_dev.keycodemax = KEY_MAX; - d->rc_input_dev.name = "IR-receiver inside an USB DVB receiver"; + d->rc_input_dev->evbit[0] = BIT(EV_KEY); + d->rc_input_dev->keycodesize = sizeof(unsigned char); + d->rc_input_dev->keycodemax = KEY_MAX; + d->rc_input_dev->name = "IR-receiver inside an USB DVB receiver"; + d->rc_input_dev->phys = d->rc_phys; /* set the bits for the keys */ - deb_rc("key map size: %d\n",d->props.rc_key_map_size); + deb_rc("key map size: %d\n", d->props.rc_key_map_size); for (i = 0; i < d->props.rc_key_map_size; i++) { deb_rc("setting bit for event %d item %d\n",d->props.rc_key_map[i].event, i); - set_bit(d->props.rc_key_map[i].event, d->rc_input_dev.keybit); + set_bit(d->props.rc_key_map[i].event, d->rc_input_dev->keybit); } /* Start the remote-control polling. */ @@ -114,14 +120,14 @@ int dvb_usb_remote_init(struct dvb_usb_device *d) d->props.rc_interval = 100; /* default */ /* setting these two values to non-zero, we have to manage key repeats */ - d->rc_input_dev.rep[REP_PERIOD] = d->props.rc_interval; - d->rc_input_dev.rep[REP_DELAY] = d->props.rc_interval + 150; + d->rc_input_dev->rep[REP_PERIOD] = d->props.rc_interval; + d->rc_input_dev->rep[REP_DELAY] = d->props.rc_interval + 150; - input_register_device(&d->rc_input_dev); + input_register_device(d->rc_input_dev); INIT_WORK(&d->rc_query_work, dvb_usb_read_remote_control, d); - info("schedule remote query interval to %d msecs.",d->props.rc_interval); + info("schedule remote query interval to %d msecs.", d->props.rc_interval); schedule_delayed_work(&d->rc_query_work,msecs_to_jiffies(d->props.rc_interval)); d->state |= DVB_USB_STATE_REMOTE; @@ -134,7 +140,7 @@ int dvb_usb_remote_exit(struct dvb_usb_device *d) if (d->state & DVB_USB_STATE_REMOTE) { cancel_delayed_work(&d->rc_query_work); flush_scheduled_work(); - input_unregister_device(&d->rc_input_dev); + input_unregister_device(d->rc_input_dev); } d->state &= ~DVB_USB_STATE_REMOTE; return 0; diff --git a/drivers/media/dvb/dvb-usb/dvb-usb.h b/drivers/media/dvb/dvb-usb/dvb-usb.h index 0e4f1035b0dd..b4a1a98006c7 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb.h @@ -300,7 +300,8 @@ struct dvb_usb_device { int (*fe_init) (struct dvb_frontend *); /* remote control */ - struct input_dev rc_input_dev; + struct input_dev *rc_input_dev; + char rc_phys[64]; struct work_struct rc_query_work; u32 last_event; int last_state; diff --git a/drivers/media/dvb/dvb-usb/vp7045.c b/drivers/media/dvb/dvb-usb/vp7045.c index 0f57abeb6d6b..75765e3a569c 100644 --- a/drivers/media/dvb/dvb-usb/vp7045.c +++ b/drivers/media/dvb/dvb-usb/vp7045.c @@ -247,7 +247,7 @@ static struct dvb_usb_properties vp7045_properties = { .cold_ids = { &vp7045_usb_table[2], NULL }, .warm_ids = { &vp7045_usb_table[3], NULL }, }, - { 0 }, + { NULL }, } }; diff --git a/drivers/media/dvb/frontends/bcm3510.c b/drivers/media/dvb/frontends/bcm3510.c index f5fdc5c3e605..f6d4ee78bdd4 100644 --- a/drivers/media/dvb/frontends/bcm3510.c +++ b/drivers/media/dvb/frontends/bcm3510.c @@ -36,6 +36,9 @@ #include <linux/moduleparam.h> #include <linux/device.h> #include <linux/firmware.h> +#include <linux/jiffies.h> +#include <linux/string.h> +#include <linux/slab.h> #include "dvb_frontend.h" #include "bcm3510.h" diff --git a/drivers/media/dvb/frontends/dib3000mb.c b/drivers/media/dvb/frontends/dib3000mb.c index 21433e1831e7..6b0553608610 100644 --- a/drivers/media/dvb/frontends/dib3000mb.c +++ b/drivers/media/dvb/frontends/dib3000mb.c @@ -27,6 +27,8 @@ #include <linux/moduleparam.h> #include <linux/init.h> #include <linux/delay.h> +#include <linux/string.h> +#include <linux/slab.h> #include "dib3000-common.h" #include "dib3000mb_priv.h" diff --git a/drivers/media/dvb/frontends/dib3000mc.c b/drivers/media/dvb/frontends/dib3000mc.c index 441de665fec3..c024fad17337 100644 --- a/drivers/media/dvb/frontends/dib3000mc.c +++ b/drivers/media/dvb/frontends/dib3000mc.c @@ -26,6 +26,8 @@ #include <linux/moduleparam.h> #include <linux/init.h> #include <linux/delay.h> +#include <linux/string.h> +#include <linux/slab.h> #include "dib3000-common.h" #include "dib3000mc_priv.h" diff --git a/drivers/media/dvb/frontends/dvb_dummy_fe.c b/drivers/media/dvb/frontends/dvb_dummy_fe.c index cff93b9d8ab2..794be520d590 100644 --- a/drivers/media/dvb/frontends/dvb_dummy_fe.c +++ b/drivers/media/dvb/frontends/dvb_dummy_fe.c @@ -22,6 +22,8 @@ #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/init.h> +#include <linux/string.h> +#include <linux/slab.h> #include "dvb_frontend.h" #include "dvb_dummy_fe.h" diff --git a/drivers/media/dvb/frontends/lgdt330x.c b/drivers/media/dvb/frontends/lgdt330x.c index 7142b9c51dd2..8dde72bd1046 100644 --- a/drivers/media/dvb/frontends/lgdt330x.c +++ b/drivers/media/dvb/frontends/lgdt330x.c @@ -37,6 +37,8 @@ #include <linux/moduleparam.h> #include <linux/init.h> #include <linux/delay.h> +#include <linux/string.h> +#include <linux/slab.h> #include <asm/byteorder.h> #include "dvb_frontend.h" diff --git a/drivers/media/dvb/frontends/mt312.c b/drivers/media/dvb/frontends/mt312.c index e455aecd76b2..e38454901dd1 100644 --- a/drivers/media/dvb/frontends/mt312.c +++ b/drivers/media/dvb/frontends/mt312.c @@ -29,6 +29,8 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/moduleparam.h> +#include <linux/string.h> +#include <linux/slab.h> #include "dvb_frontend.h" #include "mt312_priv.h" diff --git a/drivers/media/dvb/frontends/mt352.c b/drivers/media/dvb/frontends/mt352.c index cc1bc0edd65e..f0c610f2c2df 100644 --- a/drivers/media/dvb/frontends/mt352.c +++ b/drivers/media/dvb/frontends/mt352.c @@ -35,6 +35,8 @@ #include <linux/moduleparam.h> #include <linux/init.h> #include <linux/delay.h> +#include <linux/string.h> +#include <linux/slab.h> #include "dvb_frontend.h" #include "mt352_priv.h" diff --git a/drivers/media/dvb/frontends/nxt2002.c b/drivers/media/dvb/frontends/nxt2002.c index 35a1d60f1927..30786b1911bd 100644 --- a/drivers/media/dvb/frontends/nxt2002.c +++ b/drivers/media/dvb/frontends/nxt2002.c @@ -32,6 +32,8 @@ #include <linux/moduleparam.h> #include <linux/device.h> #include <linux/firmware.h> +#include <linux/string.h> +#include <linux/slab.h> #include "dvb_frontend.h" #include "nxt2002.h" diff --git a/drivers/media/dvb/frontends/or51132.c b/drivers/media/dvb/frontends/or51132.c index b6d0eecc59eb..817b044c7fd1 100644 --- a/drivers/media/dvb/frontends/or51132.c +++ b/drivers/media/dvb/frontends/or51132.c @@ -36,6 +36,8 @@ #include <linux/moduleparam.h> #include <linux/init.h> #include <linux/delay.h> +#include <linux/string.h> +#include <linux/slab.h> #include <asm/byteorder.h> #include "dvb_frontend.h" diff --git a/drivers/media/dvb/frontends/or51211.c b/drivers/media/dvb/frontends/or51211.c index ad56a9958404..8a9db23dd1b7 100644 --- a/drivers/media/dvb/frontends/or51211.c +++ b/drivers/media/dvb/frontends/or51211.c @@ -34,6 +34,8 @@ #include <linux/moduleparam.h> #include <linux/device.h> #include <linux/firmware.h> +#include <linux/string.h> +#include <linux/slab.h> #include <asm/byteorder.h> #include "dvb_frontend.h" diff --git a/drivers/media/dvb/frontends/s5h1420.c b/drivers/media/dvb/frontends/s5h1420.c index c7fe27fd530c..f265418e3261 100644 --- a/drivers/media/dvb/frontends/s5h1420.c +++ b/drivers/media/dvb/frontends/s5h1420.c @@ -26,6 +26,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. #include <linux/string.h> #include <linux/slab.h> #include <linux/delay.h> +#include <linux/jiffies.h> +#include <asm/div64.h> #include "dvb_frontend.h" #include "s5h1420.h" diff --git a/drivers/media/dvb/frontends/sp8870.c b/drivers/media/dvb/frontends/sp8870.c index 764a95a2e212..1c6b2e9264bc 100644 --- a/drivers/media/dvb/frontends/sp8870.c +++ b/drivers/media/dvb/frontends/sp8870.c @@ -32,6 +32,8 @@ #include <linux/device.h> #include <linux/firmware.h> #include <linux/delay.h> +#include <linux/string.h> +#include <linux/slab.h> #include "dvb_frontend.h" #include "sp8870.h" diff --git a/drivers/media/dvb/frontends/sp887x.c b/drivers/media/dvb/frontends/sp887x.c index d868a6927a16..73384e75625e 100644 --- a/drivers/media/dvb/frontends/sp887x.c +++ b/drivers/media/dvb/frontends/sp887x.c @@ -14,6 +14,8 @@ #include <linux/moduleparam.h> #include <linux/device.h> #include <linux/firmware.h> +#include <linux/string.h> +#include <linux/slab.h> #include "dvb_frontend.h" #include "sp887x.h" diff --git a/drivers/media/dvb/frontends/stv0297.c b/drivers/media/dvb/frontends/stv0297.c index 8d09afd7545d..6122ba754bc5 100644 --- a/drivers/media/dvb/frontends/stv0297.c +++ b/drivers/media/dvb/frontends/stv0297.c @@ -24,6 +24,8 @@ #include <linux/module.h> #include <linux/string.h> #include <linux/delay.h> +#include <linux/jiffies.h> +#include <linux/slab.h> #include "dvb_frontend.h" #include "stv0297.h" diff --git a/drivers/media/dvb/frontends/stv0299.c b/drivers/media/dvb/frontends/stv0299.c index 2d62931f20b5..889d9257215d 100644 --- a/drivers/media/dvb/frontends/stv0299.c +++ b/drivers/media/dvb/frontends/stv0299.c @@ -48,6 +48,7 @@ #include <linux/moduleparam.h> #include <linux/string.h> #include <linux/slab.h> +#include <linux/jiffies.h> #include <asm/div64.h> #include "dvb_frontend.h" diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c index 74cea9f8d721..3529c618f828 100644 --- a/drivers/media/dvb/frontends/tda1004x.c +++ b/drivers/media/dvb/frontends/tda1004x.c @@ -32,6 +32,10 @@ #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/device.h> +#include <linux/jiffies.h> +#include <linux/string.h> +#include <linux/slab.h> + #include "dvb_frontend.h" #include "tda1004x.h" diff --git a/drivers/media/dvb/frontends/tda8083.c b/drivers/media/dvb/frontends/tda8083.c index 168e013d23bd..c05cf1861051 100644 --- a/drivers/media/dvb/frontends/tda8083.c +++ b/drivers/media/dvb/frontends/tda8083.c @@ -30,6 +30,7 @@ #include <linux/moduleparam.h> #include <linux/string.h> #include <linux/slab.h> +#include <linux/jiffies.h> #include "dvb_frontend.h" #include "tda8083.h" diff --git a/drivers/media/dvb/ttpci/av7110_ir.c b/drivers/media/dvb/ttpci/av7110_ir.c index 357a3728ec68..f5e59fc924af 100644 --- a/drivers/media/dvb/ttpci/av7110_ir.c +++ b/drivers/media/dvb/ttpci/av7110_ir.c @@ -15,7 +15,7 @@ static int av_cnt; static struct av7110 *av_list[4]; -static struct input_dev input_dev; +static struct input_dev *input_dev; static u16 key_map [256] = { KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, @@ -43,10 +43,10 @@ static u16 key_map [256] = { static void av7110_emit_keyup(unsigned long data) { - if (!data || !test_bit(data, input_dev.key)) + if (!data || !test_bit(data, input_dev->key)) return; - input_event(&input_dev, EV_KEY, data, !!0); + input_event(input_dev, EV_KEY, data, !!0); } @@ -112,13 +112,13 @@ static void av7110_emit_key(unsigned long parm) if (timer_pending(&keyup_timer)) { del_timer(&keyup_timer); if (keyup_timer.data != keycode || new_toggle != old_toggle) { - input_event(&input_dev, EV_KEY, keyup_timer.data, !!0); - input_event(&input_dev, EV_KEY, keycode, !0); + input_event(input_dev, EV_KEY, keyup_timer.data, !!0); + input_event(input_dev, EV_KEY, keycode, !0); } else - input_event(&input_dev, EV_KEY, keycode, 2); + input_event(input_dev, EV_KEY, keycode, 2); } else - input_event(&input_dev, EV_KEY, keycode, !0); + input_event(input_dev, EV_KEY, keycode, !0); keyup_timer.expires = jiffies + UP_TIMEOUT; keyup_timer.data = keycode; @@ -132,13 +132,13 @@ static void input_register_keys(void) { int i; - memset(input_dev.keybit, 0, sizeof(input_dev.keybit)); + memset(input_dev->keybit, 0, sizeof(input_dev->keybit)); - for (i = 0; i < sizeof(key_map) / sizeof(key_map[0]); i++) { + for (i = 0; i < ARRAY_SIZE(key_map); i++) { if (key_map[i] > KEY_MAX) key_map[i] = 0; else if (key_map[i] > KEY_RESERVED) - set_bit(key_map[i], input_dev.keybit); + set_bit(key_map[i], input_dev->keybit); } } @@ -216,12 +216,17 @@ int __init av7110_ir_init(struct av7110 *av7110) init_timer(&keyup_timer); keyup_timer.data = 0; - input_dev.name = "DVB on-card IR receiver"; - set_bit(EV_KEY, input_dev.evbit); - set_bit(EV_REP, input_dev.evbit); + input_dev = input_allocate_device(); + if (!input_dev) + return -ENOMEM; + + input_dev->name = "DVB on-card IR receiver"; + + set_bit(EV_KEY, input_dev->evbit); + set_bit(EV_REP, input_dev->evbit); input_register_keys(); - input_register_device(&input_dev); - input_dev.timer.function = input_repeat_key; + input_register_device(input_dev); + input_dev->timer.function = input_repeat_key; e = create_proc_entry("av7110_ir", S_IFREG | S_IRUGO | S_IWUSR, NULL); if (e) { @@ -256,7 +261,7 @@ void __exit av7110_ir_exit(struct av7110 *av7110) if (av_cnt == 1) { del_timer_sync(&keyup_timer); remove_proc_entry("av7110_ir", NULL); - input_unregister_device(&input_dev); + input_unregister_device(input_dev); } av_cnt--; diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c index 2980db3ef22f..51c30ba68140 100644 --- a/drivers/media/dvb/ttpci/budget-ci.c +++ b/drivers/media/dvb/ttpci/budget-ci.c @@ -64,7 +64,7 @@ struct budget_ci { struct budget budget; - struct input_dev input_dev; + struct input_dev *input_dev; struct tasklet_struct msp430_irq_tasklet; struct tasklet_struct ciintf_irq_tasklet; int slot_status; @@ -145,7 +145,7 @@ static void msp430_ir_debounce(unsigned long data) static void msp430_ir_interrupt(unsigned long data) { struct budget_ci *budget_ci = (struct budget_ci *) data; - struct input_dev *dev = &budget_ci->input_dev; + struct input_dev *dev = budget_ci->input_dev; unsigned int code = ttpci_budget_debiread(&budget_ci->budget, DEBINOSWAP, DEBIADDR_IR, 2, 1, 0) >> 8; @@ -181,25 +181,27 @@ static void msp430_ir_interrupt(unsigned long data) static int msp430_ir_init(struct budget_ci *budget_ci) { struct saa7146_dev *saa = budget_ci->budget.dev; + struct input_dev *input_dev; int i; - memset(&budget_ci->input_dev, 0, sizeof(struct input_dev)); + budget_ci->input_dev = input_dev = input_allocate_device(); + if (!input_dev) + return -ENOMEM; sprintf(budget_ci->ir_dev_name, "Budget-CI dvb ir receiver %s", saa->name); - budget_ci->input_dev.name = budget_ci->ir_dev_name; - set_bit(EV_KEY, budget_ci->input_dev.evbit); + input_dev->name = budget_ci->ir_dev_name; - for (i = 0; i < sizeof(key_map) / sizeof(*key_map); i++) + set_bit(EV_KEY, input_dev->evbit); + for (i = 0; i < ARRAY_SIZE(key_map); i++) if (key_map[i]) - set_bit(key_map[i], budget_ci->input_dev.keybit); + set_bit(key_map[i], input_dev->keybit); - input_register_device(&budget_ci->input_dev); + input_register_device(budget_ci->input_dev); - budget_ci->input_dev.timer.function = msp430_ir_debounce; + input_dev->timer.function = msp430_ir_debounce; saa7146_write(saa, IER, saa7146_read(saa, IER) | MASK_06); - saa7146_setgpio(saa, 3, SAA7146_GPIO_IRQHI); return 0; @@ -208,7 +210,7 @@ static int msp430_ir_init(struct budget_ci *budget_ci) static void msp430_ir_deinit(struct budget_ci *budget_ci) { struct saa7146_dev *saa = budget_ci->budget.dev; - struct input_dev *dev = &budget_ci->input_dev; + struct input_dev *dev = budget_ci->input_dev; saa7146_write(saa, IER, saa7146_read(saa, IER) & ~MASK_06); saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT); diff --git a/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/drivers/media/dvb/ttusb-dec/ttusb_dec.c index 3d08fc83a754..832d179f26fa 100644 --- a/drivers/media/dvb/ttusb-dec/ttusb_dec.c +++ b/drivers/media/dvb/ttusb-dec/ttusb_dec.c @@ -152,7 +152,8 @@ struct ttusb_dec { struct list_head filter_info_list; spinlock_t filter_info_list_lock; - struct input_dev rc_input_dev; + struct input_dev *rc_input_dev; + char rc_phys[64]; int active; /* Loaded successfully */ }; @@ -235,9 +236,9 @@ static void ttusb_dec_handle_irq( struct urb *urb, struct pt_regs *regs) * this should/could be added later ... * for now lets report each signal as a key down and up*/ dprintk("%s:rc signal:%d\n", __FUNCTION__, buffer[4]); - input_report_key(&dec->rc_input_dev,rc_keys[buffer[4]-1],1); - input_report_key(&dec->rc_input_dev,rc_keys[buffer[4]-1],0); - input_sync(&dec->rc_input_dev); + input_report_key(dec->rc_input_dev, rc_keys[buffer[4] - 1], 1); + input_report_key(dec->rc_input_dev, rc_keys[buffer[4] - 1], 0); + input_sync(dec->rc_input_dev); } exit: retval = usb_submit_urb(urb, GFP_ATOMIC); @@ -1181,29 +1182,38 @@ static void ttusb_dec_init_tasklet(struct ttusb_dec *dec) (unsigned long)dec); } -static void ttusb_init_rc( struct ttusb_dec *dec) +static int ttusb_init_rc(struct ttusb_dec *dec) { + struct input_dev *input_dev; u8 b[] = { 0x00, 0x01 }; int i; - init_input_dev(&dec->rc_input_dev); + usb_make_path(dec->udev, dec->rc_phys, sizeof(dec->rc_phys)); + strlcpy(dec->rc_phys, "/input0", sizeof(dec->rc_phys)); - dec->rc_input_dev.name = "ttusb_dec remote control"; - dec->rc_input_dev.evbit[0] = BIT(EV_KEY); - dec->rc_input_dev.keycodesize = sizeof(u16); - dec->rc_input_dev.keycodemax = 0x1a; - dec->rc_input_dev.keycode = rc_keys; + dec->rc_input_dev = input_dev = input_allocate_device(); + if (!input_dev) + return -ENOMEM; + + input_dev->name = "ttusb_dec remote control"; + input_dev->phys = dec->rc_phys; + input_dev->evbit[0] = BIT(EV_KEY); + input_dev->keycodesize = sizeof(u16); + input_dev->keycodemax = 0x1a; + input_dev->keycode = rc_keys; - for (i = 0; i < sizeof(rc_keys)/sizeof(rc_keys[0]); i++) - set_bit(rc_keys[i], dec->rc_input_dev.keybit); + for (i = 0; i < ARRAY_SIZE(rc_keys); i++) + set_bit(rc_keys[i], input_dev->keybit); - input_register_device(&dec->rc_input_dev); + input_register_device(input_dev); - if(usb_submit_urb(dec->irq_urb,GFP_KERNEL)) { + if (usb_submit_urb(dec->irq_urb, GFP_KERNEL)) printk("%s: usb_submit_urb failed\n",__FUNCTION__); - } + /* enable irq pipe */ ttusb_dec_send_command(dec,0xb0,sizeof(b),b,NULL,NULL); + + return 0; } static void ttusb_dec_init_v_pes(struct ttusb_dec *dec) @@ -1513,7 +1523,7 @@ static void ttusb_dec_exit_rc(struct ttusb_dec *dec) * As the irq is submitted after the interface is changed, * this is the best method i figured out. * Any others?*/ - if(dec->interface == TTUSB_DEC_INTERFACE_IN) + if (dec->interface == TTUSB_DEC_INTERFACE_IN) usb_kill_urb(dec->irq_urb); usb_free_urb(dec->irq_urb); @@ -1521,7 +1531,10 @@ static void ttusb_dec_exit_rc(struct ttusb_dec *dec) usb_buffer_free(dec->udev,IRQ_PACKET_SIZE, dec->irq_buffer, dec->irq_dma_handle); - input_unregister_device(&dec->rc_input_dev); + if (dec->rc_input_dev) { + input_unregister_device(dec->rc_input_dev); + dec->rc_input_dev = NULL; + } } @@ -1659,7 +1672,7 @@ static int ttusb_dec_probe(struct usb_interface *intf, ttusb_dec_set_interface(dec, TTUSB_DEC_INTERFACE_IN); - if(enable_rc) + if (enable_rc) ttusb_init_rc(dec); return 0; diff --git a/drivers/media/radio/miropcm20-rds.c b/drivers/media/radio/miropcm20-rds.c index df79d5e0aaed..e09214082e01 100644 --- a/drivers/media/radio/miropcm20-rds.c +++ b/drivers/media/radio/miropcm20-rds.c @@ -14,6 +14,7 @@ #include <linux/slab.h> #include <linux/fs.h> #include <linux/miscdevice.h> +#include <linux/sched.h> /* current, TASK_*, schedule_timeout() */ #include <linux/delay.h> #include <asm/uaccess.h> #include "miropcm20-rds-core.h" diff --git a/drivers/media/video/bttvp.h b/drivers/media/video/bttvp.h index 7a312f79340a..e0e7c7a84bc5 100644 --- a/drivers/media/video/bttvp.h +++ b/drivers/media/video/bttvp.h @@ -240,7 +240,7 @@ struct bttv_pll_info { /* for gpio-connected remote control */ struct bttv_input { - struct input_dev dev; + struct input_dev *dev; struct ir_input_state ir; char name[32]; char phys[32]; diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c index d81b21d6e05d..c27fe4c36f69 100644 --- a/drivers/media/video/cx88/cx88-input.c +++ b/drivers/media/video/cx88/cx88-input.c @@ -260,7 +260,7 @@ static IR_KEYTAB_TYPE ir_codes_cinergy_1400[IR_KEYTAB_SIZE] = { struct cx88_IR { struct cx88_core *core; - struct input_dev input; + struct input_dev *input; struct ir_input_state ir; char name[32]; char phys[32]; @@ -315,23 +315,23 @@ static void cx88_ir_handle_key(struct cx88_IR *ir) if (ir->mask_keydown) { /* bit set on keydown */ if (gpio & ir->mask_keydown) { - ir_input_keydown(&ir->input, &ir->ir, data, data); + ir_input_keydown(ir->input, &ir->ir, data, data); } else { - ir_input_nokey(&ir->input, &ir->ir); + ir_input_nokey(ir->input, &ir->ir); } } else if (ir->mask_keyup) { /* bit cleared on keydown */ if (0 == (gpio & ir->mask_keyup)) { - ir_input_keydown(&ir->input, &ir->ir, data, data); + ir_input_keydown(ir->input, &ir->ir, data, data); } else { - ir_input_nokey(&ir->input, &ir->ir); + ir_input_nokey(ir->input, &ir->ir); } } else { /* can't distinguish keydown/up :-/ */ - ir_input_keydown(&ir->input, &ir->ir, data, data); - ir_input_nokey(&ir->input, &ir->ir); + ir_input_keydown(ir->input, &ir->ir, data, data); + ir_input_nokey(ir->input, &ir->ir); } } @@ -357,13 +357,19 @@ static void cx88_ir_work(void *data) int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) { struct cx88_IR *ir; + struct input_dev *input_dev; IR_KEYTAB_TYPE *ir_codes = NULL; int ir_type = IR_TYPE_OTHER; - ir = kmalloc(sizeof(*ir), GFP_KERNEL); - if (NULL == ir) + ir = kzalloc(sizeof(*ir), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!ir || !input_dev) { + kfree(ir); + input_free_device(input_dev); return -ENOMEM; - memset(ir, 0, sizeof(*ir)); + } + + ir->input = input_dev; /* detect & configure */ switch (core->board) { @@ -425,6 +431,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) if (NULL == ir_codes) { kfree(ir); + input_free_device(input_dev); return -ENODEV; } @@ -433,19 +440,19 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) cx88_boards[core->board].name); snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", pci_name(pci)); - ir_input_init(&ir->input, &ir->ir, ir_type, ir_codes); - ir->input.name = ir->name; - ir->input.phys = ir->phys; - ir->input.id.bustype = BUS_PCI; - ir->input.id.version = 1; + ir_input_init(input_dev, &ir->ir, ir_type, ir_codes); + input_dev->name = ir->name; + input_dev->phys = ir->phys; + input_dev->id.bustype = BUS_PCI; + input_dev->id.version = 1; if (pci->subsystem_vendor) { - ir->input.id.vendor = pci->subsystem_vendor; - ir->input.id.product = pci->subsystem_device; + input_dev->id.vendor = pci->subsystem_vendor; + input_dev->id.product = pci->subsystem_device; } else { - ir->input.id.vendor = pci->vendor; - ir->input.id.product = pci->device; + input_dev->id.vendor = pci->vendor; + input_dev->id.product = pci->device; } - ir->input.dev = &pci->dev; + input_dev->cdev.dev = &pci->dev; /* record handles to ourself */ ir->core = core; @@ -465,8 +472,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) } /* all done */ - input_register_device(&ir->input); - printk("%s: registered IR remote control\n", core->name); + input_register_device(ir->input); return 0; } @@ -484,7 +490,7 @@ int cx88_ir_fini(struct cx88_core *core) flush_scheduled_work(); } - input_unregister_device(&ir->input); + input_unregister_device(ir->input); kfree(ir); /* done */ @@ -515,7 +521,7 @@ void cx88_ir_irq(struct cx88_core *core) if (!ir->scount) { /* nothing to sample */ if (ir->ir.keypressed && time_after(jiffies, ir->release)) - ir_input_nokey(&ir->input, &ir->ir); + ir_input_nokey(ir->input, &ir->ir); return; } @@ -557,7 +563,7 @@ void cx88_ir_irq(struct cx88_core *core) ir_dprintk("Key Code: %x\n", (ircode >> 16) & 0x7f); - ir_input_keydown(&ir->input, &ir->ir, (ircode >> 16) & 0x7f, (ircode >> 16) & 0xff); + ir_input_keydown(ir->input, &ir->ir, (ircode >> 16) & 0x7f, (ircode >> 16) & 0xff); ir->release = jiffies + msecs_to_jiffies(120); break; case CX88_BOARD_HAUPPAUGE: @@ -566,7 +572,7 @@ void cx88_ir_irq(struct cx88_core *core) ir_dprintk("biphase decoded: %x\n", ircode); if ((ircode & 0xfffff000) != 0x3000) break; - ir_input_keydown(&ir->input, &ir->ir, ircode & 0x3f, ircode); + ir_input_keydown(ir->input, &ir->ir, ircode & 0x3f, ircode); ir->release = jiffies + msecs_to_jiffies(120); break; } diff --git a/drivers/media/video/indycam.c b/drivers/media/video/indycam.c index b2b0384cd4b9..26dd06ec89a2 100644 --- a/drivers/media/video/indycam.c +++ b/drivers/media/video/indycam.c @@ -9,16 +9,16 @@ * published by the Free Software Foundation. */ -#include <linux/module.h> -#include <linux/init.h> #include <linux/delay.h> #include <linux/errno.h> #include <linux/fs.h> +#include <linux/init.h> #include <linux/kernel.h> #include <linux/major.h> -#include <linux/slab.h> +#include <linux/module.h> #include <linux/mm.h> #include <linux/sched.h> +#include <linux/slab.h> #include <linux/videodev.h> /* IndyCam decodes stream of photons into digital image representation ;-) */ @@ -44,8 +44,6 @@ MODULE_LICENSE("GPL"); #define indycam_regdump(client) #endif -#define VINO_ADAPTER (I2C_ALGO_SGI | I2C_HW_SGI_VINO) - struct indycam { struct i2c_client *client; int version; @@ -300,7 +298,7 @@ out_free_client: static int indycam_probe(struct i2c_adapter *adap) { /* Indy specific crap */ - if (adap->id == VINO_ADAPTER) + if (adap->id == I2C_HW_SGI_VINO) return indycam_attach(adap, INDYCAM_ADDR, 0); /* Feel free to add probe here :-) */ return -ENODEV; diff --git a/drivers/media/video/ir-kbd-gpio.c b/drivers/media/video/ir-kbd-gpio.c index cf292da8fdd5..234151e48edc 100644 --- a/drivers/media/video/ir-kbd-gpio.c +++ b/drivers/media/video/ir-kbd-gpio.c @@ -158,7 +158,7 @@ static IR_KEYTAB_TYPE ir_codes_apac_viewcomp[IR_KEYTAB_SIZE] = { struct IR { struct bttv_sub_device *sub; - struct input_dev input; + struct input_dev *input; struct ir_input_state ir; char name[32]; char phys[32]; @@ -217,23 +217,23 @@ static void ir_handle_key(struct IR *ir) if (ir->mask_keydown) { /* bit set on keydown */ if (gpio & ir->mask_keydown) { - ir_input_keydown(&ir->input,&ir->ir,data,data); + ir_input_keydown(ir->input, &ir->ir, data, data); } else { - ir_input_nokey(&ir->input,&ir->ir); + ir_input_nokey(ir->input, &ir->ir); } } else if (ir->mask_keyup) { /* bit cleared on keydown */ if (0 == (gpio & ir->mask_keyup)) { - ir_input_keydown(&ir->input,&ir->ir,data,data); + ir_input_keydown(ir->input, &ir->ir, data, data); } else { - ir_input_nokey(&ir->input,&ir->ir); + ir_input_nokey(ir->input, &ir->ir); } } else { /* can't disturgissh keydown/up :-/ */ - ir_input_keydown(&ir->input,&ir->ir,data,data); - ir_input_nokey(&ir->input,&ir->ir); + ir_input_keydown(ir->input, &ir->ir, data, data); + ir_input_nokey(ir->input, &ir->ir); } } @@ -268,13 +268,17 @@ static int ir_probe(struct device *dev) { struct bttv_sub_device *sub = to_bttv_sub_dev(dev); struct IR *ir; + struct input_dev *input_dev; IR_KEYTAB_TYPE *ir_codes = NULL; int ir_type = IR_TYPE_OTHER; - ir = kmalloc(sizeof(*ir),GFP_KERNEL); - if (NULL == ir) + ir = kzalloc(sizeof(*ir), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!ir || !input_dev) { + kfree(ir); + input_free_device(input_dev); return -ENOMEM; - memset(ir,0,sizeof(*ir)); + } /* detect & configure */ switch (sub->core->type) { @@ -328,6 +332,7 @@ static int ir_probe(struct device *dev) } if (NULL == ir_codes) { kfree(ir); + input_free_device(input_dev); return -ENODEV; } @@ -341,19 +346,19 @@ static int ir_probe(struct device *dev) snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", pci_name(sub->core->pci)); - ir_input_init(&ir->input, &ir->ir, ir_type, ir_codes); - ir->input.name = ir->name; - ir->input.phys = ir->phys; - ir->input.id.bustype = BUS_PCI; - ir->input.id.version = 1; + ir_input_init(input_dev, &ir->ir, ir_type, ir_codes); + input_dev->name = ir->name; + input_dev->phys = ir->phys; + input_dev->id.bustype = BUS_PCI; + input_dev->id.version = 1; if (sub->core->pci->subsystem_vendor) { - ir->input.id.vendor = sub->core->pci->subsystem_vendor; - ir->input.id.product = sub->core->pci->subsystem_device; + input_dev->id.vendor = sub->core->pci->subsystem_vendor; + input_dev->id.product = sub->core->pci->subsystem_device; } else { - ir->input.id.vendor = sub->core->pci->vendor; - ir->input.id.product = sub->core->pci->device; + input_dev->id.vendor = sub->core->pci->vendor; + input_dev->id.product = sub->core->pci->device; } - ir->input.dev = &sub->core->pci->dev; + input_dev->cdev.dev = &sub->core->pci->dev; if (ir->polling) { INIT_WORK(&ir->work, ir_work, ir); @@ -364,9 +369,8 @@ static int ir_probe(struct device *dev) } /* all done */ - dev_set_drvdata(dev,ir); - input_register_device(&ir->input); - printk(DEVNAME ": %s detected at %s\n",ir->input.name,ir->input.phys); + dev_set_drvdata(dev, ir); + input_register_device(ir->input); return 0; } @@ -380,7 +384,7 @@ static int ir_remove(struct device *dev) flush_scheduled_work(); } - input_unregister_device(&ir->input); + input_unregister_device(ir->input); kfree(ir); return 0; } diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c index 67105b9804a2..9703d3d351f9 100644 --- a/drivers/media/video/ir-kbd-i2c.c +++ b/drivers/media/video/ir-kbd-i2c.c @@ -121,10 +121,9 @@ static IR_KEYTAB_TYPE ir_codes_purpletv[IR_KEYTAB_SIZE] = { }; -struct IR; struct IR { struct i2c_client c; - struct input_dev input; + struct input_dev *input; struct ir_input_state ir; struct work_struct work; @@ -271,9 +270,9 @@ static void ir_key_poll(struct IR *ir) } if (0 == rc) { - ir_input_nokey(&ir->input,&ir->ir); + ir_input_nokey(ir->input, &ir->ir); } else { - ir_input_keydown(&ir->input,&ir->ir, ir_key, ir_raw); + ir_input_keydown(ir->input, &ir->ir, ir_key, ir_raw); } } @@ -318,11 +317,18 @@ static int ir_attach(struct i2c_adapter *adap, int addr, char *name; int ir_type; struct IR *ir; + struct input_dev *input_dev; - if (NULL == (ir = kmalloc(sizeof(struct IR),GFP_KERNEL))) + ir = kzalloc(sizeof(struct IR), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!ir || !input_dev) { + kfree(ir); + input_free_device(input_dev); return -ENOMEM; - memset(ir,0,sizeof(*ir)); + } + ir->c = client_template; + ir->input = input_dev; i2c_set_clientdata(&ir->c, ir); ir->c.adapter = adap; @@ -375,13 +381,12 @@ static int ir_attach(struct i2c_adapter *adap, int addr, ir->c.dev.bus_id); /* init + register input device */ - ir_input_init(&ir->input,&ir->ir,ir_type,ir_codes); - ir->input.id.bustype = BUS_I2C; - ir->input.name = ir->c.name; - ir->input.phys = ir->phys; - input_register_device(&ir->input); - printk(DEVNAME ": %s detected at %s [%s]\n", - ir->input.name,ir->input.phys,adap->name); + ir_input_init(input_dev, &ir->ir, ir_type, ir_codes); + input_dev->id.bustype = BUS_I2C; + input_dev->name = ir->c.name; + input_dev->phys = ir->phys; + + input_register_device(ir->input); /* start polling via eventd */ INIT_WORK(&ir->work, ir_work, ir); @@ -402,7 +407,7 @@ static int ir_detach(struct i2c_client *client) flush_scheduled_work(); /* unregister devices */ - input_unregister_device(&ir->input); + input_unregister_device(ir->input); i2c_detach_client(&ir->c); /* free memory */ diff --git a/drivers/media/video/msp3400.c b/drivers/media/video/msp3400.c index f0d43fc2632f..262890cb20a7 100644 --- a/drivers/media/video/msp3400.c +++ b/drivers/media/video/msp3400.c @@ -1420,8 +1420,8 @@ static int msp_detach(struct i2c_client *client); static int msp_probe(struct i2c_adapter *adap); static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg); -static int msp_suspend(struct device * dev, pm_message_t state, u32 level); -static int msp_resume(struct device * dev, u32 level); +static int msp_suspend(struct device * dev, pm_message_t state); +static int msp_resume(struct device * dev); static void msp_wake_thread(struct i2c_client *client); @@ -1821,7 +1821,7 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) return 0; } -static int msp_suspend(struct device * dev, pm_message_t state, u32 level) +static int msp_suspend(struct device * dev, pm_message_t state) { struct i2c_client *c = container_of(dev, struct i2c_client, dev); @@ -1830,7 +1830,7 @@ static int msp_suspend(struct device * dev, pm_message_t state, u32 level) return 0; } -static int msp_resume(struct device * dev, u32 level) +static int msp_resume(struct device * dev) { struct i2c_client *c = container_of(dev, struct i2c_client, dev); diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index 1f456c4d76f2..242cb235cf92 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c @@ -425,9 +425,9 @@ static int build_key(struct saa7134_dev *dev) if ((ir->mask_keydown && (0 != (gpio & ir->mask_keydown))) || (ir->mask_keyup && (0 == (gpio & ir->mask_keyup)))) { - ir_input_keydown(&ir->dev,&ir->ir,data,data); + ir_input_keydown(ir->dev, &ir->ir, data, data); } else { - ir_input_nokey(&ir->dev,&ir->ir); + ir_input_nokey(ir->dev, &ir->ir); } return 0; } @@ -456,6 +456,7 @@ static void saa7134_input_timer(unsigned long data) int saa7134_input_init1(struct saa7134_dev *dev) { struct saa7134_ir *ir; + struct input_dev *input_dev; IR_KEYTAB_TYPE *ir_codes = NULL; u32 mask_keycode = 0; u32 mask_keydown = 0; @@ -535,10 +536,13 @@ int saa7134_input_init1(struct saa7134_dev *dev) return -ENODEV; } - ir = kmalloc(sizeof(*ir),GFP_KERNEL); - if (NULL == ir) + ir = kzalloc(sizeof(*ir), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!ir || !input_dev) { + kfree(ir); + input_free_device(input_dev); return -ENOMEM; - memset(ir,0,sizeof(*ir)); + } /* init hardware-specific stuff */ ir->mask_keycode = mask_keycode; @@ -552,19 +556,19 @@ int saa7134_input_init1(struct saa7134_dev *dev) snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", pci_name(dev->pci)); - ir_input_init(&ir->dev, &ir->ir, ir_type, ir_codes); - ir->dev.name = ir->name; - ir->dev.phys = ir->phys; - ir->dev.id.bustype = BUS_PCI; - ir->dev.id.version = 1; + ir_input_init(input_dev, &ir->ir, ir_type, ir_codes); + input_dev->name = ir->name; + input_dev->phys = ir->phys; + input_dev->id.bustype = BUS_PCI; + input_dev->id.version = 1; if (dev->pci->subsystem_vendor) { - ir->dev.id.vendor = dev->pci->subsystem_vendor; - ir->dev.id.product = dev->pci->subsystem_device; + input_dev->id.vendor = dev->pci->subsystem_vendor; + input_dev->id.product = dev->pci->subsystem_device; } else { - ir->dev.id.vendor = dev->pci->vendor; - ir->dev.id.product = dev->pci->device; + input_dev->id.vendor = dev->pci->vendor; + input_dev->id.product = dev->pci->device; } - ir->dev.dev = &dev->pci->dev; + input_dev->cdev.dev = &dev->pci->dev; /* all done */ dev->remote = ir; @@ -576,8 +580,7 @@ int saa7134_input_init1(struct saa7134_dev *dev) add_timer(&ir->timer); } - input_register_device(&dev->remote->dev); - printk("%s: registered input device for IR\n",dev->name); + input_register_device(ir->dev); return 0; } @@ -586,9 +589,9 @@ void saa7134_input_fini(struct saa7134_dev *dev) if (NULL == dev->remote) return; - input_unregister_device(&dev->remote->dev); if (dev->remote->polling) del_timer_sync(&dev->remote->timer); + input_unregister_device(dev->remote->dev); kfree(dev->remote); dev->remote = NULL; } diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index 3ea09142ec9c..860b89530e2a 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -351,7 +351,7 @@ struct saa7134_oss { /* IR input */ struct saa7134_ir { - struct input_dev dev; + struct input_dev *dev; struct ir_input_state ir; char name[32]; char phys[32]; diff --git a/drivers/media/video/saa7191.c b/drivers/media/video/saa7191.c index 454f5c1199b4..3ddbb62312be 100644 --- a/drivers/media/video/saa7191.c +++ b/drivers/media/video/saa7191.c @@ -9,16 +9,16 @@ * published by the Free Software Foundation. */ -#include <linux/module.h> -#include <linux/init.h> #include <linux/delay.h> #include <linux/errno.h> #include <linux/fs.h> +#include <linux/init.h> #include <linux/kernel.h> #include <linux/major.h> -#include <linux/slab.h> +#include <linux/module.h> #include <linux/mm.h> #include <linux/sched.h> +#include <linux/slab.h> #include <linux/videodev.h> #include <linux/video_decoder.h> @@ -33,8 +33,6 @@ MODULE_VERSION(SAA7191_MODULE_VERSION); MODULE_AUTHOR("Mikael Nousiainen <tmnousia@cc.hut.fi>"); MODULE_LICENSE("GPL"); -#define VINO_ADAPTER (I2C_ALGO_SGI | I2C_HW_SGI_VINO) - struct saa7191 { struct i2c_client *client; @@ -337,7 +335,7 @@ out_free_client: static int saa7191_probe(struct i2c_adapter *adap) { /* Always connected to VINO */ - if (adap->id == VINO_ADAPTER) + if (adap->id == I2C_HW_SGI_VINO) return saa7191_attach(adap, SAA7191_ADDR, 0); /* Feel free to add probe here :-) */ return -ENODEV; @@ -364,7 +362,7 @@ static int saa7191_command(struct i2c_client *client, unsigned int cmd, cap->flags = VIDEO_DECODER_PAL | VIDEO_DECODER_NTSC | VIDEO_DECODER_SECAM | VIDEO_DECODER_AUTO; - cap->inputs = (client->adapter->id == VINO_ADAPTER) ? 2 : 1; + cap->inputs = (client->adapter->id == I2C_HW_SGI_VINO) ? 2 : 1; cap->outputs = 1; break; } @@ -422,7 +420,7 @@ static int saa7191_command(struct i2c_client *client, unsigned int cmd, int *iarg = arg; switch (client->adapter->id) { - case VINO_ADAPTER: + case I2C_HW_SGI_VINO: return saa7191_set_input(client, *iarg); default: if (*iarg != 0) diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c index 0456dda2624d..94053f149ddf 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/video/tda9887.c @@ -784,13 +784,13 @@ tda9887_command(struct i2c_client *client, unsigned int cmd, void *arg) return 0; } -static int tda9887_suspend(struct device * dev, pm_message_t state, u32 level) +static int tda9887_suspend(struct device * dev, pm_message_t state) { dprintk("tda9887: suspend\n"); return 0; } -static int tda9887_resume(struct device * dev, u32 level) +static int tda9887_resume(struct device * dev) { struct i2c_client *c = container_of(dev, struct i2c_client, dev); struct tda9887 *t = i2c_get_clientdata(c); diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 05572020af4d..ad85bef1c3d5 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -697,7 +697,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) return 0; } -static int tuner_suspend(struct device *dev, pm_message_t state, u32 level) +static int tuner_suspend(struct device *dev, pm_message_t state) { struct i2c_client *c = container_of (dev, struct i2c_client, dev); struct tuner *t = i2c_get_clientdata (c); @@ -707,7 +707,7 @@ static int tuner_suspend(struct device *dev, pm_message_t state, u32 level) return 0; } -static int tuner_resume(struct device *dev, u32 level) +static int tuner_resume(struct device *dev) { struct i2c_client *c = container_of (dev, struct i2c_client, dev); struct tuner *t = i2c_get_clientdata (c); diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c index d8a0f763ca10..ed4394e854ab 100644 --- a/drivers/media/video/vino.c +++ b/drivers/media/video/vino.c @@ -26,14 +26,15 @@ #include <linux/init.h> #include <linux/module.h> #include <linux/delay.h> +#include <linux/dma-mapping.h> #include <linux/errno.h> #include <linux/fs.h> +#include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/mm.h> -#include <linux/interrupt.h> -#include <linux/dma-mapping.h> -#include <linux/time.h> #include <linux/moduleparam.h> +#include <linux/time.h> +#include <linux/version.h> #ifdef CONFIG_KMOD #include <linux/kmod.h> diff --git a/drivers/message/i2o/core.h b/drivers/message/i2o/core.h index c5bcfd70f711..9eefedb16211 100644 --- a/drivers/message/i2o/core.h +++ b/drivers/message/i2o/core.h @@ -36,9 +36,6 @@ extern void __exit i2o_pci_exit(void); extern void i2o_device_remove(struct i2o_device *); extern int i2o_device_parse_lct(struct i2o_controller *); -extern int i2o_device_init(void); -extern void i2o_device_exit(void); - /* IOP */ extern struct i2o_controller *i2o_iop_alloc(void); extern void i2o_iop_free(struct i2o_controller *); diff --git a/drivers/message/i2o/debug.c b/drivers/message/i2o/debug.c index 018ca887ca85..40d4ea898dbc 100644 --- a/drivers/message/i2o/debug.c +++ b/drivers/message/i2o/debug.c @@ -90,7 +90,7 @@ static void i2o_report_fail_status(u8 req_status, u32 * msg) }; if (req_status == I2O_FSC_TRANSPORT_UNKNOWN_FAILURE) - printk(KERN_DEBUG "TRANSPORT_UNKNOWN_FAILURE (%0#2x)\n.", + printk(KERN_DEBUG "TRANSPORT_UNKNOWN_FAILURE (%0#2x).\n", req_status); else printk(KERN_DEBUG "TRANSPORT_%s.\n", diff --git a/drivers/message/i2o/device.c b/drivers/message/i2o/device.c index 21f16ba3ac38..8eb50cdb8ae1 100644 --- a/drivers/message/i2o/device.c +++ b/drivers/message/i2o/device.c @@ -16,6 +16,8 @@ #include <linux/module.h> #include <linux/i2o.h> #include <linux/delay.h> +#include <linux/string.h> +#include <linux/slab.h> #include "core.h" /** @@ -45,10 +47,10 @@ static inline int i2o_device_issue_claim(struct i2o_device *dev, u32 cmd, writel(type, &msg->body[0]); return i2o_msg_post_wait(dev->iop, m, 60); -}; +} /** - * i2o_device_claim - claim a device for use by an OSM + * i2o_device_claim - claim a device for use by an OSM * @dev: I2O device to claim * @drv: I2O driver which wants to claim the device * @@ -73,7 +75,7 @@ int i2o_device_claim(struct i2o_device *dev) up(&dev->lock); return rc; -}; +} /** * i2o_device_claim_release - release a device that the OSM is using @@ -119,7 +121,8 @@ int i2o_device_claim_release(struct i2o_device *dev) up(&dev->lock); return rc; -}; +} + /** * i2o_device_release - release the memory for a I2O device @@ -135,39 +138,47 @@ static void i2o_device_release(struct device *dev) pr_debug("i2o: device %s released\n", dev->bus_id); kfree(i2o_dev); -}; +} + /** - * i2o_device_class_release - Remove I2O device attributes - * @cd: I2O class device which is added to the I2O device class + * i2o_device_class_show_class_id - Displays class id of I2O device + * @cd: class device of which the class id should be displayed + * @buf: buffer into which the class id should be printed * - * Removes attributes from the I2O device again. Also search each device - * on the controller for I2O devices which refert to this device as parent - * or user and remove this links also. + * Returns the number of bytes which are printed into the buffer. */ -static void i2o_device_class_release(struct class_device *cd) +static ssize_t i2o_device_show_class_id(struct device *dev, + struct device_attribute *attr, + char *buf) { - struct i2o_device *i2o_dev, *tmp; - struct i2o_controller *c; + struct i2o_device *i2o_dev = to_i2o_device(dev); - i2o_dev = to_i2o_device(cd->dev); - c = i2o_dev->iop; + sprintf(buf, "0x%03x\n", i2o_dev->lct_data.class_id); + return strlen(buf) + 1; +} - sysfs_remove_link(&i2o_dev->device.kobj, "parent"); - sysfs_remove_link(&i2o_dev->device.kobj, "user"); +/** + * i2o_device_class_show_tid - Displays TID of I2O device + * @cd: class device of which the TID should be displayed + * @buf: buffer into which the class id should be printed + * + * Returns the number of bytes which are printed into the buffer. + */ +static ssize_t i2o_device_show_tid(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct i2o_device *i2o_dev = to_i2o_device(dev); - list_for_each_entry(tmp, &c->devices, list) { - if (tmp->lct_data.parent_tid == i2o_dev->lct_data.tid) - sysfs_remove_link(&tmp->device.kobj, "parent"); - if (tmp->lct_data.user_tid == i2o_dev->lct_data.tid) - sysfs_remove_link(&tmp->device.kobj, "user"); - } -}; + sprintf(buf, "0x%03x\n", i2o_dev->lct_data.tid); + return strlen(buf) + 1; +} -/* I2O device class */ -static struct class i2o_device_class = { - .name = "i2o_device", - .release = i2o_device_class_release +struct device_attribute i2o_device_attrs[] = { + __ATTR(class_id, S_IRUGO, i2o_device_show_class_id, NULL), + __ATTR(tid, S_IRUGO, i2o_device_show_tid, NULL), + __ATTR_NULL }; /** @@ -193,11 +204,69 @@ static struct i2o_device *i2o_device_alloc(void) dev->device.bus = &i2o_bus_type; dev->device.release = &i2o_device_release; - dev->classdev.class = &i2o_device_class; - dev->classdev.dev = &dev->device; return dev; -}; +} + +/** + * i2o_setup_sysfs_links - Adds attributes to the I2O device + * @cd: I2O class device which is added to the I2O device class + * + * This function get called when a I2O device is added to the class. It + * creates the attributes for each device and creates user/parent symlink + * if necessary. + * + * Returns 0 on success or negative error code on failure. + */ +static void i2o_setup_sysfs_links(struct i2o_device *i2o_dev) +{ + struct i2o_controller *c = i2o_dev->iop; + struct i2o_device *tmp; + + /* create user entries for this device */ + tmp = i2o_iop_find_device(i2o_dev->iop, i2o_dev->lct_data.user_tid); + if (tmp && tmp != i2o_dev) + sysfs_create_link(&i2o_dev->device.kobj, + &tmp->device.kobj, "user"); + + /* create user entries refering to this device */ + list_for_each_entry(tmp, &c->devices, list) + if (tmp->lct_data.user_tid == i2o_dev->lct_data.tid && + tmp != i2o_dev) + sysfs_create_link(&tmp->device.kobj, + &i2o_dev->device.kobj, "user"); + + /* create parent entries for this device */ + tmp = i2o_iop_find_device(i2o_dev->iop, i2o_dev->lct_data.parent_tid); + if (tmp && tmp != i2o_dev) + sysfs_create_link(&i2o_dev->device.kobj, + &tmp->device.kobj, "parent"); + + /* create parent entries refering to this device */ + list_for_each_entry(tmp, &c->devices, list) + if (tmp->lct_data.parent_tid == i2o_dev->lct_data.tid && + tmp != i2o_dev) + sysfs_create_link(&tmp->device.kobj, + &i2o_dev->device.kobj, "parent"); +} + +static void i2o_remove_sysfs_links(struct i2o_device *i2o_dev) +{ + struct i2o_controller *c = i2o_dev->iop; + struct i2o_device *tmp; + + sysfs_remove_link(&i2o_dev->device.kobj, "parent"); + sysfs_remove_link(&i2o_dev->device.kobj, "user"); + + list_for_each_entry(tmp, &c->devices, list) { + if (tmp->lct_data.parent_tid == i2o_dev->lct_data.tid) + sysfs_remove_link(&tmp->device.kobj, "parent"); + if (tmp->lct_data.user_tid == i2o_dev->lct_data.tid) + sysfs_remove_link(&tmp->device.kobj, "user"); + } +} + + /** * i2o_device_add - allocate a new I2O device and add it to the IOP @@ -222,28 +291,25 @@ static struct i2o_device *i2o_device_add(struct i2o_controller *c, } dev->lct_data = *entry; + dev->iop = c; snprintf(dev->device.bus_id, BUS_ID_SIZE, "%d:%03x", c->unit, dev->lct_data.tid); - snprintf(dev->classdev.class_id, BUS_ID_SIZE, "%d:%03x", c->unit, - dev->lct_data.tid); - - dev->iop = c; dev->device.parent = &c->device; device_register(&dev->device); list_add_tail(&dev->list, &c->devices); - class_device_register(&dev->classdev); + i2o_setup_sysfs_links(dev); i2o_driver_notify_device_add_all(dev); pr_debug("i2o: device %s added\n", dev->device.bus_id); return dev; -}; +} /** * i2o_device_remove - remove an I2O device from the I2O core @@ -256,10 +322,10 @@ static struct i2o_device *i2o_device_add(struct i2o_controller *c, void i2o_device_remove(struct i2o_device *i2o_dev) { i2o_driver_notify_device_remove_all(i2o_dev); - class_device_unregister(&i2o_dev->classdev); + i2o_remove_sysfs_links(i2o_dev); list_del(&i2o_dev->list); device_unregister(&i2o_dev->device); -}; +} /** * i2o_device_parse_lct - Parse a previously fetched LCT and create devices @@ -337,99 +403,8 @@ int i2o_device_parse_lct(struct i2o_controller *c) up(&c->lct_lock); return 0; -}; - -/** - * i2o_device_class_show_class_id - Displays class id of I2O device - * @cd: class device of which the class id should be displayed - * @buf: buffer into which the class id should be printed - * - * Returns the number of bytes which are printed into the buffer. - */ -static ssize_t i2o_device_class_show_class_id(struct class_device *cd, - char *buf) -{ - struct i2o_device *dev = to_i2o_device(cd->dev); - - sprintf(buf, "0x%03x\n", dev->lct_data.class_id); - return strlen(buf) + 1; -}; - -/** - * i2o_device_class_show_tid - Displays TID of I2O device - * @cd: class device of which the TID should be displayed - * @buf: buffer into which the class id should be printed - * - * Returns the number of bytes which are printed into the buffer. - */ -static ssize_t i2o_device_class_show_tid(struct class_device *cd, char *buf) -{ - struct i2o_device *dev = to_i2o_device(cd->dev); - - sprintf(buf, "0x%03x\n", dev->lct_data.tid); - return strlen(buf) + 1; -}; - -/* I2O device class attributes */ -static CLASS_DEVICE_ATTR(class_id, S_IRUGO, i2o_device_class_show_class_id, - NULL); -static CLASS_DEVICE_ATTR(tid, S_IRUGO, i2o_device_class_show_tid, NULL); - -/** - * i2o_device_class_add - Adds attributes to the I2O device - * @cd: I2O class device which is added to the I2O device class - * - * This function get called when a I2O device is added to the class. It - * creates the attributes for each device and creates user/parent symlink - * if necessary. - * - * Returns 0 on success or negative error code on failure. - */ -static int i2o_device_class_add(struct class_device *cd) -{ - struct i2o_device *i2o_dev, *tmp; - struct i2o_controller *c; - - i2o_dev = to_i2o_device(cd->dev); - c = i2o_dev->iop; - - class_device_create_file(cd, &class_device_attr_class_id); - class_device_create_file(cd, &class_device_attr_tid); - - /* create user entries for this device */ - tmp = i2o_iop_find_device(i2o_dev->iop, i2o_dev->lct_data.user_tid); - if (tmp && (tmp != i2o_dev)) - sysfs_create_link(&i2o_dev->device.kobj, &tmp->device.kobj, - "user"); - - /* create user entries refering to this device */ - list_for_each_entry(tmp, &c->devices, list) - if ((tmp->lct_data.user_tid == i2o_dev->lct_data.tid) - && (tmp != i2o_dev)) - sysfs_create_link(&tmp->device.kobj, - &i2o_dev->device.kobj, "user"); - - /* create parent entries for this device */ - tmp = i2o_iop_find_device(i2o_dev->iop, i2o_dev->lct_data.parent_tid); - if (tmp && (tmp != i2o_dev)) - sysfs_create_link(&i2o_dev->device.kobj, &tmp->device.kobj, - "parent"); - - /* create parent entries refering to this device */ - list_for_each_entry(tmp, &c->devices, list) - if ((tmp->lct_data.parent_tid == i2o_dev->lct_data.tid) - && (tmp != i2o_dev)) - sysfs_create_link(&tmp->device.kobj, - &i2o_dev->device.kobj, "parent"); - - return 0; -}; +} -/* I2O device class interface */ -static struct class_interface i2o_device_class_interface = { - .class = &i2o_device_class, - .add = i2o_device_class_add -}; /* * Run time support routines @@ -553,11 +528,11 @@ int i2o_parm_field_get(struct i2o_device *i2o_dev, int group, int field, } /* - * if oper == I2O_PARAMS_TABLE_GET, get from all rows - * if fieldcount == -1 return all fields + * if oper == I2O_PARAMS_TABLE_GET, get from all rows + * if fieldcount == -1 return all fields * ibuf and ibuflen are unused (use NULL, 0) - * else return specific fields - * ibuf contains fieldindexes + * else return specific fields + * ibuf contains fieldindexes * * if oper == I2O_PARAMS_LIST_GET, get from specific rows * if fieldcount == -1 return all fields @@ -602,35 +577,6 @@ int i2o_parm_table_get(struct i2o_device *dev, int oper, int group, return size; } -/** - * i2o_device_init - Initialize I2O devices - * - * Registers the I2O device class. - * - * Returns 0 on success or negative error code on failure. - */ -int i2o_device_init(void) -{ - int rc; - - rc = class_register(&i2o_device_class); - if (rc) - return rc; - - return class_interface_register(&i2o_device_class_interface); -}; - -/** - * i2o_device_exit - I2O devices exit function - * - * Unregisters the I2O device class. - */ -void i2o_device_exit(void) -{ - class_interface_register(&i2o_device_class_interface); - class_unregister(&i2o_device_class); -}; - EXPORT_SYMBOL(i2o_device_claim); EXPORT_SYMBOL(i2o_device_claim_release); EXPORT_SYMBOL(i2o_parm_field_get); diff --git a/drivers/message/i2o/driver.c b/drivers/message/i2o/driver.c index 739bfdef0c6d..0fb9c4e2ad4c 100644 --- a/drivers/message/i2o/driver.c +++ b/drivers/message/i2o/driver.c @@ -17,6 +17,9 @@ #include <linux/module.h> #include <linux/rwsem.h> #include <linux/i2o.h> +#include <linux/workqueue.h> +#include <linux/string.h> +#include <linux/slab.h> #include "core.h" #define OSM_NAME "i2o" @@ -58,9 +61,12 @@ static int i2o_bus_match(struct device *dev, struct device_driver *drv) }; /* I2O bus type */ +extern struct device_attribute i2o_device_attrs[]; + struct bus_type i2o_bus_type = { .name = "i2o", .match = i2o_bus_match, + .dev_attrs = i2o_device_attrs, }; /** diff --git a/drivers/message/i2o/exec-osm.c b/drivers/message/i2o/exec-osm.c index bda2c62648ba..b675b4ebbebd 100644 --- a/drivers/message/i2o/exec-osm.c +++ b/drivers/message/i2o/exec-osm.c @@ -30,6 +30,10 @@ #include <linux/module.h> #include <linux/i2o.h> #include <linux/delay.h> +#include <linux/workqueue.h> +#include <linux/string.h> +#include <linux/slab.h> +#include <asm/param.h> /* HZ */ #include "core.h" #define OSM_NAME "exec-osm" diff --git a/drivers/message/i2o/iop.c b/drivers/message/i2o/iop.c index 42f8b810d6e5..61b837de4b6a 100644 --- a/drivers/message/i2o/iop.c +++ b/drivers/message/i2o/iop.c @@ -28,6 +28,7 @@ #include <linux/module.h> #include <linux/i2o.h> #include <linux/delay.h> +#include <linux/sched.h> #include "core.h" #define OSM_NAME "i2o" @@ -833,6 +834,7 @@ void i2o_iop_remove(struct i2o_controller *c) list_for_each_entry_safe(dev, tmp, &c->devices, list) i2o_device_remove(dev); + class_device_unregister(c->classdev); device_del(&c->device); /* Ask the IOP to switch to RESET state */ @@ -1077,9 +1079,7 @@ static void i2o_iop_release(struct device *dev) }; /* I2O controller class */ -static struct class i2o_controller_class = { - .name = "i2o_controller", -}; +static struct class *i2o_controller_class; /** * i2o_iop_alloc - Allocate and initialize a i2o_controller struct @@ -1110,14 +1110,10 @@ struct i2o_controller *i2o_iop_alloc(void) sprintf(c->name, "iop%d", c->unit); device_initialize(&c->device); - class_device_initialize(&c->classdev); c->device.release = &i2o_iop_release; - c->classdev.class = &i2o_controller_class; - c->classdev.dev = &c->device; snprintf(c->device.bus_id, BUS_ID_SIZE, "iop%d", c->unit); - snprintf(c->classdev.class_id, BUS_ID_SIZE, "iop%d", c->unit); #if BITS_PER_LONG == 64 spin_lock_init(&c->context_list_lock); @@ -1146,7 +1142,9 @@ int i2o_iop_add(struct i2o_controller *c) goto iop_reset; } - if ((rc = class_device_add(&c->classdev))) { + c->classdev = class_device_create(i2o_controller_class, NULL, MKDEV(0,0), + &c->device, "iop%d", c->unit); + if (IS_ERR(c->classdev)) { osm_err("%s: could not add controller class\n", c->name); goto device_del; } @@ -1184,7 +1182,7 @@ int i2o_iop_add(struct i2o_controller *c) return 0; class_del: - class_device_del(&c->classdev); + class_device_unregister(c->classdev); device_del: device_del(&c->device); @@ -1246,13 +1244,10 @@ static int __init i2o_iop_init(void) printk(KERN_INFO OSM_DESCRIPTION " v" OSM_VERSION "\n"); - rc = i2o_device_init(); - if (rc) - goto exit; - - if ((rc = class_register(&i2o_controller_class))) { + i2o_controller_class = class_create(THIS_MODULE, "i2o_controller"); + if (IS_ERR(i2o_controller_class)) { osm_err("can't register class i2o_controller\n"); - goto device_exit; + goto exit; } if ((rc = i2o_driver_init())) @@ -1273,10 +1268,7 @@ static int __init i2o_iop_init(void) i2o_driver_exit(); class_exit: - class_unregister(&i2o_controller_class); - - device_exit: - i2o_device_exit(); + class_destroy(i2o_controller_class); exit: return rc; @@ -1292,8 +1284,7 @@ static void __exit i2o_iop_exit(void) i2o_pci_exit(); i2o_exec_exit(); i2o_driver_exit(); - class_unregister(&i2o_controller_class); - i2o_device_exit(); + class_destroy(i2o_controller_class); }; module_init(i2o_iop_init); diff --git a/drivers/mfd/mcp-sa11x0.c b/drivers/mfd/mcp-sa11x0.c index e9806fbbe696..720e7a326308 100644 --- a/drivers/mfd/mcp-sa11x0.c +++ b/drivers/mfd/mcp-sa11x0.c @@ -219,26 +219,24 @@ static int mcp_sa11x0_remove(struct device *dev) return 0; } -static int mcp_sa11x0_suspend(struct device *dev, pm_message_t state, u32 level) +static int mcp_sa11x0_suspend(struct device *dev, pm_message_t state) { struct mcp *mcp = dev_get_drvdata(dev); - if (level == SUSPEND_DISABLE) { - priv(mcp)->mccr0 = Ser4MCCR0; - priv(mcp)->mccr1 = Ser4MCCR1; - Ser4MCCR0 &= ~MCCR0_MCE; - } + priv(mcp)->mccr0 = Ser4MCCR0; + priv(mcp)->mccr1 = Ser4MCCR1; + Ser4MCCR0 &= ~MCCR0_MCE; + return 0; } -static int mcp_sa11x0_resume(struct device *dev, u32 level) +static int mcp_sa11x0_resume(struct device *dev) { struct mcp *mcp = dev_get_drvdata(dev); - if (level == RESUME_RESTORE_STATE) { - Ser4MCCR1 = priv(mcp)->mccr1; - Ser4MCCR0 = priv(mcp)->mccr0; - } + Ser4MCCR1 = priv(mcp)->mccr1; + Ser4MCCR0 = priv(mcp)->mccr0; + return 0; } diff --git a/drivers/mfd/ucb1x00-ts.c b/drivers/mfd/ucb1x00-ts.c index a260f83bcb02..a984c0efabf0 100644 --- a/drivers/mfd/ucb1x00-ts.c +++ b/drivers/mfd/ucb1x00-ts.c @@ -32,15 +32,18 @@ #include <linux/suspend.h> #include <linux/slab.h> #include <linux/kthread.h> +#include <linux/delay.h> #include <asm/dma.h> #include <asm/semaphore.h> +#include <asm/arch/collie.h> +#include <asm/mach-types.h> #include "ucb1x00.h" struct ucb1x00_ts { - struct input_dev idev; + struct input_dev *idev; struct ucb1x00 *ucb; wait_queue_head_t irq_wait; @@ -56,16 +59,16 @@ static int adcsync; static inline void ucb1x00_ts_evt_add(struct ucb1x00_ts *ts, u16 pressure, u16 x, u16 y) { - input_report_abs(&ts->idev, ABS_X, x); - input_report_abs(&ts->idev, ABS_Y, y); - input_report_abs(&ts->idev, ABS_PRESSURE, pressure); - input_sync(&ts->idev); + input_report_abs(ts->idev, ABS_X, x); + input_report_abs(ts->idev, ABS_Y, y); + input_report_abs(ts->idev, ABS_PRESSURE, pressure); + input_sync(ts->idev); } static inline void ucb1x00_ts_event_release(struct ucb1x00_ts *ts) { - input_report_abs(&ts->idev, ABS_PRESSURE, 0); - input_sync(&ts->idev); + input_report_abs(ts->idev, ABS_PRESSURE, 0); + input_sync(ts->idev); } /* @@ -85,12 +88,23 @@ static inline void ucb1x00_ts_mode_int(struct ucb1x00_ts *ts) */ static inline unsigned int ucb1x00_ts_read_pressure(struct ucb1x00_ts *ts) { - ucb1x00_reg_write(ts->ucb, UCB_TS_CR, - UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW | - UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND | - UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); + if (machine_is_collie()) { + ucb1x00_io_write(ts->ucb, COLLIE_TC35143_GPIO_TBL_CHK, 0); + ucb1x00_reg_write(ts->ucb, UCB_TS_CR, + UCB_TS_CR_TSPX_POW | UCB_TS_CR_TSMX_POW | + UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA); - return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPY, ts->adcsync); + udelay(55); + + return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_AD2, ts->adcsync); + } else { + ucb1x00_reg_write(ts->ucb, UCB_TS_CR, + UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW | + UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND | + UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); + + return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPY, ts->adcsync); + } } /* @@ -101,12 +115,16 @@ static inline unsigned int ucb1x00_ts_read_pressure(struct ucb1x00_ts *ts) */ static inline unsigned int ucb1x00_ts_read_xpos(struct ucb1x00_ts *ts) { - ucb1x00_reg_write(ts->ucb, UCB_TS_CR, - UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW | - UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); - ucb1x00_reg_write(ts->ucb, UCB_TS_CR, - UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW | - UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); + if (machine_is_collie()) + ucb1x00_io_write(ts->ucb, 0, COLLIE_TC35143_GPIO_TBL_CHK); + else { + ucb1x00_reg_write(ts->ucb, UCB_TS_CR, + UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW | + UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); + ucb1x00_reg_write(ts->ucb, UCB_TS_CR, + UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW | + UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); + } ucb1x00_reg_write(ts->ucb, UCB_TS_CR, UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW | UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA); @@ -124,12 +142,17 @@ static inline unsigned int ucb1x00_ts_read_xpos(struct ucb1x00_ts *ts) */ static inline unsigned int ucb1x00_ts_read_ypos(struct ucb1x00_ts *ts) { - ucb1x00_reg_write(ts->ucb, UCB_TS_CR, - UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW | - UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); - ucb1x00_reg_write(ts->ucb, UCB_TS_CR, - UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW | - UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); + if (machine_is_collie()) + ucb1x00_io_write(ts->ucb, 0, COLLIE_TC35143_GPIO_TBL_CHK); + else { + ucb1x00_reg_write(ts->ucb, UCB_TS_CR, + UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW | + UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); + ucb1x00_reg_write(ts->ucb, UCB_TS_CR, + UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW | + UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); + } + ucb1x00_reg_write(ts->ucb, UCB_TS_CR, UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW | UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA); @@ -163,6 +186,15 @@ static inline unsigned int ucb1x00_ts_read_yres(struct ucb1x00_ts *ts) return ucb1x00_adc_read(ts->ucb, 0, ts->adcsync); } +static inline int ucb1x00_ts_pen_down(struct ucb1x00_ts *ts) +{ + unsigned int val = ucb1x00_reg_read(ts->ucb, UCB_TS_CR); + if (machine_is_collie()) + return (!(val & (UCB_TS_CR_TSPX_LOW))); + else + return (val & (UCB_TS_CR_TSPX_LOW | UCB_TS_CR_TSMX_LOW)); +} + /* * This is a RT kernel thread that handles the ADC accesses * (mainly so we can use semaphores in the UCB1200 core code @@ -186,7 +218,7 @@ static int ucb1x00_thread(void *_ts) add_wait_queue(&ts->irq_wait, &wait); while (!kthread_should_stop()) { - unsigned int x, y, p, val; + unsigned int x, y, p; signed long timeout; ts->restart = 0; @@ -206,12 +238,12 @@ static int ucb1x00_thread(void *_ts) msleep(10); ucb1x00_enable(ts->ucb); - val = ucb1x00_reg_read(ts->ucb, UCB_TS_CR); - if (val & (UCB_TS_CR_TSPX_LOW | UCB_TS_CR_TSMX_LOW)) { + + if (ucb1x00_ts_pen_down(ts)) { set_task_state(tsk, TASK_INTERRUPTIBLE); - ucb1x00_enable_irq(ts->ucb, UCB_IRQ_TSPX, UCB_FALLING); + ucb1x00_enable_irq(ts->ucb, UCB_IRQ_TSPX, machine_is_collie() ? UCB_RISING : UCB_FALLING); ucb1x00_disable(ts->ucb); /* @@ -341,26 +373,30 @@ static int ucb1x00_ts_add(struct ucb1x00_dev *dev) { struct ucb1x00_ts *ts; - ts = kmalloc(sizeof(struct ucb1x00_ts), GFP_KERNEL); + ts = kzalloc(sizeof(struct ucb1x00_ts), GFP_KERNEL); if (!ts) return -ENOMEM; - memset(ts, 0, sizeof(struct ucb1x00_ts)); + ts->idev = input_allocate_device(); + if (!ts->idev) { + kfree(ts); + return -ENOMEM; + } ts->ucb = dev->ucb; ts->adcsync = adcsync ? UCB_SYNC : UCB_NOSYNC; - ts->idev.name = "Touchscreen panel"; - ts->idev.id.product = ts->ucb->id; - ts->idev.open = ucb1x00_ts_open; - ts->idev.close = ucb1x00_ts_close; + ts->idev->name = "Touchscreen panel"; + ts->idev->id.product = ts->ucb->id; + ts->idev->open = ucb1x00_ts_open; + ts->idev->close = ucb1x00_ts_close; - __set_bit(EV_ABS, ts->idev.evbit); - __set_bit(ABS_X, ts->idev.absbit); - __set_bit(ABS_Y, ts->idev.absbit); - __set_bit(ABS_PRESSURE, ts->idev.absbit); + __set_bit(EV_ABS, ts->idev->evbit); + __set_bit(ABS_X, ts->idev->absbit); + __set_bit(ABS_Y, ts->idev->absbit); + __set_bit(ABS_PRESSURE, ts->idev->absbit); - input_register_device(&ts->idev); + input_register_device(ts->idev); dev->priv = ts; @@ -370,7 +406,8 @@ static int ucb1x00_ts_add(struct ucb1x00_dev *dev) static void ucb1x00_ts_remove(struct ucb1x00_dev *dev) { struct ucb1x00_ts *ts = dev->priv; - input_unregister_device(&ts->idev); + + input_unregister_device(ts->idev); kfree(ts); } diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 4991bbd054f3..c483a863b116 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -60,4 +60,13 @@ config MMC_WBSD If unsure, say N. +config MMC_AU1X + tristate "Alchemy AU1XX0 MMC Card Interface support" + depends on SOC_AU1X00 && MMC + help + This selects the AMD Alchemy(R) Multimedia card interface. + iIf you have a Alchemy platform with a MMC slot, say Y or M here. + + If unsure, say N. + endmenu diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index 89510c2086c7..e351e71146e9 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -18,5 +18,6 @@ obj-$(CONFIG_MMC_BLOCK) += mmc_block.o obj-$(CONFIG_MMC_ARMMMCI) += mmci.o obj-$(CONFIG_MMC_PXA) += pxamci.o obj-$(CONFIG_MMC_WBSD) += wbsd.o +obj-$(CONFIG_MMC_AU1X) += au1xmmc.o mmc_core-y := mmc.o mmc_queue.o mmc_sysfs.o diff --git a/drivers/mmc/au1xmmc.c b/drivers/mmc/au1xmmc.c new file mode 100644 index 000000000000..aaf04638054e --- /dev/null +++ b/drivers/mmc/au1xmmc.c @@ -0,0 +1,1026 @@ +/* + * linux/drivers/mmc/au1xmmc.c - AU1XX0 MMC driver + * + * Copyright (c) 2005, Advanced Micro Devices, Inc. + * + * Developed with help from the 2.4.30 MMC AU1XXX controller including + * the following copyright notices: + * Copyright (c) 2003-2004 Embedded Edge, LLC. + * Portions Copyright (C) 2002 Embedix, Inc + * Copyright 2002 Hewlett-Packard Company + + * 2.6 version of this driver inspired by: + * (drivers/mmc/wbsd.c) Copyright (C) 2004-2005 Pierre Ossman, + * All Rights Reserved. + * (drivers/mmc/pxa.c) Copyright (C) 2003 Russell King, + * All Rights Reserved. + * + + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* Why is a timer used to detect insert events? + * + * From the AU1100 MMC application guide: + * If the Au1100-based design is intended to support both MultiMediaCards + * and 1- or 4-data bit SecureDigital cards, then the solution is to + * connect a weak (560KOhm) pull-up resistor to connector pin 1. + * In doing so, a MMC card never enters SPI-mode communications, + * but now the SecureDigital card-detect feature of CD/DAT3 is ineffective + * (the low to high transition will not occur). + * + * So we use the timer to check the status manually. + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/mm.h> +#include <linux/interrupt.h> +#include <linux/dma-mapping.h> + +#include <linux/mmc/host.h> +#include <linux/mmc/protocol.h> +#include <asm/io.h> +#include <asm/mach-au1x00/au1000.h> +#include <asm/mach-au1x00/au1xxx_dbdma.h> +#include <asm/mach-au1x00/au1100_mmc.h> +#include <asm/scatterlist.h> + +#include <au1xxx.h> +#include "au1xmmc.h" + +#define DRIVER_NAME "au1xxx-mmc" + +/* Set this to enable special debugging macros */ +/* #define MMC_DEBUG */ + +#ifdef MMC_DEBUG +#define DEBUG(fmt, idx, args...) printk("au1xx(%d): DEBUG: " fmt, idx, ##args) +#else +#define DEBUG(fmt, idx, args...) +#endif + +const struct { + u32 iobase; + u32 tx_devid, rx_devid; + u16 bcsrpwr; + u16 bcsrstatus; + u16 wpstatus; +} au1xmmc_card_table[] = { + { SD0_BASE, DSCR_CMD0_SDMS_TX0, DSCR_CMD0_SDMS_RX0, + BCSR_BOARD_SD0PWR, BCSR_INT_SD0INSERT, BCSR_STATUS_SD0WP }, +#ifndef CONFIG_MIPS_DB1200 + { SD1_BASE, DSCR_CMD0_SDMS_TX1, DSCR_CMD0_SDMS_RX1, + BCSR_BOARD_DS1PWR, BCSR_INT_SD1INSERT, BCSR_STATUS_SD1WP } +#endif +}; + +#define AU1XMMC_CONTROLLER_COUNT \ + (sizeof(au1xmmc_card_table) / sizeof(au1xmmc_card_table[0])) + +/* This array stores pointers for the hosts (used by the IRQ handler) */ +struct au1xmmc_host *au1xmmc_hosts[AU1XMMC_CONTROLLER_COUNT]; +static int dma = 1; + +#ifdef MODULE +MODULE_PARM(dma, "i"); +MODULE_PARM_DESC(dma, "Use DMA engine for data transfers (0 = disabled)"); +#endif + +static inline void IRQ_ON(struct au1xmmc_host *host, u32 mask) +{ + u32 val = au_readl(HOST_CONFIG(host)); + val |= mask; + au_writel(val, HOST_CONFIG(host)); + au_sync(); +} + +static inline void FLUSH_FIFO(struct au1xmmc_host *host) +{ + u32 val = au_readl(HOST_CONFIG2(host)); + + au_writel(val | SD_CONFIG2_FF, HOST_CONFIG2(host)); + au_sync_delay(1); + + /* SEND_STOP will turn off clock control - this re-enables it */ + val &= ~SD_CONFIG2_DF; + + au_writel(val, HOST_CONFIG2(host)); + au_sync(); +} + +static inline void IRQ_OFF(struct au1xmmc_host *host, u32 mask) +{ + u32 val = au_readl(HOST_CONFIG(host)); + val &= ~mask; + au_writel(val, HOST_CONFIG(host)); + au_sync(); +} + +static inline void SEND_STOP(struct au1xmmc_host *host) +{ + + /* We know the value of CONFIG2, so avoid a read we don't need */ + u32 mask = SD_CONFIG2_EN; + + WARN_ON(host->status != HOST_S_DATA); + host->status = HOST_S_STOP; + + au_writel(mask | SD_CONFIG2_DF, HOST_CONFIG2(host)); + au_sync(); + + /* Send the stop commmand */ + au_writel(STOP_CMD, HOST_CMD(host)); +} + +static void au1xmmc_set_power(struct au1xmmc_host *host, int state) +{ + + u32 val = au1xmmc_card_table[host->id].bcsrpwr; + + bcsr->board &= ~val; + if (state) bcsr->board |= val; + + au_sync_delay(1); +} + +static inline int au1xmmc_card_inserted(struct au1xmmc_host *host) +{ + return (bcsr->sig_status & au1xmmc_card_table[host->id].bcsrstatus) + ? 1 : 0; +} + +static inline int au1xmmc_card_readonly(struct au1xmmc_host *host) +{ + return (bcsr->status & au1xmmc_card_table[host->id].wpstatus) + ? 1 : 0; +} + +static void au1xmmc_finish_request(struct au1xmmc_host *host) +{ + + struct mmc_request *mrq = host->mrq; + + host->mrq = NULL; + host->flags &= HOST_F_ACTIVE; + + host->dma.len = 0; + host->dma.dir = 0; + + host->pio.index = 0; + host->pio.offset = 0; + host->pio.len = 0; + + host->status = HOST_S_IDLE; + + bcsr->disk_leds |= (1 << 8); + + mmc_request_done(host->mmc, mrq); +} + +static void au1xmmc_tasklet_finish(unsigned long param) +{ + struct au1xmmc_host *host = (struct au1xmmc_host *) param; + au1xmmc_finish_request(host); +} + +static int au1xmmc_send_command(struct au1xmmc_host *host, int wait, + struct mmc_command *cmd) +{ + + u32 mmccmd = (cmd->opcode << SD_CMD_CI_SHIFT); + + switch(cmd->flags) { + case MMC_RSP_R1: + mmccmd |= SD_CMD_RT_1; + break; + case MMC_RSP_R1B: + mmccmd |= SD_CMD_RT_1B; + break; + case MMC_RSP_R2: + mmccmd |= SD_CMD_RT_2; + break; + case MMC_RSP_R3: + mmccmd |= SD_CMD_RT_3; + break; + } + + switch(cmd->opcode) { + case MMC_READ_SINGLE_BLOCK: + case SD_APP_SEND_SCR: + mmccmd |= SD_CMD_CT_2; + break; + case MMC_READ_MULTIPLE_BLOCK: + mmccmd |= SD_CMD_CT_4; + break; + case MMC_WRITE_BLOCK: + mmccmd |= SD_CMD_CT_1; + break; + + case MMC_WRITE_MULTIPLE_BLOCK: + mmccmd |= SD_CMD_CT_3; + break; + case MMC_STOP_TRANSMISSION: + mmccmd |= SD_CMD_CT_7; + break; + } + + au_writel(cmd->arg, HOST_CMDARG(host)); + au_sync(); + + if (wait) + IRQ_OFF(host, SD_CONFIG_CR); + + au_writel((mmccmd | SD_CMD_GO), HOST_CMD(host)); + au_sync(); + + /* Wait for the command to go on the line */ + + while(1) { + if (!(au_readl(HOST_CMD(host)) & SD_CMD_GO)) + break; + } + + /* Wait for the command to come back */ + + if (wait) { + u32 status = au_readl(HOST_STATUS(host)); + + while(!(status & SD_STATUS_CR)) + status = au_readl(HOST_STATUS(host)); + + /* Clear the CR status */ + au_writel(SD_STATUS_CR, HOST_STATUS(host)); + + IRQ_ON(host, SD_CONFIG_CR); + } + + return MMC_ERR_NONE; +} + +static void au1xmmc_data_complete(struct au1xmmc_host *host, u32 status) +{ + + struct mmc_request *mrq = host->mrq; + struct mmc_data *data; + u32 crc; + + WARN_ON(host->status != HOST_S_DATA && host->status != HOST_S_STOP); + + if (host->mrq == NULL) + return; + + data = mrq->cmd->data; + + if (status == 0) + status = au_readl(HOST_STATUS(host)); + + /* The transaction is really over when the SD_STATUS_DB bit is clear */ + + while((host->flags & HOST_F_XMIT) && (status & SD_STATUS_DB)) + status = au_readl(HOST_STATUS(host)); + + data->error = MMC_ERR_NONE; + dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, host->dma.dir); + + /* Process any errors */ + + crc = (status & (SD_STATUS_WC | SD_STATUS_RC)); + if (host->flags & HOST_F_XMIT) + crc |= ((status & 0x07) == 0x02) ? 0 : 1; + + if (crc) + data->error = MMC_ERR_BADCRC; + + /* Clear the CRC bits */ + au_writel(SD_STATUS_WC | SD_STATUS_RC, HOST_STATUS(host)); + + data->bytes_xfered = 0; + + if (data->error == MMC_ERR_NONE) { + if (host->flags & HOST_F_DMA) { + u32 chan = DMA_CHANNEL(host); + + chan_tab_t *c = *((chan_tab_t **) chan); + au1x_dma_chan_t *cp = c->chan_ptr; + data->bytes_xfered = cp->ddma_bytecnt; + } + else + data->bytes_xfered = + (data->blocks * (1 << data->blksz_bits)) - + host->pio.len; + } + + au1xmmc_finish_request(host); +} + +static void au1xmmc_tasklet_data(unsigned long param) +{ + struct au1xmmc_host *host = (struct au1xmmc_host *) param; + + u32 status = au_readl(HOST_STATUS(host)); + au1xmmc_data_complete(host, status); +} + +#define AU1XMMC_MAX_TRANSFER 8 + +static void au1xmmc_send_pio(struct au1xmmc_host *host) +{ + + struct mmc_data *data = 0; + int sg_len, max, count = 0; + unsigned char *sg_ptr; + u32 status = 0; + struct scatterlist *sg; + + data = host->mrq->data; + + if (!(host->flags & HOST_F_XMIT)) + return; + + /* This is the pointer to the data buffer */ + sg = &data->sg[host->pio.index]; + sg_ptr = page_address(sg->page) + sg->offset + host->pio.offset; + + /* This is the space left inside the buffer */ + sg_len = data->sg[host->pio.index].length - host->pio.offset; + + /* Check to if we need less then the size of the sg_buffer */ + + max = (sg_len > host->pio.len) ? host->pio.len : sg_len; + if (max > AU1XMMC_MAX_TRANSFER) max = AU1XMMC_MAX_TRANSFER; + + for(count = 0; count < max; count++ ) { + unsigned char val; + + status = au_readl(HOST_STATUS(host)); + + if (!(status & SD_STATUS_TH)) + break; + + val = *sg_ptr++; + + au_writel((unsigned long) val, HOST_TXPORT(host)); + au_sync(); + } + + host->pio.len -= count; + host->pio.offset += count; + + if (count == sg_len) { + host->pio.index++; + host->pio.offset = 0; + } + + if (host->pio.len == 0) { + IRQ_OFF(host, SD_CONFIG_TH); + + if (host->flags & HOST_F_STOP) + SEND_STOP(host); + + tasklet_schedule(&host->data_task); + } +} + +static void au1xmmc_receive_pio(struct au1xmmc_host *host) +{ + + struct mmc_data *data = 0; + int sg_len = 0, max = 0, count = 0; + unsigned char *sg_ptr = 0; + u32 status = 0; + struct scatterlist *sg; + + data = host->mrq->data; + + if (!(host->flags & HOST_F_RECV)) + return; + + max = host->pio.len; + + if (host->pio.index < host->dma.len) { + sg = &data->sg[host->pio.index]; + sg_ptr = page_address(sg->page) + sg->offset + host->pio.offset; + + /* This is the space left inside the buffer */ + sg_len = sg_dma_len(&data->sg[host->pio.index]) - host->pio.offset; + + /* Check to if we need less then the size of the sg_buffer */ + if (sg_len < max) max = sg_len; + } + + if (max > AU1XMMC_MAX_TRANSFER) + max = AU1XMMC_MAX_TRANSFER; + + for(count = 0; count < max; count++ ) { + u32 val; + status = au_readl(HOST_STATUS(host)); + + if (!(status & SD_STATUS_NE)) + break; + + if (status & SD_STATUS_RC) { + DEBUG("RX CRC Error [%d + %d].\n", host->id, + host->pio.len, count); + break; + } + + if (status & SD_STATUS_RO) { + DEBUG("RX Overrun [%d + %d]\n", host->id, + host->pio.len, count); + break; + } + else if (status & SD_STATUS_RU) { + DEBUG("RX Underrun [%d + %d]\n", host->id, + host->pio.len, count); + break; + } + + val = au_readl(HOST_RXPORT(host)); + + if (sg_ptr) + *sg_ptr++ = (unsigned char) (val & 0xFF); + } + + host->pio.len -= count; + host->pio.offset += count; + + if (sg_len && count == sg_len) { + host->pio.index++; + host->pio.offset = 0; + } + + if (host->pio.len == 0) { + //IRQ_OFF(host, SD_CONFIG_RA | SD_CONFIG_RF); + IRQ_OFF(host, SD_CONFIG_NE); + + if (host->flags & HOST_F_STOP) + SEND_STOP(host); + + tasklet_schedule(&host->data_task); + } +} + +/* static void au1xmmc_cmd_complete + This is called when a command has been completed - grab the response + and check for errors. Then start the data transfer if it is indicated. +*/ + +static void au1xmmc_cmd_complete(struct au1xmmc_host *host, u32 status) +{ + + struct mmc_request *mrq = host->mrq; + struct mmc_command *cmd; + int trans; + + if (!host->mrq) + return; + + cmd = mrq->cmd; + cmd->error = MMC_ERR_NONE; + + if ((cmd->flags & MMC_RSP_MASK) == MMC_RSP_SHORT) { + + /* Techincally, we should be getting all 48 bits of the response + * (SD_RESP1 + SD_RESP2), but because our response omits the CRC, + * our data ends up being shifted 8 bits to the right. In this case, + * that means that the OSR data starts at bit 31, so we can just + * read RESP0 and return that + */ + + cmd->resp[0] = au_readl(host->iobase + SD_RESP0); + } + else if ((cmd->flags & MMC_RSP_MASK) == MMC_RSP_LONG) { + u32 r[4]; + int i; + + r[0] = au_readl(host->iobase + SD_RESP3); + r[1] = au_readl(host->iobase + SD_RESP2); + r[2] = au_readl(host->iobase + SD_RESP1); + r[3] = au_readl(host->iobase + SD_RESP0); + + /* The CRC is omitted from the response, so really we only got + * 120 bytes, but the engine expects 128 bits, so we have to shift + * things up + */ + + for(i = 0; i < 4; i++) { + cmd->resp[i] = (r[i] & 0x00FFFFFF) << 8; + if (i != 3) cmd->resp[i] |= (r[i + 1] & 0xFF000000) >> 24; + } + } + + /* Figure out errors */ + + if (status & (SD_STATUS_SC | SD_STATUS_WC | SD_STATUS_RC)) + cmd->error = MMC_ERR_BADCRC; + + trans = host->flags & (HOST_F_XMIT | HOST_F_RECV); + + if (!trans || cmd->error != MMC_ERR_NONE) { + + IRQ_OFF(host, SD_CONFIG_TH | SD_CONFIG_RA|SD_CONFIG_RF); + tasklet_schedule(&host->finish_task); + return; + } + + host->status = HOST_S_DATA; + + if (host->flags & HOST_F_DMA) { + u32 channel = DMA_CHANNEL(host); + + /* Start the DMA as soon as the buffer gets something in it */ + + if (host->flags & HOST_F_RECV) { + u32 mask = SD_STATUS_DB | SD_STATUS_NE; + + while((status & mask) != mask) + status = au_readl(HOST_STATUS(host)); + } + + au1xxx_dbdma_start(channel); + } +} + +static void au1xmmc_set_clock(struct au1xmmc_host *host, int rate) +{ + + unsigned int pbus = get_au1x00_speed(); + unsigned int divisor; + u32 config; + + /* From databook: + divisor = ((((cpuclock / sbus_divisor) / 2) / mmcclock) / 2) - 1 + */ + + pbus /= ((au_readl(SYS_POWERCTRL) & 0x3) + 2); + pbus /= 2; + + divisor = ((pbus / rate) / 2) - 1; + + config = au_readl(HOST_CONFIG(host)); + + config &= ~(SD_CONFIG_DIV); + config |= (divisor & SD_CONFIG_DIV) | SD_CONFIG_DE; + + au_writel(config, HOST_CONFIG(host)); + au_sync(); +} + +static int +au1xmmc_prepare_data(struct au1xmmc_host *host, struct mmc_data *data) +{ + + int datalen = data->blocks * (1 << data->blksz_bits); + + if (dma != 0) + host->flags |= HOST_F_DMA; + + if (data->flags & MMC_DATA_READ) + host->flags |= HOST_F_RECV; + else + host->flags |= HOST_F_XMIT; + + if (host->mrq->stop) + host->flags |= HOST_F_STOP; + + host->dma.dir = DMA_BIDIRECTIONAL; + + host->dma.len = dma_map_sg(mmc_dev(host->mmc), data->sg, + data->sg_len, host->dma.dir); + + if (host->dma.len == 0) + return MMC_ERR_TIMEOUT; + + au_writel((1 << data->blksz_bits) - 1, HOST_BLKSIZE(host)); + + if (host->flags & HOST_F_DMA) { + int i; + u32 channel = DMA_CHANNEL(host); + + au1xxx_dbdma_stop(channel); + + for(i = 0; i < host->dma.len; i++) { + u32 ret = 0, flags = DDMA_FLAGS_NOIE; + struct scatterlist *sg = &data->sg[i]; + int sg_len = sg->length; + + int len = (datalen > sg_len) ? sg_len : datalen; + + if (i == host->dma.len - 1) + flags = DDMA_FLAGS_IE; + + if (host->flags & HOST_F_XMIT){ + ret = au1xxx_dbdma_put_source_flags(channel, + (void *) (page_address(sg->page) + + sg->offset), + len, flags); + } + else { + ret = au1xxx_dbdma_put_dest_flags(channel, + (void *) (page_address(sg->page) + + sg->offset), + len, flags); + } + + if (!ret) + goto dataerr; + + datalen -= len; + } + } + else { + host->pio.index = 0; + host->pio.offset = 0; + host->pio.len = datalen; + + if (host->flags & HOST_F_XMIT) + IRQ_ON(host, SD_CONFIG_TH); + else + IRQ_ON(host, SD_CONFIG_NE); + //IRQ_ON(host, SD_CONFIG_RA|SD_CONFIG_RF); + } + + return MMC_ERR_NONE; + + dataerr: + dma_unmap_sg(mmc_dev(host->mmc),data->sg,data->sg_len,host->dma.dir); + return MMC_ERR_TIMEOUT; +} + +/* static void au1xmmc_request + This actually starts a command or data transaction +*/ + +static void au1xmmc_request(struct mmc_host* mmc, struct mmc_request* mrq) +{ + + struct au1xmmc_host *host = mmc_priv(mmc); + int ret = MMC_ERR_NONE; + + WARN_ON(irqs_disabled()); + WARN_ON(host->status != HOST_S_IDLE); + + host->mrq = mrq; + host->status = HOST_S_CMD; + + bcsr->disk_leds &= ~(1 << 8); + + if (mrq->data) { + FLUSH_FIFO(host); + ret = au1xmmc_prepare_data(host, mrq->data); + } + + if (ret == MMC_ERR_NONE) + ret = au1xmmc_send_command(host, 0, mrq->cmd); + + if (ret != MMC_ERR_NONE) { + mrq->cmd->error = ret; + au1xmmc_finish_request(host); + } +} + +static void au1xmmc_reset_controller(struct au1xmmc_host *host) +{ + + /* Apply the clock */ + au_writel(SD_ENABLE_CE, HOST_ENABLE(host)); + au_sync_delay(1); + + au_writel(SD_ENABLE_R | SD_ENABLE_CE, HOST_ENABLE(host)); + au_sync_delay(5); + + au_writel(~0, HOST_STATUS(host)); + au_sync(); + + au_writel(0, HOST_BLKSIZE(host)); + au_writel(0x001fffff, HOST_TIMEOUT(host)); + au_sync(); + + au_writel(SD_CONFIG2_EN, HOST_CONFIG2(host)); + au_sync(); + + au_writel(SD_CONFIG2_EN | SD_CONFIG2_FF, HOST_CONFIG2(host)); + au_sync_delay(1); + + au_writel(SD_CONFIG2_EN, HOST_CONFIG2(host)); + au_sync(); + + /* Configure interrupts */ + au_writel(AU1XMMC_INTERRUPTS, HOST_CONFIG(host)); + au_sync(); +} + + +static void au1xmmc_set_ios(struct mmc_host* mmc, struct mmc_ios* ios) +{ + struct au1xmmc_host *host = mmc_priv(mmc); + + DEBUG("set_ios (power=%u, clock=%uHz, vdd=%u, mode=%u)\n", + host->id, ios->power_mode, ios->clock, ios->vdd, + ios->bus_mode); + + if (ios->power_mode == MMC_POWER_OFF) + au1xmmc_set_power(host, 0); + else if (ios->power_mode == MMC_POWER_ON) { + au1xmmc_set_power(host, 1); + } + + if (ios->clock && ios->clock != host->clock) { + au1xmmc_set_clock(host, ios->clock); + host->clock = ios->clock; + } +} + +static void au1xmmc_dma_callback(int irq, void *dev_id, struct pt_regs *regs) +{ + struct au1xmmc_host *host = (struct au1xmmc_host *) dev_id; + u32 status; + + /* Avoid spurious interrupts */ + + if (!host->mrq) + return; + + if (host->flags & HOST_F_STOP) + SEND_STOP(host); + + tasklet_schedule(&host->data_task); +} + +#define STATUS_TIMEOUT (SD_STATUS_RAT | SD_STATUS_DT) +#define STATUS_DATA_IN (SD_STATUS_NE) +#define STATUS_DATA_OUT (SD_STATUS_TH) + +static irqreturn_t au1xmmc_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + + u32 status; + int i, ret = 0; + + disable_irq(AU1100_SD_IRQ); + + for(i = 0; i < AU1XMMC_CONTROLLER_COUNT; i++) { + struct au1xmmc_host * host = au1xmmc_hosts[i]; + u32 handled = 1; + + status = au_readl(HOST_STATUS(host)); + + if (host->mrq && (status & STATUS_TIMEOUT)) { + if (status & SD_STATUS_RAT) + host->mrq->cmd->error = MMC_ERR_TIMEOUT; + + else if (status & SD_STATUS_DT) + host->mrq->data->error = MMC_ERR_TIMEOUT; + + /* In PIO mode, interrupts might still be enabled */ + IRQ_OFF(host, SD_CONFIG_NE | SD_CONFIG_TH); + + //IRQ_OFF(host, SD_CONFIG_TH|SD_CONFIG_RA|SD_CONFIG_RF); + tasklet_schedule(&host->finish_task); + } +#if 0 + else if (status & SD_STATUS_DD) { + + /* Sometimes we get a DD before a NE in PIO mode */ + + if (!(host->flags & HOST_F_DMA) && + (status & SD_STATUS_NE)) + au1xmmc_receive_pio(host); + else { + au1xmmc_data_complete(host, status); + //tasklet_schedule(&host->data_task); + } + } +#endif + else if (status & (SD_STATUS_CR)) { + if (host->status == HOST_S_CMD) + au1xmmc_cmd_complete(host,status); + } + else if (!(host->flags & HOST_F_DMA)) { + if ((host->flags & HOST_F_XMIT) && + (status & STATUS_DATA_OUT)) + au1xmmc_send_pio(host); + else if ((host->flags & HOST_F_RECV) && + (status & STATUS_DATA_IN)) + au1xmmc_receive_pio(host); + } + else if (status & 0x203FBC70) { + DEBUG("Unhandled status %8.8x\n", host->id, status); + handled = 0; + } + + au_writel(status, HOST_STATUS(host)); + au_sync(); + + ret |= handled; + } + + enable_irq(AU1100_SD_IRQ); + return ret; +} + +static void au1xmmc_poll_event(unsigned long arg) +{ + struct au1xmmc_host *host = (struct au1xmmc_host *) arg; + + int card = au1xmmc_card_inserted(host); + int controller = (host->flags & HOST_F_ACTIVE) ? 1 : 0; + + if (card != controller) { + host->flags &= ~HOST_F_ACTIVE; + if (card) host->flags |= HOST_F_ACTIVE; + mmc_detect_change(host->mmc, 0); + } + + if (host->mrq != NULL) { + u32 status = au_readl(HOST_STATUS(host)); + DEBUG("PENDING - %8.8x\n", host->id, status); + } + + mod_timer(&host->timer, jiffies + AU1XMMC_DETECT_TIMEOUT); +} + +static dbdev_tab_t au1xmmc_mem_dbdev = +{ + DSCR_CMD0_ALWAYS, DEV_FLAGS_ANYUSE, 0, 8, 0x00000000, 0, 0 +}; + +static void au1xmmc_init_dma(struct au1xmmc_host *host) +{ + + u32 rxchan, txchan; + + int txid = au1xmmc_card_table[host->id].tx_devid; + int rxid = au1xmmc_card_table[host->id].rx_devid; + + /* DSCR_CMD0_ALWAYS has a stride of 32 bits, we need a stride + of 8 bits. And since devices are shared, we need to create + our own to avoid freaking out other devices + */ + + int memid = au1xxx_ddma_add_device(&au1xmmc_mem_dbdev); + + txchan = au1xxx_dbdma_chan_alloc(memid, txid, + au1xmmc_dma_callback, (void *) host); + + rxchan = au1xxx_dbdma_chan_alloc(rxid, memid, + au1xmmc_dma_callback, (void *) host); + + au1xxx_dbdma_set_devwidth(txchan, 8); + au1xxx_dbdma_set_devwidth(rxchan, 8); + + au1xxx_dbdma_ring_alloc(txchan, AU1XMMC_DESCRIPTOR_COUNT); + au1xxx_dbdma_ring_alloc(rxchan, AU1XMMC_DESCRIPTOR_COUNT); + + host->tx_chan = txchan; + host->rx_chan = rxchan; +} + +struct mmc_host_ops au1xmmc_ops = { + .request = au1xmmc_request, + .set_ios = au1xmmc_set_ios, +}; + +static int au1xmmc_probe(struct device *dev) +{ + + int i, ret = 0; + + /* THe interrupt is shared among all controllers */ + ret = request_irq(AU1100_SD_IRQ, au1xmmc_irq, SA_INTERRUPT, "MMC", 0); + + if (ret) { + printk(DRIVER_NAME "ERROR: Couldn't get int %d: %d\n", + AU1100_SD_IRQ, ret); + return -ENXIO; + } + + disable_irq(AU1100_SD_IRQ); + + for(i = 0; i < AU1XMMC_CONTROLLER_COUNT; i++) { + struct mmc_host *mmc = mmc_alloc_host(sizeof(struct au1xmmc_host), dev); + struct au1xmmc_host *host = 0; + + if (!mmc) { + printk(DRIVER_NAME "ERROR: no mem for host %d\n", i); + au1xmmc_hosts[i] = 0; + continue; + } + + mmc->ops = &au1xmmc_ops; + + mmc->f_min = 450000; + mmc->f_max = 24000000; + + mmc->max_seg_size = AU1XMMC_DESCRIPTOR_SIZE; + mmc->max_phys_segs = AU1XMMC_DESCRIPTOR_COUNT; + + mmc->ocr_avail = AU1XMMC_OCR; + + host = mmc_priv(mmc); + host->mmc = mmc; + + host->id = i; + host->iobase = au1xmmc_card_table[host->id].iobase; + host->clock = 0; + host->power_mode = MMC_POWER_OFF; + + host->flags = au1xmmc_card_inserted(host) ? HOST_F_ACTIVE : 0; + host->status = HOST_S_IDLE; + + init_timer(&host->timer); + + host->timer.function = au1xmmc_poll_event; + host->timer.data = (unsigned long) host; + host->timer.expires = jiffies + AU1XMMC_DETECT_TIMEOUT; + + tasklet_init(&host->data_task, au1xmmc_tasklet_data, + (unsigned long) host); + + tasklet_init(&host->finish_task, au1xmmc_tasklet_finish, + (unsigned long) host); + + spin_lock_init(&host->lock); + + if (dma != 0) + au1xmmc_init_dma(host); + + au1xmmc_reset_controller(host); + + mmc_add_host(mmc); + au1xmmc_hosts[i] = host; + + add_timer(&host->timer); + + printk(KERN_INFO DRIVER_NAME ": MMC Controller %d set up at %8.8X (mode=%s)\n", + host->id, host->iobase, dma ? "dma" : "pio"); + } + + enable_irq(AU1100_SD_IRQ); + + return 0; +} + +static int au1xmmc_remove(struct device *dev) +{ + + int i; + + disable_irq(AU1100_SD_IRQ); + + for(i = 0; i < AU1XMMC_CONTROLLER_COUNT; i++) { + struct au1xmmc_host *host = au1xmmc_hosts[i]; + if (!host) continue; + + tasklet_kill(&host->data_task); + tasklet_kill(&host->finish_task); + + del_timer_sync(&host->timer); + au1xmmc_set_power(host, 0); + + mmc_remove_host(host->mmc); + + au1xxx_dbdma_chan_free(host->tx_chan); + au1xxx_dbdma_chan_free(host->rx_chan); + + au_writel(0x0, HOST_ENABLE(host)); + au_sync(); + } + + free_irq(AU1100_SD_IRQ, 0); + return 0; +} + +static struct device_driver au1xmmc_driver = { + .name = DRIVER_NAME, + .bus = &platform_bus_type, + .probe = au1xmmc_probe, + .remove = au1xmmc_remove, + .suspend = NULL, + .resume = NULL +}; + +static int __init au1xmmc_init(void) +{ + return driver_register(&au1xmmc_driver); +} + +static void __exit au1xmmc_exit(void) +{ + driver_unregister(&au1xmmc_driver); +} + +module_init(au1xmmc_init); +module_exit(au1xmmc_exit); + +#ifdef MODULE +MODULE_AUTHOR("Advanced Micro Devices, Inc"); +MODULE_DESCRIPTION("MMC/SD driver for the Alchemy Au1XXX"); +MODULE_LICENSE("GPL"); +#endif + diff --git a/drivers/mmc/au1xmmc.h b/drivers/mmc/au1xmmc.h new file mode 100644 index 000000000000..341cbdf0baca --- /dev/null +++ b/drivers/mmc/au1xmmc.h @@ -0,0 +1,96 @@ +#ifndef _AU1XMMC_H_ +#define _AU1XMMC_H_ + +/* Hardware definitions */ + +#define AU1XMMC_DESCRIPTOR_COUNT 1 +#define AU1XMMC_DESCRIPTOR_SIZE 2048 + +#define AU1XMMC_OCR ( MMC_VDD_27_28 | MMC_VDD_28_29 | MMC_VDD_29_30 | \ + MMC_VDD_30_31 | MMC_VDD_31_32 | MMC_VDD_32_33 | \ + MMC_VDD_33_34 | MMC_VDD_34_35 | MMC_VDD_35_36) + +/* Easy access macros */ + +#define HOST_STATUS(h) ((h)->iobase + SD_STATUS) +#define HOST_CONFIG(h) ((h)->iobase + SD_CONFIG) +#define HOST_ENABLE(h) ((h)->iobase + SD_ENABLE) +#define HOST_TXPORT(h) ((h)->iobase + SD_TXPORT) +#define HOST_RXPORT(h) ((h)->iobase + SD_RXPORT) +#define HOST_CMDARG(h) ((h)->iobase + SD_CMDARG) +#define HOST_BLKSIZE(h) ((h)->iobase + SD_BLKSIZE) +#define HOST_CMD(h) ((h)->iobase + SD_CMD) +#define HOST_CONFIG2(h) ((h)->iobase + SD_CONFIG2) +#define HOST_TIMEOUT(h) ((h)->iobase + SD_TIMEOUT) +#define HOST_DEBUG(h) ((h)->iobase + SD_DEBUG) + +#define DMA_CHANNEL(h) \ + ( ((h)->flags & HOST_F_XMIT) ? (h)->tx_chan : (h)->rx_chan) + +/* This gives us a hard value for the stop command that we can write directly + * to the command register + */ + +#define STOP_CMD (SD_CMD_RT_1B|SD_CMD_CT_7|(0xC << SD_CMD_CI_SHIFT)|SD_CMD_GO) + +/* This is the set of interrupts that we configure by default */ + +#if 0 +#define AU1XMMC_INTERRUPTS (SD_CONFIG_SC | SD_CONFIG_DT | SD_CONFIG_DD | \ + SD_CONFIG_RAT | SD_CONFIG_CR | SD_CONFIG_I) +#endif + +#define AU1XMMC_INTERRUPTS (SD_CONFIG_SC | SD_CONFIG_DT | \ + SD_CONFIG_RAT | SD_CONFIG_CR | SD_CONFIG_I) +/* The poll event (looking for insert/remove events runs twice a second */ +#define AU1XMMC_DETECT_TIMEOUT (HZ/2) + +struct au1xmmc_host { + struct mmc_host *mmc; + struct mmc_request *mrq; + + u32 id; + + u32 flags; + u32 iobase; + u32 clock; + u32 bus_width; + u32 power_mode; + + int status; + + struct { + int len; + int dir; + } dma; + + struct { + int index; + int offset; + int len; + } pio; + + u32 tx_chan; + u32 rx_chan; + + struct timer_list timer; + struct tasklet_struct finish_task; + struct tasklet_struct data_task; + + spinlock_t lock; +}; + +/* Status flags used by the host structure */ + +#define HOST_F_XMIT 0x0001 +#define HOST_F_RECV 0x0002 +#define HOST_F_DMA 0x0010 +#define HOST_F_ACTIVE 0x0100 +#define HOST_F_STOP 0x1000 + +#define HOST_S_IDLE 0x0001 +#define HOST_S_CMD 0x0002 +#define HOST_S_DATA 0x0003 +#define HOST_S_STOP 0x0004 + +#endif diff --git a/drivers/mmc/mmc_block.c b/drivers/mmc/mmc_block.c index fa83f15fdf16..9b629856c735 100644 --- a/drivers/mmc/mmc_block.c +++ b/drivers/mmc/mmc_block.c @@ -85,6 +85,12 @@ static void mmc_blk_put(struct mmc_blk_data *md) up(&open_lock); } +static inline int mmc_blk_readonly(struct mmc_card *card) +{ + return mmc_card_readonly(card) || + !(card->csd.cmdclass & CCC_BLOCK_WRITE); +} + static int mmc_blk_open(struct inode *inode, struct file *filp) { struct mmc_blk_data *md; @@ -97,7 +103,7 @@ static int mmc_blk_open(struct inode *inode, struct file *filp) ret = 0; if ((filp->f_mode & FMODE_WRITE) && - mmc_card_readonly(md->queue.card)) + mmc_blk_readonly(md->queue.card)) ret = -EROFS; } @@ -410,7 +416,7 @@ static int mmc_blk_probe(struct mmc_card *card) printk(KERN_INFO "%s: %s %s %dKiB %s\n", md->disk->disk_name, mmc_card_id(card), mmc_card_name(card), (card->csd.capacity << card->csd.read_blkbits) / 1024, - mmc_card_readonly(card)?"(ro)":""); + mmc_blk_readonly(card)?"(ro)":""); mmc_set_drvdata(card, md); add_disk(md->disk); diff --git a/drivers/mmc/mmci.c b/drivers/mmc/mmci.c index 91c74843dc0d..1e6bdba26756 100644 --- a/drivers/mmc/mmci.c +++ b/drivers/mmc/mmci.c @@ -24,6 +24,7 @@ #include <asm/io.h> #include <asm/irq.h> #include <asm/scatterlist.h> +#include <asm/sizes.h> #include <asm/hardware/amba.h> #include <asm/hardware/clock.h> #include <asm/mach/mmc.h> diff --git a/drivers/mmc/pxamci.c b/drivers/mmc/pxamci.c index b53af57074e3..d575e3a018bc 100644 --- a/drivers/mmc/pxamci.c +++ b/drivers/mmc/pxamci.c @@ -29,7 +29,6 @@ #include <asm/dma.h> #include <asm/io.h> -#include <asm/irq.h> #include <asm/scatterlist.h> #include <asm/sizes.h> @@ -571,23 +570,23 @@ static int pxamci_remove(struct device *dev) } #ifdef CONFIG_PM -static int pxamci_suspend(struct device *dev, pm_message_t state, u32 level) +static int pxamci_suspend(struct device *dev, pm_message_t state) { struct mmc_host *mmc = dev_get_drvdata(dev); int ret = 0; - if (mmc && level == SUSPEND_DISABLE) + if (mmc) ret = mmc_suspend_host(mmc, state); return ret; } -static int pxamci_resume(struct device *dev, u32 level) +static int pxamci_resume(struct device *dev) { struct mmc_host *mmc = dev_get_drvdata(dev); int ret = 0; - if (mmc && level == RESUME_ENABLE) + if (mmc) ret = mmc_resume_host(mmc); return ret; diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c index 3cbca7cbea80..3ace875decc4 100644 --- a/drivers/mmc/wbsd.c +++ b/drivers/mmc/wbsd.c @@ -1033,13 +1033,16 @@ static void wbsd_set_ios(struct mmc_host* mmc, struct mmc_ios* ios) } else { - setup &= ~WBSD_DAT3_H; + if (setup & WBSD_DAT3_H) + { + setup &= ~WBSD_DAT3_H; - /* - * We cannot resume card detection immediatly - * because of capacitance and delays in the chip. - */ - mod_timer(&host->ignore_timer, jiffies + HZ/100); + /* + * We cannot resume card detection immediatly + * because of capacitance and delays in the chip. + */ + mod_timer(&host->ignore_timer, jiffies + HZ/100); + } } wbsd_write_index(host, WBSD_IDX_SETUP, setup); @@ -1461,8 +1464,10 @@ static int __devinit wbsd_scan(struct wbsd_host* host) { id = 0xFFFF; - outb(unlock_codes[j], config_ports[i]); - outb(unlock_codes[j], config_ports[i]); + host->config = config_ports[i]; + host->unlock_code = unlock_codes[j]; + + wbsd_unlock_config(host); outb(WBSD_CONF_ID_HI, config_ports[i]); id = inb(config_ports[i] + 1) << 8; @@ -1470,13 +1475,13 @@ static int __devinit wbsd_scan(struct wbsd_host* host) outb(WBSD_CONF_ID_LO, config_ports[i]); id |= inb(config_ports[i] + 1); + wbsd_lock_config(host); + for (k = 0;k < sizeof(valid_ids)/sizeof(int);k++) { if (id == valid_ids[k]) { host->chip_id = id; - host->config = config_ports[i]; - host->unlock_code = unlock_codes[i]; return 0; } @@ -1487,13 +1492,14 @@ static int __devinit wbsd_scan(struct wbsd_host* host) DBG("Unknown hardware (id %x) found at %x\n", id, config_ports[i]); } - - outb(LOCK_CODE, config_ports[i]); } release_region(config_ports[i], 2); } + host->config = 0; + host->unlock_code = 0; + return -ENODEV; } @@ -1699,8 +1705,10 @@ static void __devexit wbsd_release_resources(struct wbsd_host* host) * Configure the resources the chip should use. */ -static void __devinit wbsd_chip_config(struct wbsd_host* host) +static void wbsd_chip_config(struct wbsd_host* host) { + wbsd_unlock_config(host); + /* * Reset the chip. */ @@ -1733,16 +1741,20 @@ static void __devinit wbsd_chip_config(struct wbsd_host* host) */ wbsd_write_config(host, WBSD_CONF_ENABLE, 1); wbsd_write_config(host, WBSD_CONF_POWER, 0x20); + + wbsd_lock_config(host); } /* * Check that configured resources are correct. */ -static int __devinit wbsd_chip_validate(struct wbsd_host* host) +static int wbsd_chip_validate(struct wbsd_host* host) { int base, irq, dma; + wbsd_unlock_config(host); + /* * Select SD/MMC function. */ @@ -1758,6 +1770,8 @@ static int __devinit wbsd_chip_validate(struct wbsd_host* host) dma = wbsd_read_config(host, WBSD_CONF_DRQ); + wbsd_lock_config(host); + /* * Validate against given configuration. */ @@ -1771,6 +1785,20 @@ static int __devinit wbsd_chip_validate(struct wbsd_host* host) return 1; } +/* + * Powers down the SD function + */ + +static void wbsd_chip_poweroff(struct wbsd_host* host) +{ + wbsd_unlock_config(host); + + wbsd_write_config(host, WBSD_CONF_DEVICE, DEVICE_SD); + wbsd_write_config(host, WBSD_CONF_ENABLE, 0); + + wbsd_lock_config(host); +} + /*****************************************************************************\ * * * Devices setup and shutdown * @@ -1844,7 +1872,11 @@ static int __devinit wbsd_init(struct device* dev, int base, int irq, int dma, */ #ifdef CONFIG_PM if (host->config) + { + wbsd_unlock_config(host); wbsd_write_config(host, WBSD_CONF_PME, 0xA0); + wbsd_lock_config(host); + } #endif /* * Allow device to initialise itself properly. @@ -1885,16 +1917,11 @@ static void __devexit wbsd_shutdown(struct device* dev, int pnp) mmc_remove_host(mmc); + /* + * Power down the SD/MMC function. + */ if (!pnp) - { - /* - * Power down the SD/MMC function. - */ - wbsd_unlock_config(host); - wbsd_write_config(host, WBSD_CONF_DEVICE, DEVICE_SD); - wbsd_write_config(host, WBSD_CONF_ENABLE, 0); - wbsd_lock_config(host); - } + wbsd_chip_poweroff(host); wbsd_release_resources(host); @@ -1955,23 +1982,59 @@ static void __devexit wbsd_pnp_remove(struct pnp_dev * dev) */ #ifdef CONFIG_PM -static int wbsd_suspend(struct device *dev, pm_message_t state, u32 level) + +static int wbsd_suspend(struct device *dev, pm_message_t state) { - DBGF("Not yet supported\n"); + struct mmc_host *mmc = dev_get_drvdata(dev); + struct wbsd_host *host; + int ret; + + if (!mmc) + return 0; + + DBG("Suspending...\n"); + + ret = mmc_suspend_host(mmc, state); + if (!ret) + return ret; + + host = mmc_priv(mmc); + + wbsd_chip_poweroff(host); return 0; } -static int wbsd_resume(struct device *dev, u32 level) +static int wbsd_resume(struct device *dev) { - DBGF("Not yet supported\n"); + struct mmc_host *mmc = dev_get_drvdata(dev); + struct wbsd_host *host; - return 0; + if (!mmc) + return 0; + + DBG("Resuming...\n"); + + host = mmc_priv(mmc); + + wbsd_chip_config(host); + + /* + * Allow device to initialise itself properly. + */ + mdelay(5); + + wbsd_init_device(host); + + return mmc_resume_host(mmc); } -#else + +#else /* CONFIG_PM */ + #define wbsd_suspend NULL #define wbsd_resume NULL -#endif + +#endif /* CONFIG_PM */ static struct platform_device *wbsd_device; diff --git a/drivers/mtd/chips/jedec.c b/drivers/mtd/chips/jedec.c index 62d235a9a4e2..4f6778f3ee3e 100644 --- a/drivers/mtd/chips/jedec.c +++ b/drivers/mtd/chips/jedec.c @@ -17,6 +17,7 @@ #include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> +#include <linux/slab.h> #include <linux/mtd/jedec.h> #include <linux/mtd/map.h> #include <linux/mtd/mtd.h> diff --git a/drivers/mtd/devices/lart.c b/drivers/mtd/devices/lart.c index dfd335e4a2a8..df987a53ed9c 100644 --- a/drivers/mtd/devices/lart.c +++ b/drivers/mtd/devices/lart.c @@ -44,6 +44,7 @@ #include <linux/types.h> #include <linux/init.h> #include <linux/errno.h> +#include <linux/string.h> #include <linux/mtd/mtd.h> #ifdef HAVE_PARTITIONS #include <linux/mtd/partitions.h> diff --git a/drivers/mtd/devices/phram.c b/drivers/mtd/devices/phram.c index a423a382095a..765c0179c8df 100644 --- a/drivers/mtd/devices/phram.c +++ b/drivers/mtd/devices/phram.c @@ -22,6 +22,7 @@ #include <linux/list.h> #include <linux/module.h> #include <linux/moduleparam.h> +#include <linux/slab.h> #include <linux/mtd/mtd.h> #define ERROR(fmt, args...) printk(KERN_ERR "phram: " fmt , ## args) diff --git a/drivers/mtd/maps/bast-flash.c b/drivers/mtd/maps/bast-flash.c index 0ba0ff7d43b9..63104c73ca3c 100644 --- a/drivers/mtd/maps/bast-flash.c +++ b/drivers/mtd/maps/bast-flash.c @@ -33,6 +33,7 @@ #include <linux/string.h> #include <linux/ioport.h> #include <linux/device.h> +#include <linux/slab.h> #include <linux/mtd/mtd.h> #include <linux/mtd/map.h> diff --git a/drivers/mtd/maps/ceiva.c b/drivers/mtd/maps/ceiva.c index da8584a662f4..c68b31dc7e6d 100644 --- a/drivers/mtd/maps/ceiva.c +++ b/drivers/mtd/maps/ceiva.c @@ -20,6 +20,7 @@ #include <linux/ioport.h> #include <linux/kernel.h> #include <linux/init.h> +#include <linux/slab.h> #include <linux/mtd/mtd.h> #include <linux/mtd/map.h> diff --git a/drivers/mtd/maps/dc21285.c b/drivers/mtd/maps/dc21285.c index 938c41f2f056..e5b74169fde6 100644 --- a/drivers/mtd/maps/dc21285.c +++ b/drivers/mtd/maps/dc21285.c @@ -13,6 +13,7 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/delay.h> +#include <linux/slab.h> #include <linux/mtd/mtd.h> #include <linux/mtd/map.h> diff --git a/drivers/mtd/maps/dilnetpc.c b/drivers/mtd/maps/dilnetpc.c index 0bc79c93a584..f99519692cb7 100644 --- a/drivers/mtd/maps/dilnetpc.c +++ b/drivers/mtd/maps/dilnetpc.c @@ -30,12 +30,15 @@ #include <linux/types.h> #include <linux/kernel.h> #include <linux/init.h> -#include <asm/io.h> +#include <linux/string.h> + #include <linux/mtd/mtd.h> #include <linux/mtd/map.h> #include <linux/mtd/partitions.h> #include <linux/mtd/concat.h> +#include <asm/io.h> + /* ** The DIL/NetPC keeps its BIOS in two distinct flash blocks. ** Destroying any of these blocks transforms the DNPC into diff --git a/drivers/mtd/maps/epxa10db-flash.c b/drivers/mtd/maps/epxa10db-flash.c index ab6dbe2b8cce..1df6188926b3 100644 --- a/drivers/mtd/maps/epxa10db-flash.c +++ b/drivers/mtd/maps/epxa10db-flash.c @@ -27,12 +27,15 @@ #include <linux/types.h> #include <linux/kernel.h> #include <linux/init.h> -#include <asm/io.h> +#include <linux/slab.h> + #include <linux/mtd/mtd.h> #include <linux/mtd/map.h> #include <linux/mtd/partitions.h> +#include <asm/io.h> #include <asm/hardware.h> + #ifdef CONFIG_EPXA10DB #define BOARD_NAME "EPXA10DB" #else diff --git a/drivers/mtd/maps/fortunet.c b/drivers/mtd/maps/fortunet.c index 068bb6a54520..00f7bbe5479e 100644 --- a/drivers/mtd/maps/fortunet.c +++ b/drivers/mtd/maps/fortunet.c @@ -7,11 +7,14 @@ #include <linux/types.h> #include <linux/kernel.h> #include <linux/init.h> -#include <asm/io.h> +#include <linux/string.h> + #include <linux/mtd/mtd.h> #include <linux/mtd/map.h> #include <linux/mtd/partitions.h> +#include <asm/io.h> + #define MAX_NUM_REGIONS 4 #define MAX_NUM_PARTITIONS 8 diff --git a/drivers/mtd/maps/ixp2000.c b/drivers/mtd/maps/ixp2000.c index a9f86c7fbd52..1e5d6e1d05f3 100644 --- a/drivers/mtd/maps/ixp2000.c +++ b/drivers/mtd/maps/ixp2000.c @@ -22,11 +22,13 @@ #include <linux/init.h> #include <linux/kernel.h> #include <linux/string.h> +#include <linux/slab.h> +#include <linux/ioport.h> +#include <linux/device.h> + #include <linux/mtd/mtd.h> #include <linux/mtd/map.h> #include <linux/mtd/partitions.h> -#include <linux/ioport.h> -#include <linux/device.h> #include <asm/io.h> #include <asm/hardware.h> diff --git a/drivers/mtd/maps/ixp4xx.c b/drivers/mtd/maps/ixp4xx.c index 3fcc32884074..da316e543237 100644 --- a/drivers/mtd/maps/ixp4xx.c +++ b/drivers/mtd/maps/ixp4xx.c @@ -20,11 +20,14 @@ #include <linux/init.h> #include <linux/kernel.h> #include <linux/string.h> +#include <linux/slab.h> +#include <linux/ioport.h> +#include <linux/device.h> + #include <linux/mtd/mtd.h> #include <linux/mtd/map.h> #include <linux/mtd/partitions.h> -#include <linux/ioport.h> -#include <linux/device.h> + #include <asm/io.h> #include <asm/mach/flash.h> diff --git a/drivers/mtd/maps/lubbock-flash.c b/drivers/mtd/maps/lubbock-flash.c index 1298de475c9a..2337e0c46750 100644 --- a/drivers/mtd/maps/lubbock-flash.c +++ b/drivers/mtd/maps/lubbock-flash.c @@ -15,10 +15,13 @@ #include <linux/types.h> #include <linux/kernel.h> #include <linux/init.h> +#include <linux/slab.h> + #include <linux/dma-mapping.h> #include <linux/mtd/mtd.h> #include <linux/mtd/map.h> #include <linux/mtd/partitions.h> + #include <asm/io.h> #include <asm/hardware.h> #include <asm/arch/pxa-regs.h> diff --git a/drivers/mtd/maps/mainstone-flash.c b/drivers/mtd/maps/mainstone-flash.c index 87e93fa60588..da0f8a692628 100644 --- a/drivers/mtd/maps/mainstone-flash.c +++ b/drivers/mtd/maps/mainstone-flash.c @@ -16,9 +16,12 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/dma-mapping.h> +#include <linux/slab.h> + #include <linux/mtd/mtd.h> #include <linux/mtd/map.h> #include <linux/mtd/partitions.h> + #include <asm/io.h> #include <asm/hardware.h> #include <asm/arch/pxa-regs.h> diff --git a/drivers/mtd/maps/omap-toto-flash.c b/drivers/mtd/maps/omap-toto-flash.c index 496109071cb1..da36e8dddd17 100644 --- a/drivers/mtd/maps/omap-toto-flash.c +++ b/drivers/mtd/maps/omap-toto-flash.c @@ -12,9 +12,9 @@ #include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> - #include <linux/errno.h> #include <linux/init.h> +#include <linux/slab.h> #include <linux/mtd/mtd.h> #include <linux/mtd/map.h> diff --git a/drivers/mtd/maps/omap_nor.c b/drivers/mtd/maps/omap_nor.c index b17bca657daf..fa84566245a7 100644 --- a/drivers/mtd/maps/omap_nor.c +++ b/drivers/mtd/maps/omap_nor.c @@ -36,6 +36,8 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/ioport.h> +#include <linux/slab.h> + #include <linux/mtd/mtd.h> #include <linux/mtd/map.h> #include <linux/mtd/partitions.h> diff --git a/drivers/mtd/maps/pci.c b/drivers/mtd/maps/pci.c index 18dbd3af1eaa..d9c64e99ee32 100644 --- a/drivers/mtd/maps/pci.c +++ b/drivers/mtd/maps/pci.c @@ -17,6 +17,7 @@ #include <linux/kernel.h> #include <linux/pci.h> #include <linux/init.h> +#include <linux/slab.h> #include <linux/mtd/mtd.h> #include <linux/mtd/map.h> diff --git a/drivers/mtd/maps/plat-ram.c b/drivers/mtd/maps/plat-ram.c index 118b04544cad..a0577ea00c3c 100644 --- a/drivers/mtd/maps/plat-ram.c +++ b/drivers/mtd/maps/plat-ram.c @@ -30,6 +30,7 @@ #include <linux/string.h> #include <linux/ioport.h> #include <linux/device.h> +#include <linux/slab.h> #include <linux/mtd/mtd.h> #include <linux/mtd/map.h> diff --git a/drivers/mtd/maps/sa1100-flash.c b/drivers/mtd/maps/sa1100-flash.c index 8dcaa357b4bb..c81bec7b14d5 100644 --- a/drivers/mtd/maps/sa1100-flash.c +++ b/drivers/mtd/maps/sa1100-flash.c @@ -21,6 +21,7 @@ #include <linux/mtd/partitions.h> #include <linux/mtd/concat.h> +#include <asm/hardware.h> #include <asm/io.h> #include <asm/sizes.h> #include <asm/mach/flash.h> @@ -129,20 +130,21 @@ struct sa_subdev_info { char name[16]; struct map_info map; struct mtd_info *mtd; - struct flash_platform_data *data; + struct flash_platform_data *plat; }; struct sa_info { struct mtd_partition *parts; struct mtd_info *mtd; int num_subdev; + unsigned int nr_parts; struct sa_subdev_info subdev[0]; }; static void sa1100_set_vpp(struct map_info *map, int on) { struct sa_subdev_info *subdev = container_of(map, struct sa_subdev_info, map); - subdev->data->set_vpp(on); + subdev->plat->set_vpp(on); } static void sa1100_destroy_subdev(struct sa_subdev_info *subdev) @@ -186,7 +188,7 @@ static int sa1100_probe_subdev(struct sa_subdev_info *subdev, struct resource *r goto out; } - if (subdev->data->set_vpp) + if (subdev->plat->set_vpp) subdev->map.set_vpp = sa1100_set_vpp; subdev->map.phys = phys; @@ -203,7 +205,7 @@ static int sa1100_probe_subdev(struct sa_subdev_info *subdev, struct resource *r * Now let's probe for the actual flash. Do it here since * specific machine settings might have been set above. */ - subdev->mtd = do_map_probe(subdev->data->map_name, &subdev->map); + subdev->mtd = do_map_probe(subdev->plat->map_name, &subdev->map); if (subdev->mtd == NULL) { ret = -ENXIO; goto err; @@ -222,13 +224,17 @@ static int sa1100_probe_subdev(struct sa_subdev_info *subdev, struct resource *r return ret; } -static void sa1100_destroy(struct sa_info *info) +static void sa1100_destroy(struct sa_info *info, struct flash_platform_data *plat) { int i; if (info->mtd) { - del_mtd_partitions(info->mtd); - + if (info->nr_parts == 0) + del_mtd_device(info->mtd); +#ifdef CONFIG_MTD_PARTITIONS + else + del_mtd_partitions(info->mtd); +#endif #ifdef CONFIG_MTD_CONCAT if (info->mtd != info->subdev[0].mtd) mtd_concat_destroy(info->mtd); @@ -241,10 +247,13 @@ static void sa1100_destroy(struct sa_info *info) for (i = info->num_subdev - 1; i >= 0; i--) sa1100_destroy_subdev(&info->subdev[i]); kfree(info); + + if (plat->exit) + plat->exit(); } static struct sa_info *__init -sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *flash) +sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *plat) { struct sa_info *info; int nr, size, i, ret = 0; @@ -274,6 +283,12 @@ sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *flash memset(info, 0, size); + if (plat->init) { + ret = plat->init(); + if (ret) + goto err; + } + /* * Claim and then map the memory regions. */ @@ -286,8 +301,8 @@ sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *flash break; subdev->map.name = subdev->name; - sprintf(subdev->name, "sa1100-%d", i); - subdev->data = flash; + sprintf(subdev->name, "%s-%d", plat->name, i); + subdev->plat = plat; ret = sa1100_probe_subdev(subdev, res); if (ret) @@ -308,7 +323,7 @@ sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *flash * otherwise fail. Either way, it'll be called "sa1100". */ if (info->num_subdev == 1) { - strcpy(info->subdev[0].name, "sa1100"); + strcpy(info->subdev[0].name, plat->name); info->mtd = info->subdev[0].mtd; ret = 0; } else if (info->num_subdev > 1) { @@ -321,7 +336,7 @@ sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *flash cdev[i] = info->subdev[i].mtd; info->mtd = mtd_concat_create(cdev, info->num_subdev, - "sa1100"); + plat->name); if (info->mtd == NULL) ret = -ENXIO; #else @@ -335,7 +350,7 @@ sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *flash return info; err: - sa1100_destroy(info); + sa1100_destroy(info, plat); out: return ERR_PTR(ret); } @@ -345,16 +360,16 @@ static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL }; static int __init sa1100_mtd_probe(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); - struct flash_platform_data *flash = pdev->dev.platform_data; + struct flash_platform_data *plat = pdev->dev.platform_data; struct mtd_partition *parts; const char *part_type = NULL; struct sa_info *info; int err, nr_parts = 0; - if (!flash) + if (!plat) return -ENODEV; - info = sa1100_setup_mtd(pdev, flash); + info = sa1100_setup_mtd(pdev, plat); if (IS_ERR(info)) { err = PTR_ERR(info); goto out; @@ -371,8 +386,8 @@ static int __init sa1100_mtd_probe(struct device *dev) } else #endif { - parts = flash->parts; - nr_parts = flash->nr_parts; + parts = plat->parts; + nr_parts = plat->nr_parts; part_type = "static"; } @@ -386,6 +401,8 @@ static int __init sa1100_mtd_probe(struct device *dev) add_mtd_partitions(info->mtd, parts, nr_parts); } + info->nr_parts = nr_parts; + dev_set_drvdata(dev, info); err = 0; @@ -396,33 +413,44 @@ static int __init sa1100_mtd_probe(struct device *dev) static int __exit sa1100_mtd_remove(struct device *dev) { struct sa_info *info = dev_get_drvdata(dev); + struct flash_platform_data *plat = dev->platform_data; + dev_set_drvdata(dev, NULL); - sa1100_destroy(info); + sa1100_destroy(info, plat); + return 0; } #ifdef CONFIG_PM -static int sa1100_mtd_suspend(struct device *dev, pm_message_t state, u32 level) +static int sa1100_mtd_suspend(struct device *dev, pm_message_t state) { struct sa_info *info = dev_get_drvdata(dev); int ret = 0; - if (info && level == SUSPEND_SAVE_STATE) + if (info) ret = info->mtd->suspend(info->mtd); return ret; } -static int sa1100_mtd_resume(struct device *dev, u32 level) +static int sa1100_mtd_resume(struct device *dev) { struct sa_info *info = dev_get_drvdata(dev); - if (info && level == RESUME_RESTORE_STATE) + if (info) info->mtd->resume(info->mtd); return 0; } + +static void sa1100_mtd_shutdown(struct device *dev) +{ + struct sa_info *info = dev_get_drvdata(dev); + if (info && info->mtd->suspend(info->mtd) == 0) + info->mtd->resume(info->mtd); +} #else #define sa1100_mtd_suspend NULL #define sa1100_mtd_resume NULL +#define sa1100_mtd_shutdown NULL #endif static struct device_driver sa1100_mtd_driver = { @@ -432,6 +460,7 @@ static struct device_driver sa1100_mtd_driver = { .remove = __exit_p(sa1100_mtd_remove), .suspend = sa1100_mtd_suspend, .resume = sa1100_mtd_resume, + .shutdown = sa1100_mtd_shutdown, }; static int __init sa1100_mtd_init(void) diff --git a/drivers/mtd/maps/tqm8xxl.c b/drivers/mtd/maps/tqm8xxl.c index 995e9991cb8d..4e28b977f224 100644 --- a/drivers/mtd/maps/tqm8xxl.c +++ b/drivers/mtd/maps/tqm8xxl.c @@ -27,12 +27,14 @@ #include <linux/types.h> #include <linux/kernel.h> #include <linux/init.h> -#include <asm/io.h> +#include <linux/slab.h> #include <linux/mtd/mtd.h> #include <linux/mtd/map.h> #include <linux/mtd/partitions.h> +#include <asm/io.h> + #define FLASH_ADDR 0x40000000 #define FLASH_SIZE 0x00800000 #define FLASH_BANK_MAX 4 diff --git a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c index b7c32c242bc7..400dd9c89883 100644 --- a/drivers/mtd/mtdblock.c +++ b/drivers/mtd/mtdblock.c @@ -15,6 +15,7 @@ #include <linux/init.h> #include <linux/slab.h> #include <linux/vmalloc.h> +#include <linux/sched.h> /* TASK_* */ #include <linux/mtd/mtd.h> #include <linux/mtd/blktrans.h> diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index 1ed602a0f24c..16df1e4fb0e9 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -13,6 +13,7 @@ #include <linux/slab.h> #include <linux/init.h> #include <linux/fs.h> +#include <linux/sched.h> /* TASK_* */ #include <asm/uaccess.h> #include <linux/device.h> @@ -24,10 +25,10 @@ static void mtd_notify_add(struct mtd_info* mtd) if (!mtd) return; - class_device_create(mtd_class, MKDEV(MTD_CHAR_MAJOR, mtd->index*2), + class_device_create(mtd_class, NULL, MKDEV(MTD_CHAR_MAJOR, mtd->index*2), NULL, "mtd%d", mtd->index); - class_device_create(mtd_class, + class_device_create(mtd_class, NULL, MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1), NULL, "mtd%dro", mtd->index); } diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c index 8f66d093c80d..f3e65af33a9c 100644 --- a/drivers/mtd/mtdconcat.c +++ b/drivers/mtd/mtdconcat.c @@ -14,7 +14,7 @@ #include <linux/types.h> #include <linux/kernel.h> #include <linux/slab.h> - +#include <linux/sched.h> /* TASK_* */ #include <linux/mtd/mtd.h> #include <linux/mtd/concat.h> diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index b47ebcb31e0f..b58ba236a9eb 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c @@ -51,6 +51,7 @@ #include <linux/device.h> #include <linux/delay.h> #include <linux/err.h> +#include <linux/slab.h> #include <linux/mtd/mtd.h> #include <linux/mtd/nand.h> diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index bc537440ca02..f822cd3025ff 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -1027,8 +1027,7 @@ static void cp_reset_hw (struct cp_private *cp) if (!(cpr8(Cmd) & CmdReset)) return; - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(10); + schedule_timeout_uninterruptible(10); } printk(KERN_ERR "%s: hardware reset timeout\n", cp->dev->name); @@ -1575,6 +1574,7 @@ static struct ethtool_ops cp_ethtool_ops = { .set_wol = cp_set_wol, .get_strings = cp_get_strings, .get_ethtool_stats = cp_get_ethtool_stats, + .get_perm_addr = ethtool_op_get_perm_addr, }; static int cp_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) @@ -1773,6 +1773,7 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) for (i = 0; i < 3; i++) ((u16 *) (dev->dev_addr))[i] = le16_to_cpu (read_eeprom (regs, i + 7, addr_len)); + memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); dev->open = cp_open; dev->stop = cp_close; diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index 4c2cf7bbd252..30bee11c48bd 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -552,7 +552,8 @@ const static struct { { "RTL-8100B/8139D", HW_REVID(1, 1, 1, 0, 1, 0, 1), - HasLWake, + HasHltClk /* XXX undocumented? */ + | HasLWake, }, { "RTL-8101", @@ -970,6 +971,7 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev, for (i = 0; i < 3; i++) ((u16 *) (dev->dev_addr))[i] = le16_to_cpu (read_eeprom (ioaddr, i + 7, addr_len)); + memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); /* The Rtl8139-specific entries in the device structure. */ dev->open = rtl8139_open; @@ -2465,6 +2467,7 @@ static struct ethtool_ops rtl8139_ethtool_ops = { .get_strings = rtl8139_get_strings, .get_stats_count = rtl8139_get_stats_count, .get_ethtool_stats = rtl8139_get_ethtool_stats, + .get_perm_addr = ethtool_op_get_perm_addr, }; static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index c748b0e16419..6d4f9ceb0a32 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -475,6 +475,14 @@ config SGI_IOC3_ETH_HW_TX_CSUM the moment only acceleration of IPv4 is supported. This option enables offloading for checksums on transmit. If unsure, say Y. +config MIPS_SIM_NET + tristate "MIPS simulator Network device (EXPERIMENTAL)" + depends on NETDEVICES && MIPS_SIM && EXPERIMENTAL + help + The MIPSNET device is a simple Ethernet network device which is + emulated by the MIPS Simulator. + If you are not using a MIPSsim or are unsure, say N. + config SGI_O2MACE_ETH tristate "SGI O2 MACE Fast Ethernet support" depends on NET_ETHERNET && SGI_IP32=y @@ -1155,38 +1163,74 @@ config IBMVETH be called ibmveth. config IBM_EMAC - bool "IBM PPC4xx EMAC driver support" + tristate "PowerPC 4xx on-chip Ethernet support" depends on 4xx - select CRC32 - ---help--- - This driver supports the IBM PPC4xx EMAC family of on-chip - Ethernet controllers. - -config IBM_EMAC_ERRMSG - bool "Verbose error messages" - depends on IBM_EMAC && BROKEN + help + This driver supports the PowerPC 4xx EMAC family of on-chip + Ethernet controllers. config IBM_EMAC_RXB int "Number of receive buffers" depends on IBM_EMAC - default "128" if IBM_EMAC4 - default "64" + default "128" config IBM_EMAC_TXB int "Number of transmit buffers" depends on IBM_EMAC - default "128" if IBM_EMAC4 - default "8" + default "64" + +config IBM_EMAC_POLL_WEIGHT + int "MAL NAPI polling weight" + depends on IBM_EMAC + default "32" -config IBM_EMAC_FGAP - int "Frame gap" +config IBM_EMAC_RX_COPY_THRESHOLD + int "RX skb copy threshold (bytes)" depends on IBM_EMAC - default "8" + default "256" -config IBM_EMAC_SKBRES - int "Skb reserve amount" +config IBM_EMAC_RX_SKB_HEADROOM + int "Additional RX skb headroom (bytes)" depends on IBM_EMAC default "0" + help + Additional receive skb headroom. Note, that driver + will always reserve at least 2 bytes to make IP header + aligned, so usualy there is no need to add any additional + headroom. + + If unsure, set to 0. + +config IBM_EMAC_PHY_RX_CLK_FIX + bool "PHY Rx clock workaround" + depends on IBM_EMAC && (405EP || 440GX || 440EP) + help + Enable this if EMAC attached to a PHY which doesn't generate + RX clock if there is no link, if this is the case, you will + see "TX disable timeout" or "RX disable timeout" in the system + log. + + If unsure, say N. + +config IBM_EMAC_DEBUG + bool "Debugging" + depends on IBM_EMAC + default n + +config IBM_EMAC_ZMII + bool + depends on IBM_EMAC && (NP405H || NP405L || 44x) + default y + +config IBM_EMAC_RGMII + bool + depends on IBM_EMAC && 440GX + default y + +config IBM_EMAC_TAH + bool + depends on IBM_EMAC && 440GX + default y config NET_PCI bool "EISA, VLB, PCI and on board controllers" @@ -1330,7 +1374,7 @@ config FORCEDETH config CS89x0 tristate "CS89x0 support" - depends on (NET_PCI && (ISA || ARCH_IXDP2X01)) || ARCH_PNX0105 + depends on (NET_PCI && (ISA || ARCH_IXDP2X01)) || ARCH_PNX0105 || MACH_MP1000 ---help--- Support for CS89x0 chipset based Ethernet cards. If you have a network (Ethernet) card of this type, say Y and read the @@ -1767,6 +1811,7 @@ config NE_H8300 controller on the Renesas H8/300 processor. source "drivers/net/fec_8xx/Kconfig" +source "drivers/net/fs_enet/Kconfig" endmenu @@ -2083,6 +2128,7 @@ config SPIDER_NET config GIANFAR tristate "Gianfar Ethernet" depends on 85xx || 83xx + select PHYLIB help This driver supports the Gigabit TSEC on the MPC85xx family of chips, and the FEC on the 8540 @@ -2192,8 +2238,8 @@ config S2IO depends on PCI ---help--- This driver supports the 10Gbe XFrame NIC of S2IO. - For help regarding driver compilation, installation and - tuning please look into ~/drivers/net/s2io/README.txt. + More specific information on configuring the driver is in + <file:Documentation/networking/s2io.txt>. config S2IO_NAPI bool "Use Rx Polling (NAPI) (EXPERIMENTAL)" @@ -2243,6 +2289,20 @@ config ISERIES_VETH tristate "iSeries Virtual Ethernet driver support" depends on PPC_ISERIES +config RIONET + tristate "RapidIO Ethernet over messaging driver support" + depends on NETDEVICES && RAPIDIO + +config RIONET_TX_SIZE + int "Number of outbound queue entries" + depends on RIONET + default "128" + +config RIONET_RX_SIZE + int "Number of inbound queue entries" + depends on RIONET + default "128" + config FDDI bool "FDDI driver support" depends on (PCI || EISA) diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 8aeec9f2495b..7c313cb341b8 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -13,7 +13,7 @@ obj-$(CONFIG_CHELSIO_T1) += chelsio/ obj-$(CONFIG_BONDING) += bonding/ obj-$(CONFIG_GIANFAR) += gianfar_driver.o -gianfar_driver-objs := gianfar.o gianfar_ethtool.o gianfar_phy.o +gianfar_driver-objs := gianfar.o gianfar_ethtool.o gianfar_mii.o # # link order important here @@ -64,6 +64,7 @@ obj-$(CONFIG_SKFP) += skfp/ obj-$(CONFIG_VIA_RHINE) += via-rhine.o obj-$(CONFIG_VIA_VELOCITY) += via-velocity.o obj-$(CONFIG_ADAPTEC_STARFIRE) += starfire.o +obj-$(CONFIG_RIONET) += rionet.o # # end link order section @@ -166,6 +167,7 @@ obj-$(CONFIG_EQUALIZER) += eql.o obj-$(CONFIG_MIPS_JAZZ_SONIC) += jazzsonic.o obj-$(CONFIG_MIPS_GT96100ETH) += gt96100eth.o obj-$(CONFIG_MIPS_AU1X00_ENET) += au1000_eth.o +obj-$(CONFIG_MIPS_SIM_NET) += mipsnet.o obj-$(CONFIG_SGI_IOC3_ETH) += ioc3-eth.o obj-$(CONFIG_DECLANCE) += declance.o obj-$(CONFIG_ATARILANCE) += atarilance.o @@ -201,3 +203,6 @@ obj-$(CONFIG_IRDA) += irda/ obj-$(CONFIG_ETRAX_ETHERNET) += cris/ obj-$(CONFIG_NETCONSOLE) += netconsole.o + +obj-$(CONFIG_FS_ENET) += fs_enet/ + diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c index dbecc6bf7851..b8953de5664a 100644 --- a/drivers/net/acenic.c +++ b/drivers/net/acenic.c @@ -871,10 +871,8 @@ static void ace_init_cleanup(struct net_device *dev) if (ap->info) pci_free_consistent(ap->pdev, sizeof(struct ace_info), ap->info, ap->info_dma); - if (ap->skb) - kfree(ap->skb); - if (ap->trace_buf) - kfree(ap->trace_buf); + kfree(ap->skb); + kfree(ap->trace_buf); if (dev->irq) free_irq(dev->irq, dev); diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c index d9ba8be72af8..d9ba8be72af8 100755..100644 --- a/drivers/net/amd8111e.c +++ b/drivers/net/amd8111e.c diff --git a/drivers/net/amd8111e.h b/drivers/net/amd8111e.h index cfe3a4298822..cfe3a4298822 100755..100644 --- a/drivers/net/amd8111e.h +++ b/drivers/net/amd8111e.h diff --git a/drivers/net/arm/am79c961a.c b/drivers/net/arm/am79c961a.c index c56d86d371a9..3d50e953faaa 100644 --- a/drivers/net/arm/am79c961a.c +++ b/drivers/net/arm/am79c961a.c @@ -29,6 +29,7 @@ #include <asm/system.h> #include <asm/irq.h> +#include <asm/hardware.h> #include <asm/io.h> #define TX_BUFFERS 15 diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c index c82b9cd1c924..332e9953c55c 100644 --- a/drivers/net/au1000_eth.c +++ b/drivers/net/au1000_eth.c @@ -151,13 +151,6 @@ struct au1000_private *au_macs[NUM_ETH_INTERFACES]; SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | \ SUPPORTED_Autoneg -static char *phy_link[] = -{ "unknown", - "10Base2", "10BaseT", - "AUI", - "100BaseT", "100BaseTX", "100BaseFX" -}; - int bcm_5201_init(struct net_device *dev, int phy_addr) { s16 data; @@ -785,6 +778,7 @@ static struct mii_chip_info { {"Broadcom BCM5201 10/100 BaseT PHY",0x0040,0x6212, &bcm_5201_ops,0}, {"Broadcom BCM5221 10/100 BaseT PHY",0x0040,0x61e4, &bcm_5201_ops,0}, {"Broadcom BCM5222 10/100 BaseT PHY",0x0040,0x6322, &bcm_5201_ops,1}, + {"NS DP83847 PHY", 0x2000, 0x5c30, &bcm_5201_ops ,0}, {"AMD 79C901 HomePNA PHY",0x0000,0x35c8, &am79c901_ops,0}, {"AMD 79C874 10/100 BaseT PHY",0x0022,0x561b, &am79c874_ops,0}, {"LSI 80227 10/100 BaseT PHY",0x0016,0xf840, &lsi_80227_ops,0}, @@ -1045,7 +1039,7 @@ found: #endif if (aup->mii->chip_info == NULL) { - printk(KERN_ERR "%s: Au1x No MII transceivers found!\n", + printk(KERN_ERR "%s: Au1x No known MII transceivers found!\n", dev->name); return -1; } @@ -1546,6 +1540,9 @@ au1000_probe(u32 ioaddr, int irq, int port_num) printk(KERN_ERR "%s: out of memory\n", dev->name); goto err_out; } + aup->mii->next = NULL; + aup->mii->chip_info = NULL; + aup->mii->status = 0; aup->mii->mii_control_reg = 0; aup->mii->mii_data_reg = 0; @@ -1609,8 +1606,7 @@ err_out: /* here we should have a valid dev plus aup-> register addresses * so we can reset the mac properly.*/ reset_mac(dev); - if (aup->mii) - kfree(aup->mii); + kfree(aup->mii); for (i = 0; i < NUM_RX_DMA; i++) { if (aup->rx_db_inuse[i]) ReleaseDB(aup, aup->rx_db_inuse[i]); @@ -1809,8 +1805,7 @@ static void __exit au1000_cleanup_module(void) if (dev) { aup = (struct au1000_private *) dev->priv; unregister_netdev(dev); - if (aup->mii) - kfree(aup->mii); + kfree(aup->mii); for (j = 0; j < NUM_RX_DMA; j++) { if (aup->rx_db_inuse[j]) ReleaseDB(aup, aup->rx_db_inuse[j]); diff --git a/drivers/net/b44.c b/drivers/net/b44.c index 94939f570f78..0ee3e27969c6 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -19,6 +19,7 @@ #include <linux/delay.h> #include <linux/init.h> #include <linux/version.h> +#include <linux/dma-mapping.h> #include <asm/uaccess.h> #include <asm/io.h> @@ -106,6 +107,29 @@ static int b44_poll(struct net_device *dev, int *budget); static void b44_poll_controller(struct net_device *dev); #endif +static int dma_desc_align_mask; +static int dma_desc_sync_size; + +static inline void b44_sync_dma_desc_for_device(struct pci_dev *pdev, + dma_addr_t dma_base, + unsigned long offset, + enum dma_data_direction dir) +{ + dma_sync_single_range_for_device(&pdev->dev, dma_base, + offset & dma_desc_align_mask, + dma_desc_sync_size, dir); +} + +static inline void b44_sync_dma_desc_for_cpu(struct pci_dev *pdev, + dma_addr_t dma_base, + unsigned long offset, + enum dma_data_direction dir) +{ + dma_sync_single_range_for_cpu(&pdev->dev, dma_base, + offset & dma_desc_align_mask, + dma_desc_sync_size, dir); +} + static inline unsigned long br32(const struct b44 *bp, unsigned long reg) { return readl(bp->regs + reg); @@ -668,6 +692,11 @@ static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked) dp->ctrl = cpu_to_le32(ctrl); dp->addr = cpu_to_le32((u32) mapping + bp->rx_offset + bp->dma_offset); + if (bp->flags & B44_FLAG_RX_RING_HACK) + b44_sync_dma_desc_for_device(bp->pdev, bp->rx_ring_dma, + dest_idx * sizeof(dp), + DMA_BIDIRECTIONAL); + return RX_PKT_BUF_SZ; } @@ -692,6 +721,11 @@ static void b44_recycle_rx(struct b44 *bp, int src_idx, u32 dest_idx_unmasked) pci_unmap_addr_set(dest_map, mapping, pci_unmap_addr(src_map, mapping)); + if (bp->flags & B44_FLAG_RX_RING_HACK) + b44_sync_dma_desc_for_cpu(bp->pdev, bp->rx_ring_dma, + src_idx * sizeof(src_desc), + DMA_BIDIRECTIONAL); + ctrl = src_desc->ctrl; if (dest_idx == (B44_RX_RING_SIZE - 1)) ctrl |= cpu_to_le32(DESC_CTRL_EOT); @@ -700,8 +734,14 @@ static void b44_recycle_rx(struct b44 *bp, int src_idx, u32 dest_idx_unmasked) dest_desc->ctrl = ctrl; dest_desc->addr = src_desc->addr; + src_map->skb = NULL; + if (bp->flags & B44_FLAG_RX_RING_HACK) + b44_sync_dma_desc_for_device(bp->pdev, bp->rx_ring_dma, + dest_idx * sizeof(dest_desc), + DMA_BIDIRECTIONAL); + pci_dma_sync_single_for_device(bp->pdev, src_desc->addr, RX_PKT_BUF_SZ, PCI_DMA_FROMDEVICE); @@ -959,6 +999,11 @@ static int b44_start_xmit(struct sk_buff *skb, struct net_device *dev) bp->tx_ring[entry].ctrl = cpu_to_le32(ctrl); bp->tx_ring[entry].addr = cpu_to_le32((u32) mapping+bp->dma_offset); + if (bp->flags & B44_FLAG_TX_RING_HACK) + b44_sync_dma_desc_for_device(bp->pdev, bp->tx_ring_dma, + entry * sizeof(bp->tx_ring[0]), + DMA_TO_DEVICE); + entry = NEXT_TX(entry); bp->tx_prod = entry; @@ -1064,6 +1109,16 @@ static void b44_init_rings(struct b44 *bp) memset(bp->rx_ring, 0, B44_RX_RING_BYTES); memset(bp->tx_ring, 0, B44_TX_RING_BYTES); + if (bp->flags & B44_FLAG_RX_RING_HACK) + dma_sync_single_for_device(&bp->pdev->dev, bp->rx_ring_dma, + DMA_TABLE_BYTES, + PCI_DMA_BIDIRECTIONAL); + + if (bp->flags & B44_FLAG_TX_RING_HACK) + dma_sync_single_for_device(&bp->pdev->dev, bp->tx_ring_dma, + DMA_TABLE_BYTES, + PCI_DMA_TODEVICE); + for (i = 0; i < bp->rx_pending; i++) { if (b44_alloc_rx_skb(bp, -1, i) < 0) break; @@ -1076,23 +1131,33 @@ static void b44_init_rings(struct b44 *bp) */ static void b44_free_consistent(struct b44 *bp) { - if (bp->rx_buffers) { - kfree(bp->rx_buffers); - bp->rx_buffers = NULL; - } - if (bp->tx_buffers) { - kfree(bp->tx_buffers); - bp->tx_buffers = NULL; - } + kfree(bp->rx_buffers); + bp->rx_buffers = NULL; + kfree(bp->tx_buffers); + bp->tx_buffers = NULL; if (bp->rx_ring) { - pci_free_consistent(bp->pdev, DMA_TABLE_BYTES, - bp->rx_ring, bp->rx_ring_dma); + if (bp->flags & B44_FLAG_RX_RING_HACK) { + dma_unmap_single(&bp->pdev->dev, bp->rx_ring_dma, + DMA_TABLE_BYTES, + DMA_BIDIRECTIONAL); + kfree(bp->rx_ring); + } else + pci_free_consistent(bp->pdev, DMA_TABLE_BYTES, + bp->rx_ring, bp->rx_ring_dma); bp->rx_ring = NULL; + bp->flags &= ~B44_FLAG_RX_RING_HACK; } if (bp->tx_ring) { - pci_free_consistent(bp->pdev, DMA_TABLE_BYTES, - bp->tx_ring, bp->tx_ring_dma); + if (bp->flags & B44_FLAG_TX_RING_HACK) { + dma_unmap_single(&bp->pdev->dev, bp->tx_ring_dma, + DMA_TABLE_BYTES, + DMA_TO_DEVICE); + kfree(bp->tx_ring); + } else + pci_free_consistent(bp->pdev, DMA_TABLE_BYTES, + bp->tx_ring, bp->tx_ring_dma); bp->tx_ring = NULL; + bp->flags &= ~B44_FLAG_TX_RING_HACK; } } @@ -1118,12 +1183,56 @@ static int b44_alloc_consistent(struct b44 *bp) size = DMA_TABLE_BYTES; bp->rx_ring = pci_alloc_consistent(bp->pdev, size, &bp->rx_ring_dma); - if (!bp->rx_ring) - goto out_err; + if (!bp->rx_ring) { + /* Allocation may have failed due to pci_alloc_consistent + insisting on use of GFP_DMA, which is more restrictive + than necessary... */ + struct dma_desc *rx_ring; + dma_addr_t rx_ring_dma; + + if (!(rx_ring = (struct dma_desc *)kmalloc(size, GFP_KERNEL))) + goto out_err; + + memset(rx_ring, 0, size); + rx_ring_dma = dma_map_single(&bp->pdev->dev, rx_ring, + DMA_TABLE_BYTES, + DMA_BIDIRECTIONAL); + + if (rx_ring_dma + size > B44_DMA_MASK) { + kfree(rx_ring); + goto out_err; + } + + bp->rx_ring = rx_ring; + bp->rx_ring_dma = rx_ring_dma; + bp->flags |= B44_FLAG_RX_RING_HACK; + } bp->tx_ring = pci_alloc_consistent(bp->pdev, size, &bp->tx_ring_dma); - if (!bp->tx_ring) - goto out_err; + if (!bp->tx_ring) { + /* Allocation may have failed due to pci_alloc_consistent + insisting on use of GFP_DMA, which is more restrictive + than necessary... */ + struct dma_desc *tx_ring; + dma_addr_t tx_ring_dma; + + if (!(tx_ring = (struct dma_desc *)kmalloc(size, GFP_KERNEL))) + goto out_err; + + memset(tx_ring, 0, size); + tx_ring_dma = dma_map_single(&bp->pdev->dev, tx_ring, + DMA_TABLE_BYTES, + DMA_TO_DEVICE); + + if (tx_ring_dma + size > B44_DMA_MASK) { + kfree(tx_ring); + goto out_err; + } + + bp->tx_ring = tx_ring; + bp->tx_ring_dma = tx_ring_dma; + bp->flags |= B44_FLAG_TX_RING_HACK; + } return 0; @@ -1507,14 +1616,14 @@ static int b44_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) cmd->advertising = 0; if (bp->flags & B44_FLAG_ADV_10HALF) - cmd->advertising |= ADVERTISE_10HALF; + cmd->advertising |= ADVERTISED_10baseT_Half; if (bp->flags & B44_FLAG_ADV_10FULL) - cmd->advertising |= ADVERTISE_10FULL; + cmd->advertising |= ADVERTISED_10baseT_Full; if (bp->flags & B44_FLAG_ADV_100HALF) - cmd->advertising |= ADVERTISE_100HALF; + cmd->advertising |= ADVERTISED_100baseT_Half; if (bp->flags & B44_FLAG_ADV_100FULL) - cmd->advertising |= ADVERTISE_100FULL; - cmd->advertising |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; + cmd->advertising |= ADVERTISED_100baseT_Full; + cmd->advertising |= ADVERTISED_Pause | ADVERTISED_Asym_Pause; cmd->speed = (bp->flags & B44_FLAG_100_BASE_T) ? SPEED_100 : SPEED_10; cmd->duplex = (bp->flags & B44_FLAG_FULL_DUPLEX) ? @@ -1676,6 +1785,7 @@ static struct ethtool_ops b44_ethtool_ops = { .set_pauseparam = b44_set_pauseparam, .get_msglevel = b44_get_msglevel, .set_msglevel = b44_set_msglevel, + .get_perm_addr = ethtool_op_get_perm_addr, }; static int b44_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) @@ -1718,6 +1828,7 @@ static int __devinit b44_get_invariants(struct b44 *bp) bp->dev->dev_addr[3] = eeprom[80]; bp->dev->dev_addr[4] = eeprom[83]; bp->dev->dev_addr[5] = eeprom[82]; + memcpy(bp->dev->perm_addr, bp->dev->dev_addr, bp->dev->addr_len); bp->phy_addr = eeprom[90] & 0x1f; @@ -1930,6 +2041,8 @@ static int b44_suspend(struct pci_dev *pdev, pm_message_t state) b44_free_rings(bp); spin_unlock_irq(&bp->lock); + + free_irq(dev->irq, dev); pci_disable_device(pdev); return 0; } @@ -1946,6 +2059,9 @@ static int b44_resume(struct pci_dev *pdev) if (!netif_running(dev)) return 0; + if (request_irq(dev->irq, b44_interrupt, SA_SHIRQ, dev->name, dev)) + printk(KERN_ERR PFX "%s: request_irq failed\n", dev->name); + spin_lock_irq(&bp->lock); b44_init_rings(bp); @@ -1971,6 +2087,12 @@ static struct pci_driver b44_driver = { static int __init b44_init(void) { + unsigned int dma_desc_align_size = dma_get_cache_alignment(); + + /* Setup paramaters for syncing RX/TX DMA descriptors */ + dma_desc_align_mask = ~(dma_desc_align_size - 1); + dma_desc_sync_size = max(dma_desc_align_size, sizeof(struct dma_desc)); + return pci_module_init(&b44_driver); } diff --git a/drivers/net/b44.h b/drivers/net/b44.h index 11c40a2e71c7..593cb0ad4100 100644 --- a/drivers/net/b44.h +++ b/drivers/net/b44.h @@ -400,6 +400,8 @@ struct b44 { #define B44_FLAG_ADV_100HALF 0x04000000 #define B44_FLAG_ADV_100FULL 0x08000000 #define B44_FLAG_INTERNAL_PHY 0x10000000 +#define B44_FLAG_RX_RING_HACK 0x20000000 +#define B44_FLAG_TX_RING_HACK 0x40000000 u32 rx_offset; diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c index 0ee28899fb8d..bbca8ae8018c 100644 --- a/drivers/net/bmac.c +++ b/drivers/net/bmac.c @@ -1690,10 +1690,8 @@ static void __exit bmac_exit(void) { macio_unregister_driver(&bmac_driver); - if (bmac_emergency_rxbuf != NULL) { - kfree(bmac_emergency_rxbuf); - bmac_emergency_rxbuf = NULL; - } + kfree(bmac_emergency_rxbuf); + bmac_emergency_rxbuf = NULL; } MODULE_AUTHOR("Randy Gobbel/Paul Mackerras"); diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 3a2ace01e444..11d252318221 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -314,20 +314,16 @@ bnx2_free_mem(struct bnx2 *bp) bp->tx_desc_ring, bp->tx_desc_mapping); bp->tx_desc_ring = NULL; } - if (bp->tx_buf_ring) { - kfree(bp->tx_buf_ring); - bp->tx_buf_ring = NULL; - } + kfree(bp->tx_buf_ring); + bp->tx_buf_ring = NULL; if (bp->rx_desc_ring) { pci_free_consistent(bp->pdev, sizeof(struct rx_bd) * RX_DESC_CNT, bp->rx_desc_ring, bp->rx_desc_mapping); bp->rx_desc_ring = NULL; } - if (bp->rx_buf_ring) { - kfree(bp->rx_buf_ring); - bp->rx_buf_ring = NULL; - } + kfree(bp->rx_buf_ring); + bp->rx_buf_ring = NULL; } static int diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index f264ff162979..8032126fd589 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -4241,6 +4241,43 @@ out: return 0; } +static void bond_activebackup_xmit_copy(struct sk_buff *skb, + struct bonding *bond, + struct slave *slave) +{ + struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC); + struct ethhdr *eth_data; + u8 *hwaddr; + int res; + + if (!skb2) { + printk(KERN_ERR DRV_NAME ": Error: " + "bond_activebackup_xmit_copy(): skb_copy() failed\n"); + return; + } + + skb2->mac.raw = (unsigned char *)skb2->data; + eth_data = eth_hdr(skb2); + + /* Pick an appropriate source MAC address + * -- use slave's perm MAC addr, unless used by bond + * -- otherwise, borrow active slave's perm MAC addr + * since that will not be used + */ + hwaddr = slave->perm_hwaddr; + if (!memcmp(eth_data->h_source, hwaddr, ETH_ALEN)) + hwaddr = bond->curr_active_slave->perm_hwaddr; + + /* Set source MAC address appropriately */ + memcpy(eth_data->h_source, hwaddr, ETH_ALEN); + + res = bond_dev_queue_xmit(bond, skb2, slave->dev); + if (res) + dev_kfree_skb(skb2); + + return; +} + /* * in active-backup mode, we know that bond->curr_active_slave is always valid if * the bond has a usable interface. @@ -4257,10 +4294,26 @@ static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *bond_d goto out; } - if (bond->curr_active_slave) { /* one usable interface */ - res = bond_dev_queue_xmit(bond, skb, bond->curr_active_slave->dev); + if (!bond->curr_active_slave) + goto out; + + /* Xmit IGMP frames on all slaves to ensure rapid fail-over + for multicast traffic on snooping switches */ + if (skb->protocol == __constant_htons(ETH_P_IP) && + skb->nh.iph->protocol == IPPROTO_IGMP) { + struct slave *slave, *active_slave; + int i; + + active_slave = bond->curr_active_slave; + bond_for_each_slave_from_to(bond, slave, i, active_slave->next, + active_slave->prev) + if (IS_UP(slave->dev) && + (slave->link == BOND_LINK_UP)) + bond_activebackup_xmit_copy(skb, bond, slave); } + res = bond_dev_queue_xmit(bond, skb, bond->curr_active_slave->dev); + out: if (res) { /* no suitable interface, frame not sent */ diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c index 2e617424d3fb..50f43dbf31ae 100644 --- a/drivers/net/cassini.c +++ b/drivers/net/cassini.c @@ -489,7 +489,7 @@ static int cas_page_free(struct cas *cp, cas_page_t *page) /* local page allocation routines for the receive buffers. jumbo pages * require at least 8K contiguous and 8K aligned buffers. */ -static cas_page_t *cas_page_alloc(struct cas *cp, const int flags) +static cas_page_t *cas_page_alloc(struct cas *cp, const gfp_t flags) { cas_page_t *page; @@ -561,7 +561,7 @@ static void cas_spare_free(struct cas *cp) } /* replenish spares if needed */ -static void cas_spare_recover(struct cas *cp, const int flags) +static void cas_spare_recover(struct cas *cp, const gfp_t flags) { struct list_head list, *elem, *tmp; int needed, i; diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c index a6078ad9b654..bfdae10036ed 100644 --- a/drivers/net/cs89x0.c +++ b/drivers/net/cs89x0.c @@ -182,6 +182,10 @@ static unsigned int cs8900_irq_map[] = {IRQ_IXDP2X01_CS8900, 0, 0, 0}; #define CIRRUS_DEFAULT_IRQ VH_INTC_INT_NUM_CASCADED_INTERRUPT_1 /* Event inputs bank 1 - ID 35/bit 3 */ static unsigned int netcard_portlist[] __initdata = {CIRRUS_DEFAULT_BASE, 0}; static unsigned int cs8900_irq_map[] = {CIRRUS_DEFAULT_IRQ, 0, 0, 0}; +#elif defined(CONFIG_MACH_MP1000) +#include <asm/arch/mp1000-seprom.h> +static unsigned int netcard_portlist[] __initdata = {MP1000_EIO_BASE+0x300, 0}; +static unsigned int cs8900_irq_map[] = {IRQ_EINT3,0,0,0}; #else static unsigned int netcard_portlist[] __initdata = { 0x300, 0x320, 0x340, 0x360, 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0}; @@ -590,6 +594,10 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular) cnt -= j; } } else +#elif defined(CONFIG_MACH_MP1000) + if (1) { + memcpy(dev->dev_addr, get_eeprom_mac_address(), ETH_ALEN); + } else #endif if ((readreg(dev, PP_SelfST) & (EEPROM_OK | EEPROM_PRESENT)) == @@ -649,6 +657,10 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular) if (1) { printk(KERN_NOTICE "cs89x0: No EEPROM on HiCO.SH4\n"); } else +#elif defined(CONFIG_MACH_MP1000) + if (1) { + lp->force |= FORCE_RJ45; + } else #endif if ((readreg(dev, PP_SelfST) & EEPROM_PRESENT) == 0) printk(KERN_WARNING "cs89x0: No EEPROM, relying on command line....\n"); @@ -1231,7 +1243,7 @@ net_open(struct net_device *dev) else #endif { -#if !defined(CONFIG_ARCH_IXDP2X01) && !defined(CONFIG_ARCH_PNX0105) +#if !defined(CONFIG_ARCH_IXDP2X01) && !defined(CONFIG_ARCH_PNX0105) && !defined(CONFIG_MACH_MP1000) if (((1 << dev->irq) & lp->irq_map) == 0) { printk(KERN_ERR "%s: IRQ %d is not in our map of allowable IRQs, which is %x\n", dev->name, dev->irq, lp->irq_map); diff --git a/drivers/net/cs89x0.h b/drivers/net/cs89x0.h index decea264f121..f19d1ebe0183 100644 --- a/drivers/net/cs89x0.h +++ b/drivers/net/cs89x0.h @@ -16,7 +16,7 @@ #include <linux/config.h> -#if defined(CONFIG_ARCH_IXDP2X01) || defined(CONFIG_ARCH_PNX0105) +#if defined(CONFIG_ARCH_IXDP2X01) || defined(CONFIG_ARCH_PNX0105) || defined (CONFIG_MACH_MP1000) /* IXDP2401/IXDP2801 uses dword-aligned register addressing */ #define CS89x0_PORT(reg) ((reg) * 2) #else diff --git a/drivers/net/declance.c b/drivers/net/declance.c index 521c83137bf6..f130bdab3fd3 100644 --- a/drivers/net/declance.c +++ b/drivers/net/declance.c @@ -5,7 +5,7 @@ * * adopted from sunlance.c by Richard van den Berg * - * Copyright (C) 2002, 2003 Maciej W. Rozycki + * Copyright (C) 2002, 2003, 2005 Maciej W. Rozycki * * additional sources: * - PMAD-AA TURBOchannel Ethernet Module Functional Specification, @@ -57,13 +57,15 @@ #include <linux/string.h> #include <asm/addrspace.h> +#include <asm/system.h> + #include <asm/dec/interrupts.h> #include <asm/dec/ioasic.h> #include <asm/dec/ioasic_addrs.h> #include <asm/dec/kn01.h> #include <asm/dec/machtype.h> +#include <asm/dec/system.h> #include <asm/dec/tc.h> -#include <asm/system.h> static char version[] __devinitdata = "declance.c: v0.009 by Linux MIPS DECstation task force\n"; @@ -79,10 +81,6 @@ MODULE_LICENSE("GPL"); #define PMAD_LANCE 2 #define PMAX_LANCE 3 -#ifndef CONFIG_TC -unsigned long system_base; -unsigned long dmaptr; -#endif #define LE_CSR0 0 #define LE_CSR1 1 @@ -237,7 +235,7 @@ struct lance_init_block { /* * This works *only* for the ring descriptors */ -#define LANCE_ADDR(x) (PHYSADDR(x) >> 1) +#define LANCE_ADDR(x) (CPHYSADDR(x) >> 1) struct lance_private { struct net_device *next; @@ -697,12 +695,13 @@ out: spin_unlock(&lp->lock); } -static void lance_dma_merr_int(const int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t lance_dma_merr_int(const int irq, void *dev_id, + struct pt_regs *regs) { struct net_device *dev = (struct net_device *) dev_id; printk("%s: DMA error\n", dev->name); + return IRQ_HANDLED; } static irqreturn_t @@ -1026,10 +1025,6 @@ static int __init dec_lance_init(const int type, const int slot) unsigned long esar_base; unsigned char *esar; -#ifndef CONFIG_TC - system_base = KN01_LANCE_BASE; -#endif - if (dec_lance_debug && version_printed++ == 0) printk(version); @@ -1062,16 +1057,16 @@ static int __init dec_lance_init(const int type, const int slot) switch (type) { #ifdef CONFIG_TC case ASIC_LANCE: - dev->base_addr = system_base + IOASIC_LANCE; + dev->base_addr = CKSEG1ADDR(dec_kn_slot_base + IOASIC_LANCE); /* buffer space for the on-board LANCE shared memory */ /* * FIXME: ugly hack! */ - dev->mem_start = KSEG1ADDR(0x00020000); + dev->mem_start = CKSEG1ADDR(0x00020000); dev->mem_end = dev->mem_start + 0x00020000; dev->irq = dec_interrupt[DEC_IRQ_LANCE]; - esar_base = system_base + IOASIC_ESAR; + esar_base = CKSEG1ADDR(dec_kn_slot_base + IOASIC_ESAR); /* Workaround crash with booting KN04 2.1k from Disk */ memset((void *)dev->mem_start, 0, @@ -1101,14 +1096,14 @@ static int __init dec_lance_init(const int type, const int slot) /* Setup I/O ASIC LANCE DMA. */ lp->dma_irq = dec_interrupt[DEC_IRQ_LANCE_MERR]; ioasic_write(IO_REG_LANCE_DMA_P, - PHYSADDR(dev->mem_start) << 3); + CPHYSADDR(dev->mem_start) << 3); break; case PMAD_LANCE: claim_tc_card(slot); - dev->mem_start = get_tc_base_addr(slot); + dev->mem_start = CKSEG1ADDR(get_tc_base_addr(slot)); dev->base_addr = dev->mem_start + 0x100000; dev->irq = get_tc_irq_nr(slot); esar_base = dev->mem_start + 0x1c0002; @@ -1137,9 +1132,9 @@ static int __init dec_lance_init(const int type, const int slot) case PMAX_LANCE: dev->irq = dec_interrupt[DEC_IRQ_LANCE]; - dev->base_addr = KN01_LANCE_BASE; - dev->mem_start = KN01_LANCE_BASE + 0x01000000; - esar_base = KN01_RTC_BASE + 1; + dev->base_addr = CKSEG1ADDR(KN01_SLOT_BASE + KN01_LANCE); + dev->mem_start = CKSEG1ADDR(KN01_SLOT_BASE + KN01_LANCE_MEM); + esar_base = CKSEG1ADDR(KN01_SLOT_BASE + KN01_ESAR + 1); lp->dma_irq = -1; /* diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c index e54fc10f6846..abce1f730d00 100644 --- a/drivers/net/dm9000.c +++ b/drivers/net/dm9000.c @@ -1140,11 +1140,11 @@ dm9000_phy_write(struct net_device *dev, int phyaddr_unused, int reg, int value) } static int -dm9000_drv_suspend(struct device *dev, pm_message_t state, u32 level) +dm9000_drv_suspend(struct device *dev, pm_message_t state) { struct net_device *ndev = dev_get_drvdata(dev); - if (ndev && level == SUSPEND_DISABLE) { + if (ndev) { if (netif_running(ndev)) { netif_device_detach(ndev); dm9000_shutdown(ndev); @@ -1154,12 +1154,12 @@ dm9000_drv_suspend(struct device *dev, pm_message_t state, u32 level) } static int -dm9000_drv_resume(struct device *dev, u32 level) +dm9000_drv_resume(struct device *dev) { struct net_device *ndev = dev_get_drvdata(dev); board_info_t *db = (board_info_t *) ndev->priv; - if (ndev && level == RESUME_ENABLE) { + if (ndev) { if (netif_running(ndev)) { dm9000_reset(db); diff --git a/drivers/net/e100.c b/drivers/net/e100.c index 40887f09b681..eb169a8e8773 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -2201,6 +2201,7 @@ static struct ethtool_ops e100_ethtool_ops = { .phys_id = e100_phys_id, .get_stats_count = e100_get_stats_count, .get_ethtool_stats = e100_get_ethtool_stats, + .get_perm_addr = ethtool_op_get_perm_addr, }; static int e100_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) @@ -2351,7 +2352,8 @@ static int __devinit e100_probe(struct pci_dev *pdev, e100_phy_init(nic); memcpy(netdev->dev_addr, nic->eeprom, ETH_ALEN); - if(!is_valid_ether_addr(netdev->dev_addr)) { + memcpy(netdev->perm_addr, nic->eeprom, ETH_ALEN); + if(!is_valid_ether_addr(netdev->perm_addr)) { DPRINTK(PROBE, ERR, "Invalid MAC address from " "EEPROM, aborting.\n"); err = -EAGAIN; diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h index 092757bc721f..3f653a93e1bc 100644 --- a/drivers/net/e1000/e1000.h +++ b/drivers/net/e1000/e1000.h @@ -72,6 +72,10 @@ #include <linux/mii.h> #include <linux/ethtool.h> #include <linux/if_vlan.h> +#ifdef CONFIG_E1000_MQ +#include <linux/cpu.h> +#include <linux/smp.h> +#endif #define BAR_0 0 #define BAR_1 1 @@ -165,10 +169,33 @@ struct e1000_buffer { uint16_t next_to_watch; }; -struct e1000_ps_page { struct page *ps_page[MAX_PS_BUFFERS]; }; -struct e1000_ps_page_dma { uint64_t ps_page_dma[MAX_PS_BUFFERS]; }; +struct e1000_ps_page { struct page *ps_page[PS_PAGE_BUFFERS]; }; +struct e1000_ps_page_dma { uint64_t ps_page_dma[PS_PAGE_BUFFERS]; }; + +struct e1000_tx_ring { + /* pointer to the descriptor ring memory */ + void *desc; + /* physical address of the descriptor ring */ + dma_addr_t dma; + /* length of descriptor ring in bytes */ + unsigned int size; + /* number of descriptors in the ring */ + unsigned int count; + /* next descriptor to associate a buffer with */ + unsigned int next_to_use; + /* next descriptor to check for DD status bit */ + unsigned int next_to_clean; + /* array of buffer information structs */ + struct e1000_buffer *buffer_info; + + struct e1000_buffer previous_buffer_info; + spinlock_t tx_lock; + uint16_t tdh; + uint16_t tdt; + uint64_t pkt; +}; -struct e1000_desc_ring { +struct e1000_rx_ring { /* pointer to the descriptor ring memory */ void *desc; /* physical address of the descriptor ring */ @@ -186,6 +213,10 @@ struct e1000_desc_ring { /* arrays of page information for packet split */ struct e1000_ps_page *ps_page; struct e1000_ps_page_dma *ps_page_dma; + + uint16_t rdh; + uint16_t rdt; + uint64_t pkt; }; #define E1000_DESC_UNUSED(R) \ @@ -227,9 +258,10 @@ struct e1000_adapter { unsigned long led_status; /* TX */ - struct e1000_desc_ring tx_ring; - struct e1000_buffer previous_buffer_info; - spinlock_t tx_lock; + struct e1000_tx_ring *tx_ring; /* One per active queue */ +#ifdef CONFIG_E1000_MQ + struct e1000_tx_ring **cpu_tx_ring; /* per-cpu */ +#endif uint32_t txd_cmd; uint32_t tx_int_delay; uint32_t tx_abs_int_delay; @@ -246,19 +278,33 @@ struct e1000_adapter { /* RX */ #ifdef CONFIG_E1000_NAPI - boolean_t (*clean_rx) (struct e1000_adapter *adapter, int *work_done, - int work_to_do); + boolean_t (*clean_rx) (struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring, + int *work_done, int work_to_do); #else - boolean_t (*clean_rx) (struct e1000_adapter *adapter); + boolean_t (*clean_rx) (struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring); #endif - void (*alloc_rx_buf) (struct e1000_adapter *adapter); - struct e1000_desc_ring rx_ring; + void (*alloc_rx_buf) (struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring); + struct e1000_rx_ring *rx_ring; /* One per active queue */ +#ifdef CONFIG_E1000_NAPI + struct net_device *polling_netdev; /* One per active queue */ +#endif +#ifdef CONFIG_E1000_MQ + struct net_device **cpu_netdev; /* per-cpu */ + struct call_async_data_struct rx_sched_call_data; + int cpu_for_queue[4]; +#endif + int num_queues; + uint64_t hw_csum_err; uint64_t hw_csum_good; + uint64_t rx_hdr_split; uint32_t rx_int_delay; uint32_t rx_abs_int_delay; boolean_t rx_csum; - boolean_t rx_ps; + unsigned int rx_ps_pages; uint32_t gorcl; uint64_t gorcl_old; uint16_t rx_ps_bsize0; @@ -278,8 +324,8 @@ struct e1000_adapter { struct e1000_phy_stats phy_stats; uint32_t test_icr; - struct e1000_desc_ring test_tx_ring; - struct e1000_desc_ring test_rx_ring; + struct e1000_tx_ring test_tx_ring; + struct e1000_rx_ring test_rx_ring; int msg_enable; diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index f133ff0b0b94..9c7feaeaa6a4 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -39,10 +39,10 @@ extern int e1000_up(struct e1000_adapter *adapter); extern void e1000_down(struct e1000_adapter *adapter); extern void e1000_reset(struct e1000_adapter *adapter); extern int e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx); -extern int e1000_setup_rx_resources(struct e1000_adapter *adapter); -extern int e1000_setup_tx_resources(struct e1000_adapter *adapter); -extern void e1000_free_rx_resources(struct e1000_adapter *adapter); -extern void e1000_free_tx_resources(struct e1000_adapter *adapter); +extern int e1000_setup_all_rx_resources(struct e1000_adapter *adapter); +extern int e1000_setup_all_tx_resources(struct e1000_adapter *adapter); +extern void e1000_free_all_rx_resources(struct e1000_adapter *adapter); +extern void e1000_free_all_tx_resources(struct e1000_adapter *adapter); extern void e1000_update_stats(struct e1000_adapter *adapter); struct e1000_stats { @@ -91,7 +91,8 @@ static const struct e1000_stats e1000_gstrings_stats[] = { { "tx_flow_control_xoff", E1000_STAT(stats.xofftxc) }, { "rx_long_byte_count", E1000_STAT(stats.gorcl) }, { "rx_csum_offload_good", E1000_STAT(hw_csum_good) }, - { "rx_csum_offload_errors", E1000_STAT(hw_csum_err) } + { "rx_csum_offload_errors", E1000_STAT(hw_csum_err) }, + { "rx_header_split", E1000_STAT(rx_hdr_split) }, }; #define E1000_STATS_LEN \ sizeof(e1000_gstrings_stats) / sizeof(struct e1000_stats) @@ -546,8 +547,10 @@ e1000_set_eeprom(struct net_device *netdev, ret_val = e1000_write_eeprom(hw, first_word, last_word - first_word + 1, eeprom_buff); - /* Update the checksum over the first part of the EEPROM if needed */ - if((ret_val == 0) && first_word <= EEPROM_CHECKSUM_REG) + /* Update the checksum over the first part of the EEPROM if needed + * and flush shadow RAM for 82573 conrollers */ + if((ret_val == 0) && ((first_word <= EEPROM_CHECKSUM_REG) || + (hw->mac_type == e1000_82573))) e1000_update_eeprom_checksum(hw); kfree(eeprom_buff); @@ -576,8 +579,8 @@ e1000_get_ringparam(struct net_device *netdev, { struct e1000_adapter *adapter = netdev_priv(netdev); e1000_mac_type mac_type = adapter->hw.mac_type; - struct e1000_desc_ring *txdr = &adapter->tx_ring; - struct e1000_desc_ring *rxdr = &adapter->rx_ring; + struct e1000_tx_ring *txdr = adapter->tx_ring; + struct e1000_rx_ring *rxdr = adapter->rx_ring; ring->rx_max_pending = (mac_type < e1000_82544) ? E1000_MAX_RXD : E1000_MAX_82544_RXD; @@ -597,20 +600,40 @@ e1000_set_ringparam(struct net_device *netdev, { struct e1000_adapter *adapter = netdev_priv(netdev); e1000_mac_type mac_type = adapter->hw.mac_type; - struct e1000_desc_ring *txdr = &adapter->tx_ring; - struct e1000_desc_ring *rxdr = &adapter->rx_ring; - struct e1000_desc_ring tx_old, tx_new, rx_old, rx_new; - int err; + struct e1000_tx_ring *txdr, *tx_old, *tx_new; + struct e1000_rx_ring *rxdr, *rx_old, *rx_new; + int i, err, tx_ring_size, rx_ring_size; + + tx_ring_size = sizeof(struct e1000_tx_ring) * adapter->num_queues; + rx_ring_size = sizeof(struct e1000_rx_ring) * adapter->num_queues; + + if (netif_running(adapter->netdev)) + e1000_down(adapter); tx_old = adapter->tx_ring; rx_old = adapter->rx_ring; + adapter->tx_ring = kmalloc(tx_ring_size, GFP_KERNEL); + if (!adapter->tx_ring) { + err = -ENOMEM; + goto err_setup_rx; + } + memset(adapter->tx_ring, 0, tx_ring_size); + + adapter->rx_ring = kmalloc(rx_ring_size, GFP_KERNEL); + if (!adapter->rx_ring) { + kfree(adapter->tx_ring); + err = -ENOMEM; + goto err_setup_rx; + } + memset(adapter->rx_ring, 0, rx_ring_size); + + txdr = adapter->tx_ring; + rxdr = adapter->rx_ring; + if((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) return -EINVAL; - if(netif_running(adapter->netdev)) - e1000_down(adapter); - rxdr->count = max(ring->rx_pending,(uint32_t)E1000_MIN_RXD); rxdr->count = min(rxdr->count,(uint32_t)(mac_type < e1000_82544 ? E1000_MAX_RXD : E1000_MAX_82544_RXD)); @@ -621,11 +644,16 @@ e1000_set_ringparam(struct net_device *netdev, E1000_MAX_TXD : E1000_MAX_82544_TXD)); E1000_ROUNDUP(txdr->count, REQ_TX_DESCRIPTOR_MULTIPLE); + for (i = 0; i < adapter->num_queues; i++) { + txdr[i].count = txdr->count; + rxdr[i].count = rxdr->count; + } + if(netif_running(adapter->netdev)) { /* Try to get new resources before deleting old */ - if((err = e1000_setup_rx_resources(adapter))) + if ((err = e1000_setup_all_rx_resources(adapter))) goto err_setup_rx; - if((err = e1000_setup_tx_resources(adapter))) + if ((err = e1000_setup_all_tx_resources(adapter))) goto err_setup_tx; /* save the new, restore the old in order to free it, @@ -635,8 +663,10 @@ e1000_set_ringparam(struct net_device *netdev, tx_new = adapter->tx_ring; adapter->rx_ring = rx_old; adapter->tx_ring = tx_old; - e1000_free_rx_resources(adapter); - e1000_free_tx_resources(adapter); + e1000_free_all_rx_resources(adapter); + e1000_free_all_tx_resources(adapter); + kfree(tx_old); + kfree(rx_old); adapter->rx_ring = rx_new; adapter->tx_ring = tx_new; if((err = e1000_up(adapter))) @@ -645,7 +675,7 @@ e1000_set_ringparam(struct net_device *netdev, return 0; err_setup_tx: - e1000_free_rx_resources(adapter); + e1000_free_all_rx_resources(adapter); err_setup_rx: adapter->rx_ring = rx_old; adapter->tx_ring = tx_old; @@ -696,6 +726,11 @@ e1000_reg_test(struct e1000_adapter *adapter, uint64_t *data) * Some bits that get toggled are ignored. */ switch (adapter->hw.mac_type) { + /* there are several bits on newer hardware that are r/w */ + case e1000_82571: + case e1000_82572: + toggle = 0x7FFFF3FF; + break; case e1000_82573: toggle = 0x7FFFF033; break; @@ -898,8 +933,8 @@ e1000_intr_test(struct e1000_adapter *adapter, uint64_t *data) static void e1000_free_desc_rings(struct e1000_adapter *adapter) { - struct e1000_desc_ring *txdr = &adapter->test_tx_ring; - struct e1000_desc_ring *rxdr = &adapter->test_rx_ring; + struct e1000_tx_ring *txdr = &adapter->test_tx_ring; + struct e1000_rx_ring *rxdr = &adapter->test_rx_ring; struct pci_dev *pdev = adapter->pdev; int i; @@ -930,19 +965,16 @@ e1000_free_desc_rings(struct e1000_adapter *adapter) if(rxdr->desc) pci_free_consistent(pdev, rxdr->size, rxdr->desc, rxdr->dma); - if(txdr->buffer_info) - kfree(txdr->buffer_info); - if(rxdr->buffer_info) - kfree(rxdr->buffer_info); - + kfree(txdr->buffer_info); + kfree(rxdr->buffer_info); return; } static int e1000_setup_desc_rings(struct e1000_adapter *adapter) { - struct e1000_desc_ring *txdr = &adapter->test_tx_ring; - struct e1000_desc_ring *rxdr = &adapter->test_rx_ring; + struct e1000_tx_ring *txdr = &adapter->test_tx_ring; + struct e1000_rx_ring *rxdr = &adapter->test_rx_ring; struct pci_dev *pdev = adapter->pdev; uint32_t rctl; int size, i, ret_val; @@ -1245,6 +1277,8 @@ e1000_set_phy_loopback(struct e1000_adapter *adapter) case e1000_82541_rev_2: case e1000_82547: case e1000_82547_rev_2: + case e1000_82571: + case e1000_82572: case e1000_82573: return e1000_integrated_phy_loopback(adapter); break; @@ -1340,8 +1374,8 @@ e1000_check_lbtest_frame(struct sk_buff *skb, unsigned int frame_size) static int e1000_run_loopback_test(struct e1000_adapter *adapter) { - struct e1000_desc_ring *txdr = &adapter->test_tx_ring; - struct e1000_desc_ring *rxdr = &adapter->test_rx_ring; + struct e1000_tx_ring *txdr = &adapter->test_tx_ring; + struct e1000_rx_ring *rxdr = &adapter->test_rx_ring; struct pci_dev *pdev = adapter->pdev; int i, j, k, l, lc, good_cnt, ret_val=0; unsigned long time; @@ -1509,6 +1543,7 @@ e1000_diag_test(struct net_device *netdev, data[2] = 0; data[3] = 0; } + msleep_interruptible(4 * 1000); } static void @@ -1625,7 +1660,7 @@ e1000_phys_id(struct net_device *netdev, uint32_t data) if(!data || data > (uint32_t)(MAX_SCHEDULE_TIMEOUT / HZ)) data = (uint32_t)(MAX_SCHEDULE_TIMEOUT / HZ); - if(adapter->hw.mac_type < e1000_82573) { + if(adapter->hw.mac_type < e1000_82571) { if(!adapter->blink_timer.function) { init_timer(&adapter->blink_timer); adapter->blink_timer.function = e1000_led_blink_callback; @@ -1739,6 +1774,7 @@ struct ethtool_ops e1000_ethtool_ops = { .phys_id = e1000_phys_id, .get_stats_count = e1000_get_stats_count, .get_ethtool_stats = e1000_get_ethtool_stats, + .get_perm_addr = ethtool_op_get_perm_addr, }; void e1000_set_ethtool_ops(struct net_device *netdev) diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c index 045f5426ab9a..8fc876da43b4 100644 --- a/drivers/net/e1000/e1000_hw.c +++ b/drivers/net/e1000/e1000_hw.c @@ -83,14 +83,14 @@ uint16_t e1000_igp_cable_length_table[IGP01E1000_AGC_LENGTH_TABLE_SIZE] = static const uint16_t e1000_igp_2_cable_length_table[IGP02E1000_AGC_LENGTH_TABLE_SIZE] = - { 8, 13, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, - 22, 24, 27, 30, 32, 35, 37, 40, 42, 44, 47, 49, 51, 54, 56, 58, - 32, 35, 38, 41, 44, 47, 50, 53, 55, 58, 61, 63, 66, 69, 71, 74, - 43, 47, 51, 54, 58, 61, 64, 67, 71, 74, 77, 80, 82, 85, 88, 90, - 57, 62, 66, 70, 74, 77, 81, 85, 88, 91, 94, 97, 100, 103, 106, 108, - 73, 78, 82, 87, 91, 95, 98, 102, 105, 109, 112, 114, 117, 119, 122, 124, - 91, 96, 101, 105, 109, 113, 116, 119, 122, 125, 127, 128, 128, 128, 128, 128, - 108, 113, 117, 121, 124, 127, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128}; + { 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 8, 11, 13, 16, 18, 21, + 0, 0, 0, 3, 6, 10, 13, 16, 19, 23, 26, 29, 32, 35, 38, 41, + 6, 10, 14, 18, 22, 26, 30, 33, 37, 41, 44, 48, 51, 54, 58, 61, + 21, 26, 31, 35, 40, 44, 49, 53, 57, 61, 65, 68, 72, 75, 79, 82, + 40, 45, 51, 56, 61, 66, 70, 75, 79, 83, 87, 91, 94, 98, 101, 104, + 60, 66, 72, 77, 82, 87, 92, 96, 100, 104, 108, 111, 114, 117, 119, 121, + 83, 89, 95, 100, 105, 109, 113, 116, 119, 122, 124, + 104, 109, 114, 118, 121, 124}; /****************************************************************************** @@ -286,7 +286,6 @@ e1000_set_mac_type(struct e1000_hw *hw) case E1000_DEV_ID_82546GB_FIBER: case E1000_DEV_ID_82546GB_SERDES: case E1000_DEV_ID_82546GB_PCIE: - case E1000_DEV_ID_82546GB_QUAD_COPPER: hw->mac_type = e1000_82546_rev_3; break; case E1000_DEV_ID_82541EI: @@ -305,8 +304,19 @@ e1000_set_mac_type(struct e1000_hw *hw) case E1000_DEV_ID_82547GI: hw->mac_type = e1000_82547_rev_2; break; + case E1000_DEV_ID_82571EB_COPPER: + case E1000_DEV_ID_82571EB_FIBER: + case E1000_DEV_ID_82571EB_SERDES: + hw->mac_type = e1000_82571; + break; + case E1000_DEV_ID_82572EI_COPPER: + case E1000_DEV_ID_82572EI_FIBER: + case E1000_DEV_ID_82572EI_SERDES: + hw->mac_type = e1000_82572; + break; case E1000_DEV_ID_82573E: case E1000_DEV_ID_82573E_IAMT: + case E1000_DEV_ID_82573L: hw->mac_type = e1000_82573; break; default: @@ -315,6 +325,8 @@ e1000_set_mac_type(struct e1000_hw *hw) } switch(hw->mac_type) { + case e1000_82571: + case e1000_82572: case e1000_82573: hw->eeprom_semaphore_present = TRUE; /* fall through */ @@ -351,6 +363,8 @@ e1000_set_media_type(struct e1000_hw *hw) switch (hw->device_id) { case E1000_DEV_ID_82545GM_SERDES: case E1000_DEV_ID_82546GB_SERDES: + case E1000_DEV_ID_82571EB_SERDES: + case E1000_DEV_ID_82572EI_SERDES: hw->media_type = e1000_media_type_internal_serdes; break; default: @@ -523,6 +537,8 @@ e1000_reset_hw(struct e1000_hw *hw) E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext); E1000_WRITE_FLUSH(hw); /* fall through */ + case e1000_82571: + case e1000_82572: ret_val = e1000_get_auto_rd_done(hw); if(ret_val) /* We don't want to continue accessing MAC registers. */ @@ -683,6 +699,9 @@ e1000_init_hw(struct e1000_hw *hw) switch (hw->mac_type) { default: break; + case e1000_82571: + case e1000_82572: + ctrl |= (1 << 22); case e1000_82573: ctrl |= E1000_TXDCTL_COUNT_DESC; break; @@ -694,6 +713,26 @@ e1000_init_hw(struct e1000_hw *hw) e1000_enable_tx_pkt_filtering(hw); } + switch (hw->mac_type) { + default: + break; + case e1000_82571: + case e1000_82572: + ctrl = E1000_READ_REG(hw, TXDCTL1); + ctrl &= ~E1000_TXDCTL_WTHRESH; + ctrl |= E1000_TXDCTL_COUNT_DESC | E1000_TXDCTL_FULL_TX_DESC_WB; + ctrl |= (1 << 22); + E1000_WRITE_REG(hw, TXDCTL1, ctrl); + break; + } + + + + if (hw->mac_type == e1000_82573) { + uint32_t gcr = E1000_READ_REG(hw, GCR); + gcr |= E1000_GCR_L1_ACT_WITHOUT_L0S_RX; + E1000_WRITE_REG(hw, GCR, gcr); + } /* Clear all of the statistics registers (clear on read). It is * important that we do this after we have tried to establish link @@ -878,6 +917,14 @@ e1000_setup_fiber_serdes_link(struct e1000_hw *hw) DEBUGFUNC("e1000_setup_fiber_serdes_link"); + /* On 82571 and 82572 Fiber connections, SerDes loopback mode persists + * until explicitly turned off or a power cycle is performed. A read to + * the register does not indicate its status. Therefore, we ensure + * loopback mode is disabled during initialization. + */ + if (hw->mac_type == e1000_82571 || hw->mac_type == e1000_82572) + E1000_WRITE_REG(hw, SCTL, E1000_DISABLE_SERDES_LOOPBACK); + /* On adapters with a MAC newer than 82544, SW Defineable pin 1 will be * set when the optics detect a signal. On older adapters, it will be * cleared when there is a signal. This applies to fiber media only. @@ -2943,6 +2990,8 @@ e1000_phy_reset(struct e1000_hw *hw) switch (hw->mac_type) { case e1000_82541_rev_2: + case e1000_82571: + case e1000_82572: ret_val = e1000_phy_hw_reset(hw); if(ret_val) return ret_val; @@ -2981,6 +3030,16 @@ e1000_detect_gig_phy(struct e1000_hw *hw) DEBUGFUNC("e1000_detect_gig_phy"); + /* The 82571 firmware may still be configuring the PHY. In this + * case, we cannot access the PHY until the configuration is done. So + * we explicitly set the PHY values. */ + if(hw->mac_type == e1000_82571 || + hw->mac_type == e1000_82572) { + hw->phy_id = IGP01E1000_I_PHY_ID; + hw->phy_type = e1000_phy_igp_2; + return E1000_SUCCESS; + } + /* Read the PHY ID Registers to identify which PHY is onboard. */ ret_val = e1000_read_phy_reg(hw, PHY_ID1, &phy_id_high); if(ret_val) @@ -3334,6 +3393,21 @@ e1000_init_eeprom_params(struct e1000_hw *hw) eeprom->use_eerd = FALSE; eeprom->use_eewr = FALSE; break; + case e1000_82571: + case e1000_82572: + eeprom->type = e1000_eeprom_spi; + eeprom->opcode_bits = 8; + eeprom->delay_usec = 1; + if (eecd & E1000_EECD_ADDR_BITS) { + eeprom->page_size = 32; + eeprom->address_bits = 16; + } else { + eeprom->page_size = 8; + eeprom->address_bits = 8; + } + eeprom->use_eerd = FALSE; + eeprom->use_eewr = FALSE; + break; case e1000_82573: eeprom->type = e1000_eeprom_spi; eeprom->opcode_bits = 8; @@ -3543,25 +3617,26 @@ e1000_acquire_eeprom(struct e1000_hw *hw) eecd = E1000_READ_REG(hw, EECD); if (hw->mac_type != e1000_82573) { - /* Request EEPROM Access */ - if(hw->mac_type > e1000_82544) { - eecd |= E1000_EECD_REQ; - E1000_WRITE_REG(hw, EECD, eecd); - eecd = E1000_READ_REG(hw, EECD); - while((!(eecd & E1000_EECD_GNT)) && - (i < E1000_EEPROM_GRANT_ATTEMPTS)) { - i++; - udelay(5); - eecd = E1000_READ_REG(hw, EECD); - } - if(!(eecd & E1000_EECD_GNT)) { - eecd &= ~E1000_EECD_REQ; + /* Request EEPROM Access */ + if(hw->mac_type > e1000_82544) { + eecd |= E1000_EECD_REQ; E1000_WRITE_REG(hw, EECD, eecd); - DEBUGOUT("Could not acquire EEPROM grant\n"); - return -E1000_ERR_EEPROM; + eecd = E1000_READ_REG(hw, EECD); + while((!(eecd & E1000_EECD_GNT)) && + (i < E1000_EEPROM_GRANT_ATTEMPTS)) { + i++; + udelay(5); + eecd = E1000_READ_REG(hw, EECD); + } + if(!(eecd & E1000_EECD_GNT)) { + eecd &= ~E1000_EECD_REQ; + E1000_WRITE_REG(hw, EECD, eecd); + DEBUGOUT("Could not acquire EEPROM grant\n"); + e1000_put_hw_eeprom_semaphore(hw); + return -E1000_ERR_EEPROM; + } } } - } /* Setup EEPROM for Read/Write */ @@ -4064,7 +4139,7 @@ e1000_write_eeprom(struct e1000_hw *hw, return -E1000_ERR_EEPROM; } - /* 82573 reads only through eerd */ + /* 82573 writes only through eewr */ if(eeprom->use_eewr == TRUE) return e1000_write_eeprom_eewr(hw, offset, words, data); @@ -4353,9 +4428,16 @@ e1000_read_mac_addr(struct e1000_hw * hw) hw->perm_mac_addr[i] = (uint8_t) (eeprom_data & 0x00FF); hw->perm_mac_addr[i+1] = (uint8_t) (eeprom_data >> 8); } - if(((hw->mac_type == e1000_82546) || (hw->mac_type == e1000_82546_rev_3)) && - (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)) + switch (hw->mac_type) { + default: + break; + case e1000_82546: + case e1000_82546_rev_3: + case e1000_82571: + if(E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1) hw->perm_mac_addr[5] ^= 0x01; + break; + } for(i = 0; i < NODE_ADDRESS_SIZE; i++) hw->mac_addr[i] = hw->perm_mac_addr[i]; @@ -4385,6 +4467,12 @@ e1000_init_rx_addrs(struct e1000_hw *hw) e1000_rar_set(hw, hw->mac_addr, 0); rar_num = E1000_RAR_ENTRIES; + + /* Reserve a spot for the Locally Administered Address to work around + * an 82571 issue in which a reset on one port will reload the MAC on + * the other port. */ + if ((hw->mac_type == e1000_82571) && (hw->laa_is_present == TRUE)) + rar_num -= 1; /* Zero out the other 15 receive addresses. */ DEBUGOUT("Clearing RAR[1-15]\n"); for(i = 1; i < rar_num; i++) { @@ -4427,6 +4515,12 @@ e1000_mc_addr_list_update(struct e1000_hw *hw, /* Clear RAR[1-15] */ DEBUGOUT(" Clearing RAR[1-15]\n"); num_rar_entry = E1000_RAR_ENTRIES; + /* Reserve a spot for the Locally Administered Address to work around + * an 82571 issue in which a reset on one port will reload the MAC on + * the other port. */ + if ((hw->mac_type == e1000_82571) && (hw->laa_is_present == TRUE)) + num_rar_entry -= 1; + for(i = rar_used_count; i < num_rar_entry; i++) { E1000_WRITE_REG_ARRAY(hw, RA, (i << 1), 0); E1000_WRITE_REG_ARRAY(hw, RA, ((i << 1) + 1), 0); @@ -4984,7 +5078,6 @@ e1000_clear_hw_cntrs(struct e1000_hw *hw) temp = E1000_READ_REG(hw, ICTXQEC); temp = E1000_READ_REG(hw, ICTXQMTC); temp = E1000_READ_REG(hw, ICRXDMTC); - } /****************************************************************************** @@ -5151,6 +5244,8 @@ e1000_get_bus_info(struct e1000_hw *hw) hw->bus_speed = e1000_bus_speed_unknown; hw->bus_width = e1000_bus_width_unknown; break; + case e1000_82571: + case e1000_82572: case e1000_82573: hw->bus_type = e1000_bus_type_pci_express; hw->bus_speed = e1000_bus_speed_2500; @@ -5250,6 +5345,7 @@ e1000_get_cable_length(struct e1000_hw *hw, int32_t ret_val; uint16_t agc_value = 0; uint16_t cur_agc, min_agc = IGP01E1000_AGC_LENGTH_TABLE_SIZE; + uint16_t max_agc = 0; uint16_t i, phy_data; uint16_t cable_length; @@ -5338,6 +5434,40 @@ e1000_get_cable_length(struct e1000_hw *hw, IGP01E1000_AGC_RANGE) : 0; *max_length = e1000_igp_cable_length_table[agc_value] + IGP01E1000_AGC_RANGE; + } else if (hw->phy_type == e1000_phy_igp_2) { + uint16_t agc_reg_array[IGP02E1000_PHY_CHANNEL_NUM] = + {IGP02E1000_PHY_AGC_A, + IGP02E1000_PHY_AGC_B, + IGP02E1000_PHY_AGC_C, + IGP02E1000_PHY_AGC_D}; + /* Read the AGC registers for all channels */ + for (i = 0; i < IGP02E1000_PHY_CHANNEL_NUM; i++) { + ret_val = e1000_read_phy_reg(hw, agc_reg_array[i], &phy_data); + if (ret_val) + return ret_val; + + /* Getting bits 15:9, which represent the combination of course and + * fine gain values. The result is a number that can be put into + * the lookup table to obtain the approximate cable length. */ + cur_agc = (phy_data >> IGP02E1000_AGC_LENGTH_SHIFT) & + IGP02E1000_AGC_LENGTH_MASK; + + /* Remove min & max AGC values from calculation. */ + if (e1000_igp_2_cable_length_table[min_agc] > e1000_igp_2_cable_length_table[cur_agc]) + min_agc = cur_agc; + if (e1000_igp_2_cable_length_table[max_agc] < e1000_igp_2_cable_length_table[cur_agc]) + max_agc = cur_agc; + + agc_value += e1000_igp_2_cable_length_table[cur_agc]; + } + + agc_value -= (e1000_igp_2_cable_length_table[min_agc] + e1000_igp_2_cable_length_table[max_agc]); + agc_value /= (IGP02E1000_PHY_CHANNEL_NUM - 2); + + /* Calculate cable length with the error range of +/- 10 meters. */ + *min_length = ((agc_value - IGP02E1000_AGC_RANGE) > 0) ? + (agc_value - IGP02E1000_AGC_RANGE) : 0; + *max_length = agc_value + IGP02E1000_AGC_RANGE; } return E1000_SUCCESS; @@ -6465,6 +6595,8 @@ e1000_get_auto_rd_done(struct e1000_hw *hw) default: msec_delay(5); break; + case e1000_82571: + case e1000_82572: case e1000_82573: while(timeout) { if (E1000_READ_REG(hw, EECD) & E1000_EECD_AUTO_RD) break; @@ -6494,10 +6626,31 @@ e1000_get_auto_rd_done(struct e1000_hw *hw) int32_t e1000_get_phy_cfg_done(struct e1000_hw *hw) { + int32_t timeout = PHY_CFG_TIMEOUT; + uint32_t cfg_mask = E1000_EEPROM_CFG_DONE; + DEBUGFUNC("e1000_get_phy_cfg_done"); - /* Simply wait for 10ms */ - msec_delay(10); + switch (hw->mac_type) { + default: + msec_delay(10); + break; + case e1000_82571: + case e1000_82572: + while (timeout) { + if (E1000_READ_REG(hw, EEMNGCTL) & cfg_mask) + break; + else + msec_delay(1); + timeout--; + } + + if (!timeout) { + DEBUGOUT("MNG configuration cycle has not completed.\n"); + return -E1000_ERR_RESET; + } + break; + } return E1000_SUCCESS; } @@ -6569,8 +6722,7 @@ e1000_put_hw_eeprom_semaphore(struct e1000_hw *hw) return; swsm = E1000_READ_REG(hw, SWSM); - /* Release both semaphores. */ - swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI); + swsm &= ~(E1000_SWSM_SWESMBI); E1000_WRITE_REG(hw, SWSM, swsm); } @@ -6606,6 +6758,8 @@ e1000_arc_subsystem_valid(struct e1000_hw *hw) * if this is the case. We read FWSM to determine the manageability mode. */ switch (hw->mac_type) { + case e1000_82571: + case e1000_82572: case e1000_82573: fwsm = E1000_READ_REG(hw, FWSM); if((fwsm & E1000_FWSM_MODE_MASK) != 0) diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h index 51c2b3a18b6f..4f2c196dc314 100644 --- a/drivers/net/e1000/e1000_hw.h +++ b/drivers/net/e1000/e1000_hw.h @@ -57,6 +57,8 @@ typedef enum { e1000_82541_rev_2, e1000_82547, e1000_82547_rev_2, + e1000_82571, + e1000_82572, e1000_82573, e1000_num_macs } e1000_mac_type; @@ -478,10 +480,16 @@ uint8_t e1000_arc_subsystem_valid(struct e1000_hw *hw); #define E1000_DEV_ID_82546GB_SERDES 0x107B #define E1000_DEV_ID_82546GB_PCIE 0x108A #define E1000_DEV_ID_82547EI 0x1019 +#define E1000_DEV_ID_82571EB_COPPER 0x105E +#define E1000_DEV_ID_82571EB_FIBER 0x105F +#define E1000_DEV_ID_82571EB_SERDES 0x1060 +#define E1000_DEV_ID_82572EI_COPPER 0x107D +#define E1000_DEV_ID_82572EI_FIBER 0x107E +#define E1000_DEV_ID_82572EI_SERDES 0x107F #define E1000_DEV_ID_82573E 0x108B #define E1000_DEV_ID_82573E_IAMT 0x108C +#define E1000_DEV_ID_82573L 0x109A -#define E1000_DEV_ID_82546GB_QUAD_COPPER 0x1099 #define NODE_ADDRESS_SIZE 6 #define ETH_LENGTH_OF_ADDRESS 6 @@ -833,6 +841,8 @@ struct e1000_ffvt_entry { #define E1000_FFMT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX #define E1000_FFVT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX +#define E1000_DISABLE_SERDES_LOOPBACK 0x0400 + /* Register Set. (82543, 82544) * * Registers are defined to be 32 bits and should be accessed as 32 bit values. @@ -853,6 +863,7 @@ struct e1000_ffvt_entry { #define E1000_CTRL_EXT 0x00018 /* Extended Device Control - RW */ #define E1000_FLA 0x0001C /* Flash Access - RW */ #define E1000_MDIC 0x00020 /* MDI Control - RW */ +#define E1000_SCTL 0x00024 /* SerDes Control - RW */ #define E1000_FCAL 0x00028 /* Flow Control Address Low - RW */ #define E1000_FCAH 0x0002C /* Flow Control Address High -RW */ #define E1000_FCT 0x00030 /* Flow Control Type - RW */ @@ -864,6 +875,12 @@ struct e1000_ffvt_entry { #define E1000_IMC 0x000D8 /* Interrupt Mask Clear - WO */ #define E1000_IAM 0x000E0 /* Interrupt Acknowledge Auto Mask */ #define E1000_RCTL 0x00100 /* RX Control - RW */ +#define E1000_RDTR1 0x02820 /* RX Delay Timer (1) - RW */ +#define E1000_RDBAL1 0x02900 /* RX Descriptor Base Address Low (1) - RW */ +#define E1000_RDBAH1 0x02904 /* RX Descriptor Base Address High (1) - RW */ +#define E1000_RDLEN1 0x02908 /* RX Descriptor Length (1) - RW */ +#define E1000_RDH1 0x02910 /* RX Descriptor Head (1) - RW */ +#define E1000_RDT1 0x02918 /* RX Descriptor Tail (1) - RW */ #define E1000_FCTTV 0x00170 /* Flow Control Transmit Timer Value - RW */ #define E1000_TXCW 0x00178 /* TX Configuration Word - RW */ #define E1000_RXCW 0x00180 /* RX Configuration Word - RO */ @@ -895,6 +912,12 @@ struct e1000_ffvt_entry { #define E1000_RDH 0x02810 /* RX Descriptor Head - RW */ #define E1000_RDT 0x02818 /* RX Descriptor Tail - RW */ #define E1000_RDTR 0x02820 /* RX Delay Timer - RW */ +#define E1000_RDBAL0 E1000_RDBAL /* RX Desc Base Address Low (0) - RW */ +#define E1000_RDBAH0 E1000_RDBAH /* RX Desc Base Address High (0) - RW */ +#define E1000_RDLEN0 E1000_RDLEN /* RX Desc Length (0) - RW */ +#define E1000_RDH0 E1000_RDH /* RX Desc Head (0) - RW */ +#define E1000_RDT0 E1000_RDT /* RX Desc Tail (0) - RW */ +#define E1000_RDTR0 E1000_RDTR /* RX Delay Timer (0) - RW */ #define E1000_RXDCTL 0x02828 /* RX Descriptor Control - RW */ #define E1000_RADV 0x0282C /* RX Interrupt Absolute Delay Timer - RW */ #define E1000_RSRPD 0x02C00 /* RX Small Packet Detect - RW */ @@ -980,15 +1003,15 @@ struct e1000_ffvt_entry { #define E1000_BPTC 0x040F4 /* Broadcast Packets TX Count - R/clr */ #define E1000_TSCTC 0x040F8 /* TCP Segmentation Context TX - R/clr */ #define E1000_TSCTFC 0x040FC /* TCP Segmentation Context TX Fail - R/clr */ -#define E1000_IAC 0x4100 /* Interrupt Assertion Count */ -#define E1000_ICRXPTC 0x4104 /* Interrupt Cause Rx Packet Timer Expire Count */ -#define E1000_ICRXATC 0x4108 /* Interrupt Cause Rx Absolute Timer Expire Count */ -#define E1000_ICTXPTC 0x410C /* Interrupt Cause Tx Packet Timer Expire Count */ -#define E1000_ICTXATC 0x4110 /* Interrupt Cause Tx Absolute Timer Expire Count */ -#define E1000_ICTXQEC 0x4118 /* Interrupt Cause Tx Queue Empty Count */ -#define E1000_ICTXQMTC 0x411C /* Interrupt Cause Tx Queue Minimum Threshold Count */ -#define E1000_ICRXDMTC 0x4120 /* Interrupt Cause Rx Descriptor Minimum Threshold Count */ -#define E1000_ICRXOC 0x4124 /* Interrupt Cause Receiver Overrun Count */ +#define E1000_IAC 0x04100 /* Interrupt Assertion Count */ +#define E1000_ICRXPTC 0x04104 /* Interrupt Cause Rx Packet Timer Expire Count */ +#define E1000_ICRXATC 0x04108 /* Interrupt Cause Rx Absolute Timer Expire Count */ +#define E1000_ICTXPTC 0x0410C /* Interrupt Cause Tx Packet Timer Expire Count */ +#define E1000_ICTXATC 0x04110 /* Interrupt Cause Tx Absolute Timer Expire Count */ +#define E1000_ICTXQEC 0x04118 /* Interrupt Cause Tx Queue Empty Count */ +#define E1000_ICTXQMTC 0x0411C /* Interrupt Cause Tx Queue Minimum Threshold Count */ +#define E1000_ICRXDMTC 0x04120 /* Interrupt Cause Rx Descriptor Minimum Threshold Count */ +#define E1000_ICRXOC 0x04124 /* Interrupt Cause Receiver Overrun Count */ #define E1000_RXCSUM 0x05000 /* RX Checksum Control - RW */ #define E1000_RFCTL 0x05008 /* Receive Filter Control*/ #define E1000_MTA 0x05200 /* Multicast Table Array - RW Array */ @@ -1018,6 +1041,14 @@ struct e1000_ffvt_entry { #define E1000_FWSM 0x05B54 /* FW Semaphore */ #define E1000_FFLT_DBG 0x05F04 /* Debug Register */ #define E1000_HICR 0x08F00 /* Host Inteface Control */ + +/* RSS registers */ +#define E1000_CPUVEC 0x02C10 /* CPU Vector Register - RW */ +#define E1000_MRQC 0x05818 /* Multiple Receive Control - RW */ +#define E1000_RETA 0x05C00 /* Redirection Table - RW Array */ +#define E1000_RSSRK 0x05C80 /* RSS Random Key - RW Array */ +#define E1000_RSSIM 0x05864 /* RSS Interrupt Mask */ +#define E1000_RSSIR 0x05868 /* RSS Interrupt Request */ /* Register Set (82542) * * Some of the 82542 registers are located at different offsets than they are @@ -1032,6 +1063,7 @@ struct e1000_ffvt_entry { #define E1000_82542_CTRL_EXT E1000_CTRL_EXT #define E1000_82542_FLA E1000_FLA #define E1000_82542_MDIC E1000_MDIC +#define E1000_82542_SCTL E1000_SCTL #define E1000_82542_FCAL E1000_FCAL #define E1000_82542_FCAH E1000_FCAH #define E1000_82542_FCT E1000_FCT @@ -1049,6 +1081,18 @@ struct e1000_ffvt_entry { #define E1000_82542_RDLEN 0x00118 #define E1000_82542_RDH 0x00120 #define E1000_82542_RDT 0x00128 +#define E1000_82542_RDTR0 E1000_82542_RDTR +#define E1000_82542_RDBAL0 E1000_82542_RDBAL +#define E1000_82542_RDBAH0 E1000_82542_RDBAH +#define E1000_82542_RDLEN0 E1000_82542_RDLEN +#define E1000_82542_RDH0 E1000_82542_RDH +#define E1000_82542_RDT0 E1000_82542_RDT +#define E1000_82542_RDTR1 0x00130 +#define E1000_82542_RDBAL1 0x00138 +#define E1000_82542_RDBAH1 0x0013C +#define E1000_82542_RDLEN1 0x00140 +#define E1000_82542_RDH1 0x00148 +#define E1000_82542_RDT1 0x00150 #define E1000_82542_FCRTH 0x00160 #define E1000_82542_FCRTL 0x00168 #define E1000_82542_FCTTV E1000_FCTTV @@ -1197,6 +1241,13 @@ struct e1000_ffvt_entry { #define E1000_82542_ICRXOC E1000_ICRXOC #define E1000_82542_HICR E1000_HICR +#define E1000_82542_CPUVEC E1000_CPUVEC +#define E1000_82542_MRQC E1000_MRQC +#define E1000_82542_RETA E1000_RETA +#define E1000_82542_RSSRK E1000_RSSRK +#define E1000_82542_RSSIM E1000_RSSIM +#define E1000_82542_RSSIR E1000_RSSIR + /* Statistics counters collected by the MAC */ struct e1000_hw_stats { uint64_t crcerrs; @@ -1336,6 +1387,7 @@ struct e1000_hw { boolean_t serdes_link_down; boolean_t tbi_compatibility_en; boolean_t tbi_compatibility_on; + boolean_t laa_is_present; boolean_t phy_reset_disable; boolean_t fc_send_xon; boolean_t fc_strict_ieee; @@ -1374,6 +1426,7 @@ struct e1000_hw { #define E1000_CTRL_BEM32 0x00000400 /* Big Endian 32 mode */ #define E1000_CTRL_FRCSPD 0x00000800 /* Force Speed */ #define E1000_CTRL_FRCDPX 0x00001000 /* Force Duplex */ +#define E1000_CTRL_D_UD_EN 0x00002000 /* Dock/Undock enable */ #define E1000_CTRL_D_UD_POLARITY 0x00004000 /* Defined polarity of Dock/Undock indication in SDP[0] */ #define E1000_CTRL_SWDPIN0 0x00040000 /* SWDPIN 0 value */ #define E1000_CTRL_SWDPIN1 0x00080000 /* SWDPIN 1 value */ @@ -1491,6 +1544,8 @@ struct e1000_hw { #define E1000_CTRL_EXT_WR_WMARK_320 0x01000000 #define E1000_CTRL_EXT_WR_WMARK_384 0x02000000 #define E1000_CTRL_EXT_WR_WMARK_448 0x03000000 +#define E1000_CTRL_EXT_CANC 0x04000000 /* Interrupt delay cancellation */ +#define E1000_CTRL_EXT_DRV_LOAD 0x10000000 /* Driver loaded bit for FW */ #define E1000_CTRL_EXT_IAME 0x08000000 /* Interrupt acknowledge Auto-mask */ #define E1000_CTRL_EXT_INT_TIMER_CLR 0x20000000 /* Clear Interrupt timers after IMS clear */ @@ -1524,6 +1579,7 @@ struct e1000_hw { #define E1000_LEDCTL_LED2_BLINK 0x00800000 #define E1000_LEDCTL_LED3_MODE_MASK 0x0F000000 #define E1000_LEDCTL_LED3_MODE_SHIFT 24 +#define E1000_LEDCTL_LED3_BLINK_RATE 0x20000000 #define E1000_LEDCTL_LED3_IVRT 0x40000000 #define E1000_LEDCTL_LED3_BLINK 0x80000000 @@ -1784,6 +1840,16 @@ struct e1000_hw { #define E1000_RXCSUM_IPPCSE 0x00001000 /* IP payload checksum enable */ #define E1000_RXCSUM_PCSD 0x00002000 /* packet checksum disabled */ +/* Multiple Receive Queue Control */ +#define E1000_MRQC_ENABLE_MASK 0x00000003 +#define E1000_MRQC_ENABLE_RSS_2Q 0x00000001 +#define E1000_MRQC_ENABLE_RSS_INT 0x00000004 +#define E1000_MRQC_RSS_FIELD_MASK 0xFFFF0000 +#define E1000_MRQC_RSS_FIELD_IPV4_TCP 0x00010000 +#define E1000_MRQC_RSS_FIELD_IPV4 0x00020000 +#define E1000_MRQC_RSS_FIELD_IPV6_TCP 0x00040000 +#define E1000_MRQC_RSS_FIELD_IPV6_EX 0x00080000 +#define E1000_MRQC_RSS_FIELD_IPV6 0x00100000 /* Definitions for power management and wakeup registers */ /* Wake Up Control */ @@ -1928,6 +1994,7 @@ struct e1000_host_command_info { #define E1000_MDALIGN 4096 #define E1000_GCR_BEM32 0x00400000 +#define E1000_GCR_L1_ACT_WITHOUT_L0S_RX 0x08000000 /* Function Active and Power State to MNG */ #define E1000_FACTPS_FUNC0_POWER_STATE_MASK 0x00000003 #define E1000_FACTPS_LAN0_VALID 0x00000004 @@ -1980,6 +2047,7 @@ struct e1000_host_command_info { /* EEPROM Word Offsets */ #define EEPROM_COMPAT 0x0003 #define EEPROM_ID_LED_SETTINGS 0x0004 +#define EEPROM_VERSION 0x0005 #define EEPROM_SERDES_AMPLITUDE 0x0006 /* For SERDES output amplitude adjustment. */ #define EEPROM_PHY_CLASS_WORD 0x0007 #define EEPROM_INIT_CONTROL1_REG 0x000A @@ -1990,6 +2058,8 @@ struct e1000_host_command_info { #define EEPROM_FLASH_VERSION 0x0032 #define EEPROM_CHECKSUM_REG 0x003F +#define E1000_EEPROM_CFG_DONE 0x00040000 /* MNG config cycle done */ + /* Word definitions for ID LED Settings */ #define ID_LED_RESERVED_0000 0x0000 #define ID_LED_RESERVED_FFFF 0xFFFF @@ -2108,6 +2178,8 @@ struct e1000_host_command_info { #define E1000_PBA_22K 0x0016 #define E1000_PBA_24K 0x0018 #define E1000_PBA_30K 0x001E +#define E1000_PBA_32K 0x0020 +#define E1000_PBA_38K 0x0026 #define E1000_PBA_40K 0x0028 #define E1000_PBA_48K 0x0030 /* 48KB, default RX allocation */ @@ -2592,11 +2664,11 @@ struct e1000_host_command_info { /* 7 bits (3 Coarse + 4 Fine) --> 128 optional values */ #define IGP01E1000_AGC_LENGTH_TABLE_SIZE 128 -#define IGP02E1000_AGC_LENGTH_TABLE_SIZE 128 +#define IGP02E1000_AGC_LENGTH_TABLE_SIZE 113 /* The precision error of the cable length is +/- 10 meters */ #define IGP01E1000_AGC_RANGE 10 -#define IGP02E1000_AGC_RANGE 10 +#define IGP02E1000_AGC_RANGE 15 /* IGP01E1000 PCS Initialization register */ /* bits 3:6 in the PCS registers stores the channels polarity */ diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index ee687c902a20..efbbda7cbcbf 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -43,7 +43,7 @@ char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver"; #else #define DRIVERNAPI "-NAPI" #endif -#define DRV_VERSION "6.0.60-k2"DRIVERNAPI +#define DRV_VERSION "6.1.16-k2"DRIVERNAPI char e1000_driver_version[] = DRV_VERSION; char e1000_copyright[] = "Copyright (c) 1999-2005 Intel Corporation."; @@ -80,6 +80,9 @@ static struct pci_device_id e1000_pci_tbl[] = { INTEL_E1000_ETHERNET_DEVICE(0x1026), INTEL_E1000_ETHERNET_DEVICE(0x1027), INTEL_E1000_ETHERNET_DEVICE(0x1028), + INTEL_E1000_ETHERNET_DEVICE(0x105E), + INTEL_E1000_ETHERNET_DEVICE(0x105F), + INTEL_E1000_ETHERNET_DEVICE(0x1060), INTEL_E1000_ETHERNET_DEVICE(0x1075), INTEL_E1000_ETHERNET_DEVICE(0x1076), INTEL_E1000_ETHERNET_DEVICE(0x1077), @@ -88,10 +91,13 @@ static struct pci_device_id e1000_pci_tbl[] = { INTEL_E1000_ETHERNET_DEVICE(0x107A), INTEL_E1000_ETHERNET_DEVICE(0x107B), INTEL_E1000_ETHERNET_DEVICE(0x107C), + INTEL_E1000_ETHERNET_DEVICE(0x107D), + INTEL_E1000_ETHERNET_DEVICE(0x107E), + INTEL_E1000_ETHERNET_DEVICE(0x107F), INTEL_E1000_ETHERNET_DEVICE(0x108A), INTEL_E1000_ETHERNET_DEVICE(0x108B), INTEL_E1000_ETHERNET_DEVICE(0x108C), - INTEL_E1000_ETHERNET_DEVICE(0x1099), + INTEL_E1000_ETHERNET_DEVICE(0x109A), /* required last entry */ {0,} }; @@ -102,10 +108,18 @@ int e1000_up(struct e1000_adapter *adapter); void e1000_down(struct e1000_adapter *adapter); void e1000_reset(struct e1000_adapter *adapter); int e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx); -int e1000_setup_tx_resources(struct e1000_adapter *adapter); -int e1000_setup_rx_resources(struct e1000_adapter *adapter); -void e1000_free_tx_resources(struct e1000_adapter *adapter); -void e1000_free_rx_resources(struct e1000_adapter *adapter); +int e1000_setup_all_tx_resources(struct e1000_adapter *adapter); +int e1000_setup_all_rx_resources(struct e1000_adapter *adapter); +void e1000_free_all_tx_resources(struct e1000_adapter *adapter); +void e1000_free_all_rx_resources(struct e1000_adapter *adapter); +int e1000_setup_tx_resources(struct e1000_adapter *adapter, + struct e1000_tx_ring *txdr); +int e1000_setup_rx_resources(struct e1000_adapter *adapter, + struct e1000_rx_ring *rxdr); +void e1000_free_tx_resources(struct e1000_adapter *adapter, + struct e1000_tx_ring *tx_ring); +void e1000_free_rx_resources(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring); void e1000_update_stats(struct e1000_adapter *adapter); /* Local Function Prototypes */ @@ -114,14 +128,22 @@ static int e1000_init_module(void); static void e1000_exit_module(void); static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent); static void __devexit e1000_remove(struct pci_dev *pdev); +static int e1000_alloc_queues(struct e1000_adapter *adapter); +#ifdef CONFIG_E1000_MQ +static void e1000_setup_queue_mapping(struct e1000_adapter *adapter); +#endif static int e1000_sw_init(struct e1000_adapter *adapter); static int e1000_open(struct net_device *netdev); static int e1000_close(struct net_device *netdev); static void e1000_configure_tx(struct e1000_adapter *adapter); static void e1000_configure_rx(struct e1000_adapter *adapter); static void e1000_setup_rctl(struct e1000_adapter *adapter); -static void e1000_clean_tx_ring(struct e1000_adapter *adapter); -static void e1000_clean_rx_ring(struct e1000_adapter *adapter); +static void e1000_clean_all_tx_rings(struct e1000_adapter *adapter); +static void e1000_clean_all_rx_rings(struct e1000_adapter *adapter); +static void e1000_clean_tx_ring(struct e1000_adapter *adapter, + struct e1000_tx_ring *tx_ring); +static void e1000_clean_rx_ring(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring); static void e1000_set_multi(struct net_device *netdev); static void e1000_update_phy_info(unsigned long data); static void e1000_watchdog(unsigned long data); @@ -132,19 +154,26 @@ static struct net_device_stats * e1000_get_stats(struct net_device *netdev); static int e1000_change_mtu(struct net_device *netdev, int new_mtu); static int e1000_set_mac(struct net_device *netdev, void *p); static irqreturn_t e1000_intr(int irq, void *data, struct pt_regs *regs); -static boolean_t e1000_clean_tx_irq(struct e1000_adapter *adapter); +static boolean_t e1000_clean_tx_irq(struct e1000_adapter *adapter, + struct e1000_tx_ring *tx_ring); #ifdef CONFIG_E1000_NAPI -static int e1000_clean(struct net_device *netdev, int *budget); +static int e1000_clean(struct net_device *poll_dev, int *budget); static boolean_t e1000_clean_rx_irq(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring, int *work_done, int work_to_do); static boolean_t e1000_clean_rx_irq_ps(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring, int *work_done, int work_to_do); #else -static boolean_t e1000_clean_rx_irq(struct e1000_adapter *adapter); -static boolean_t e1000_clean_rx_irq_ps(struct e1000_adapter *adapter); +static boolean_t e1000_clean_rx_irq(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring); +static boolean_t e1000_clean_rx_irq_ps(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring); #endif -static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter); -static void e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter); +static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring); +static void e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring); static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd); static int e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd); @@ -162,8 +191,8 @@ static void e1000_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid); static void e1000_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid); static void e1000_restore_vlan(struct e1000_adapter *adapter); -static int e1000_suspend(struct pci_dev *pdev, pm_message_t state); #ifdef CONFIG_PM +static int e1000_suspend(struct pci_dev *pdev, pm_message_t state); static int e1000_resume(struct pci_dev *pdev); #endif @@ -172,6 +201,11 @@ static int e1000_resume(struct pci_dev *pdev); static void e1000_netpoll (struct net_device *netdev); #endif +#ifdef CONFIG_E1000_MQ +/* for multiple Rx queues */ +void e1000_rx_schedule(void *data); +#endif + /* Exported from other modules */ extern void e1000_check_options(struct e1000_adapter *adapter); @@ -289,7 +323,7 @@ int e1000_up(struct e1000_adapter *adapter) { struct net_device *netdev = adapter->netdev; - int err; + int i, err; /* hardware has been reset, we need to reload some things */ @@ -308,7 +342,8 @@ e1000_up(struct e1000_adapter *adapter) e1000_configure_tx(adapter); e1000_setup_rctl(adapter); e1000_configure_rx(adapter); - adapter->alloc_rx_buf(adapter); + for (i = 0; i < adapter->num_queues; i++) + adapter->alloc_rx_buf(adapter, &adapter->rx_ring[i]); #ifdef CONFIG_PCI_MSI if(adapter->hw.mac_type > e1000_82547_rev_2) { @@ -344,6 +379,9 @@ e1000_down(struct e1000_adapter *adapter) struct net_device *netdev = adapter->netdev; e1000_irq_disable(adapter); +#ifdef CONFIG_E1000_MQ + while (atomic_read(&adapter->rx_sched_call_data.count) != 0); +#endif free_irq(adapter->pdev->irq, netdev); #ifdef CONFIG_PCI_MSI if(adapter->hw.mac_type > e1000_82547_rev_2 && @@ -363,11 +401,10 @@ e1000_down(struct e1000_adapter *adapter) netif_stop_queue(netdev); e1000_reset(adapter); - e1000_clean_tx_ring(adapter); - e1000_clean_rx_ring(adapter); + e1000_clean_all_tx_rings(adapter); + e1000_clean_all_rx_rings(adapter); - /* If WoL is not enabled - * and management mode is not IAMT + /* If WoL is not enabled and management mode is not IAMT * Power down the PHY so no link is implied when interface is down */ if(!adapter->wol && adapter->hw.mac_type >= e1000_82540 && adapter->hw.media_type == e1000_media_type_copper && @@ -398,6 +435,10 @@ e1000_reset(struct e1000_adapter *adapter) case e1000_82547_rev_2: pba = E1000_PBA_30K; break; + case e1000_82571: + case e1000_82572: + pba = E1000_PBA_38K; + break; case e1000_82573: pba = E1000_PBA_12K; break; @@ -475,6 +516,7 @@ e1000_probe(struct pci_dev *pdev, struct net_device *netdev; struct e1000_adapter *adapter; unsigned long mmio_start, mmio_len; + uint32_t ctrl_ext; uint32_t swsm; static int cards_found = 0; @@ -614,8 +656,9 @@ e1000_probe(struct pci_dev *pdev, if(e1000_read_mac_addr(&adapter->hw)) DPRINTK(PROBE, ERR, "EEPROM Read Error\n"); memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len); + memcpy(netdev->perm_addr, adapter->hw.mac_addr, netdev->addr_len); - if(!is_valid_ether_addr(netdev->dev_addr)) { + if(!is_valid_ether_addr(netdev->perm_addr)) { DPRINTK(PROBE, ERR, "Invalid MAC Address\n"); err = -EIO; goto err_eeprom; @@ -687,6 +730,12 @@ e1000_probe(struct pci_dev *pdev, /* Let firmware know the driver has taken over */ switch(adapter->hw.mac_type) { + case e1000_82571: + case e1000_82572: + ctrl_ext = E1000_READ_REG(&adapter->hw, CTRL_EXT); + E1000_WRITE_REG(&adapter->hw, CTRL_EXT, + ctrl_ext | E1000_CTRL_EXT_DRV_LOAD); + break; case e1000_82573: swsm = E1000_READ_REG(&adapter->hw, SWSM); E1000_WRITE_REG(&adapter->hw, SWSM, @@ -731,7 +780,11 @@ e1000_remove(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); struct e1000_adapter *adapter = netdev_priv(netdev); + uint32_t ctrl_ext; uint32_t manc, swsm; +#ifdef CONFIG_E1000_NAPI + int i; +#endif flush_scheduled_work(); @@ -745,6 +798,12 @@ e1000_remove(struct pci_dev *pdev) } switch(adapter->hw.mac_type) { + case e1000_82571: + case e1000_82572: + ctrl_ext = E1000_READ_REG(&adapter->hw, CTRL_EXT); + E1000_WRITE_REG(&adapter->hw, CTRL_EXT, + ctrl_ext & ~E1000_CTRL_EXT_DRV_LOAD); + break; case e1000_82573: swsm = E1000_READ_REG(&adapter->hw, SWSM); E1000_WRITE_REG(&adapter->hw, SWSM, @@ -756,13 +815,27 @@ e1000_remove(struct pci_dev *pdev) } unregister_netdev(netdev); +#ifdef CONFIG_E1000_NAPI + for (i = 0; i < adapter->num_queues; i++) + __dev_put(&adapter->polling_netdev[i]); +#endif if(!e1000_check_phy_reset_block(&adapter->hw)) e1000_phy_hw_reset(&adapter->hw); + kfree(adapter->tx_ring); + kfree(adapter->rx_ring); +#ifdef CONFIG_E1000_NAPI + kfree(adapter->polling_netdev); +#endif + iounmap(adapter->hw.hw_addr); pci_release_regions(pdev); +#ifdef CONFIG_E1000_MQ + free_percpu(adapter->cpu_netdev); + free_percpu(adapter->cpu_tx_ring); +#endif free_netdev(netdev); pci_disable_device(pdev); @@ -783,6 +856,9 @@ e1000_sw_init(struct e1000_adapter *adapter) struct e1000_hw *hw = &adapter->hw; struct net_device *netdev = adapter->netdev; struct pci_dev *pdev = adapter->pdev; +#ifdef CONFIG_E1000_NAPI + int i; +#endif /* PCI config space info */ @@ -840,14 +916,123 @@ e1000_sw_init(struct e1000_adapter *adapter) hw->master_slave = E1000_MASTER_SLAVE; } +#ifdef CONFIG_E1000_MQ + /* Number of supported queues */ + switch (hw->mac_type) { + case e1000_82571: + case e1000_82572: + adapter->num_queues = 2; + break; + default: + adapter->num_queues = 1; + break; + } + adapter->num_queues = min(adapter->num_queues, num_online_cpus()); +#else + adapter->num_queues = 1; +#endif + + if (e1000_alloc_queues(adapter)) { + DPRINTK(PROBE, ERR, "Unable to allocate memory for queues\n"); + return -ENOMEM; + } + +#ifdef CONFIG_E1000_NAPI + for (i = 0; i < adapter->num_queues; i++) { + adapter->polling_netdev[i].priv = adapter; + adapter->polling_netdev[i].poll = &e1000_clean; + adapter->polling_netdev[i].weight = 64; + dev_hold(&adapter->polling_netdev[i]); + set_bit(__LINK_STATE_START, &adapter->polling_netdev[i].state); + } +#endif + +#ifdef CONFIG_E1000_MQ + e1000_setup_queue_mapping(adapter); +#endif + atomic_set(&adapter->irq_sem, 1); spin_lock_init(&adapter->stats_lock); - spin_lock_init(&adapter->tx_lock); return 0; } /** + * e1000_alloc_queues - Allocate memory for all rings + * @adapter: board private structure to initialize + * + * We allocate one ring per queue at run-time since we don't know the + * number of queues at compile-time. The polling_netdev array is + * intended for Multiqueue, but should work fine with a single queue. + **/ + +static int __devinit +e1000_alloc_queues(struct e1000_adapter *adapter) +{ + int size; + + size = sizeof(struct e1000_tx_ring) * adapter->num_queues; + adapter->tx_ring = kmalloc(size, GFP_KERNEL); + if (!adapter->tx_ring) + return -ENOMEM; + memset(adapter->tx_ring, 0, size); + + size = sizeof(struct e1000_rx_ring) * adapter->num_queues; + adapter->rx_ring = kmalloc(size, GFP_KERNEL); + if (!adapter->rx_ring) { + kfree(adapter->tx_ring); + return -ENOMEM; + } + memset(adapter->rx_ring, 0, size); + +#ifdef CONFIG_E1000_NAPI + size = sizeof(struct net_device) * adapter->num_queues; + adapter->polling_netdev = kmalloc(size, GFP_KERNEL); + if (!adapter->polling_netdev) { + kfree(adapter->tx_ring); + kfree(adapter->rx_ring); + return -ENOMEM; + } + memset(adapter->polling_netdev, 0, size); +#endif + + return E1000_SUCCESS; +} + +#ifdef CONFIG_E1000_MQ +static void __devinit +e1000_setup_queue_mapping(struct e1000_adapter *adapter) +{ + int i, cpu; + + adapter->rx_sched_call_data.func = e1000_rx_schedule; + adapter->rx_sched_call_data.info = adapter->netdev; + cpus_clear(adapter->rx_sched_call_data.cpumask); + + adapter->cpu_netdev = alloc_percpu(struct net_device *); + adapter->cpu_tx_ring = alloc_percpu(struct e1000_tx_ring *); + + lock_cpu_hotplug(); + i = 0; + for_each_online_cpu(cpu) { + *per_cpu_ptr(adapter->cpu_tx_ring, cpu) = &adapter->tx_ring[i % adapter->num_queues]; + /* This is incomplete because we'd like to assign separate + * physical cpus to these netdev polling structures and + * avoid saturating a subset of cpus. + */ + if (i < adapter->num_queues) { + *per_cpu_ptr(adapter->cpu_netdev, cpu) = &adapter->polling_netdev[i]; + adapter->cpu_for_queue[i] = cpu; + } else + *per_cpu_ptr(adapter->cpu_netdev, cpu) = NULL; + + i++; + } + unlock_cpu_hotplug(); +} +#endif + +/** * e1000_open - Called when a network interface is made active * @netdev: network interface device structure * @@ -868,12 +1053,12 @@ e1000_open(struct net_device *netdev) /* allocate transmit descriptors */ - if((err = e1000_setup_tx_resources(adapter))) + if ((err = e1000_setup_all_tx_resources(adapter))) goto err_setup_tx; /* allocate receive descriptors */ - if((err = e1000_setup_rx_resources(adapter))) + if ((err = e1000_setup_all_rx_resources(adapter))) goto err_setup_rx; if((err = e1000_up(adapter))) @@ -887,9 +1072,9 @@ e1000_open(struct net_device *netdev) return E1000_SUCCESS; err_up: - e1000_free_rx_resources(adapter); + e1000_free_all_rx_resources(adapter); err_setup_rx: - e1000_free_tx_resources(adapter); + e1000_free_all_tx_resources(adapter); err_setup_tx: e1000_reset(adapter); @@ -915,8 +1100,8 @@ e1000_close(struct net_device *netdev) e1000_down(adapter); - e1000_free_tx_resources(adapter); - e1000_free_rx_resources(adapter); + e1000_free_all_tx_resources(adapter); + e1000_free_all_rx_resources(adapter); if((adapter->hw.mng_cookie.status & E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT)) { @@ -951,25 +1136,28 @@ e1000_check_64k_bound(struct e1000_adapter *adapter, /** * e1000_setup_tx_resources - allocate Tx resources (Descriptors) * @adapter: board private structure + * @txdr: tx descriptor ring (for a specific queue) to setup * * Return 0 on success, negative on failure **/ int -e1000_setup_tx_resources(struct e1000_adapter *adapter) +e1000_setup_tx_resources(struct e1000_adapter *adapter, + struct e1000_tx_ring *txdr) { - struct e1000_desc_ring *txdr = &adapter->tx_ring; struct pci_dev *pdev = adapter->pdev; int size; size = sizeof(struct e1000_buffer) * txdr->count; - txdr->buffer_info = vmalloc(size); + + txdr->buffer_info = vmalloc_node(size, pcibus_to_node(pdev->bus)); if(!txdr->buffer_info) { DPRINTK(PROBE, ERR, "Unable to allocate memory for the transmit descriptor ring\n"); return -ENOMEM; } memset(txdr->buffer_info, 0, size); + memset(&txdr->previous_buffer_info, 0, sizeof(struct e1000_buffer)); /* round up to nearest 4K */ @@ -1018,11 +1206,41 @@ setup_tx_desc_die: txdr->next_to_use = 0; txdr->next_to_clean = 0; + spin_lock_init(&txdr->tx_lock); return 0; } /** + * e1000_setup_all_tx_resources - wrapper to allocate Tx resources + * (Descriptors) for all queues + * @adapter: board private structure + * + * If this function returns with an error, then it's possible one or + * more of the rings is populated (while the rest are not). It is the + * callers duty to clean those orphaned rings. + * + * Return 0 on success, negative on failure + **/ + +int +e1000_setup_all_tx_resources(struct e1000_adapter *adapter) +{ + int i, err = 0; + + for (i = 0; i < adapter->num_queues; i++) { + err = e1000_setup_tx_resources(adapter, &adapter->tx_ring[i]); + if (err) { + DPRINTK(PROBE, ERR, + "Allocation for Tx Queue %u failed\n", i); + break; + } + } + + return err; +} + +/** * e1000_configure_tx - Configure 8254x Transmit Unit after Reset * @adapter: board private structure * @@ -1032,23 +1250,43 @@ setup_tx_desc_die: static void e1000_configure_tx(struct e1000_adapter *adapter) { - uint64_t tdba = adapter->tx_ring.dma; - uint32_t tdlen = adapter->tx_ring.count * sizeof(struct e1000_tx_desc); - uint32_t tctl, tipg; - - E1000_WRITE_REG(&adapter->hw, TDBAL, (tdba & 0x00000000ffffffffULL)); - E1000_WRITE_REG(&adapter->hw, TDBAH, (tdba >> 32)); - - E1000_WRITE_REG(&adapter->hw, TDLEN, tdlen); + uint64_t tdba; + struct e1000_hw *hw = &adapter->hw; + uint32_t tdlen, tctl, tipg, tarc; /* Setup the HW Tx Head and Tail descriptor pointers */ - E1000_WRITE_REG(&adapter->hw, TDH, 0); - E1000_WRITE_REG(&adapter->hw, TDT, 0); + switch (adapter->num_queues) { + case 2: + tdba = adapter->tx_ring[1].dma; + tdlen = adapter->tx_ring[1].count * + sizeof(struct e1000_tx_desc); + E1000_WRITE_REG(hw, TDBAL1, (tdba & 0x00000000ffffffffULL)); + E1000_WRITE_REG(hw, TDBAH1, (tdba >> 32)); + E1000_WRITE_REG(hw, TDLEN1, tdlen); + E1000_WRITE_REG(hw, TDH1, 0); + E1000_WRITE_REG(hw, TDT1, 0); + adapter->tx_ring[1].tdh = E1000_TDH1; + adapter->tx_ring[1].tdt = E1000_TDT1; + /* Fall Through */ + case 1: + default: + tdba = adapter->tx_ring[0].dma; + tdlen = adapter->tx_ring[0].count * + sizeof(struct e1000_tx_desc); + E1000_WRITE_REG(hw, TDBAL, (tdba & 0x00000000ffffffffULL)); + E1000_WRITE_REG(hw, TDBAH, (tdba >> 32)); + E1000_WRITE_REG(hw, TDLEN, tdlen); + E1000_WRITE_REG(hw, TDH, 0); + E1000_WRITE_REG(hw, TDT, 0); + adapter->tx_ring[0].tdh = E1000_TDH; + adapter->tx_ring[0].tdt = E1000_TDT; + break; + } /* Set the default values for the Tx Inter Packet Gap timer */ - switch (adapter->hw.mac_type) { + switch (hw->mac_type) { case e1000_82542_rev2_0: case e1000_82542_rev2_1: tipg = DEFAULT_82542_TIPG_IPGT; @@ -1056,67 +1294,81 @@ e1000_configure_tx(struct e1000_adapter *adapter) tipg |= DEFAULT_82542_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT; break; default: - if(adapter->hw.media_type == e1000_media_type_fiber || - adapter->hw.media_type == e1000_media_type_internal_serdes) + if (hw->media_type == e1000_media_type_fiber || + hw->media_type == e1000_media_type_internal_serdes) tipg = DEFAULT_82543_TIPG_IPGT_FIBER; else tipg = DEFAULT_82543_TIPG_IPGT_COPPER; tipg |= DEFAULT_82543_TIPG_IPGR1 << E1000_TIPG_IPGR1_SHIFT; tipg |= DEFAULT_82543_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT; } - E1000_WRITE_REG(&adapter->hw, TIPG, tipg); + E1000_WRITE_REG(hw, TIPG, tipg); /* Set the Tx Interrupt Delay register */ - E1000_WRITE_REG(&adapter->hw, TIDV, adapter->tx_int_delay); - if(adapter->hw.mac_type >= e1000_82540) - E1000_WRITE_REG(&adapter->hw, TADV, adapter->tx_abs_int_delay); + E1000_WRITE_REG(hw, TIDV, adapter->tx_int_delay); + if (hw->mac_type >= e1000_82540) + E1000_WRITE_REG(hw, TADV, adapter->tx_abs_int_delay); /* Program the Transmit Control Register */ - tctl = E1000_READ_REG(&adapter->hw, TCTL); + tctl = E1000_READ_REG(hw, TCTL); tctl &= ~E1000_TCTL_CT; - tctl |= E1000_TCTL_EN | E1000_TCTL_PSP | + tctl |= E1000_TCTL_EN | E1000_TCTL_PSP | E1000_TCTL_RTLC | (E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT); - E1000_WRITE_REG(&adapter->hw, TCTL, tctl); + E1000_WRITE_REG(hw, TCTL, tctl); + + if (hw->mac_type == e1000_82571 || hw->mac_type == e1000_82572) { + tarc = E1000_READ_REG(hw, TARC0); + tarc |= ((1 << 25) | (1 << 21)); + E1000_WRITE_REG(hw, TARC0, tarc); + tarc = E1000_READ_REG(hw, TARC1); + tarc |= (1 << 25); + if (tctl & E1000_TCTL_MULR) + tarc &= ~(1 << 28); + else + tarc |= (1 << 28); + E1000_WRITE_REG(hw, TARC1, tarc); + } - e1000_config_collision_dist(&adapter->hw); + e1000_config_collision_dist(hw); /* Setup Transmit Descriptor Settings for eop descriptor */ adapter->txd_cmd = E1000_TXD_CMD_IDE | E1000_TXD_CMD_EOP | E1000_TXD_CMD_IFCS; - if(adapter->hw.mac_type < e1000_82543) + if (hw->mac_type < e1000_82543) adapter->txd_cmd |= E1000_TXD_CMD_RPS; else adapter->txd_cmd |= E1000_TXD_CMD_RS; /* Cache if we're 82544 running in PCI-X because we'll * need this to apply a workaround later in the send path. */ - if(adapter->hw.mac_type == e1000_82544 && - adapter->hw.bus_type == e1000_bus_type_pcix) + if (hw->mac_type == e1000_82544 && + hw->bus_type == e1000_bus_type_pcix) adapter->pcix_82544 = 1; } /** * e1000_setup_rx_resources - allocate Rx resources (Descriptors) * @adapter: board private structure + * @rxdr: rx descriptor ring (for a specific queue) to setup * * Returns 0 on success, negative on failure **/ int -e1000_setup_rx_resources(struct e1000_adapter *adapter) +e1000_setup_rx_resources(struct e1000_adapter *adapter, + struct e1000_rx_ring *rxdr) { - struct e1000_desc_ring *rxdr = &adapter->rx_ring; struct pci_dev *pdev = adapter->pdev; int size, desc_len; size = sizeof(struct e1000_buffer) * rxdr->count; - rxdr->buffer_info = vmalloc(size); - if(!rxdr->buffer_info) { + rxdr->buffer_info = vmalloc_node(size, pcibus_to_node(pdev->bus)); + if (!rxdr->buffer_info) { DPRINTK(PROBE, ERR, "Unable to allocate memory for the receive descriptor ring\n"); return -ENOMEM; @@ -1156,13 +1408,13 @@ e1000_setup_rx_resources(struct e1000_adapter *adapter) rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma); - if(!rxdr->desc) { + if (!rxdr->desc) { + DPRINTK(PROBE, ERR, + "Unable to allocate memory for the receive descriptor ring\n"); setup_rx_desc_die: vfree(rxdr->buffer_info); kfree(rxdr->ps_page); kfree(rxdr->ps_page_dma); - DPRINTK(PROBE, ERR, - "Unable to allocate memory for the receive descriptor ring\n"); return -ENOMEM; } @@ -1174,9 +1426,12 @@ setup_rx_desc_die: "at %p\n", rxdr->size, rxdr->desc); /* Try again, without freeing the previous */ rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma); - if(!rxdr->desc) { /* Failed allocation, critical failure */ + if (!rxdr->desc) { pci_free_consistent(pdev, rxdr->size, olddesc, olddma); + DPRINTK(PROBE, ERR, + "Unable to allocate memory " + "for the receive descriptor ring\n"); goto setup_rx_desc_die; } @@ -1188,10 +1443,7 @@ setup_rx_desc_die: DPRINTK(PROBE, ERR, "Unable to allocate aligned memory " "for the receive descriptor ring\n"); - vfree(rxdr->buffer_info); - kfree(rxdr->ps_page); - kfree(rxdr->ps_page_dma); - return -ENOMEM; + goto setup_rx_desc_die; } else { /* Free old allocation, new allocation was successful */ pci_free_consistent(pdev, rxdr->size, olddesc, olddma); @@ -1206,15 +1458,48 @@ setup_rx_desc_die: } /** + * e1000_setup_all_rx_resources - wrapper to allocate Rx resources + * (Descriptors) for all queues + * @adapter: board private structure + * + * If this function returns with an error, then it's possible one or + * more of the rings is populated (while the rest are not). It is the + * callers duty to clean those orphaned rings. + * + * Return 0 on success, negative on failure + **/ + +int +e1000_setup_all_rx_resources(struct e1000_adapter *adapter) +{ + int i, err = 0; + + for (i = 0; i < adapter->num_queues; i++) { + err = e1000_setup_rx_resources(adapter, &adapter->rx_ring[i]); + if (err) { + DPRINTK(PROBE, ERR, + "Allocation for Rx Queue %u failed\n", i); + break; + } + } + + return err; +} + +/** * e1000_setup_rctl - configure the receive control registers * @adapter: Board private structure **/ - +#define PAGE_USE_COUNT(S) (((S) >> PAGE_SHIFT) + \ + (((S) & (PAGE_SIZE - 1)) ? 1 : 0)) static void e1000_setup_rctl(struct e1000_adapter *adapter) { uint32_t rctl, rfctl; uint32_t psrctl = 0; +#ifdef CONFIG_E1000_PACKET_SPLIT + uint32_t pages = 0; +#endif rctl = E1000_READ_REG(&adapter->hw, RCTL); @@ -1235,7 +1520,7 @@ e1000_setup_rctl(struct e1000_adapter *adapter) rctl |= E1000_RCTL_LPE; /* Setup buffer sizes */ - if(adapter->hw.mac_type == e1000_82573) { + if(adapter->hw.mac_type >= e1000_82571) { /* We can now specify buffers in 1K increments. * BSIZE and BSEX are ignored in this case. */ rctl |= adapter->rx_buffer_len << 0x11; @@ -1268,11 +1553,14 @@ e1000_setup_rctl(struct e1000_adapter *adapter) * followed by the page buffers. Therefore, skb->data is * sized to hold the largest protocol header. */ - adapter->rx_ps = (adapter->hw.mac_type > e1000_82547_rev_2) - && (adapter->netdev->mtu - < ((3 * PAGE_SIZE) + adapter->rx_ps_bsize0)); + pages = PAGE_USE_COUNT(adapter->netdev->mtu); + if ((adapter->hw.mac_type > e1000_82547_rev_2) && (pages <= 3) && + PAGE_SIZE <= 16384) + adapter->rx_ps_pages = pages; + else + adapter->rx_ps_pages = 0; #endif - if(adapter->rx_ps) { + if (adapter->rx_ps_pages) { /* Configure extra packet-split registers */ rfctl = E1000_READ_REG(&adapter->hw, RFCTL); rfctl |= E1000_RFCTL_EXTEN; @@ -1284,12 +1572,19 @@ e1000_setup_rctl(struct e1000_adapter *adapter) psrctl |= adapter->rx_ps_bsize0 >> E1000_PSRCTL_BSIZE0_SHIFT; - psrctl |= PAGE_SIZE >> - E1000_PSRCTL_BSIZE1_SHIFT; - psrctl |= PAGE_SIZE << - E1000_PSRCTL_BSIZE2_SHIFT; - psrctl |= PAGE_SIZE << - E1000_PSRCTL_BSIZE3_SHIFT; + + switch (adapter->rx_ps_pages) { + case 3: + psrctl |= PAGE_SIZE << + E1000_PSRCTL_BSIZE3_SHIFT; + case 2: + psrctl |= PAGE_SIZE << + E1000_PSRCTL_BSIZE2_SHIFT; + case 1: + psrctl |= PAGE_SIZE >> + E1000_PSRCTL_BSIZE1_SHIFT; + break; + } E1000_WRITE_REG(&adapter->hw, PSRCTL, psrctl); } @@ -1307,91 +1602,181 @@ e1000_setup_rctl(struct e1000_adapter *adapter) static void e1000_configure_rx(struct e1000_adapter *adapter) { - uint64_t rdba = adapter->rx_ring.dma; - uint32_t rdlen, rctl, rxcsum; + uint64_t rdba; + struct e1000_hw *hw = &adapter->hw; + uint32_t rdlen, rctl, rxcsum, ctrl_ext; +#ifdef CONFIG_E1000_MQ + uint32_t reta, mrqc; + int i; +#endif - if(adapter->rx_ps) { - rdlen = adapter->rx_ring.count * + if (adapter->rx_ps_pages) { + rdlen = adapter->rx_ring[0].count * sizeof(union e1000_rx_desc_packet_split); adapter->clean_rx = e1000_clean_rx_irq_ps; adapter->alloc_rx_buf = e1000_alloc_rx_buffers_ps; } else { - rdlen = adapter->rx_ring.count * sizeof(struct e1000_rx_desc); + rdlen = adapter->rx_ring[0].count * + sizeof(struct e1000_rx_desc); adapter->clean_rx = e1000_clean_rx_irq; adapter->alloc_rx_buf = e1000_alloc_rx_buffers; } /* disable receives while setting up the descriptors */ - rctl = E1000_READ_REG(&adapter->hw, RCTL); - E1000_WRITE_REG(&adapter->hw, RCTL, rctl & ~E1000_RCTL_EN); + rctl = E1000_READ_REG(hw, RCTL); + E1000_WRITE_REG(hw, RCTL, rctl & ~E1000_RCTL_EN); /* set the Receive Delay Timer Register */ - E1000_WRITE_REG(&adapter->hw, RDTR, adapter->rx_int_delay); + E1000_WRITE_REG(hw, RDTR, adapter->rx_int_delay); - if(adapter->hw.mac_type >= e1000_82540) { - E1000_WRITE_REG(&adapter->hw, RADV, adapter->rx_abs_int_delay); + if (hw->mac_type >= e1000_82540) { + E1000_WRITE_REG(hw, RADV, adapter->rx_abs_int_delay); if(adapter->itr > 1) - E1000_WRITE_REG(&adapter->hw, ITR, + E1000_WRITE_REG(hw, ITR, 1000000000 / (adapter->itr * 256)); } - /* Setup the Base and Length of the Rx Descriptor Ring */ - E1000_WRITE_REG(&adapter->hw, RDBAL, (rdba & 0x00000000ffffffffULL)); - E1000_WRITE_REG(&adapter->hw, RDBAH, (rdba >> 32)); + if (hw->mac_type >= e1000_82571) { + /* Reset delay timers after every interrupt */ + ctrl_ext = E1000_READ_REG(hw, CTRL_EXT); + ctrl_ext |= E1000_CTRL_EXT_CANC; + E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext); + E1000_WRITE_FLUSH(hw); + } + + /* Setup the HW Rx Head and Tail Descriptor Pointers and + * the Base and Length of the Rx Descriptor Ring */ + switch (adapter->num_queues) { +#ifdef CONFIG_E1000_MQ + case 2: + rdba = adapter->rx_ring[1].dma; + E1000_WRITE_REG(hw, RDBAL1, (rdba & 0x00000000ffffffffULL)); + E1000_WRITE_REG(hw, RDBAH1, (rdba >> 32)); + E1000_WRITE_REG(hw, RDLEN1, rdlen); + E1000_WRITE_REG(hw, RDH1, 0); + E1000_WRITE_REG(hw, RDT1, 0); + adapter->rx_ring[1].rdh = E1000_RDH1; + adapter->rx_ring[1].rdt = E1000_RDT1; + /* Fall Through */ +#endif + case 1: + default: + rdba = adapter->rx_ring[0].dma; + E1000_WRITE_REG(hw, RDBAL, (rdba & 0x00000000ffffffffULL)); + E1000_WRITE_REG(hw, RDBAH, (rdba >> 32)); + E1000_WRITE_REG(hw, RDLEN, rdlen); + E1000_WRITE_REG(hw, RDH, 0); + E1000_WRITE_REG(hw, RDT, 0); + adapter->rx_ring[0].rdh = E1000_RDH; + adapter->rx_ring[0].rdt = E1000_RDT; + break; + } + +#ifdef CONFIG_E1000_MQ + if (adapter->num_queues > 1) { + uint32_t random[10]; + + get_random_bytes(&random[0], 40); - E1000_WRITE_REG(&adapter->hw, RDLEN, rdlen); + if (hw->mac_type <= e1000_82572) { + E1000_WRITE_REG(hw, RSSIR, 0); + E1000_WRITE_REG(hw, RSSIM, 0); + } + + switch (adapter->num_queues) { + case 2: + default: + reta = 0x00800080; + mrqc = E1000_MRQC_ENABLE_RSS_2Q; + break; + } - /* Setup the HW Rx Head and Tail Descriptor Pointers */ - E1000_WRITE_REG(&adapter->hw, RDH, 0); - E1000_WRITE_REG(&adapter->hw, RDT, 0); + /* Fill out redirection table */ + for (i = 0; i < 32; i++) + E1000_WRITE_REG_ARRAY(hw, RETA, i, reta); + /* Fill out hash function seeds */ + for (i = 0; i < 10; i++) + E1000_WRITE_REG_ARRAY(hw, RSSRK, i, random[i]); + + mrqc |= (E1000_MRQC_RSS_FIELD_IPV4 | + E1000_MRQC_RSS_FIELD_IPV4_TCP); + E1000_WRITE_REG(hw, MRQC, mrqc); + } + + /* Multiqueue and packet checksumming are mutually exclusive. */ + if (hw->mac_type >= e1000_82571) { + rxcsum = E1000_READ_REG(hw, RXCSUM); + rxcsum |= E1000_RXCSUM_PCSD; + E1000_WRITE_REG(hw, RXCSUM, rxcsum); + } + +#else /* Enable 82543 Receive Checksum Offload for TCP and UDP */ - if(adapter->hw.mac_type >= e1000_82543) { - rxcsum = E1000_READ_REG(&adapter->hw, RXCSUM); + if (hw->mac_type >= e1000_82543) { + rxcsum = E1000_READ_REG(hw, RXCSUM); if(adapter->rx_csum == TRUE) { rxcsum |= E1000_RXCSUM_TUOFL; - /* Enable 82573 IPv4 payload checksum for UDP fragments + /* Enable 82571 IPv4 payload checksum for UDP fragments * Must be used in conjunction with packet-split. */ - if((adapter->hw.mac_type > e1000_82547_rev_2) && - (adapter->rx_ps)) { + if ((hw->mac_type >= e1000_82571) && + (adapter->rx_ps_pages)) { rxcsum |= E1000_RXCSUM_IPPCSE; } } else { rxcsum &= ~E1000_RXCSUM_TUOFL; /* don't need to clear IPPCSE as it defaults to 0 */ } - E1000_WRITE_REG(&adapter->hw, RXCSUM, rxcsum); + E1000_WRITE_REG(hw, RXCSUM, rxcsum); } +#endif /* CONFIG_E1000_MQ */ - if (adapter->hw.mac_type == e1000_82573) - E1000_WRITE_REG(&adapter->hw, ERT, 0x0100); + if (hw->mac_type == e1000_82573) + E1000_WRITE_REG(hw, ERT, 0x0100); /* Enable Receives */ - E1000_WRITE_REG(&adapter->hw, RCTL, rctl); + E1000_WRITE_REG(hw, RCTL, rctl); } /** - * e1000_free_tx_resources - Free Tx Resources + * e1000_free_tx_resources - Free Tx Resources per Queue * @adapter: board private structure + * @tx_ring: Tx descriptor ring for a specific queue * * Free all transmit software resources **/ void -e1000_free_tx_resources(struct e1000_adapter *adapter) +e1000_free_tx_resources(struct e1000_adapter *adapter, + struct e1000_tx_ring *tx_ring) { struct pci_dev *pdev = adapter->pdev; - e1000_clean_tx_ring(adapter); + e1000_clean_tx_ring(adapter, tx_ring); - vfree(adapter->tx_ring.buffer_info); - adapter->tx_ring.buffer_info = NULL; + vfree(tx_ring->buffer_info); + tx_ring->buffer_info = NULL; - pci_free_consistent(pdev, adapter->tx_ring.size, - adapter->tx_ring.desc, adapter->tx_ring.dma); + pci_free_consistent(pdev, tx_ring->size, tx_ring->desc, tx_ring->dma); + + tx_ring->desc = NULL; +} + +/** + * e1000_free_all_tx_resources - Free Tx Resources for All Queues + * @adapter: board private structure + * + * Free all transmit software resources + **/ + +void +e1000_free_all_tx_resources(struct e1000_adapter *adapter) +{ + int i; - adapter->tx_ring.desc = NULL; + for (i = 0; i < adapter->num_queues; i++) + e1000_free_tx_resources(adapter, &adapter->tx_ring[i]); } static inline void @@ -1414,21 +1799,22 @@ e1000_unmap_and_free_tx_resource(struct e1000_adapter *adapter, /** * e1000_clean_tx_ring - Free Tx Buffers * @adapter: board private structure + * @tx_ring: ring to be cleaned **/ static void -e1000_clean_tx_ring(struct e1000_adapter *adapter) +e1000_clean_tx_ring(struct e1000_adapter *adapter, + struct e1000_tx_ring *tx_ring) { - struct e1000_desc_ring *tx_ring = &adapter->tx_ring; struct e1000_buffer *buffer_info; unsigned long size; unsigned int i; /* Free all the Tx ring sk_buffs */ - if (likely(adapter->previous_buffer_info.skb != NULL)) { + if (likely(tx_ring->previous_buffer_info.skb != NULL)) { e1000_unmap_and_free_tx_resource(adapter, - &adapter->previous_buffer_info); + &tx_ring->previous_buffer_info); } for(i = 0; i < tx_ring->count; i++) { @@ -1446,24 +1832,39 @@ e1000_clean_tx_ring(struct e1000_adapter *adapter) tx_ring->next_to_use = 0; tx_ring->next_to_clean = 0; - E1000_WRITE_REG(&adapter->hw, TDH, 0); - E1000_WRITE_REG(&adapter->hw, TDT, 0); + writel(0, adapter->hw.hw_addr + tx_ring->tdh); + writel(0, adapter->hw.hw_addr + tx_ring->tdt); +} + +/** + * e1000_clean_all_tx_rings - Free Tx Buffers for all queues + * @adapter: board private structure + **/ + +static void +e1000_clean_all_tx_rings(struct e1000_adapter *adapter) +{ + int i; + + for (i = 0; i < adapter->num_queues; i++) + e1000_clean_tx_ring(adapter, &adapter->tx_ring[i]); } /** * e1000_free_rx_resources - Free Rx Resources * @adapter: board private structure + * @rx_ring: ring to clean the resources from * * Free all receive software resources **/ void -e1000_free_rx_resources(struct e1000_adapter *adapter) +e1000_free_rx_resources(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring) { - struct e1000_desc_ring *rx_ring = &adapter->rx_ring; struct pci_dev *pdev = adapter->pdev; - e1000_clean_rx_ring(adapter); + e1000_clean_rx_ring(adapter, rx_ring); vfree(rx_ring->buffer_info); rx_ring->buffer_info = NULL; @@ -1478,14 +1879,31 @@ e1000_free_rx_resources(struct e1000_adapter *adapter) } /** - * e1000_clean_rx_ring - Free Rx Buffers + * e1000_free_all_rx_resources - Free Rx Resources for All Queues + * @adapter: board private structure + * + * Free all receive software resources + **/ + +void +e1000_free_all_rx_resources(struct e1000_adapter *adapter) +{ + int i; + + for (i = 0; i < adapter->num_queues; i++) + e1000_free_rx_resources(adapter, &adapter->rx_ring[i]); +} + +/** + * e1000_clean_rx_ring - Free Rx Buffers per Queue * @adapter: board private structure + * @rx_ring: ring to free buffers from **/ static void -e1000_clean_rx_ring(struct e1000_adapter *adapter) +e1000_clean_rx_ring(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring) { - struct e1000_desc_ring *rx_ring = &adapter->rx_ring; struct e1000_buffer *buffer_info; struct e1000_ps_page *ps_page; struct e1000_ps_page_dma *ps_page_dma; @@ -1508,7 +1926,7 @@ e1000_clean_rx_ring(struct e1000_adapter *adapter) dev_kfree_skb(buffer_info->skb); buffer_info->skb = NULL; - for(j = 0; j < PS_PAGE_BUFFERS; j++) { + for(j = 0; j < adapter->rx_ps_pages; j++) { if(!ps_page->ps_page[j]) break; pci_unmap_single(pdev, ps_page_dma->ps_page_dma[j], @@ -1534,8 +1952,22 @@ e1000_clean_rx_ring(struct e1000_adapter *adapter) rx_ring->next_to_clean = 0; rx_ring->next_to_use = 0; - E1000_WRITE_REG(&adapter->hw, RDH, 0); - E1000_WRITE_REG(&adapter->hw, RDT, 0); + writel(0, adapter->hw.hw_addr + rx_ring->rdh); + writel(0, adapter->hw.hw_addr + rx_ring->rdt); +} + +/** + * e1000_clean_all_rx_rings - Free Rx Buffers for all queues + * @adapter: board private structure + **/ + +static void +e1000_clean_all_rx_rings(struct e1000_adapter *adapter) +{ + int i; + + for (i = 0; i < adapter->num_queues; i++) + e1000_clean_rx_ring(adapter, &adapter->rx_ring[i]); } /* The 82542 2.0 (revision 2) needs to have the receive unit in reset @@ -1556,7 +1988,7 @@ e1000_enter_82542_rst(struct e1000_adapter *adapter) mdelay(5); if(netif_running(netdev)) - e1000_clean_rx_ring(adapter); + e1000_clean_all_rx_rings(adapter); } static void @@ -1576,7 +2008,7 @@ e1000_leave_82542_rst(struct e1000_adapter *adapter) if(netif_running(netdev)) { e1000_configure_rx(adapter); - e1000_alloc_rx_buffers(adapter); + e1000_alloc_rx_buffers(adapter, &adapter->rx_ring[0]); } } @@ -1607,6 +2039,22 @@ e1000_set_mac(struct net_device *netdev, void *p) e1000_rar_set(&adapter->hw, adapter->hw.mac_addr, 0); + /* With 82571 controllers, LAA may be overwritten (with the default) + * due to controller reset from the other port. */ + if (adapter->hw.mac_type == e1000_82571) { + /* activate the work around */ + adapter->hw.laa_is_present = 1; + + /* Hold a copy of the LAA in RAR[14] This is done so that + * between the time RAR[0] gets clobbered and the time it + * gets fixed (in e1000_watchdog), the actual LAA is in one + * of the RARs and no incoming packets directed to this port + * are dropped. Eventaully the LAA will be in RAR[0] and + * RAR[14] */ + e1000_rar_set(&adapter->hw, adapter->hw.mac_addr, + E1000_RAR_ENTRIES - 1); + } + if(adapter->hw.mac_type == e1000_82542_rev2_0) e1000_leave_82542_rst(adapter); @@ -1629,12 +2077,13 @@ e1000_set_multi(struct net_device *netdev) struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; struct dev_mc_list *mc_ptr; - unsigned long flags; uint32_t rctl; uint32_t hash_value; - int i; + int i, rar_entries = E1000_RAR_ENTRIES; - spin_lock_irqsave(&adapter->tx_lock, flags); + /* reserve RAR[14] for LAA over-write work-around */ + if (adapter->hw.mac_type == e1000_82571) + rar_entries--; /* Check for Promiscuous and All Multicast modes */ @@ -1659,11 +2108,12 @@ e1000_set_multi(struct net_device *netdev) /* load the first 14 multicast address into the exact filters 1-14 * RAR 0 is used for the station MAC adddress * if there are not 14 addresses, go ahead and clear the filters + * -- with 82571 controllers only 0-13 entries are filled here */ mc_ptr = netdev->mc_list; - for(i = 1; i < E1000_RAR_ENTRIES; i++) { - if(mc_ptr) { + for(i = 1; i < rar_entries; i++) { + if (mc_ptr) { e1000_rar_set(hw, mc_ptr->dmi_addr, i); mc_ptr = mc_ptr->next; } else { @@ -1686,8 +2136,6 @@ e1000_set_multi(struct net_device *netdev) if(hw->mac_type == e1000_82542_rev2_0) e1000_leave_82542_rst(adapter); - - spin_unlock_irqrestore(&adapter->tx_lock, flags); } /* Need to wait a few seconds after link up to get diagnostic information from @@ -1759,7 +2207,7 @@ static void e1000_watchdog_task(struct e1000_adapter *adapter) { struct net_device *netdev = adapter->netdev; - struct e1000_desc_ring *txdr = &adapter->tx_ring; + struct e1000_tx_ring *txdr = &adapter->tx_ring[0]; uint32_t link; e1000_check_for_link(&adapter->hw); @@ -1818,8 +2266,8 @@ e1000_watchdog_task(struct e1000_adapter *adapter) e1000_update_adaptive(&adapter->hw); - if(!netif_carrier_ok(netdev)) { - if(E1000_DESC_UNUSED(txdr) + 1 < txdr->count) { + if (adapter->num_queues == 1 && !netif_carrier_ok(netdev)) { + if (E1000_DESC_UNUSED(txdr) + 1 < txdr->count) { /* We've lost link, so the controller stops DMA, * but we've got queued Tx work that's never going * to get done, so reset controller to flush Tx. @@ -1847,6 +2295,11 @@ e1000_watchdog_task(struct e1000_adapter *adapter) /* Force detection of hung controller every watchdog period */ adapter->detect_tx_hung = TRUE; + /* With 82571 controllers, LAA may be overwritten due to controller + * reset from the other port. Set the appropriate LAA in RAR[0] */ + if (adapter->hw.mac_type == e1000_82571 && adapter->hw.laa_is_present) + e1000_rar_set(&adapter->hw, adapter->hw.mac_addr, 0); + /* Reset the timer */ mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ); } @@ -1859,7 +2312,8 @@ e1000_watchdog_task(struct e1000_adapter *adapter) #define E1000_TX_FLAGS_VLAN_SHIFT 16 static inline int -e1000_tso(struct e1000_adapter *adapter, struct sk_buff *skb) +e1000_tso(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring, + struct sk_buff *skb) { #ifdef NETIF_F_TSO struct e1000_context_desc *context_desc; @@ -1910,8 +2364,8 @@ e1000_tso(struct e1000_adapter *adapter, struct sk_buff *skb) cmd_length |= (E1000_TXD_CMD_DEXT | E1000_TXD_CMD_TSE | E1000_TXD_CMD_TCP | (skb->len - (hdr_len))); - i = adapter->tx_ring.next_to_use; - context_desc = E1000_CONTEXT_DESC(adapter->tx_ring, i); + i = tx_ring->next_to_use; + context_desc = E1000_CONTEXT_DESC(*tx_ring, i); context_desc->lower_setup.ip_fields.ipcss = ipcss; context_desc->lower_setup.ip_fields.ipcso = ipcso; @@ -1923,8 +2377,8 @@ e1000_tso(struct e1000_adapter *adapter, struct sk_buff *skb) context_desc->tcp_seg_setup.fields.hdr_len = hdr_len; context_desc->cmd_and_length = cpu_to_le32(cmd_length); - if(++i == adapter->tx_ring.count) i = 0; - adapter->tx_ring.next_to_use = i; + if (++i == tx_ring->count) i = 0; + tx_ring->next_to_use = i; return 1; } @@ -1934,7 +2388,8 @@ e1000_tso(struct e1000_adapter *adapter, struct sk_buff *skb) } static inline boolean_t -e1000_tx_csum(struct e1000_adapter *adapter, struct sk_buff *skb) +e1000_tx_csum(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring, + struct sk_buff *skb) { struct e1000_context_desc *context_desc; unsigned int i; @@ -1943,8 +2398,8 @@ e1000_tx_csum(struct e1000_adapter *adapter, struct sk_buff *skb) if(likely(skb->ip_summed == CHECKSUM_HW)) { css = skb->h.raw - skb->data; - i = adapter->tx_ring.next_to_use; - context_desc = E1000_CONTEXT_DESC(adapter->tx_ring, i); + i = tx_ring->next_to_use; + context_desc = E1000_CONTEXT_DESC(*tx_ring, i); context_desc->upper_setup.tcp_fields.tucss = css; context_desc->upper_setup.tcp_fields.tucso = css + skb->csum; @@ -1952,8 +2407,8 @@ e1000_tx_csum(struct e1000_adapter *adapter, struct sk_buff *skb) context_desc->tcp_seg_setup.data = 0; context_desc->cmd_and_length = cpu_to_le32(E1000_TXD_CMD_DEXT); - if(unlikely(++i == adapter->tx_ring.count)) i = 0; - adapter->tx_ring.next_to_use = i; + if (unlikely(++i == tx_ring->count)) i = 0; + tx_ring->next_to_use = i; return TRUE; } @@ -1965,11 +2420,10 @@ e1000_tx_csum(struct e1000_adapter *adapter, struct sk_buff *skb) #define E1000_MAX_DATA_PER_TXD (1<<E1000_MAX_TXD_PWR) static inline int -e1000_tx_map(struct e1000_adapter *adapter, struct sk_buff *skb, - unsigned int first, unsigned int max_per_txd, - unsigned int nr_frags, unsigned int mss) +e1000_tx_map(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring, + struct sk_buff *skb, unsigned int first, unsigned int max_per_txd, + unsigned int nr_frags, unsigned int mss) { - struct e1000_desc_ring *tx_ring = &adapter->tx_ring; struct e1000_buffer *buffer_info; unsigned int len = skb->len; unsigned int offset = 0, size, count = 0, i; @@ -2065,9 +2519,9 @@ e1000_tx_map(struct e1000_adapter *adapter, struct sk_buff *skb, } static inline void -e1000_tx_queue(struct e1000_adapter *adapter, int count, int tx_flags) +e1000_tx_queue(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring, + int tx_flags, int count) { - struct e1000_desc_ring *tx_ring = &adapter->tx_ring; struct e1000_tx_desc *tx_desc = NULL; struct e1000_buffer *buffer_info; uint32_t txd_upper = 0, txd_lower = E1000_TXD_CMD_IFCS; @@ -2113,7 +2567,7 @@ e1000_tx_queue(struct e1000_adapter *adapter, int count, int tx_flags) wmb(); tx_ring->next_to_use = i; - E1000_WRITE_REG(&adapter->hw, TDT, i); + writel(i, adapter->hw.hw_addr + tx_ring->tdt); } /** @@ -2206,6 +2660,7 @@ static int e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) { struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_tx_ring *tx_ring; unsigned int first, max_per_txd = E1000_MAX_DATA_PER_TXD; unsigned int max_txd_pwr = E1000_MAX_TXD_PWR; unsigned int tx_flags = 0; @@ -2218,7 +2673,13 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) unsigned int f; len -= skb->data_len; - if(unlikely(skb->len <= 0)) { +#ifdef CONFIG_E1000_MQ + tx_ring = *per_cpu_ptr(adapter->cpu_tx_ring, smp_processor_id()); +#else + tx_ring = adapter->tx_ring; +#endif + + if (unlikely(skb->len <= 0)) { dev_kfree_skb_any(skb); return NETDEV_TX_OK; } @@ -2262,21 +2723,42 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) if(adapter->pcix_82544) count += nr_frags; - local_irq_save(flags); - if (!spin_trylock(&adapter->tx_lock)) { - /* Collision - tell upper layer to requeue */ - local_irq_restore(flags); - return NETDEV_TX_LOCKED; - } +#ifdef NETIF_F_TSO + /* TSO Workaround for 82571/2 Controllers -- if skb->data + * points to just header, pull a few bytes of payload from + * frags into skb->data */ + if (skb_shinfo(skb)->tso_size) { + uint8_t hdr_len; + hdr_len = ((skb->h.raw - skb->data) + (skb->h.th->doff << 2)); + if (skb->data_len && (hdr_len < (skb->len - skb->data_len)) && + (adapter->hw.mac_type == e1000_82571 || + adapter->hw.mac_type == e1000_82572)) { + unsigned int pull_size; + pull_size = min((unsigned int)4, skb->data_len); + if (!__pskb_pull_tail(skb, pull_size)) { + printk(KERN_ERR "__pskb_pull_tail failed.\n"); + dev_kfree_skb_any(skb); + return -EFAULT; + } + } + } +#endif + if(adapter->hw.tx_pkt_filtering && (adapter->hw.mac_type == e1000_82573) ) e1000_transfer_dhcp_info(adapter, skb); + local_irq_save(flags); + if (!spin_trylock(&tx_ring->tx_lock)) { + /* Collision - tell upper layer to requeue */ + local_irq_restore(flags); + return NETDEV_TX_LOCKED; + } /* need: count + 2 desc gap to keep tail from touching * head, otherwise try next time */ - if(unlikely(E1000_DESC_UNUSED(&adapter->tx_ring) < count + 2)) { + if (unlikely(E1000_DESC_UNUSED(tx_ring) < count + 2)) { netif_stop_queue(netdev); - spin_unlock_irqrestore(&adapter->tx_lock, flags); + spin_unlock_irqrestore(&tx_ring->tx_lock, flags); return NETDEV_TX_BUSY; } @@ -2284,7 +2766,7 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) if(unlikely(e1000_82547_fifo_workaround(adapter, skb))) { netif_stop_queue(netdev); mod_timer(&adapter->tx_fifo_stall_timer, jiffies); - spin_unlock_irqrestore(&adapter->tx_lock, flags); + spin_unlock_irqrestore(&tx_ring->tx_lock, flags); return NETDEV_TX_BUSY; } } @@ -2294,37 +2776,37 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) tx_flags |= (vlan_tx_tag_get(skb) << E1000_TX_FLAGS_VLAN_SHIFT); } - first = adapter->tx_ring.next_to_use; + first = tx_ring->next_to_use; - tso = e1000_tso(adapter, skb); + tso = e1000_tso(adapter, tx_ring, skb); if (tso < 0) { dev_kfree_skb_any(skb); - spin_unlock_irqrestore(&adapter->tx_lock, flags); + spin_unlock_irqrestore(&tx_ring->tx_lock, flags); return NETDEV_TX_OK; } if (likely(tso)) tx_flags |= E1000_TX_FLAGS_TSO; - else if(likely(e1000_tx_csum(adapter, skb))) + else if (likely(e1000_tx_csum(adapter, tx_ring, skb))) tx_flags |= E1000_TX_FLAGS_CSUM; /* Old method was to assume IPv4 packet by default if TSO was enabled. - * 82573 hardware supports TSO capabilities for IPv6 as well... + * 82571 hardware supports TSO capabilities for IPv6 as well... * no longer assume, we must. */ - if(likely(skb->protocol == ntohs(ETH_P_IP))) + if (likely(skb->protocol == ntohs(ETH_P_IP))) tx_flags |= E1000_TX_FLAGS_IPV4; - e1000_tx_queue(adapter, - e1000_tx_map(adapter, skb, first, max_per_txd, nr_frags, mss), - tx_flags); + e1000_tx_queue(adapter, tx_ring, tx_flags, + e1000_tx_map(adapter, tx_ring, skb, first, + max_per_txd, nr_frags, mss)); netdev->trans_start = jiffies; /* Make sure there is space in the ring for the next send. */ - if(unlikely(E1000_DESC_UNUSED(&adapter->tx_ring) < MAX_SKB_FRAGS + 2)) + if (unlikely(E1000_DESC_UNUSED(tx_ring) < MAX_SKB_FRAGS + 2)) netif_stop_queue(netdev); - spin_unlock_irqrestore(&adapter->tx_lock, flags); + spin_unlock_irqrestore(&tx_ring->tx_lock, flags); return NETDEV_TX_OK; } @@ -2388,9 +2870,18 @@ e1000_change_mtu(struct net_device *netdev, int new_mtu) return -EINVAL; } -#define MAX_STD_JUMBO_FRAME_SIZE 9216 +#define MAX_STD_JUMBO_FRAME_SIZE 9234 /* might want this to be bigger enum check... */ - if (adapter->hw.mac_type == e1000_82573 && + /* 82571 controllers limit jumbo frame size to 10500 bytes */ + if ((adapter->hw.mac_type == e1000_82571 || + adapter->hw.mac_type == e1000_82572) && + max_frame > MAX_STD_JUMBO_FRAME_SIZE) { + DPRINTK(PROBE, ERR, "MTU > 9216 bytes not supported " + "on 82571 and 82572 controllers.\n"); + return -EINVAL; + } + + if(adapter->hw.mac_type == e1000_82573 && max_frame > MAXIMUM_ETHERNET_FRAME_SIZE) { DPRINTK(PROBE, ERR, "Jumbo Frames not supported " "on 82573\n"); @@ -2578,6 +3069,29 @@ e1000_update_stats(struct e1000_adapter *adapter) spin_unlock_irqrestore(&adapter->stats_lock, flags); } +#ifdef CONFIG_E1000_MQ +void +e1000_rx_schedule(void *data) +{ + struct net_device *poll_dev, *netdev = data; + struct e1000_adapter *adapter = netdev->priv; + int this_cpu = get_cpu(); + + poll_dev = *per_cpu_ptr(adapter->cpu_netdev, this_cpu); + if (poll_dev == NULL) { + put_cpu(); + return; + } + + if (likely(netif_rx_schedule_prep(poll_dev))) + __netif_rx_schedule(poll_dev); + else + e1000_irq_enable(adapter); + + put_cpu(); +} +#endif + /** * e1000_intr - Interrupt Handler * @irq: interrupt number @@ -2592,8 +3106,8 @@ e1000_intr(int irq, void *data, struct pt_regs *regs) struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; uint32_t icr = E1000_READ_REG(hw, ICR); -#ifndef CONFIG_E1000_NAPI - unsigned int i; +#if defined(CONFIG_E1000_NAPI) && defined(CONFIG_E1000_MQ) || !defined(CONFIG_E1000_NAPI) + int i; #endif if(unlikely(!icr)) @@ -2605,17 +3119,31 @@ e1000_intr(int irq, void *data, struct pt_regs *regs) } #ifdef CONFIG_E1000_NAPI - if(likely(netif_rx_schedule_prep(netdev))) { - - /* Disable interrupts and register for poll. The flush - of the posted write is intentionally left out. - */ - - atomic_inc(&adapter->irq_sem); - E1000_WRITE_REG(hw, IMC, ~0); - __netif_rx_schedule(netdev); + atomic_inc(&adapter->irq_sem); + E1000_WRITE_REG(hw, IMC, ~0); + E1000_WRITE_FLUSH(hw); +#ifdef CONFIG_E1000_MQ + if (atomic_read(&adapter->rx_sched_call_data.count) == 0) { + cpu_set(adapter->cpu_for_queue[0], + adapter->rx_sched_call_data.cpumask); + for (i = 1; i < adapter->num_queues; i++) { + cpu_set(adapter->cpu_for_queue[i], + adapter->rx_sched_call_data.cpumask); + atomic_inc(&adapter->irq_sem); + } + atomic_set(&adapter->rx_sched_call_data.count, i); + smp_call_async_mask(&adapter->rx_sched_call_data); + } else { + printk("call_data.count == %u\n", atomic_read(&adapter->rx_sched_call_data.count)); } -#else +#else /* if !CONFIG_E1000_MQ */ + if (likely(netif_rx_schedule_prep(&adapter->polling_netdev[0]))) + __netif_rx_schedule(&adapter->polling_netdev[0]); + else + e1000_irq_enable(adapter); +#endif /* CONFIG_E1000_MQ */ + +#else /* if !CONFIG_E1000_NAPI */ /* Writing IMC and IMS is needed for 82547. Due to Hub Link bus being occupied, an interrupt de-assertion message is not able to be sent. @@ -2632,13 +3160,14 @@ e1000_intr(int irq, void *data, struct pt_regs *regs) } for(i = 0; i < E1000_MAX_INTR; i++) - if(unlikely(!adapter->clean_rx(adapter) & - !e1000_clean_tx_irq(adapter))) + if(unlikely(!adapter->clean_rx(adapter, adapter->rx_ring) & + !e1000_clean_tx_irq(adapter, adapter->tx_ring))) break; if(hw->mac_type == e1000_82547 || hw->mac_type == e1000_82547_rev_2) e1000_irq_enable(adapter); -#endif + +#endif /* CONFIG_E1000_NAPI */ return IRQ_HANDLED; } @@ -2650,22 +3179,37 @@ e1000_intr(int irq, void *data, struct pt_regs *regs) **/ static int -e1000_clean(struct net_device *netdev, int *budget) +e1000_clean(struct net_device *poll_dev, int *budget) { - struct e1000_adapter *adapter = netdev_priv(netdev); - int work_to_do = min(*budget, netdev->quota); - int tx_cleaned; - int work_done = 0; + struct e1000_adapter *adapter; + int work_to_do = min(*budget, poll_dev->quota); + int tx_cleaned, i = 0, work_done = 0; + + /* Must NOT use netdev_priv macro here. */ + adapter = poll_dev->priv; - tx_cleaned = e1000_clean_tx_irq(adapter); - adapter->clean_rx(adapter, &work_done, work_to_do); + /* Keep link state information with original netdev */ + if (!netif_carrier_ok(adapter->netdev)) + goto quit_polling; + + while (poll_dev != &adapter->polling_netdev[i]) { + i++; + if (unlikely(i == adapter->num_queues)) + BUG(); + } + + tx_cleaned = e1000_clean_tx_irq(adapter, &adapter->tx_ring[i]); + adapter->clean_rx(adapter, &adapter->rx_ring[i], + &work_done, work_to_do); *budget -= work_done; - netdev->quota -= work_done; + poll_dev->quota -= work_done; - if ((!tx_cleaned && (work_done == 0)) || !netif_running(netdev)) { /* If no Tx and not enough Rx work done, exit the polling mode */ - netif_rx_complete(netdev); + if((!tx_cleaned && (work_done == 0)) || + !netif_running(adapter->netdev)) { +quit_polling: + netif_rx_complete(poll_dev); e1000_irq_enable(adapter); return 0; } @@ -2680,9 +3224,9 @@ e1000_clean(struct net_device *netdev, int *budget) **/ static boolean_t -e1000_clean_tx_irq(struct e1000_adapter *adapter) +e1000_clean_tx_irq(struct e1000_adapter *adapter, + struct e1000_tx_ring *tx_ring) { - struct e1000_desc_ring *tx_ring = &adapter->tx_ring; struct net_device *netdev = adapter->netdev; struct e1000_tx_desc *tx_desc, *eop_desc; struct e1000_buffer *buffer_info; @@ -2693,12 +3237,12 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter) eop = tx_ring->buffer_info[i].next_to_watch; eop_desc = E1000_TX_DESC(*tx_ring, eop); - while(eop_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) { + while (eop_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) { /* Premature writeback of Tx descriptors clear (free buffers * and unmap pci_mapping) previous_buffer_info */ - if (likely(adapter->previous_buffer_info.skb != NULL)) { + if (likely(tx_ring->previous_buffer_info.skb != NULL)) { e1000_unmap_and_free_tx_resource(adapter, - &adapter->previous_buffer_info); + &tx_ring->previous_buffer_info); } for(cleaned = FALSE; !cleaned; ) { @@ -2714,7 +3258,7 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter) #ifdef NETIF_F_TSO } else { if (cleaned) { - memcpy(&adapter->previous_buffer_info, + memcpy(&tx_ring->previous_buffer_info, buffer_info, sizeof(struct e1000_buffer)); memset(buffer_info, 0, @@ -2732,6 +3276,8 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter) if(unlikely(++i == tx_ring->count)) i = 0; } + + tx_ring->pkt++; eop = tx_ring->buffer_info[i].next_to_watch; eop_desc = E1000_TX_DESC(*tx_ring, eop); @@ -2739,15 +3285,15 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter) tx_ring->next_to_clean = i; - spin_lock(&adapter->tx_lock); + spin_lock(&tx_ring->tx_lock); if(unlikely(cleaned && netif_queue_stopped(netdev) && netif_carrier_ok(netdev))) netif_wake_queue(netdev); - spin_unlock(&adapter->tx_lock); - if(adapter->detect_tx_hung) { + spin_unlock(&tx_ring->tx_lock); + if (adapter->detect_tx_hung) { /* Detect a transmit hang in hardware, this serializes the * check with the clearing of time_stamp and movement of i */ adapter->detect_tx_hung = FALSE; @@ -2771,8 +3317,8 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter) " next_to_watch <%x>\n" " jiffies <%lx>\n" " next_to_watch.status <%x>\n", - E1000_READ_REG(&adapter->hw, TDH), - E1000_READ_REG(&adapter->hw, TDT), + readl(adapter->hw.hw_addr + tx_ring->tdh), + readl(adapter->hw.hw_addr + tx_ring->tdt), tx_ring->next_to_use, i, (unsigned long long)tx_ring->buffer_info[i].dma, @@ -2784,12 +3330,10 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter) } } #ifdef NETIF_F_TSO - - if( unlikely(!(eop_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) && - time_after(jiffies, adapter->previous_buffer_info.time_stamp + HZ))) + if (unlikely(!(eop_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) && + time_after(jiffies, tx_ring->previous_buffer_info.time_stamp + HZ))) e1000_unmap_and_free_tx_resource( - adapter, &adapter->previous_buffer_info); - + adapter, &tx_ring->previous_buffer_info); #endif return cleaned; } @@ -2852,13 +3396,14 @@ e1000_rx_checksum(struct e1000_adapter *adapter, static boolean_t #ifdef CONFIG_E1000_NAPI -e1000_clean_rx_irq(struct e1000_adapter *adapter, int *work_done, - int work_to_do) +e1000_clean_rx_irq(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring, + int *work_done, int work_to_do) #else -e1000_clean_rx_irq(struct e1000_adapter *adapter) +e1000_clean_rx_irq(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring) #endif { - struct e1000_desc_ring *rx_ring = &adapter->rx_ring; struct net_device *netdev = adapter->netdev; struct pci_dev *pdev = adapter->pdev; struct e1000_rx_desc *rx_desc; @@ -2944,6 +3489,7 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter) } #endif /* CONFIG_E1000_NAPI */ netdev->last_rx = jiffies; + rx_ring->pkt++; next_desc: rx_desc->status = 0; @@ -2953,7 +3499,7 @@ next_desc: rx_desc = E1000_RX_DESC(*rx_ring, i); } rx_ring->next_to_clean = i; - adapter->alloc_rx_buf(adapter); + adapter->alloc_rx_buf(adapter, rx_ring); return cleaned; } @@ -2965,13 +3511,14 @@ next_desc: static boolean_t #ifdef CONFIG_E1000_NAPI -e1000_clean_rx_irq_ps(struct e1000_adapter *adapter, int *work_done, - int work_to_do) +e1000_clean_rx_irq_ps(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring, + int *work_done, int work_to_do) #else -e1000_clean_rx_irq_ps(struct e1000_adapter *adapter) +e1000_clean_rx_irq_ps(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring) #endif { - struct e1000_desc_ring *rx_ring = &adapter->rx_ring; union e1000_rx_desc_packet_split *rx_desc; struct net_device *netdev = adapter->netdev; struct pci_dev *pdev = adapter->pdev; @@ -3027,7 +3574,7 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter) /* Good Receive */ skb_put(skb, length); - for(j = 0; j < PS_PAGE_BUFFERS; j++) { + for(j = 0; j < adapter->rx_ps_pages; j++) { if(!(length = le16_to_cpu(rx_desc->wb.upper.length[j]))) break; @@ -3048,11 +3595,13 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter) rx_desc->wb.lower.hi_dword.csum_ip.csum, skb); skb->protocol = eth_type_trans(skb, netdev); -#ifdef HAVE_RX_ZERO_COPY if(likely(rx_desc->wb.upper.header_status & - E1000_RXDPS_HDRSTAT_HDRSP)) + E1000_RXDPS_HDRSTAT_HDRSP)) { + adapter->rx_hdr_split++; +#ifdef HAVE_RX_ZERO_COPY skb_shinfo(skb)->zero_copy = TRUE; #endif + } #ifdef CONFIG_E1000_NAPI if(unlikely(adapter->vlgrp && (staterr & E1000_RXD_STAT_VP))) { vlan_hwaccel_receive_skb(skb, adapter->vlgrp, @@ -3071,6 +3620,7 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter) } #endif /* CONFIG_E1000_NAPI */ netdev->last_rx = jiffies; + rx_ring->pkt++; next_desc: rx_desc->wb.middle.status_error &= ~0xFF; @@ -3081,7 +3631,7 @@ next_desc: staterr = le32_to_cpu(rx_desc->wb.middle.status_error); } rx_ring->next_to_clean = i; - adapter->alloc_rx_buf(adapter); + adapter->alloc_rx_buf(adapter, rx_ring); return cleaned; } @@ -3092,9 +3642,9 @@ next_desc: **/ static void -e1000_alloc_rx_buffers(struct e1000_adapter *adapter) +e1000_alloc_rx_buffers(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring) { - struct e1000_desc_ring *rx_ring = &adapter->rx_ring; struct net_device *netdev = adapter->netdev; struct pci_dev *pdev = adapter->pdev; struct e1000_rx_desc *rx_desc; @@ -3178,7 +3728,7 @@ e1000_alloc_rx_buffers(struct e1000_adapter *adapter) * applicable for weak-ordered memory model archs, * such as IA-64). */ wmb(); - E1000_WRITE_REG(&adapter->hw, RDT, i); + writel(i, adapter->hw.hw_addr + rx_ring->rdt); } if(unlikely(++i == rx_ring->count)) i = 0; @@ -3194,9 +3744,9 @@ e1000_alloc_rx_buffers(struct e1000_adapter *adapter) **/ static void -e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter) +e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring) { - struct e1000_desc_ring *rx_ring = &adapter->rx_ring; struct net_device *netdev = adapter->netdev; struct pci_dev *pdev = adapter->pdev; union e1000_rx_desc_packet_split *rx_desc; @@ -3215,22 +3765,26 @@ e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter) rx_desc = E1000_RX_DESC_PS(*rx_ring, i); for(j = 0; j < PS_PAGE_BUFFERS; j++) { - if(unlikely(!ps_page->ps_page[j])) { - ps_page->ps_page[j] = - alloc_page(GFP_ATOMIC); - if(unlikely(!ps_page->ps_page[j])) - goto no_buffers; - ps_page_dma->ps_page_dma[j] = - pci_map_page(pdev, - ps_page->ps_page[j], - 0, PAGE_SIZE, - PCI_DMA_FROMDEVICE); - } - /* Refresh the desc even if buffer_addrs didn't - * change because each write-back erases this info. - */ - rx_desc->read.buffer_addr[j+1] = - cpu_to_le64(ps_page_dma->ps_page_dma[j]); + if (j < adapter->rx_ps_pages) { + if (likely(!ps_page->ps_page[j])) { + ps_page->ps_page[j] = + alloc_page(GFP_ATOMIC); + if (unlikely(!ps_page->ps_page[j])) + goto no_buffers; + ps_page_dma->ps_page_dma[j] = + pci_map_page(pdev, + ps_page->ps_page[j], + 0, PAGE_SIZE, + PCI_DMA_FROMDEVICE); + } + /* Refresh the desc even if buffer_addrs didn't + * change because each write-back erases + * this info. + */ + rx_desc->read.buffer_addr[j+1] = + cpu_to_le64(ps_page_dma->ps_page_dma[j]); + } else + rx_desc->read.buffer_addr[j+1] = ~0; } skb = dev_alloc_skb(adapter->rx_ps_bsize0 + NET_IP_ALIGN); @@ -3264,7 +3818,7 @@ e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter) * descriptors are 32 bytes...so we increment tail * twice as much. */ - E1000_WRITE_REG(&adapter->hw, RDT, i<<1); + writel(i<<1, adapter->hw.hw_addr + rx_ring->rdt); } if(unlikely(++i == rx_ring->count)) i = 0; @@ -3640,6 +4194,7 @@ e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx) return 0; } +#ifdef CONFIG_PM static int e1000_suspend(struct pci_dev *pdev, pm_message_t state) { @@ -3715,6 +4270,12 @@ e1000_suspend(struct pci_dev *pdev, pm_message_t state) } switch(adapter->hw.mac_type) { + case e1000_82571: + case e1000_82572: + ctrl_ext = E1000_READ_REG(&adapter->hw, CTRL_EXT); + E1000_WRITE_REG(&adapter->hw, CTRL_EXT, + ctrl_ext & ~E1000_CTRL_EXT_DRV_LOAD); + break; case e1000_82573: swsm = E1000_READ_REG(&adapter->hw, SWSM); E1000_WRITE_REG(&adapter->hw, SWSM, @@ -3730,13 +4291,13 @@ e1000_suspend(struct pci_dev *pdev, pm_message_t state) return 0; } -#ifdef CONFIG_PM static int e1000_resume(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); struct e1000_adapter *adapter = netdev_priv(netdev); uint32_t manc, ret_val, swsm; + uint32_t ctrl_ext; pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); @@ -3762,6 +4323,12 @@ e1000_resume(struct pci_dev *pdev) } switch(adapter->hw.mac_type) { + case e1000_82571: + case e1000_82572: + ctrl_ext = E1000_READ_REG(&adapter->hw, CTRL_EXT); + E1000_WRITE_REG(&adapter->hw, CTRL_EXT, + ctrl_ext | E1000_CTRL_EXT_DRV_LOAD); + break; case e1000_82573: swsm = E1000_READ_REG(&adapter->hw, SWSM); E1000_WRITE_REG(&adapter->hw, SWSM, @@ -3786,7 +4353,7 @@ e1000_netpoll(struct net_device *netdev) struct e1000_adapter *adapter = netdev_priv(netdev); disable_irq(adapter->pdev->irq); e1000_intr(adapter->pdev->irq, netdev, NULL); - e1000_clean_tx_irq(adapter); + e1000_clean_tx_irq(adapter, adapter->tx_ring); enable_irq(adapter->pdev->irq); } #endif diff --git a/drivers/net/e1000/e1000_param.c b/drivers/net/e1000/e1000_param.c index 676247f9f1cc..38695d5b4637 100644 --- a/drivers/net/e1000/e1000_param.c +++ b/drivers/net/e1000/e1000_param.c @@ -306,7 +306,8 @@ e1000_check_options(struct e1000_adapter *adapter) .def = E1000_DEFAULT_TXD, .arg = { .r = { .min = E1000_MIN_TXD }} }; - struct e1000_desc_ring *tx_ring = &adapter->tx_ring; + struct e1000_tx_ring *tx_ring = adapter->tx_ring; + int i; e1000_mac_type mac_type = adapter->hw.mac_type; opt.arg.r.max = mac_type < e1000_82544 ? E1000_MAX_TXD : E1000_MAX_82544_TXD; @@ -319,6 +320,8 @@ e1000_check_options(struct e1000_adapter *adapter) } else { tx_ring->count = opt.def; } + for (i = 0; i < adapter->num_queues; i++) + tx_ring[i].count = tx_ring->count; } { /* Receive Descriptor Count */ struct e1000_option opt = { @@ -329,7 +332,8 @@ e1000_check_options(struct e1000_adapter *adapter) .def = E1000_DEFAULT_RXD, .arg = { .r = { .min = E1000_MIN_RXD }} }; - struct e1000_desc_ring *rx_ring = &adapter->rx_ring; + struct e1000_rx_ring *rx_ring = adapter->rx_ring; + int i; e1000_mac_type mac_type = adapter->hw.mac_type; opt.arg.r.max = mac_type < e1000_82544 ? E1000_MAX_RXD : E1000_MAX_82544_RXD; @@ -342,6 +346,8 @@ e1000_check_options(struct e1000_adapter *adapter) } else { rx_ring->count = opt.def; } + for (i = 0; i < adapter->num_queues; i++) + rx_ring[i].count = rx_ring->count; } { /* Checksum Offload Enable/Disable */ struct e1000_option opt = { diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c index dcb3028bb60f..a806dfe54d23 100644 --- a/drivers/net/eepro.c +++ b/drivers/net/eepro.c @@ -552,8 +552,7 @@ static int __init do_eepro_probe(struct net_device *dev) { unsigned short int WS[32]=WakeupSeq; - if (check_region(WakeupPort, 2)==0) { - + if (request_region(WakeupPort, 2, "eepro wakeup")) { if (net_debug>5) printk(KERN_DEBUG "Waking UP\n"); @@ -563,7 +562,10 @@ static int __init do_eepro_probe(struct net_device *dev) outb_p(WS[i],WakeupPort); if (net_debug>5) printk(KERN_DEBUG ": %#x ",WS[i]); } - } else printk(KERN_WARNING "Checkregion Failed!\n"); + + release_region(WakeupPort, 2); + } else + printk(KERN_WARNING "PnP wakeup region busy!\n"); } #endif @@ -705,7 +707,7 @@ static void __init eepro_print_info (struct net_device *dev) dev->name, (unsigned)dev->base_addr); break; case LAN595FX: - printk("%s: Intel EtherExpress Pro/10+ ISA\n at %#x,", + printk("%s: Intel EtherExpress Pro/10+ ISA\n at %#x,", dev->name, (unsigned)dev->base_addr); break; case LAN595TX: @@ -713,7 +715,7 @@ static void __init eepro_print_info (struct net_device *dev) dev->name, (unsigned)dev->base_addr); break; case LAN595: - printk("%s: Intel 82595-based lan card at %#x,", + printk("%s: Intel 82595-based lan card at %#x,", dev->name, (unsigned)dev->base_addr); } @@ -726,7 +728,7 @@ static void __init eepro_print_info (struct net_device *dev) if (dev->irq > 2) printk(", IRQ %d, %s.\n", dev->irq, ifmap[dev->if_port]); - else + else printk(", %s.\n", ifmap[dev->if_port]); if (net_debug > 3) { @@ -756,7 +758,7 @@ static int __init eepro_probe1(struct net_device *dev, int autoprobe) int err; /* Grab the region so we can find another board if autoIRQ fails. */ - if (!request_region(ioaddr, EEPRO_IO_EXTENT, DRV_NAME)) { + if (!request_region(ioaddr, EEPRO_IO_EXTENT, DRV_NAME)) { if (!autoprobe) printk(KERN_WARNING "EEPRO: io-port 0x%04x in use \n", ioaddr); @@ -838,15 +840,15 @@ static int __init eepro_probe1(struct net_device *dev, int autoprobe) /* Mask off INT number */ int count = lp->word[1] & 7; unsigned irqMask = lp->word[7]; - + while (count--) irqMask &= irqMask - 1; - + count = ffs(irqMask); - + if (count) dev->irq = count - 1; - + if (dev->irq < 2) { printk(KERN_ERR " Duh! illegal interrupt vector stored in EEPROM.\n"); goto exit; @@ -854,7 +856,7 @@ static int __init eepro_probe1(struct net_device *dev, int autoprobe) dev->irq = 9; } } - + dev->open = eepro_open; dev->stop = eepro_close; dev->hard_start_xmit = eepro_send_packet; @@ -863,7 +865,7 @@ static int __init eepro_probe1(struct net_device *dev, int autoprobe) dev->tx_timeout = eepro_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; dev->ethtool_ops = &eepro_ethtool_ops; - + /* print boot time info */ eepro_print_info(dev); @@ -1047,8 +1049,8 @@ static int eepro_open(struct net_device *dev) /* Initialize the RCV and XMT upper and lower limits */ - outb(lp->rcv_lower_limit >> 8, ioaddr + RCV_LOWER_LIMIT_REG); - outb(lp->rcv_upper_limit >> 8, ioaddr + RCV_UPPER_LIMIT_REG); + outb(lp->rcv_lower_limit >> 8, ioaddr + RCV_LOWER_LIMIT_REG); + outb(lp->rcv_upper_limit >> 8, ioaddr + RCV_UPPER_LIMIT_REG); outb(lp->xmt_lower_limit >> 8, ioaddr + lp->xmt_lower_limit_reg); outb(lp->xmt_upper_limit >> 8, ioaddr + lp->xmt_upper_limit_reg); @@ -1065,12 +1067,12 @@ static int eepro_open(struct net_device *dev) eepro_clear_int(ioaddr); /* Initialize RCV */ - outw(lp->rcv_lower_limit, ioaddr + RCV_BAR); + outw(lp->rcv_lower_limit, ioaddr + RCV_BAR); lp->rx_start = lp->rcv_lower_limit; - outw(lp->rcv_upper_limit | 0xfe, ioaddr + RCV_STOP); + outw(lp->rcv_upper_limit | 0xfe, ioaddr + RCV_STOP); /* Initialize XMT */ - outw(lp->xmt_lower_limit, ioaddr + lp->xmt_bar); + outw(lp->xmt_lower_limit, ioaddr + lp->xmt_bar); lp->tx_start = lp->tx_end = lp->xmt_lower_limit; lp->tx_last = 0; @@ -1411,7 +1413,7 @@ set_multicast_list(struct net_device *dev) outb(0x08, ioaddr + STATUS_REG); if (i & 0x20) { /* command ABORTed */ - printk(KERN_NOTICE "%s: multicast setup failed.\n", + printk(KERN_NOTICE "%s: multicast setup failed.\n", dev->name); break; } else if ((i & 0x0f) == 0x03) { /* MC-Done */ @@ -1512,7 +1514,7 @@ hardware_send_packet(struct net_device *dev, void *buf, short length) end = last + (((length + 3) >> 1) << 1) + XMT_HEADER; if (end >= lp->xmt_upper_limit + 2) { /* the transmit buffer is wrapped around */ - if ((lp->xmt_upper_limit + 2 - last) <= XMT_HEADER) { + if ((lp->xmt_upper_limit + 2 - last) <= XMT_HEADER) { /* Arrrr!!!, must keep the xmt header together, several days were lost to chase this one down. */ last = lp->xmt_lower_limit; @@ -1643,7 +1645,7 @@ eepro_rx(struct net_device *dev) else if (rcv_status & 0x0800) lp->stats.rx_crc_errors++; - printk(KERN_DEBUG "%s: event = %#x, status = %#x, next = %#x, size = %#x\n", + printk(KERN_DEBUG "%s: event = %#x, status = %#x, next = %#x, size = %#x\n", dev->name, rcv_event, rcv_status, rcv_next_frame, rcv_size); } @@ -1674,10 +1676,10 @@ eepro_transmit_interrupt(struct net_device *dev) { struct eepro_local *lp = netdev_priv(dev); short ioaddr = dev->base_addr; - short boguscount = 25; + short boguscount = 25; short xmt_status; - while ((lp->tx_start != lp->tx_end) && boguscount--) { + while ((lp->tx_start != lp->tx_end) && boguscount--) { outw(lp->tx_start, ioaddr + HOST_ADDRESS_REG); xmt_status = inw(ioaddr+IO_PORT); @@ -1723,7 +1725,7 @@ static int eepro_ethtool_get_settings(struct net_device *dev, { struct eepro_local *lp = (struct eepro_local *)dev->priv; - cmd->supported = SUPPORTED_10baseT_Half | + cmd->supported = SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_Autoneg; cmd->advertising = ADVERTISED_10baseT_Half | @@ -1797,10 +1799,9 @@ MODULE_AUTHOR("Pascal Dupuis and others"); MODULE_DESCRIPTION("Intel i82595 ISA EtherExpressPro10/10+ driver"); MODULE_LICENSE("GPL"); -static int num_params; -module_param_array(io, int, &num_params, 0); -module_param_array(irq, int, &num_params, 0); -module_param_array(mem, int, &num_params, 0); +module_param_array(io, int, NULL, 0); +module_param_array(irq, int, NULL, 0); +module_param_array(mem, int, NULL, 0); module_param(autodetect, int, 0); MODULE_PARM_DESC(io, "EtherExpress Pro/10 I/O base addres(es)"); MODULE_PARM_DESC(irq, "EtherExpress Pro/10 IRQ number(s)"); diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c index 87f522738bfc..f119ec4e89ea 100644 --- a/drivers/net/epic100.c +++ b/drivers/net/epic100.c @@ -1334,7 +1334,7 @@ static void epic_rx_err(struct net_device *dev, struct epic_private *ep) static int epic_poll(struct net_device *dev, int *budget) { struct epic_private *ep = dev->priv; - int work_done, orig_budget; + int work_done = 0, orig_budget; long ioaddr = dev->base_addr; orig_budget = (*budget > dev->quota) ? dev->quota : *budget; @@ -1343,7 +1343,7 @@ rx_action: epic_tx(dev, ep); - work_done = epic_rx(dev, *budget); + work_done += epic_rx(dev, *budget); epic_rx_err(dev, ep); diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index d6eefdb71c17..22aec6ed80f5 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -95,6 +95,8 @@ * of nv_remove * 0.42: 06 Aug 2005: Fix lack of link speed initialization * in the second (and later) nv_open call + * 0.43: 10 Aug 2005: Add support for tx checksum. + * 0.44: 20 Aug 2005: Add support for scatter gather and segmentation. * * Known bugs: * We suspect that on some hardware no TX done interrupts are generated. @@ -106,7 +108,7 @@ * DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few * superfluous timer interrupts from the nic. */ -#define FORCEDETH_VERSION "0.41" +#define FORCEDETH_VERSION "0.44" #define DRV_NAME "forcedeth" #include <linux/module.h> @@ -145,6 +147,7 @@ #define DEV_NEED_LINKTIMER 0x0002 /* poll link settings. Relies on the timer irq */ #define DEV_HAS_LARGEDESC 0x0004 /* device supports jumbo frames and needs packet format 2 */ #define DEV_HAS_HIGH_DMA 0x0008 /* device supports 64bit dma */ +#define DEV_HAS_CHECKSUM 0x0010 /* device supports tx and rx checksum offloads */ enum { NvRegIrqStatus = 0x000, @@ -241,6 +244,9 @@ enum { #define NVREG_TXRXCTL_IDLE 0x0008 #define NVREG_TXRXCTL_RESET 0x0010 #define NVREG_TXRXCTL_RXCHECK 0x0400 +#define NVREG_TXRXCTL_DESC_1 0 +#define NVREG_TXRXCTL_DESC_2 0x02100 +#define NVREG_TXRXCTL_DESC_3 0x02200 NvRegMIIStatus = 0x180, #define NVREG_MIISTAT_ERROR 0x0001 #define NVREG_MIISTAT_LINKCHANGE 0x0008 @@ -335,6 +341,10 @@ typedef union _ring_type { /* error and valid are the same for both */ #define NV_TX2_ERROR (1<<30) #define NV_TX2_VALID (1<<31) +#define NV_TX2_TSO (1<<28) +#define NV_TX2_TSO_SHIFT 14 +#define NV_TX2_CHECKSUM_L3 (1<<27) +#define NV_TX2_CHECKSUM_L4 (1<<26) #define NV_RX_DESCRIPTORVALID (1<<16) #define NV_RX_MISSEDFRAME (1<<17) @@ -417,14 +427,14 @@ typedef union _ring_type { /* * desc_ver values: - * This field has two purposes: - * - Newer nics uses a different ring layout. The layout is selected by - * comparing np->desc_ver with DESC_VER_xy. - * - It contains bits that are forced on when writing to NvRegTxRxControl. + * The nic supports three different descriptor types: + * - DESC_VER_1: Original + * - DESC_VER_2: support for jumbo frames. + * - DESC_VER_3: 64-bit format. */ -#define DESC_VER_1 0x0 -#define DESC_VER_2 (0x02100|NVREG_TXRXCTL_RXCHECK) -#define DESC_VER_3 (0x02200|NVREG_TXRXCTL_RXCHECK) +#define DESC_VER_1 1 +#define DESC_VER_2 2 +#define DESC_VER_3 3 /* PHY defines */ #define PHY_OUI_MARVELL 0x5043 @@ -491,6 +501,7 @@ struct fe_priv { u32 orig_mac[2]; u32 irqmask; u32 desc_ver; + u32 txrxctl_bits; void __iomem *base; @@ -534,7 +545,7 @@ static inline struct fe_priv *get_nvpriv(struct net_device *dev) static inline u8 __iomem *get_hwbase(struct net_device *dev) { - return get_nvpriv(dev)->base; + return ((struct fe_priv *)netdev_priv(dev))->base; } static inline void pci_push(u8 __iomem *base) @@ -623,7 +634,7 @@ static int mii_rw(struct net_device *dev, int addr, int miireg, int value) static int phy_reset(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); u32 miicontrol; unsigned int tries = 0; @@ -726,7 +737,7 @@ static int phy_init(struct net_device *dev) static void nv_start_rx(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); dprintk(KERN_DEBUG "%s: nv_start_rx\n", dev->name); @@ -782,14 +793,14 @@ static void nv_stop_tx(struct net_device *dev) static void nv_txrx_reset(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); dprintk(KERN_DEBUG "%s: nv_txrx_reset\n", dev->name); - writel(NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET | np->desc_ver, base + NvRegTxRxControl); + writel(NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET | np->txrxctl_bits, base + NvRegTxRxControl); pci_push(base); udelay(NV_TXRX_RESET_DELAY); - writel(NVREG_TXRXCTL_BIT2 | np->desc_ver, base + NvRegTxRxControl); + writel(NVREG_TXRXCTL_BIT2 | np->txrxctl_bits, base + NvRegTxRxControl); pci_push(base); } @@ -801,7 +812,7 @@ static void nv_txrx_reset(struct net_device *dev) */ static struct net_device_stats *nv_get_stats(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); /* It seems that the nic always generates interrupts and doesn't * accumulate errors internally. Thus the current values in np->stats @@ -817,7 +828,7 @@ static struct net_device_stats *nv_get_stats(struct net_device *dev) */ static int nv_alloc_rx(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); unsigned int refill_rx = np->refill_rx; int nr; @@ -861,7 +872,7 @@ static int nv_alloc_rx(struct net_device *dev) static void nv_do_rx_refill(unsigned long data) { struct net_device *dev = (struct net_device *) data; - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); disable_irq(dev->irq); if (nv_alloc_rx(dev)) { @@ -875,7 +886,7 @@ static void nv_do_rx_refill(unsigned long data) static void nv_init_rx(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); int i; np->cur_rx = RX_RING; @@ -889,15 +900,17 @@ static void nv_init_rx(struct net_device *dev) static void nv_init_tx(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); int i; np->next_tx = np->nic_tx = 0; - for (i = 0; i < TX_RING; i++) + for (i = 0; i < TX_RING; i++) { if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) np->tx_ring.orig[i].FlagLen = 0; else np->tx_ring.ex[i].FlagLen = 0; + np->tx_skbuff[i] = NULL; + } } static int nv_init_ring(struct net_device *dev) @@ -907,21 +920,44 @@ static int nv_init_ring(struct net_device *dev) return nv_alloc_rx(dev); } +static void nv_release_txskb(struct net_device *dev, unsigned int skbnr) +{ + struct fe_priv *np = netdev_priv(dev); + struct sk_buff *skb = np->tx_skbuff[skbnr]; + unsigned int j, entry, fragments; + + dprintk(KERN_INFO "%s: nv_release_txskb for skbnr %d, skb %p\n", + dev->name, skbnr, np->tx_skbuff[skbnr]); + + entry = skbnr; + if ((fragments = skb_shinfo(skb)->nr_frags) != 0) { + for (j = fragments; j >= 1; j--) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[j-1]; + pci_unmap_page(np->pci_dev, np->tx_dma[entry], + frag->size, + PCI_DMA_TODEVICE); + entry = (entry - 1) % TX_RING; + } + } + pci_unmap_single(np->pci_dev, np->tx_dma[entry], + skb->len - skb->data_len, + PCI_DMA_TODEVICE); + dev_kfree_skb_irq(skb); + np->tx_skbuff[skbnr] = NULL; +} + static void nv_drain_tx(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); - int i; + struct fe_priv *np = netdev_priv(dev); + unsigned int i; + for (i = 0; i < TX_RING; i++) { if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) np->tx_ring.orig[i].FlagLen = 0; else np->tx_ring.ex[i].FlagLen = 0; if (np->tx_skbuff[i]) { - pci_unmap_single(np->pci_dev, np->tx_dma[i], - np->tx_skbuff[i]->len, - PCI_DMA_TODEVICE); - dev_kfree_skb(np->tx_skbuff[i]); - np->tx_skbuff[i] = NULL; + nv_release_txskb(dev, i); np->stats.tx_dropped++; } } @@ -929,7 +965,7 @@ static void nv_drain_tx(struct net_device *dev) static void nv_drain_rx(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); int i; for (i = 0; i < RX_RING; i++) { if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) @@ -959,28 +995,69 @@ static void drain_ring(struct net_device *dev) */ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); - int nr = np->next_tx % TX_RING; + struct fe_priv *np = netdev_priv(dev); + u32 tx_flags_extra = (np->desc_ver == DESC_VER_1 ? NV_TX_LASTPACKET : NV_TX2_LASTPACKET); + unsigned int fragments = skb_shinfo(skb)->nr_frags; + unsigned int nr = (np->next_tx + fragments) % TX_RING; + unsigned int i; + + spin_lock_irq(&np->lock); + + if ((np->next_tx - np->nic_tx + fragments) > TX_LIMIT_STOP) { + spin_unlock_irq(&np->lock); + netif_stop_queue(dev); + return NETDEV_TX_BUSY; + } np->tx_skbuff[nr] = skb; - np->tx_dma[nr] = pci_map_single(np->pci_dev, skb->data,skb->len, - PCI_DMA_TODEVICE); + + if (fragments) { + dprintk(KERN_DEBUG "%s: nv_start_xmit: buffer contains %d fragments\n", dev->name, fragments); + /* setup descriptors in reverse order */ + for (i = fragments; i >= 1; i--) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[i-1]; + np->tx_dma[nr] = pci_map_page(np->pci_dev, frag->page, frag->page_offset, frag->size, + PCI_DMA_TODEVICE); - if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { + np->tx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]); + np->tx_ring.orig[nr].FlagLen = cpu_to_le32( (frag->size-1) | np->tx_flags | tx_flags_extra); + } else { + np->tx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->tx_dma[nr]) >> 32; + np->tx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF; + np->tx_ring.ex[nr].FlagLen = cpu_to_le32( (frag->size-1) | np->tx_flags | tx_flags_extra); + } + + nr = (nr - 1) % TX_RING; + + if (np->desc_ver == DESC_VER_1) + tx_flags_extra &= ~NV_TX_LASTPACKET; + else + tx_flags_extra &= ~NV_TX2_LASTPACKET; + } + } + +#ifdef NETIF_F_TSO + if (skb_shinfo(skb)->tso_size) + tx_flags_extra |= NV_TX2_TSO | (skb_shinfo(skb)->tso_size << NV_TX2_TSO_SHIFT); + else +#endif + tx_flags_extra |= (skb->ip_summed == CHECKSUM_HW ? (NV_TX2_CHECKSUM_L3|NV_TX2_CHECKSUM_L4) : 0); + + np->tx_dma[nr] = pci_map_single(np->pci_dev, skb->data, skb->len-skb->data_len, + PCI_DMA_TODEVICE); + + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { np->tx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]); - else { + np->tx_ring.orig[nr].FlagLen = cpu_to_le32( (skb->len-skb->data_len-1) | np->tx_flags | tx_flags_extra); + } else { np->tx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->tx_dma[nr]) >> 32; np->tx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF; - } + np->tx_ring.ex[nr].FlagLen = cpu_to_le32( (skb->len-skb->data_len-1) | np->tx_flags | tx_flags_extra); + } - spin_lock_irq(&np->lock); - wmb(); - if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) - np->tx_ring.orig[nr].FlagLen = cpu_to_le32( (skb->len-1) | np->tx_flags ); - else - np->tx_ring.ex[nr].FlagLen = cpu_to_le32( (skb->len-1) | np->tx_flags ); - dprintk(KERN_DEBUG "%s: nv_start_xmit: packet packet %d queued for transmission.\n", - dev->name, np->next_tx); + dprintk(KERN_DEBUG "%s: nv_start_xmit: packet packet %d queued for transmission. tx_flags_extra: %x\n", + dev->name, np->next_tx, tx_flags_extra); { int j; for (j=0; j<64; j++) { @@ -991,15 +1068,13 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev) dprintk("\n"); } - np->next_tx++; + np->next_tx += 1 + fragments; dev->trans_start = jiffies; - if (np->next_tx - np->nic_tx >= TX_LIMIT_STOP) - netif_stop_queue(dev); spin_unlock_irq(&np->lock); - writel(NVREG_TXRXCTL_KICK|np->desc_ver, get_hwbase(dev) + NvRegTxRxControl); + writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl); pci_push(get_hwbase(dev)); - return 0; + return NETDEV_TX_OK; } /* @@ -1009,9 +1084,10 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev) */ static void nv_tx_done(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); u32 Flags; - int i; + unsigned int i; + struct sk_buff *skb; while (np->nic_tx != np->next_tx) { i = np->nic_tx % TX_RING; @@ -1026,35 +1102,38 @@ static void nv_tx_done(struct net_device *dev) if (Flags & NV_TX_VALID) break; if (np->desc_ver == DESC_VER_1) { - if (Flags & (NV_TX_RETRYERROR|NV_TX_CARRIERLOST|NV_TX_LATECOLLISION| - NV_TX_UNDERFLOW|NV_TX_ERROR)) { - if (Flags & NV_TX_UNDERFLOW) - np->stats.tx_fifo_errors++; - if (Flags & NV_TX_CARRIERLOST) - np->stats.tx_carrier_errors++; - np->stats.tx_errors++; - } else { - np->stats.tx_packets++; - np->stats.tx_bytes += np->tx_skbuff[i]->len; + if (Flags & NV_TX_LASTPACKET) { + skb = np->tx_skbuff[i]; + if (Flags & (NV_TX_RETRYERROR|NV_TX_CARRIERLOST|NV_TX_LATECOLLISION| + NV_TX_UNDERFLOW|NV_TX_ERROR)) { + if (Flags & NV_TX_UNDERFLOW) + np->stats.tx_fifo_errors++; + if (Flags & NV_TX_CARRIERLOST) + np->stats.tx_carrier_errors++; + np->stats.tx_errors++; + } else { + np->stats.tx_packets++; + np->stats.tx_bytes += skb->len; + } + nv_release_txskb(dev, i); } } else { - if (Flags & (NV_TX2_RETRYERROR|NV_TX2_CARRIERLOST|NV_TX2_LATECOLLISION| - NV_TX2_UNDERFLOW|NV_TX2_ERROR)) { - if (Flags & NV_TX2_UNDERFLOW) - np->stats.tx_fifo_errors++; - if (Flags & NV_TX2_CARRIERLOST) - np->stats.tx_carrier_errors++; - np->stats.tx_errors++; - } else { - np->stats.tx_packets++; - np->stats.tx_bytes += np->tx_skbuff[i]->len; + if (Flags & NV_TX2_LASTPACKET) { + skb = np->tx_skbuff[i]; + if (Flags & (NV_TX2_RETRYERROR|NV_TX2_CARRIERLOST|NV_TX2_LATECOLLISION| + NV_TX2_UNDERFLOW|NV_TX2_ERROR)) { + if (Flags & NV_TX2_UNDERFLOW) + np->stats.tx_fifo_errors++; + if (Flags & NV_TX2_CARRIERLOST) + np->stats.tx_carrier_errors++; + np->stats.tx_errors++; + } else { + np->stats.tx_packets++; + np->stats.tx_bytes += skb->len; + } + nv_release_txskb(dev, i); } } - pci_unmap_single(np->pci_dev, np->tx_dma[i], - np->tx_skbuff[i]->len, - PCI_DMA_TODEVICE); - dev_kfree_skb_irq(np->tx_skbuff[i]); - np->tx_skbuff[i] = NULL; np->nic_tx++; } if (np->next_tx - np->nic_tx < TX_LIMIT_START) @@ -1067,7 +1146,7 @@ static void nv_tx_done(struct net_device *dev) */ static void nv_tx_timeout(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); printk(KERN_INFO "%s: Got tx_timeout. irq: %08x\n", dev->name, @@ -1200,7 +1279,7 @@ static int nv_getlen(struct net_device *dev, void *packet, int datalen) static void nv_rx_process(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); u32 Flags; for (;;) { @@ -1355,7 +1434,7 @@ static void set_bufsize(struct net_device *dev) */ static int nv_change_mtu(struct net_device *dev, int new_mtu) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); int old_mtu; if (new_mtu < 64 || new_mtu > np->pkt_limit) @@ -1408,7 +1487,7 @@ static int nv_change_mtu(struct net_device *dev, int new_mtu) writel( ((RX_RING-1) << NVREG_RINGSZ_RXSHIFT) + ((TX_RING-1) << NVREG_RINGSZ_TXSHIFT), base + NvRegRingSizes); pci_push(base); - writel(NVREG_TXRXCTL_KICK|np->desc_ver, get_hwbase(dev) + NvRegTxRxControl); + writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl); pci_push(base); /* restart rx engine */ @@ -1440,7 +1519,7 @@ static void nv_copy_mac_to_hw(struct net_device *dev) */ static int nv_set_mac_address(struct net_device *dev, void *addr) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); struct sockaddr *macaddr = (struct sockaddr*)addr; if(!is_valid_ether_addr(macaddr->sa_data)) @@ -1475,7 +1554,7 @@ static int nv_set_mac_address(struct net_device *dev, void *addr) */ static void nv_set_multicast(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); u32 addr[2]; u32 mask[2]; @@ -1535,7 +1614,7 @@ static void nv_set_multicast(struct net_device *dev) static int nv_update_linkspeed(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); int adv, lpa; int newls = np->linkspeed; @@ -1705,7 +1784,7 @@ static void nv_link_irq(struct net_device *dev) static irqreturn_t nv_nic_irq(int foo, void *data, struct pt_regs *regs) { struct net_device *dev = (struct net_device *) data; - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); u32 events; int i; @@ -1777,7 +1856,7 @@ static irqreturn_t nv_nic_irq(int foo, void *data, struct pt_regs *regs) static void nv_do_nic_poll(unsigned long data) { struct net_device *dev = (struct net_device *) data; - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); disable_irq(dev->irq); @@ -1801,7 +1880,7 @@ static void nv_poll_controller(struct net_device *dev) static void nv_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); strcpy(info->driver, "forcedeth"); strcpy(info->version, FORCEDETH_VERSION); strcpy(info->bus_info, pci_name(np->pci_dev)); @@ -1809,7 +1888,7 @@ static void nv_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) static void nv_get_wol(struct net_device *dev, struct ethtool_wolinfo *wolinfo) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); wolinfo->supported = WAKE_MAGIC; spin_lock_irq(&np->lock); @@ -1820,7 +1899,7 @@ static void nv_get_wol(struct net_device *dev, struct ethtool_wolinfo *wolinfo) static int nv_set_wol(struct net_device *dev, struct ethtool_wolinfo *wolinfo) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); spin_lock_irq(&np->lock); @@ -2021,7 +2100,7 @@ static int nv_get_regs_len(struct net_device *dev) static void nv_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *buf) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); u32 *rbuf = buf; int i; @@ -2035,7 +2114,7 @@ static void nv_get_regs(struct net_device *dev, struct ethtool_regs *regs, void static int nv_nway_reset(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); int ret; spin_lock_irq(&np->lock); @@ -2065,11 +2144,12 @@ static struct ethtool_ops ops = { .get_regs_len = nv_get_regs_len, .get_regs = nv_get_regs, .nway_reset = nv_nway_reset, + .get_perm_addr = ethtool_op_get_perm_addr, }; static int nv_open(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); int ret, oom, i; @@ -2114,9 +2194,9 @@ static int nv_open(struct net_device *dev) /* 5) continue setup */ writel(np->linkspeed, base + NvRegLinkSpeed); writel(NVREG_UNKSETUP3_VAL1, base + NvRegUnknownSetupReg3); - writel(np->desc_ver, base + NvRegTxRxControl); + writel(np->txrxctl_bits, base + NvRegTxRxControl); pci_push(base); - writel(NVREG_TXRXCTL_BIT1|np->desc_ver, base + NvRegTxRxControl); + writel(NVREG_TXRXCTL_BIT1|np->txrxctl_bits, base + NvRegTxRxControl); reg_delay(dev, NvRegUnknownSetupReg5, NVREG_UNKSETUP5_BIT31, NVREG_UNKSETUP5_BIT31, NV_SETUP5_DELAY, NV_SETUP5_DELAYMAX, KERN_INFO "open: SetupReg5, Bit 31 remained off\n"); @@ -2205,7 +2285,7 @@ out_drain: static int nv_close(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); u8 __iomem *base; spin_lock_irq(&np->lock); @@ -2261,7 +2341,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i if (!dev) goto out; - np = get_nvpriv(dev); + np = netdev_priv(dev); np->pci_dev = pci_dev; spin_lock_init(&np->lock); SET_MODULE_OWNER(dev); @@ -2313,19 +2393,32 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i if (pci_set_dma_mask(pci_dev, 0x0000007fffffffffULL)) { printk(KERN_INFO "forcedeth: 64-bit DMA failed, using 32-bit addressing for device %s.\n", pci_name(pci_dev)); + } else { + dev->features |= NETIF_F_HIGHDMA; } + np->txrxctl_bits = NVREG_TXRXCTL_DESC_3; } else if (id->driver_data & DEV_HAS_LARGEDESC) { /* packet format 2: supports jumbo frames */ np->desc_ver = DESC_VER_2; + np->txrxctl_bits = NVREG_TXRXCTL_DESC_2; } else { /* original packet format */ np->desc_ver = DESC_VER_1; + np->txrxctl_bits = NVREG_TXRXCTL_DESC_1; } np->pkt_limit = NV_PKTLIMIT_1; if (id->driver_data & DEV_HAS_LARGEDESC) np->pkt_limit = NV_PKTLIMIT_2; + if (id->driver_data & DEV_HAS_CHECKSUM) { + np->txrxctl_bits |= NVREG_TXRXCTL_RXCHECK; + dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG; +#ifdef NETIF_F_TSO + dev->features |= NETIF_F_TSO; +#endif + } + err = -ENOMEM; np->base = ioremap(addr, NV_PCI_REGSZ); if (!np->base) @@ -2377,8 +2470,9 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i dev->dev_addr[3] = (np->orig_mac[0] >> 16) & 0xff; dev->dev_addr[4] = (np->orig_mac[0] >> 8) & 0xff; dev->dev_addr[5] = (np->orig_mac[0] >> 0) & 0xff; + memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); - if (!is_valid_ether_addr(dev->dev_addr)) { + if (!is_valid_ether_addr(dev->perm_addr)) { /* * Bad mac address. At least one bios sets the mac address * to 01:23:45:67:89:ab @@ -2403,9 +2497,9 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i np->wolenabled = 0; if (np->desc_ver == DESC_VER_1) { - np->tx_flags = NV_TX_LASTPACKET|NV_TX_VALID; + np->tx_flags = NV_TX_VALID; } else { - np->tx_flags = NV_TX2_LASTPACKET|NV_TX2_VALID; + np->tx_flags = NV_TX2_VALID; } np->irqmask = NVREG_IRQMASK_WANTED; if (id->driver_data & DEV_NEED_TIMERIRQ) @@ -2494,7 +2588,7 @@ out: static void __devexit nv_remove(struct pci_dev *pci_dev) { struct net_device *dev = pci_get_drvdata(pci_dev); - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); unregister_netdev(dev); @@ -2525,35 +2619,35 @@ static struct pci_device_id pci_tbl[] = { }, { /* nForce3 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_4), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM, }, { /* nForce3 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_5), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM, }, { /* nForce3 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_6), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM, }, { /* nForce3 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_7), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM, }, { /* CK804 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_8), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA, }, { /* CK804 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_9), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA, }, { /* MCP04 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_10), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA, }, { /* MCP04 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_11), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA, }, { /* MCP51 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_12), @@ -2565,11 +2659,11 @@ static struct pci_device_id pci_tbl[] = { }, { /* MCP55 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_14), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA, }, { /* MCP55 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_15), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA, }, {0,}, }; diff --git a/drivers/net/fs_enet/Kconfig b/drivers/net/fs_enet/Kconfig new file mode 100644 index 000000000000..6aaee67dd4b7 --- /dev/null +++ b/drivers/net/fs_enet/Kconfig @@ -0,0 +1,20 @@ +config FS_ENET + tristate "Freescale Ethernet Driver" + depends on NET_ETHERNET && (CPM1 || CPM2) + select MII + +config FS_ENET_HAS_SCC + bool "Chip has an SCC usable for ethernet" + depends on FS_ENET && (CPM1 || CPM2) + default y + +config FS_ENET_HAS_FCC + bool "Chip has an FCC usable for ethernet" + depends on FS_ENET && CPM2 + default y + +config FS_ENET_HAS_FEC + bool "Chip has an FEC usable for ethernet" + depends on FS_ENET && CPM1 + default y + diff --git a/drivers/net/fs_enet/Makefile b/drivers/net/fs_enet/Makefile new file mode 100644 index 000000000000..d6dd3f2fb43e --- /dev/null +++ b/drivers/net/fs_enet/Makefile @@ -0,0 +1,10 @@ +# +# Makefile for the Freescale Ethernet controllers +# + +obj-$(CONFIG_FS_ENET) += fs_enet.o + +obj-$(CONFIG_8xx) += mac-fec.o mac-scc.o +obj-$(CONFIG_8260) += mac-fcc.o + +fs_enet-objs := fs_enet-main.o fs_enet-mii.o mii-bitbang.o mii-fixed.o diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c new file mode 100644 index 000000000000..44fac7373289 --- /dev/null +++ b/drivers/net/fs_enet/fs_enet-main.c @@ -0,0 +1,1226 @@ +/* + * Combined Ethernet driver for Motorola MPC8xx and MPC82xx. + * + * Copyright (c) 2003 Intracom S.A. + * by Pantelis Antoniou <panto@intracom.gr> + * + * 2005 (c) MontaVista Software, Inc. + * Vitaly Bordug <vbordug@ru.mvista.com> + * + * Heavily based on original FEC driver by Dan Malek <dan@embeddededge.com> + * and modifications by Joakim Tjernlund <joakim.tjernlund@lumentis.se> + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/sched.h> +#include <linux/string.h> +#include <linux/ptrace.h> +#include <linux/errno.h> +#include <linux/ioport.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/spinlock.h> +#include <linux/mii.h> +#include <linux/ethtool.h> +#include <linux/bitops.h> +#include <linux/fs.h> + +#include <linux/vmalloc.h> +#include <asm/pgtable.h> + +#include <asm/pgtable.h> +#include <asm/irq.h> +#include <asm/uaccess.h> + +#include "fs_enet.h" + +/*************************************************/ + +static char version[] __devinitdata = + DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")" "\n"; + +MODULE_AUTHOR("Pantelis Antoniou <panto@intracom.gr>"); +MODULE_DESCRIPTION("Freescale Ethernet Driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_MODULE_VERSION); + +MODULE_PARM(fs_enet_debug, "i"); +MODULE_PARM_DESC(fs_enet_debug, + "Freescale bitmapped debugging message enable value"); + +int fs_enet_debug = -1; /* -1 == use FS_ENET_DEF_MSG_ENABLE as value */ + +static void fs_set_multicast_list(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + + (*fep->ops->set_multicast_list)(dev); +} + +/* NAPI receive function */ +static int fs_enet_rx_napi(struct net_device *dev, int *budget) +{ + struct fs_enet_private *fep = netdev_priv(dev); + const struct fs_platform_info *fpi = fep->fpi; + cbd_t *bdp; + struct sk_buff *skb, *skbn, *skbt; + int received = 0; + u16 pkt_len, sc; + int curidx; + int rx_work_limit = 0; /* pacify gcc */ + + rx_work_limit = min(dev->quota, *budget); + + if (!netif_running(dev)) + return 0; + + /* + * First, grab all of the stats for the incoming packet. + * These get messed up if we get called due to a busy condition. + */ + bdp = fep->cur_rx; + + /* clear RX status bits for napi*/ + (*fep->ops->napi_clear_rx_event)(dev); + + while (((sc = CBDR_SC(bdp)) & BD_ENET_RX_EMPTY) == 0) { + + curidx = bdp - fep->rx_bd_base; + + /* + * Since we have allocated space to hold a complete frame, + * the last indicator should be set. + */ + if ((sc & BD_ENET_RX_LAST) == 0) + printk(KERN_WARNING DRV_MODULE_NAME + ": %s rcv is not +last\n", + dev->name); + + /* + * Check for errors. + */ + if (sc & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_CL | + BD_ENET_RX_NO | BD_ENET_RX_CR | BD_ENET_RX_OV)) { + fep->stats.rx_errors++; + /* Frame too long or too short. */ + if (sc & (BD_ENET_RX_LG | BD_ENET_RX_SH)) + fep->stats.rx_length_errors++; + /* Frame alignment */ + if (sc & (BD_ENET_RX_NO | BD_ENET_RX_CL)) + fep->stats.rx_frame_errors++; + /* CRC Error */ + if (sc & BD_ENET_RX_CR) + fep->stats.rx_crc_errors++; + /* FIFO overrun */ + if (sc & BD_ENET_RX_OV) + fep->stats.rx_crc_errors++; + + skb = fep->rx_skbuff[curidx]; + + dma_unmap_single(fep->dev, skb->data, + L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), + DMA_FROM_DEVICE); + + skbn = skb; + + } else { + + /* napi, got packet but no quota */ + if (--rx_work_limit < 0) + break; + + skb = fep->rx_skbuff[curidx]; + + dma_unmap_single(fep->dev, skb->data, + L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), + DMA_FROM_DEVICE); + + /* + * Process the incoming frame. + */ + fep->stats.rx_packets++; + pkt_len = CBDR_DATLEN(bdp) - 4; /* remove CRC */ + fep->stats.rx_bytes += pkt_len + 4; + + if (pkt_len <= fpi->rx_copybreak) { + /* +2 to make IP header L1 cache aligned */ + skbn = dev_alloc_skb(pkt_len + 2); + if (skbn != NULL) { + skb_reserve(skbn, 2); /* align IP header */ + memcpy(skbn->data, skb->data, pkt_len); + /* swap */ + skbt = skb; + skb = skbn; + skbn = skbt; + } + } else + skbn = dev_alloc_skb(ENET_RX_FRSIZE); + + if (skbn != NULL) { + skb->dev = dev; + skb_put(skb, pkt_len); /* Make room */ + skb->protocol = eth_type_trans(skb, dev); + received++; + netif_receive_skb(skb); + } else { + printk(KERN_WARNING DRV_MODULE_NAME + ": %s Memory squeeze, dropping packet.\n", + dev->name); + fep->stats.rx_dropped++; + skbn = skb; + } + } + + fep->rx_skbuff[curidx] = skbn; + CBDW_BUFADDR(bdp, dma_map_single(fep->dev, skbn->data, + L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), + DMA_FROM_DEVICE)); + CBDW_DATLEN(bdp, 0); + CBDW_SC(bdp, (sc & ~BD_ENET_RX_STATS) | BD_ENET_RX_EMPTY); + + /* + * Update BD pointer to next entry. + */ + if ((sc & BD_ENET_RX_WRAP) == 0) + bdp++; + else + bdp = fep->rx_bd_base; + + (*fep->ops->rx_bd_done)(dev); + } + + fep->cur_rx = bdp; + + dev->quota -= received; + *budget -= received; + + if (rx_work_limit < 0) + return 1; /* not done */ + + /* done */ + netif_rx_complete(dev); + + (*fep->ops->napi_enable_rx)(dev); + + return 0; +} + +/* non NAPI receive function */ +static int fs_enet_rx_non_napi(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + const struct fs_platform_info *fpi = fep->fpi; + cbd_t *bdp; + struct sk_buff *skb, *skbn, *skbt; + int received = 0; + u16 pkt_len, sc; + int curidx; + /* + * First, grab all of the stats for the incoming packet. + * These get messed up if we get called due to a busy condition. + */ + bdp = fep->cur_rx; + + while (((sc = CBDR_SC(bdp)) & BD_ENET_RX_EMPTY) == 0) { + + curidx = bdp - fep->rx_bd_base; + + /* + * Since we have allocated space to hold a complete frame, + * the last indicator should be set. + */ + if ((sc & BD_ENET_RX_LAST) == 0) + printk(KERN_WARNING DRV_MODULE_NAME + ": %s rcv is not +last\n", + dev->name); + + /* + * Check for errors. + */ + if (sc & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_CL | + BD_ENET_RX_NO | BD_ENET_RX_CR | BD_ENET_RX_OV)) { + fep->stats.rx_errors++; + /* Frame too long or too short. */ + if (sc & (BD_ENET_RX_LG | BD_ENET_RX_SH)) + fep->stats.rx_length_errors++; + /* Frame alignment */ + if (sc & (BD_ENET_RX_NO | BD_ENET_RX_CL)) + fep->stats.rx_frame_errors++; + /* CRC Error */ + if (sc & BD_ENET_RX_CR) + fep->stats.rx_crc_errors++; + /* FIFO overrun */ + if (sc & BD_ENET_RX_OV) + fep->stats.rx_crc_errors++; + + skb = fep->rx_skbuff[curidx]; + + dma_unmap_single(fep->dev, skb->data, + L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), + DMA_FROM_DEVICE); + + skbn = skb; + + } else { + + skb = fep->rx_skbuff[curidx]; + + dma_unmap_single(fep->dev, skb->data, + L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), + DMA_FROM_DEVICE); + + /* + * Process the incoming frame. + */ + fep->stats.rx_packets++; + pkt_len = CBDR_DATLEN(bdp) - 4; /* remove CRC */ + fep->stats.rx_bytes += pkt_len + 4; + + if (pkt_len <= fpi->rx_copybreak) { + /* +2 to make IP header L1 cache aligned */ + skbn = dev_alloc_skb(pkt_len + 2); + if (skbn != NULL) { + skb_reserve(skbn, 2); /* align IP header */ + memcpy(skbn->data, skb->data, pkt_len); + /* swap */ + skbt = skb; + skb = skbn; + skbn = skbt; + } + } else + skbn = dev_alloc_skb(ENET_RX_FRSIZE); + + if (skbn != NULL) { + skb->dev = dev; + skb_put(skb, pkt_len); /* Make room */ + skb->protocol = eth_type_trans(skb, dev); + received++; + netif_rx(skb); + } else { + printk(KERN_WARNING DRV_MODULE_NAME + ": %s Memory squeeze, dropping packet.\n", + dev->name); + fep->stats.rx_dropped++; + skbn = skb; + } + } + + fep->rx_skbuff[curidx] = skbn; + CBDW_BUFADDR(bdp, dma_map_single(fep->dev, skbn->data, + L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), + DMA_FROM_DEVICE)); + CBDW_DATLEN(bdp, 0); + CBDW_SC(bdp, (sc & ~BD_ENET_RX_STATS) | BD_ENET_RX_EMPTY); + + /* + * Update BD pointer to next entry. + */ + if ((sc & BD_ENET_RX_WRAP) == 0) + bdp++; + else + bdp = fep->rx_bd_base; + + (*fep->ops->rx_bd_done)(dev); + } + + fep->cur_rx = bdp; + + return 0; +} + +static void fs_enet_tx(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + cbd_t *bdp; + struct sk_buff *skb; + int dirtyidx, do_wake, do_restart; + u16 sc; + + spin_lock(&fep->lock); + bdp = fep->dirty_tx; + + do_wake = do_restart = 0; + while (((sc = CBDR_SC(bdp)) & BD_ENET_TX_READY) == 0) { + + dirtyidx = bdp - fep->tx_bd_base; + + if (fep->tx_free == fep->tx_ring) + break; + + skb = fep->tx_skbuff[dirtyidx]; + + /* + * Check for errors. + */ + if (sc & (BD_ENET_TX_HB | BD_ENET_TX_LC | + BD_ENET_TX_RL | BD_ENET_TX_UN | BD_ENET_TX_CSL)) { + + if (sc & BD_ENET_TX_HB) /* No heartbeat */ + fep->stats.tx_heartbeat_errors++; + if (sc & BD_ENET_TX_LC) /* Late collision */ + fep->stats.tx_window_errors++; + if (sc & BD_ENET_TX_RL) /* Retrans limit */ + fep->stats.tx_aborted_errors++; + if (sc & BD_ENET_TX_UN) /* Underrun */ + fep->stats.tx_fifo_errors++; + if (sc & BD_ENET_TX_CSL) /* Carrier lost */ + fep->stats.tx_carrier_errors++; + + if (sc & (BD_ENET_TX_LC | BD_ENET_TX_RL | BD_ENET_TX_UN)) { + fep->stats.tx_errors++; + do_restart = 1; + } + } else + fep->stats.tx_packets++; + + if (sc & BD_ENET_TX_READY) + printk(KERN_WARNING DRV_MODULE_NAME + ": %s HEY! Enet xmit interrupt and TX_READY.\n", + dev->name); + + /* + * Deferred means some collisions occurred during transmit, + * but we eventually sent the packet OK. + */ + if (sc & BD_ENET_TX_DEF) + fep->stats.collisions++; + + /* unmap */ + dma_unmap_single(fep->dev, skb->data, skb->len, DMA_TO_DEVICE); + + /* + * Free the sk buffer associated with this last transmit. + */ + dev_kfree_skb_irq(skb); + fep->tx_skbuff[dirtyidx] = NULL; + + /* + * Update pointer to next buffer descriptor to be transmitted. + */ + if ((sc & BD_ENET_TX_WRAP) == 0) + bdp++; + else + bdp = fep->tx_bd_base; + + /* + * Since we have freed up a buffer, the ring is no longer + * full. + */ + if (!fep->tx_free++) + do_wake = 1; + } + + fep->dirty_tx = bdp; + + if (do_restart) + (*fep->ops->tx_restart)(dev); + + spin_unlock(&fep->lock); + + if (do_wake) + netif_wake_queue(dev); +} + +/* + * The interrupt handler. + * This is called from the MPC core interrupt. + */ +static irqreturn_t +fs_enet_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = dev_id; + struct fs_enet_private *fep; + const struct fs_platform_info *fpi; + u32 int_events; + u32 int_clr_events; + int nr, napi_ok; + int handled; + + fep = netdev_priv(dev); + fpi = fep->fpi; + + nr = 0; + while ((int_events = (*fep->ops->get_int_events)(dev)) != 0) { + + nr++; + + int_clr_events = int_events; + if (fpi->use_napi) + int_clr_events &= ~fep->ev_napi_rx; + + (*fep->ops->clear_int_events)(dev, int_clr_events); + + if (int_events & fep->ev_err) + (*fep->ops->ev_error)(dev, int_events); + + if (int_events & fep->ev_rx) { + if (!fpi->use_napi) + fs_enet_rx_non_napi(dev); + else { + napi_ok = netif_rx_schedule_prep(dev); + + (*fep->ops->napi_disable_rx)(dev); + (*fep->ops->clear_int_events)(dev, fep->ev_napi_rx); + + /* NOTE: it is possible for FCCs in NAPI mode */ + /* to submit a spurious interrupt while in poll */ + if (napi_ok) + __netif_rx_schedule(dev); + } + } + + if (int_events & fep->ev_tx) + fs_enet_tx(dev); + } + + handled = nr > 0; + return IRQ_RETVAL(handled); +} + +void fs_init_bds(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + cbd_t *bdp; + struct sk_buff *skb; + int i; + + fs_cleanup_bds(dev); + + fep->dirty_tx = fep->cur_tx = fep->tx_bd_base; + fep->tx_free = fep->tx_ring; + fep->cur_rx = fep->rx_bd_base; + + /* + * Initialize the receive buffer descriptors. + */ + for (i = 0, bdp = fep->rx_bd_base; i < fep->rx_ring; i++, bdp++) { + skb = dev_alloc_skb(ENET_RX_FRSIZE); + if (skb == NULL) { + printk(KERN_WARNING DRV_MODULE_NAME + ": %s Memory squeeze, unable to allocate skb\n", + dev->name); + break; + } + fep->rx_skbuff[i] = skb; + skb->dev = dev; + CBDW_BUFADDR(bdp, + dma_map_single(fep->dev, skb->data, + L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), + DMA_FROM_DEVICE)); + CBDW_DATLEN(bdp, 0); /* zero */ + CBDW_SC(bdp, BD_ENET_RX_EMPTY | + ((i < fep->rx_ring - 1) ? 0 : BD_SC_WRAP)); + } + /* + * if we failed, fillup remainder + */ + for (; i < fep->rx_ring; i++, bdp++) { + fep->rx_skbuff[i] = NULL; + CBDW_SC(bdp, (i < fep->rx_ring - 1) ? 0 : BD_SC_WRAP); + } + + /* + * ...and the same for transmit. + */ + for (i = 0, bdp = fep->tx_bd_base; i < fep->tx_ring; i++, bdp++) { + fep->tx_skbuff[i] = NULL; + CBDW_BUFADDR(bdp, 0); + CBDW_DATLEN(bdp, 0); + CBDW_SC(bdp, (i < fep->tx_ring - 1) ? 0 : BD_SC_WRAP); + } +} + +void fs_cleanup_bds(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + struct sk_buff *skb; + int i; + + /* + * Reset SKB transmit buffers. + */ + for (i = 0; i < fep->tx_ring; i++) { + if ((skb = fep->tx_skbuff[i]) == NULL) + continue; + + /* unmap */ + dma_unmap_single(fep->dev, skb->data, skb->len, DMA_TO_DEVICE); + + fep->tx_skbuff[i] = NULL; + dev_kfree_skb(skb); + } + + /* + * Reset SKB receive buffers + */ + for (i = 0; i < fep->rx_ring; i++) { + if ((skb = fep->rx_skbuff[i]) == NULL) + continue; + + /* unmap */ + dma_unmap_single(fep->dev, skb->data, + L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), + DMA_FROM_DEVICE); + + fep->rx_skbuff[i] = NULL; + + dev_kfree_skb(skb); + } +} + +/**********************************************************************************/ + +static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + cbd_t *bdp; + int curidx; + u16 sc; + unsigned long flags; + + spin_lock_irqsave(&fep->tx_lock, flags); + + /* + * Fill in a Tx ring entry + */ + bdp = fep->cur_tx; + + if (!fep->tx_free || (CBDR_SC(bdp) & BD_ENET_TX_READY)) { + netif_stop_queue(dev); + spin_unlock_irqrestore(&fep->tx_lock, flags); + + /* + * Ooops. All transmit buffers are full. Bail out. + * This should not happen, since the tx queue should be stopped. + */ + printk(KERN_WARNING DRV_MODULE_NAME + ": %s tx queue full!.\n", dev->name); + return NETDEV_TX_BUSY; + } + + curidx = bdp - fep->tx_bd_base; + /* + * Clear all of the status flags. + */ + CBDC_SC(bdp, BD_ENET_TX_STATS); + + /* + * Save skb pointer. + */ + fep->tx_skbuff[curidx] = skb; + + fep->stats.tx_bytes += skb->len; + + /* + * Push the data cache so the CPM does not get stale memory data. + */ + CBDW_BUFADDR(bdp, dma_map_single(fep->dev, + skb->data, skb->len, DMA_TO_DEVICE)); + CBDW_DATLEN(bdp, skb->len); + + dev->trans_start = jiffies; + + /* + * If this was the last BD in the ring, start at the beginning again. + */ + if ((CBDR_SC(bdp) & BD_ENET_TX_WRAP) == 0) + fep->cur_tx++; + else + fep->cur_tx = fep->tx_bd_base; + + if (!--fep->tx_free) + netif_stop_queue(dev); + + /* Trigger transmission start */ + sc = BD_ENET_TX_READY | BD_ENET_TX_INTR | + BD_ENET_TX_LAST | BD_ENET_TX_TC; + + /* note that while FEC does not have this bit + * it marks it as available for software use + * yay for hw reuse :) */ + if (skb->len <= 60) + sc |= BD_ENET_TX_PAD; + CBDS_SC(bdp, sc); + + (*fep->ops->tx_kickstart)(dev); + + spin_unlock_irqrestore(&fep->tx_lock, flags); + + return NETDEV_TX_OK; +} + +static int fs_request_irq(struct net_device *dev, int irq, const char *name, + irqreturn_t (*irqf)(int irq, void *dev_id, struct pt_regs *regs)) +{ + struct fs_enet_private *fep = netdev_priv(dev); + + (*fep->ops->pre_request_irq)(dev, irq); + return request_irq(irq, irqf, SA_SHIRQ, name, dev); +} + +static void fs_free_irq(struct net_device *dev, int irq) +{ + struct fs_enet_private *fep = netdev_priv(dev); + + free_irq(irq, dev); + (*fep->ops->post_free_irq)(dev, irq); +} + +/**********************************************************************************/ + +/* This interrupt occurs when the PHY detects a link change. */ +static irqreturn_t +fs_mii_link_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = dev_id; + struct fs_enet_private *fep; + const struct fs_platform_info *fpi; + + fep = netdev_priv(dev); + fpi = fep->fpi; + + /* + * Acknowledge the interrupt if possible. If we have not + * found the PHY yet we can't process or acknowledge the + * interrupt now. Instead we ignore this interrupt for now, + * which we can do since it is edge triggered. It will be + * acknowledged later by fs_enet_open(). + */ + if (!fep->phy) + return IRQ_NONE; + + fs_mii_ack_int(dev); + fs_mii_link_status_change_check(dev, 0); + + return IRQ_HANDLED; +} + +static void fs_timeout(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + unsigned long flags; + int wake = 0; + + fep->stats.tx_errors++; + + spin_lock_irqsave(&fep->lock, flags); + + if (dev->flags & IFF_UP) { + (*fep->ops->stop)(dev); + (*fep->ops->restart)(dev); + } + + wake = fep->tx_free && !(CBDR_SC(fep->cur_tx) & BD_ENET_TX_READY); + spin_unlock_irqrestore(&fep->lock, flags); + + if (wake) + netif_wake_queue(dev); +} + +static int fs_enet_open(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + const struct fs_platform_info *fpi = fep->fpi; + int r; + + /* Install our interrupt handler. */ + r = fs_request_irq(dev, fep->interrupt, "fs_enet-mac", fs_enet_interrupt); + if (r != 0) { + printk(KERN_ERR DRV_MODULE_NAME + ": %s Could not allocate FEC IRQ!", dev->name); + return -EINVAL; + } + + /* Install our phy interrupt handler */ + if (fpi->phy_irq != -1) { + + r = fs_request_irq(dev, fpi->phy_irq, "fs_enet-phy", fs_mii_link_interrupt); + if (r != 0) { + printk(KERN_ERR DRV_MODULE_NAME + ": %s Could not allocate PHY IRQ!", dev->name); + fs_free_irq(dev, fep->interrupt); + return -EINVAL; + } + } + + fs_mii_startup(dev); + netif_carrier_off(dev); + fs_mii_link_status_change_check(dev, 1); + + return 0; +} + +static int fs_enet_close(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + const struct fs_platform_info *fpi = fep->fpi; + unsigned long flags; + + netif_stop_queue(dev); + netif_carrier_off(dev); + fs_mii_shutdown(dev); + + spin_lock_irqsave(&fep->lock, flags); + (*fep->ops->stop)(dev); + spin_unlock_irqrestore(&fep->lock, flags); + + /* release any irqs */ + if (fpi->phy_irq != -1) + fs_free_irq(dev, fpi->phy_irq); + fs_free_irq(dev, fep->interrupt); + + return 0; +} + +static struct net_device_stats *fs_enet_get_stats(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + return &fep->stats; +} + +/*************************************************************************/ + +static void fs_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *info) +{ + strcpy(info->driver, DRV_MODULE_NAME); + strcpy(info->version, DRV_MODULE_VERSION); +} + +static int fs_get_regs_len(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + + return (*fep->ops->get_regs_len)(dev); +} + +static void fs_get_regs(struct net_device *dev, struct ethtool_regs *regs, + void *p) +{ + struct fs_enet_private *fep = netdev_priv(dev); + unsigned long flags; + int r, len; + + len = regs->len; + + spin_lock_irqsave(&fep->lock, flags); + r = (*fep->ops->get_regs)(dev, p, &len); + spin_unlock_irqrestore(&fep->lock, flags); + + if (r == 0) + regs->version = 0; +} + +static int fs_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct fs_enet_private *fep = netdev_priv(dev); + unsigned long flags; + int rc; + + spin_lock_irqsave(&fep->lock, flags); + rc = mii_ethtool_gset(&fep->mii_if, cmd); + spin_unlock_irqrestore(&fep->lock, flags); + + return rc; +} + +static int fs_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct fs_enet_private *fep = netdev_priv(dev); + unsigned long flags; + int rc; + + spin_lock_irqsave(&fep->lock, flags); + rc = mii_ethtool_sset(&fep->mii_if, cmd); + spin_unlock_irqrestore(&fep->lock, flags); + + return rc; +} + +static int fs_nway_reset(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + return mii_nway_restart(&fep->mii_if); +} + +static u32 fs_get_msglevel(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + return fep->msg_enable; +} + +static void fs_set_msglevel(struct net_device *dev, u32 value) +{ + struct fs_enet_private *fep = netdev_priv(dev); + fep->msg_enable = value; +} + +static struct ethtool_ops fs_ethtool_ops = { + .get_drvinfo = fs_get_drvinfo, + .get_regs_len = fs_get_regs_len, + .get_settings = fs_get_settings, + .set_settings = fs_set_settings, + .nway_reset = fs_nway_reset, + .get_link = ethtool_op_get_link, + .get_msglevel = fs_get_msglevel, + .set_msglevel = fs_set_msglevel, + .get_tx_csum = ethtool_op_get_tx_csum, + .set_tx_csum = ethtool_op_set_tx_csum, /* local! */ + .get_sg = ethtool_op_get_sg, + .set_sg = ethtool_op_set_sg, + .get_regs = fs_get_regs, +}; + +static int fs_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct fs_enet_private *fep = netdev_priv(dev); + struct mii_ioctl_data *mii = (struct mii_ioctl_data *)&rq->ifr_data; + unsigned long flags; + int rc; + + if (!netif_running(dev)) + return -EINVAL; + + spin_lock_irqsave(&fep->lock, flags); + rc = generic_mii_ioctl(&fep->mii_if, mii, cmd, NULL); + spin_unlock_irqrestore(&fep->lock, flags); + return rc; +} + +extern int fs_mii_connect(struct net_device *dev); +extern void fs_mii_disconnect(struct net_device *dev); + +static struct net_device *fs_init_instance(struct device *dev, + const struct fs_platform_info *fpi) +{ + struct net_device *ndev = NULL; + struct fs_enet_private *fep = NULL; + int privsize, i, r, err = 0, registered = 0; + + /* guard */ + if ((unsigned int)fpi->fs_no >= FS_MAX_INDEX) + return ERR_PTR(-EINVAL); + + privsize = sizeof(*fep) + (sizeof(struct sk_buff **) * + (fpi->rx_ring + fpi->tx_ring)); + + ndev = alloc_etherdev(privsize); + if (!ndev) { + err = -ENOMEM; + goto err; + } + SET_MODULE_OWNER(ndev); + + fep = netdev_priv(ndev); + memset(fep, 0, privsize); /* clear everything */ + + fep->dev = dev; + dev_set_drvdata(dev, ndev); + fep->fpi = fpi; + if (fpi->init_ioports) + fpi->init_ioports(); + +#ifdef CONFIG_FS_ENET_HAS_FEC + if (fs_get_fec_index(fpi->fs_no) >= 0) + fep->ops = &fs_fec_ops; +#endif + +#ifdef CONFIG_FS_ENET_HAS_SCC + if (fs_get_scc_index(fpi->fs_no) >=0 ) + fep->ops = &fs_scc_ops; +#endif + +#ifdef CONFIG_FS_ENET_HAS_FCC + if (fs_get_fcc_index(fpi->fs_no) >= 0) + fep->ops = &fs_fcc_ops; +#endif + + if (fep->ops == NULL) { + printk(KERN_ERR DRV_MODULE_NAME + ": %s No matching ops found (%d).\n", + ndev->name, fpi->fs_no); + err = -EINVAL; + goto err; + } + + r = (*fep->ops->setup_data)(ndev); + if (r != 0) { + printk(KERN_ERR DRV_MODULE_NAME + ": %s setup_data failed\n", + ndev->name); + err = r; + goto err; + } + + /* point rx_skbuff, tx_skbuff */ + fep->rx_skbuff = (struct sk_buff **)&fep[1]; + fep->tx_skbuff = fep->rx_skbuff + fpi->rx_ring; + + /* init locks */ + spin_lock_init(&fep->lock); + spin_lock_init(&fep->tx_lock); + + /* + * Set the Ethernet address. + */ + for (i = 0; i < 6; i++) + ndev->dev_addr[i] = fpi->macaddr[i]; + + r = (*fep->ops->allocate_bd)(ndev); + + if (fep->ring_base == NULL) { + printk(KERN_ERR DRV_MODULE_NAME + ": %s buffer descriptor alloc failed (%d).\n", ndev->name, r); + err = r; + goto err; + } + + /* + * Set receive and transmit descriptor base. + */ + fep->rx_bd_base = fep->ring_base; + fep->tx_bd_base = fep->rx_bd_base + fpi->rx_ring; + + /* initialize ring size variables */ + fep->tx_ring = fpi->tx_ring; + fep->rx_ring = fpi->rx_ring; + + /* + * The FEC Ethernet specific entries in the device structure. + */ + ndev->open = fs_enet_open; + ndev->hard_start_xmit = fs_enet_start_xmit; + ndev->tx_timeout = fs_timeout; + ndev->watchdog_timeo = 2 * HZ; + ndev->stop = fs_enet_close; + ndev->get_stats = fs_enet_get_stats; + ndev->set_multicast_list = fs_set_multicast_list; + if (fpi->use_napi) { + ndev->poll = fs_enet_rx_napi; + ndev->weight = fpi->napi_weight; + } + ndev->ethtool_ops = &fs_ethtool_ops; + ndev->do_ioctl = fs_ioctl; + + init_timer(&fep->phy_timer_list); + + netif_carrier_off(ndev); + + err = register_netdev(ndev); + if (err != 0) { + printk(KERN_ERR DRV_MODULE_NAME + ": %s register_netdev failed.\n", ndev->name); + goto err; + } + registered = 1; + + err = fs_mii_connect(ndev); + if (err != 0) { + printk(KERN_ERR DRV_MODULE_NAME + ": %s fs_mii_connect failed.\n", ndev->name); + goto err; + } + + return ndev; + + err: + if (ndev != NULL) { + + if (registered) + unregister_netdev(ndev); + + if (fep != NULL) { + (*fep->ops->free_bd)(ndev); + (*fep->ops->cleanup_data)(ndev); + } + + free_netdev(ndev); + } + + dev_set_drvdata(dev, NULL); + + return ERR_PTR(err); +} + +static int fs_cleanup_instance(struct net_device *ndev) +{ + struct fs_enet_private *fep; + const struct fs_platform_info *fpi; + struct device *dev; + + if (ndev == NULL) + return -EINVAL; + + fep = netdev_priv(ndev); + if (fep == NULL) + return -EINVAL; + + fpi = fep->fpi; + + fs_mii_disconnect(ndev); + + unregister_netdev(ndev); + + dma_free_coherent(fep->dev, (fpi->tx_ring + fpi->rx_ring) * sizeof(cbd_t), + fep->ring_base, fep->ring_mem_addr); + + /* reset it */ + (*fep->ops->cleanup_data)(ndev); + + dev = fep->dev; + if (dev != NULL) { + dev_set_drvdata(dev, NULL); + fep->dev = NULL; + } + + free_netdev(ndev); + + return 0; +} + +/**************************************************************************************/ + +/* handy pointer to the immap */ +void *fs_enet_immap = NULL; + +static int setup_immap(void) +{ + phys_addr_t paddr = 0; + unsigned long size = 0; + +#ifdef CONFIG_CPM1 + paddr = IMAP_ADDR; + size = 0x10000; /* map 64K */ +#endif + +#ifdef CONFIG_CPM2 + paddr = CPM_MAP_ADDR; + size = 0x40000; /* map 256 K */ +#endif + fs_enet_immap = ioremap(paddr, size); + if (fs_enet_immap == NULL) + return -EBADF; /* XXX ahem; maybe just BUG_ON? */ + + return 0; +} + +static void cleanup_immap(void) +{ + if (fs_enet_immap != NULL) { + iounmap(fs_enet_immap); + fs_enet_immap = NULL; + } +} + +/**************************************************************************************/ + +static int __devinit fs_enet_probe(struct device *dev) +{ + struct net_device *ndev; + + /* no fixup - no device */ + if (dev->platform_data == NULL) { + printk(KERN_INFO "fs_enet: " + "probe called with no platform data; " + "remove unused devices\n"); + return -ENODEV; + } + + ndev = fs_init_instance(dev, dev->platform_data); + if (IS_ERR(ndev)) + return PTR_ERR(ndev); + return 0; +} + +static int fs_enet_remove(struct device *dev) +{ + return fs_cleanup_instance(dev_get_drvdata(dev)); +} + +static struct device_driver fs_enet_fec_driver = { + .name = "fsl-cpm-fec", + .bus = &platform_bus_type, + .probe = fs_enet_probe, + .remove = fs_enet_remove, +#ifdef CONFIG_PM +/* .suspend = fs_enet_suspend, TODO */ +/* .resume = fs_enet_resume, TODO */ +#endif +}; + +static struct device_driver fs_enet_scc_driver = { + .name = "fsl-cpm-scc", + .bus = &platform_bus_type, + .probe = fs_enet_probe, + .remove = fs_enet_remove, +#ifdef CONFIG_PM +/* .suspend = fs_enet_suspend, TODO */ +/* .resume = fs_enet_resume, TODO */ +#endif +}; + +static struct device_driver fs_enet_fcc_driver = { + .name = "fsl-cpm-fcc", + .bus = &platform_bus_type, + .probe = fs_enet_probe, + .remove = fs_enet_remove, +#ifdef CONFIG_PM +/* .suspend = fs_enet_suspend, TODO */ +/* .resume = fs_enet_resume, TODO */ +#endif +}; + +static int __init fs_init(void) +{ + int r; + + printk(KERN_INFO + "%s", version); + + r = setup_immap(); + if (r != 0) + return r; + r = driver_register(&fs_enet_fec_driver); + if (r != 0) + goto err; + + r = driver_register(&fs_enet_fcc_driver); + if (r != 0) + goto err; + + r = driver_register(&fs_enet_scc_driver); + if (r != 0) + goto err; + + return 0; +err: + cleanup_immap(); + return r; + +} + +static void __exit fs_cleanup(void) +{ + driver_unregister(&fs_enet_fec_driver); + driver_unregister(&fs_enet_fcc_driver); + driver_unregister(&fs_enet_scc_driver); + cleanup_immap(); +} + +/**************************************************************************************/ + +module_init(fs_init); +module_exit(fs_cleanup); diff --git a/drivers/net/fs_enet/fs_enet-mii.c b/drivers/net/fs_enet/fs_enet-mii.c new file mode 100644 index 000000000000..c6770377ef87 --- /dev/null +++ b/drivers/net/fs_enet/fs_enet-mii.c @@ -0,0 +1,507 @@ +/* + * Combined Ethernet driver for Motorola MPC8xx and MPC82xx. + * + * Copyright (c) 2003 Intracom S.A. + * by Pantelis Antoniou <panto@intracom.gr> + * + * 2005 (c) MontaVista Software, Inc. + * Vitaly Bordug <vbordug@ru.mvista.com> + * + * Heavily based on original FEC driver by Dan Malek <dan@embeddededge.com> + * and modifications by Joakim Tjernlund <joakim.tjernlund@lumentis.se> + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/string.h> +#include <linux/ptrace.h> +#include <linux/errno.h> +#include <linux/ioport.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/spinlock.h> +#include <linux/mii.h> +#include <linux/ethtool.h> +#include <linux/bitops.h> + +#include <asm/pgtable.h> +#include <asm/irq.h> +#include <asm/uaccess.h> + +#include "fs_enet.h" + +/*************************************************/ + +/* + * Generic PHY support. + * Should work for all PHYs, but link change is detected by polling + */ + +static void generic_timer_callback(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct fs_enet_private *fep = netdev_priv(dev); + + fep->phy_timer_list.expires = jiffies + HZ / 2; + + add_timer(&fep->phy_timer_list); + + fs_mii_link_status_change_check(dev, 0); +} + +static void generic_startup(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + + fep->phy_timer_list.expires = jiffies + HZ / 2; /* every 500ms */ + fep->phy_timer_list.data = (unsigned long)dev; + fep->phy_timer_list.function = generic_timer_callback; + add_timer(&fep->phy_timer_list); +} + +static void generic_shutdown(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + + del_timer_sync(&fep->phy_timer_list); +} + +/* ------------------------------------------------------------------------- */ +/* The Davicom DM9161 is used on the NETTA board */ + +/* register definitions */ + +#define MII_DM9161_ANAR 4 /* Aux. Config Register */ +#define MII_DM9161_ACR 16 /* Aux. Config Register */ +#define MII_DM9161_ACSR 17 /* Aux. Config/Status Register */ +#define MII_DM9161_10TCSR 18 /* 10BaseT Config/Status Reg. */ +#define MII_DM9161_INTR 21 /* Interrupt Register */ +#define MII_DM9161_RECR 22 /* Receive Error Counter Reg. */ +#define MII_DM9161_DISCR 23 /* Disconnect Counter Register */ + +static void dm9161_startup(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + + fs_mii_write(dev, fep->mii_if.phy_id, MII_DM9161_INTR, 0x0000); + /* Start autonegotiation */ + fs_mii_write(dev, fep->mii_if.phy_id, MII_BMCR, 0x1200); + + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ*8); +} + +static void dm9161_ack_int(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + + fs_mii_read(dev, fep->mii_if.phy_id, MII_DM9161_INTR); +} + +static void dm9161_shutdown(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + + fs_mii_write(dev, fep->mii_if.phy_id, MII_DM9161_INTR, 0x0f00); +} + +/**********************************************************************************/ + +static const struct phy_info phy_info[] = { + { + .id = 0x00181b88, + .name = "DM9161", + .startup = dm9161_startup, + .ack_int = dm9161_ack_int, + .shutdown = dm9161_shutdown, + }, { + .id = 0, + .name = "GENERIC", + .startup = generic_startup, + .shutdown = generic_shutdown, + }, +}; + +/**********************************************************************************/ + +static int phy_id_detect(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + const struct fs_platform_info *fpi = fep->fpi; + struct fs_enet_mii_bus *bus = fep->mii_bus; + int i, r, start, end, phytype, physubtype; + const struct phy_info *phy; + int phy_hwid, phy_id; + + phy_hwid = -1; + fep->phy = NULL; + + /* auto-detect? */ + if (fpi->phy_addr == -1) { + start = 1; + end = 32; + } else { /* direct */ + start = fpi->phy_addr; + end = start + 1; + } + + for (phy_id = start; phy_id < end; phy_id++) { + /* skip already used phy addresses on this bus */ + if (bus->usage_map & (1 << phy_id)) + continue; + r = fs_mii_read(dev, phy_id, MII_PHYSID1); + if (r == -1 || (phytype = (r & 0xffff)) == 0xffff) + continue; + r = fs_mii_read(dev, phy_id, MII_PHYSID2); + if (r == -1 || (physubtype = (r & 0xffff)) == 0xffff) + continue; + phy_hwid = (phytype << 16) | physubtype; + if (phy_hwid != -1) + break; + } + + if (phy_hwid == -1) { + printk(KERN_ERR DRV_MODULE_NAME + ": %s No PHY detected! range=0x%02x-0x%02x\n", + dev->name, start, end); + return -1; + } + + for (i = 0, phy = phy_info; i < ARRAY_SIZE(phy_info); i++, phy++) + if (phy->id == (phy_hwid >> 4) || phy->id == 0) + break; + + if (i >= ARRAY_SIZE(phy_info)) { + printk(KERN_ERR DRV_MODULE_NAME + ": %s PHY id 0x%08x is not supported!\n", + dev->name, phy_hwid); + return -1; + } + + fep->phy = phy; + + /* mark this address as used */ + bus->usage_map |= (1 << phy_id); + + printk(KERN_INFO DRV_MODULE_NAME + ": %s Phy @ 0x%x, type %s (0x%08x)%s\n", + dev->name, phy_id, fep->phy->name, phy_hwid, + fpi->phy_addr == -1 ? " (auto-detected)" : ""); + + return phy_id; +} + +void fs_mii_startup(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + + if (fep->phy->startup) + (*fep->phy->startup) (dev); +} + +void fs_mii_shutdown(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + + if (fep->phy->shutdown) + (*fep->phy->shutdown) (dev); +} + +void fs_mii_ack_int(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + + if (fep->phy->ack_int) + (*fep->phy->ack_int) (dev); +} + +#define MII_LINK 0x0001 +#define MII_HALF 0x0002 +#define MII_FULL 0x0004 +#define MII_BASE4 0x0008 +#define MII_10M 0x0010 +#define MII_100M 0x0020 +#define MII_1G 0x0040 +#define MII_10G 0x0080 + +/* return full mii info at one gulp, with a usable form */ +static unsigned int mii_full_status(struct mii_if_info *mii) +{ + unsigned int status; + int bmsr, adv, lpa, neg; + struct fs_enet_private* fep = netdev_priv(mii->dev); + + /* first, a dummy read, needed to latch some MII phys */ + (void)mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR); + bmsr = mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR); + + /* no link */ + if ((bmsr & BMSR_LSTATUS) == 0) + return 0; + + status = MII_LINK; + + /* Lets look what ANEG says if it's supported - otherwize we shall + take the right values from the platform info*/ + if(!mii->force_media) { + /* autoneg not completed; don't bother */ + if ((bmsr & BMSR_ANEGCOMPLETE) == 0) + return 0; + + adv = (*mii->mdio_read)(mii->dev, mii->phy_id, MII_ADVERTISE); + lpa = (*mii->mdio_read)(mii->dev, mii->phy_id, MII_LPA); + + neg = lpa & adv; + } else { + neg = fep->fpi->bus_info->lpa; + } + + if (neg & LPA_100FULL) + status |= MII_FULL | MII_100M; + else if (neg & LPA_100BASE4) + status |= MII_FULL | MII_BASE4 | MII_100M; + else if (neg & LPA_100HALF) + status |= MII_HALF | MII_100M; + else if (neg & LPA_10FULL) + status |= MII_FULL | MII_10M; + else + status |= MII_HALF | MII_10M; + + return status; +} + +void fs_mii_link_status_change_check(struct net_device *dev, int init_media) +{ + struct fs_enet_private *fep = netdev_priv(dev); + struct mii_if_info *mii = &fep->mii_if; + unsigned int mii_status; + int ok_to_print, link, duplex, speed; + unsigned long flags; + + ok_to_print = netif_msg_link(fep); + + mii_status = mii_full_status(mii); + + if (!init_media && mii_status == fep->last_mii_status) + return; + + fep->last_mii_status = mii_status; + + link = !!(mii_status & MII_LINK); + duplex = !!(mii_status & MII_FULL); + speed = (mii_status & MII_100M) ? 100 : 10; + + if (link == 0) { + netif_carrier_off(mii->dev); + netif_stop_queue(dev); + if (!init_media) { + spin_lock_irqsave(&fep->lock, flags); + (*fep->ops->stop)(dev); + spin_unlock_irqrestore(&fep->lock, flags); + } + + if (ok_to_print) + printk(KERN_INFO "%s: link down\n", mii->dev->name); + + } else { + + mii->full_duplex = duplex; + + netif_carrier_on(mii->dev); + + spin_lock_irqsave(&fep->lock, flags); + fep->duplex = duplex; + fep->speed = speed; + (*fep->ops->restart)(dev); + spin_unlock_irqrestore(&fep->lock, flags); + + netif_start_queue(dev); + + if (ok_to_print) + printk(KERN_INFO "%s: link up, %dMbps, %s-duplex\n", + dev->name, speed, duplex ? "full" : "half"); + } +} + +/**********************************************************************************/ + +int fs_mii_read(struct net_device *dev, int phy_id, int location) +{ + struct fs_enet_private *fep = netdev_priv(dev); + struct fs_enet_mii_bus *bus = fep->mii_bus; + + unsigned long flags; + int ret; + + spin_lock_irqsave(&bus->mii_lock, flags); + ret = (*bus->mii_read)(bus, phy_id, location); + spin_unlock_irqrestore(&bus->mii_lock, flags); + + return ret; +} + +void fs_mii_write(struct net_device *dev, int phy_id, int location, int value) +{ + struct fs_enet_private *fep = netdev_priv(dev); + struct fs_enet_mii_bus *bus = fep->mii_bus; + unsigned long flags; + + spin_lock_irqsave(&bus->mii_lock, flags); + (*bus->mii_write)(bus, phy_id, location, value); + spin_unlock_irqrestore(&bus->mii_lock, flags); +} + +/*****************************************************************************/ + +/* list of all registered mii buses */ +static LIST_HEAD(fs_mii_bus_list); + +static struct fs_enet_mii_bus *lookup_bus(int method, int id) +{ + struct list_head *ptr; + struct fs_enet_mii_bus *bus; + + list_for_each(ptr, &fs_mii_bus_list) { + bus = list_entry(ptr, struct fs_enet_mii_bus, list); + if (bus->bus_info->method == method && + bus->bus_info->id == id) + return bus; + } + return NULL; +} + +static struct fs_enet_mii_bus *create_bus(const struct fs_mii_bus_info *bi) +{ + struct fs_enet_mii_bus *bus; + int ret = 0; + + bus = kmalloc(sizeof(*bus), GFP_KERNEL); + if (bus == NULL) { + ret = -ENOMEM; + goto err; + } + memset(bus, 0, sizeof(*bus)); + spin_lock_init(&bus->mii_lock); + bus->bus_info = bi; + bus->refs = 0; + bus->usage_map = 0; + + /* perform initialization */ + switch (bi->method) { + + case fsmii_fixed: + ret = fs_mii_fixed_init(bus); + if (ret != 0) + goto err; + break; + + case fsmii_bitbang: + ret = fs_mii_bitbang_init(bus); + if (ret != 0) + goto err; + break; +#ifdef CONFIG_FS_ENET_HAS_FEC + case fsmii_fec: + ret = fs_mii_fec_init(bus); + if (ret != 0) + goto err; + break; +#endif + default: + ret = -EINVAL; + goto err; + } + + list_add(&bus->list, &fs_mii_bus_list); + + return bus; + +err: + if (bus) + kfree(bus); + return ERR_PTR(ret); +} + +static void destroy_bus(struct fs_enet_mii_bus *bus) +{ + /* remove from bus list */ + list_del(&bus->list); + + /* nothing more needed */ + kfree(bus); +} + +int fs_mii_connect(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + const struct fs_platform_info *fpi = fep->fpi; + struct fs_enet_mii_bus *bus = NULL; + + /* check method validity */ + switch (fpi->bus_info->method) { + case fsmii_fixed: + case fsmii_bitbang: + break; +#ifdef CONFIG_FS_ENET_HAS_FEC + case fsmii_fec: + break; +#endif + default: + printk(KERN_ERR DRV_MODULE_NAME + ": %s Unknown MII bus method (%d)!\n", + dev->name, fpi->bus_info->method); + return -EINVAL; + } + + bus = lookup_bus(fpi->bus_info->method, fpi->bus_info->id); + + /* if not found create new bus */ + if (bus == NULL) { + bus = create_bus(fpi->bus_info); + if (IS_ERR(bus)) { + printk(KERN_ERR DRV_MODULE_NAME + ": %s MII bus creation failure!\n", dev->name); + return PTR_ERR(bus); + } + } + + bus->refs++; + + fep->mii_bus = bus; + + fep->mii_if.dev = dev; + fep->mii_if.phy_id_mask = 0x1f; + fep->mii_if.reg_num_mask = 0x1f; + fep->mii_if.mdio_read = fs_mii_read; + fep->mii_if.mdio_write = fs_mii_write; + fep->mii_if.force_media = fpi->bus_info->disable_aneg; + fep->mii_if.phy_id = phy_id_detect(dev); + + return 0; +} + +void fs_mii_disconnect(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + struct fs_enet_mii_bus *bus = NULL; + + bus = fep->mii_bus; + fep->mii_bus = NULL; + + if (--bus->refs <= 0) + destroy_bus(bus); +} diff --git a/drivers/net/fs_enet/fs_enet.h b/drivers/net/fs_enet/fs_enet.h new file mode 100644 index 000000000000..1105543b9d88 --- /dev/null +++ b/drivers/net/fs_enet/fs_enet.h @@ -0,0 +1,245 @@ +#ifndef FS_ENET_H +#define FS_ENET_H + +#include <linux/mii.h> +#include <linux/netdevice.h> +#include <linux/types.h> +#include <linux/version.h> +#include <linux/list.h> + +#include <linux/fs_enet_pd.h> + +#include <asm/dma-mapping.h> + +#ifdef CONFIG_CPM1 +#include <asm/commproc.h> +#endif + +#ifdef CONFIG_CPM2 +#include <asm/cpm2.h> +#endif + +/* hw driver ops */ +struct fs_ops { + int (*setup_data)(struct net_device *dev); + int (*allocate_bd)(struct net_device *dev); + void (*free_bd)(struct net_device *dev); + void (*cleanup_data)(struct net_device *dev); + void (*set_multicast_list)(struct net_device *dev); + void (*restart)(struct net_device *dev); + void (*stop)(struct net_device *dev); + void (*pre_request_irq)(struct net_device *dev, int irq); + void (*post_free_irq)(struct net_device *dev, int irq); + void (*napi_clear_rx_event)(struct net_device *dev); + void (*napi_enable_rx)(struct net_device *dev); + void (*napi_disable_rx)(struct net_device *dev); + void (*rx_bd_done)(struct net_device *dev); + void (*tx_kickstart)(struct net_device *dev); + u32 (*get_int_events)(struct net_device *dev); + void (*clear_int_events)(struct net_device *dev, u32 int_events); + void (*ev_error)(struct net_device *dev, u32 int_events); + int (*get_regs)(struct net_device *dev, void *p, int *sizep); + int (*get_regs_len)(struct net_device *dev); + void (*tx_restart)(struct net_device *dev); +}; + +struct phy_info { + unsigned int id; + const char *name; + void (*startup) (struct net_device * dev); + void (*shutdown) (struct net_device * dev); + void (*ack_int) (struct net_device * dev); +}; + +/* The FEC stores dest/src/type, data, and checksum for receive packets. + */ +#define MAX_MTU 1508 /* Allow fullsized pppoe packets over VLAN */ +#define MIN_MTU 46 /* this is data size */ +#define CRC_LEN 4 + +#define PKT_MAXBUF_SIZE (MAX_MTU+ETH_HLEN+CRC_LEN) +#define PKT_MINBUF_SIZE (MIN_MTU+ETH_HLEN+CRC_LEN) + +/* Must be a multiple of 32 (to cover both FEC & FCC) */ +#define PKT_MAXBLR_SIZE ((PKT_MAXBUF_SIZE + 31) & ~31) +/* This is needed so that invalidate_xxx wont invalidate too much */ +#define ENET_RX_FRSIZE L1_CACHE_ALIGN(PKT_MAXBUF_SIZE) + +struct fs_enet_mii_bus { + struct list_head list; + spinlock_t mii_lock; + const struct fs_mii_bus_info *bus_info; + int refs; + u32 usage_map; + + int (*mii_read)(struct fs_enet_mii_bus *bus, + int phy_id, int location); + + void (*mii_write)(struct fs_enet_mii_bus *bus, + int phy_id, int location, int value); + + union { + struct { + unsigned int mii_speed; + void *fecp; + } fec; + + struct { + /* note that the actual port size may */ + /* be different; cpm(s) handle it OK */ + u8 mdio_msk; + u8 *mdio_dir; + u8 *mdio_dat; + u8 mdc_msk; + u8 *mdc_dir; + u8 *mdc_dat; + } bitbang; + + struct { + u16 lpa; + } fixed; + }; +}; + +int fs_mii_bitbang_init(struct fs_enet_mii_bus *bus); +int fs_mii_fixed_init(struct fs_enet_mii_bus *bus); +int fs_mii_fec_init(struct fs_enet_mii_bus *bus); + +struct fs_enet_private { + struct device *dev; /* pointer back to the device (must be initialized first) */ + spinlock_t lock; /* during all ops except TX pckt processing */ + spinlock_t tx_lock; /* during fs_start_xmit and fs_tx */ + const struct fs_platform_info *fpi; + const struct fs_ops *ops; + int rx_ring, tx_ring; + dma_addr_t ring_mem_addr; + void *ring_base; + struct sk_buff **rx_skbuff; + struct sk_buff **tx_skbuff; + cbd_t *rx_bd_base; /* Address of Rx and Tx buffers. */ + cbd_t *tx_bd_base; + cbd_t *dirty_tx; /* ring entries to be free()ed. */ + cbd_t *cur_rx; + cbd_t *cur_tx; + int tx_free; + struct net_device_stats stats; + struct timer_list phy_timer_list; + const struct phy_info *phy; + u32 msg_enable; + struct mii_if_info mii_if; + unsigned int last_mii_status; + struct fs_enet_mii_bus *mii_bus; + int interrupt; + + int duplex, speed; /* current settings */ + + /* event masks */ + u32 ev_napi_rx; /* mask of NAPI rx events */ + u32 ev_rx; /* rx event mask */ + u32 ev_tx; /* tx event mask */ + u32 ev_err; /* error event mask */ + + u16 bd_rx_empty; /* mask of BD rx empty */ + u16 bd_rx_err; /* mask of BD rx errors */ + + union { + struct { + int idx; /* FEC1 = 0, FEC2 = 1 */ + void *fecp; /* hw registers */ + u32 hthi, htlo; /* state for multicast */ + } fec; + + struct { + int idx; /* FCC1-3 = 0-2 */ + void *fccp; /* hw registers */ + void *ep; /* parameter ram */ + void *fcccp; /* hw registers cont. */ + void *mem; /* FCC DPRAM */ + u32 gaddrh, gaddrl; /* group address */ + } fcc; + + struct { + int idx; /* FEC1 = 0, FEC2 = 1 */ + void *sccp; /* hw registers */ + void *ep; /* parameter ram */ + u32 hthi, htlo; /* state for multicast */ + } scc; + + }; +}; + +/***************************************************************************/ + +int fs_mii_read(struct net_device *dev, int phy_id, int location); +void fs_mii_write(struct net_device *dev, int phy_id, int location, int value); + +void fs_mii_startup(struct net_device *dev); +void fs_mii_shutdown(struct net_device *dev); +void fs_mii_ack_int(struct net_device *dev); + +void fs_mii_link_status_change_check(struct net_device *dev, int init_media); + +void fs_init_bds(struct net_device *dev); +void fs_cleanup_bds(struct net_device *dev); + +/***************************************************************************/ + +#define DRV_MODULE_NAME "fs_enet" +#define PFX DRV_MODULE_NAME ": " +#define DRV_MODULE_VERSION "1.0" +#define DRV_MODULE_RELDATE "Aug 8, 2005" + +/***************************************************************************/ + +int fs_enet_platform_init(void); +void fs_enet_platform_cleanup(void); + +/***************************************************************************/ + +/* buffer descriptor access macros */ + +/* access macros */ +#if defined(CONFIG_CPM1) +/* for a a CPM1 __raw_xxx's are sufficient */ +#define __cbd_out32(addr, x) __raw_writel(x, addr) +#define __cbd_out16(addr, x) __raw_writew(x, addr) +#define __cbd_in32(addr) __raw_readl(addr) +#define __cbd_in16(addr) __raw_readw(addr) +#else +/* for others play it safe */ +#define __cbd_out32(addr, x) out_be32(addr, x) +#define __cbd_out16(addr, x) out_be16(addr, x) +#define __cbd_in32(addr) in_be32(addr) +#define __cbd_in16(addr) in_be16(addr) +#endif + +/* write */ +#define CBDW_SC(_cbd, _sc) __cbd_out16(&(_cbd)->cbd_sc, (_sc)) +#define CBDW_DATLEN(_cbd, _datlen) __cbd_out16(&(_cbd)->cbd_datlen, (_datlen)) +#define CBDW_BUFADDR(_cbd, _bufaddr) __cbd_out32(&(_cbd)->cbd_bufaddr, (_bufaddr)) + +/* read */ +#define CBDR_SC(_cbd) __cbd_in16(&(_cbd)->cbd_sc) +#define CBDR_DATLEN(_cbd) __cbd_in16(&(_cbd)->cbd_datlen) +#define CBDR_BUFADDR(_cbd) __cbd_in32(&(_cbd)->cbd_bufaddr) + +/* set bits */ +#define CBDS_SC(_cbd, _sc) CBDW_SC(_cbd, CBDR_SC(_cbd) | (_sc)) + +/* clear bits */ +#define CBDC_SC(_cbd, _sc) CBDW_SC(_cbd, CBDR_SC(_cbd) & ~(_sc)) + +/*******************************************************************/ + +extern const struct fs_ops fs_fec_ops; +extern const struct fs_ops fs_fcc_ops; +extern const struct fs_ops fs_scc_ops; + +/*******************************************************************/ + +/* handy pointer to the immap */ +extern void *fs_enet_immap; + +/*******************************************************************/ + +#endif diff --git a/drivers/net/fs_enet/mac-fcc.c b/drivers/net/fs_enet/mac-fcc.c new file mode 100644 index 000000000000..a940b96433c7 --- /dev/null +++ b/drivers/net/fs_enet/mac-fcc.c @@ -0,0 +1,578 @@ +/* + * FCC driver for Motorola MPC82xx (PQ2). + * + * Copyright (c) 2003 Intracom S.A. + * by Pantelis Antoniou <panto@intracom.gr> + * + * 2005 (c) MontaVista Software, Inc. + * Vitaly Bordug <vbordug@ru.mvista.com> + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/sched.h> +#include <linux/string.h> +#include <linux/ptrace.h> +#include <linux/errno.h> +#include <linux/ioport.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/spinlock.h> +#include <linux/mii.h> +#include <linux/ethtool.h> +#include <linux/bitops.h> +#include <linux/fs.h> + +#include <asm/immap_cpm2.h> +#include <asm/mpc8260.h> +#include <asm/cpm2.h> + +#include <asm/pgtable.h> +#include <asm/irq.h> +#include <asm/uaccess.h> + +#include "fs_enet.h" + +/*************************************************/ + +/* FCC access macros */ + +#define __fcc_out32(addr, x) out_be32((unsigned *)addr, x) +#define __fcc_out16(addr, x) out_be16((unsigned short *)addr, x) +#define __fcc_out8(addr, x) out_8((unsigned char *)addr, x) +#define __fcc_in32(addr) in_be32((unsigned *)addr) +#define __fcc_in16(addr) in_be16((unsigned short *)addr) +#define __fcc_in8(addr) in_8((unsigned char *)addr) + +/* parameter space */ + +/* write, read, set bits, clear bits */ +#define W32(_p, _m, _v) __fcc_out32(&(_p)->_m, (_v)) +#define R32(_p, _m) __fcc_in32(&(_p)->_m) +#define S32(_p, _m, _v) W32(_p, _m, R32(_p, _m) | (_v)) +#define C32(_p, _m, _v) W32(_p, _m, R32(_p, _m) & ~(_v)) + +#define W16(_p, _m, _v) __fcc_out16(&(_p)->_m, (_v)) +#define R16(_p, _m) __fcc_in16(&(_p)->_m) +#define S16(_p, _m, _v) W16(_p, _m, R16(_p, _m) | (_v)) +#define C16(_p, _m, _v) W16(_p, _m, R16(_p, _m) & ~(_v)) + +#define W8(_p, _m, _v) __fcc_out8(&(_p)->_m, (_v)) +#define R8(_p, _m) __fcc_in8(&(_p)->_m) +#define S8(_p, _m, _v) W8(_p, _m, R8(_p, _m) | (_v)) +#define C8(_p, _m, _v) W8(_p, _m, R8(_p, _m) & ~(_v)) + +/*************************************************/ + +#define FCC_MAX_MULTICAST_ADDRS 64 + +#define mk_mii_read(REG) (0x60020000 | ((REG & 0x1f) << 18)) +#define mk_mii_write(REG, VAL) (0x50020000 | ((REG & 0x1f) << 18) | (VAL & 0xffff)) +#define mk_mii_end 0 + +#define MAX_CR_CMD_LOOPS 10000 + +static inline int fcc_cr_cmd(struct fs_enet_private *fep, u32 mcn, u32 op) +{ + const struct fs_platform_info *fpi = fep->fpi; + + cpm2_map_t *immap = fs_enet_immap; + cpm_cpm2_t *cpmp = &immap->im_cpm; + u32 v; + int i; + + /* Currently I don't know what feature call will look like. But + I guess there'd be something like do_cpm_cmd() which will require page & sblock */ + v = mk_cr_cmd(fpi->cp_page, fpi->cp_block, mcn, op); + W32(cpmp, cp_cpcr, v | CPM_CR_FLG); + for (i = 0; i < MAX_CR_CMD_LOOPS; i++) + if ((R32(cpmp, cp_cpcr) & CPM_CR_FLG) == 0) + break; + + if (i >= MAX_CR_CMD_LOOPS) { + printk(KERN_ERR "%s(): Not able to issue CPM command\n", + __FUNCTION__); + return 1; + } + + return 0; +} + +static int do_pd_setup(struct fs_enet_private *fep) +{ + struct platform_device *pdev = to_platform_device(fep->dev); + struct resource *r; + + /* Fill out IRQ field */ + fep->interrupt = platform_get_irq(pdev, 0); + + /* Attach the memory for the FCC Parameter RAM */ + r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fcc_pram"); + fep->fcc.ep = (void *)r->start; + + if (fep->fcc.ep == NULL) + return -EINVAL; + + r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fcc_regs"); + fep->fcc.fccp = (void *)r->start; + + if (fep->fcc.fccp == NULL) + return -EINVAL; + + fep->fcc.fcccp = (void *)fep->fpi->fcc_regs_c; + + if (fep->fcc.fcccp == NULL) + return -EINVAL; + + return 0; +} + +#define FCC_NAPI_RX_EVENT_MSK (FCC_ENET_RXF | FCC_ENET_RXB) +#define FCC_RX_EVENT (FCC_ENET_RXF) +#define FCC_TX_EVENT (FCC_ENET_TXB) +#define FCC_ERR_EVENT_MSK (FCC_ENET_TXE | FCC_ENET_BSY) + +static int setup_data(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + const struct fs_platform_info *fpi = fep->fpi; + + fep->fcc.idx = fs_get_fcc_index(fpi->fs_no); + if ((unsigned int)fep->fcc.idx >= 3) /* max 3 FCCs */ + return -EINVAL; + + fep->fcc.mem = (void *)fpi->mem_offset; + + if (do_pd_setup(fep) != 0) + return -EINVAL; + + fep->ev_napi_rx = FCC_NAPI_RX_EVENT_MSK; + fep->ev_rx = FCC_RX_EVENT; + fep->ev_tx = FCC_TX_EVENT; + fep->ev_err = FCC_ERR_EVENT_MSK; + + return 0; +} + +static int allocate_bd(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + const struct fs_platform_info *fpi = fep->fpi; + + fep->ring_base = dma_alloc_coherent(fep->dev, + (fpi->tx_ring + fpi->rx_ring) * + sizeof(cbd_t), &fep->ring_mem_addr, + GFP_KERNEL); + if (fep->ring_base == NULL) + return -ENOMEM; + + return 0; +} + +static void free_bd(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + const struct fs_platform_info *fpi = fep->fpi; + + if (fep->ring_base) + dma_free_coherent(fep->dev, + (fpi->tx_ring + fpi->rx_ring) * sizeof(cbd_t), + fep->ring_base, fep->ring_mem_addr); +} + +static void cleanup_data(struct net_device *dev) +{ + /* nothing */ +} + +static void set_promiscuous_mode(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + fcc_t *fccp = fep->fcc.fccp; + + S32(fccp, fcc_fpsmr, FCC_PSMR_PRO); +} + +static void set_multicast_start(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + fcc_enet_t *ep = fep->fcc.ep; + + W32(ep, fen_gaddrh, 0); + W32(ep, fen_gaddrl, 0); +} + +static void set_multicast_one(struct net_device *dev, const u8 *mac) +{ + struct fs_enet_private *fep = netdev_priv(dev); + fcc_enet_t *ep = fep->fcc.ep; + u16 taddrh, taddrm, taddrl; + + taddrh = ((u16)mac[5] << 8) | mac[4]; + taddrm = ((u16)mac[3] << 8) | mac[2]; + taddrl = ((u16)mac[1] << 8) | mac[0]; + + W16(ep, fen_taddrh, taddrh); + W16(ep, fen_taddrm, taddrm); + W16(ep, fen_taddrl, taddrl); + fcc_cr_cmd(fep, 0x0C, CPM_CR_SET_GADDR); +} + +static void set_multicast_finish(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + fcc_t *fccp = fep->fcc.fccp; + fcc_enet_t *ep = fep->fcc.ep; + + /* clear promiscuous always */ + C32(fccp, fcc_fpsmr, FCC_PSMR_PRO); + + /* if all multi or too many multicasts; just enable all */ + if ((dev->flags & IFF_ALLMULTI) != 0 || + dev->mc_count > FCC_MAX_MULTICAST_ADDRS) { + + W32(ep, fen_gaddrh, 0xffffffff); + W32(ep, fen_gaddrl, 0xffffffff); + } + + /* read back */ + fep->fcc.gaddrh = R32(ep, fen_gaddrh); + fep->fcc.gaddrl = R32(ep, fen_gaddrl); +} + +static void set_multicast_list(struct net_device *dev) +{ + struct dev_mc_list *pmc; + + if ((dev->flags & IFF_PROMISC) == 0) { + set_multicast_start(dev); + for (pmc = dev->mc_list; pmc != NULL; pmc = pmc->next) + set_multicast_one(dev, pmc->dmi_addr); + set_multicast_finish(dev); + } else + set_promiscuous_mode(dev); +} + +static void restart(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + const struct fs_platform_info *fpi = fep->fpi; + fcc_t *fccp = fep->fcc.fccp; + fcc_c_t *fcccp = fep->fcc.fcccp; + fcc_enet_t *ep = fep->fcc.ep; + dma_addr_t rx_bd_base_phys, tx_bd_base_phys; + u16 paddrh, paddrm, paddrl; + u16 mem_addr; + const unsigned char *mac; + int i; + + C32(fccp, fcc_gfmr, FCC_GFMR_ENR | FCC_GFMR_ENT); + + /* clear everything (slow & steady does it) */ + for (i = 0; i < sizeof(*ep); i++) + __fcc_out8((char *)ep + i, 0); + + /* get physical address */ + rx_bd_base_phys = fep->ring_mem_addr; + tx_bd_base_phys = rx_bd_base_phys + sizeof(cbd_t) * fpi->rx_ring; + + /* point to bds */ + W32(ep, fen_genfcc.fcc_rbase, rx_bd_base_phys); + W32(ep, fen_genfcc.fcc_tbase, tx_bd_base_phys); + + /* Set maximum bytes per receive buffer. + * It must be a multiple of 32. + */ + W16(ep, fen_genfcc.fcc_mrblr, PKT_MAXBLR_SIZE); + + W32(ep, fen_genfcc.fcc_rstate, (CPMFCR_GBL | CPMFCR_EB) << 24); + W32(ep, fen_genfcc.fcc_tstate, (CPMFCR_GBL | CPMFCR_EB) << 24); + + /* Allocate space in the reserved FCC area of DPRAM for the + * internal buffers. No one uses this space (yet), so we + * can do this. Later, we will add resource management for + * this area. + */ + + mem_addr = (u32) fep->fcc.mem; /* de-fixup dpram offset */ + + W16(ep, fen_genfcc.fcc_riptr, (mem_addr & 0xffff)); + W16(ep, fen_genfcc.fcc_tiptr, ((mem_addr + 32) & 0xffff)); + W16(ep, fen_padptr, mem_addr + 64); + + /* fill with special symbol... */ + memset(fep->fcc.mem + fpi->dpram_offset + 64, 0x88, 32); + + W32(ep, fen_genfcc.fcc_rbptr, 0); + W32(ep, fen_genfcc.fcc_tbptr, 0); + W32(ep, fen_genfcc.fcc_rcrc, 0); + W32(ep, fen_genfcc.fcc_tcrc, 0); + W16(ep, fen_genfcc.fcc_res1, 0); + W32(ep, fen_genfcc.fcc_res2, 0); + + /* no CAM */ + W32(ep, fen_camptr, 0); + + /* Set CRC preset and mask */ + W32(ep, fen_cmask, 0xdebb20e3); + W32(ep, fen_cpres, 0xffffffff); + + W32(ep, fen_crcec, 0); /* CRC Error counter */ + W32(ep, fen_alec, 0); /* alignment error counter */ + W32(ep, fen_disfc, 0); /* discard frame counter */ + W16(ep, fen_retlim, 15); /* Retry limit threshold */ + W16(ep, fen_pper, 0); /* Normal persistence */ + + /* set group address */ + W32(ep, fen_gaddrh, fep->fcc.gaddrh); + W32(ep, fen_gaddrl, fep->fcc.gaddrh); + + /* Clear hash filter tables */ + W32(ep, fen_iaddrh, 0); + W32(ep, fen_iaddrl, 0); + + /* Clear the Out-of-sequence TxBD */ + W16(ep, fen_tfcstat, 0); + W16(ep, fen_tfclen, 0); + W32(ep, fen_tfcptr, 0); + + W16(ep, fen_mflr, PKT_MAXBUF_SIZE); /* maximum frame length register */ + W16(ep, fen_minflr, PKT_MINBUF_SIZE); /* minimum frame length register */ + + /* set address */ + mac = dev->dev_addr; + paddrh = ((u16)mac[5] << 8) | mac[4]; + paddrm = ((u16)mac[3] << 8) | mac[2]; + paddrl = ((u16)mac[1] << 8) | mac[0]; + + W16(ep, fen_paddrh, paddrh); + W16(ep, fen_paddrm, paddrm); + W16(ep, fen_paddrl, paddrl); + + W16(ep, fen_taddrh, 0); + W16(ep, fen_taddrm, 0); + W16(ep, fen_taddrl, 0); + + W16(ep, fen_maxd1, 1520); /* maximum DMA1 length */ + W16(ep, fen_maxd2, 1520); /* maximum DMA2 length */ + + /* Clear stat counters, in case we ever enable RMON */ + W32(ep, fen_octc, 0); + W32(ep, fen_colc, 0); + W32(ep, fen_broc, 0); + W32(ep, fen_mulc, 0); + W32(ep, fen_uspc, 0); + W32(ep, fen_frgc, 0); + W32(ep, fen_ospc, 0); + W32(ep, fen_jbrc, 0); + W32(ep, fen_p64c, 0); + W32(ep, fen_p65c, 0); + W32(ep, fen_p128c, 0); + W32(ep, fen_p256c, 0); + W32(ep, fen_p512c, 0); + W32(ep, fen_p1024c, 0); + + W16(ep, fen_rfthr, 0); /* Suggested by manual */ + W16(ep, fen_rfcnt, 0); + W16(ep, fen_cftype, 0); + + fs_init_bds(dev); + + /* adjust to speed (for RMII mode) */ + if (fpi->use_rmii) { + if (fep->speed == 100) + C8(fcccp, fcc_gfemr, 0x20); + else + S8(fcccp, fcc_gfemr, 0x20); + } + + fcc_cr_cmd(fep, 0x0c, CPM_CR_INIT_TRX); + + /* clear events */ + W16(fccp, fcc_fcce, 0xffff); + + /* Enable interrupts we wish to service */ + W16(fccp, fcc_fccm, FCC_ENET_TXE | FCC_ENET_RXF | FCC_ENET_TXB); + + /* Set GFMR to enable Ethernet operating mode */ + W32(fccp, fcc_gfmr, FCC_GFMR_TCI | FCC_GFMR_MODE_ENET); + + /* set sync/delimiters */ + W16(fccp, fcc_fdsr, 0xd555); + + W32(fccp, fcc_fpsmr, FCC_PSMR_ENCRC); + + if (fpi->use_rmii) + S32(fccp, fcc_fpsmr, FCC_PSMR_RMII); + + /* adjust to duplex mode */ + if (fep->duplex) + S32(fccp, fcc_fpsmr, FCC_PSMR_FDE | FCC_PSMR_LPB); + else + C32(fccp, fcc_fpsmr, FCC_PSMR_FDE | FCC_PSMR_LPB); + + S32(fccp, fcc_gfmr, FCC_GFMR_ENR | FCC_GFMR_ENT); +} + +static void stop(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + fcc_t *fccp = fep->fcc.fccp; + + /* stop ethernet */ + C32(fccp, fcc_gfmr, FCC_GFMR_ENR | FCC_GFMR_ENT); + + /* clear events */ + W16(fccp, fcc_fcce, 0xffff); + + /* clear interrupt mask */ + W16(fccp, fcc_fccm, 0); + + fs_cleanup_bds(dev); +} + +static void pre_request_irq(struct net_device *dev, int irq) +{ + /* nothing */ +} + +static void post_free_irq(struct net_device *dev, int irq) +{ + /* nothing */ +} + +static void napi_clear_rx_event(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + fcc_t *fccp = fep->fcc.fccp; + + W16(fccp, fcc_fcce, FCC_NAPI_RX_EVENT_MSK); +} + +static void napi_enable_rx(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + fcc_t *fccp = fep->fcc.fccp; + + S16(fccp, fcc_fccm, FCC_NAPI_RX_EVENT_MSK); +} + +static void napi_disable_rx(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + fcc_t *fccp = fep->fcc.fccp; + + C16(fccp, fcc_fccm, FCC_NAPI_RX_EVENT_MSK); +} + +static void rx_bd_done(struct net_device *dev) +{ + /* nothing */ +} + +static void tx_kickstart(struct net_device *dev) +{ + /* nothing */ +} + +static u32 get_int_events(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + fcc_t *fccp = fep->fcc.fccp; + + return (u32)R16(fccp, fcc_fcce); +} + +static void clear_int_events(struct net_device *dev, u32 int_events) +{ + struct fs_enet_private *fep = netdev_priv(dev); + fcc_t *fccp = fep->fcc.fccp; + + W16(fccp, fcc_fcce, int_events & 0xffff); +} + +static void ev_error(struct net_device *dev, u32 int_events) +{ + printk(KERN_WARNING DRV_MODULE_NAME + ": %s FS_ENET ERROR(s) 0x%x\n", dev->name, int_events); +} + +int get_regs(struct net_device *dev, void *p, int *sizep) +{ + struct fs_enet_private *fep = netdev_priv(dev); + + if (*sizep < sizeof(fcc_t) + sizeof(fcc_c_t) + sizeof(fcc_enet_t)) + return -EINVAL; + + memcpy_fromio(p, fep->fcc.fccp, sizeof(fcc_t)); + p = (char *)p + sizeof(fcc_t); + + memcpy_fromio(p, fep->fcc.fcccp, sizeof(fcc_c_t)); + p = (char *)p + sizeof(fcc_c_t); + + memcpy_fromio(p, fep->fcc.ep, sizeof(fcc_enet_t)); + + return 0; +} + +int get_regs_len(struct net_device *dev) +{ + return sizeof(fcc_t) + sizeof(fcc_c_t) + sizeof(fcc_enet_t); +} + +/* Some transmit errors cause the transmitter to shut + * down. We now issue a restart transmit. Since the + * errors close the BD and update the pointers, the restart + * _should_ pick up without having to reset any of our + * pointers either. Also, To workaround 8260 device erratum + * CPM37, we must disable and then re-enable the transmitter + * following a Late Collision, Underrun, or Retry Limit error. + */ +void tx_restart(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + fcc_t *fccp = fep->fcc.fccp; + + C32(fccp, fcc_gfmr, FCC_GFMR_ENT); + udelay(10); + S32(fccp, fcc_gfmr, FCC_GFMR_ENT); + + fcc_cr_cmd(fep, 0x0C, CPM_CR_RESTART_TX); +} + +/*************************************************************************/ + +const struct fs_ops fs_fcc_ops = { + .setup_data = setup_data, + .cleanup_data = cleanup_data, + .set_multicast_list = set_multicast_list, + .restart = restart, + .stop = stop, + .pre_request_irq = pre_request_irq, + .post_free_irq = post_free_irq, + .napi_clear_rx_event = napi_clear_rx_event, + .napi_enable_rx = napi_enable_rx, + .napi_disable_rx = napi_disable_rx, + .rx_bd_done = rx_bd_done, + .tx_kickstart = tx_kickstart, + .get_int_events = get_int_events, + .clear_int_events = clear_int_events, + .ev_error = ev_error, + .get_regs = get_regs, + .get_regs_len = get_regs_len, + .tx_restart = tx_restart, + .allocate_bd = allocate_bd, + .free_bd = free_bd, +}; diff --git a/drivers/net/fs_enet/mac-fec.c b/drivers/net/fs_enet/mac-fec.c new file mode 100644 index 000000000000..5ef4e845a387 --- /dev/null +++ b/drivers/net/fs_enet/mac-fec.c @@ -0,0 +1,653 @@ +/* + * Freescale Ethernet controllers + * + * Copyright (c) 2005 Intracom S.A. + * by Pantelis Antoniou <panto@intracom.gr> + * + * 2005 (c) MontaVista Software, Inc. + * Vitaly Bordug <vbordug@ru.mvista.com> + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/sched.h> +#include <linux/string.h> +#include <linux/ptrace.h> +#include <linux/errno.h> +#include <linux/ioport.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/spinlock.h> +#include <linux/mii.h> +#include <linux/ethtool.h> +#include <linux/bitops.h> +#include <linux/fs.h> + +#include <asm/irq.h> +#include <asm/uaccess.h> + +#ifdef CONFIG_8xx +#include <asm/8xx_immap.h> +#include <asm/pgtable.h> +#include <asm/mpc8xx.h> +#include <asm/commproc.h> +#endif + +#include "fs_enet.h" + +/*************************************************/ + +#if defined(CONFIG_CPM1) +/* for a CPM1 __raw_xxx's are sufficient */ +#define __fs_out32(addr, x) __raw_writel(x, addr) +#define __fs_out16(addr, x) __raw_writew(x, addr) +#define __fs_in32(addr) __raw_readl(addr) +#define __fs_in16(addr) __raw_readw(addr) +#else +/* for others play it safe */ +#define __fs_out32(addr, x) out_be32(addr, x) +#define __fs_out16(addr, x) out_be16(addr, x) +#define __fs_in32(addr) in_be32(addr) +#define __fs_in16(addr) in_be16(addr) +#endif + +/* write */ +#define FW(_fecp, _reg, _v) __fs_out32(&(_fecp)->fec_ ## _reg, (_v)) + +/* read */ +#define FR(_fecp, _reg) __fs_in32(&(_fecp)->fec_ ## _reg) + +/* set bits */ +#define FS(_fecp, _reg, _v) FW(_fecp, _reg, FR(_fecp, _reg) | (_v)) + +/* clear bits */ +#define FC(_fecp, _reg, _v) FW(_fecp, _reg, FR(_fecp, _reg) & ~(_v)) + + +/* CRC polynomium used by the FEC for the multicast group filtering */ +#define FEC_CRC_POLY 0x04C11DB7 + +#define FEC_MAX_MULTICAST_ADDRS 64 + +/* Interrupt events/masks. +*/ +#define FEC_ENET_HBERR 0x80000000U /* Heartbeat error */ +#define FEC_ENET_BABR 0x40000000U /* Babbling receiver */ +#define FEC_ENET_BABT 0x20000000U /* Babbling transmitter */ +#define FEC_ENET_GRA 0x10000000U /* Graceful stop complete */ +#define FEC_ENET_TXF 0x08000000U /* Full frame transmitted */ +#define FEC_ENET_TXB 0x04000000U /* A buffer was transmitted */ +#define FEC_ENET_RXF 0x02000000U /* Full frame received */ +#define FEC_ENET_RXB 0x01000000U /* A buffer was received */ +#define FEC_ENET_MII 0x00800000U /* MII interrupt */ +#define FEC_ENET_EBERR 0x00400000U /* SDMA bus error */ + +#define FEC_ECNTRL_PINMUX 0x00000004 +#define FEC_ECNTRL_ETHER_EN 0x00000002 +#define FEC_ECNTRL_RESET 0x00000001 + +#define FEC_RCNTRL_BC_REJ 0x00000010 +#define FEC_RCNTRL_PROM 0x00000008 +#define FEC_RCNTRL_MII_MODE 0x00000004 +#define FEC_RCNTRL_DRT 0x00000002 +#define FEC_RCNTRL_LOOP 0x00000001 + +#define FEC_TCNTRL_FDEN 0x00000004 +#define FEC_TCNTRL_HBC 0x00000002 +#define FEC_TCNTRL_GTS 0x00000001 + + +/* Make MII read/write commands for the FEC. +*/ +#define mk_mii_read(REG) (0x60020000 | ((REG & 0x1f) << 18)) +#define mk_mii_write(REG, VAL) (0x50020000 | ((REG & 0x1f) << 18) | (VAL & 0xffff)) +#define mk_mii_end 0 + +#define FEC_MII_LOOPS 10000 + +/* + * Delay to wait for FEC reset command to complete (in us) + */ +#define FEC_RESET_DELAY 50 + +static int whack_reset(fec_t * fecp) +{ + int i; + + FW(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_RESET); + for (i = 0; i < FEC_RESET_DELAY; i++) { + if ((FR(fecp, ecntrl) & FEC_ECNTRL_RESET) == 0) + return 0; /* OK */ + udelay(1); + } + + return -1; +} + +static int do_pd_setup(struct fs_enet_private *fep) +{ + struct platform_device *pdev = to_platform_device(fep->dev); + struct resource *r; + + /* Fill out IRQ field */ + fep->interrupt = platform_get_irq_byname(pdev,"interrupt"); + + r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs"); + fep->fec.fecp =(void*)r->start; + + if(fep->fec.fecp == NULL) + return -EINVAL; + + return 0; + +} + +#define FEC_NAPI_RX_EVENT_MSK (FEC_ENET_RXF | FEC_ENET_RXB) +#define FEC_RX_EVENT (FEC_ENET_RXF) +#define FEC_TX_EVENT (FEC_ENET_TXF) +#define FEC_ERR_EVENT_MSK (FEC_ENET_HBERR | FEC_ENET_BABR | \ + FEC_ENET_BABT | FEC_ENET_EBERR) + +static int setup_data(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + + if (do_pd_setup(fep) != 0) + return -EINVAL; + + fep->fec.hthi = 0; + fep->fec.htlo = 0; + + fep->ev_napi_rx = FEC_NAPI_RX_EVENT_MSK; + fep->ev_rx = FEC_RX_EVENT; + fep->ev_tx = FEC_TX_EVENT; + fep->ev_err = FEC_ERR_EVENT_MSK; + + return 0; +} + +static int allocate_bd(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + const struct fs_platform_info *fpi = fep->fpi; + + fep->ring_base = dma_alloc_coherent(fep->dev, + (fpi->tx_ring + fpi->rx_ring) * + sizeof(cbd_t), &fep->ring_mem_addr, + GFP_KERNEL); + if (fep->ring_base == NULL) + return -ENOMEM; + + return 0; +} + +static void free_bd(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + const struct fs_platform_info *fpi = fep->fpi; + + if(fep->ring_base) + dma_free_coherent(fep->dev, (fpi->tx_ring + fpi->rx_ring) + * sizeof(cbd_t), + fep->ring_base, + fep->ring_mem_addr); +} + +static void cleanup_data(struct net_device *dev) +{ + /* nothing */ +} + +static void set_promiscuous_mode(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + fec_t *fecp = fep->fec.fecp; + + FS(fecp, r_cntrl, FEC_RCNTRL_PROM); +} + +static void set_multicast_start(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + + fep->fec.hthi = 0; + fep->fec.htlo = 0; +} + +static void set_multicast_one(struct net_device *dev, const u8 *mac) +{ + struct fs_enet_private *fep = netdev_priv(dev); + int temp, hash_index, i, j; + u32 crc, csrVal; + u8 byte, msb; + + crc = 0xffffffff; + for (i = 0; i < 6; i++) { + byte = mac[i]; + for (j = 0; j < 8; j++) { + msb = crc >> 31; + crc <<= 1; + if (msb ^ (byte & 0x1)) + crc ^= FEC_CRC_POLY; + byte >>= 1; + } + } + + temp = (crc & 0x3f) >> 1; + hash_index = ((temp & 0x01) << 4) | + ((temp & 0x02) << 2) | + ((temp & 0x04)) | + ((temp & 0x08) >> 2) | + ((temp & 0x10) >> 4); + csrVal = 1 << hash_index; + if (crc & 1) + fep->fec.hthi |= csrVal; + else + fep->fec.htlo |= csrVal; +} + +static void set_multicast_finish(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + fec_t *fecp = fep->fec.fecp; + + /* if all multi or too many multicasts; just enable all */ + if ((dev->flags & IFF_ALLMULTI) != 0 || + dev->mc_count > FEC_MAX_MULTICAST_ADDRS) { + fep->fec.hthi = 0xffffffffU; + fep->fec.htlo = 0xffffffffU; + } + + FC(fecp, r_cntrl, FEC_RCNTRL_PROM); + FW(fecp, hash_table_high, fep->fec.hthi); + FW(fecp, hash_table_low, fep->fec.htlo); +} + +static void set_multicast_list(struct net_device *dev) +{ + struct dev_mc_list *pmc; + + if ((dev->flags & IFF_PROMISC) == 0) { + set_multicast_start(dev); + for (pmc = dev->mc_list; pmc != NULL; pmc = pmc->next) + set_multicast_one(dev, pmc->dmi_addr); + set_multicast_finish(dev); + } else + set_promiscuous_mode(dev); +} + +static void restart(struct net_device *dev) +{ +#ifdef CONFIG_DUET + immap_t *immap = fs_enet_immap; + u32 cptr; +#endif + struct fs_enet_private *fep = netdev_priv(dev); + fec_t *fecp = fep->fec.fecp; + const struct fs_platform_info *fpi = fep->fpi; + dma_addr_t rx_bd_base_phys, tx_bd_base_phys; + int r; + u32 addrhi, addrlo; + + r = whack_reset(fep->fec.fecp); + if (r != 0) + printk(KERN_ERR DRV_MODULE_NAME + ": %s FEC Reset FAILED!\n", dev->name); + + /* + * Set station address. + */ + addrhi = ((u32) dev->dev_addr[0] << 24) | + ((u32) dev->dev_addr[1] << 16) | + ((u32) dev->dev_addr[2] << 8) | + (u32) dev->dev_addr[3]; + addrlo = ((u32) dev->dev_addr[4] << 24) | + ((u32) dev->dev_addr[5] << 16); + FW(fecp, addr_low, addrhi); + FW(fecp, addr_high, addrlo); + + /* + * Reset all multicast. + */ + FW(fecp, hash_table_high, fep->fec.hthi); + FW(fecp, hash_table_low, fep->fec.htlo); + + /* + * Set maximum receive buffer size. + */ + FW(fecp, r_buff_size, PKT_MAXBLR_SIZE); + FW(fecp, r_hash, PKT_MAXBUF_SIZE); + + /* get physical address */ + rx_bd_base_phys = fep->ring_mem_addr; + tx_bd_base_phys = rx_bd_base_phys + sizeof(cbd_t) * fpi->rx_ring; + + /* + * Set receive and transmit descriptor base. + */ + FW(fecp, r_des_start, rx_bd_base_phys); + FW(fecp, x_des_start, tx_bd_base_phys); + + fs_init_bds(dev); + + /* + * Enable big endian and don't care about SDMA FC. + */ + FW(fecp, fun_code, 0x78000000); + + /* + * Set MII speed. + */ + FW(fecp, mii_speed, fep->mii_bus->fec.mii_speed); + + /* + * Clear any outstanding interrupt. + */ + FW(fecp, ievent, 0xffc0); + FW(fecp, ivec, (fep->interrupt / 2) << 29); + + + /* + * adjust to speed (only for DUET & RMII) + */ +#ifdef CONFIG_DUET + if (fpi->use_rmii) { + cptr = in_be32(&immap->im_cpm.cp_cptr); + switch (fs_get_fec_index(fpi->fs_no)) { + case 0: + cptr |= 0x100; + if (fep->speed == 10) + cptr |= 0x0000010; + else if (fep->speed == 100) + cptr &= ~0x0000010; + break; + case 1: + cptr |= 0x80; + if (fep->speed == 10) + cptr |= 0x0000008; + else if (fep->speed == 100) + cptr &= ~0x0000008; + break; + default: + BUG(); /* should never happen */ + break; + } + out_be32(&immap->im_cpm.cp_cptr, cptr); + } +#endif + + FW(fecp, r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */ + /* + * adjust to duplex mode + */ + if (fep->duplex) { + FC(fecp, r_cntrl, FEC_RCNTRL_DRT); + FS(fecp, x_cntrl, FEC_TCNTRL_FDEN); /* FD enable */ + } else { + FS(fecp, r_cntrl, FEC_RCNTRL_DRT); + FC(fecp, x_cntrl, FEC_TCNTRL_FDEN); /* FD disable */ + } + + /* + * Enable interrupts we wish to service. + */ + FW(fecp, imask, FEC_ENET_TXF | FEC_ENET_TXB | + FEC_ENET_RXF | FEC_ENET_RXB); + + /* + * And last, enable the transmit and receive processing. + */ + FW(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN); + FW(fecp, r_des_active, 0x01000000); +} + +static void stop(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + fec_t *fecp = fep->fec.fecp; + struct fs_enet_mii_bus *bus = fep->mii_bus; + const struct fs_mii_bus_info *bi = bus->bus_info; + int i; + + if ((FR(fecp, ecntrl) & FEC_ECNTRL_ETHER_EN) == 0) + return; /* already down */ + + FW(fecp, x_cntrl, 0x01); /* Graceful transmit stop */ + for (i = 0; ((FR(fecp, ievent) & 0x10000000) == 0) && + i < FEC_RESET_DELAY; i++) + udelay(1); + + if (i == FEC_RESET_DELAY) + printk(KERN_WARNING DRV_MODULE_NAME + ": %s FEC timeout on graceful transmit stop\n", + dev->name); + /* + * Disable FEC. Let only MII interrupts. + */ + FW(fecp, imask, 0); + FC(fecp, ecntrl, FEC_ECNTRL_ETHER_EN); + + fs_cleanup_bds(dev); + + /* shut down FEC1? that's where the mii bus is */ + if (fep->fec.idx == 0 && bus->refs > 1 && bi->method == fsmii_fec) { + FS(fecp, r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */ + FS(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN); + FW(fecp, ievent, FEC_ENET_MII); + FW(fecp, mii_speed, bus->fec.mii_speed); + } +} + +static void pre_request_irq(struct net_device *dev, int irq) +{ + immap_t *immap = fs_enet_immap; + u32 siel; + + /* SIU interrupt */ + if (irq >= SIU_IRQ0 && irq < SIU_LEVEL7) { + + siel = in_be32(&immap->im_siu_conf.sc_siel); + if ((irq & 1) == 0) + siel |= (0x80000000 >> irq); + else + siel &= ~(0x80000000 >> (irq & ~1)); + out_be32(&immap->im_siu_conf.sc_siel, siel); + } +} + +static void post_free_irq(struct net_device *dev, int irq) +{ + /* nothing */ +} + +static void napi_clear_rx_event(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + fec_t *fecp = fep->fec.fecp; + + FW(fecp, ievent, FEC_NAPI_RX_EVENT_MSK); +} + +static void napi_enable_rx(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + fec_t *fecp = fep->fec.fecp; + + FS(fecp, imask, FEC_NAPI_RX_EVENT_MSK); +} + +static void napi_disable_rx(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + fec_t *fecp = fep->fec.fecp; + + FC(fecp, imask, FEC_NAPI_RX_EVENT_MSK); +} + +static void rx_bd_done(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + fec_t *fecp = fep->fec.fecp; + + FW(fecp, r_des_active, 0x01000000); +} + +static void tx_kickstart(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + fec_t *fecp = fep->fec.fecp; + + FW(fecp, x_des_active, 0x01000000); +} + +static u32 get_int_events(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + fec_t *fecp = fep->fec.fecp; + + return FR(fecp, ievent) & FR(fecp, imask); +} + +static void clear_int_events(struct net_device *dev, u32 int_events) +{ + struct fs_enet_private *fep = netdev_priv(dev); + fec_t *fecp = fep->fec.fecp; + + FW(fecp, ievent, int_events); +} + +static void ev_error(struct net_device *dev, u32 int_events) +{ + printk(KERN_WARNING DRV_MODULE_NAME + ": %s FEC ERROR(s) 0x%x\n", dev->name, int_events); +} + +int get_regs(struct net_device *dev, void *p, int *sizep) +{ + struct fs_enet_private *fep = netdev_priv(dev); + + if (*sizep < sizeof(fec_t)) + return -EINVAL; + + memcpy_fromio(p, fep->fec.fecp, sizeof(fec_t)); + + return 0; +} + +int get_regs_len(struct net_device *dev) +{ + return sizeof(fec_t); +} + +void tx_restart(struct net_device *dev) +{ + /* nothing */ +} + +/*************************************************************************/ + +const struct fs_ops fs_fec_ops = { + .setup_data = setup_data, + .cleanup_data = cleanup_data, + .set_multicast_list = set_multicast_list, + .restart = restart, + .stop = stop, + .pre_request_irq = pre_request_irq, + .post_free_irq = post_free_irq, + .napi_clear_rx_event = napi_clear_rx_event, + .napi_enable_rx = napi_enable_rx, + .napi_disable_rx = napi_disable_rx, + .rx_bd_done = rx_bd_done, + .tx_kickstart = tx_kickstart, + .get_int_events = get_int_events, + .clear_int_events = clear_int_events, + .ev_error = ev_error, + .get_regs = get_regs, + .get_regs_len = get_regs_len, + .tx_restart = tx_restart, + .allocate_bd = allocate_bd, + .free_bd = free_bd, +}; + +/***********************************************************************/ + +static int mii_read(struct fs_enet_mii_bus *bus, int phy_id, int location) +{ + fec_t *fecp = bus->fec.fecp; + int i, ret = -1; + + if ((FR(fecp, r_cntrl) & FEC_RCNTRL_MII_MODE) == 0) + BUG(); + + /* Add PHY address to register command. */ + FW(fecp, mii_data, (phy_id << 23) | mk_mii_read(location)); + + for (i = 0; i < FEC_MII_LOOPS; i++) + if ((FR(fecp, ievent) & FEC_ENET_MII) != 0) + break; + + if (i < FEC_MII_LOOPS) { + FW(fecp, ievent, FEC_ENET_MII); + ret = FR(fecp, mii_data) & 0xffff; + } + + return ret; +} + +static void mii_write(struct fs_enet_mii_bus *bus, int phy_id, int location, int value) +{ + fec_t *fecp = bus->fec.fecp; + int i; + + /* this must never happen */ + if ((FR(fecp, r_cntrl) & FEC_RCNTRL_MII_MODE) == 0) + BUG(); + + /* Add PHY address to register command. */ + FW(fecp, mii_data, (phy_id << 23) | mk_mii_write(location, value)); + + for (i = 0; i < FEC_MII_LOOPS; i++) + if ((FR(fecp, ievent) & FEC_ENET_MII) != 0) + break; + + if (i < FEC_MII_LOOPS) + FW(fecp, ievent, FEC_ENET_MII); +} + +int fs_mii_fec_init(struct fs_enet_mii_bus *bus) +{ + bd_t *bd = (bd_t *)__res; + const struct fs_mii_bus_info *bi = bus->bus_info; + fec_t *fecp; + + if (bi->id != 0) + return -1; + + bus->fec.fecp = &((immap_t *)fs_enet_immap)->im_cpm.cp_fec; + bus->fec.mii_speed = ((((bd->bi_intfreq + 4999999) / 2500000) / 2) + & 0x3F) << 1; + + fecp = bus->fec.fecp; + + FS(fecp, r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */ + FS(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN); + FW(fecp, ievent, FEC_ENET_MII); + FW(fecp, mii_speed, bus->fec.mii_speed); + + bus->mii_read = mii_read; + bus->mii_write = mii_write; + + return 0; +} diff --git a/drivers/net/fs_enet/mac-scc.c b/drivers/net/fs_enet/mac-scc.c new file mode 100644 index 000000000000..d8c6e9cadcf5 --- /dev/null +++ b/drivers/net/fs_enet/mac-scc.c @@ -0,0 +1,524 @@ +/* + * Ethernet on Serial Communications Controller (SCC) driver for Motorola MPC8xx and MPC82xx. + * + * Copyright (c) 2003 Intracom S.A. + * by Pantelis Antoniou <panto@intracom.gr> + * + * 2005 (c) MontaVista Software, Inc. + * Vitaly Bordug <vbordug@ru.mvista.com> + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/sched.h> +#include <linux/string.h> +#include <linux/ptrace.h> +#include <linux/errno.h> +#include <linux/ioport.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/spinlock.h> +#include <linux/mii.h> +#include <linux/ethtool.h> +#include <linux/bitops.h> +#include <linux/fs.h> + +#include <asm/irq.h> +#include <asm/uaccess.h> + +#ifdef CONFIG_8xx +#include <asm/8xx_immap.h> +#include <asm/pgtable.h> +#include <asm/mpc8xx.h> +#include <asm/commproc.h> +#endif + +#include "fs_enet.h" + +/*************************************************/ + +#if defined(CONFIG_CPM1) +/* for a 8xx __raw_xxx's are sufficient */ +#define __fs_out32(addr, x) __raw_writel(x, addr) +#define __fs_out16(addr, x) __raw_writew(x, addr) +#define __fs_out8(addr, x) __raw_writeb(x, addr) +#define __fs_in32(addr) __raw_readl(addr) +#define __fs_in16(addr) __raw_readw(addr) +#define __fs_in8(addr) __raw_readb(addr) +#else +/* for others play it safe */ +#define __fs_out32(addr, x) out_be32(addr, x) +#define __fs_out16(addr, x) out_be16(addr, x) +#define __fs_in32(addr) in_be32(addr) +#define __fs_in16(addr) in_be16(addr) +#endif + +/* write, read, set bits, clear bits */ +#define W32(_p, _m, _v) __fs_out32(&(_p)->_m, (_v)) +#define R32(_p, _m) __fs_in32(&(_p)->_m) +#define S32(_p, _m, _v) W32(_p, _m, R32(_p, _m) | (_v)) +#define C32(_p, _m, _v) W32(_p, _m, R32(_p, _m) & ~(_v)) + +#define W16(_p, _m, _v) __fs_out16(&(_p)->_m, (_v)) +#define R16(_p, _m) __fs_in16(&(_p)->_m) +#define S16(_p, _m, _v) W16(_p, _m, R16(_p, _m) | (_v)) +#define C16(_p, _m, _v) W16(_p, _m, R16(_p, _m) & ~(_v)) + +#define W8(_p, _m, _v) __fs_out8(&(_p)->_m, (_v)) +#define R8(_p, _m) __fs_in8(&(_p)->_m) +#define S8(_p, _m, _v) W8(_p, _m, R8(_p, _m) | (_v)) +#define C8(_p, _m, _v) W8(_p, _m, R8(_p, _m) & ~(_v)) + +#define SCC_MAX_MULTICAST_ADDRS 64 + +/* + * Delay to wait for SCC reset command to complete (in us) + */ +#define SCC_RESET_DELAY 50 +#define MAX_CR_CMD_LOOPS 10000 + +static inline int scc_cr_cmd(struct fs_enet_private *fep, u32 op) +{ + cpm8xx_t *cpmp = &((immap_t *)fs_enet_immap)->im_cpm; + u32 v, ch; + int i = 0; + + ch = fep->scc.idx << 2; + v = mk_cr_cmd(ch, op); + W16(cpmp, cp_cpcr, v | CPM_CR_FLG); + for (i = 0; i < MAX_CR_CMD_LOOPS; i++) + if ((R16(cpmp, cp_cpcr) & CPM_CR_FLG) == 0) + break; + + if (i >= MAX_CR_CMD_LOOPS) { + printk(KERN_ERR "%s(): Not able to issue CPM command\n", + __FUNCTION__); + return 1; + } + return 0; +} + +static int do_pd_setup(struct fs_enet_private *fep) +{ + struct platform_device *pdev = to_platform_device(fep->dev); + struct resource *r; + + /* Fill out IRQ field */ + fep->interrupt = platform_get_irq_byname(pdev, "interrupt"); + + r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs"); + fep->scc.sccp = (void *)r->start; + + if (fep->scc.sccp == NULL) + return -EINVAL; + + r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pram"); + fep->scc.ep = (void *)r->start; + + if (fep->scc.ep == NULL) + return -EINVAL; + + return 0; +} + +#define SCC_NAPI_RX_EVENT_MSK (SCCE_ENET_RXF | SCCE_ENET_RXB) +#define SCC_RX_EVENT (SCCE_ENET_RXF) +#define SCC_TX_EVENT (SCCE_ENET_TXB) +#define SCC_ERR_EVENT_MSK (SCCE_ENET_TXE | SCCE_ENET_BSY) + +static int setup_data(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + const struct fs_platform_info *fpi = fep->fpi; + + fep->scc.idx = fs_get_scc_index(fpi->fs_no); + if ((unsigned int)fep->fcc.idx > 4) /* max 4 SCCs */ + return -EINVAL; + + do_pd_setup(fep); + + fep->scc.hthi = 0; + fep->scc.htlo = 0; + + fep->ev_napi_rx = SCC_NAPI_RX_EVENT_MSK; + fep->ev_rx = SCC_RX_EVENT; + fep->ev_tx = SCC_TX_EVENT; + fep->ev_err = SCC_ERR_EVENT_MSK; + + return 0; +} + +static int allocate_bd(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + const struct fs_platform_info *fpi = fep->fpi; + + fep->ring_mem_addr = cpm_dpalloc((fpi->tx_ring + fpi->rx_ring) * + sizeof(cbd_t), 8); + if (IS_DPERR(fep->ring_mem_addr)) + return -ENOMEM; + + fep->ring_base = cpm_dpram_addr(fep->ring_mem_addr); + + return 0; +} + +static void free_bd(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + + if (fep->ring_base) + cpm_dpfree(fep->ring_mem_addr); +} + +static void cleanup_data(struct net_device *dev) +{ + /* nothing */ +} + +static void set_promiscuous_mode(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + scc_t *sccp = fep->scc.sccp; + + S16(sccp, scc_psmr, SCC_PSMR_PRO); +} + +static void set_multicast_start(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + scc_enet_t *ep = fep->scc.ep; + + W16(ep, sen_gaddr1, 0); + W16(ep, sen_gaddr2, 0); + W16(ep, sen_gaddr3, 0); + W16(ep, sen_gaddr4, 0); +} + +static void set_multicast_one(struct net_device *dev, const u8 * mac) +{ + struct fs_enet_private *fep = netdev_priv(dev); + scc_enet_t *ep = fep->scc.ep; + u16 taddrh, taddrm, taddrl; + + taddrh = ((u16) mac[5] << 8) | mac[4]; + taddrm = ((u16) mac[3] << 8) | mac[2]; + taddrl = ((u16) mac[1] << 8) | mac[0]; + + W16(ep, sen_taddrh, taddrh); + W16(ep, sen_taddrm, taddrm); + W16(ep, sen_taddrl, taddrl); + scc_cr_cmd(fep, CPM_CR_SET_GADDR); +} + +static void set_multicast_finish(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + scc_t *sccp = fep->scc.sccp; + scc_enet_t *ep = fep->scc.ep; + + /* clear promiscuous always */ + C16(sccp, scc_psmr, SCC_PSMR_PRO); + + /* if all multi or too many multicasts; just enable all */ + if ((dev->flags & IFF_ALLMULTI) != 0 || + dev->mc_count > SCC_MAX_MULTICAST_ADDRS) { + + W16(ep, sen_gaddr1, 0xffff); + W16(ep, sen_gaddr2, 0xffff); + W16(ep, sen_gaddr3, 0xffff); + W16(ep, sen_gaddr4, 0xffff); + } +} + +static void set_multicast_list(struct net_device *dev) +{ + struct dev_mc_list *pmc; + + if ((dev->flags & IFF_PROMISC) == 0) { + set_multicast_start(dev); + for (pmc = dev->mc_list; pmc != NULL; pmc = pmc->next) + set_multicast_one(dev, pmc->dmi_addr); + set_multicast_finish(dev); + } else + set_promiscuous_mode(dev); +} + +/* + * This function is called to start or restart the FEC during a link + * change. This only happens when switching between half and full + * duplex. + */ +static void restart(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + scc_t *sccp = fep->scc.sccp; + scc_enet_t *ep = fep->scc.ep; + const struct fs_platform_info *fpi = fep->fpi; + u16 paddrh, paddrm, paddrl; + const unsigned char *mac; + int i; + + C32(sccp, scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT); + + /* clear everything (slow & steady does it) */ + for (i = 0; i < sizeof(*ep); i++) + __fs_out8((char *)ep + i, 0); + + /* point to bds */ + W16(ep, sen_genscc.scc_rbase, fep->ring_mem_addr); + W16(ep, sen_genscc.scc_tbase, + fep->ring_mem_addr + sizeof(cbd_t) * fpi->rx_ring); + + /* Initialize function code registers for big-endian. + */ + W8(ep, sen_genscc.scc_rfcr, SCC_EB); + W8(ep, sen_genscc.scc_tfcr, SCC_EB); + + /* Set maximum bytes per receive buffer. + * This appears to be an Ethernet frame size, not the buffer + * fragment size. It must be a multiple of four. + */ + W16(ep, sen_genscc.scc_mrblr, 0x5f0); + + /* Set CRC preset and mask. + */ + W32(ep, sen_cpres, 0xffffffff); + W32(ep, sen_cmask, 0xdebb20e3); + + W32(ep, sen_crcec, 0); /* CRC Error counter */ + W32(ep, sen_alec, 0); /* alignment error counter */ + W32(ep, sen_disfc, 0); /* discard frame counter */ + + W16(ep, sen_pads, 0x8888); /* Tx short frame pad character */ + W16(ep, sen_retlim, 15); /* Retry limit threshold */ + + W16(ep, sen_maxflr, 0x5ee); /* maximum frame length register */ + + W16(ep, sen_minflr, PKT_MINBUF_SIZE); /* minimum frame length register */ + + W16(ep, sen_maxd1, 0x000005f0); /* maximum DMA1 length */ + W16(ep, sen_maxd2, 0x000005f0); /* maximum DMA2 length */ + + /* Clear hash tables. + */ + W16(ep, sen_gaddr1, 0); + W16(ep, sen_gaddr2, 0); + W16(ep, sen_gaddr3, 0); + W16(ep, sen_gaddr4, 0); + W16(ep, sen_iaddr1, 0); + W16(ep, sen_iaddr2, 0); + W16(ep, sen_iaddr3, 0); + W16(ep, sen_iaddr4, 0); + + /* set address + */ + mac = dev->dev_addr; + paddrh = ((u16) mac[5] << 8) | mac[4]; + paddrm = ((u16) mac[3] << 8) | mac[2]; + paddrl = ((u16) mac[1] << 8) | mac[0]; + + W16(ep, sen_paddrh, paddrh); + W16(ep, sen_paddrm, paddrm); + W16(ep, sen_paddrl, paddrl); + + W16(ep, sen_pper, 0); + W16(ep, sen_taddrl, 0); + W16(ep, sen_taddrm, 0); + W16(ep, sen_taddrh, 0); + + fs_init_bds(dev); + + scc_cr_cmd(fep, CPM_CR_INIT_TRX); + + W16(sccp, scc_scce, 0xffff); + + /* Enable interrupts we wish to service. + */ + W16(sccp, scc_sccm, SCCE_ENET_TXE | SCCE_ENET_RXF | SCCE_ENET_TXB); + + /* Set GSMR_H to enable all normal operating modes. + * Set GSMR_L to enable Ethernet to MC68160. + */ + W32(sccp, scc_gsmrh, 0); + W32(sccp, scc_gsmrl, + SCC_GSMRL_TCI | SCC_GSMRL_TPL_48 | SCC_GSMRL_TPP_10 | + SCC_GSMRL_MODE_ENET); + + /* Set sync/delimiters. + */ + W16(sccp, scc_dsr, 0xd555); + + /* Set processing mode. Use Ethernet CRC, catch broadcast, and + * start frame search 22 bit times after RENA. + */ + W16(sccp, scc_psmr, SCC_PSMR_ENCRC | SCC_PSMR_NIB22); + + /* Set full duplex mode if needed */ + if (fep->duplex) + S16(sccp, scc_psmr, SCC_PSMR_LPB | SCC_PSMR_FDE); + + S32(sccp, scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT); +} + +static void stop(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + scc_t *sccp = fep->scc.sccp; + int i; + + for (i = 0; (R16(sccp, scc_sccm) == 0) && i < SCC_RESET_DELAY; i++) + udelay(1); + + if (i == SCC_RESET_DELAY) + printk(KERN_WARNING DRV_MODULE_NAME + ": %s SCC timeout on graceful transmit stop\n", + dev->name); + + W16(sccp, scc_sccm, 0); + C32(sccp, scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT); + + fs_cleanup_bds(dev); +} + +static void pre_request_irq(struct net_device *dev, int irq) +{ + immap_t *immap = fs_enet_immap; + u32 siel; + + /* SIU interrupt */ + if (irq >= SIU_IRQ0 && irq < SIU_LEVEL7) { + + siel = in_be32(&immap->im_siu_conf.sc_siel); + if ((irq & 1) == 0) + siel |= (0x80000000 >> irq); + else + siel &= ~(0x80000000 >> (irq & ~1)); + out_be32(&immap->im_siu_conf.sc_siel, siel); + } +} + +static void post_free_irq(struct net_device *dev, int irq) +{ + /* nothing */ +} + +static void napi_clear_rx_event(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + scc_t *sccp = fep->scc.sccp; + + W16(sccp, scc_scce, SCC_NAPI_RX_EVENT_MSK); +} + +static void napi_enable_rx(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + scc_t *sccp = fep->scc.sccp; + + S16(sccp, scc_sccm, SCC_NAPI_RX_EVENT_MSK); +} + +static void napi_disable_rx(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + scc_t *sccp = fep->scc.sccp; + + C16(sccp, scc_sccm, SCC_NAPI_RX_EVENT_MSK); +} + +static void rx_bd_done(struct net_device *dev) +{ + /* nothing */ +} + +static void tx_kickstart(struct net_device *dev) +{ + /* nothing */ +} + +static u32 get_int_events(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + scc_t *sccp = fep->scc.sccp; + + return (u32) R16(sccp, scc_scce); +} + +static void clear_int_events(struct net_device *dev, u32 int_events) +{ + struct fs_enet_private *fep = netdev_priv(dev); + scc_t *sccp = fep->scc.sccp; + + W16(sccp, scc_scce, int_events & 0xffff); +} + +static void ev_error(struct net_device *dev, u32 int_events) +{ + printk(KERN_WARNING DRV_MODULE_NAME + ": %s SCC ERROR(s) 0x%x\n", dev->name, int_events); +} + +static int get_regs(struct net_device *dev, void *p, int *sizep) +{ + struct fs_enet_private *fep = netdev_priv(dev); + + if (*sizep < sizeof(scc_t) + sizeof(scc_enet_t)) + return -EINVAL; + + memcpy_fromio(p, fep->scc.sccp, sizeof(scc_t)); + p = (char *)p + sizeof(scc_t); + + memcpy_fromio(p, fep->scc.ep, sizeof(scc_enet_t)); + + return 0; +} + +static int get_regs_len(struct net_device *dev) +{ + return sizeof(scc_t) + sizeof(scc_enet_t); +} + +static void tx_restart(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + + scc_cr_cmd(fep, CPM_CR_RESTART_TX); +} + +/*************************************************************************/ + +const struct fs_ops fs_scc_ops = { + .setup_data = setup_data, + .cleanup_data = cleanup_data, + .set_multicast_list = set_multicast_list, + .restart = restart, + .stop = stop, + .pre_request_irq = pre_request_irq, + .post_free_irq = post_free_irq, + .napi_clear_rx_event = napi_clear_rx_event, + .napi_enable_rx = napi_enable_rx, + .napi_disable_rx = napi_disable_rx, + .rx_bd_done = rx_bd_done, + .tx_kickstart = tx_kickstart, + .get_int_events = get_int_events, + .clear_int_events = clear_int_events, + .ev_error = ev_error, + .get_regs = get_regs, + .get_regs_len = get_regs_len, + .tx_restart = tx_restart, + .allocate_bd = allocate_bd, + .free_bd = free_bd, +}; diff --git a/drivers/net/fs_enet/mii-bitbang.c b/drivers/net/fs_enet/mii-bitbang.c new file mode 100644 index 000000000000..24a5e2e23d18 --- /dev/null +++ b/drivers/net/fs_enet/mii-bitbang.c @@ -0,0 +1,405 @@ +/* + * Combined Ethernet driver for Motorola MPC8xx and MPC82xx. + * + * Copyright (c) 2003 Intracom S.A. + * by Pantelis Antoniou <panto@intracom.gr> + * + * 2005 (c) MontaVista Software, Inc. + * Vitaly Bordug <vbordug@ru.mvista.com> + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/string.h> +#include <linux/ptrace.h> +#include <linux/errno.h> +#include <linux/ioport.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/spinlock.h> +#include <linux/mii.h> +#include <linux/ethtool.h> +#include <linux/bitops.h> + +#include <asm/pgtable.h> +#include <asm/irq.h> +#include <asm/uaccess.h> + +#include "fs_enet.h" + +#ifdef CONFIG_8xx +static int bitbang_prep_bit(u8 **dirp, u8 **datp, u8 *mskp, int port, int bit) +{ + immap_t *im = (immap_t *)fs_enet_immap; + void *dir, *dat, *ppar; + int adv; + u8 msk; + + switch (port) { + case fsiop_porta: + dir = &im->im_ioport.iop_padir; + dat = &im->im_ioport.iop_padat; + ppar = &im->im_ioport.iop_papar; + break; + + case fsiop_portb: + dir = &im->im_cpm.cp_pbdir; + dat = &im->im_cpm.cp_pbdat; + ppar = &im->im_cpm.cp_pbpar; + break; + + case fsiop_portc: + dir = &im->im_ioport.iop_pcdir; + dat = &im->im_ioport.iop_pcdat; + ppar = &im->im_ioport.iop_pcpar; + break; + + case fsiop_portd: + dir = &im->im_ioport.iop_pddir; + dat = &im->im_ioport.iop_pddat; + ppar = &im->im_ioport.iop_pdpar; + break; + + case fsiop_porte: + dir = &im->im_cpm.cp_pedir; + dat = &im->im_cpm.cp_pedat; + ppar = &im->im_cpm.cp_pepar; + break; + + default: + printk(KERN_ERR DRV_MODULE_NAME + "Illegal port value %d!\n", port); + return -EINVAL; + } + + adv = bit >> 3; + dir = (char *)dir + adv; + dat = (char *)dat + adv; + ppar = (char *)ppar + adv; + + msk = 1 << (7 - (bit & 7)); + if ((in_8(ppar) & msk) != 0) { + printk(KERN_ERR DRV_MODULE_NAME + "pin %d on port %d is not general purpose!\n", bit, port); + return -EINVAL; + } + + *dirp = dir; + *datp = dat; + *mskp = msk; + + return 0; +} +#endif + +#ifdef CONFIG_8260 +static int bitbang_prep_bit(u8 **dirp, u8 **datp, u8 *mskp, int port, int bit) +{ + iop_cpm2_t *io = &((cpm2_map_t *)fs_enet_immap)->im_ioport; + void *dir, *dat, *ppar; + int adv; + u8 msk; + + switch (port) { + case fsiop_porta: + dir = &io->iop_pdira; + dat = &io->iop_pdata; + ppar = &io->iop_ppara; + break; + + case fsiop_portb: + dir = &io->iop_pdirb; + dat = &io->iop_pdatb; + ppar = &io->iop_pparb; + break; + + case fsiop_portc: + dir = &io->iop_pdirc; + dat = &io->iop_pdatc; + ppar = &io->iop_pparc; + break; + + case fsiop_portd: + dir = &io->iop_pdird; + dat = &io->iop_pdatd; + ppar = &io->iop_ppard; + break; + + default: + printk(KERN_ERR DRV_MODULE_NAME + "Illegal port value %d!\n", port); + return -EINVAL; + } + + adv = bit >> 3; + dir = (char *)dir + adv; + dat = (char *)dat + adv; + ppar = (char *)ppar + adv; + + msk = 1 << (7 - (bit & 7)); + if ((in_8(ppar) & msk) != 0) { + printk(KERN_ERR DRV_MODULE_NAME + "pin %d on port %d is not general purpose!\n", bit, port); + return -EINVAL; + } + + *dirp = dir; + *datp = dat; + *mskp = msk; + + return 0; +} +#endif + +static inline void bb_set(u8 *p, u8 m) +{ + out_8(p, in_8(p) | m); +} + +static inline void bb_clr(u8 *p, u8 m) +{ + out_8(p, in_8(p) & ~m); +} + +static inline int bb_read(u8 *p, u8 m) +{ + return (in_8(p) & m) != 0; +} + +static inline void mdio_active(struct fs_enet_mii_bus *bus) +{ + bb_set(bus->bitbang.mdio_dir, bus->bitbang.mdio_msk); +} + +static inline void mdio_tristate(struct fs_enet_mii_bus *bus) +{ + bb_clr(bus->bitbang.mdio_dir, bus->bitbang.mdio_msk); +} + +static inline int mdio_read(struct fs_enet_mii_bus *bus) +{ + return bb_read(bus->bitbang.mdio_dat, bus->bitbang.mdio_msk); +} + +static inline void mdio(struct fs_enet_mii_bus *bus, int what) +{ + if (what) + bb_set(bus->bitbang.mdio_dat, bus->bitbang.mdio_msk); + else + bb_clr(bus->bitbang.mdio_dat, bus->bitbang.mdio_msk); +} + +static inline void mdc(struct fs_enet_mii_bus *bus, int what) +{ + if (what) + bb_set(bus->bitbang.mdc_dat, bus->bitbang.mdc_msk); + else + bb_clr(bus->bitbang.mdc_dat, bus->bitbang.mdc_msk); +} + +static inline void mii_delay(struct fs_enet_mii_bus *bus) +{ + udelay(bus->bus_info->i.bitbang.delay); +} + +/* Utility to send the preamble, address, and register (common to read and write). */ +static void bitbang_pre(struct fs_enet_mii_bus *bus, int read, u8 addr, u8 reg) +{ + int j; + + /* + * Send a 32 bit preamble ('1's) with an extra '1' bit for good measure. + * The IEEE spec says this is a PHY optional requirement. The AMD + * 79C874 requires one after power up and one after a MII communications + * error. This means that we are doing more preambles than we need, + * but it is safer and will be much more robust. + */ + + mdio_active(bus); + mdio(bus, 1); + for (j = 0; j < 32; j++) { + mdc(bus, 0); + mii_delay(bus); + mdc(bus, 1); + mii_delay(bus); + } + + /* send the start bit (01) and the read opcode (10) or write (10) */ + mdc(bus, 0); + mdio(bus, 0); + mii_delay(bus); + mdc(bus, 1); + mii_delay(bus); + mdc(bus, 0); + mdio(bus, 1); + mii_delay(bus); + mdc(bus, 1); + mii_delay(bus); + mdc(bus, 0); + mdio(bus, read); + mii_delay(bus); + mdc(bus, 1); + mii_delay(bus); + mdc(bus, 0); + mdio(bus, !read); + mii_delay(bus); + mdc(bus, 1); + mii_delay(bus); + + /* send the PHY address */ + for (j = 0; j < 5; j++) { + mdc(bus, 0); + mdio(bus, (addr & 0x10) != 0); + mii_delay(bus); + mdc(bus, 1); + mii_delay(bus); + addr <<= 1; + } + + /* send the register address */ + for (j = 0; j < 5; j++) { + mdc(bus, 0); + mdio(bus, (reg & 0x10) != 0); + mii_delay(bus); + mdc(bus, 1); + mii_delay(bus); + reg <<= 1; + } +} + +static int mii_read(struct fs_enet_mii_bus *bus, int phy_id, int location) +{ + u16 rdreg; + int ret, j; + u8 addr = phy_id & 0xff; + u8 reg = location & 0xff; + + bitbang_pre(bus, 1, addr, reg); + + /* tri-state our MDIO I/O pin so we can read */ + mdc(bus, 0); + mdio_tristate(bus); + mii_delay(bus); + mdc(bus, 1); + mii_delay(bus); + + /* check the turnaround bit: the PHY should be driving it to zero */ + if (mdio_read(bus) != 0) { + /* PHY didn't drive TA low */ + for (j = 0; j < 32; j++) { + mdc(bus, 0); + mii_delay(bus); + mdc(bus, 1); + mii_delay(bus); + } + ret = -1; + goto out; + } + + mdc(bus, 0); + mii_delay(bus); + + /* read 16 bits of register data, MSB first */ + rdreg = 0; + for (j = 0; j < 16; j++) { + mdc(bus, 1); + mii_delay(bus); + rdreg <<= 1; + rdreg |= mdio_read(bus); + mdc(bus, 0); + mii_delay(bus); + } + + mdc(bus, 1); + mii_delay(bus); + mdc(bus, 0); + mii_delay(bus); + mdc(bus, 1); + mii_delay(bus); + + ret = rdreg; +out: + return ret; +} + +static void mii_write(struct fs_enet_mii_bus *bus, int phy_id, int location, int val) +{ + int j; + u8 addr = phy_id & 0xff; + u8 reg = location & 0xff; + u16 value = val & 0xffff; + + bitbang_pre(bus, 0, addr, reg); + + /* send the turnaround (10) */ + mdc(bus, 0); + mdio(bus, 1); + mii_delay(bus); + mdc(bus, 1); + mii_delay(bus); + mdc(bus, 0); + mdio(bus, 0); + mii_delay(bus); + mdc(bus, 1); + mii_delay(bus); + + /* write 16 bits of register data, MSB first */ + for (j = 0; j < 16; j++) { + mdc(bus, 0); + mdio(bus, (value & 0x8000) != 0); + mii_delay(bus); + mdc(bus, 1); + mii_delay(bus); + value <<= 1; + } + + /* + * Tri-state the MDIO line. + */ + mdio_tristate(bus); + mdc(bus, 0); + mii_delay(bus); + mdc(bus, 1); + mii_delay(bus); +} + +int fs_mii_bitbang_init(struct fs_enet_mii_bus *bus) +{ + const struct fs_mii_bus_info *bi = bus->bus_info; + int r; + + r = bitbang_prep_bit(&bus->bitbang.mdio_dir, + &bus->bitbang.mdio_dat, + &bus->bitbang.mdio_msk, + bi->i.bitbang.mdio_port, + bi->i.bitbang.mdio_bit); + if (r != 0) + return r; + + r = bitbang_prep_bit(&bus->bitbang.mdc_dir, + &bus->bitbang.mdc_dat, + &bus->bitbang.mdc_msk, + bi->i.bitbang.mdc_port, + bi->i.bitbang.mdc_bit); + if (r != 0) + return r; + + bus->mii_read = mii_read; + bus->mii_write = mii_write; + + return 0; +} diff --git a/drivers/net/fs_enet/mii-fixed.c b/drivers/net/fs_enet/mii-fixed.c new file mode 100644 index 000000000000..b3e192d612e5 --- /dev/null +++ b/drivers/net/fs_enet/mii-fixed.c @@ -0,0 +1,92 @@ +/* + * Combined Ethernet driver for Motorola MPC8xx and MPC82xx. + * + * Copyright (c) 2003 Intracom S.A. + * by Pantelis Antoniou <panto@intracom.gr> + * + * 2005 (c) MontaVista Software, Inc. + * Vitaly Bordug <vbordug@ru.mvista.com> + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/string.h> +#include <linux/ptrace.h> +#include <linux/errno.h> +#include <linux/ioport.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/spinlock.h> +#include <linux/mii.h> +#include <linux/ethtool.h> +#include <linux/bitops.h> + +#include <asm/pgtable.h> +#include <asm/irq.h> +#include <asm/uaccess.h> + +#include "fs_enet.h" + +static const u16 mii_regs[7] = { + 0x3100, + 0x786d, + 0x0fff, + 0x0fff, + 0x01e1, + 0x45e1, + 0x0003, +}; + +static int mii_read(struct fs_enet_mii_bus *bus, int phy_id, int location) +{ + int ret = 0; + + if ((unsigned int)location >= ARRAY_SIZE(mii_regs)) + return -1; + + if (location != 5) + ret = mii_regs[location]; + else + ret = bus->fixed.lpa; + + return ret; +} + +static void mii_write(struct fs_enet_mii_bus *bus, int phy_id, int location, int val) +{ + /* do nothing */ +} + +int fs_mii_fixed_init(struct fs_enet_mii_bus *bus) +{ + const struct fs_mii_bus_info *bi = bus->bus_info; + + bus->fixed.lpa = 0x45e1; /* default 100Mb, full duplex */ + + /* if speed is fixed at 10Mb, remove 100Mb modes */ + if (bi->i.fixed.speed == 10) + bus->fixed.lpa &= ~LPA_100; + + /* if duplex is half, remove full duplex modes */ + if (bi->i.fixed.duplex == 0) + bus->fixed.lpa &= ~LPA_DUPLEX; + + bus->mii_read = mii_read; + bus->mii_write = mii_write; + + return 0; +} diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 6518334b9280..ae5a2ed3b264 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -29,12 +29,7 @@ * define the configuration needed by the board are defined in a * board structure in arch/ppc/platforms (though I do not * discount the possibility that other architectures could one - * day be supported. One assumption the driver currently makes - * is that the PHY is configured in such a way to advertise all - * capabilities. This is a sensible default, and on certain - * PHYs, changing this default encounters substantial errata - * issues. Future versions may remove this requirement, but for - * now, it is best for the firmware to ensure this is the case. + * day be supported. * * The Gianfar Ethernet Controller uses a ring of buffer * descriptors. The beginning is indicated by a register @@ -47,7 +42,7 @@ * corresponding bit in the IMASK register is also set (if * interrupt coalescing is active, then the interrupt may not * happen immediately, but will wait until either a set number - * of frames or amount of time have passed.). In NAPI, the + * of frames or amount of time have passed). In NAPI, the * interrupt handler will signal there is work to be done, and * exit. Without NAPI, the packet(s) will be handled * immediately. Both methods will start at the last known empty @@ -75,6 +70,7 @@ #include <linux/sched.h> #include <linux/string.h> #include <linux/errno.h> +#include <linux/unistd.h> #include <linux/slab.h> #include <linux/interrupt.h> #include <linux/init.h> @@ -97,9 +93,11 @@ #include <linux/version.h> #include <linux/dma-mapping.h> #include <linux/crc32.h> +#include <linux/mii.h> +#include <linux/phy.h> #include "gianfar.h" -#include "gianfar_phy.h" +#include "gianfar_mii.h" #define TX_TIMEOUT (1*HZ) #define SKB_ALLOC_TIMEOUT 1000000 @@ -113,9 +111,8 @@ #endif const char gfar_driver_name[] = "Gianfar Ethernet"; -const char gfar_driver_version[] = "1.1"; +const char gfar_driver_version[] = "1.2"; -int startup_gfar(struct net_device *dev); static int gfar_enet_open(struct net_device *dev); static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev); static void gfar_timeout(struct net_device *dev); @@ -126,17 +123,13 @@ static int gfar_set_mac_address(struct net_device *dev); static int gfar_change_mtu(struct net_device *dev, int new_mtu); static irqreturn_t gfar_error(int irq, void *dev_id, struct pt_regs *regs); static irqreturn_t gfar_transmit(int irq, void *dev_id, struct pt_regs *regs); -static irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs); static irqreturn_t gfar_interrupt(int irq, void *dev_id, struct pt_regs *regs); -static irqreturn_t phy_interrupt(int irq, void *dev_id, struct pt_regs *regs); -static void gfar_phy_change(void *data); -static void gfar_phy_timer(unsigned long data); static void adjust_link(struct net_device *dev); static void init_registers(struct net_device *dev); static int init_phy(struct net_device *dev); static int gfar_probe(struct device *device); static int gfar_remove(struct device *device); -void free_skb_resources(struct gfar_private *priv); +static void free_skb_resources(struct gfar_private *priv); static void gfar_set_multi(struct net_device *dev); static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr); #ifdef CONFIG_GFAR_NAPI @@ -144,7 +137,6 @@ static int gfar_poll(struct net_device *dev, int *budget); #endif int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit); static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, int length); -static void gfar_phy_startup_timer(unsigned long data); static void gfar_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp); static void gfar_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid); @@ -162,6 +154,9 @@ int gfar_uses_fcb(struct gfar_private *priv) else return 0; } + +/* Set up the ethernet device structure, private data, + * and anything else we need before we start */ static int gfar_probe(struct device *device) { u32 tempval; @@ -175,7 +170,7 @@ static int gfar_probe(struct device *device) einfo = (struct gianfar_platform_data *) pdev->dev.platform_data; - if (einfo == NULL) { + if (NULL == einfo) { printk(KERN_ERR "gfar %d: Missing additional data!\n", pdev->id); @@ -185,7 +180,7 @@ static int gfar_probe(struct device *device) /* Create an ethernet device instance */ dev = alloc_etherdev(sizeof (*priv)); - if (dev == NULL) + if (NULL == dev) return -ENOMEM; priv = netdev_priv(dev); @@ -207,20 +202,11 @@ static int gfar_probe(struct device *device) priv->regs = (struct gfar *) ioremap(r->start, sizeof (struct gfar)); - if (priv->regs == NULL) { + if (NULL == priv->regs) { err = -ENOMEM; goto regs_fail; } - /* Set the PHY base address */ - priv->phyregs = (struct gfar *) - ioremap(einfo->phy_reg_addr, sizeof (struct gfar)); - - if (priv->phyregs == NULL) { - err = -ENOMEM; - goto phy_regs_fail; - } - spin_lock_init(&priv->lock); dev_set_drvdata(device, dev); @@ -386,12 +372,10 @@ static int gfar_probe(struct device *device) return 0; register_fail: - iounmap((void *) priv->phyregs); -phy_regs_fail: iounmap((void *) priv->regs); regs_fail: free_netdev(dev); - return -ENOMEM; + return err; } static int gfar_remove(struct device *device) @@ -402,108 +386,41 @@ static int gfar_remove(struct device *device) dev_set_drvdata(device, NULL); iounmap((void *) priv->regs); - iounmap((void *) priv->phyregs); free_netdev(dev); return 0; } -/* Configure the PHY for dev. - * returns 0 if success. -1 if failure +/* Initializes driver's PHY state, and attaches to the PHY. + * Returns 0 on success. */ static int init_phy(struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); - struct phy_info *curphy; - unsigned int timeout = PHY_INIT_TIMEOUT; - struct gfar *phyregs = priv->phyregs; - struct gfar_mii_info *mii_info; - int err; + uint gigabit_support = + priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_GIGABIT ? + SUPPORTED_1000baseT_Full : 0; + struct phy_device *phydev; priv->oldlink = 0; priv->oldspeed = 0; priv->oldduplex = -1; - mii_info = kmalloc(sizeof(struct gfar_mii_info), - GFP_KERNEL); - - if(NULL == mii_info) { - if (netif_msg_ifup(priv)) - printk(KERN_ERR "%s: Could not allocate mii_info\n", - dev->name); - return -ENOMEM; - } - - mii_info->speed = SPEED_1000; - mii_info->duplex = DUPLEX_FULL; - mii_info->pause = 0; - mii_info->link = 1; - - mii_info->advertising = (ADVERTISED_10baseT_Half | - ADVERTISED_10baseT_Full | - ADVERTISED_100baseT_Half | - ADVERTISED_100baseT_Full | - ADVERTISED_1000baseT_Full); - mii_info->autoneg = 1; + phydev = phy_connect(dev, priv->einfo->bus_id, &adjust_link, 0); - spin_lock_init(&mii_info->mdio_lock); - - mii_info->mii_id = priv->einfo->phyid; - - mii_info->dev = dev; - - mii_info->mdio_read = &read_phy_reg; - mii_info->mdio_write = &write_phy_reg; - - priv->mii_info = mii_info; - - /* Reset the management interface */ - gfar_write(&phyregs->miimcfg, MIIMCFG_RESET); - - /* Setup the MII Mgmt clock speed */ - gfar_write(&phyregs->miimcfg, MIIMCFG_INIT_VALUE); - - /* Wait until the bus is free */ - while ((gfar_read(&phyregs->miimind) & MIIMIND_BUSY) && - timeout--) - cpu_relax(); - - if(timeout <= 0) { - printk(KERN_ERR "%s: The MII Bus is stuck!\n", - dev->name); - err = -1; - goto bus_fail; - } - - /* get info for this PHY */ - curphy = get_phy_info(priv->mii_info); - - if (curphy == NULL) { - if (netif_msg_ifup(priv)) - printk(KERN_ERR "%s: No PHY found\n", dev->name); - err = -1; - goto no_phy; + if (IS_ERR(phydev)) { + printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name); + return PTR_ERR(phydev); } - mii_info->phyinfo = curphy; + /* Remove any features not supported by the controller */ + phydev->supported &= (GFAR_SUPPORTED | gigabit_support); + phydev->advertising = phydev->supported; - /* Run the commands which initialize the PHY */ - if(curphy->init) { - err = curphy->init(priv->mii_info); - - if (err) - goto phy_init_fail; - } + priv->phydev = phydev; return 0; - -phy_init_fail: -no_phy: -bus_fail: - kfree(mii_info); - - return err; } static void init_registers(struct net_device *dev) @@ -603,24 +520,13 @@ void stop_gfar(struct net_device *dev) struct gfar *regs = priv->regs; unsigned long flags; + phy_stop(priv->phydev); + /* Lock it down */ spin_lock_irqsave(&priv->lock, flags); - /* Tell the kernel the link is down */ - priv->mii_info->link = 0; - adjust_link(dev); - gfar_halt(dev); - if (priv->einfo->board_flags & FSL_GIANFAR_BRD_HAS_PHY_INTR) { - /* Clear any pending interrupts */ - mii_clear_phy_interrupt(priv->mii_info); - - /* Disable PHY Interrupts */ - mii_configure_phy_interrupt(priv->mii_info, - MII_INTERRUPT_DISABLED); - } - spin_unlock_irqrestore(&priv->lock, flags); /* Free the IRQs */ @@ -629,13 +535,7 @@ void stop_gfar(struct net_device *dev) free_irq(priv->interruptTransmit, dev); free_irq(priv->interruptReceive, dev); } else { - free_irq(priv->interruptTransmit, dev); - } - - if (priv->einfo->board_flags & FSL_GIANFAR_BRD_HAS_PHY_INTR) { - free_irq(priv->einfo->interruptPHY, dev); - } else { - del_timer_sync(&priv->phy_info_timer); + free_irq(priv->interruptTransmit, dev); } free_skb_resources(priv); @@ -649,7 +549,7 @@ void stop_gfar(struct net_device *dev) /* If there are any tx skbs or rx skbs still around, free them. * Then free tx_skbuff and rx_skbuff */ -void free_skb_resources(struct gfar_private *priv) +static void free_skb_resources(struct gfar_private *priv) { struct rxbd8 *rxbdp; struct txbd8 *txbdp; @@ -770,7 +670,7 @@ int startup_gfar(struct net_device *dev) (struct sk_buff **) kmalloc(sizeof (struct sk_buff *) * priv->tx_ring_size, GFP_KERNEL); - if (priv->tx_skbuff == NULL) { + if (NULL == priv->tx_skbuff) { if (netif_msg_ifup(priv)) printk(KERN_ERR "%s: Could not allocate tx_skbuff\n", dev->name); @@ -785,7 +685,7 @@ int startup_gfar(struct net_device *dev) (struct sk_buff **) kmalloc(sizeof (struct sk_buff *) * priv->rx_ring_size, GFP_KERNEL); - if (priv->rx_skbuff == NULL) { + if (NULL == priv->rx_skbuff) { if (netif_msg_ifup(priv)) printk(KERN_ERR "%s: Could not allocate rx_skbuff\n", dev->name); @@ -879,13 +779,7 @@ int startup_gfar(struct net_device *dev) } } - /* Set up the PHY change work queue */ - INIT_WORK(&priv->tq, gfar_phy_change, dev); - - init_timer(&priv->phy_info_timer); - priv->phy_info_timer.function = &gfar_phy_startup_timer; - priv->phy_info_timer.data = (unsigned long) priv->mii_info; - mod_timer(&priv->phy_info_timer, jiffies + HZ); + phy_start(priv->phydev); /* Configure the coalescing support */ if (priv->txcoalescing) @@ -933,11 +827,6 @@ tx_skb_fail: priv->tx_bd_base, gfar_read(®s->tbase0)); - if (priv->mii_info->phyinfo->close) - priv->mii_info->phyinfo->close(priv->mii_info); - - kfree(priv->mii_info); - return err; } @@ -1035,7 +924,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) txbdp->status &= TXBD_WRAP; /* Set up checksumming */ - if ((dev->features & NETIF_F_IP_CSUM) + if ((dev->features & NETIF_F_IP_CSUM) && (CHECKSUM_HW == skb->ip_summed)) { fcb = gfar_add_fcb(skb, txbdp); gfar_tx_checksum(skb, fcb); @@ -1103,11 +992,9 @@ static int gfar_close(struct net_device *dev) struct gfar_private *priv = netdev_priv(dev); stop_gfar(dev); - /* Shutdown the PHY */ - if (priv->mii_info->phyinfo->close) - priv->mii_info->phyinfo->close(priv->mii_info); - - kfree(priv->mii_info); + /* Disconnect from the PHY */ + phy_disconnect(priv->phydev); + priv->phydev = NULL; netif_stop_queue(dev); @@ -1343,7 +1230,7 @@ struct sk_buff * gfar_new_skb(struct net_device *dev, struct rxbd8 *bdp) while ((!skb) && timeout--) skb = dev_alloc_skb(priv->rx_buffer_size + RXBUF_ALIGNMENT); - if (skb == NULL) + if (NULL == skb) return NULL; /* We need the data buffer to be aligned properly. We will reserve @@ -1490,7 +1377,7 @@ static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, struct gfar_private *priv = netdev_priv(dev); struct rxfcb *fcb = NULL; - if (skb == NULL) { + if (NULL == skb) { if (netif_msg_rx_err(priv)) printk(KERN_WARNING "%s: Missing skb!!.\n", dev->name); priv->stats.rx_dropped++; @@ -1718,131 +1605,9 @@ static irqreturn_t gfar_interrupt(int irq, void *dev_id, struct pt_regs *regs) return IRQ_HANDLED; } -static irqreturn_t phy_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - struct net_device *dev = (struct net_device *) dev_id; - struct gfar_private *priv = netdev_priv(dev); - - /* Clear the interrupt */ - mii_clear_phy_interrupt(priv->mii_info); - - /* Disable PHY interrupts */ - mii_configure_phy_interrupt(priv->mii_info, - MII_INTERRUPT_DISABLED); - - /* Schedule the phy change */ - schedule_work(&priv->tq); - - return IRQ_HANDLED; -} - -/* Scheduled by the phy_interrupt/timer to handle PHY changes */ -static void gfar_phy_change(void *data) -{ - struct net_device *dev = (struct net_device *) data; - struct gfar_private *priv = netdev_priv(dev); - int result = 0; - - /* Delay to give the PHY a chance to change the - * register state */ - msleep(1); - - /* Update the link, speed, duplex */ - result = priv->mii_info->phyinfo->read_status(priv->mii_info); - - /* Adjust the known status as long as the link - * isn't still coming up */ - if((0 == result) || (priv->mii_info->link == 0)) - adjust_link(dev); - - /* Reenable interrupts, if needed */ - if (priv->einfo->board_flags & FSL_GIANFAR_BRD_HAS_PHY_INTR) - mii_configure_phy_interrupt(priv->mii_info, - MII_INTERRUPT_ENABLED); -} - -/* Called every so often on systems that don't interrupt - * the core for PHY changes */ -static void gfar_phy_timer(unsigned long data) -{ - struct net_device *dev = (struct net_device *) data; - struct gfar_private *priv = netdev_priv(dev); - - schedule_work(&priv->tq); - - mod_timer(&priv->phy_info_timer, jiffies + - GFAR_PHY_CHANGE_TIME * HZ); -} - -/* Keep trying aneg for some time - * If, after GFAR_AN_TIMEOUT seconds, it has not - * finished, we switch to forced. - * Either way, once the process has completed, we either - * request the interrupt, or switch the timer over to - * using gfar_phy_timer to check status */ -static void gfar_phy_startup_timer(unsigned long data) -{ - int result; - static int secondary = GFAR_AN_TIMEOUT; - struct gfar_mii_info *mii_info = (struct gfar_mii_info *)data; - struct gfar_private *priv = netdev_priv(mii_info->dev); - - /* Configure the Auto-negotiation */ - result = mii_info->phyinfo->config_aneg(mii_info); - - /* If autonegotiation failed to start, and - * we haven't timed out, reset the timer, and return */ - if (result && secondary--) { - mod_timer(&priv->phy_info_timer, jiffies + HZ); - return; - } else if (result) { - /* Couldn't start autonegotiation. - * Try switching to forced */ - mii_info->autoneg = 0; - result = mii_info->phyinfo->config_aneg(mii_info); - - /* Forcing failed! Give up */ - if(result) { - if (netif_msg_link(priv)) - printk(KERN_ERR "%s: Forcing failed!\n", - mii_info->dev->name); - return; - } - } - - /* Kill the timer so it can be restarted */ - del_timer_sync(&priv->phy_info_timer); - - /* Grab the PHY interrupt, if necessary/possible */ - if (priv->einfo->board_flags & FSL_GIANFAR_BRD_HAS_PHY_INTR) { - if (request_irq(priv->einfo->interruptPHY, - phy_interrupt, - SA_SHIRQ, - "phy_interrupt", - mii_info->dev) < 0) { - if (netif_msg_intr(priv)) - printk(KERN_ERR "%s: Can't get IRQ %d (PHY)\n", - mii_info->dev->name, - priv->einfo->interruptPHY); - } else { - mii_configure_phy_interrupt(priv->mii_info, - MII_INTERRUPT_ENABLED); - return; - } - } - - /* Start the timer again, this time in order to - * handle a change in status */ - init_timer(&priv->phy_info_timer); - priv->phy_info_timer.function = &gfar_phy_timer; - priv->phy_info_timer.data = (unsigned long) mii_info->dev; - mod_timer(&priv->phy_info_timer, jiffies + - GFAR_PHY_CHANGE_TIME * HZ); -} - /* Called every time the controller might need to be made * aware of new link state. The PHY code conveys this - * information through variables in the priv structure, and this + * information through variables in the phydev structure, and this * function converts those variables into the appropriate * register values, and can bring down the device if needed. */ @@ -1850,84 +1615,68 @@ static void adjust_link(struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); struct gfar *regs = priv->regs; - u32 tempval; - struct gfar_mii_info *mii_info = priv->mii_info; + unsigned long flags; + struct phy_device *phydev = priv->phydev; + int new_state = 0; + + spin_lock_irqsave(&priv->lock, flags); + if (phydev->link) { + u32 tempval = gfar_read(®s->maccfg2); - if (mii_info->link) { /* Now we make sure that we can be in full duplex mode. * If not, we operate in half-duplex mode. */ - if (mii_info->duplex != priv->oldduplex) { - if (!(mii_info->duplex)) { - tempval = gfar_read(®s->maccfg2); + if (phydev->duplex != priv->oldduplex) { + new_state = 1; + if (!(phydev->duplex)) tempval &= ~(MACCFG2_FULL_DUPLEX); - gfar_write(®s->maccfg2, tempval); - - if (netif_msg_link(priv)) - printk(KERN_INFO "%s: Half Duplex\n", - dev->name); - } else { - tempval = gfar_read(®s->maccfg2); + else tempval |= MACCFG2_FULL_DUPLEX; - gfar_write(®s->maccfg2, tempval); - if (netif_msg_link(priv)) - printk(KERN_INFO "%s: Full Duplex\n", - dev->name); - } - - priv->oldduplex = mii_info->duplex; + priv->oldduplex = phydev->duplex; } - if (mii_info->speed != priv->oldspeed) { - switch (mii_info->speed) { + if (phydev->speed != priv->oldspeed) { + new_state = 1; + switch (phydev->speed) { case 1000: - tempval = gfar_read(®s->maccfg2); tempval = ((tempval & ~(MACCFG2_IF)) | MACCFG2_GMII); - gfar_write(®s->maccfg2, tempval); break; case 100: case 10: - tempval = gfar_read(®s->maccfg2); tempval = ((tempval & ~(MACCFG2_IF)) | MACCFG2_MII); - gfar_write(®s->maccfg2, tempval); break; default: if (netif_msg_link(priv)) printk(KERN_WARNING - "%s: Ack! Speed (%d) is not 10/100/1000!\n", - dev->name, mii_info->speed); + "%s: Ack! Speed (%d) is not 10/100/1000!\n", + dev->name, phydev->speed); break; } - if (netif_msg_link(priv)) - printk(KERN_INFO "%s: Speed %dBT\n", dev->name, - mii_info->speed); - - priv->oldspeed = mii_info->speed; + priv->oldspeed = phydev->speed; } + gfar_write(®s->maccfg2, tempval); + if (!priv->oldlink) { - if (netif_msg_link(priv)) - printk(KERN_INFO "%s: Link is up\n", dev->name); + new_state = 1; priv->oldlink = 1; - netif_carrier_on(dev); netif_schedule(dev); } - } else { - if (priv->oldlink) { - if (netif_msg_link(priv)) - printk(KERN_INFO "%s: Link is down\n", - dev->name); - priv->oldlink = 0; - priv->oldspeed = 0; - priv->oldduplex = -1; - netif_carrier_off(dev); - } + } else if (priv->oldlink) { + new_state = 1; + priv->oldlink = 0; + priv->oldspeed = 0; + priv->oldduplex = -1; } -} + if (new_state && netif_msg_link(priv)) + phy_print_status(phydev); + + spin_unlock_irqrestore(&priv->lock, flags); +} /* Update the hash table based on the current list of multicast * addresses we subscribe to. Also, change the promiscuity of @@ -2122,12 +1871,23 @@ static struct device_driver gfar_driver = { static int __init gfar_init(void) { - return driver_register(&gfar_driver); + int err = gfar_mdio_init(); + + if (err) + return err; + + err = driver_register(&gfar_driver); + + if (err) + gfar_mdio_exit(); + + return err; } static void __exit gfar_exit(void) { driver_unregister(&gfar_driver); + gfar_mdio_exit(); } module_init(gfar_init); diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h index 28af087d9fbb..c77ca6c0d04a 100644 --- a/drivers/net/gianfar.h +++ b/drivers/net/gianfar.h @@ -17,7 +17,6 @@ * * Still left to do: * -Add support for module parameters - * -Add support for ethtool -s * -Add patch for ethtool phys id */ #ifndef __GIANFAR_H @@ -37,7 +36,8 @@ #include <linux/skbuff.h> #include <linux/spinlock.h> #include <linux/mm.h> -#include <linux/fsl_devices.h> +#include <linux/mii.h> +#include <linux/phy.h> #include <asm/io.h> #include <asm/irq.h> @@ -48,7 +48,8 @@ #include <linux/workqueue.h> #include <linux/ethtool.h> #include <linux/netdevice.h> -#include "gianfar_phy.h" +#include <linux/fsl_devices.h> +#include "gianfar_mii.h" /* The maximum number of packets to be handled in one call of gfar_poll */ #define GFAR_DEV_WEIGHT 64 @@ -73,7 +74,7 @@ #define PHY_INIT_TIMEOUT 100000 #define GFAR_PHY_CHANGE_TIME 2 -#define DEVICE_NAME "%s: Gianfar Ethernet Controller Version 1.1, " +#define DEVICE_NAME "%s: Gianfar Ethernet Controller Version 1.2, " #define DRV_NAME "gfar-enet" extern const char gfar_driver_name[]; extern const char gfar_driver_version[]; @@ -578,12 +579,7 @@ struct gfar { u32 hafdup; /* 0x.50c - Half Duplex Register */ u32 maxfrm; /* 0x.510 - Maximum Frame Length Register */ u8 res18[12]; - u32 miimcfg; /* 0x.520 - MII Management Configuration Register */ - u32 miimcom; /* 0x.524 - MII Management Command Register */ - u32 miimadd; /* 0x.528 - MII Management Address Register */ - u32 miimcon; /* 0x.52c - MII Management Control Register */ - u32 miimstat; /* 0x.530 - MII Management Status Register */ - u32 miimind; /* 0x.534 - MII Management Indicator Register */ + u8 gfar_mii_regs[24]; /* See gianfar_phy.h */ u8 res19[4]; u32 ifstat; /* 0x.53c - Interface Status Register */ u32 macstnaddr1; /* 0x.540 - Station Address Part 1 Register */ @@ -688,9 +684,6 @@ struct gfar_private { struct gfar *regs; /* Pointer to the GFAR memory mapped Registers */ u32 *hash_regs[16]; int hash_width; - struct gfar *phyregs; - struct work_struct tq; - struct timer_list phy_info_timer; struct net_device_stats stats; /* linux network statistics */ struct gfar_extra_stats extra_stats; spinlock_t lock; @@ -710,7 +703,8 @@ struct gfar_private { unsigned int interruptError; struct gianfar_platform_data *einfo; - struct gfar_mii_info *mii_info; + struct phy_device *phydev; + struct mii_bus *mii_bus; int oldspeed; int oldduplex; int oldlink; @@ -732,4 +726,12 @@ extern inline void gfar_write(volatile unsigned *addr, u32 val) extern struct ethtool_ops *gfar_op_array[]; +extern irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs); +extern int startup_gfar(struct net_device *dev); +extern void stop_gfar(struct net_device *dev); +extern void gfar_halt(struct net_device *dev); +extern void gfar_phy_test(struct mii_bus *bus, struct phy_device *phydev, + int enable, u32 regnum, u32 read); +void gfar_setup_stashing(struct net_device *dev); + #endif /* __GIANFAR_H */ diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c index a451de629197..68e3578e7613 100644 --- a/drivers/net/gianfar_ethtool.c +++ b/drivers/net/gianfar_ethtool.c @@ -39,17 +39,18 @@ #include <asm/types.h> #include <asm/uaccess.h> #include <linux/ethtool.h> +#include <linux/mii.h> +#include <linux/phy.h> #include "gianfar.h" #define is_power_of_2(x) ((x) != 0 && (((x) & ((x) - 1)) == 0)) -extern int startup_gfar(struct net_device *dev); -extern void stop_gfar(struct net_device *dev); -extern void gfar_halt(struct net_device *dev); extern void gfar_start(struct net_device *dev); extern int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit); +#define GFAR_MAX_COAL_USECS 0xffff +#define GFAR_MAX_COAL_FRAMES 0xff static void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy, u64 * buf); static void gfar_gstrings(struct net_device *dev, u32 stringset, u8 * buf); @@ -182,38 +183,32 @@ static void gfar_gdrvinfo(struct net_device *dev, struct drvinfo->eedump_len = 0; } + +static int gfar_ssettings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct gfar_private *priv = netdev_priv(dev); + struct phy_device *phydev = priv->phydev; + + if (NULL == phydev) + return -ENODEV; + + return phy_ethtool_sset(phydev, cmd); +} + + /* Return the current settings in the ethtool_cmd structure */ static int gfar_gsettings(struct net_device *dev, struct ethtool_cmd *cmd) { struct gfar_private *priv = netdev_priv(dev); - uint gigabit_support = - priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_GIGABIT ? - SUPPORTED_1000baseT_Full : 0; - uint gigabit_advert = - priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_GIGABIT ? - ADVERTISED_1000baseT_Full: 0; - - cmd->supported = (SUPPORTED_10baseT_Half - | SUPPORTED_100baseT_Half - | SUPPORTED_100baseT_Full - | gigabit_support | SUPPORTED_Autoneg); - - /* For now, we always advertise everything */ - cmd->advertising = (ADVERTISED_10baseT_Half - | ADVERTISED_100baseT_Half - | ADVERTISED_100baseT_Full - | gigabit_advert | ADVERTISED_Autoneg); - - cmd->speed = priv->mii_info->speed; - cmd->duplex = priv->mii_info->duplex; - cmd->port = PORT_MII; - cmd->phy_address = priv->mii_info->mii_id; - cmd->transceiver = XCVR_EXTERNAL; - cmd->autoneg = AUTONEG_ENABLE; + struct phy_device *phydev = priv->phydev; + + if (NULL == phydev) + return -ENODEV; + cmd->maxtxpkt = priv->txcount; cmd->maxrxpkt = priv->rxcount; - return 0; + return phy_ethtool_gset(phydev, cmd); } /* Return the length of the register structure */ @@ -241,14 +236,14 @@ static unsigned int gfar_usecs2ticks(struct gfar_private *priv, unsigned int use unsigned int count; /* The timer is different, depending on the interface speed */ - switch (priv->mii_info->speed) { - case 1000: + switch (priv->phydev->speed) { + case SPEED_1000: count = GFAR_GBIT_TIME; break; - case 100: + case SPEED_100: count = GFAR_100_TIME; break; - case 10: + case SPEED_10: default: count = GFAR_10_TIME; break; @@ -265,14 +260,14 @@ static unsigned int gfar_ticks2usecs(struct gfar_private *priv, unsigned int tic unsigned int count; /* The timer is different, depending on the interface speed */ - switch (priv->mii_info->speed) { - case 1000: + switch (priv->phydev->speed) { + case SPEED_1000: count = GFAR_GBIT_TIME; break; - case 100: + case SPEED_100: count = GFAR_100_TIME; break; - case 10: + case SPEED_10: default: count = GFAR_10_TIME; break; @@ -292,6 +287,9 @@ static int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_COALESCE)) return -EOPNOTSUPP; + if (NULL == priv->phydev) + return -ENODEV; + cvals->rx_coalesce_usecs = gfar_ticks2usecs(priv, priv->rxtime); cvals->rx_max_coalesced_frames = priv->rxcount; @@ -348,6 +346,22 @@ static int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals else priv->rxcoalescing = 1; + if (NULL == priv->phydev) + return -ENODEV; + + /* Check the bounds of the values */ + if (cvals->rx_coalesce_usecs > GFAR_MAX_COAL_USECS) { + pr_info("Coalescing is limited to %d microseconds\n", + GFAR_MAX_COAL_USECS); + return -EINVAL; + } + + if (cvals->rx_max_coalesced_frames > GFAR_MAX_COAL_FRAMES) { + pr_info("Coalescing is limited to %d frames\n", + GFAR_MAX_COAL_FRAMES); + return -EINVAL; + } + priv->rxtime = gfar_usecs2ticks(priv, cvals->rx_coalesce_usecs); priv->rxcount = cvals->rx_max_coalesced_frames; @@ -358,6 +372,19 @@ static int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals else priv->txcoalescing = 1; + /* Check the bounds of the values */ + if (cvals->tx_coalesce_usecs > GFAR_MAX_COAL_USECS) { + pr_info("Coalescing is limited to %d microseconds\n", + GFAR_MAX_COAL_USECS); + return -EINVAL; + } + + if (cvals->tx_max_coalesced_frames > GFAR_MAX_COAL_FRAMES) { + pr_info("Coalescing is limited to %d frames\n", + GFAR_MAX_COAL_FRAMES); + return -EINVAL; + } + priv->txtime = gfar_usecs2ticks(priv, cvals->tx_coalesce_usecs); priv->txcount = cvals->tx_max_coalesced_frames; @@ -536,6 +563,7 @@ static void gfar_set_msglevel(struct net_device *dev, uint32_t data) struct ethtool_ops gfar_ethtool_ops = { .get_settings = gfar_gsettings, + .set_settings = gfar_ssettings, .get_drvinfo = gfar_gdrvinfo, .get_regs_len = gfar_reglen, .get_regs = gfar_get_regs, diff --git a/drivers/net/gianfar_mii.c b/drivers/net/gianfar_mii.c new file mode 100644 index 000000000000..1eca1dbca7f1 --- /dev/null +++ b/drivers/net/gianfar_mii.c @@ -0,0 +1,219 @@ +/* + * drivers/net/gianfar_mii.c + * + * Gianfar Ethernet Driver -- MIIM bus implementation + * Provides Bus interface for MIIM regs + * + * Author: Andy Fleming + * Maintainer: Kumar Gala (kumar.gala@freescale.com) + * + * Copyright (c) 2002-2004 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/string.h> +#include <linux/errno.h> +#include <linux/unistd.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/spinlock.h> +#include <linux/mm.h> +#include <linux/module.h> +#include <linux/version.h> +#include <asm/ocp.h> +#include <linux/crc32.h> +#include <linux/mii.h> +#include <linux/phy.h> + +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/uaccess.h> + +#include "gianfar.h" +#include "gianfar_mii.h" + +/* Write value to the PHY at mii_id at register regnum, + * on the bus, waiting until the write is done before returning. + * All PHY configuration is done through the TSEC1 MIIM regs */ +int gfar_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value) +{ + struct gfar_mii *regs = bus->priv; + + /* Set the PHY address and the register address we want to write */ + gfar_write(®s->miimadd, (mii_id << 8) | regnum); + + /* Write out the value we want */ + gfar_write(®s->miimcon, value); + + /* Wait for the transaction to finish */ + while (gfar_read(®s->miimind) & MIIMIND_BUSY) + cpu_relax(); + + return 0; +} + +/* Read the bus for PHY at addr mii_id, register regnum, and + * return the value. Clears miimcom first. All PHY + * configuration has to be done through the TSEC1 MIIM regs */ +int gfar_mdio_read(struct mii_bus *bus, int mii_id, int regnum) +{ + struct gfar_mii *regs = bus->priv; + u16 value; + + /* Set the PHY address and the register address we want to read */ + gfar_write(®s->miimadd, (mii_id << 8) | regnum); + + /* Clear miimcom, and then initiate a read */ + gfar_write(®s->miimcom, 0); + gfar_write(®s->miimcom, MII_READ_COMMAND); + + /* Wait for the transaction to finish */ + while (gfar_read(®s->miimind) & (MIIMIND_NOTVALID | MIIMIND_BUSY)) + cpu_relax(); + + /* Grab the value of the register from miimstat */ + value = gfar_read(®s->miimstat); + + return value; +} + + +/* Reset the MIIM registers, and wait for the bus to free */ +int gfar_mdio_reset(struct mii_bus *bus) +{ + struct gfar_mii *regs = bus->priv; + unsigned int timeout = PHY_INIT_TIMEOUT; + + spin_lock_bh(&bus->mdio_lock); + + /* Reset the management interface */ + gfar_write(®s->miimcfg, MIIMCFG_RESET); + + /* Setup the MII Mgmt clock speed */ + gfar_write(®s->miimcfg, MIIMCFG_INIT_VALUE); + + /* Wait until the bus is free */ + while ((gfar_read(®s->miimind) & MIIMIND_BUSY) && + timeout--) + cpu_relax(); + + spin_unlock_bh(&bus->mdio_lock); + + if(timeout <= 0) { + printk(KERN_ERR "%s: The MII Bus is stuck!\n", + bus->name); + return -EBUSY; + } + + return 0; +} + + +int gfar_mdio_probe(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct gianfar_mdio_data *pdata; + struct gfar_mii *regs; + struct mii_bus *new_bus; + int err = 0; + + if (NULL == dev) + return -EINVAL; + + new_bus = kmalloc(sizeof(struct mii_bus), GFP_KERNEL); + + if (NULL == new_bus) + return -ENOMEM; + + new_bus->name = "Gianfar MII Bus", + new_bus->read = &gfar_mdio_read, + new_bus->write = &gfar_mdio_write, + new_bus->reset = &gfar_mdio_reset, + new_bus->id = pdev->id; + + pdata = (struct gianfar_mdio_data *)pdev->dev.platform_data; + + if (NULL == pdata) { + printk(KERN_ERR "gfar mdio %d: Missing platform data!\n", pdev->id); + return -ENODEV; + } + + /* Set the PHY base address */ + regs = (struct gfar_mii *) ioremap(pdata->paddr, + sizeof (struct gfar_mii)); + + if (NULL == regs) { + err = -ENOMEM; + goto reg_map_fail; + } + + new_bus->priv = regs; + + new_bus->irq = pdata->irq; + + new_bus->dev = dev; + dev_set_drvdata(dev, new_bus); + + err = mdiobus_register(new_bus); + + if (0 != err) { + printk (KERN_ERR "%s: Cannot register as MDIO bus\n", + new_bus->name); + goto bus_register_fail; + } + + return 0; + +bus_register_fail: + iounmap((void *) regs); +reg_map_fail: + kfree(new_bus); + + return err; +} + + +int gfar_mdio_remove(struct device *dev) +{ + struct mii_bus *bus = dev_get_drvdata(dev); + + mdiobus_unregister(bus); + + dev_set_drvdata(dev, NULL); + + iounmap((void *) (&bus->priv)); + bus->priv = NULL; + kfree(bus); + + return 0; +} + +static struct device_driver gianfar_mdio_driver = { + .name = "fsl-gianfar_mdio", + .bus = &platform_bus_type, + .probe = gfar_mdio_probe, + .remove = gfar_mdio_remove, +}; + +int __init gfar_mdio_init(void) +{ + return driver_register(&gianfar_mdio_driver); +} + +void __exit gfar_mdio_exit(void) +{ + driver_unregister(&gianfar_mdio_driver); +} diff --git a/drivers/net/gianfar_mii.h b/drivers/net/gianfar_mii.h new file mode 100644 index 000000000000..56e5665d5c9b --- /dev/null +++ b/drivers/net/gianfar_mii.h @@ -0,0 +1,45 @@ +/* + * drivers/net/gianfar_mii.h + * + * Gianfar Ethernet Driver -- MII Management Bus Implementation + * Driver for the MDIO bus controller in the Gianfar register space + * + * Author: Andy Fleming + * Maintainer: Kumar Gala (kumar.gala@freescale.com) + * + * Copyright (c) 2002-2004 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ +#ifndef __GIANFAR_MII_H +#define __GIANFAR_MII_H + +#define MIIMIND_BUSY 0x00000001 +#define MIIMIND_NOTVALID 0x00000004 + +#define MII_READ_COMMAND 0x00000001 + +#define GFAR_SUPPORTED (SUPPORTED_10baseT_Half \ + | SUPPORTED_100baseT_Half \ + | SUPPORTED_100baseT_Full \ + | SUPPORTED_Autoneg \ + | SUPPORTED_MII) + +struct gfar_mii { + u32 miimcfg; /* 0x.520 - MII Management Config Register */ + u32 miimcom; /* 0x.524 - MII Management Command Register */ + u32 miimadd; /* 0x.528 - MII Management Address Register */ + u32 miimcon; /* 0x.52c - MII Management Control Register */ + u32 miimstat; /* 0x.530 - MII Management Status Register */ + u32 miimind; /* 0x.534 - MII Management Indicator Register */ +}; + +int gfar_mdio_read(struct mii_bus *bus, int mii_id, int regnum); +int gfar_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value); +int __init gfar_mdio_init(void); +void __exit gfar_mdio_exit(void); +#endif /* GIANFAR_PHY_H */ diff --git a/drivers/net/gianfar_phy.c b/drivers/net/gianfar_phy.c deleted file mode 100644 index 7c965f268a82..000000000000 --- a/drivers/net/gianfar_phy.c +++ /dev/null @@ -1,661 +0,0 @@ -/* - * drivers/net/gianfar_phy.c - * - * Gianfar Ethernet Driver -- PHY handling - * Driver for FEC on MPC8540 and TSEC on MPC8540/MPC8560 - * Based on 8260_io/fcc_enet.c - * - * Author: Andy Fleming - * Maintainer: Kumar Gala (kumar.gala@freescale.com) - * - * Copyright (c) 2002-2004 Freescale Semiconductor, Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - */ - -#include <linux/config.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/string.h> -#include <linux/errno.h> -#include <linux/slab.h> -#include <linux/interrupt.h> -#include <linux/init.h> -#include <linux/delay.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/skbuff.h> -#include <linux/spinlock.h> -#include <linux/mm.h> - -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/uaccess.h> -#include <linux/module.h> -#include <linux/version.h> -#include <linux/crc32.h> -#include <linux/mii.h> - -#include "gianfar.h" -#include "gianfar_phy.h" - -static void config_genmii_advert(struct gfar_mii_info *mii_info); -static void genmii_setup_forced(struct gfar_mii_info *mii_info); -static void genmii_restart_aneg(struct gfar_mii_info *mii_info); -static int gbit_config_aneg(struct gfar_mii_info *mii_info); -static int genmii_config_aneg(struct gfar_mii_info *mii_info); -static int genmii_update_link(struct gfar_mii_info *mii_info); -static int genmii_read_status(struct gfar_mii_info *mii_info); -u16 phy_read(struct gfar_mii_info *mii_info, u16 regnum); -void phy_write(struct gfar_mii_info *mii_info, u16 regnum, u16 val); - -/* Write value to the PHY for this device to the register at regnum, */ -/* waiting until the write is done before it returns. All PHY */ -/* configuration has to be done through the TSEC1 MIIM regs */ -void write_phy_reg(struct net_device *dev, int mii_id, int regnum, int value) -{ - struct gfar_private *priv = netdev_priv(dev); - struct gfar *regbase = priv->phyregs; - - /* Set the PHY address and the register address we want to write */ - gfar_write(®base->miimadd, (mii_id << 8) | regnum); - - /* Write out the value we want */ - gfar_write(®base->miimcon, value); - - /* Wait for the transaction to finish */ - while (gfar_read(®base->miimind) & MIIMIND_BUSY) - cpu_relax(); -} - -/* Reads from register regnum in the PHY for device dev, */ -/* returning the value. Clears miimcom first. All PHY */ -/* configuration has to be done through the TSEC1 MIIM regs */ -int read_phy_reg(struct net_device *dev, int mii_id, int regnum) -{ - struct gfar_private *priv = netdev_priv(dev); - struct gfar *regbase = priv->phyregs; - u16 value; - - /* Set the PHY address and the register address we want to read */ - gfar_write(®base->miimadd, (mii_id << 8) | regnum); - - /* Clear miimcom, and then initiate a read */ - gfar_write(®base->miimcom, 0); - gfar_write(®base->miimcom, MII_READ_COMMAND); - - /* Wait for the transaction to finish */ - while (gfar_read(®base->miimind) & (MIIMIND_NOTVALID | MIIMIND_BUSY)) - cpu_relax(); - - /* Grab the value of the register from miimstat */ - value = gfar_read(®base->miimstat); - - return value; -} - -void mii_clear_phy_interrupt(struct gfar_mii_info *mii_info) -{ - if(mii_info->phyinfo->ack_interrupt) - mii_info->phyinfo->ack_interrupt(mii_info); -} - - -void mii_configure_phy_interrupt(struct gfar_mii_info *mii_info, u32 interrupts) -{ - mii_info->interrupts = interrupts; - if(mii_info->phyinfo->config_intr) - mii_info->phyinfo->config_intr(mii_info); -} - - -/* Writes MII_ADVERTISE with the appropriate values, after - * sanitizing advertise to make sure only supported features - * are advertised - */ -static void config_genmii_advert(struct gfar_mii_info *mii_info) -{ - u32 advertise; - u16 adv; - - /* Only allow advertising what this PHY supports */ - mii_info->advertising &= mii_info->phyinfo->features; - advertise = mii_info->advertising; - - /* Setup standard advertisement */ - adv = phy_read(mii_info, MII_ADVERTISE); - adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4); - if (advertise & ADVERTISED_10baseT_Half) - adv |= ADVERTISE_10HALF; - if (advertise & ADVERTISED_10baseT_Full) - adv |= ADVERTISE_10FULL; - if (advertise & ADVERTISED_100baseT_Half) - adv |= ADVERTISE_100HALF; - if (advertise & ADVERTISED_100baseT_Full) - adv |= ADVERTISE_100FULL; - phy_write(mii_info, MII_ADVERTISE, adv); -} - -static void genmii_setup_forced(struct gfar_mii_info *mii_info) -{ - u16 ctrl; - u32 features = mii_info->phyinfo->features; - - ctrl = phy_read(mii_info, MII_BMCR); - - ctrl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_SPEED1000|BMCR_ANENABLE); - ctrl |= BMCR_RESET; - - switch(mii_info->speed) { - case SPEED_1000: - if(features & (SUPPORTED_1000baseT_Half - | SUPPORTED_1000baseT_Full)) { - ctrl |= BMCR_SPEED1000; - break; - } - mii_info->speed = SPEED_100; - case SPEED_100: - if (features & (SUPPORTED_100baseT_Half - | SUPPORTED_100baseT_Full)) { - ctrl |= BMCR_SPEED100; - break; - } - mii_info->speed = SPEED_10; - case SPEED_10: - if (features & (SUPPORTED_10baseT_Half - | SUPPORTED_10baseT_Full)) - break; - default: /* Unsupported speed! */ - printk(KERN_ERR "%s: Bad speed!\n", - mii_info->dev->name); - break; - } - - phy_write(mii_info, MII_BMCR, ctrl); -} - - -/* Enable and Restart Autonegotiation */ -static void genmii_restart_aneg(struct gfar_mii_info *mii_info) -{ - u16 ctl; - - ctl = phy_read(mii_info, MII_BMCR); - ctl |= (BMCR_ANENABLE | BMCR_ANRESTART); - phy_write(mii_info, MII_BMCR, ctl); -} - - -static int gbit_config_aneg(struct gfar_mii_info *mii_info) -{ - u16 adv; - u32 advertise; - - if(mii_info->autoneg) { - /* Configure the ADVERTISE register */ - config_genmii_advert(mii_info); - advertise = mii_info->advertising; - - adv = phy_read(mii_info, MII_1000BASETCONTROL); - adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP | - MII_1000BASETCONTROL_HALFDUPLEXCAP); - if (advertise & SUPPORTED_1000baseT_Half) - adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP; - if (advertise & SUPPORTED_1000baseT_Full) - adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP; - phy_write(mii_info, MII_1000BASETCONTROL, adv); - - /* Start/Restart aneg */ - genmii_restart_aneg(mii_info); - } else - genmii_setup_forced(mii_info); - - return 0; -} - -static int marvell_config_aneg(struct gfar_mii_info *mii_info) -{ - /* The Marvell PHY has an errata which requires - * that certain registers get written in order - * to restart autonegotiation */ - phy_write(mii_info, MII_BMCR, BMCR_RESET); - - phy_write(mii_info, 0x1d, 0x1f); - phy_write(mii_info, 0x1e, 0x200c); - phy_write(mii_info, 0x1d, 0x5); - phy_write(mii_info, 0x1e, 0); - phy_write(mii_info, 0x1e, 0x100); - - gbit_config_aneg(mii_info); - - return 0; -} -static int genmii_config_aneg(struct gfar_mii_info *mii_info) -{ - if (mii_info->autoneg) { - config_genmii_advert(mii_info); - genmii_restart_aneg(mii_info); - } else - genmii_setup_forced(mii_info); - - return 0; -} - - -static int genmii_update_link(struct gfar_mii_info *mii_info) -{ - u16 status; - - /* Do a fake read */ - phy_read(mii_info, MII_BMSR); - - /* Read link and autonegotiation status */ - status = phy_read(mii_info, MII_BMSR); - if ((status & BMSR_LSTATUS) == 0) - mii_info->link = 0; - else - mii_info->link = 1; - - /* If we are autonegotiating, and not done, - * return an error */ - if (mii_info->autoneg && !(status & BMSR_ANEGCOMPLETE)) - return -EAGAIN; - - return 0; -} - -static int genmii_read_status(struct gfar_mii_info *mii_info) -{ - u16 status; - int err; - - /* Update the link, but return if there - * was an error */ - err = genmii_update_link(mii_info); - if (err) - return err; - - if (mii_info->autoneg) { - status = phy_read(mii_info, MII_LPA); - - if (status & (LPA_10FULL | LPA_100FULL)) - mii_info->duplex = DUPLEX_FULL; - else - mii_info->duplex = DUPLEX_HALF; - if (status & (LPA_100FULL | LPA_100HALF)) - mii_info->speed = SPEED_100; - else - mii_info->speed = SPEED_10; - mii_info->pause = 0; - } - /* On non-aneg, we assume what we put in BMCR is the speed, - * though magic-aneg shouldn't prevent this case from occurring - */ - - return 0; -} -static int marvell_read_status(struct gfar_mii_info *mii_info) -{ - u16 status; - int err; - - /* Update the link, but return if there - * was an error */ - err = genmii_update_link(mii_info); - if (err) - return err; - - /* If the link is up, read the speed and duplex */ - /* If we aren't autonegotiating, assume speeds - * are as set */ - if (mii_info->autoneg && mii_info->link) { - int speed; - status = phy_read(mii_info, MII_M1011_PHY_SPEC_STATUS); - -#if 0 - /* If speed and duplex aren't resolved, - * return an error. Isn't this handled - * by checking aneg? - */ - if ((status & MII_M1011_PHY_SPEC_STATUS_RESOLVED) == 0) - return -EAGAIN; -#endif - - /* Get the duplexity */ - if (status & MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX) - mii_info->duplex = DUPLEX_FULL; - else - mii_info->duplex = DUPLEX_HALF; - - /* Get the speed */ - speed = status & MII_M1011_PHY_SPEC_STATUS_SPD_MASK; - switch(speed) { - case MII_M1011_PHY_SPEC_STATUS_1000: - mii_info->speed = SPEED_1000; - break; - case MII_M1011_PHY_SPEC_STATUS_100: - mii_info->speed = SPEED_100; - break; - default: - mii_info->speed = SPEED_10; - break; - } - mii_info->pause = 0; - } - - return 0; -} - - -static int cis820x_read_status(struct gfar_mii_info *mii_info) -{ - u16 status; - int err; - - /* Update the link, but return if there - * was an error */ - err = genmii_update_link(mii_info); - if (err) - return err; - - /* If the link is up, read the speed and duplex */ - /* If we aren't autonegotiating, assume speeds - * are as set */ - if (mii_info->autoneg && mii_info->link) { - int speed; - - status = phy_read(mii_info, MII_CIS8201_AUX_CONSTAT); - if (status & MII_CIS8201_AUXCONSTAT_DUPLEX) - mii_info->duplex = DUPLEX_FULL; - else - mii_info->duplex = DUPLEX_HALF; - - speed = status & MII_CIS8201_AUXCONSTAT_SPEED; - - switch (speed) { - case MII_CIS8201_AUXCONSTAT_GBIT: - mii_info->speed = SPEED_1000; - break; - case MII_CIS8201_AUXCONSTAT_100: - mii_info->speed = SPEED_100; - break; - default: - mii_info->speed = SPEED_10; - break; - } - } - - return 0; -} - -static int marvell_ack_interrupt(struct gfar_mii_info *mii_info) -{ - /* Clear the interrupts by reading the reg */ - phy_read(mii_info, MII_M1011_IEVENT); - - return 0; -} - -static int marvell_config_intr(struct gfar_mii_info *mii_info) -{ - if(mii_info->interrupts == MII_INTERRUPT_ENABLED) - phy_write(mii_info, MII_M1011_IMASK, MII_M1011_IMASK_INIT); - else - phy_write(mii_info, MII_M1011_IMASK, MII_M1011_IMASK_CLEAR); - - return 0; -} - -static int cis820x_init(struct gfar_mii_info *mii_info) -{ - phy_write(mii_info, MII_CIS8201_AUX_CONSTAT, - MII_CIS8201_AUXCONSTAT_INIT); - phy_write(mii_info, MII_CIS8201_EXT_CON1, - MII_CIS8201_EXTCON1_INIT); - - return 0; -} - -static int cis820x_ack_interrupt(struct gfar_mii_info *mii_info) -{ - phy_read(mii_info, MII_CIS8201_ISTAT); - - return 0; -} - -static int cis820x_config_intr(struct gfar_mii_info *mii_info) -{ - if(mii_info->interrupts == MII_INTERRUPT_ENABLED) - phy_write(mii_info, MII_CIS8201_IMASK, MII_CIS8201_IMASK_MASK); - else - phy_write(mii_info, MII_CIS8201_IMASK, 0); - - return 0; -} - -#define DM9161_DELAY 10 - -static int dm9161_read_status(struct gfar_mii_info *mii_info) -{ - u16 status; - int err; - - /* Update the link, but return if there - * was an error */ - err = genmii_update_link(mii_info); - if (err) - return err; - - /* If the link is up, read the speed and duplex */ - /* If we aren't autonegotiating, assume speeds - * are as set */ - if (mii_info->autoneg && mii_info->link) { - status = phy_read(mii_info, MII_DM9161_SCSR); - if (status & (MII_DM9161_SCSR_100F | MII_DM9161_SCSR_100H)) - mii_info->speed = SPEED_100; - else - mii_info->speed = SPEED_10; - - if (status & (MII_DM9161_SCSR_100F | MII_DM9161_SCSR_10F)) - mii_info->duplex = DUPLEX_FULL; - else - mii_info->duplex = DUPLEX_HALF; - } - - return 0; -} - - -static int dm9161_config_aneg(struct gfar_mii_info *mii_info) -{ - struct dm9161_private *priv = mii_info->priv; - - if(0 == priv->resetdone) - return -EAGAIN; - - return 0; -} - -static void dm9161_timer(unsigned long data) -{ - struct gfar_mii_info *mii_info = (struct gfar_mii_info *)data; - struct dm9161_private *priv = mii_info->priv; - u16 status = phy_read(mii_info, MII_BMSR); - - if (status & BMSR_ANEGCOMPLETE) { - priv->resetdone = 1; - } else - mod_timer(&priv->timer, jiffies + DM9161_DELAY * HZ); -} - -static int dm9161_init(struct gfar_mii_info *mii_info) -{ - struct dm9161_private *priv; - - /* Allocate the private data structure */ - priv = kmalloc(sizeof(struct dm9161_private), GFP_KERNEL); - - if (NULL == priv) - return -ENOMEM; - - mii_info->priv = priv; - - /* Reset is not done yet */ - priv->resetdone = 0; - - /* Isolate the PHY */ - phy_write(mii_info, MII_BMCR, BMCR_ISOLATE); - - /* Do not bypass the scrambler/descrambler */ - phy_write(mii_info, MII_DM9161_SCR, MII_DM9161_SCR_INIT); - - /* Clear 10BTCSR to default */ - phy_write(mii_info, MII_DM9161_10BTCSR, MII_DM9161_10BTCSR_INIT); - - /* Reconnect the PHY, and enable Autonegotiation */ - phy_write(mii_info, MII_BMCR, BMCR_ANENABLE); - - /* Start a timer for DM9161_DELAY seconds to wait - * for the PHY to be ready */ - init_timer(&priv->timer); - priv->timer.function = &dm9161_timer; - priv->timer.data = (unsigned long) mii_info; - mod_timer(&priv->timer, jiffies + DM9161_DELAY * HZ); - - return 0; -} - -static void dm9161_close(struct gfar_mii_info *mii_info) -{ - struct dm9161_private *priv = mii_info->priv; - - del_timer_sync(&priv->timer); - kfree(priv); -} - -#if 0 -static int dm9161_ack_interrupt(struct gfar_mii_info *mii_info) -{ - phy_read(mii_info, MII_DM9161_INTR); - - return 0; -} -#endif - -/* Cicada 820x */ -static struct phy_info phy_info_cis820x = { - 0x000fc440, - "Cicada Cis8204", - 0x000fffc0, - .features = MII_GBIT_FEATURES, - .init = &cis820x_init, - .config_aneg = &gbit_config_aneg, - .read_status = &cis820x_read_status, - .ack_interrupt = &cis820x_ack_interrupt, - .config_intr = &cis820x_config_intr, -}; - -static struct phy_info phy_info_dm9161 = { - .phy_id = 0x0181b880, - .name = "Davicom DM9161E", - .phy_id_mask = 0x0ffffff0, - .init = dm9161_init, - .config_aneg = dm9161_config_aneg, - .read_status = dm9161_read_status, - .close = dm9161_close, -}; - -static struct phy_info phy_info_marvell = { - .phy_id = 0x01410c00, - .phy_id_mask = 0xffffff00, - .name = "Marvell 88E1101/88E1111", - .features = MII_GBIT_FEATURES, - .config_aneg = &marvell_config_aneg, - .read_status = &marvell_read_status, - .ack_interrupt = &marvell_ack_interrupt, - .config_intr = &marvell_config_intr, -}; - -static struct phy_info phy_info_genmii= { - .phy_id = 0x00000000, - .phy_id_mask = 0x00000000, - .name = "Generic MII", - .features = MII_BASIC_FEATURES, - .config_aneg = genmii_config_aneg, - .read_status = genmii_read_status, -}; - -static struct phy_info *phy_info[] = { - &phy_info_cis820x, - &phy_info_marvell, - &phy_info_dm9161, - &phy_info_genmii, - NULL -}; - -u16 phy_read(struct gfar_mii_info *mii_info, u16 regnum) -{ - u16 retval; - unsigned long flags; - - spin_lock_irqsave(&mii_info->mdio_lock, flags); - retval = mii_info->mdio_read(mii_info->dev, mii_info->mii_id, regnum); - spin_unlock_irqrestore(&mii_info->mdio_lock, flags); - - return retval; -} - -void phy_write(struct gfar_mii_info *mii_info, u16 regnum, u16 val) -{ - unsigned long flags; - - spin_lock_irqsave(&mii_info->mdio_lock, flags); - mii_info->mdio_write(mii_info->dev, - mii_info->mii_id, - regnum, val); - spin_unlock_irqrestore(&mii_info->mdio_lock, flags); -} - -/* Use the PHY ID registers to determine what type of PHY is attached - * to device dev. return a struct phy_info structure describing that PHY - */ -struct phy_info * get_phy_info(struct gfar_mii_info *mii_info) -{ - u16 phy_reg; - u32 phy_ID; - int i; - struct phy_info *theInfo = NULL; - struct net_device *dev = mii_info->dev; - - /* Grab the bits from PHYIR1, and put them in the upper half */ - phy_reg = phy_read(mii_info, MII_PHYSID1); - phy_ID = (phy_reg & 0xffff) << 16; - - /* Grab the bits from PHYIR2, and put them in the lower half */ - phy_reg = phy_read(mii_info, MII_PHYSID2); - phy_ID |= (phy_reg & 0xffff); - - /* loop through all the known PHY types, and find one that */ - /* matches the ID we read from the PHY. */ - for (i = 0; phy_info[i]; i++) - if (phy_info[i]->phy_id == - (phy_ID & phy_info[i]->phy_id_mask)) { - theInfo = phy_info[i]; - break; - } - - /* This shouldn't happen, as we have generic PHY support */ - if (theInfo == NULL) { - printk("%s: PHY id %x is not supported!\n", dev->name, phy_ID); - return NULL; - } else { - printk("%s: PHY is %s (%x)\n", dev->name, theInfo->name, - phy_ID); - } - - return theInfo; -} diff --git a/drivers/net/gianfar_phy.h b/drivers/net/gianfar_phy.h deleted file mode 100644 index 1e9b3abf1e6d..000000000000 --- a/drivers/net/gianfar_phy.h +++ /dev/null @@ -1,213 +0,0 @@ -/* - * drivers/net/gianfar_phy.h - * - * Gianfar Ethernet Driver -- PHY handling - * Driver for FEC on MPC8540 and TSEC on MPC8540/MPC8560 - * Based on 8260_io/fcc_enet.c - * - * Author: Andy Fleming - * Maintainer: Kumar Gala (kumar.gala@freescale.com) - * - * Copyright (c) 2002-2004 Freescale Semiconductor, Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - */ -#ifndef __GIANFAR_PHY_H -#define __GIANFAR_PHY_H - -#define MII_end ((u32)-2) -#define MII_read ((u32)-1) - -#define MIIMIND_BUSY 0x00000001 -#define MIIMIND_NOTVALID 0x00000004 - -#define GFAR_AN_TIMEOUT 2000 - -/* 1000BT control (Marvell & BCM54xx at least) */ -#define MII_1000BASETCONTROL 0x09 -#define MII_1000BASETCONTROL_FULLDUPLEXCAP 0x0200 -#define MII_1000BASETCONTROL_HALFDUPLEXCAP 0x0100 - -/* Cicada Extended Control Register 1 */ -#define MII_CIS8201_EXT_CON1 0x17 -#define MII_CIS8201_EXTCON1_INIT 0x0000 - -/* Cicada Interrupt Mask Register */ -#define MII_CIS8201_IMASK 0x19 -#define MII_CIS8201_IMASK_IEN 0x8000 -#define MII_CIS8201_IMASK_SPEED 0x4000 -#define MII_CIS8201_IMASK_LINK 0x2000 -#define MII_CIS8201_IMASK_DUPLEX 0x1000 -#define MII_CIS8201_IMASK_MASK 0xf000 - -/* Cicada Interrupt Status Register */ -#define MII_CIS8201_ISTAT 0x1a -#define MII_CIS8201_ISTAT_STATUS 0x8000 -#define MII_CIS8201_ISTAT_SPEED 0x4000 -#define MII_CIS8201_ISTAT_LINK 0x2000 -#define MII_CIS8201_ISTAT_DUPLEX 0x1000 - -/* Cicada Auxiliary Control/Status Register */ -#define MII_CIS8201_AUX_CONSTAT 0x1c -#define MII_CIS8201_AUXCONSTAT_INIT 0x0004 -#define MII_CIS8201_AUXCONSTAT_DUPLEX 0x0020 -#define MII_CIS8201_AUXCONSTAT_SPEED 0x0018 -#define MII_CIS8201_AUXCONSTAT_GBIT 0x0010 -#define MII_CIS8201_AUXCONSTAT_100 0x0008 - -/* 88E1011 PHY Status Register */ -#define MII_M1011_PHY_SPEC_STATUS 0x11 -#define MII_M1011_PHY_SPEC_STATUS_1000 0x8000 -#define MII_M1011_PHY_SPEC_STATUS_100 0x4000 -#define MII_M1011_PHY_SPEC_STATUS_SPD_MASK 0xc000 -#define MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX 0x2000 -#define MII_M1011_PHY_SPEC_STATUS_RESOLVED 0x0800 -#define MII_M1011_PHY_SPEC_STATUS_LINK 0x0400 - -#define MII_M1011_IEVENT 0x13 -#define MII_M1011_IEVENT_CLEAR 0x0000 - -#define MII_M1011_IMASK 0x12 -#define MII_M1011_IMASK_INIT 0x6400 -#define MII_M1011_IMASK_CLEAR 0x0000 - -#define MII_DM9161_SCR 0x10 -#define MII_DM9161_SCR_INIT 0x0610 - -/* DM9161 Specified Configuration and Status Register */ -#define MII_DM9161_SCSR 0x11 -#define MII_DM9161_SCSR_100F 0x8000 -#define MII_DM9161_SCSR_100H 0x4000 -#define MII_DM9161_SCSR_10F 0x2000 -#define MII_DM9161_SCSR_10H 0x1000 - -/* DM9161 Interrupt Register */ -#define MII_DM9161_INTR 0x15 -#define MII_DM9161_INTR_PEND 0x8000 -#define MII_DM9161_INTR_DPLX_MASK 0x0800 -#define MII_DM9161_INTR_SPD_MASK 0x0400 -#define MII_DM9161_INTR_LINK_MASK 0x0200 -#define MII_DM9161_INTR_MASK 0x0100 -#define MII_DM9161_INTR_DPLX_CHANGE 0x0010 -#define MII_DM9161_INTR_SPD_CHANGE 0x0008 -#define MII_DM9161_INTR_LINK_CHANGE 0x0004 -#define MII_DM9161_INTR_INIT 0x0000 -#define MII_DM9161_INTR_STOP \ -(MII_DM9161_INTR_DPLX_MASK | MII_DM9161_INTR_SPD_MASK \ - | MII_DM9161_INTR_LINK_MASK | MII_DM9161_INTR_MASK) - -/* DM9161 10BT Configuration/Status */ -#define MII_DM9161_10BTCSR 0x12 -#define MII_DM9161_10BTCSR_INIT 0x7800 - -#define MII_BASIC_FEATURES (SUPPORTED_10baseT_Half | \ - SUPPORTED_10baseT_Full | \ - SUPPORTED_100baseT_Half | \ - SUPPORTED_100baseT_Full | \ - SUPPORTED_Autoneg | \ - SUPPORTED_TP | \ - SUPPORTED_MII) - -#define MII_GBIT_FEATURES (MII_BASIC_FEATURES | \ - SUPPORTED_1000baseT_Half | \ - SUPPORTED_1000baseT_Full) - -#define MII_READ_COMMAND 0x00000001 - -#define MII_INTERRUPT_DISABLED 0x0 -#define MII_INTERRUPT_ENABLED 0x1 -/* Taken from mii_if_info and sungem_phy.h */ -struct gfar_mii_info { - /* Information about the PHY type */ - /* And management functions */ - struct phy_info *phyinfo; - - /* forced speed & duplex (no autoneg) - * partner speed & duplex & pause (autoneg) - */ - int speed; - int duplex; - int pause; - - /* The most recently read link state */ - int link; - - /* Enabled Interrupts */ - u32 interrupts; - - u32 advertising; - int autoneg; - int mii_id; - - /* private data pointer */ - /* For use by PHYs to maintain extra state */ - void *priv; - - /* Provided by host chip */ - struct net_device *dev; - - /* A lock to ensure that only one thing can read/write - * the MDIO bus at a time */ - spinlock_t mdio_lock; - - /* Provided by ethernet driver */ - int (*mdio_read) (struct net_device *dev, int mii_id, int reg); - void (*mdio_write) (struct net_device *dev, int mii_id, int reg, int val); -}; - -/* struct phy_info: a structure which defines attributes for a PHY - * - * id will contain a number which represents the PHY. During - * startup, the driver will poll the PHY to find out what its - * UID--as defined by registers 2 and 3--is. The 32-bit result - * gotten from the PHY will be ANDed with phy_id_mask to - * discard any bits which may change based on revision numbers - * unimportant to functionality - * - * There are 6 commands which take a gfar_mii_info structure. - * Each PHY must declare config_aneg, and read_status. - */ -struct phy_info { - u32 phy_id; - char *name; - unsigned int phy_id_mask; - u32 features; - - /* Called to initialize the PHY */ - int (*init)(struct gfar_mii_info *mii_info); - - /* Called to suspend the PHY for power */ - int (*suspend)(struct gfar_mii_info *mii_info); - - /* Reconfigures autonegotiation (or disables it) */ - int (*config_aneg)(struct gfar_mii_info *mii_info); - - /* Determines the negotiated speed and duplex */ - int (*read_status)(struct gfar_mii_info *mii_info); - - /* Clears any pending interrupts */ - int (*ack_interrupt)(struct gfar_mii_info *mii_info); - - /* Enables or disables interrupts */ - int (*config_intr)(struct gfar_mii_info *mii_info); - - /* Clears up any memory if needed */ - void (*close)(struct gfar_mii_info *mii_info); -}; - -struct phy_info *get_phy_info(struct gfar_mii_info *mii_info); -int read_phy_reg(struct net_device *dev, int mii_id, int regnum); -void write_phy_reg(struct net_device *dev, int mii_id, int regnum, int value); -void mii_clear_phy_interrupt(struct gfar_mii_info *mii_info); -void mii_configure_phy_interrupt(struct gfar_mii_info *mii_info, u32 interrupts); - -struct dm9161_private { - struct timer_list timer; - int resetdone; -}; - -#endif /* GIANFAR_PHY_H */ diff --git a/drivers/net/hamradio/Kconfig b/drivers/net/hamradio/Kconfig index de087cd609d9..896aa02000d7 100644 --- a/drivers/net/hamradio/Kconfig +++ b/drivers/net/hamradio/Kconfig @@ -1,6 +1,7 @@ config MKISS tristate "Serial port KISS driver" depends on AX25 + select CRC16 ---help--- KISS is a protocol used for the exchange of data between a computer and a Terminal Node Controller (a small embedded system commonly diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c index 1756f0ed54cc..cb43a9d28774 100644 --- a/drivers/net/hamradio/bpqether.c +++ b/drivers/net/hamradio/bpqether.c @@ -144,7 +144,7 @@ static inline struct net_device *bpq_get_ax25_dev(struct net_device *dev) { struct bpqdev *bpq; - list_for_each_entry(bpq, &bpq_devices, bpq_list) { + list_for_each_entry_rcu(bpq, &bpq_devices, bpq_list) { if (bpq->ethdev == dev) return bpq->axdev; } @@ -399,7 +399,7 @@ static void *bpq_seq_start(struct seq_file *seq, loff_t *pos) if (*pos == 0) return SEQ_START_TOKEN; - list_for_each_entry(bpqdev, &bpq_devices, bpq_list) { + list_for_each_entry_rcu(bpqdev, &bpq_devices, bpq_list) { if (i == *pos) return bpqdev; } @@ -418,7 +418,7 @@ static void *bpq_seq_next(struct seq_file *seq, void *v, loff_t *pos) p = ((struct bpqdev *)v)->bpq_list.next; return (p == &bpq_devices) ? NULL - : list_entry(p, struct bpqdev, bpq_list); + : rcu_dereference(list_entry(p, struct bpqdev, bpq_list)); } static void bpq_seq_stop(struct seq_file *seq, void *v) @@ -561,8 +561,6 @@ static int bpq_device_event(struct notifier_block *this,unsigned long event, voi if (!dev_is_ethdev(dev)) return NOTIFY_DONE; - rcu_read_lock(); - switch (event) { case NETDEV_UP: /* new ethernet device -> new BPQ interface */ if (bpq_get_ax25_dev(dev) == NULL) @@ -581,7 +579,6 @@ static int bpq_device_event(struct notifier_block *this,unsigned long event, voi default: break; } - rcu_read_unlock(); return NOTIFY_DONE; } diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c index d9fe64b46f4b..3e9accf137e7 100644 --- a/drivers/net/hamradio/mkiss.c +++ b/drivers/net/hamradio/mkiss.c @@ -14,13 +14,14 @@ * * Copyright (C) Hans Alblas PE1AYX <hans@esrac.ele.tue.nl> * Copyright (C) 2004, 05 Ralf Baechle DL5RB <ralf@linux-mips.org> + * Copyright (C) 2004, 05 Thomas Osterried DL9SAU <thomas@x-berg.in-berlin.de> */ - #include <linux/config.h> #include <linux/module.h> #include <asm/system.h> #include <linux/bitops.h> #include <asm/uaccess.h> +#include <linux/crc16.h> #include <linux/string.h> #include <linux/mm.h> #include <linux/interrupt.h> @@ -39,11 +40,6 @@ #include <net/ax25.h> -#ifdef CONFIG_INET -#include <linux/ip.h> -#include <linux/tcp.h> -#endif - #define AX_MTU 236 /* SLIP/KISS protocol characters. */ @@ -80,9 +76,13 @@ struct mkiss { int mode; int crcmode; /* MW: for FlexNet, SMACK etc. */ -#define CRC_MODE_NONE 0 -#define CRC_MODE_FLEX 1 -#define CRC_MODE_SMACK 2 + int crcauto; /* CRC auto mode */ + +#define CRC_MODE_NONE 0 +#define CRC_MODE_FLEX 1 +#define CRC_MODE_SMACK 2 +#define CRC_MODE_FLEX_TEST 3 +#define CRC_MODE_SMACK_TEST 4 atomic_t refcnt; struct semaphore dead_sem; @@ -151,6 +151,21 @@ static int check_crc_flex(unsigned char *cp, int size) return 0; } +static int check_crc_16(unsigned char *cp, int size) +{ + unsigned short crc = 0x0000; + + if (size < 3) + return -1; + + crc = crc16(0, cp, size); + + if (crc != 0x0000) + return -1; + + return 0; +} + /* * Standard encapsulation */ @@ -237,19 +252,42 @@ static void ax_bump(struct mkiss *ax) spin_lock_bh(&ax->buflock); if (ax->rbuff[0] > 0x0f) { - if (ax->rbuff[0] & 0x20) { - ax->crcmode = CRC_MODE_FLEX; + if (ax->rbuff[0] & 0x80) { + if (check_crc_16(ax->rbuff, ax->rcount) < 0) { + ax->stats.rx_errors++; + spin_unlock_bh(&ax->buflock); + + return; + } + if (ax->crcmode != CRC_MODE_SMACK && ax->crcauto) { + printk(KERN_INFO + "mkiss: %s: Switchting to crc-smack\n", + ax->dev->name); + ax->crcmode = CRC_MODE_SMACK; + } + ax->rcount -= 2; + *ax->rbuff &= ~0x80; + } else if (ax->rbuff[0] & 0x20) { if (check_crc_flex(ax->rbuff, ax->rcount) < 0) { - ax->stats.rx_errors++; + ax->stats.rx_errors++; + spin_unlock_bh(&ax->buflock); return; } + if (ax->crcmode != CRC_MODE_FLEX && ax->crcauto) { + printk(KERN_INFO + "mkiss: %s: Switchting to crc-flexnet\n", + ax->dev->name); + ax->crcmode = CRC_MODE_FLEX; + } ax->rcount -= 2; - /* dl9sau bugfix: the trailling two bytes flexnet crc - * will not be passed to the kernel. thus we have - * to correct the kissparm signature, because it - * indicates a crc but there's none + + /* + * dl9sau bugfix: the trailling two bytes flexnet crc + * will not be passed to the kernel. thus we have to + * correct the kissparm signature, because it indicates + * a crc but there's none */ - *ax->rbuff &= ~0x20; + *ax->rbuff &= ~0x20; } } spin_unlock_bh(&ax->buflock); @@ -352,10 +390,8 @@ static void ax_changedmtu(struct mkiss *ax) "MTU change cancelled.\n", ax->dev->name); dev->mtu = ax->mtu; - if (xbuff != NULL) - kfree(xbuff); - if (rbuff != NULL) - kfree(rbuff); + kfree(xbuff); + kfree(rbuff); return; } @@ -417,20 +453,69 @@ static void ax_encaps(struct net_device *dev, unsigned char *icp, int len) p = icp; spin_lock_bh(&ax->buflock); - switch (ax->crcmode) { - unsigned short crc; + if ((*p & 0x0f) != 0) { + /* Configuration Command (kissparms(1). + * Protocol spec says: never append CRC. + * This fixes a very old bug in the linux + * kiss driver. -- dl9sau */ + switch (*p & 0xff) { + case 0x85: + /* command from userspace especially for us, + * not for delivery to the tnc */ + if (len > 1) { + int cmd = (p[1] & 0xff); + switch(cmd) { + case 3: + ax->crcmode = CRC_MODE_SMACK; + break; + case 2: + ax->crcmode = CRC_MODE_FLEX; + break; + case 1: + ax->crcmode = CRC_MODE_NONE; + break; + case 0: + default: + ax->crcmode = CRC_MODE_SMACK_TEST; + cmd = 0; + } + ax->crcauto = (cmd ? 0 : 1); + printk(KERN_INFO "mkiss: %s: crc mode %s %d\n", ax->dev->name, (len) ? "set to" : "is", cmd); + } + spin_unlock_bh(&ax->buflock); + netif_start_queue(dev); - case CRC_MODE_FLEX: - *p |= 0x20; - crc = calc_crc_flex(p, len); - count = kiss_esc_crc(p, (unsigned char *)ax->xbuff, crc, len+2); - break; + return; + default: + count = kiss_esc(p, (unsigned char *)ax->xbuff, len); + } + } else { + unsigned short crc; + switch (ax->crcmode) { + case CRC_MODE_SMACK_TEST: + ax->crcmode = CRC_MODE_FLEX_TEST; + printk(KERN_INFO "mkiss: %s: Trying crc-smack\n", ax->dev->name); + // fall through + case CRC_MODE_SMACK: + *p |= 0x80; + crc = swab16(crc16(0, p, len)); + count = kiss_esc_crc(p, (unsigned char *)ax->xbuff, crc, len+2); + break; + case CRC_MODE_FLEX_TEST: + ax->crcmode = CRC_MODE_NONE; + printk(KERN_INFO "mkiss: %s: Trying crc-flexnet\n", ax->dev->name); + // fall through + case CRC_MODE_FLEX: + *p |= 0x20; + crc = calc_crc_flex(p, len); + count = kiss_esc_crc(p, (unsigned char *)ax->xbuff, crc, len+2); + break; + + default: + count = kiss_esc(p, (unsigned char *)ax->xbuff, len); + } + } - default: - count = kiss_esc(p, (unsigned char *)ax->xbuff, len); - break; - } - set_bit(TTY_DO_WRITE_WAKEUP, &ax->tty->flags); actual = ax->tty->driver->write(ax->tty, ax->xbuff, count); ax->stats.tx_packets++; @@ -439,8 +524,6 @@ static void ax_encaps(struct net_device *dev, unsigned char *icp, int len) ax->dev->trans_start = jiffies; ax->xleft = count - actual; ax->xhead = ax->xbuff + actual; - - spin_unlock_bh(&ax->buflock); } /* Encapsulate an AX.25 packet and kick it into a TTY queue. */ @@ -622,7 +705,7 @@ static void ax_setup(struct net_device *dev) * best way to fix this is to use a rwlock in the tty struct, but for now we * use a single global rwlock for all ttys in ppp line discipline. */ -static rwlock_t disc_data_lock = RW_LOCK_UNLOCKED; +static DEFINE_RWLOCK(disc_data_lock); static struct mkiss *mkiss_get(struct tty_struct *tty) { @@ -643,6 +726,8 @@ static void mkiss_put(struct mkiss *ax) up(&ax->dead_sem); } +static int crc_force = 0; /* Can be overridden with insmod */ + static int mkiss_open(struct tty_struct *tty) { struct net_device *dev; @@ -682,6 +767,33 @@ static int mkiss_open(struct tty_struct *tty) if (register_netdev(dev)) goto out_free_buffers; + /* after register_netdev() - because else printk smashes the kernel */ + switch (crc_force) { + case 3: + ax->crcmode = CRC_MODE_SMACK; + printk(KERN_INFO "mkiss: %s: crc mode smack forced.\n", + ax->dev->name); + break; + case 2: + ax->crcmode = CRC_MODE_FLEX; + printk(KERN_INFO "mkiss: %s: crc mode flexnet forced.\n", + ax->dev->name); + break; + case 1: + ax->crcmode = CRC_MODE_NONE; + printk(KERN_INFO "mkiss: %s: crc mode disabled.\n", + ax->dev->name); + break; + case 0: + /* fall through */ + default: + crc_force = 0; + printk(KERN_INFO "mkiss: %s: crc mode is auto.\n", + ax->dev->name); + ax->crcmode = CRC_MODE_SMACK_TEST; + } + ax->crcauto = (crc_force ? 0 : 1); + netif_start_queue(dev); /* Done. We have linked the TTY line to a channel. */ @@ -765,7 +877,6 @@ static int mkiss_ioctl(struct tty_struct *tty, struct file *file, case SIOCSIFHWADDR: { char addr[AX25_ADDR_LEN]; -printk(KERN_INFO "In SIOCSIFHWADDR"); if (copy_from_user(&addr, (void __user *) arg, AX25_ADDR_LEN)) { @@ -864,6 +975,7 @@ out: } static struct tty_ldisc ax_ldisc = { + .owner = THIS_MODULE, .magic = TTY_LDISC_MAGIC, .name = "mkiss", .open = mkiss_open, @@ -904,6 +1016,8 @@ static void __exit mkiss_exit_driver(void) MODULE_AUTHOR("Ralf Baechle DL5RB <ralf@linux-mips.org>"); MODULE_DESCRIPTION("KISS driver for AX.25 over TTYs"); +MODULE_PARM(crc_force, "i"); +MODULE_PARM_DESC(crc_force, "crc [0 = auto | 1 = none | 2 = flexnet | 3 = smack]"); MODULE_LICENSE("GPL"); MODULE_ALIAS_LDISC(N_AX25); diff --git a/drivers/net/hamradio/mkiss.h b/drivers/net/hamradio/mkiss.h deleted file mode 100644 index 4ab700478598..000000000000 --- a/drivers/net/hamradio/mkiss.h +++ /dev/null @@ -1,62 +0,0 @@ -/**************************************************************************** - * Defines for the Multi-KISS driver. - ****************************************************************************/ - -#define AX25_MAXDEV 16 /* MAX number of AX25 channels; - This can be overridden with - insmod -oax25_maxdev=nnn */ -#define AX_MTU 236 - -/* SLIP/KISS protocol characters. */ -#define END 0300 /* indicates end of frame */ -#define ESC 0333 /* indicates byte stuffing */ -#define ESC_END 0334 /* ESC ESC_END means END 'data' */ -#define ESC_ESC 0335 /* ESC ESC_ESC means ESC 'data' */ - -struct ax_disp { - int magic; - - /* Various fields. */ - struct tty_struct *tty; /* ptr to TTY structure */ - struct net_device *dev; /* easy for intr handling */ - - /* These are pointers to the malloc()ed frame buffers. */ - unsigned char *rbuff; /* receiver buffer */ - int rcount; /* received chars counter */ - unsigned char *xbuff; /* transmitter buffer */ - unsigned char *xhead; /* pointer to next byte to XMIT */ - int xleft; /* bytes left in XMIT queue */ - - /* SLIP interface statistics. */ - unsigned long rx_packets; /* inbound frames counter */ - unsigned long tx_packets; /* outbound frames counter */ - unsigned long rx_bytes; /* inbound bytes counter */ - unsigned long tx_bytes; /* outbound bytes counter */ - unsigned long rx_errors; /* Parity, etc. errors */ - unsigned long tx_errors; /* Planned stuff */ - unsigned long rx_dropped; /* No memory for skb */ - unsigned long tx_dropped; /* When MTU change */ - unsigned long rx_over_errors; /* Frame bigger then SLIP buf. */ - - /* Detailed SLIP statistics. */ - int mtu; /* Our mtu (to spot changes!) */ - int buffsize; /* Max buffers sizes */ - - - unsigned long flags; /* Flag values/ mode etc */ - /* long req'd: used by set_bit --RR */ -#define AXF_INUSE 0 /* Channel in use */ -#define AXF_ESCAPE 1 /* ESC received */ -#define AXF_ERROR 2 /* Parity, etc. error */ -#define AXF_KEEPTEST 3 /* Keepalive test flag */ -#define AXF_OUTWAIT 4 /* is outpacket was flag */ - - int mode; - int crcmode; /* MW: for FlexNet, SMACK etc. */ -#define CRC_MODE_NONE 0 -#define CRC_MODE_FLEX 1 -#define CRC_MODE_SMACK 2 - spinlock_t buflock; /* lock for rbuf and xbuf */ -}; - -#define AX25_MAGIC 0x5316 diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c index cf0ac6fda1a1..b71fab6e34f4 100644 --- a/drivers/net/hp100.c +++ b/drivers/net/hp100.c @@ -2517,10 +2517,8 @@ static int hp100_down_vg_link(struct net_device *dev) do { if (hp100_inb(VG_LAN_CFG_1) & HP100_LINK_CABLE_ST) break; - if (!in_interrupt()) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); - } + if (!in_interrupt()) + schedule_timeout_interruptible(1); } while (time_after(time, jiffies)); if (time_after_eq(jiffies, time)) /* no signal->no logout */ @@ -2536,10 +2534,8 @@ static int hp100_down_vg_link(struct net_device *dev) do { if (!(hp100_inb(VG_LAN_CFG_1) & HP100_LINK_UP_ST)) break; - if (!in_interrupt()) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); - } + if (!in_interrupt()) + schedule_timeout_interruptible(1); } while (time_after(time, jiffies)); #ifdef HP100_DEBUG @@ -2577,10 +2573,8 @@ static int hp100_down_vg_link(struct net_device *dev) do { if (!(hp100_inb(MAC_CFG_4) & HP100_MAC_SEL_ST)) break; - if (!in_interrupt()) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); - } + if (!in_interrupt()) + schedule_timeout_interruptible(1); } while (time_after(time, jiffies)); hp100_orb(HP100_AUTO_MODE, MAC_CFG_3); /* Autosel back on */ @@ -2591,10 +2585,8 @@ static int hp100_down_vg_link(struct net_device *dev) do { if ((hp100_inb(VG_LAN_CFG_1) & HP100_LINK_CABLE_ST) == 0) break; - if (!in_interrupt()) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); - } + if (!in_interrupt()) + schedule_timeout_interruptible(1); } while (time_after(time, jiffies)); if (time_before_eq(time, jiffies)) { @@ -2606,10 +2598,8 @@ static int hp100_down_vg_link(struct net_device *dev) time = jiffies + (2 * HZ); /* This seems to take a while.... */ do { - if (!in_interrupt()) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); - } + if (!in_interrupt()) + schedule_timeout_interruptible(1); } while (time_after(time, jiffies)); return 0; @@ -2659,10 +2649,8 @@ static int hp100_login_to_vg_hub(struct net_device *dev, u_short force_relogin) do { if (~(hp100_inb(VG_LAN_CFG_1) & HP100_LINK_UP_ST)) break; - if (!in_interrupt()) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); - } + if (!in_interrupt()) + schedule_timeout_interruptible(1); } while (time_after(time, jiffies)); /* Start an addressed training and optionally request promiscuous port */ @@ -2697,10 +2685,8 @@ static int hp100_login_to_vg_hub(struct net_device *dev, u_short force_relogin) do { if (hp100_inb(VG_LAN_CFG_1) & HP100_LINK_CABLE_ST) break; - if (!in_interrupt()) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); - } + if (!in_interrupt()) + schedule_timeout_interruptible(1); } while (time_before(jiffies, time)); if (time_after_eq(jiffies, time)) { @@ -2723,10 +2709,8 @@ static int hp100_login_to_vg_hub(struct net_device *dev, u_short force_relogin) #endif break; } - if (!in_interrupt()) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); - } + if (!in_interrupt()) + schedule_timeout_interruptible(1); } while (time_after(time, jiffies)); } diff --git a/drivers/net/ibm_emac/Makefile b/drivers/net/ibm_emac/Makefile index 7f583a333c24..f98ddf0e807a 100644 --- a/drivers/net/ibm_emac/Makefile +++ b/drivers/net/ibm_emac/Makefile @@ -1,12 +1,11 @@ # -# Makefile for the IBM PPC4xx EMAC controllers +# Makefile for the PowerPC 4xx on-chip ethernet driver # obj-$(CONFIG_IBM_EMAC) += ibm_emac.o -ibm_emac-objs := ibm_emac_mal.o ibm_emac_core.o ibm_emac_phy.o - -# Only need this if you want to see additional debug messages -ifeq ($(CONFIG_IBM_EMAC_ERRMSG), y) -ibm_emac-objs += ibm_emac_debug.o -endif +ibm_emac-objs := ibm_emac_mal.o ibm_emac_core.o ibm_emac_phy.o +ibm_emac-$(CONFIG_IBM_EMAC_ZMII) += ibm_emac_zmii.o +ibm_emac-$(CONFIG_IBM_EMAC_RGMII) += ibm_emac_rgmii.o +ibm_emac-$(CONFIG_IBM_EMAC_TAH) += ibm_emac_tah.o +ibm_emac-$(CONFIG_IBM_EMAC_DEBUG) += ibm_emac_debug.o diff --git a/drivers/net/ibm_emac/ibm_emac.h b/drivers/net/ibm_emac/ibm_emac.h index 15d5a0e82862..28c476f28c20 100644 --- a/drivers/net/ibm_emac/ibm_emac.h +++ b/drivers/net/ibm_emac/ibm_emac.h @@ -1,110 +1,142 @@ /* - * ibm_emac.h + * drivers/net/ibm_emac/ibm_emac.h * + * Register definitions for PowerPC 4xx on-chip ethernet contoller * - * Armin Kuster akuster@mvista.com - * June, 2002 + * Copyright (c) 2004, 2005 Zultys Technologies. + * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net> * - * Copyright 2002 MontaVista Softare Inc. + * Based on original work by + * Matt Porter <mporter@kernel.crashing.org> + * Armin Kuster <akuster@mvista.com> + * Copyright 2002-2004 MontaVista Software Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. + * */ +#ifndef __IBM_EMAC_H_ +#define __IBM_EMAC_H_ + +#include <linux/config.h> +#include <linux/types.h> + +/* This is a simple check to prevent use of this driver on non-tested SoCs */ +#if !defined(CONFIG_405GP) && !defined(CONFIG_405GPR) && !defined(CONFIG_405EP) && \ + !defined(CONFIG_440GP) && !defined(CONFIG_440GX) && !defined(CONFIG_440SP) && \ + !defined(CONFIG_440EP) && !defined(CONFIG_NP405H) +#error "Unknown SoC. Please, check chip user manual and make sure EMAC defines are OK" +#endif + +/* EMAC registers Write Access rules */ +struct emac_regs { + u32 mr0; /* special */ + u32 mr1; /* Reset */ + u32 tmr0; /* special */ + u32 tmr1; /* special */ + u32 rmr; /* Reset */ + u32 isr; /* Always */ + u32 iser; /* Reset */ + u32 iahr; /* Reset, R, T */ + u32 ialr; /* Reset, R, T */ + u32 vtpid; /* Reset, R, T */ + u32 vtci; /* Reset, R, T */ + u32 ptr; /* Reset, T */ + u32 iaht1; /* Reset, R */ + u32 iaht2; /* Reset, R */ + u32 iaht3; /* Reset, R */ + u32 iaht4; /* Reset, R */ + u32 gaht1; /* Reset, R */ + u32 gaht2; /* Reset, R */ + u32 gaht3; /* Reset, R */ + u32 gaht4; /* Reset, R */ + u32 lsah; + u32 lsal; + u32 ipgvr; /* Reset, T */ + u32 stacr; /* special */ + u32 trtr; /* special */ + u32 rwmr; /* Reset */ + u32 octx; + u32 ocrx; + u32 ipcr; +}; + +#if !defined(CONFIG_IBM_EMAC4) +#define EMAC_ETHTOOL_REGS_VER 0 +#define EMAC_ETHTOOL_REGS_SIZE (sizeof(struct emac_regs) - sizeof(u32)) +#else +#define EMAC_ETHTOOL_REGS_VER 1 +#define EMAC_ETHTOOL_REGS_SIZE sizeof(struct emac_regs) +#endif -#ifndef _IBM_EMAC_H_ -#define _IBM_EMAC_H_ -/* General defines needed for the driver */ +/* EMACx_MR0 */ +#define EMAC_MR0_RXI 0x80000000 +#define EMAC_MR0_TXI 0x40000000 +#define EMAC_MR0_SRST 0x20000000 +#define EMAC_MR0_TXE 0x10000000 +#define EMAC_MR0_RXE 0x08000000 +#define EMAC_MR0_WKE 0x04000000 -/* Emac */ -typedef struct emac_regs { - u32 em0mr0; - u32 em0mr1; - u32 em0tmr0; - u32 em0tmr1; - u32 em0rmr; - u32 em0isr; - u32 em0iser; - u32 em0iahr; - u32 em0ialr; - u32 em0vtpid; - u32 em0vtci; - u32 em0ptr; - u32 em0iaht1; - u32 em0iaht2; - u32 em0iaht3; - u32 em0iaht4; - u32 em0gaht1; - u32 em0gaht2; - u32 em0gaht3; - u32 em0gaht4; - u32 em0lsah; - u32 em0lsal; - u32 em0ipgvr; - u32 em0stacr; - u32 em0trtr; - u32 em0rwmr; -} emac_t; +/* EMACx_MR1 */ +#define EMAC_MR1_FDE 0x80000000 +#define EMAC_MR1_ILE 0x40000000 +#define EMAC_MR1_VLE 0x20000000 +#define EMAC_MR1_EIFC 0x10000000 +#define EMAC_MR1_APP 0x08000000 +#define EMAC_MR1_IST 0x01000000 -/* MODE REG 0 */ -#define EMAC_M0_RXI 0x80000000 -#define EMAC_M0_TXI 0x40000000 -#define EMAC_M0_SRST 0x20000000 -#define EMAC_M0_TXE 0x10000000 -#define EMAC_M0_RXE 0x08000000 -#define EMAC_M0_WKE 0x04000000 +#define EMAC_MR1_MF_MASK 0x00c00000 +#define EMAC_MR1_MF_10 0x00000000 +#define EMAC_MR1_MF_100 0x00400000 +#if !defined(CONFIG_IBM_EMAC4) +#define EMAC_MR1_MF_1000 0x00000000 +#define EMAC_MR1_MF_1000GPCS 0x00000000 +#define EMAC_MR1_MF_IPPA(id) 0x00000000 +#else +#define EMAC_MR1_MF_1000 0x00800000 +#define EMAC_MR1_MF_1000GPCS 0x00c00000 +#define EMAC_MR1_MF_IPPA(id) (((id) & 0x1f) << 6) +#endif -/* MODE Reg 1 */ -#define EMAC_M1_FDE 0x80000000 -#define EMAC_M1_ILE 0x40000000 -#define EMAC_M1_VLE 0x20000000 -#define EMAC_M1_EIFC 0x10000000 -#define EMAC_M1_APP 0x08000000 -#define EMAC_M1_AEMI 0x02000000 -#define EMAC_M1_IST 0x01000000 -#define EMAC_M1_MF_1000GPCS 0x00c00000 /* Internal GPCS */ -#define EMAC_M1_MF_1000MBPS 0x00800000 /* External GPCS */ -#define EMAC_M1_MF_100MBPS 0x00400000 -#define EMAC_M1_RFS_16K 0x00280000 /* 000 for 512 byte */ -#define EMAC_M1_TR 0x00008000 -#ifdef CONFIG_IBM_EMAC4 -#define EMAC_M1_RFS_8K 0x00200000 -#define EMAC_M1_RFS_4K 0x00180000 -#define EMAC_M1_RFS_2K 0x00100000 -#define EMAC_M1_RFS_1K 0x00080000 -#define EMAC_M1_TX_FIFO_16K 0x00050000 /* 0's for 512 byte */ -#define EMAC_M1_TX_FIFO_8K 0x00040000 -#define EMAC_M1_TX_FIFO_4K 0x00030000 -#define EMAC_M1_TX_FIFO_2K 0x00020000 -#define EMAC_M1_TX_FIFO_1K 0x00010000 -#define EMAC_M1_TX_TR 0x00008000 -#define EMAC_M1_TX_MWSW 0x00001000 /* 0 wait for status */ -#define EMAC_M1_JUMBO_ENABLE 0x00000800 /* Upt to 9Kr status */ -#define EMAC_M1_OPB_CLK_66 0x00000008 /* 66Mhz */ -#define EMAC_M1_OPB_CLK_83 0x00000010 /* 83Mhz */ -#define EMAC_M1_OPB_CLK_100 0x00000018 /* 100Mhz */ -#define EMAC_M1_OPB_CLK_100P 0x00000020 /* 100Mhz+ */ -#else /* CONFIG_IBM_EMAC4 */ -#define EMAC_M1_RFS_4K 0x00300000 /* ~4k for 512 byte */ -#define EMAC_M1_RFS_2K 0x00200000 -#define EMAC_M1_RFS_1K 0x00100000 -#define EMAC_M1_TX_FIFO_2K 0x00080000 /* 0's for 512 byte */ -#define EMAC_M1_TX_FIFO_1K 0x00040000 -#define EMAC_M1_TR0_DEPEND 0x00010000 /* 0'x for single packet */ -#define EMAC_M1_TR1_DEPEND 0x00004000 -#define EMAC_M1_TR1_MULTI 0x00002000 -#define EMAC_M1_JUMBO_ENABLE 0x00001000 -#endif /* CONFIG_IBM_EMAC4 */ -#define EMAC_M1_BASE (EMAC_M1_TX_FIFO_2K | \ - EMAC_M1_APP | \ - EMAC_M1_TR | EMAC_M1_VLE) +#define EMAC_TX_FIFO_SIZE 2048 -/* Transmit Mode Register 0 */ -#define EMAC_TMR0_GNP0 0x80000000 -#define EMAC_TMR0_GNP1 0x40000000 -#define EMAC_TMR0_GNPD 0x20000000 -#define EMAC_TMR0_FC 0x10000000 +#if !defined(CONFIG_IBM_EMAC4) +#define EMAC_MR1_RFS_4K 0x00300000 +#define EMAC_MR1_RFS_16K 0x00000000 +#define EMAC_RX_FIFO_SIZE(gige) 4096 +#define EMAC_MR1_TFS_2K 0x00080000 +#define EMAC_MR1_TR0_MULT 0x00008000 +#define EMAC_MR1_JPSM 0x00000000 +#define EMAC_MR1_BASE(opb) (EMAC_MR1_TFS_2K | EMAC_MR1_TR0_MULT) +#else +#define EMAC_MR1_RFS_4K 0x00180000 +#define EMAC_MR1_RFS_16K 0x00280000 +#define EMAC_RX_FIFO_SIZE(gige) ((gige) ? 16384 : 4096) +#define EMAC_MR1_TFS_2K 0x00020000 +#define EMAC_MR1_TR 0x00008000 +#define EMAC_MR1_MWSW_001 0x00001000 +#define EMAC_MR1_JPSM 0x00000800 +#define EMAC_MR1_OBCI_MASK 0x00000038 +#define EMAC_MR1_OBCI_50 0x00000000 +#define EMAC_MR1_OBCI_66 0x00000008 +#define EMAC_MR1_OBCI_83 0x00000010 +#define EMAC_MR1_OBCI_100 0x00000018 +#define EMAC_MR1_OBCI_100P 0x00000020 +#define EMAC_MR1_OBCI(freq) ((freq) <= 50 ? EMAC_MR1_OBCI_50 : \ + (freq) <= 66 ? EMAC_MR1_OBCI_66 : \ + (freq) <= 83 ? EMAC_MR1_OBCI_83 : \ + (freq) <= 100 ? EMAC_MR1_OBCI_100 : EMAC_MR1_OBCI_100P) +#define EMAC_MR1_BASE(opb) (EMAC_MR1_TFS_2K | EMAC_MR1_TR | \ + EMAC_MR1_MWSW_001 | EMAC_MR1_OBCI(opb)) +#endif + +/* EMACx_TMR0 */ +#define EMAC_TMR0_GNP 0x80000000 +#if !defined(CONFIG_IBM_EMAC4) +#define EMAC_TMR0_DEFAULT 0x00000000 +#else #define EMAC_TMR0_TFAE_2_32 0x00000001 #define EMAC_TMR0_TFAE_4_64 0x00000002 #define EMAC_TMR0_TFAE_8_128 0x00000003 @@ -112,14 +144,36 @@ typedef struct emac_regs { #define EMAC_TMR0_TFAE_32_512 0x00000005 #define EMAC_TMR0_TFAE_64_1024 0x00000006 #define EMAC_TMR0_TFAE_128_2048 0x00000007 +#define EMAC_TMR0_DEFAULT EMAC_TMR0_TFAE_2_32 +#endif +#define EMAC_TMR0_XMIT (EMAC_TMR0_GNP | EMAC_TMR0_DEFAULT) + +/* EMACx_TMR1 */ + +/* IBM manuals are not very clear here. + * This is my interpretation of how things are. --ebs + */ +#if defined(CONFIG_40x) +#define EMAC_FIFO_ENTRY_SIZE 8 +#define EMAC_MAL_BURST_SIZE (16 * 4) +#else +#define EMAC_FIFO_ENTRY_SIZE 16 +#define EMAC_MAL_BURST_SIZE (64 * 4) +#endif + +#if !defined(CONFIG_IBM_EMAC4) +#define EMAC_TMR1(l,h) (((l) << 27) | (((h) & 0xff) << 16)) +#else +#define EMAC_TMR1(l,h) (((l) << 27) | (((h) & 0x3ff) << 14)) +#endif -/* Receive Mode Register */ +/* EMACx_RMR */ #define EMAC_RMR_SP 0x80000000 #define EMAC_RMR_SFCS 0x40000000 -#define EMAC_RMR_ARRP 0x20000000 -#define EMAC_RMR_ARP 0x10000000 -#define EMAC_RMR_AROP 0x08000000 -#define EMAC_RMR_ARPI 0x04000000 +#define EMAC_RMR_RRP 0x20000000 +#define EMAC_RMR_RFP 0x10000000 +#define EMAC_RMR_ROP 0x08000000 +#define EMAC_RMR_RPIR 0x04000000 #define EMAC_RMR_PPP 0x02000000 #define EMAC_RMR_PME 0x01000000 #define EMAC_RMR_PMME 0x00800000 @@ -127,6 +181,9 @@ typedef struct emac_regs { #define EMAC_RMR_MIAE 0x00200000 #define EMAC_RMR_BAE 0x00100000 #define EMAC_RMR_MAE 0x00080000 +#if !defined(CONFIG_IBM_EMAC4) +#define EMAC_RMR_BASE 0x00000000 +#else #define EMAC_RMR_RFAF_2_32 0x00000001 #define EMAC_RMR_RFAF_4_64 0x00000002 #define EMAC_RMR_RFAF_8_128 0x00000003 @@ -134,9 +191,21 @@ typedef struct emac_regs { #define EMAC_RMR_RFAF_32_512 0x00000005 #define EMAC_RMR_RFAF_64_1024 0x00000006 #define EMAC_RMR_RFAF_128_2048 0x00000007 -#define EMAC_RMR_BASE (EMAC_RMR_IAE | EMAC_RMR_BAE) +#define EMAC_RMR_BASE EMAC_RMR_RFAF_128_2048 +#endif -/* Interrupt Status & enable Regs */ +/* EMACx_ISR & EMACx_ISER */ +#if !defined(CONFIG_IBM_EMAC4) +#define EMAC_ISR_TXPE 0x00000000 +#define EMAC_ISR_RXPE 0x00000000 +#define EMAC_ISR_TXUE 0x00000000 +#define EMAC_ISR_RXOE 0x00000000 +#else +#define EMAC_ISR_TXPE 0x20000000 +#define EMAC_ISR_RXPE 0x10000000 +#define EMAC_ISR_TXUE 0x08000000 +#define EMAC_ISR_RXOE 0x04000000 +#endif #define EMAC_ISR_OVR 0x02000000 #define EMAC_ISR_PP 0x01000000 #define EMAC_ISR_BP 0x00800000 @@ -147,53 +216,62 @@ typedef struct emac_regs { #define EMAC_ISR_PTLE 0x00040000 #define EMAC_ISR_ORE 0x00020000 #define EMAC_ISR_IRE 0x00010000 -#define EMAC_ISR_DBDM 0x00000200 -#define EMAC_ISR_DB0 0x00000100 -#define EMAC_ISR_SE0 0x00000080 -#define EMAC_ISR_TE0 0x00000040 -#define EMAC_ISR_DB1 0x00000020 -#define EMAC_ISR_SE1 0x00000010 -#define EMAC_ISR_TE1 0x00000008 +#define EMAC_ISR_SQE 0x00000080 +#define EMAC_ISR_TE 0x00000040 #define EMAC_ISR_MOS 0x00000002 #define EMAC_ISR_MOF 0x00000001 -/* STA CONTROL REG */ +/* EMACx_STACR */ +#define EMAC_STACR_PHYD_MASK 0xffff +#define EMAC_STACR_PHYD_SHIFT 16 #define EMAC_STACR_OC 0x00008000 #define EMAC_STACR_PHYE 0x00004000 -#define EMAC_STACR_WRITE 0x00002000 -#define EMAC_STACR_READ 0x00001000 -#define EMAC_STACR_CLK_83MHZ 0x00000800 /* 0's for 50Mhz */ -#define EMAC_STACR_CLK_66MHZ 0x00000400 -#define EMAC_STACR_CLK_100MHZ 0x00000C00 +#define EMAC_STACR_STAC_MASK 0x00003000 +#define EMAC_STACR_STAC_READ 0x00001000 +#define EMAC_STACR_STAC_WRITE 0x00002000 +#if !defined(CONFIG_IBM_EMAC4) +#define EMAC_STACR_OPBC_MASK 0x00000C00 +#define EMAC_STACR_OPBC_50 0x00000000 +#define EMAC_STACR_OPBC_66 0x00000400 +#define EMAC_STACR_OPBC_83 0x00000800 +#define EMAC_STACR_OPBC_100 0x00000C00 +#define EMAC_STACR_OPBC(freq) ((freq) <= 50 ? EMAC_STACR_OPBC_50 : \ + (freq) <= 66 ? EMAC_STACR_OPBC_66 : \ + (freq) <= 83 ? EMAC_STACR_OPBC_83 : EMAC_STACR_OPBC_100) +#define EMAC_STACR_BASE(opb) EMAC_STACR_OPBC(opb) +#else +#define EMAC_STACR_BASE(opb) 0x00000000 +#endif +#define EMAC_STACR_PCDA_MASK 0x1f +#define EMAC_STACR_PCDA_SHIFT 5 +#define EMAC_STACR_PRA_MASK 0x1f + +/* EMACx_TRTR */ +#if !defined(CONFIG_IBM_EMAC4) +#define EMAC_TRTR_SHIFT 27 +#else +#define EMAC_TRTR_SHIFT 24 +#endif +#define EMAC_TRTR(size) ((((size) >> 6) - 1) << EMAC_TRTR_SHIFT) -/* Transmit Request Threshold Register */ -#define EMAC_TRTR_1600 0x18000000 /* 0's for 64 Bytes */ -#define EMAC_TRTR_1024 0x0f000000 -#define EMAC_TRTR_512 0x07000000 -#define EMAC_TRTR_256 0x03000000 -#define EMAC_TRTR_192 0x10000000 -#define EMAC_TRTR_128 0x01000000 +/* EMACx_RWMR */ +#if !defined(CONFIG_IBM_EMAC4) +#define EMAC_RWMR(l,h) (((l) << 23) | ( ((h) & 0x1ff) << 7)) +#else +#define EMAC_RWMR(l,h) (((l) << 22) | ( ((h) & 0x3ff) << 6)) +#endif +/* EMAC specific TX descriptor control fields (write access) */ #define EMAC_TX_CTRL_GFCS 0x0200 #define EMAC_TX_CTRL_GP 0x0100 #define EMAC_TX_CTRL_ISA 0x0080 #define EMAC_TX_CTRL_RSA 0x0040 #define EMAC_TX_CTRL_IVT 0x0020 #define EMAC_TX_CTRL_RVT 0x0010 -#define EMAC_TX_CTRL_TAH_CSUM 0x000e /* TAH only */ -#define EMAC_TX_CTRL_TAH_SEG4 0x000a /* TAH only */ -#define EMAC_TX_CTRL_TAH_SEG3 0x0008 /* TAH only */ -#define EMAC_TX_CTRL_TAH_SEG2 0x0006 /* TAH only */ -#define EMAC_TX_CTRL_TAH_SEG1 0x0004 /* TAH only */ -#define EMAC_TX_CTRL_TAH_SEG0 0x0002 /* TAH only */ -#define EMAC_TX_CTRL_TAH_DIS 0x0000 /* TAH only */ +#define EMAC_TX_CTRL_TAH_CSUM 0x000e -#define EMAC_TX_CTRL_DFLT ( \ - MAL_TX_CTRL_INTR | EMAC_TX_CTRL_GFCS | EMAC_TX_CTRL_GP ) - -/* madmal transmit status / Control bits */ +/* EMAC specific TX descriptor status fields (read access) */ #define EMAC_TX_ST_BFCS 0x0200 -#define EMAC_TX_ST_BPP 0x0100 #define EMAC_TX_ST_LCS 0x0080 #define EMAC_TX_ST_ED 0x0040 #define EMAC_TX_ST_EC 0x0020 @@ -202,8 +280,16 @@ typedef struct emac_regs { #define EMAC_TX_ST_SC 0x0004 #define EMAC_TX_ST_UR 0x0002 #define EMAC_TX_ST_SQE 0x0001 +#if !defined(CONFIG_IBM_EMAC_TAH) +#define EMAC_IS_BAD_TX(v) ((v) & (EMAC_TX_ST_LCS | EMAC_TX_ST_ED | \ + EMAC_TX_ST_EC | EMAC_TX_ST_LC | \ + EMAC_TX_ST_MC | EMAC_TX_ST_UR)) +#else +#define EMAC_IS_BAD_TX(v) ((v) & (EMAC_TX_ST_LCS | EMAC_TX_ST_ED | \ + EMAC_TX_ST_EC | EMAC_TX_ST_LC)) +#endif -/* madmal receive status / Control bits */ +/* EMAC specific RX descriptor status fields (read access) */ #define EMAC_RX_ST_OE 0x0200 #define EMAC_RX_ST_PP 0x0100 #define EMAC_RX_ST_BP 0x0080 @@ -214,54 +300,10 @@ typedef struct emac_regs { #define EMAC_RX_ST_PTL 0x0004 #define EMAC_RX_ST_ORE 0x0002 #define EMAC_RX_ST_IRE 0x0001 -#define EMAC_BAD_RX_PACKET 0x02ff -#define EMAC_CSUM_VER_ERROR 0x0003 - -/* identify a bad rx packet dependent on emac features */ -#ifdef CONFIG_IBM_EMAC4 -#define EMAC_IS_BAD_RX_PACKET(desc) \ - (((desc & (EMAC_BAD_RX_PACKET & ~EMAC_CSUM_VER_ERROR)) || \ - ((desc & EMAC_CSUM_VER_ERROR) == EMAC_RX_ST_ORE) || \ - ((desc & EMAC_CSUM_VER_ERROR) == EMAC_RX_ST_IRE))) -#else -#define EMAC_IS_BAD_RX_PACKET(desc) \ - (desc & EMAC_BAD_RX_PACKET) -#endif - -/* SoC implementation specific EMAC register defaults */ -#if defined(CONFIG_440GP) -#define EMAC_RWMR_DEFAULT 0x80009000 -#define EMAC_TMR0_DEFAULT 0x00000000 -#define EMAC_TMR1_DEFAULT 0xf8640000 -#elif defined(CONFIG_440GX) -#define EMAC_RWMR_DEFAULT 0x1000a200 -#define EMAC_TMR0_DEFAULT EMAC_TMR0_TFAE_2_32 -#define EMAC_TMR1_DEFAULT 0xa00f0000 -#elif defined(CONFIG_440SP) -#define EMAC_RWMR_DEFAULT 0x08002000 -#define EMAC_TMR0_DEFAULT EMAC_TMR0_TFAE_128_2048 -#define EMAC_TMR1_DEFAULT 0xf8200000 -#else -#define EMAC_RWMR_DEFAULT 0x0f002000 -#define EMAC_TMR0_DEFAULT 0x00000000 -#define EMAC_TMR1_DEFAULT 0x380f0000 -#endif /* CONFIG_440GP */ - -/* Revision specific EMAC register defaults */ -#ifdef CONFIG_IBM_EMAC4 -#define EMAC_M1_DEFAULT (EMAC_M1_BASE | \ - EMAC_M1_OPB_CLK_83 | \ - EMAC_M1_TX_MWSW) -#define EMAC_RMR_DEFAULT (EMAC_RMR_BASE | \ - EMAC_RMR_RFAF_128_2048) -#define EMAC_TMR0_XMIT (EMAC_TMR0_GNP0 | \ - EMAC_TMR0_DEFAULT) -#define EMAC_TRTR_DEFAULT EMAC_TRTR_1024 -#else /* !CONFIG_IBM_EMAC4 */ -#define EMAC_M1_DEFAULT EMAC_M1_BASE -#define EMAC_RMR_DEFAULT EMAC_RMR_BASE -#define EMAC_TMR0_XMIT EMAC_TMR0_GNP0 -#define EMAC_TRTR_DEFAULT EMAC_TRTR_1600 -#endif /* CONFIG_IBM_EMAC4 */ - -#endif +#define EMAC_RX_TAH_BAD_CSUM 0x0003 +#define EMAC_BAD_RX_MASK (EMAC_RX_ST_OE | EMAC_RX_ST_BP | \ + EMAC_RX_ST_RP | EMAC_RX_ST_SE | \ + EMAC_RX_ST_AE | EMAC_RX_ST_BFCS | \ + EMAC_RX_ST_PTL | EMAC_RX_ST_ORE | \ + EMAC_RX_ST_IRE ) +#endif /* __IBM_EMAC_H_ */ diff --git a/drivers/net/ibm_emac/ibm_emac_core.c b/drivers/net/ibm_emac/ibm_emac_core.c index 14e9b6315f20..943fbd1546ff 100644 --- a/drivers/net/ibm_emac/ibm_emac_core.c +++ b/drivers/net/ibm_emac/ibm_emac_core.c @@ -1,13 +1,14 @@ /* - * ibm_emac_core.c + * drivers/net/ibm_emac/ibm_emac_core.c * - * Ethernet driver for the built in ethernet on the IBM 4xx PowerPC - * processors. - * - * (c) 2003 Benjamin Herrenschmidt <benh@kernel.crashing.org> + * Driver for PowerPC 4xx on-chip ethernet controller. * - * Based on original work by + * Copyright (c) 2004, 2005 Zultys Technologies. + * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net> * + * Based on original work by + * Matt Porter <mporter@kernel.crashing.org> + * (c) 2003 Benjamin Herrenschmidt <benh@kernel.crashing.org> * Armin Kuster <akuster@mvista.com> * Johnnie Peters <jpeters@mvista.com> * @@ -15,29 +16,24 @@ * 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. - * TODO - * - Check for races in the "remove" code path - * - Add some Power Management to the MAC and the PHY - * - Audit remaining of non-rewritten code (--BenH) - * - Cleanup message display using msglevel mecanism - * - Address all errata - * - Audit all register update paths to ensure they - * are being written post soft reset if required. + * */ + +#include <linux/config.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/sched.h> #include <linux/string.h> -#include <linux/timer.h> -#include <linux/ptrace.h> #include <linux/errno.h> -#include <linux/ioport.h> -#include <linux/slab.h> #include <linux/interrupt.h> #include <linux/delay.h> #include <linux/init.h> #include <linux/types.h> -#include <linux/dma-mapping.h> +#include <linux/pci.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/crc32.h> #include <linux/ethtool.h> #include <linux/mii.h> #include <linux/bitops.h> @@ -45,1691 +41,1893 @@ #include <asm/processor.h> #include <asm/io.h> #include <asm/dma.h> -#include <asm/irq.h> #include <asm/uaccess.h> #include <asm/ocp.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/skbuff.h> -#include <linux/crc32.h> - #include "ibm_emac_core.h" - -//#define MDIO_DEBUG(fmt) printk fmt -#define MDIO_DEBUG(fmt) - -//#define LINK_DEBUG(fmt) printk fmt -#define LINK_DEBUG(fmt) - -//#define PKT_DEBUG(fmt) printk fmt -#define PKT_DEBUG(fmt) - -#define DRV_NAME "emac" -#define DRV_VERSION "2.0" -#define DRV_AUTHOR "Benjamin Herrenschmidt <benh@kernel.crashing.org>" -#define DRV_DESC "IBM EMAC Ethernet driver" +#include "ibm_emac_debug.h" /* - * When mdio_idx >= 0, contains a list of emac ocp_devs - * that have had their initialization deferred until the - * common MDIO controller has been initialized. + * Lack of dma_unmap_???? calls is intentional. + * + * API-correct usage requires additional support state information to be + * maintained for every RX and TX buffer descriptor (BD). Unfortunately, due to + * EMAC design (e.g. TX buffer passed from network stack can be split into + * several BDs, dma_map_single/dma_map_page can be used to map particular BD), + * maintaining such information will add additional overhead. + * Current DMA API implementation for 4xx processors only ensures cache coherency + * and dma_unmap_???? routines are empty and are likely to stay this way. + * I decided to omit dma_unmap_??? calls because I don't want to add additional + * complexity just for the sake of following some abstract API, when it doesn't + * add any real benefit to the driver. I understand that this decision maybe + * controversial, but I really tried to make code API-correct and efficient + * at the same time and didn't come up with code I liked :(. --ebs */ -LIST_HEAD(emac_init_list); -MODULE_AUTHOR(DRV_AUTHOR); +#define DRV_NAME "emac" +#define DRV_VERSION "3.53" +#define DRV_DESC "PPC 4xx OCP EMAC driver" + MODULE_DESCRIPTION(DRV_DESC); +MODULE_AUTHOR + ("Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>"); MODULE_LICENSE("GPL"); -static int skb_res = SKB_RES; -module_param(skb_res, int, 0444); -MODULE_PARM_DESC(skb_res, "Amount of data to reserve on skb buffs\n" - "The 405 handles a misaligned IP header fine but\n" - "this can help if you are routing to a tunnel or a\n" - "device that needs aligned data. 0..2"); - -#define RGMII_PRIV(ocpdev) ((struct ibm_ocp_rgmii*)ocp_get_drvdata(ocpdev)) +/* minimum number of free TX descriptors required to wake up TX process */ +#define EMAC_TX_WAKEUP_THRESH (NUM_TX_BUFF / 4) -static unsigned int rgmii_enable[] = { - RGMII_RTBI, - RGMII_RGMII, - RGMII_TBI, - RGMII_GMII -}; +/* If packet size is less than this number, we allocate small skb and copy packet + * contents into it instead of just sending original big skb up + */ +#define EMAC_RX_COPY_THRESH CONFIG_IBM_EMAC_RX_COPY_THRESHOLD -static unsigned int rgmii_speed_mask[] = { - RGMII_MII2_SPDMASK, - RGMII_MII3_SPDMASK -}; +/* Since multiple EMACs share MDIO lines in various ways, we need + * to avoid re-using the same PHY ID in cases where the arch didn't + * setup precise phy_map entries + */ +static u32 busy_phy_map; -static unsigned int rgmii_speed100[] = { - RGMII_MII2_100MB, - RGMII_MII3_100MB -}; +#if defined(CONFIG_IBM_EMAC_PHY_RX_CLK_FIX) && (defined(CONFIG_405EP) || defined(CONFIG_440EP)) +/* 405EP has "EMAC to PHY Control Register" (CPC0_EPCTL) which can help us + * with PHY RX clock problem. + * 440EP has more sane SDR0_MFR register implementation than 440GX, which + * also allows controlling each EMAC clock + */ +static inline void EMAC_RX_CLK_TX(int idx) +{ + unsigned long flags; + local_irq_save(flags); -static unsigned int rgmii_speed1000[] = { - RGMII_MII2_1000MB, - RGMII_MII3_1000MB -}; +#if defined(CONFIG_405EP) + mtdcr(0xf3, mfdcr(0xf3) | (1 << idx)); +#else /* CONFIG_440EP */ + SDR_WRITE(DCRN_SDR_MFR, SDR_READ(DCRN_SDR_MFR) | (0x08000000 >> idx)); +#endif -#define ZMII_PRIV(ocpdev) ((struct ibm_ocp_zmii*)ocp_get_drvdata(ocpdev)) + local_irq_restore(flags); +} -static unsigned int zmii_enable[][4] = { - {ZMII_SMII0, ZMII_RMII0, ZMII_MII0, - ~(ZMII_MDI1 | ZMII_MDI2 | ZMII_MDI3)}, - {ZMII_SMII1, ZMII_RMII1, ZMII_MII1, - ~(ZMII_MDI0 | ZMII_MDI2 | ZMII_MDI3)}, - {ZMII_SMII2, ZMII_RMII2, ZMII_MII2, - ~(ZMII_MDI0 | ZMII_MDI1 | ZMII_MDI3)}, - {ZMII_SMII3, ZMII_RMII3, ZMII_MII3, ~(ZMII_MDI0 | ZMII_MDI1 | ZMII_MDI2)} -}; +static inline void EMAC_RX_CLK_DEFAULT(int idx) +{ + unsigned long flags; + local_irq_save(flags); -static unsigned int mdi_enable[] = { - ZMII_MDI0, - ZMII_MDI1, - ZMII_MDI2, - ZMII_MDI3 -}; +#if defined(CONFIG_405EP) + mtdcr(0xf3, mfdcr(0xf3) & ~(1 << idx)); +#else /* CONFIG_440EP */ + SDR_WRITE(DCRN_SDR_MFR, SDR_READ(DCRN_SDR_MFR) & ~(0x08000000 >> idx)); +#endif -static unsigned int zmii_speed = 0x0; -static unsigned int zmii_speed100[] = { - ZMII_MII0_100MB, - ZMII_MII1_100MB, - ZMII_MII2_100MB, - ZMII_MII3_100MB -}; + local_irq_restore(flags); +} +#else +#define EMAC_RX_CLK_TX(idx) ((void)0) +#define EMAC_RX_CLK_DEFAULT(idx) ((void)0) +#endif -/* Since multiple EMACs share MDIO lines in various ways, we need - * to avoid re-using the same PHY ID in cases where the arch didn't - * setup precise phy_map entries +#if defined(CONFIG_IBM_EMAC_PHY_RX_CLK_FIX) && defined(CONFIG_440GX) +/* We can switch Ethernet clock to the internal source through SDR0_MFR[ECS], + * unfortunately this is less flexible than 440EP case, because it's a global + * setting for all EMACs, therefore we do this clock trick only during probe. */ -static u32 busy_phy_map = 0; +#define EMAC_CLK_INTERNAL SDR_WRITE(DCRN_SDR_MFR, \ + SDR_READ(DCRN_SDR_MFR) | 0x08000000) +#define EMAC_CLK_EXTERNAL SDR_WRITE(DCRN_SDR_MFR, \ + SDR_READ(DCRN_SDR_MFR) & ~0x08000000) +#else +#define EMAC_CLK_INTERNAL ((void)0) +#define EMAC_CLK_EXTERNAL ((void)0) +#endif -/* If EMACs share a common MDIO device, this points to it */ -static struct net_device *mdio_ndev = NULL; +/* I don't want to litter system log with timeout errors + * when we have brain-damaged PHY. + */ +static inline void emac_report_timeout_error(struct ocp_enet_private *dev, + const char *error) +{ +#if defined(CONFIG_IBM_EMAC_PHY_RX_CLK_FIX) + DBG("%d: %s" NL, dev->def->index, error); +#else + if (net_ratelimit()) + printk(KERN_ERR "emac%d: %s\n", dev->def->index, error); +#endif +} -struct emac_def_dev { - struct list_head link; - struct ocp_device *ocpdev; - struct ibm_ocp_mal *mal; +/* PHY polling intervals */ +#define PHY_POLL_LINK_ON HZ +#define PHY_POLL_LINK_OFF (HZ / 5) + +/* Please, keep in sync with struct ibm_emac_stats/ibm_emac_error_stats */ +static const char emac_stats_keys[EMAC_ETHTOOL_STATS_COUNT][ETH_GSTRING_LEN] = { + "rx_packets", "rx_bytes", "tx_packets", "tx_bytes", "rx_packets_csum", + "tx_packets_csum", "tx_undo", "rx_dropped_stack", "rx_dropped_oom", + "rx_dropped_error", "rx_dropped_resize", "rx_dropped_mtu", + "rx_stopped", "rx_bd_errors", "rx_bd_overrun", "rx_bd_bad_packet", + "rx_bd_runt_packet", "rx_bd_short_event", "rx_bd_alignment_error", + "rx_bd_bad_fcs", "rx_bd_packet_too_long", "rx_bd_out_of_range", + "rx_bd_in_range", "rx_parity", "rx_fifo_overrun", "rx_overrun", + "rx_bad_packet", "rx_runt_packet", "rx_short_event", + "rx_alignment_error", "rx_bad_fcs", "rx_packet_too_long", + "rx_out_of_range", "rx_in_range", "tx_dropped", "tx_bd_errors", + "tx_bd_bad_fcs", "tx_bd_carrier_loss", "tx_bd_excessive_deferral", + "tx_bd_excessive_collisions", "tx_bd_late_collision", + "tx_bd_multple_collisions", "tx_bd_single_collision", + "tx_bd_underrun", "tx_bd_sqe", "tx_parity", "tx_underrun", "tx_sqe", + "tx_errors" }; -static struct net_device_stats *emac_stats(struct net_device *dev) +static irqreturn_t emac_irq(int irq, void *dev_instance, struct pt_regs *regs); +static void emac_clean_tx_ring(struct ocp_enet_private *dev); + +static inline int emac_phy_supports_gige(int phy_mode) { - struct ocp_enet_private *fep = dev->priv; - return &fep->stats; -}; + return phy_mode == PHY_MODE_GMII || + phy_mode == PHY_MODE_RGMII || + phy_mode == PHY_MODE_TBI || + phy_mode == PHY_MODE_RTBI; +} -static int -emac_init_rgmii(struct ocp_device *rgmii_dev, int input, int phy_mode) +static inline int emac_phy_gpcs(int phy_mode) { - struct ibm_ocp_rgmii *rgmii = RGMII_PRIV(rgmii_dev); - const char *mode_name[] = { "RTBI", "RGMII", "TBI", "GMII" }; - int mode = -1; + return phy_mode == PHY_MODE_TBI || + phy_mode == PHY_MODE_RTBI; +} - if (!rgmii) { - rgmii = kmalloc(sizeof(struct ibm_ocp_rgmii), GFP_KERNEL); +static inline void emac_tx_enable(struct ocp_enet_private *dev) +{ + struct emac_regs *p = dev->emacp; + unsigned long flags; + u32 r; - if (rgmii == NULL) { - printk(KERN_ERR - "rgmii%d: Out of memory allocating RGMII structure!\n", - rgmii_dev->def->index); - return -ENOMEM; - } + local_irq_save(flags); - memset(rgmii, 0, sizeof(*rgmii)); + DBG("%d: tx_enable" NL, dev->def->index); - rgmii->base = - (struct rgmii_regs *)ioremap(rgmii_dev->def->paddr, - sizeof(*rgmii->base)); - if (rgmii->base == NULL) { - printk(KERN_ERR - "rgmii%d: Cannot ioremap bridge registers!\n", - rgmii_dev->def->index); + r = in_be32(&p->mr0); + if (!(r & EMAC_MR0_TXE)) + out_be32(&p->mr0, r | EMAC_MR0_TXE); + local_irq_restore(flags); +} - kfree(rgmii); - return -ENOMEM; - } - ocp_set_drvdata(rgmii_dev, rgmii); - } +static void emac_tx_disable(struct ocp_enet_private *dev) +{ + struct emac_regs *p = dev->emacp; + unsigned long flags; + u32 r; - if (phy_mode) { - switch (phy_mode) { - case PHY_MODE_GMII: - mode = GMII; - break; - case PHY_MODE_TBI: - mode = TBI; - break; - case PHY_MODE_RTBI: - mode = RTBI; - break; - case PHY_MODE_RGMII: - default: - mode = RGMII; - } - rgmii->base->fer &= ~RGMII_FER_MASK(input); - rgmii->base->fer |= rgmii_enable[mode] << (4 * input); - } else { - switch ((rgmii->base->fer & RGMII_FER_MASK(input)) >> (4 * - input)) { - case RGMII_RTBI: - mode = RTBI; - break; - case RGMII_RGMII: - mode = RGMII; - break; - case RGMII_TBI: - mode = TBI; - break; - case RGMII_GMII: - mode = GMII; - } - } + local_irq_save(flags); + + DBG("%d: tx_disable" NL, dev->def->index); - /* Set mode to RGMII if nothing valid is detected */ - if (mode < 0) - mode = RGMII; + r = in_be32(&p->mr0); + if (r & EMAC_MR0_TXE) { + int n = 300; + out_be32(&p->mr0, r & ~EMAC_MR0_TXE); + while (!(in_be32(&p->mr0) & EMAC_MR0_TXI) && n) + --n; + if (unlikely(!n)) + emac_report_timeout_error(dev, "TX disable timeout"); + } + local_irq_restore(flags); +} - printk(KERN_NOTICE "rgmii%d: input %d in %s mode\n", - rgmii_dev->def->index, input, mode_name[mode]); +static void emac_rx_enable(struct ocp_enet_private *dev) +{ + struct emac_regs *p = dev->emacp; + unsigned long flags; + u32 r; - rgmii->mode[input] = mode; - rgmii->users++; + local_irq_save(flags); + if (unlikely(dev->commac.rx_stopped)) + goto out; - return 0; + DBG("%d: rx_enable" NL, dev->def->index); + + r = in_be32(&p->mr0); + if (!(r & EMAC_MR0_RXE)) { + if (unlikely(!(r & EMAC_MR0_RXI))) { + /* Wait if previous async disable is still in progress */ + int n = 100; + while (!(r = in_be32(&p->mr0) & EMAC_MR0_RXI) && n) + --n; + if (unlikely(!n)) + emac_report_timeout_error(dev, + "RX disable timeout"); + } + out_be32(&p->mr0, r | EMAC_MR0_RXE); + } + out: + local_irq_restore(flags); } -static void -emac_rgmii_port_speed(struct ocp_device *ocpdev, int input, int speed) +static void emac_rx_disable(struct ocp_enet_private *dev) { - struct ibm_ocp_rgmii *rgmii = RGMII_PRIV(ocpdev); - unsigned int rgmii_speed; - - rgmii_speed = in_be32(&rgmii->base->ssr); + struct emac_regs *p = dev->emacp; + unsigned long flags; + u32 r; - rgmii_speed &= ~rgmii_speed_mask[input]; + local_irq_save(flags); - if (speed == 1000) - rgmii_speed |= rgmii_speed1000[input]; - else if (speed == 100) - rgmii_speed |= rgmii_speed100[input]; + DBG("%d: rx_disable" NL, dev->def->index); - out_be32(&rgmii->base->ssr, rgmii_speed); + r = in_be32(&p->mr0); + if (r & EMAC_MR0_RXE) { + int n = 300; + out_be32(&p->mr0, r & ~EMAC_MR0_RXE); + while (!(in_be32(&p->mr0) & EMAC_MR0_RXI) && n) + --n; + if (unlikely(!n)) + emac_report_timeout_error(dev, "RX disable timeout"); + } + local_irq_restore(flags); } -static void emac_close_rgmii(struct ocp_device *ocpdev) +static inline void emac_rx_disable_async(struct ocp_enet_private *dev) { - struct ibm_ocp_rgmii *rgmii = RGMII_PRIV(ocpdev); - BUG_ON(!rgmii || rgmii->users == 0); + struct emac_regs *p = dev->emacp; + unsigned long flags; + u32 r; - if (!--rgmii->users) { - ocp_set_drvdata(ocpdev, NULL); - iounmap((void *)rgmii->base); - kfree(rgmii); - } + local_irq_save(flags); + + DBG("%d: rx_disable_async" NL, dev->def->index); + + r = in_be32(&p->mr0); + if (r & EMAC_MR0_RXE) + out_be32(&p->mr0, r & ~EMAC_MR0_RXE); + local_irq_restore(flags); } -static int emac_init_zmii(struct ocp_device *zmii_dev, int input, int phy_mode) +static int emac_reset(struct ocp_enet_private *dev) { - struct ibm_ocp_zmii *zmii = ZMII_PRIV(zmii_dev); - const char *mode_name[] = { "SMII", "RMII", "MII" }; - int mode = -1; + struct emac_regs *p = dev->emacp; + unsigned long flags; + int n = 20; - if (!zmii) { - zmii = kmalloc(sizeof(struct ibm_ocp_zmii), GFP_KERNEL); - if (zmii == NULL) { - printk(KERN_ERR - "zmii%d: Out of memory allocating ZMII structure!\n", - zmii_dev->def->index); - return -ENOMEM; - } - memset(zmii, 0, sizeof(*zmii)); + DBG("%d: reset" NL, dev->def->index); - zmii->base = - (struct zmii_regs *)ioremap(zmii_dev->def->paddr, - sizeof(*zmii->base)); - if (zmii->base == NULL) { - printk(KERN_ERR - "zmii%d: Cannot ioremap bridge registers!\n", - zmii_dev->def->index); + local_irq_save(flags); - kfree(zmii); - return -ENOMEM; - } - ocp_set_drvdata(zmii_dev, zmii); + if (!dev->reset_failed) { + /* 40x erratum suggests stopping RX channel before reset, + * we stop TX as well + */ + emac_rx_disable(dev); + emac_tx_disable(dev); } - if (phy_mode) { - switch (phy_mode) { - case PHY_MODE_MII: - mode = MII; - break; - case PHY_MODE_RMII: - mode = RMII; - break; - case PHY_MODE_SMII: - default: - mode = SMII; - } - zmii->base->fer &= ~ZMII_FER_MASK(input); - zmii->base->fer |= zmii_enable[input][mode]; + out_be32(&p->mr0, EMAC_MR0_SRST); + while ((in_be32(&p->mr0) & EMAC_MR0_SRST) && n) + --n; + local_irq_restore(flags); + + if (n) { + dev->reset_failed = 0; + return 0; } else { - switch ((zmii->base->fer & ZMII_FER_MASK(input)) << (4 * input)) { - case ZMII_MII0: - mode = MII; - break; - case ZMII_RMII0: - mode = RMII; - break; - case ZMII_SMII0: - mode = SMII; - } + emac_report_timeout_error(dev, "reset timeout"); + dev->reset_failed = 1; + return -ETIMEDOUT; } +} - /* Set mode to SMII if nothing valid is detected */ - if (mode < 0) - mode = SMII; +static void emac_hash_mc(struct ocp_enet_private *dev) +{ + struct emac_regs *p = dev->emacp; + u16 gaht[4] = { 0 }; + struct dev_mc_list *dmi; - printk(KERN_NOTICE "zmii%d: input %d in %s mode\n", - zmii_dev->def->index, input, mode_name[mode]); + DBG("%d: hash_mc %d" NL, dev->def->index, dev->ndev->mc_count); - zmii->mode[input] = mode; - zmii->users++; + for (dmi = dev->ndev->mc_list; dmi; dmi = dmi->next) { + int bit; + DBG2("%d: mc %02x:%02x:%02x:%02x:%02x:%02x" NL, + dev->def->index, + dmi->dmi_addr[0], dmi->dmi_addr[1], dmi->dmi_addr[2], + dmi->dmi_addr[3], dmi->dmi_addr[4], dmi->dmi_addr[5]); - return 0; + bit = 63 - (ether_crc(ETH_ALEN, dmi->dmi_addr) >> 26); + gaht[bit >> 4] |= 0x8000 >> (bit & 0x0f); + } + out_be32(&p->gaht1, gaht[0]); + out_be32(&p->gaht2, gaht[1]); + out_be32(&p->gaht3, gaht[2]); + out_be32(&p->gaht4, gaht[3]); } -static void emac_enable_zmii_port(struct ocp_device *ocpdev, int input) +static inline u32 emac_iff2rmr(struct net_device *ndev) { - u32 mask; - struct ibm_ocp_zmii *zmii = ZMII_PRIV(ocpdev); + u32 r = EMAC_RMR_SP | EMAC_RMR_SFCS | EMAC_RMR_IAE | EMAC_RMR_BAE | + EMAC_RMR_BASE; - mask = in_be32(&zmii->base->fer); - mask &= zmii_enable[input][MDI]; /* turn all non enabled MDI's off */ - mask |= zmii_enable[input][zmii->mode[input]] | mdi_enable[input]; - out_be32(&zmii->base->fer, mask); + if (ndev->flags & IFF_PROMISC) + r |= EMAC_RMR_PME; + else if (ndev->flags & IFF_ALLMULTI || ndev->mc_count > 32) + r |= EMAC_RMR_PMME; + else if (ndev->mc_count > 0) + r |= EMAC_RMR_MAE; + + return r; } -static void -emac_zmii_port_speed(struct ocp_device *ocpdev, int input, int speed) +static inline int emac_opb_mhz(void) { - struct ibm_ocp_zmii *zmii = ZMII_PRIV(ocpdev); - - if (speed == 100) - zmii_speed |= zmii_speed100[input]; - else - zmii_speed &= ~zmii_speed100[input]; - - out_be32(&zmii->base->ssr, zmii_speed); + return (ocp_sys_info.opb_bus_freq + 500000) / 1000000; } -static void emac_close_zmii(struct ocp_device *ocpdev) +/* BHs disabled */ +static int emac_configure(struct ocp_enet_private *dev) { - struct ibm_ocp_zmii *zmii = ZMII_PRIV(ocpdev); - BUG_ON(!zmii || zmii->users == 0); + struct emac_regs *p = dev->emacp; + struct net_device *ndev = dev->ndev; + int gige; + u32 r; - if (!--zmii->users) { - ocp_set_drvdata(ocpdev, NULL); - iounmap((void *)zmii->base); - kfree(zmii); - } -} + DBG("%d: configure" NL, dev->def->index); -int emac_phy_read(struct net_device *dev, int mii_id, int reg) -{ - int count; - uint32_t stacr; - struct ocp_enet_private *fep = dev->priv; - emac_t *emacp = fep->emacp; + if (emac_reset(dev) < 0) + return -ETIMEDOUT; - MDIO_DEBUG(("%s: phy_read, id: 0x%x, reg: 0x%x\n", dev->name, mii_id, - reg)); + tah_reset(dev->tah_dev); - /* Enable proper ZMII port */ - if (fep->zmii_dev) - emac_enable_zmii_port(fep->zmii_dev, fep->zmii_input); + /* Mode register */ + r = EMAC_MR1_BASE(emac_opb_mhz()) | EMAC_MR1_VLE | EMAC_MR1_IST; + if (dev->phy.duplex == DUPLEX_FULL) + r |= EMAC_MR1_FDE; + switch (dev->phy.speed) { + case SPEED_1000: + if (emac_phy_gpcs(dev->phy.mode)) { + r |= EMAC_MR1_MF_1000GPCS | + EMAC_MR1_MF_IPPA(dev->phy.address); - /* Use the EMAC that has the MDIO port */ - if (fep->mdio_dev) { - dev = fep->mdio_dev; - fep = dev->priv; - emacp = fep->emacp; + /* Put some arbitrary OUI, Manuf & Rev IDs so we can + * identify this GPCS PHY later. + */ + out_be32(&p->ipcr, 0xdeadbeef); + } else + r |= EMAC_MR1_MF_1000; + r |= EMAC_MR1_RFS_16K; + gige = 1; + + if (dev->ndev->mtu > ETH_DATA_LEN) + r |= EMAC_MR1_JPSM; + break; + case SPEED_100: + r |= EMAC_MR1_MF_100; + /* Fall through */ + default: + r |= EMAC_MR1_RFS_4K; + gige = 0; + break; } - count = 0; - while ((((stacr = in_be32(&emacp->em0stacr)) & EMAC_STACR_OC) == 0) - && (count++ < MDIO_DELAY)) - udelay(1); - MDIO_DEBUG((" (count was %d)\n", count)); + if (dev->rgmii_dev) + rgmii_set_speed(dev->rgmii_dev, dev->rgmii_input, + dev->phy.speed); + else + zmii_set_speed(dev->zmii_dev, dev->zmii_input, dev->phy.speed); - if ((stacr & EMAC_STACR_OC) == 0) { - printk(KERN_WARNING "%s: PHY read timeout #1!\n", dev->name); - return -1; +#if !defined(CONFIG_40x) + /* on 40x erratum forces us to NOT use integrated flow control, + * let's hope it works on 44x ;) + */ + if (dev->phy.duplex == DUPLEX_FULL) { + if (dev->phy.pause) + r |= EMAC_MR1_EIFC | EMAC_MR1_APP; + else if (dev->phy.asym_pause) + r |= EMAC_MR1_APP; } +#endif + out_be32(&p->mr1, r); + + /* Set individual MAC address */ + out_be32(&p->iahr, (ndev->dev_addr[0] << 8) | ndev->dev_addr[1]); + out_be32(&p->ialr, (ndev->dev_addr[2] << 24) | + (ndev->dev_addr[3] << 16) | (ndev->dev_addr[4] << 8) | + ndev->dev_addr[5]); + + /* VLAN Tag Protocol ID */ + out_be32(&p->vtpid, 0x8100); + + /* Receive mode register */ + r = emac_iff2rmr(ndev); + if (r & EMAC_RMR_MAE) + emac_hash_mc(dev); + out_be32(&p->rmr, r); + + /* FIFOs thresholds */ + r = EMAC_TMR1((EMAC_MAL_BURST_SIZE / EMAC_FIFO_ENTRY_SIZE) + 1, + EMAC_TX_FIFO_SIZE / 2 / EMAC_FIFO_ENTRY_SIZE); + out_be32(&p->tmr1, r); + out_be32(&p->trtr, EMAC_TRTR(EMAC_TX_FIFO_SIZE / 2)); + + /* PAUSE frame is sent when RX FIFO reaches its high-water mark, + there should be still enough space in FIFO to allow the our link + partner time to process this frame and also time to send PAUSE + frame itself. + + Here is the worst case scenario for the RX FIFO "headroom" + (from "The Switch Book") (100Mbps, without preamble, inter-frame gap): + + 1) One maximum-length frame on TX 1522 bytes + 2) One PAUSE frame time 64 bytes + 3) PAUSE frame decode time allowance 64 bytes + 4) One maximum-length frame on RX 1522 bytes + 5) Round-trip propagation delay of the link (100Mb) 15 bytes + ---------- + 3187 bytes + + I chose to set high-water mark to RX_FIFO_SIZE / 4 (1024 bytes) + low-water mark to RX_FIFO_SIZE / 8 (512 bytes) + */ + r = EMAC_RWMR(EMAC_RX_FIFO_SIZE(gige) / 8 / EMAC_FIFO_ENTRY_SIZE, + EMAC_RX_FIFO_SIZE(gige) / 4 / EMAC_FIFO_ENTRY_SIZE); + out_be32(&p->rwmr, r); + + /* Set PAUSE timer to the maximum */ + out_be32(&p->ptr, 0xffff); + + /* IRQ sources */ + out_be32(&p->iser, EMAC_ISR_TXPE | EMAC_ISR_RXPE | /* EMAC_ISR_TXUE | + EMAC_ISR_RXOE | */ EMAC_ISR_OVR | EMAC_ISR_BP | EMAC_ISR_SE | + EMAC_ISR_ALE | EMAC_ISR_BFCS | EMAC_ISR_PTLE | EMAC_ISR_ORE | + EMAC_ISR_IRE | EMAC_ISR_TE); + + /* We need to take GPCS PHY out of isolate mode after EMAC reset */ + if (emac_phy_gpcs(dev->phy.mode)) + mii_reset_phy(&dev->phy); + + return 0; +} - /* Clear the speed bits and make a read request to the PHY */ - stacr = ((EMAC_STACR_READ | (reg & 0x1f)) & ~EMAC_STACR_CLK_100MHZ); - stacr |= ((mii_id & 0x1F) << 5); +/* BHs disabled */ +static void emac_reinitialize(struct ocp_enet_private *dev) +{ + DBG("%d: reinitialize" NL, dev->def->index); - out_be32(&emacp->em0stacr, stacr); + if (!emac_configure(dev)) { + emac_tx_enable(dev); + emac_rx_enable(dev); + } +} - count = 0; - while ((((stacr = in_be32(&emacp->em0stacr)) & EMAC_STACR_OC) == 0) - && (count++ < MDIO_DELAY)) - udelay(1); - MDIO_DEBUG((" (count was %d)\n", count)); +/* BHs disabled */ +static void emac_full_tx_reset(struct net_device *ndev) +{ + struct ocp_enet_private *dev = ndev->priv; + struct ocp_func_emac_data *emacdata = dev->def->additions; - if ((stacr & EMAC_STACR_OC) == 0) { - printk(KERN_WARNING "%s: PHY read timeout #2!\n", dev->name); - return -1; - } + DBG("%d: full_tx_reset" NL, dev->def->index); - /* Check for a read error */ - if (stacr & EMAC_STACR_PHYE) { - MDIO_DEBUG(("EMAC MDIO PHY error !\n")); - return -1; - } + emac_tx_disable(dev); + mal_disable_tx_channel(dev->mal, emacdata->mal_tx_chan); + emac_clean_tx_ring(dev); + dev->tx_cnt = dev->tx_slot = dev->ack_slot = 0; - MDIO_DEBUG((" -> 0x%x\n", stacr >> 16)); + emac_configure(dev); - return (stacr >> 16); + mal_enable_tx_channel(dev->mal, emacdata->mal_tx_chan); + emac_tx_enable(dev); + emac_rx_enable(dev); + + netif_wake_queue(ndev); } -void emac_phy_write(struct net_device *dev, int mii_id, int reg, int data) +static int __emac_mdio_read(struct ocp_enet_private *dev, u8 id, u8 reg) { - int count; - uint32_t stacr; - struct ocp_enet_private *fep = dev->priv; - emac_t *emacp = fep->emacp; + struct emac_regs *p = dev->emacp; + u32 r; + int n; - MDIO_DEBUG(("%s phy_write, id: 0x%x, reg: 0x%x, data: 0x%x\n", - dev->name, mii_id, reg, data)); + DBG2("%d: mdio_read(%02x,%02x)" NL, dev->def->index, id, reg); - /* Enable proper ZMII port */ - if (fep->zmii_dev) - emac_enable_zmii_port(fep->zmii_dev, fep->zmii_input); + /* Enable proper MDIO port */ + zmii_enable_mdio(dev->zmii_dev, dev->zmii_input); - /* Use the EMAC that has the MDIO port */ - if (fep->mdio_dev) { - dev = fep->mdio_dev; - fep = dev->priv; - emacp = fep->emacp; + /* Wait for management interface to become idle */ + n = 10; + while (!(in_be32(&p->stacr) & EMAC_STACR_OC)) { + udelay(1); + if (!--n) + goto to; } - count = 0; - while ((((stacr = in_be32(&emacp->em0stacr)) & EMAC_STACR_OC) == 0) - && (count++ < MDIO_DELAY)) + /* Issue read command */ + out_be32(&p->stacr, + EMAC_STACR_BASE(emac_opb_mhz()) | EMAC_STACR_STAC_READ | + (reg & EMAC_STACR_PRA_MASK) + | ((id & EMAC_STACR_PCDA_MASK) << EMAC_STACR_PCDA_SHIFT)); + + /* Wait for read to complete */ + n = 100; + while (!((r = in_be32(&p->stacr)) & EMAC_STACR_OC)) { udelay(1); - MDIO_DEBUG((" (count was %d)\n", count)); + if (!--n) + goto to; + } - if ((stacr & EMAC_STACR_OC) == 0) { - printk(KERN_WARNING "%s: PHY write timeout #2!\n", dev->name); - return; + if (unlikely(r & EMAC_STACR_PHYE)) { + DBG("%d: mdio_read(%02x, %02x) failed" NL, dev->def->index, + id, reg); + return -EREMOTEIO; } - /* Clear the speed bits and make a read request to the PHY */ + r = ((r >> EMAC_STACR_PHYD_SHIFT) & EMAC_STACR_PHYD_MASK); + DBG2("%d: mdio_read -> %04x" NL, dev->def->index, r); + return r; + to: + DBG("%d: MII management interface timeout (read)" NL, dev->def->index); + return -ETIMEDOUT; +} - stacr = ((EMAC_STACR_WRITE | (reg & 0x1f)) & ~EMAC_STACR_CLK_100MHZ); - stacr |= ((mii_id & 0x1f) << 5) | ((data & 0xffff) << 16); +static void __emac_mdio_write(struct ocp_enet_private *dev, u8 id, u8 reg, + u16 val) +{ + struct emac_regs *p = dev->emacp; + int n; - out_be32(&emacp->em0stacr, stacr); + DBG2("%d: mdio_write(%02x,%02x,%04x)" NL, dev->def->index, id, reg, + val); - count = 0; - while ((((stacr = in_be32(&emacp->em0stacr)) & EMAC_STACR_OC) == 0) - && (count++ < MDIO_DELAY)) + /* Enable proper MDIO port */ + zmii_enable_mdio(dev->zmii_dev, dev->zmii_input); + + /* Wait for management interface to be idle */ + n = 10; + while (!(in_be32(&p->stacr) & EMAC_STACR_OC)) { udelay(1); - MDIO_DEBUG((" (count was %d)\n", count)); + if (!--n) + goto to; + } - if ((stacr & EMAC_STACR_OC) == 0) - printk(KERN_WARNING "%s: PHY write timeout #2!\n", dev->name); + /* Issue write command */ + out_be32(&p->stacr, + EMAC_STACR_BASE(emac_opb_mhz()) | EMAC_STACR_STAC_WRITE | + (reg & EMAC_STACR_PRA_MASK) | + ((id & EMAC_STACR_PCDA_MASK) << EMAC_STACR_PCDA_SHIFT) | + (val << EMAC_STACR_PHYD_SHIFT)); - /* Check for a write error */ - if ((stacr & EMAC_STACR_PHYE) != 0) { - MDIO_DEBUG(("EMAC MDIO PHY error !\n")); + /* Wait for write to complete */ + n = 100; + while (!(in_be32(&p->stacr) & EMAC_STACR_OC)) { + udelay(1); + if (!--n) + goto to; } + return; + to: + DBG("%d: MII management interface timeout (write)" NL, dev->def->index); } -static void emac_txeob_dev(void *param, u32 chanmask) +static int emac_mdio_read(struct net_device *ndev, int id, int reg) { - struct net_device *dev = param; - struct ocp_enet_private *fep = dev->priv; - unsigned long flags; - - spin_lock_irqsave(&fep->lock, flags); - - PKT_DEBUG(("emac_txeob_dev() entry, tx_cnt: %d\n", fep->tx_cnt)); - - while (fep->tx_cnt && - !(fep->tx_desc[fep->ack_slot].ctrl & MAL_TX_CTRL_READY)) { + struct ocp_enet_private *dev = ndev->priv; + int res; + + local_bh_disable(); + res = __emac_mdio_read(dev->mdio_dev ? dev->mdio_dev : dev, (u8) id, + (u8) reg); + local_bh_enable(); + return res; +} - if (fep->tx_desc[fep->ack_slot].ctrl & MAL_TX_CTRL_LAST) { - /* Tell the system the transmit completed. */ - dma_unmap_single(&fep->ocpdev->dev, - fep->tx_desc[fep->ack_slot].data_ptr, - fep->tx_desc[fep->ack_slot].data_len, - DMA_TO_DEVICE); - dev_kfree_skb_irq(fep->tx_skb[fep->ack_slot]); +static void emac_mdio_write(struct net_device *ndev, int id, int reg, int val) +{ + struct ocp_enet_private *dev = ndev->priv; - if (fep->tx_desc[fep->ack_slot].ctrl & - (EMAC_TX_ST_EC | EMAC_TX_ST_MC | EMAC_TX_ST_SC)) - fep->stats.collisions++; - } + local_bh_disable(); + __emac_mdio_write(dev->mdio_dev ? dev->mdio_dev : dev, (u8) id, + (u8) reg, (u16) val); + local_bh_enable(); +} - fep->tx_skb[fep->ack_slot] = (struct sk_buff *)NULL; - if (++fep->ack_slot == NUM_TX_BUFF) - fep->ack_slot = 0; +/* BHs disabled */ +static void emac_set_multicast_list(struct net_device *ndev) +{ + struct ocp_enet_private *dev = ndev->priv; + struct emac_regs *p = dev->emacp; + u32 rmr = emac_iff2rmr(ndev); + + DBG("%d: multicast %08x" NL, dev->def->index, rmr); + BUG_ON(!netif_running(dev->ndev)); + + /* I decided to relax register access rules here to avoid + * full EMAC reset. + * + * There is a real problem with EMAC4 core if we use MWSW_001 bit + * in MR1 register and do a full EMAC reset. + * One TX BD status update is delayed and, after EMAC reset, it + * never happens, resulting in TX hung (it'll be recovered by TX + * timeout handler eventually, but this is just gross). + * So we either have to do full TX reset or try to cheat here :) + * + * The only required change is to RX mode register, so I *think* all + * we need is just to stop RX channel. This seems to work on all + * tested SoCs. --ebs + */ + emac_rx_disable(dev); + if (rmr & EMAC_RMR_MAE) + emac_hash_mc(dev); + out_be32(&p->rmr, rmr); + emac_rx_enable(dev); +} - fep->tx_cnt--; +/* BHs disabled */ +static int emac_resize_rx_ring(struct ocp_enet_private *dev, int new_mtu) +{ + struct ocp_func_emac_data *emacdata = dev->def->additions; + int rx_sync_size = emac_rx_sync_size(new_mtu); + int rx_skb_size = emac_rx_skb_size(new_mtu); + int i, ret = 0; + + emac_rx_disable(dev); + mal_disable_rx_channel(dev->mal, emacdata->mal_rx_chan); + + if (dev->rx_sg_skb) { + ++dev->estats.rx_dropped_resize; + dev_kfree_skb(dev->rx_sg_skb); + dev->rx_sg_skb = NULL; } - if (fep->tx_cnt < NUM_TX_BUFF) - netif_wake_queue(dev); - PKT_DEBUG(("emac_txeob_dev() exit, tx_cnt: %d\n", fep->tx_cnt)); + /* Make a first pass over RX ring and mark BDs ready, dropping + * non-processed packets on the way. We need this as a separate pass + * to simplify error recovery in the case of allocation failure later. + */ + for (i = 0; i < NUM_RX_BUFF; ++i) { + if (dev->rx_desc[i].ctrl & MAL_RX_CTRL_FIRST) + ++dev->estats.rx_dropped_resize; - spin_unlock_irqrestore(&fep->lock, flags); -} + dev->rx_desc[i].data_len = 0; + dev->rx_desc[i].ctrl = MAL_RX_CTRL_EMPTY | + (i == (NUM_RX_BUFF - 1) ? MAL_RX_CTRL_WRAP : 0); + } -/* - Fill/Re-fill the rx chain with valid ctrl/ptrs. - This function will fill from rx_slot up to the parm end. - So to completely fill the chain pre-set rx_slot to 0 and - pass in an end of 0. - */ -static void emac_rx_fill(struct net_device *dev, int end) -{ - int i; - struct ocp_enet_private *fep = dev->priv; - - i = fep->rx_slot; - do { - /* We don't want the 16 bytes skb_reserve done by dev_alloc_skb, - * it breaks our cache line alignement. However, we still allocate - * +16 so that we end up allocating the exact same size as - * dev_alloc_skb() would do. - * Also, because of the skb_res, the max DMA size we give to EMAC - * is slighly wrong, causing it to potentially DMA 2 more bytes - * from a broken/oversized packet. These 16 bytes will take care - * that we don't walk on somebody else toes with that. - */ - fep->rx_skb[i] = - alloc_skb(fep->rx_buffer_size + 16, GFP_ATOMIC); - - if (fep->rx_skb[i] == NULL) { - /* Keep rx_slot here, the next time clean/fill is called - * we will try again before the MAL wraps back here - * If the MAL tries to use this descriptor with - * the EMPTY bit off it will cause the - * rxde interrupt. That is where we will - * try again to allocate an sk_buff. - */ - break; + /* Reallocate RX ring only if bigger skb buffers are required */ + if (rx_skb_size <= dev->rx_skb_size) + goto skip; + /* Second pass, allocate new skbs */ + for (i = 0; i < NUM_RX_BUFF; ++i) { + struct sk_buff *skb = alloc_skb(rx_skb_size, GFP_ATOMIC); + if (!skb) { + ret = -ENOMEM; + goto oom; } - if (skb_res) - skb_reserve(fep->rx_skb[i], skb_res); + BUG_ON(!dev->rx_skb[i]); + dev_kfree_skb(dev->rx_skb[i]); - /* We must NOT dma_map_single the cache line right after the - * buffer, so we must crop our sync size to account for the - * reserved space - */ - fep->rx_desc[i].data_ptr = - (unsigned char *)dma_map_single(&fep->ocpdev->dev, - (void *)fep->rx_skb[i]-> - data, - fep->rx_buffer_size - - skb_res, DMA_FROM_DEVICE); - - /* - * Some 4xx implementations use the previously - * reserved bits in data_len to encode the MS - * 4-bits of a 36-bit physical address (ERPN) - * This must be initialized. - */ - fep->rx_desc[i].data_len = 0; - fep->rx_desc[i].ctrl = MAL_RX_CTRL_EMPTY | MAL_RX_CTRL_INTR | - (i == (NUM_RX_BUFF - 1) ? MAL_RX_CTRL_WRAP : 0); + skb_reserve(skb, EMAC_RX_SKB_HEADROOM + 2); + dev->rx_desc[i].data_ptr = + dma_map_single(dev->ldev, skb->data - 2, rx_sync_size, + DMA_FROM_DEVICE) + 2; + dev->rx_skb[i] = skb; + } + skip: + /* Check if we need to change "Jumbo" bit in MR1 */ + if ((new_mtu > ETH_DATA_LEN) ^ (dev->ndev->mtu > ETH_DATA_LEN)) { + /* This is to prevent starting RX channel in emac_rx_enable() */ + dev->commac.rx_stopped = 1; + + dev->ndev->mtu = new_mtu; + emac_full_tx_reset(dev->ndev); + } - } while ((i = (i + 1) % NUM_RX_BUFF) != end); + mal_set_rcbs(dev->mal, emacdata->mal_rx_chan, emac_rx_size(new_mtu)); + oom: + /* Restart RX */ + dev->commac.rx_stopped = dev->rx_slot = 0; + mal_enable_rx_channel(dev->mal, emacdata->mal_rx_chan); + emac_rx_enable(dev); - fep->rx_slot = i; + return ret; } -static void -emac_rx_csum(struct net_device *dev, unsigned short ctrl, struct sk_buff *skb) +/* Process ctx, rtnl_lock semaphore */ +static int emac_change_mtu(struct net_device *ndev, int new_mtu) { - struct ocp_enet_private *fep = dev->priv; + struct ocp_enet_private *dev = ndev->priv; + int ret = 0; - /* Exit if interface has no TAH engine */ - if (!fep->tah_dev) { - skb->ip_summed = CHECKSUM_NONE; - return; - } + if (new_mtu < EMAC_MIN_MTU || new_mtu > EMAC_MAX_MTU) + return -EINVAL; - /* Check for TCP/UDP/IP csum error */ - if (ctrl & EMAC_CSUM_VER_ERROR) { - /* Let the stack verify checksum errors */ - skb->ip_summed = CHECKSUM_NONE; -/* adapter->hw_csum_err++; */ - } else { - /* Csum is good */ - skb->ip_summed = CHECKSUM_UNNECESSARY; -/* adapter->hw_csum_good++; */ - } -} + DBG("%d: change_mtu(%d)" NL, dev->def->index, new_mtu); -static int emac_rx_clean(struct net_device *dev) -{ - int i, b, bnum = 0, buf[6]; - int error, frame_length; - struct ocp_enet_private *fep = dev->priv; - unsigned short ctrl; + local_bh_disable(); + if (netif_running(ndev)) { + /* Check if we really need to reinitalize RX ring */ + if (emac_rx_skb_size(ndev->mtu) != emac_rx_skb_size(new_mtu)) + ret = emac_resize_rx_ring(dev, new_mtu); + } - i = fep->rx_slot; + if (!ret) { + ndev->mtu = new_mtu; + dev->rx_skb_size = emac_rx_skb_size(new_mtu); + dev->rx_sync_size = emac_rx_sync_size(new_mtu); + } + local_bh_enable(); - PKT_DEBUG(("emac_rx_clean() entry, rx_slot: %d\n", fep->rx_slot)); + return ret; +} - do { - if (fep->rx_skb[i] == NULL) - continue; /*we have already handled the packet but haved failed to alloc */ - /* - since rx_desc is in uncached mem we don't keep reading it directly - we pull out a local copy of ctrl and do the checks on the copy. - */ - ctrl = fep->rx_desc[i].ctrl; - if (ctrl & MAL_RX_CTRL_EMPTY) - break; /*we don't have any more ready packets */ - - if (EMAC_IS_BAD_RX_PACKET(ctrl)) { - fep->stats.rx_errors++; - fep->stats.rx_dropped++; - - if (ctrl & EMAC_RX_ST_OE) - fep->stats.rx_fifo_errors++; - if (ctrl & EMAC_RX_ST_AE) - fep->stats.rx_frame_errors++; - if (ctrl & EMAC_RX_ST_BFCS) - fep->stats.rx_crc_errors++; - if (ctrl & (EMAC_RX_ST_RP | EMAC_RX_ST_PTL | - EMAC_RX_ST_ORE | EMAC_RX_ST_IRE)) - fep->stats.rx_length_errors++; - } else { - if ((ctrl & (MAL_RX_CTRL_FIRST | MAL_RX_CTRL_LAST)) == - (MAL_RX_CTRL_FIRST | MAL_RX_CTRL_LAST)) { - /* Single descriptor packet */ - emac_rx_csum(dev, ctrl, fep->rx_skb[i]); - /* Send the skb up the chain. */ - frame_length = fep->rx_desc[i].data_len - 4; - skb_put(fep->rx_skb[i], frame_length); - fep->rx_skb[i]->dev = dev; - fep->rx_skb[i]->protocol = - eth_type_trans(fep->rx_skb[i], dev); - error = netif_rx(fep->rx_skb[i]); - - if ((error == NET_RX_DROP) || - (error == NET_RX_BAD)) { - fep->stats.rx_dropped++; - } else { - fep->stats.rx_packets++; - fep->stats.rx_bytes += frame_length; - } - fep->rx_skb[i] = NULL; - } else { - /* Multiple descriptor packet */ - if (ctrl & MAL_RX_CTRL_FIRST) { - if (fep->rx_desc[(i + 1) % NUM_RX_BUFF]. - ctrl & MAL_RX_CTRL_EMPTY) - break; - bnum = 0; - buf[bnum] = i; - ++bnum; - continue; - } - if (((ctrl & MAL_RX_CTRL_FIRST) != - MAL_RX_CTRL_FIRST) && - ((ctrl & MAL_RX_CTRL_LAST) != - MAL_RX_CTRL_LAST)) { - if (fep->rx_desc[(i + 1) % - NUM_RX_BUFF].ctrl & - MAL_RX_CTRL_EMPTY) { - i = buf[0]; - break; - } - buf[bnum] = i; - ++bnum; - continue; - } - if (ctrl & MAL_RX_CTRL_LAST) { - buf[bnum] = i; - ++bnum; - skb_put(fep->rx_skb[buf[0]], - fep->rx_desc[buf[0]].data_len); - for (b = 1; b < bnum; b++) { - /* - * MAL is braindead, we need - * to copy the remainder - * of the packet from the - * latter descriptor buffers - * to the first skb. Then - * dispose of the source - * skbs. - * - * Once the stack is fixed - * to handle frags on most - * protocols we can generate - * a fragmented skb with - * no copies. - */ - memcpy(fep->rx_skb[buf[0]]-> - data + - fep->rx_skb[buf[0]]->len, - fep->rx_skb[buf[b]]-> - data, - fep->rx_desc[buf[b]]. - data_len); - skb_put(fep->rx_skb[buf[0]], - fep->rx_desc[buf[b]]. - data_len); - dma_unmap_single(&fep->ocpdev-> - dev, - fep-> - rx_desc[buf - [b]]. - data_ptr, - fep-> - rx_desc[buf - [b]]. - data_len, - DMA_FROM_DEVICE); - dev_kfree_skb(fep-> - rx_skb[buf[b]]); - } - emac_rx_csum(dev, ctrl, - fep->rx_skb[buf[0]]); - - fep->rx_skb[buf[0]]->dev = dev; - fep->rx_skb[buf[0]]->protocol = - eth_type_trans(fep->rx_skb[buf[0]], - dev); - error = netif_rx(fep->rx_skb[buf[0]]); - - if ((error == NET_RX_DROP) - || (error == NET_RX_BAD)) { - fep->stats.rx_dropped++; - } else { - fep->stats.rx_packets++; - fep->stats.rx_bytes += - fep->rx_skb[buf[0]]->len; - } - for (b = 0; b < bnum; b++) - fep->rx_skb[buf[b]] = NULL; - } - } +static void emac_clean_tx_ring(struct ocp_enet_private *dev) +{ + int i; + for (i = 0; i < NUM_TX_BUFF; ++i) { + if (dev->tx_skb[i]) { + dev_kfree_skb(dev->tx_skb[i]); + dev->tx_skb[i] = NULL; + if (dev->tx_desc[i].ctrl & MAL_TX_CTRL_READY) + ++dev->estats.tx_dropped; } - } while ((i = (i + 1) % NUM_RX_BUFF) != fep->rx_slot); - - PKT_DEBUG(("emac_rx_clean() exit, rx_slot: %d\n", fep->rx_slot)); - - return i; + dev->tx_desc[i].ctrl = 0; + dev->tx_desc[i].data_ptr = 0; + } } -static void emac_rxeob_dev(void *param, u32 chanmask) +static void emac_clean_rx_ring(struct ocp_enet_private *dev) { - struct net_device *dev = param; - struct ocp_enet_private *fep = dev->priv; - unsigned long flags; - int n; + int i; + for (i = 0; i < NUM_RX_BUFF; ++i) + if (dev->rx_skb[i]) { + dev->rx_desc[i].ctrl = 0; + dev_kfree_skb(dev->rx_skb[i]); + dev->rx_skb[i] = NULL; + dev->rx_desc[i].data_ptr = 0; + } - spin_lock_irqsave(&fep->lock, flags); - if ((n = emac_rx_clean(dev)) != fep->rx_slot) - emac_rx_fill(dev, n); - spin_unlock_irqrestore(&fep->lock, flags); + if (dev->rx_sg_skb) { + dev_kfree_skb(dev->rx_sg_skb); + dev->rx_sg_skb = NULL; + } } -/* - * This interrupt should never occurr, we don't program - * the MAL for contiunous mode. - */ -static void emac_txde_dev(void *param, u32 chanmask) +static inline int emac_alloc_rx_skb(struct ocp_enet_private *dev, int slot, + int flags) { - struct net_device *dev = param; - struct ocp_enet_private *fep = dev->priv; + struct sk_buff *skb = alloc_skb(dev->rx_skb_size, flags); + if (unlikely(!skb)) + return -ENOMEM; - printk(KERN_WARNING "%s: transmit descriptor error\n", dev->name); + dev->rx_skb[slot] = skb; + dev->rx_desc[slot].data_len = 0; - emac_mac_dump(dev); - emac_mal_dump(dev); + skb_reserve(skb, EMAC_RX_SKB_HEADROOM + 2); + dev->rx_desc[slot].data_ptr = + dma_map_single(dev->ldev, skb->data - 2, dev->rx_sync_size, + DMA_FROM_DEVICE) + 2; + barrier(); + dev->rx_desc[slot].ctrl = MAL_RX_CTRL_EMPTY | + (slot == (NUM_RX_BUFF - 1) ? MAL_RX_CTRL_WRAP : 0); - /* Reenable the transmit channel */ - mal_enable_tx_channels(fep->mal, fep->commac.tx_chan_mask); + return 0; } -/* - * This interrupt should be very rare at best. This occurs when - * the hardware has a problem with the receive descriptors. The manual - * states that it occurs when the hardware cannot the receive descriptor - * empty bit is not set. The recovery mechanism will be to - * traverse through the descriptors, handle any that are marked to be - * handled and reinitialize each along the way. At that point the driver - * will be restarted. - */ -static void emac_rxde_dev(void *param, u32 chanmask) +static void emac_print_link_status(struct ocp_enet_private *dev) { - struct net_device *dev = param; - struct ocp_enet_private *fep = dev->priv; - unsigned long flags; - - if (net_ratelimit()) { - printk(KERN_WARNING "%s: receive descriptor error\n", - fep->ndev->name); + if (netif_carrier_ok(dev->ndev)) + printk(KERN_INFO "%s: link is up, %d %s%s\n", + dev->ndev->name, dev->phy.speed, + dev->phy.duplex == DUPLEX_FULL ? "FDX" : "HDX", + dev->phy.pause ? ", pause enabled" : + dev->phy.asym_pause ? ", assymetric pause enabled" : ""); + else + printk(KERN_INFO "%s: link is down\n", dev->ndev->name); +} - emac_mac_dump(dev); - emac_mal_dump(dev); - emac_desc_dump(dev); +/* Process ctx, rtnl_lock semaphore */ +static int emac_open(struct net_device *ndev) +{ + struct ocp_enet_private *dev = ndev->priv; + struct ocp_func_emac_data *emacdata = dev->def->additions; + int err, i; + + DBG("%d: open" NL, dev->def->index); + + /* Setup error IRQ handler */ + err = request_irq(dev->def->irq, emac_irq, 0, "EMAC", dev); + if (err) { + printk(KERN_ERR "%s: failed to request IRQ %d\n", + ndev->name, dev->def->irq); + return err; } - /* Disable RX channel */ - spin_lock_irqsave(&fep->lock, flags); - mal_disable_rx_channels(fep->mal, fep->commac.rx_chan_mask); - - /* For now, charge the error against all emacs */ - fep->stats.rx_errors++; - - /* so do we have any good packets still? */ - emac_rx_clean(dev); - - /* When the interface is restarted it resets processing to the - * first descriptor in the table. - */ - - fep->rx_slot = 0; - emac_rx_fill(dev, 0); + /* Allocate RX ring */ + for (i = 0; i < NUM_RX_BUFF; ++i) + if (emac_alloc_rx_skb(dev, i, GFP_KERNEL)) { + printk(KERN_ERR "%s: failed to allocate RX ring\n", + ndev->name); + goto oom; + } - set_mal_dcrn(fep->mal, DCRN_MALRXEOBISR, fep->commac.rx_chan_mask); - set_mal_dcrn(fep->mal, DCRN_MALRXDEIR, fep->commac.rx_chan_mask); + local_bh_disable(); + dev->tx_cnt = dev->tx_slot = dev->ack_slot = dev->rx_slot = + dev->commac.rx_stopped = 0; + dev->rx_sg_skb = NULL; + + if (dev->phy.address >= 0) { + int link_poll_interval; + if (dev->phy.def->ops->poll_link(&dev->phy)) { + dev->phy.def->ops->read_link(&dev->phy); + EMAC_RX_CLK_DEFAULT(dev->def->index); + netif_carrier_on(dev->ndev); + link_poll_interval = PHY_POLL_LINK_ON; + } else { + EMAC_RX_CLK_TX(dev->def->index); + netif_carrier_off(dev->ndev); + link_poll_interval = PHY_POLL_LINK_OFF; + } + mod_timer(&dev->link_timer, jiffies + link_poll_interval); + emac_print_link_status(dev); + } else + netif_carrier_on(dev->ndev); + + emac_configure(dev); + mal_poll_add(dev->mal, &dev->commac); + mal_enable_tx_channel(dev->mal, emacdata->mal_tx_chan); + mal_set_rcbs(dev->mal, emacdata->mal_rx_chan, emac_rx_size(ndev->mtu)); + mal_enable_rx_channel(dev->mal, emacdata->mal_rx_chan); + emac_tx_enable(dev); + emac_rx_enable(dev); + netif_start_queue(ndev); + local_bh_enable(); - /* Reenable the receive channels */ - mal_enable_rx_channels(fep->mal, fep->commac.rx_chan_mask); - spin_unlock_irqrestore(&fep->lock, flags); + return 0; + oom: + emac_clean_rx_ring(dev); + free_irq(dev->def->irq, dev); + return -ENOMEM; } -static irqreturn_t -emac_mac_irq(int irq, void *dev_instance, struct pt_regs *regs) +/* BHs disabled */ +static int emac_link_differs(struct ocp_enet_private *dev) { - struct net_device *dev = dev_instance; - struct ocp_enet_private *fep = dev->priv; - emac_t *emacp = fep->emacp; - unsigned long tmp_em0isr; + u32 r = in_be32(&dev->emacp->mr1); - /* EMAC interrupt */ - tmp_em0isr = in_be32(&emacp->em0isr); - if (tmp_em0isr & (EMAC_ISR_TE0 | EMAC_ISR_TE1)) { - /* This error is a hard transmit error - could retransmit */ - fep->stats.tx_errors++; + int duplex = r & EMAC_MR1_FDE ? DUPLEX_FULL : DUPLEX_HALF; + int speed, pause, asym_pause; - /* Reenable the transmit channel */ - mal_enable_tx_channels(fep->mal, fep->commac.tx_chan_mask); + if (r & (EMAC_MR1_MF_1000 | EMAC_MR1_MF_1000GPCS)) + speed = SPEED_1000; + else if (r & EMAC_MR1_MF_100) + speed = SPEED_100; + else + speed = SPEED_10; - } else { - fep->stats.rx_errors++; + switch (r & (EMAC_MR1_EIFC | EMAC_MR1_APP)) { + case (EMAC_MR1_EIFC | EMAC_MR1_APP): + pause = 1; + asym_pause = 0; + break; + case EMAC_MR1_APP: + pause = 0; + asym_pause = 1; + break; + default: + pause = asym_pause = 0; } - - if (tmp_em0isr & EMAC_ISR_RP) - fep->stats.rx_length_errors++; - if (tmp_em0isr & EMAC_ISR_ALE) - fep->stats.rx_frame_errors++; - if (tmp_em0isr & EMAC_ISR_BFCS) - fep->stats.rx_crc_errors++; - if (tmp_em0isr & EMAC_ISR_PTLE) - fep->stats.rx_length_errors++; - if (tmp_em0isr & EMAC_ISR_ORE) - fep->stats.rx_length_errors++; - if (tmp_em0isr & EMAC_ISR_TE0) - fep->stats.tx_aborted_errors++; - - emac_err_dump(dev, tmp_em0isr); - - out_be32(&emacp->em0isr, tmp_em0isr); - - return IRQ_HANDLED; + return speed != dev->phy.speed || duplex != dev->phy.duplex || + pause != dev->phy.pause || asym_pause != dev->phy.asym_pause; } -static int emac_start_xmit(struct sk_buff *skb, struct net_device *dev) +/* BHs disabled */ +static void emac_link_timer(unsigned long data) { - unsigned short ctrl; - unsigned long flags; - struct ocp_enet_private *fep = dev->priv; - emac_t *emacp = fep->emacp; - int len = skb->len; - unsigned int offset = 0, size, f, tx_slot_first; - unsigned int nr_frags = skb_shinfo(skb)->nr_frags; + struct ocp_enet_private *dev = (struct ocp_enet_private *)data; + int link_poll_interval; - spin_lock_irqsave(&fep->lock, flags); + DBG2("%d: link timer" NL, dev->def->index); - len -= skb->data_len; + if (dev->phy.def->ops->poll_link(&dev->phy)) { + if (!netif_carrier_ok(dev->ndev)) { + EMAC_RX_CLK_DEFAULT(dev->def->index); - if ((fep->tx_cnt + nr_frags + len / DESC_BUF_SIZE + 1) > NUM_TX_BUFF) { - PKT_DEBUG(("emac_start_xmit() stopping queue\n")); - netif_stop_queue(dev); - spin_unlock_irqrestore(&fep->lock, flags); - return -EBUSY; - } + /* Get new link parameters */ + dev->phy.def->ops->read_link(&dev->phy); - tx_slot_first = fep->tx_slot; + if (dev->tah_dev || emac_link_differs(dev)) + emac_full_tx_reset(dev->ndev); - while (len) { - size = min(len, DESC_BUF_SIZE); - - fep->tx_desc[fep->tx_slot].data_len = (short)size; - fep->tx_desc[fep->tx_slot].data_ptr = - (unsigned char *)dma_map_single(&fep->ocpdev->dev, - (void *)((unsigned int)skb-> - data + offset), - size, DMA_TO_DEVICE); - - ctrl = EMAC_TX_CTRL_DFLT; - if (fep->tx_slot != tx_slot_first) - ctrl |= MAL_TX_CTRL_READY; - if ((NUM_TX_BUFF - 1) == fep->tx_slot) - ctrl |= MAL_TX_CTRL_WRAP; - if (!nr_frags && (len == size)) { - ctrl |= MAL_TX_CTRL_LAST; - fep->tx_skb[fep->tx_slot] = skb; + netif_carrier_on(dev->ndev); + emac_print_link_status(dev); + } + link_poll_interval = PHY_POLL_LINK_ON; + } else { + if (netif_carrier_ok(dev->ndev)) { + EMAC_RX_CLK_TX(dev->def->index); +#if defined(CONFIG_IBM_EMAC_PHY_RX_CLK_FIX) + emac_reinitialize(dev); +#endif + netif_carrier_off(dev->ndev); + emac_print_link_status(dev); } - if (skb->ip_summed == CHECKSUM_HW) - ctrl |= EMAC_TX_CTRL_TAH_CSUM; - fep->tx_desc[fep->tx_slot].ctrl = ctrl; + /* Retry reset if the previous attempt failed. + * This is needed mostly for CONFIG_IBM_EMAC_PHY_RX_CLK_FIX + * case, but I left it here because it shouldn't trigger for + * sane PHYs anyway. + */ + if (unlikely(dev->reset_failed)) + emac_reinitialize(dev); - len -= size; - offset += size; + link_poll_interval = PHY_POLL_LINK_OFF; + } + mod_timer(&dev->link_timer, jiffies + link_poll_interval); +} - /* Bump tx count */ - if (++fep->tx_cnt == NUM_TX_BUFF) - netif_stop_queue(dev); +/* BHs disabled */ +static void emac_force_link_update(struct ocp_enet_private *dev) +{ + netif_carrier_off(dev->ndev); + if (timer_pending(&dev->link_timer)) + mod_timer(&dev->link_timer, jiffies + PHY_POLL_LINK_OFF); +} - /* Next descriptor */ - if (++fep->tx_slot == NUM_TX_BUFF) - fep->tx_slot = 0; - } +/* Process ctx, rtnl_lock semaphore */ +static int emac_close(struct net_device *ndev) +{ + struct ocp_enet_private *dev = ndev->priv; + struct ocp_func_emac_data *emacdata = dev->def->additions; - for (f = 0; f < nr_frags; f++) { - struct skb_frag_struct *frag; + DBG("%d: close" NL, dev->def->index); - frag = &skb_shinfo(skb)->frags[f]; - len = frag->size; - offset = 0; - - while (len) { - size = min(len, DESC_BUF_SIZE); - - dma_map_page(&fep->ocpdev->dev, - frag->page, - frag->page_offset + offset, - size, DMA_TO_DEVICE); - - ctrl = EMAC_TX_CTRL_DFLT | MAL_TX_CTRL_READY; - if ((NUM_TX_BUFF - 1) == fep->tx_slot) - ctrl |= MAL_TX_CTRL_WRAP; - if ((f == (nr_frags - 1)) && (len == size)) { - ctrl |= MAL_TX_CTRL_LAST; - fep->tx_skb[fep->tx_slot] = skb; - } + local_bh_disable(); - if (skb->ip_summed == CHECKSUM_HW) - ctrl |= EMAC_TX_CTRL_TAH_CSUM; + if (dev->phy.address >= 0) + del_timer_sync(&dev->link_timer); - fep->tx_desc[fep->tx_slot].data_len = (short)size; - fep->tx_desc[fep->tx_slot].data_ptr = - (char *)((page_to_pfn(frag->page) << PAGE_SHIFT) + - frag->page_offset + offset); - fep->tx_desc[fep->tx_slot].ctrl = ctrl; + netif_stop_queue(ndev); + emac_rx_disable(dev); + emac_tx_disable(dev); + mal_disable_rx_channel(dev->mal, emacdata->mal_rx_chan); + mal_disable_tx_channel(dev->mal, emacdata->mal_tx_chan); + mal_poll_del(dev->mal, &dev->commac); + local_bh_enable(); - len -= size; - offset += size; + emac_clean_tx_ring(dev); + emac_clean_rx_ring(dev); + free_irq(dev->def->irq, dev); - /* Bump tx count */ - if (++fep->tx_cnt == NUM_TX_BUFF) - netif_stop_queue(dev); + return 0; +} - /* Next descriptor */ - if (++fep->tx_slot == NUM_TX_BUFF) - fep->tx_slot = 0; - } +static inline u16 emac_tx_csum(struct ocp_enet_private *dev, + struct sk_buff *skb) +{ +#if defined(CONFIG_IBM_EMAC_TAH) + if (skb->ip_summed == CHECKSUM_HW) { + ++dev->stats.tx_packets_csum; + return EMAC_TX_CTRL_TAH_CSUM; } +#endif + return 0; +} - /* - * Deferred set READY on first descriptor of packet to - * avoid TX MAL race. - */ - fep->tx_desc[tx_slot_first].ctrl |= MAL_TX_CTRL_READY; - - /* Send the packet out. */ - out_be32(&emacp->em0tmr0, EMAC_TMR0_XMIT); +static inline int emac_xmit_finish(struct ocp_enet_private *dev, int len) +{ + struct emac_regs *p = dev->emacp; + struct net_device *ndev = dev->ndev; - fep->stats.tx_packets++; - fep->stats.tx_bytes += skb->len; + /* Send the packet out */ + out_be32(&p->tmr0, EMAC_TMR0_XMIT); - PKT_DEBUG(("emac_start_xmit() exitn")); + if (unlikely(++dev->tx_cnt == NUM_TX_BUFF)) { + netif_stop_queue(ndev); + DBG2("%d: stopped TX queue" NL, dev->def->index); + } - spin_unlock_irqrestore(&fep->lock, flags); + ndev->trans_start = jiffies; + ++dev->stats.tx_packets; + dev->stats.tx_bytes += len; return 0; } -static int emac_adjust_to_link(struct ocp_enet_private *fep) +/* BHs disabled */ +static int emac_start_xmit(struct sk_buff *skb, struct net_device *ndev) { - emac_t *emacp = fep->emacp; - unsigned long mode_reg; - int full_duplex, speed; + struct ocp_enet_private *dev = ndev->priv; + unsigned int len = skb->len; + int slot; - full_duplex = 0; - speed = SPEED_10; + u16 ctrl = EMAC_TX_CTRL_GFCS | EMAC_TX_CTRL_GP | MAL_TX_CTRL_READY | + MAL_TX_CTRL_LAST | emac_tx_csum(dev, skb); - /* set mode register 1 defaults */ - mode_reg = EMAC_M1_DEFAULT; - - /* Read link mode on PHY */ - if (fep->phy_mii.def->ops->read_link(&fep->phy_mii) == 0) { - /* If an error occurred, we don't deal with it yet */ - full_duplex = (fep->phy_mii.duplex == DUPLEX_FULL); - speed = fep->phy_mii.speed; + slot = dev->tx_slot++; + if (dev->tx_slot == NUM_TX_BUFF) { + dev->tx_slot = 0; + ctrl |= MAL_TX_CTRL_WRAP; } + DBG2("%d: xmit(%u) %d" NL, dev->def->index, len, slot); - /* set speed (default is 10Mb) */ - switch (speed) { - case SPEED_1000: - mode_reg |= EMAC_M1_RFS_16K; - if (fep->rgmii_dev) { - struct ibm_ocp_rgmii *rgmii = RGMII_PRIV(fep->rgmii_dev); - - if ((rgmii->mode[fep->rgmii_input] == RTBI) - || (rgmii->mode[fep->rgmii_input] == TBI)) - mode_reg |= EMAC_M1_MF_1000GPCS; - else - mode_reg |= EMAC_M1_MF_1000MBPS; - - emac_rgmii_port_speed(fep->rgmii_dev, fep->rgmii_input, - 1000); - } - break; - case SPEED_100: - mode_reg |= EMAC_M1_MF_100MBPS | EMAC_M1_RFS_4K; - if (fep->rgmii_dev) - emac_rgmii_port_speed(fep->rgmii_dev, fep->rgmii_input, - 100); - if (fep->zmii_dev) - emac_zmii_port_speed(fep->zmii_dev, fep->zmii_input, - 100); - break; - case SPEED_10: - default: - mode_reg = (mode_reg & ~EMAC_M1_MF_100MBPS) | EMAC_M1_RFS_4K; - if (fep->rgmii_dev) - emac_rgmii_port_speed(fep->rgmii_dev, fep->rgmii_input, - 10); - if (fep->zmii_dev) - emac_zmii_port_speed(fep->zmii_dev, fep->zmii_input, - 10); - } - - if (full_duplex) - mode_reg |= EMAC_M1_FDE | EMAC_M1_EIFC | EMAC_M1_IST; - else - mode_reg &= ~(EMAC_M1_FDE | EMAC_M1_EIFC | EMAC_M1_ILE); + dev->tx_skb[slot] = skb; + dev->tx_desc[slot].data_ptr = dma_map_single(dev->ldev, skb->data, len, + DMA_TO_DEVICE); + dev->tx_desc[slot].data_len = (u16) len; + barrier(); + dev->tx_desc[slot].ctrl = ctrl; - LINK_DEBUG(("%s: adjust to link, speed: %d, duplex: %d, opened: %d\n", - fep->ndev->name, speed, full_duplex, fep->opened)); - - printk(KERN_INFO "%s: Speed: %d, %s duplex.\n", - fep->ndev->name, speed, full_duplex ? "Full" : "Half"); - if (fep->opened) - out_be32(&emacp->em0mr1, mode_reg); - - return 0; + return emac_xmit_finish(dev, len); } -static int emac_set_mac_address(struct net_device *ndev, void *p) +#if defined(CONFIG_IBM_EMAC_TAH) +static inline int emac_xmit_split(struct ocp_enet_private *dev, int slot, + u32 pd, int len, int last, u16 base_ctrl) { - struct ocp_enet_private *fep = ndev->priv; - emac_t *emacp = fep->emacp; - struct sockaddr *addr = p; + while (1) { + u16 ctrl = base_ctrl; + int chunk = min(len, MAL_MAX_TX_SIZE); + len -= chunk; - if (!is_valid_ether_addr(addr->sa_data)) - return -EADDRNOTAVAIL; + slot = (slot + 1) % NUM_TX_BUFF; - memcpy(ndev->dev_addr, addr->sa_data, ndev->addr_len); + if (last && !len) + ctrl |= MAL_TX_CTRL_LAST; + if (slot == NUM_TX_BUFF - 1) + ctrl |= MAL_TX_CTRL_WRAP; - /* set the high address */ - out_be32(&emacp->em0iahr, - (fep->ndev->dev_addr[0] << 8) | fep->ndev->dev_addr[1]); + dev->tx_skb[slot] = NULL; + dev->tx_desc[slot].data_ptr = pd; + dev->tx_desc[slot].data_len = (u16) chunk; + dev->tx_desc[slot].ctrl = ctrl; + ++dev->tx_cnt; - /* set the low address */ - out_be32(&emacp->em0ialr, - (fep->ndev->dev_addr[2] << 24) | (fep->ndev->dev_addr[3] << 16) - | (fep->ndev->dev_addr[4] << 8) | fep->ndev->dev_addr[5]); + if (!len) + break; - return 0; + pd += chunk; + } + return slot; } -static int emac_change_mtu(struct net_device *dev, int new_mtu) +/* BHs disabled (SG version for TAH equipped EMACs) */ +static int emac_start_xmit_sg(struct sk_buff *skb, struct net_device *ndev) { - struct ocp_enet_private *fep = dev->priv; - int old_mtu = dev->mtu; - unsigned long mode_reg; - emac_t *emacp = fep->emacp; - u32 em0mr0; - int i, full; - unsigned long flags; + struct ocp_enet_private *dev = ndev->priv; + int nr_frags = skb_shinfo(skb)->nr_frags; + int len = skb->len, chunk; + int slot, i; + u16 ctrl; + u32 pd; - if ((new_mtu < EMAC_MIN_MTU) || (new_mtu > EMAC_MAX_MTU)) { - printk(KERN_ERR - "emac: Invalid MTU setting, MTU must be between %d and %d\n", - EMAC_MIN_MTU, EMAC_MAX_MTU); - return -EINVAL; - } + /* This is common "fast" path */ + if (likely(!nr_frags && len <= MAL_MAX_TX_SIZE)) + return emac_start_xmit(skb, ndev); - if (old_mtu != new_mtu && netif_running(dev)) { - /* Stop rx engine */ - em0mr0 = in_be32(&emacp->em0mr0); - out_be32(&emacp->em0mr0, em0mr0 & ~EMAC_M0_RXE); - - /* Wait for descriptors to be empty */ - do { - full = 0; - for (i = 0; i < NUM_RX_BUFF; i++) - if (!(fep->rx_desc[i].ctrl & MAL_RX_CTRL_EMPTY)) { - printk(KERN_NOTICE - "emac: RX ring is still full\n"); - full = 1; - } - } while (full); - - spin_lock_irqsave(&fep->lock, flags); - - mal_disable_rx_channels(fep->mal, fep->commac.rx_chan_mask); - - /* Destroy all old rx skbs */ - for (i = 0; i < NUM_RX_BUFF; i++) { - dma_unmap_single(&fep->ocpdev->dev, - fep->rx_desc[i].data_ptr, - fep->rx_desc[i].data_len, - DMA_FROM_DEVICE); - dev_kfree_skb(fep->rx_skb[i]); - fep->rx_skb[i] = NULL; - } + len -= skb->data_len; - /* Set new rx_buffer_size, jumbo cap, and advertise new mtu */ - mode_reg = in_be32(&emacp->em0mr1); - if (new_mtu > ENET_DEF_MTU_SIZE) { - mode_reg |= EMAC_M1_JUMBO_ENABLE; - fep->rx_buffer_size = EMAC_MAX_FRAME; - } else { - mode_reg &= ~EMAC_M1_JUMBO_ENABLE; - fep->rx_buffer_size = ENET_DEF_BUF_SIZE; - } - dev->mtu = new_mtu; - out_be32(&emacp->em0mr1, mode_reg); + /* Note, this is only an *estimation*, we can still run out of empty + * slots because of the additional fragmentation into + * MAL_MAX_TX_SIZE-sized chunks + */ + if (unlikely(dev->tx_cnt + nr_frags + mal_tx_chunks(len) > NUM_TX_BUFF)) + goto stop_queue; + + ctrl = EMAC_TX_CTRL_GFCS | EMAC_TX_CTRL_GP | MAL_TX_CTRL_READY | + emac_tx_csum(dev, skb); + slot = dev->tx_slot; + + /* skb data */ + dev->tx_skb[slot] = NULL; + chunk = min(len, MAL_MAX_TX_SIZE); + dev->tx_desc[slot].data_ptr = pd = + dma_map_single(dev->ldev, skb->data, len, DMA_TO_DEVICE); + dev->tx_desc[slot].data_len = (u16) chunk; + len -= chunk; + if (unlikely(len)) + slot = emac_xmit_split(dev, slot, pd + chunk, len, !nr_frags, + ctrl); + /* skb fragments */ + for (i = 0; i < nr_frags; ++i) { + struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i]; + len = frag->size; - /* Re-init rx skbs */ - fep->rx_slot = 0; - emac_rx_fill(dev, 0); + if (unlikely(dev->tx_cnt + mal_tx_chunks(len) >= NUM_TX_BUFF)) + goto undo_frame; - /* Restart the rx engine */ - mal_enable_rx_channels(fep->mal, fep->commac.rx_chan_mask); - out_be32(&emacp->em0mr0, em0mr0 | EMAC_M0_RXE); + pd = dma_map_page(dev->ldev, frag->page, frag->page_offset, len, + DMA_TO_DEVICE); - spin_unlock_irqrestore(&fep->lock, flags); + slot = emac_xmit_split(dev, slot, pd, len, i == nr_frags - 1, + ctrl); } - return 0; -} + DBG2("%d: xmit_sg(%u) %d - %d" NL, dev->def->index, skb->len, + dev->tx_slot, slot); -static void __emac_set_multicast_list(struct net_device *dev) -{ - struct ocp_enet_private *fep = dev->priv; - emac_t *emacp = fep->emacp; - u32 rmr = in_be32(&emacp->em0rmr); + /* Attach skb to the last slot so we don't release it too early */ + dev->tx_skb[slot] = skb; - /* First clear all special bits, they can be set later */ - rmr &= ~(EMAC_RMR_PME | EMAC_RMR_PMME | EMAC_RMR_MAE); + /* Send the packet out */ + if (dev->tx_slot == NUM_TX_BUFF - 1) + ctrl |= MAL_TX_CTRL_WRAP; + barrier(); + dev->tx_desc[dev->tx_slot].ctrl = ctrl; + dev->tx_slot = (slot + 1) % NUM_TX_BUFF; - if (dev->flags & IFF_PROMISC) { - rmr |= EMAC_RMR_PME; - } else if (dev->flags & IFF_ALLMULTI || 32 < dev->mc_count) { - /* - * Must be setting up to use multicast - * Now check for promiscuous multicast - */ - rmr |= EMAC_RMR_PMME; - } else if (dev->flags & IFF_MULTICAST && 0 < dev->mc_count) { - unsigned short em0gaht[4] = { 0, 0, 0, 0 }; - struct dev_mc_list *dmi; - - /* Need to hash on the multicast address. */ - for (dmi = dev->mc_list; dmi; dmi = dmi->next) { - unsigned long mc_crc; - unsigned int bit_number; - - mc_crc = ether_crc(6, (char *)dmi->dmi_addr); - bit_number = 63 - (mc_crc >> 26); /* MSB: 0 LSB: 63 */ - em0gaht[bit_number >> 4] |= - 0x8000 >> (bit_number & 0x0f); - } - emacp->em0gaht1 = em0gaht[0]; - emacp->em0gaht2 = em0gaht[1]; - emacp->em0gaht3 = em0gaht[2]; - emacp->em0gaht4 = em0gaht[3]; + return emac_xmit_finish(dev, skb->len); - /* Turn on multicast addressing */ - rmr |= EMAC_RMR_MAE; + undo_frame: + /* Well, too bad. Our previous estimation was overly optimistic. + * Undo everything. + */ + while (slot != dev->tx_slot) { + dev->tx_desc[slot].ctrl = 0; + --dev->tx_cnt; + if (--slot < 0) + slot = NUM_TX_BUFF - 1; } - out_be32(&emacp->em0rmr, rmr); + ++dev->estats.tx_undo; + + stop_queue: + netif_stop_queue(ndev); + DBG2("%d: stopped TX queue" NL, dev->def->index); + return 1; } +#else +# define emac_start_xmit_sg emac_start_xmit +#endif /* !defined(CONFIG_IBM_EMAC_TAH) */ -static int emac_init_tah(struct ocp_enet_private *fep) +/* BHs disabled */ +static void emac_parse_tx_error(struct ocp_enet_private *dev, u16 ctrl) { - tah_t *tahp; + struct ibm_emac_error_stats *st = &dev->estats; + DBG("%d: BD TX error %04x" NL, dev->def->index, ctrl); + + ++st->tx_bd_errors; + if (ctrl & EMAC_TX_ST_BFCS) + ++st->tx_bd_bad_fcs; + if (ctrl & EMAC_TX_ST_LCS) + ++st->tx_bd_carrier_loss; + if (ctrl & EMAC_TX_ST_ED) + ++st->tx_bd_excessive_deferral; + if (ctrl & EMAC_TX_ST_EC) + ++st->tx_bd_excessive_collisions; + if (ctrl & EMAC_TX_ST_LC) + ++st->tx_bd_late_collision; + if (ctrl & EMAC_TX_ST_MC) + ++st->tx_bd_multple_collisions; + if (ctrl & EMAC_TX_ST_SC) + ++st->tx_bd_single_collision; + if (ctrl & EMAC_TX_ST_UR) + ++st->tx_bd_underrun; + if (ctrl & EMAC_TX_ST_SQE) + ++st->tx_bd_sqe; +} - /* Initialize TAH and enable checksum verification */ - tahp = (tah_t *) ioremap(fep->tah_dev->def->paddr, sizeof(*tahp)); +static void emac_poll_tx(void *param) +{ + struct ocp_enet_private *dev = param; + DBG2("%d: poll_tx, %d %d" NL, dev->def->index, dev->tx_cnt, + dev->ack_slot); + + if (dev->tx_cnt) { + u16 ctrl; + int slot = dev->ack_slot, n = 0; + again: + ctrl = dev->tx_desc[slot].ctrl; + if (!(ctrl & MAL_TX_CTRL_READY)) { + struct sk_buff *skb = dev->tx_skb[slot]; + ++n; + + if (skb) { + dev_kfree_skb(skb); + dev->tx_skb[slot] = NULL; + } + slot = (slot + 1) % NUM_TX_BUFF; - if (tahp == NULL) { - printk(KERN_ERR "tah%d: Cannot ioremap TAH registers!\n", - fep->tah_dev->def->index); + if (unlikely(EMAC_IS_BAD_TX(ctrl))) + emac_parse_tx_error(dev, ctrl); - return -ENOMEM; - } - - out_be32(&tahp->tah_mr, TAH_MR_SR); + if (--dev->tx_cnt) + goto again; + } + if (n) { + dev->ack_slot = slot; + if (netif_queue_stopped(dev->ndev) && + dev->tx_cnt < EMAC_TX_WAKEUP_THRESH) + netif_wake_queue(dev->ndev); - /* wait for reset to complete */ - while (in_be32(&tahp->tah_mr) & TAH_MR_SR) ; + DBG2("%d: tx %d pkts" NL, dev->def->index, n); + } + } +} - /* 10KB TAH TX FIFO accomodates the max MTU of 9000 */ - out_be32(&tahp->tah_mr, - TAH_MR_CVR | TAH_MR_ST_768 | TAH_MR_TFS_10KB | TAH_MR_DTFP | - TAH_MR_DIG); +static inline void emac_recycle_rx_skb(struct ocp_enet_private *dev, int slot, + int len) +{ + struct sk_buff *skb = dev->rx_skb[slot]; + DBG2("%d: recycle %d %d" NL, dev->def->index, slot, len); - iounmap(tahp); + if (len) + dma_map_single(dev->ldev, skb->data - 2, + EMAC_DMA_ALIGN(len + 2), DMA_FROM_DEVICE); - return 0; + dev->rx_desc[slot].data_len = 0; + barrier(); + dev->rx_desc[slot].ctrl = MAL_RX_CTRL_EMPTY | + (slot == (NUM_RX_BUFF - 1) ? MAL_RX_CTRL_WRAP : 0); } -static void emac_init_rings(struct net_device *dev) +static void emac_parse_rx_error(struct ocp_enet_private *dev, u16 ctrl) { - struct ocp_enet_private *ep = dev->priv; - int loop; + struct ibm_emac_error_stats *st = &dev->estats; + DBG("%d: BD RX error %04x" NL, dev->def->index, ctrl); + + ++st->rx_bd_errors; + if (ctrl & EMAC_RX_ST_OE) + ++st->rx_bd_overrun; + if (ctrl & EMAC_RX_ST_BP) + ++st->rx_bd_bad_packet; + if (ctrl & EMAC_RX_ST_RP) + ++st->rx_bd_runt_packet; + if (ctrl & EMAC_RX_ST_SE) + ++st->rx_bd_short_event; + if (ctrl & EMAC_RX_ST_AE) + ++st->rx_bd_alignment_error; + if (ctrl & EMAC_RX_ST_BFCS) + ++st->rx_bd_bad_fcs; + if (ctrl & EMAC_RX_ST_PTL) + ++st->rx_bd_packet_too_long; + if (ctrl & EMAC_RX_ST_ORE) + ++st->rx_bd_out_of_range; + if (ctrl & EMAC_RX_ST_IRE) + ++st->rx_bd_in_range; +} - ep->tx_desc = (struct mal_descriptor *)((char *)ep->mal->tx_virt_addr + - (ep->mal_tx_chan * - MAL_DT_ALIGN)); - ep->rx_desc = - (struct mal_descriptor *)((char *)ep->mal->rx_virt_addr + - (ep->mal_rx_chan * MAL_DT_ALIGN)); +static inline void emac_rx_csum(struct ocp_enet_private *dev, + struct sk_buff *skb, u16 ctrl) +{ +#if defined(CONFIG_IBM_EMAC_TAH) + if (!ctrl && dev->tah_dev) { + skb->ip_summed = CHECKSUM_UNNECESSARY; + ++dev->stats.rx_packets_csum; + } +#endif +} - /* Fill in the transmit descriptor ring. */ - for (loop = 0; loop < NUM_TX_BUFF; loop++) { - if (ep->tx_skb[loop]) { - dma_unmap_single(&ep->ocpdev->dev, - ep->tx_desc[loop].data_ptr, - ep->tx_desc[loop].data_len, - DMA_TO_DEVICE); - dev_kfree_skb_irq(ep->tx_skb[loop]); +static inline int emac_rx_sg_append(struct ocp_enet_private *dev, int slot) +{ + if (likely(dev->rx_sg_skb != NULL)) { + int len = dev->rx_desc[slot].data_len; + int tot_len = dev->rx_sg_skb->len + len; + + if (unlikely(tot_len + 2 > dev->rx_skb_size)) { + ++dev->estats.rx_dropped_mtu; + dev_kfree_skb(dev->rx_sg_skb); + dev->rx_sg_skb = NULL; + } else { + cacheable_memcpy(dev->rx_sg_skb->tail, + dev->rx_skb[slot]->data, len); + skb_put(dev->rx_sg_skb, len); + emac_recycle_rx_skb(dev, slot, len); + return 0; } - ep->tx_skb[loop] = NULL; - ep->tx_desc[loop].ctrl = 0; - ep->tx_desc[loop].data_len = 0; - ep->tx_desc[loop].data_ptr = NULL; - } - ep->tx_desc[loop - 1].ctrl |= MAL_TX_CTRL_WRAP; - - /* Format the receive descriptor ring. */ - ep->rx_slot = 0; - /* Default is MTU=1500 + Ethernet overhead */ - ep->rx_buffer_size = dev->mtu + ENET_HEADER_SIZE + ENET_FCS_SIZE; - emac_rx_fill(dev, 0); - if (ep->rx_slot != 0) { - printk(KERN_ERR - "%s: Not enough mem for RxChain durning Open?\n", - dev->name); - /*We couldn't fill the ring at startup? - *We could clean up and fail to open but right now we will try to - *carry on. It may be a sign of a bad NUM_RX_BUFF value - */ } - - ep->tx_cnt = 0; - ep->tx_slot = 0; - ep->ack_slot = 0; + emac_recycle_rx_skb(dev, slot, 0); + return -1; } -static void emac_reset_configure(struct ocp_enet_private *fep) +/* BHs disabled */ +static int emac_poll_rx(void *param, int budget) { - emac_t *emacp = fep->emacp; - int i; - - mal_disable_tx_channels(fep->mal, fep->commac.tx_chan_mask); - mal_disable_rx_channels(fep->mal, fep->commac.rx_chan_mask); + struct ocp_enet_private *dev = param; + int slot = dev->rx_slot, received = 0; - /* - * Check for a link, some PHYs don't provide a clock if - * no link is present. Some EMACs will not come out of - * soft reset without a PHY clock present. - */ - if (fep->phy_mii.def->ops->poll_link(&fep->phy_mii)) { - /* Reset the EMAC */ - out_be32(&emacp->em0mr0, EMAC_M0_SRST); - udelay(20); - for (i = 0; i < 100; i++) { - if ((in_be32(&emacp->em0mr0) & EMAC_M0_SRST) == 0) - break; - udelay(10); - } - - if (i >= 100) { - printk(KERN_ERR "%s: Cannot reset EMAC\n", - fep->ndev->name); - return; - } - } + DBG2("%d: poll_rx(%d)" NL, dev->def->index, budget); - /* Switch IRQs off for now */ - out_be32(&emacp->em0iser, 0); + again: + while (budget > 0) { + int len; + struct sk_buff *skb; + u16 ctrl = dev->rx_desc[slot].ctrl; - /* Configure MAL rx channel */ - mal_set_rcbs(fep->mal, fep->mal_rx_chan, DESC_BUF_SIZE_REG); + if (ctrl & MAL_RX_CTRL_EMPTY) + break; - /* set the high address */ - out_be32(&emacp->em0iahr, - (fep->ndev->dev_addr[0] << 8) | fep->ndev->dev_addr[1]); + skb = dev->rx_skb[slot]; + barrier(); + len = dev->rx_desc[slot].data_len; - /* set the low address */ - out_be32(&emacp->em0ialr, - (fep->ndev->dev_addr[2] << 24) | (fep->ndev->dev_addr[3] << 16) - | (fep->ndev->dev_addr[4] << 8) | fep->ndev->dev_addr[5]); + if (unlikely(!MAL_IS_SINGLE_RX(ctrl))) + goto sg; - /* Adjust to link */ - if (netif_carrier_ok(fep->ndev)) - emac_adjust_to_link(fep); + ctrl &= EMAC_BAD_RX_MASK; + if (unlikely(ctrl && ctrl != EMAC_RX_TAH_BAD_CSUM)) { + emac_parse_rx_error(dev, ctrl); + ++dev->estats.rx_dropped_error; + emac_recycle_rx_skb(dev, slot, 0); + len = 0; + goto next; + } - /* enable broadcast/individual address and RX FIFO defaults */ - out_be32(&emacp->em0rmr, EMAC_RMR_DEFAULT); + if (len && len < EMAC_RX_COPY_THRESH) { + struct sk_buff *copy_skb = + alloc_skb(len + EMAC_RX_SKB_HEADROOM + 2, GFP_ATOMIC); + if (unlikely(!copy_skb)) + goto oom; + + skb_reserve(copy_skb, EMAC_RX_SKB_HEADROOM + 2); + cacheable_memcpy(copy_skb->data - 2, skb->data - 2, + len + 2); + emac_recycle_rx_skb(dev, slot, len); + skb = copy_skb; + } else if (unlikely(emac_alloc_rx_skb(dev, slot, GFP_ATOMIC))) + goto oom; + + skb_put(skb, len); + push_packet: + skb->dev = dev->ndev; + skb->protocol = eth_type_trans(skb, dev->ndev); + emac_rx_csum(dev, skb, ctrl); + + if (unlikely(netif_receive_skb(skb) == NET_RX_DROP)) + ++dev->estats.rx_dropped_stack; + next: + ++dev->stats.rx_packets; + skip: + dev->stats.rx_bytes += len; + slot = (slot + 1) % NUM_RX_BUFF; + --budget; + ++received; + continue; + sg: + if (ctrl & MAL_RX_CTRL_FIRST) { + BUG_ON(dev->rx_sg_skb); + if (unlikely(emac_alloc_rx_skb(dev, slot, GFP_ATOMIC))) { + DBG("%d: rx OOM %d" NL, dev->def->index, slot); + ++dev->estats.rx_dropped_oom; + emac_recycle_rx_skb(dev, slot, 0); + } else { + dev->rx_sg_skb = skb; + skb_put(skb, len); + } + } else if (!emac_rx_sg_append(dev, slot) && + (ctrl & MAL_RX_CTRL_LAST)) { + + skb = dev->rx_sg_skb; + dev->rx_sg_skb = NULL; + + ctrl &= EMAC_BAD_RX_MASK; + if (unlikely(ctrl && ctrl != EMAC_RX_TAH_BAD_CSUM)) { + emac_parse_rx_error(dev, ctrl); + ++dev->estats.rx_dropped_error; + dev_kfree_skb(skb); + len = 0; + } else + goto push_packet; + } + goto skip; + oom: + DBG("%d: rx OOM %d" NL, dev->def->index, slot); + /* Drop the packet and recycle skb */ + ++dev->estats.rx_dropped_oom; + emac_recycle_rx_skb(dev, slot, 0); + goto next; + } - /* set transmit request threshold register */ - out_be32(&emacp->em0trtr, EMAC_TRTR_DEFAULT); + if (received) { + DBG2("%d: rx %d BDs" NL, dev->def->index, received); + dev->rx_slot = slot; + } - /* Reconfigure multicast */ - __emac_set_multicast_list(fep->ndev); + if (unlikely(budget && dev->commac.rx_stopped)) { + struct ocp_func_emac_data *emacdata = dev->def->additions; - /* Set receiver/transmitter defaults */ - out_be32(&emacp->em0rwmr, EMAC_RWMR_DEFAULT); - out_be32(&emacp->em0tmr0, EMAC_TMR0_DEFAULT); - out_be32(&emacp->em0tmr1, EMAC_TMR1_DEFAULT); + barrier(); + if (!(dev->rx_desc[slot].ctrl & MAL_RX_CTRL_EMPTY)) { + DBG2("%d: rx restart" NL, dev->def->index); + received = 0; + goto again; + } - /* set frame gap */ - out_be32(&emacp->em0ipgvr, CONFIG_IBM_EMAC_FGAP); - - /* set VLAN Tag Protocol Identifier */ - out_be32(&emacp->em0vtpid, 0x8100); + if (dev->rx_sg_skb) { + DBG2("%d: dropping partial rx packet" NL, + dev->def->index); + ++dev->estats.rx_dropped_error; + dev_kfree_skb(dev->rx_sg_skb); + dev->rx_sg_skb = NULL; + } - /* Init ring buffers */ - emac_init_rings(fep->ndev); + dev->commac.rx_stopped = 0; + mal_enable_rx_channel(dev->mal, emacdata->mal_rx_chan); + emac_rx_enable(dev); + dev->rx_slot = 0; + } + return received; } -static void emac_kick(struct ocp_enet_private *fep) +/* BHs disabled */ +static int emac_peek_rx(void *param) { - emac_t *emacp = fep->emacp; - unsigned long emac_ier; - - emac_ier = EMAC_ISR_PP | EMAC_ISR_BP | EMAC_ISR_RP | - EMAC_ISR_SE | EMAC_ISR_PTLE | EMAC_ISR_ALE | - EMAC_ISR_BFCS | EMAC_ISR_ORE | EMAC_ISR_IRE; + struct ocp_enet_private *dev = param; + return !(dev->rx_desc[dev->rx_slot].ctrl & MAL_RX_CTRL_EMPTY); +} - out_be32(&emacp->em0iser, emac_ier); +/* BHs disabled */ +static int emac_peek_rx_sg(void *param) +{ + struct ocp_enet_private *dev = param; + int slot = dev->rx_slot; + while (1) { + u16 ctrl = dev->rx_desc[slot].ctrl; + if (ctrl & MAL_RX_CTRL_EMPTY) + return 0; + else if (ctrl & MAL_RX_CTRL_LAST) + return 1; - /* enable all MAL transmit and receive channels */ - mal_enable_tx_channels(fep->mal, fep->commac.tx_chan_mask); - mal_enable_rx_channels(fep->mal, fep->commac.rx_chan_mask); + slot = (slot + 1) % NUM_RX_BUFF; - /* set transmit and receive enable */ - out_be32(&emacp->em0mr0, EMAC_M0_TXE | EMAC_M0_RXE); + /* I'm just being paranoid here :) */ + if (unlikely(slot == dev->rx_slot)) + return 0; + } } -static void -emac_start_link(struct ocp_enet_private *fep, struct ethtool_cmd *ep) +/* Hard IRQ */ +static void emac_rxde(void *param) { - u32 advertise; - int autoneg; - int forced_speed; - int forced_duplex; + struct ocp_enet_private *dev = param; + ++dev->estats.rx_stopped; + emac_rx_disable_async(dev); +} - /* Default advertise */ - advertise = ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | - ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | - ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full; - autoneg = fep->want_autoneg; - forced_speed = fep->phy_mii.speed; - forced_duplex = fep->phy_mii.duplex; +/* Hard IRQ */ +static irqreturn_t emac_irq(int irq, void *dev_instance, struct pt_regs *regs) +{ + struct ocp_enet_private *dev = dev_instance; + struct emac_regs *p = dev->emacp; + struct ibm_emac_error_stats *st = &dev->estats; + + u32 isr = in_be32(&p->isr); + out_be32(&p->isr, isr); + + DBG("%d: isr = %08x" NL, dev->def->index, isr); + + if (isr & EMAC_ISR_TXPE) + ++st->tx_parity; + if (isr & EMAC_ISR_RXPE) + ++st->rx_parity; + if (isr & EMAC_ISR_TXUE) + ++st->tx_underrun; + if (isr & EMAC_ISR_RXOE) + ++st->rx_fifo_overrun; + if (isr & EMAC_ISR_OVR) + ++st->rx_overrun; + if (isr & EMAC_ISR_BP) + ++st->rx_bad_packet; + if (isr & EMAC_ISR_RP) + ++st->rx_runt_packet; + if (isr & EMAC_ISR_SE) + ++st->rx_short_event; + if (isr & EMAC_ISR_ALE) + ++st->rx_alignment_error; + if (isr & EMAC_ISR_BFCS) + ++st->rx_bad_fcs; + if (isr & EMAC_ISR_PTLE) + ++st->rx_packet_too_long; + if (isr & EMAC_ISR_ORE) + ++st->rx_out_of_range; + if (isr & EMAC_ISR_IRE) + ++st->rx_in_range; + if (isr & EMAC_ISR_SQE) + ++st->tx_sqe; + if (isr & EMAC_ISR_TE) + ++st->tx_errors; - /* Setup link parameters */ - if (ep) { - if (ep->autoneg == AUTONEG_ENABLE) { - advertise = ep->advertising; - autoneg = 1; - } else { - autoneg = 0; - forced_speed = ep->speed; - forced_duplex = ep->duplex; - } - } + return IRQ_HANDLED; +} - /* Configure PHY & start aneg */ - fep->want_autoneg = autoneg; - if (autoneg) { - LINK_DEBUG(("%s: start link aneg, advertise: 0x%x\n", - fep->ndev->name, advertise)); - fep->phy_mii.def->ops->setup_aneg(&fep->phy_mii, advertise); - } else { - LINK_DEBUG(("%s: start link forced, speed: %d, duplex: %d\n", - fep->ndev->name, forced_speed, forced_duplex)); - fep->phy_mii.def->ops->setup_forced(&fep->phy_mii, forced_speed, - forced_duplex); - } - fep->timer_ticks = 0; - mod_timer(&fep->link_timer, jiffies + HZ); +static struct net_device_stats *emac_stats(struct net_device *ndev) +{ + struct ocp_enet_private *dev = ndev->priv; + struct ibm_emac_stats *st = &dev->stats; + struct ibm_emac_error_stats *est = &dev->estats; + struct net_device_stats *nst = &dev->nstats; + + DBG2("%d: stats" NL, dev->def->index); + + /* Compute "legacy" statistics */ + local_irq_disable(); + nst->rx_packets = (unsigned long)st->rx_packets; + nst->rx_bytes = (unsigned long)st->rx_bytes; + nst->tx_packets = (unsigned long)st->tx_packets; + nst->tx_bytes = (unsigned long)st->tx_bytes; + nst->rx_dropped = (unsigned long)(est->rx_dropped_oom + + est->rx_dropped_error + + est->rx_dropped_resize + + est->rx_dropped_mtu); + nst->tx_dropped = (unsigned long)est->tx_dropped; + + nst->rx_errors = (unsigned long)est->rx_bd_errors; + nst->rx_fifo_errors = (unsigned long)(est->rx_bd_overrun + + est->rx_fifo_overrun + + est->rx_overrun); + nst->rx_frame_errors = (unsigned long)(est->rx_bd_alignment_error + + est->rx_alignment_error); + nst->rx_crc_errors = (unsigned long)(est->rx_bd_bad_fcs + + est->rx_bad_fcs); + nst->rx_length_errors = (unsigned long)(est->rx_bd_runt_packet + + est->rx_bd_short_event + + est->rx_bd_packet_too_long + + est->rx_bd_out_of_range + + est->rx_bd_in_range + + est->rx_runt_packet + + est->rx_short_event + + est->rx_packet_too_long + + est->rx_out_of_range + + est->rx_in_range); + + nst->tx_errors = (unsigned long)(est->tx_bd_errors + est->tx_errors); + nst->tx_fifo_errors = (unsigned long)(est->tx_bd_underrun + + est->tx_underrun); + nst->tx_carrier_errors = (unsigned long)est->tx_bd_carrier_loss; + nst->collisions = (unsigned long)(est->tx_bd_excessive_deferral + + est->tx_bd_excessive_collisions + + est->tx_bd_late_collision + + est->tx_bd_multple_collisions); + local_irq_enable(); + return nst; } -static void emac_link_timer(unsigned long data) +static void emac_remove(struct ocp_device *ocpdev) { - struct ocp_enet_private *fep = (struct ocp_enet_private *)data; - int link; + struct ocp_enet_private *dev = ocp_get_drvdata(ocpdev); - if (fep->going_away) - return; + DBG("%d: remove" NL, dev->def->index); - spin_lock_irq(&fep->lock); + ocp_set_drvdata(ocpdev, 0); + unregister_netdev(dev->ndev); - link = fep->phy_mii.def->ops->poll_link(&fep->phy_mii); - LINK_DEBUG(("%s: poll_link: %d\n", fep->ndev->name, link)); + tah_fini(dev->tah_dev); + rgmii_fini(dev->rgmii_dev, dev->rgmii_input); + zmii_fini(dev->zmii_dev, dev->zmii_input); - if (link == netif_carrier_ok(fep->ndev)) { - if (!link && fep->want_autoneg && (++fep->timer_ticks) > 10) - emac_start_link(fep, NULL); - goto out; - } - printk(KERN_INFO "%s: Link is %s\n", fep->ndev->name, - link ? "Up" : "Down"); - if (link) { - netif_carrier_on(fep->ndev); - /* Chip needs a full reset on config change. That sucks, so I - * should ultimately move that to some tasklet to limit - * latency peaks caused by this code - */ - emac_reset_configure(fep); - if (fep->opened) - emac_kick(fep); - } else { - fep->timer_ticks = 0; - netif_carrier_off(fep->ndev); - } - out: - mod_timer(&fep->link_timer, jiffies + HZ); - spin_unlock_irq(&fep->lock); + emac_dbg_register(dev->def->index, 0); + + mal_unregister_commac(dev->mal, &dev->commac); + iounmap((void *)dev->emacp); + kfree(dev->ndev); } -static void emac_set_multicast_list(struct net_device *dev) -{ - struct ocp_enet_private *fep = dev->priv; +static struct mal_commac_ops emac_commac_ops = { + .poll_tx = &emac_poll_tx, + .poll_rx = &emac_poll_rx, + .peek_rx = &emac_peek_rx, + .rxde = &emac_rxde, +}; - spin_lock_irq(&fep->lock); - __emac_set_multicast_list(dev); - spin_unlock_irq(&fep->lock); -} +static struct mal_commac_ops emac_commac_sg_ops = { + .poll_tx = &emac_poll_tx, + .poll_rx = &emac_poll_rx, + .peek_rx = &emac_peek_rx_sg, + .rxde = &emac_rxde, +}; -static int emac_get_settings(struct net_device *ndev, struct ethtool_cmd *cmd) +/* Ethtool support */ +static int emac_ethtool_get_settings(struct net_device *ndev, + struct ethtool_cmd *cmd) { - struct ocp_enet_private *fep = ndev->priv; + struct ocp_enet_private *dev = ndev->priv; - cmd->supported = fep->phy_mii.def->features; + cmd->supported = dev->phy.features; cmd->port = PORT_MII; - cmd->transceiver = XCVR_EXTERNAL; - cmd->phy_address = fep->mii_phy_addr; - spin_lock_irq(&fep->lock); - cmd->autoneg = fep->want_autoneg; - cmd->speed = fep->phy_mii.speed; - cmd->duplex = fep->phy_mii.duplex; - spin_unlock_irq(&fep->lock); + cmd->phy_address = dev->phy.address; + cmd->transceiver = + dev->phy.address >= 0 ? XCVR_EXTERNAL : XCVR_INTERNAL; + + local_bh_disable(); + cmd->advertising = dev->phy.advertising; + cmd->autoneg = dev->phy.autoneg; + cmd->speed = dev->phy.speed; + cmd->duplex = dev->phy.duplex; + local_bh_enable(); + return 0; } -static int emac_set_settings(struct net_device *ndev, struct ethtool_cmd *cmd) +static int emac_ethtool_set_settings(struct net_device *ndev, + struct ethtool_cmd *cmd) { - struct ocp_enet_private *fep = ndev->priv; - unsigned long features = fep->phy_mii.def->features; + struct ocp_enet_private *dev = ndev->priv; + u32 f = dev->phy.features; - if (!capable(CAP_NET_ADMIN)) - return -EPERM; + DBG("%d: set_settings(%d, %d, %d, 0x%08x)" NL, dev->def->index, + cmd->autoneg, cmd->speed, cmd->duplex, cmd->advertising); + /* Basic sanity checks */ + if (dev->phy.address < 0) + return -EOPNOTSUPP; if (cmd->autoneg != AUTONEG_ENABLE && cmd->autoneg != AUTONEG_DISABLE) return -EINVAL; if (cmd->autoneg == AUTONEG_ENABLE && cmd->advertising == 0) return -EINVAL; if (cmd->duplex != DUPLEX_HALF && cmd->duplex != DUPLEX_FULL) return -EINVAL; - if (cmd->autoneg == AUTONEG_DISABLE) + + if (cmd->autoneg == AUTONEG_DISABLE) { switch (cmd->speed) { case SPEED_10: - if (cmd->duplex == DUPLEX_HALF && - (features & SUPPORTED_10baseT_Half) == 0) + if (cmd->duplex == DUPLEX_HALF + && !(f & SUPPORTED_10baseT_Half)) return -EINVAL; - if (cmd->duplex == DUPLEX_FULL && - (features & SUPPORTED_10baseT_Full) == 0) + if (cmd->duplex == DUPLEX_FULL + && !(f & SUPPORTED_10baseT_Full)) return -EINVAL; break; case SPEED_100: - if (cmd->duplex == DUPLEX_HALF && - (features & SUPPORTED_100baseT_Half) == 0) + if (cmd->duplex == DUPLEX_HALF + && !(f & SUPPORTED_100baseT_Half)) return -EINVAL; - if (cmd->duplex == DUPLEX_FULL && - (features & SUPPORTED_100baseT_Full) == 0) + if (cmd->duplex == DUPLEX_FULL + && !(f & SUPPORTED_100baseT_Full)) return -EINVAL; break; case SPEED_1000: - if (cmd->duplex == DUPLEX_HALF && - (features & SUPPORTED_1000baseT_Half) == 0) + if (cmd->duplex == DUPLEX_HALF + && !(f & SUPPORTED_1000baseT_Half)) return -EINVAL; - if (cmd->duplex == DUPLEX_FULL && - (features & SUPPORTED_1000baseT_Full) == 0) + if (cmd->duplex == DUPLEX_FULL + && !(f & SUPPORTED_1000baseT_Full)) return -EINVAL; break; default: return -EINVAL; - } else if ((features & SUPPORTED_Autoneg) == 0) - return -EINVAL; - spin_lock_irq(&fep->lock); - emac_start_link(fep, cmd); - spin_unlock_irq(&fep->lock); + } + + local_bh_disable(); + dev->phy.def->ops->setup_forced(&dev->phy, cmd->speed, + cmd->duplex); + + } else { + if (!(f & SUPPORTED_Autoneg)) + return -EINVAL; + + local_bh_disable(); + dev->phy.def->ops->setup_aneg(&dev->phy, + (cmd->advertising & f) | + (dev->phy.advertising & + (ADVERTISED_Pause | + ADVERTISED_Asym_Pause))); + } + emac_force_link_update(dev); + local_bh_enable(); + return 0; } -static void -emac_get_drvinfo(struct net_device *ndev, struct ethtool_drvinfo *info) +static void emac_ethtool_get_ringparam(struct net_device *ndev, + struct ethtool_ringparam *rp) { - struct ocp_enet_private *fep = ndev->priv; - - strcpy(info->driver, DRV_NAME); - strcpy(info->version, DRV_VERSION); - info->fw_version[0] = '\0'; - sprintf(info->bus_info, "IBM EMAC %d", fep->ocpdev->def->index); - info->regdump_len = 0; + rp->rx_max_pending = rp->rx_pending = NUM_RX_BUFF; + rp->tx_max_pending = rp->tx_pending = NUM_TX_BUFF; } -static int emac_nway_reset(struct net_device *ndev) +static void emac_ethtool_get_pauseparam(struct net_device *ndev, + struct ethtool_pauseparam *pp) { - struct ocp_enet_private *fep = ndev->priv; + struct ocp_enet_private *dev = ndev->priv; + + local_bh_disable(); + if ((dev->phy.features & SUPPORTED_Autoneg) && + (dev->phy.advertising & (ADVERTISED_Pause | ADVERTISED_Asym_Pause))) + pp->autoneg = 1; + + if (dev->phy.duplex == DUPLEX_FULL) { + if (dev->phy.pause) + pp->rx_pause = pp->tx_pause = 1; + else if (dev->phy.asym_pause) + pp->tx_pause = 1; + } + local_bh_enable(); +} - if (!fep->want_autoneg) - return -EINVAL; - spin_lock_irq(&fep->lock); - emac_start_link(fep, NULL); - spin_unlock_irq(&fep->lock); - return 0; +static u32 emac_ethtool_get_rx_csum(struct net_device *ndev) +{ + struct ocp_enet_private *dev = ndev->priv; + return dev->tah_dev != 0; } -static u32 emac_get_link(struct net_device *ndev) +static int emac_get_regs_len(struct ocp_enet_private *dev) { - return netif_carrier_ok(ndev); + return sizeof(struct emac_ethtool_regs_subhdr) + EMAC_ETHTOOL_REGS_SIZE; } -static struct ethtool_ops emac_ethtool_ops = { - .get_settings = emac_get_settings, - .set_settings = emac_set_settings, - .get_drvinfo = emac_get_drvinfo, - .nway_reset = emac_nway_reset, - .get_link = emac_get_link -}; +static int emac_ethtool_get_regs_len(struct net_device *ndev) +{ + struct ocp_enet_private *dev = ndev->priv; + return sizeof(struct emac_ethtool_regs_hdr) + + emac_get_regs_len(dev) + mal_get_regs_len(dev->mal) + + zmii_get_regs_len(dev->zmii_dev) + + rgmii_get_regs_len(dev->rgmii_dev) + + tah_get_regs_len(dev->tah_dev); +} -static int emac_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +static void *emac_dump_regs(struct ocp_enet_private *dev, void *buf) { - struct ocp_enet_private *fep = dev->priv; - uint16_t *data = (uint16_t *) & rq->ifr_ifru; + struct emac_ethtool_regs_subhdr *hdr = buf; - switch (cmd) { - case SIOCGMIIPHY: - data[0] = fep->mii_phy_addr; - /* Fall through */ - case SIOCGMIIREG: - data[3] = emac_phy_read(dev, fep->mii_phy_addr, data[1]); - return 0; - case SIOCSMIIREG: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; + hdr->version = EMAC_ETHTOOL_REGS_VER; + hdr->index = dev->def->index; + memcpy_fromio(hdr + 1, dev->emacp, EMAC_ETHTOOL_REGS_SIZE); + return ((void *)(hdr + 1) + EMAC_ETHTOOL_REGS_SIZE); +} - emac_phy_write(dev, fep->mii_phy_addr, data[1], data[2]); - return 0; - default: - return -EOPNOTSUPP; +static void emac_ethtool_get_regs(struct net_device *ndev, + struct ethtool_regs *regs, void *buf) +{ + struct ocp_enet_private *dev = ndev->priv; + struct emac_ethtool_regs_hdr *hdr = buf; + + hdr->components = 0; + buf = hdr + 1; + + local_irq_disable(); + buf = mal_dump_regs(dev->mal, buf); + buf = emac_dump_regs(dev, buf); + if (dev->zmii_dev) { + hdr->components |= EMAC_ETHTOOL_REGS_ZMII; + buf = zmii_dump_regs(dev->zmii_dev, buf); } + if (dev->rgmii_dev) { + hdr->components |= EMAC_ETHTOOL_REGS_RGMII; + buf = rgmii_dump_regs(dev->rgmii_dev, buf); + } + if (dev->tah_dev) { + hdr->components |= EMAC_ETHTOOL_REGS_TAH; + buf = tah_dump_regs(dev->tah_dev, buf); + } + local_irq_enable(); } -static int emac_open(struct net_device *dev) +static int emac_ethtool_nway_reset(struct net_device *ndev) { - struct ocp_enet_private *fep = dev->priv; - int rc; + struct ocp_enet_private *dev = ndev->priv; + int res = 0; - spin_lock_irq(&fep->lock); + DBG("%d: nway_reset" NL, dev->def->index); - fep->opened = 1; - netif_carrier_off(dev); + if (dev->phy.address < 0) + return -EOPNOTSUPP; - /* Reset & configure the chip */ - emac_reset_configure(fep); + local_bh_disable(); + if (!dev->phy.autoneg) { + res = -EINVAL; + goto out; + } - spin_unlock_irq(&fep->lock); + dev->phy.def->ops->setup_aneg(&dev->phy, dev->phy.advertising); + emac_force_link_update(dev); - /* Request our interrupt lines */ - rc = request_irq(dev->irq, emac_mac_irq, 0, "IBM EMAC MAC", dev); - if (rc != 0) { - printk("dev->irq %d failed\n", dev->irq); - goto bail; - } - /* Kick the chip rx & tx channels into life */ - spin_lock_irq(&fep->lock); - emac_kick(fep); - spin_unlock_irq(&fep->lock); + out: + local_bh_enable(); + return res; +} - netif_start_queue(dev); - bail: - return rc; +static int emac_ethtool_get_stats_count(struct net_device *ndev) +{ + return EMAC_ETHTOOL_STATS_COUNT; } -static int emac_close(struct net_device *dev) +static void emac_ethtool_get_strings(struct net_device *ndev, u32 stringset, + u8 * buf) { - struct ocp_enet_private *fep = dev->priv; - emac_t *emacp = fep->emacp; + if (stringset == ETH_SS_STATS) + memcpy(buf, &emac_stats_keys, sizeof(emac_stats_keys)); +} - /* XXX Stop IRQ emitting here */ - spin_lock_irq(&fep->lock); - fep->opened = 0; - mal_disable_tx_channels(fep->mal, fep->commac.tx_chan_mask); - mal_disable_rx_channels(fep->mal, fep->commac.rx_chan_mask); - netif_carrier_off(dev); - netif_stop_queue(dev); +static void emac_ethtool_get_ethtool_stats(struct net_device *ndev, + struct ethtool_stats *estats, + u64 * tmp_stats) +{ + struct ocp_enet_private *dev = ndev->priv; + local_irq_disable(); + memcpy(tmp_stats, &dev->stats, sizeof(dev->stats)); + tmp_stats += sizeof(dev->stats) / sizeof(u64); + memcpy(tmp_stats, &dev->estats, sizeof(dev->estats)); + local_irq_enable(); +} - /* - * Check for a link, some PHYs don't provide a clock if - * no link is present. Some EMACs will not come out of - * soft reset without a PHY clock present. - */ - if (fep->phy_mii.def->ops->poll_link(&fep->phy_mii)) { - out_be32(&emacp->em0mr0, EMAC_M0_SRST); - udelay(10); +static void emac_ethtool_get_drvinfo(struct net_device *ndev, + struct ethtool_drvinfo *info) +{ + struct ocp_enet_private *dev = ndev->priv; - if (emacp->em0mr0 & EMAC_M0_SRST) { - /*not sure what to do here hopefully it clears before another open */ - printk(KERN_ERR - "%s: Phy SoftReset didn't clear, no link?\n", - dev->name); - } - } + strcpy(info->driver, "ibm_emac"); + strcpy(info->version, DRV_VERSION); + info->fw_version[0] = '\0'; + sprintf(info->bus_info, "PPC 4xx EMAC %d", dev->def->index); + info->n_stats = emac_ethtool_get_stats_count(ndev); + info->regdump_len = emac_ethtool_get_regs_len(ndev); +} - /* Free the irq's */ - free_irq(dev->irq, dev); +static struct ethtool_ops emac_ethtool_ops = { + .get_settings = emac_ethtool_get_settings, + .set_settings = emac_ethtool_set_settings, + .get_drvinfo = emac_ethtool_get_drvinfo, - spin_unlock_irq(&fep->lock); + .get_regs_len = emac_ethtool_get_regs_len, + .get_regs = emac_ethtool_get_regs, - return 0; -} + .nway_reset = emac_ethtool_nway_reset, -static void emac_remove(struct ocp_device *ocpdev) -{ - struct net_device *dev = ocp_get_drvdata(ocpdev); - struct ocp_enet_private *ep = dev->priv; - - /* FIXME: locking, races, ... */ - ep->going_away = 1; - ocp_set_drvdata(ocpdev, NULL); - if (ep->rgmii_dev) - emac_close_rgmii(ep->rgmii_dev); - if (ep->zmii_dev) - emac_close_zmii(ep->zmii_dev); - - unregister_netdev(dev); - del_timer_sync(&ep->link_timer); - mal_unregister_commac(ep->mal, &ep->commac); - iounmap((void *)ep->emacp); - kfree(dev); -} - -struct mal_commac_ops emac_commac_ops = { - .txeob = &emac_txeob_dev, - .txde = &emac_txde_dev, - .rxeob = &emac_rxeob_dev, - .rxde = &emac_rxde_dev, + .get_ringparam = emac_ethtool_get_ringparam, + .get_pauseparam = emac_ethtool_get_pauseparam, + + .get_rx_csum = emac_ethtool_get_rx_csum, + + .get_strings = emac_ethtool_get_strings, + .get_stats_count = emac_ethtool_get_stats_count, + .get_ethtool_stats = emac_ethtool_get_ethtool_stats, + + .get_link = ethtool_op_get_link, + .get_tx_csum = ethtool_op_get_tx_csum, + .get_sg = ethtool_op_get_sg, }; -#ifdef CONFIG_NET_POLL_CONTROLLER -static void emac_netpoll(struct net_device *ndev) +static int emac_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) { - emac_rxeob_dev((void *)ndev, 0); - emac_txeob_dev((void *)ndev, 0); + struct ocp_enet_private *dev = ndev->priv; + uint16_t *data = (uint16_t *) & rq->ifr_ifru; + + DBG("%d: ioctl %08x" NL, dev->def->index, cmd); + + if (dev->phy.address < 0) + return -EOPNOTSUPP; + + switch (cmd) { + case SIOCGMIIPHY: + case SIOCDEVPRIVATE: + data[0] = dev->phy.address; + /* Fall through */ + case SIOCGMIIREG: + case SIOCDEVPRIVATE + 1: + data[3] = emac_mdio_read(ndev, dev->phy.address, data[1]); + return 0; + + case SIOCSMIIREG: + case SIOCDEVPRIVATE + 2: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + emac_mdio_write(ndev, dev->phy.address, data[1], data[2]); + return 0; + default: + return -EOPNOTSUPP; + } } -#endif -static int emac_init_device(struct ocp_device *ocpdev, struct ibm_ocp_mal *mal) +static int __init emac_probe(struct ocp_device *ocpdev) { - int deferred_init = 0; - int rc = 0, i; + struct ocp_func_emac_data *emacdata = ocpdev->def->additions; struct net_device *ndev; - struct ocp_enet_private *ep; - struct ocp_func_emac_data *emacdata; - int commac_reg = 0; - u32 phy_map; + struct ocp_device *maldev; + struct ocp_enet_private *dev; + int err, i; + + DBG("%d: probe" NL, ocpdev->def->index); - emacdata = (struct ocp_func_emac_data *)ocpdev->def->additions; if (!emacdata) { printk(KERN_ERR "emac%d: Missing additional data!\n", ocpdev->def->index); @@ -1738,304 +1936,312 @@ static int emac_init_device(struct ocp_device *ocpdev, struct ibm_ocp_mal *mal) /* Allocate our net_device structure */ ndev = alloc_etherdev(sizeof(struct ocp_enet_private)); - if (ndev == NULL) { - printk(KERN_ERR - "emac%d: Could not allocate ethernet device.\n", + if (!ndev) { + printk(KERN_ERR "emac%d: could not allocate ethernet device!\n", ocpdev->def->index); return -ENOMEM; } - ep = ndev->priv; - ep->ndev = ndev; - ep->ocpdev = ocpdev; - ndev->irq = ocpdev->def->irq; - ep->wol_irq = emacdata->wol_irq; - if (emacdata->mdio_idx >= 0) { - if (emacdata->mdio_idx == ocpdev->def->index) { - /* Set the common MDIO net_device */ - mdio_ndev = ndev; - deferred_init = 1; - } - ep->mdio_dev = mdio_ndev; - } else { - ep->mdio_dev = ndev; - } + dev = ndev->priv; + dev->ndev = ndev; + dev->ldev = &ocpdev->dev; + dev->def = ocpdev->def; + SET_MODULE_OWNER(ndev); - ocp_set_drvdata(ocpdev, ndev); - - spin_lock_init(&ep->lock); - - /* Fill out MAL informations and register commac */ - ep->mal = mal; - ep->mal_tx_chan = emacdata->mal_tx_chan; - ep->mal_rx_chan = emacdata->mal_rx_chan; - ep->commac.ops = &emac_commac_ops; - ep->commac.dev = ndev; - ep->commac.tx_chan_mask = MAL_CHAN_MASK(ep->mal_tx_chan); - ep->commac.rx_chan_mask = MAL_CHAN_MASK(ep->mal_rx_chan); - rc = mal_register_commac(ep->mal, &ep->commac); - if (rc != 0) - goto bail; - commac_reg = 1; - - /* Map our MMIOs */ - ep->emacp = (emac_t *) ioremap(ocpdev->def->paddr, sizeof(emac_t)); - - /* Check if we need to attach to a ZMII */ - if (emacdata->zmii_idx >= 0) { - ep->zmii_input = emacdata->zmii_mux; - ep->zmii_dev = - ocp_find_device(OCP_ANY_ID, OCP_FUNC_ZMII, - emacdata->zmii_idx); - if (ep->zmii_dev == NULL) - printk(KERN_WARNING - "emac%d: ZMII %d requested but not found !\n", - ocpdev->def->index, emacdata->zmii_idx); - else if ((rc = - emac_init_zmii(ep->zmii_dev, ep->zmii_input, - emacdata->phy_mode)) != 0) - goto bail; + /* Find MAL device we are connected to */ + maldev = + ocp_find_device(OCP_VENDOR_IBM, OCP_FUNC_MAL, emacdata->mal_idx); + if (!maldev) { + printk(KERN_ERR "emac%d: unknown mal%d device!\n", + dev->def->index, emacdata->mal_idx); + err = -ENODEV; + goto out; + } + dev->mal = ocp_get_drvdata(maldev); + if (!dev->mal) { + printk(KERN_ERR "emac%d: mal%d hasn't been initialized yet!\n", + dev->def->index, emacdata->mal_idx); + err = -ENODEV; + goto out; } - /* Check if we need to attach to a RGMII */ - if (emacdata->rgmii_idx >= 0) { - ep->rgmii_input = emacdata->rgmii_mux; - ep->rgmii_dev = - ocp_find_device(OCP_ANY_ID, OCP_FUNC_RGMII, - emacdata->rgmii_idx); - if (ep->rgmii_dev == NULL) - printk(KERN_WARNING - "emac%d: RGMII %d requested but not found !\n", - ocpdev->def->index, emacdata->rgmii_idx); - else if ((rc = - emac_init_rgmii(ep->rgmii_dev, ep->rgmii_input, - emacdata->phy_mode)) != 0) - goto bail; + /* Register with MAL */ + dev->commac.ops = &emac_commac_ops; + dev->commac.dev = dev; + dev->commac.tx_chan_mask = MAL_CHAN_MASK(emacdata->mal_tx_chan); + dev->commac.rx_chan_mask = MAL_CHAN_MASK(emacdata->mal_rx_chan); + err = mal_register_commac(dev->mal, &dev->commac); + if (err) { + printk(KERN_ERR "emac%d: failed to register with mal%d!\n", + dev->def->index, emacdata->mal_idx); + goto out; + } + dev->rx_skb_size = emac_rx_skb_size(ndev->mtu); + dev->rx_sync_size = emac_rx_sync_size(ndev->mtu); + + /* Get pointers to BD rings */ + dev->tx_desc = + dev->mal->bd_virt + mal_tx_bd_offset(dev->mal, + emacdata->mal_tx_chan); + dev->rx_desc = + dev->mal->bd_virt + mal_rx_bd_offset(dev->mal, + emacdata->mal_rx_chan); + + DBG("%d: tx_desc %p" NL, ocpdev->def->index, dev->tx_desc); + DBG("%d: rx_desc %p" NL, ocpdev->def->index, dev->rx_desc); + + /* Clean rings */ + memset(dev->tx_desc, 0, NUM_TX_BUFF * sizeof(struct mal_descriptor)); + memset(dev->rx_desc, 0, NUM_RX_BUFF * sizeof(struct mal_descriptor)); + + /* If we depend on another EMAC for MDIO, check whether it was probed already */ + if (emacdata->mdio_idx >= 0 && emacdata->mdio_idx != ocpdev->def->index) { + struct ocp_device *mdiodev = + ocp_find_device(OCP_VENDOR_IBM, OCP_FUNC_EMAC, + emacdata->mdio_idx); + if (!mdiodev) { + printk(KERN_ERR "emac%d: unknown emac%d device!\n", + dev->def->index, emacdata->mdio_idx); + err = -ENODEV; + goto out2; + } + dev->mdio_dev = ocp_get_drvdata(mdiodev); + if (!dev->mdio_dev) { + printk(KERN_ERR + "emac%d: emac%d hasn't been initialized yet!\n", + dev->def->index, emacdata->mdio_idx); + err = -ENODEV; + goto out2; + } } - /* Check if we need to attach to a TAH */ - if (emacdata->tah_idx >= 0) { - ep->tah_dev = - ocp_find_device(OCP_ANY_ID, OCP_FUNC_TAH, - emacdata->tah_idx); - if (ep->tah_dev == NULL) - printk(KERN_WARNING - "emac%d: TAH %d requested but not found !\n", - ocpdev->def->index, emacdata->tah_idx); - else if ((rc = emac_init_tah(ep)) != 0) - goto bail; + /* Attach to ZMII, if needed */ + if ((err = zmii_attach(dev)) != 0) + goto out2; + + /* Attach to RGMII, if needed */ + if ((err = rgmii_attach(dev)) != 0) + goto out3; + + /* Attach to TAH, if needed */ + if ((err = tah_attach(dev)) != 0) + goto out4; + + /* Map EMAC regs */ + dev->emacp = + (struct emac_regs *)ioremap(dev->def->paddr, + sizeof(struct emac_regs)); + if (!dev->emacp) { + printk(KERN_ERR "emac%d: could not ioremap device registers!\n", + dev->def->index); + err = -ENOMEM; + goto out5; } - if (deferred_init) { - if (!list_empty(&emac_init_list)) { - struct list_head *entry; - struct emac_def_dev *ddev; + /* Fill in MAC address */ + for (i = 0; i < 6; ++i) + ndev->dev_addr[i] = emacdata->mac_addr[i]; - list_for_each(entry, &emac_init_list) { - ddev = - list_entry(entry, struct emac_def_dev, - link); - emac_init_device(ddev->ocpdev, ddev->mal); - } + /* Set some link defaults before we can find out real parameters */ + dev->phy.speed = SPEED_100; + dev->phy.duplex = DUPLEX_FULL; + dev->phy.autoneg = AUTONEG_DISABLE; + dev->phy.pause = dev->phy.asym_pause = 0; + init_timer(&dev->link_timer); + dev->link_timer.function = emac_link_timer; + dev->link_timer.data = (unsigned long)dev; + + /* Find PHY if any */ + dev->phy.dev = ndev; + dev->phy.mode = emacdata->phy_mode; + if (emacdata->phy_map != 0xffffffff) { + u32 phy_map = emacdata->phy_map | busy_phy_map; + u32 adv; + + DBG("%d: PHY maps %08x %08x" NL, dev->def->index, + emacdata->phy_map, busy_phy_map); + + EMAC_RX_CLK_TX(dev->def->index); + + dev->phy.mdio_read = emac_mdio_read; + dev->phy.mdio_write = emac_mdio_write; + + /* Configure EMAC with defaults so we can at least use MDIO + * This is needed mostly for 440GX + */ + if (emac_phy_gpcs(dev->phy.mode)) { + /* XXX + * Make GPCS PHY address equal to EMAC index. + * We probably should take into account busy_phy_map + * and/or phy_map here. + */ + dev->phy.address = dev->def->index; } - } + + emac_configure(dev); - /* Init link monitoring timer */ - init_timer(&ep->link_timer); - ep->link_timer.function = emac_link_timer; - ep->link_timer.data = (unsigned long)ep; - ep->timer_ticks = 0; - - /* Fill up the mii_phy structure */ - ep->phy_mii.dev = ndev; - ep->phy_mii.mdio_read = emac_phy_read; - ep->phy_mii.mdio_write = emac_phy_write; - ep->phy_mii.mode = emacdata->phy_mode; - - /* Find PHY */ - phy_map = emacdata->phy_map | busy_phy_map; - for (i = 0; i <= 0x1f; i++, phy_map >>= 1) { - if ((phy_map & 0x1) == 0) { - int val = emac_phy_read(ndev, i, MII_BMCR); - if (val != 0xffff && val != -1) - break; + for (i = 0; i < 0x20; phy_map >>= 1, ++i) + if (!(phy_map & 1)) { + int r; + busy_phy_map |= 1 << i; + + /* Quick check if there is a PHY at the address */ + r = emac_mdio_read(dev->ndev, i, MII_BMCR); + if (r == 0xffff || r < 0) + continue; + if (!mii_phy_probe(&dev->phy, i)) + break; + } + if (i == 0x20) { + printk(KERN_WARNING "emac%d: can't find PHY!\n", + dev->def->index); + goto out6; } - } - if (i == 0x20) { - printk(KERN_WARNING "emac%d: Can't find PHY.\n", - ocpdev->def->index); - rc = -ENODEV; - goto bail; - } - busy_phy_map |= 1 << i; - ep->mii_phy_addr = i; - rc = mii_phy_probe(&ep->phy_mii, i); - if (rc) { - printk(KERN_WARNING "emac%d: Failed to probe PHY type.\n", - ocpdev->def->index); - rc = -ENODEV; - goto bail; - } - - /* Disable any PHY features not supported by the platform */ - ep->phy_mii.def->features &= ~emacdata->phy_feat_exc; - /* Setup initial PHY config & startup aneg */ - if (ep->phy_mii.def->ops->init) - ep->phy_mii.def->ops->init(&ep->phy_mii); - netif_carrier_off(ndev); - if (ep->phy_mii.def->features & SUPPORTED_Autoneg) - ep->want_autoneg = 1; - else { - ep->want_autoneg = 0; + /* Init PHY */ + if (dev->phy.def->ops->init) + dev->phy.def->ops->init(&dev->phy); - /* Select highest supported speed/duplex */ - if (ep->phy_mii.def->features & SUPPORTED_1000baseT_Full) { - ep->phy_mii.speed = SPEED_1000; - ep->phy_mii.duplex = DUPLEX_FULL; - } else if (ep->phy_mii.def->features & - SUPPORTED_1000baseT_Half) { - ep->phy_mii.speed = SPEED_1000; - ep->phy_mii.duplex = DUPLEX_HALF; - } else if (ep->phy_mii.def->features & - SUPPORTED_100baseT_Full) { - ep->phy_mii.speed = SPEED_100; - ep->phy_mii.duplex = DUPLEX_FULL; - } else if (ep->phy_mii.def->features & - SUPPORTED_100baseT_Half) { - ep->phy_mii.speed = SPEED_100; - ep->phy_mii.duplex = DUPLEX_HALF; - } else if (ep->phy_mii.def->features & - SUPPORTED_10baseT_Full) { - ep->phy_mii.speed = SPEED_10; - ep->phy_mii.duplex = DUPLEX_FULL; + /* Disable any PHY features not supported by the platform */ + dev->phy.def->features &= ~emacdata->phy_feat_exc; + + /* Setup initial link parameters */ + if (dev->phy.features & SUPPORTED_Autoneg) { + adv = dev->phy.features; +#if !defined(CONFIG_40x) + adv |= ADVERTISED_Pause | ADVERTISED_Asym_Pause; +#endif + /* Restart autonegotiation */ + dev->phy.def->ops->setup_aneg(&dev->phy, adv); } else { - ep->phy_mii.speed = SPEED_10; - ep->phy_mii.duplex = DUPLEX_HALF; + u32 f = dev->phy.def->features; + int speed = SPEED_10, fd = DUPLEX_HALF; + + /* Select highest supported speed/duplex */ + if (f & SUPPORTED_1000baseT_Full) { + speed = SPEED_1000; + fd = DUPLEX_FULL; + } else if (f & SUPPORTED_1000baseT_Half) + speed = SPEED_1000; + else if (f & SUPPORTED_100baseT_Full) { + speed = SPEED_100; + fd = DUPLEX_FULL; + } else if (f & SUPPORTED_100baseT_Half) + speed = SPEED_100; + else if (f & SUPPORTED_10baseT_Full) + fd = DUPLEX_FULL; + + /* Force link parameters */ + dev->phy.def->ops->setup_forced(&dev->phy, speed, fd); } - } - emac_start_link(ep, NULL); + } else { + emac_reset(dev); - /* read the MAC Address */ - for (i = 0; i < 6; i++) - ndev->dev_addr[i] = emacdata->mac_addr[i]; + /* PHY-less configuration. + * XXX I probably should move these settings to emacdata + */ + dev->phy.address = -1; + dev->phy.features = SUPPORTED_100baseT_Full | SUPPORTED_MII; + dev->phy.pause = 1; + } /* Fill in the driver function table */ ndev->open = &emac_open; - ndev->hard_start_xmit = &emac_start_xmit; + if (dev->tah_dev) { + ndev->hard_start_xmit = &emac_start_xmit_sg; + ndev->features |= NETIF_F_IP_CSUM | NETIF_F_SG; + } else + ndev->hard_start_xmit = &emac_start_xmit; + ndev->tx_timeout = &emac_full_tx_reset; + ndev->watchdog_timeo = 5 * HZ; ndev->stop = &emac_close; ndev->get_stats = &emac_stats; - if (emacdata->jumbo) - ndev->change_mtu = &emac_change_mtu; - ndev->set_mac_address = &emac_set_mac_address; ndev->set_multicast_list = &emac_set_multicast_list; ndev->do_ioctl = &emac_ioctl; + if (emac_phy_supports_gige(emacdata->phy_mode)) { + ndev->change_mtu = &emac_change_mtu; + dev->commac.ops = &emac_commac_sg_ops; + } SET_ETHTOOL_OPS(ndev, &emac_ethtool_ops); - if (emacdata->tah_idx >= 0) - ndev->features = NETIF_F_IP_CSUM | NETIF_F_SG; -#ifdef CONFIG_NET_POLL_CONTROLLER - ndev->poll_controller = emac_netpoll; -#endif - SET_MODULE_OWNER(ndev); + netif_carrier_off(ndev); + netif_stop_queue(ndev); + + err = register_netdev(ndev); + if (err) { + printk(KERN_ERR "emac%d: failed to register net device (%d)!\n", + dev->def->index, err); + goto out6; + } - rc = register_netdev(ndev); - if (rc != 0) - goto bail; + ocp_set_drvdata(ocpdev, dev); - printk("%s: IBM emac, MAC %02x:%02x:%02x:%02x:%02x:%02x\n", - ndev->name, + printk("%s: emac%d, MAC %02x:%02x:%02x:%02x:%02x:%02x\n", + ndev->name, dev->def->index, ndev->dev_addr[0], ndev->dev_addr[1], ndev->dev_addr[2], ndev->dev_addr[3], ndev->dev_addr[4], ndev->dev_addr[5]); - printk(KERN_INFO "%s: Found %s PHY (0x%02x)\n", - ndev->name, ep->phy_mii.def->name, ep->mii_phy_addr); - bail: - if (rc && commac_reg) - mal_unregister_commac(ep->mal, &ep->commac); - if (rc && ndev) - kfree(ndev); + if (dev->phy.address >= 0) + printk("%s: found %s PHY (0x%02x)\n", ndev->name, + dev->phy.def->name, dev->phy.address); - return rc; -} - -static int emac_probe(struct ocp_device *ocpdev) -{ - struct ocp_device *maldev; - struct ibm_ocp_mal *mal; - struct ocp_func_emac_data *emacdata; - - emacdata = (struct ocp_func_emac_data *)ocpdev->def->additions; - if (emacdata == NULL) { - printk(KERN_ERR "emac%d: Missing additional datas !\n", - ocpdev->def->index); - return -ENODEV; - } - - /* Get the MAL device */ - maldev = ocp_find_device(OCP_ANY_ID, OCP_FUNC_MAL, emacdata->mal_idx); - if (maldev == NULL) { - printk("No maldev\n"); - return -ENODEV; - } - /* - * Get MAL driver data, it must be here due to link order. - * When the driver is modularized, symbol dependencies will - * ensure the MAL driver is already present if built as a - * module. - */ - mal = (struct ibm_ocp_mal *)ocp_get_drvdata(maldev); - if (mal == NULL) { - printk("No maldrv\n"); - return -ENODEV; - } - - /* If we depend on another EMAC for MDIO, wait for it to show up */ - if (emacdata->mdio_idx >= 0 && - (emacdata->mdio_idx != ocpdev->def->index) && !mdio_ndev) { - struct emac_def_dev *ddev; - /* Add this index to the deferred init table */ - ddev = kmalloc(sizeof(struct emac_def_dev), GFP_KERNEL); - ddev->ocpdev = ocpdev; - ddev->mal = mal; - list_add_tail(&ddev->link, &emac_init_list); - } else { - emac_init_device(ocpdev, mal); - } + emac_dbg_register(dev->def->index, dev); return 0; + out6: + iounmap((void *)dev->emacp); + out5: + tah_fini(dev->tah_dev); + out4: + rgmii_fini(dev->rgmii_dev, dev->rgmii_input); + out3: + zmii_fini(dev->zmii_dev, dev->zmii_input); + out2: + mal_unregister_commac(dev->mal, &dev->commac); + out: + kfree(ndev); + return err; } -/* Structure for a device driver */ static struct ocp_device_id emac_ids[] = { - {.vendor = OCP_ANY_ID,.function = OCP_FUNC_EMAC}, - {.vendor = OCP_VENDOR_INVALID} + { .vendor = OCP_VENDOR_IBM, .function = OCP_FUNC_EMAC }, + { .vendor = OCP_VENDOR_INVALID} }; static struct ocp_driver emac_driver = { .name = "emac", .id_table = emac_ids, - .probe = emac_probe, .remove = emac_remove, }; static int __init emac_init(void) { - printk(KERN_INFO DRV_NAME ": " DRV_DESC ", version " DRV_VERSION "\n"); - printk(KERN_INFO "Maintained by " DRV_AUTHOR "\n"); + printk(KERN_INFO DRV_DESC ", version " DRV_VERSION "\n"); + + DBG(": init" NL); - if (skb_res > 2) { - printk(KERN_WARNING "Invalid skb_res: %d, cropping to 2\n", - skb_res); - skb_res = 2; + if (mal_init()) + return -ENODEV; + + EMAC_CLK_INTERNAL; + if (ocp_register_driver(&emac_driver)) { + EMAC_CLK_EXTERNAL; + ocp_unregister_driver(&emac_driver); + mal_exit(); + return -ENODEV; } + EMAC_CLK_EXTERNAL; - return ocp_register_driver(&emac_driver); + emac_init_debug(); + return 0; } static void __exit emac_exit(void) { + DBG(": exit" NL); ocp_unregister_driver(&emac_driver); + mal_exit(); + emac_fini_debug(); } module_init(emac_init); diff --git a/drivers/net/ibm_emac/ibm_emac_core.h b/drivers/net/ibm_emac/ibm_emac_core.h index 97e6e1ea8c89..e9b44d030ac3 100644 --- a/drivers/net/ibm_emac/ibm_emac_core.h +++ b/drivers/net/ibm_emac/ibm_emac_core.h @@ -1,146 +1,221 @@ /* - * ibm_emac_core.h + * drivers/net/ibm_emac/ibm_emac_core.h * - * Ethernet driver for the built in ethernet on the IBM 405 PowerPC - * processor. + * Driver for PowerPC 4xx on-chip ethernet controller. * - * Armin Kuster akuster@mvista.com - * Sept, 2001 + * Copyright (c) 2004, 2005 Zultys Technologies. + * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net> * - * Orignial driver - * Johnnie Peters - * jpeters@mvista.com - * - * Copyright 2000 MontaVista Softare Inc. + * Based on original work by + * Armin Kuster <akuster@mvista.com> + * Johnnie Peters <jpeters@mvista.com> + * Copyright 2000, 2001 MontaVista Softare Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. + * */ +#ifndef __IBM_EMAC_CORE_H_ +#define __IBM_EMAC_CORE_H_ -#ifndef _IBM_EMAC_CORE_H_ -#define _IBM_EMAC_CORE_H_ - +#include <linux/config.h> #include <linux/netdevice.h> +#include <linux/dma-mapping.h> #include <asm/ocp.h> -#include <asm/mmu.h> /* For phys_addr_t */ #include "ibm_emac.h" #include "ibm_emac_phy.h" -#include "ibm_emac_rgmii.h" #include "ibm_emac_zmii.h" +#include "ibm_emac_rgmii.h" #include "ibm_emac_mal.h" #include "ibm_emac_tah.h" -#ifndef CONFIG_IBM_EMAC_TXB -#define NUM_TX_BUFF 64 -#define NUM_RX_BUFF 64 -#else -#define NUM_TX_BUFF CONFIG_IBM_EMAC_TXB -#define NUM_RX_BUFF CONFIG_IBM_EMAC_RXB -#endif +#define NUM_TX_BUFF CONFIG_IBM_EMAC_TXB +#define NUM_RX_BUFF CONFIG_IBM_EMAC_RXB -/* This does 16 byte alignment, exactly what we need. - * The packet length includes FCS, but we don't want to - * include that when passing upstream as it messes up - * bridging applications. - */ -#ifndef CONFIG_IBM_EMAC_SKBRES -#define SKB_RES 2 -#else -#define SKB_RES CONFIG_IBM_EMAC_SKBRES +/* Simple sanity check */ +#if NUM_TX_BUFF > 256 || NUM_RX_BUFF > 256 +#error Invalid number of buffer descriptors (greater than 256) #endif -/* Note about alignement. alloc_skb() returns a cache line - * aligned buffer. However, dev_alloc_skb() will add 16 more - * bytes and "reserve" them, so our buffer will actually end - * on a half cache line. What we do is to use directly - * alloc_skb, allocate 16 more bytes to match the total amount - * allocated by dev_alloc_skb(), but we don't reserve. +// XXX +#define EMAC_MIN_MTU 46 +#define EMAC_MAX_MTU 9000 + +/* Maximum L2 header length (VLAN tagged, no FCS) */ +#define EMAC_MTU_OVERHEAD (6 * 2 + 2 + 4) + +/* RX BD size for the given MTU */ +static inline int emac_rx_size(int mtu) +{ + if (mtu > ETH_DATA_LEN) + return MAL_MAX_RX_SIZE; + else + return mal_rx_size(ETH_DATA_LEN + EMAC_MTU_OVERHEAD); +} + +#define EMAC_DMA_ALIGN(x) ALIGN((x), dma_get_cache_alignment()) + +#define EMAC_RX_SKB_HEADROOM \ + EMAC_DMA_ALIGN(CONFIG_IBM_EMAC_RX_SKB_HEADROOM) + +/* Size of RX skb for the given MTU */ +static inline int emac_rx_skb_size(int mtu) +{ + int size = max(mtu + EMAC_MTU_OVERHEAD, emac_rx_size(mtu)); + return EMAC_DMA_ALIGN(size + 2) + EMAC_RX_SKB_HEADROOM; +} + +/* RX DMA sync size */ +static inline int emac_rx_sync_size(int mtu) +{ + return EMAC_DMA_ALIGN(emac_rx_size(mtu) + 2); +} + +/* Driver statistcs is split into two parts to make it more cache friendly: + * - normal statistics (packet count, etc) + * - error statistics + * + * When statistics is requested by ethtool, these parts are concatenated, + * normal one goes first. + * + * Please, keep these structures in sync with emac_stats_keys. */ -#define MAX_NUM_BUF_DESC 255 -#define DESC_BUF_SIZE 4080 /* max 4096-16 */ -#define DESC_BUF_SIZE_REG (DESC_BUF_SIZE / 16) - -/* Transmitter timeout. */ -#define TX_TIMEOUT (2*HZ) - -/* MDIO latency delay */ -#define MDIO_DELAY 250 - -/* Power managment shift registers */ -#define IBM_CPM_EMMII 0 /* Shift value for MII */ -#define IBM_CPM_EMRX 1 /* Shift value for recv */ -#define IBM_CPM_EMTX 2 /* Shift value for MAC */ -#define IBM_CPM_EMAC(x) (((x)>>IBM_CPM_EMMII) | ((x)>>IBM_CPM_EMRX) | ((x)>>IBM_CPM_EMTX)) - -#define ENET_HEADER_SIZE 14 -#define ENET_FCS_SIZE 4 -#define ENET_DEF_MTU_SIZE 1500 -#define ENET_DEF_BUF_SIZE (ENET_DEF_MTU_SIZE + ENET_HEADER_SIZE + ENET_FCS_SIZE) -#define EMAC_MIN_FRAME 64 -#define EMAC_MAX_FRAME 9018 -#define EMAC_MIN_MTU (EMAC_MIN_FRAME - ENET_HEADER_SIZE - ENET_FCS_SIZE) -#define EMAC_MAX_MTU (EMAC_MAX_FRAME - ENET_HEADER_SIZE - ENET_FCS_SIZE) - -#ifdef CONFIG_IBM_EMAC_ERRMSG -void emac_serr_dump_0(struct net_device *dev); -void emac_serr_dump_1(struct net_device *dev); -void emac_err_dump(struct net_device *dev, int em0isr); -void emac_phy_dump(struct net_device *); -void emac_desc_dump(struct net_device *); -void emac_mac_dump(struct net_device *); -void emac_mal_dump(struct net_device *); -#else -#define emac_serr_dump_0(dev) do { } while (0) -#define emac_serr_dump_1(dev) do { } while (0) -#define emac_err_dump(dev,x) do { } while (0) -#define emac_phy_dump(dev) do { } while (0) -#define emac_desc_dump(dev) do { } while (0) -#define emac_mac_dump(dev) do { } while (0) -#define emac_mal_dump(dev) do { } while (0) -#endif + +/* Normal TX/RX Statistics */ +struct ibm_emac_stats { + u64 rx_packets; + u64 rx_bytes; + u64 tx_packets; + u64 tx_bytes; + u64 rx_packets_csum; + u64 tx_packets_csum; +}; + +/* Error statistics */ +struct ibm_emac_error_stats { + u64 tx_undo; + + /* Software RX Errors */ + u64 rx_dropped_stack; + u64 rx_dropped_oom; + u64 rx_dropped_error; + u64 rx_dropped_resize; + u64 rx_dropped_mtu; + u64 rx_stopped; + /* BD reported RX errors */ + u64 rx_bd_errors; + u64 rx_bd_overrun; + u64 rx_bd_bad_packet; + u64 rx_bd_runt_packet; + u64 rx_bd_short_event; + u64 rx_bd_alignment_error; + u64 rx_bd_bad_fcs; + u64 rx_bd_packet_too_long; + u64 rx_bd_out_of_range; + u64 rx_bd_in_range; + /* EMAC IRQ reported RX errors */ + u64 rx_parity; + u64 rx_fifo_overrun; + u64 rx_overrun; + u64 rx_bad_packet; + u64 rx_runt_packet; + u64 rx_short_event; + u64 rx_alignment_error; + u64 rx_bad_fcs; + u64 rx_packet_too_long; + u64 rx_out_of_range; + u64 rx_in_range; + + /* Software TX Errors */ + u64 tx_dropped; + /* BD reported TX errors */ + u64 tx_bd_errors; + u64 tx_bd_bad_fcs; + u64 tx_bd_carrier_loss; + u64 tx_bd_excessive_deferral; + u64 tx_bd_excessive_collisions; + u64 tx_bd_late_collision; + u64 tx_bd_multple_collisions; + u64 tx_bd_single_collision; + u64 tx_bd_underrun; + u64 tx_bd_sqe; + /* EMAC IRQ reported TX errors */ + u64 tx_parity; + u64 tx_underrun; + u64 tx_sqe; + u64 tx_errors; +}; + +#define EMAC_ETHTOOL_STATS_COUNT ((sizeof(struct ibm_emac_stats) + \ + sizeof(struct ibm_emac_error_stats)) \ + / sizeof(u64)) struct ocp_enet_private { - struct sk_buff *tx_skb[NUM_TX_BUFF]; - struct sk_buff *rx_skb[NUM_RX_BUFF]; - struct mal_descriptor *tx_desc; - struct mal_descriptor *rx_desc; - struct mal_descriptor *rx_dirty; - struct net_device_stats stats; - int tx_cnt; - int rx_slot; - int dirty_rx; - int tx_slot; - int ack_slot; - int rx_buffer_size; - - struct mii_phy phy_mii; - int mii_phy_addr; - int want_autoneg; - int timer_ticks; - struct timer_list link_timer; - struct net_device *mdio_dev; - - struct ocp_device *rgmii_dev; - int rgmii_input; - - struct ocp_device *zmii_dev; - int zmii_input; - - struct ibm_ocp_mal *mal; - int mal_tx_chan, mal_rx_chan; - struct mal_commac commac; - - struct ocp_device *tah_dev; - - int opened; - int going_away; - int wol_irq; - emac_t *emacp; - struct ocp_device *ocpdev; - struct net_device *ndev; - spinlock_t lock; + struct net_device *ndev; /* 0 */ + struct emac_regs *emacp; + + struct mal_descriptor *tx_desc; + int tx_cnt; + int tx_slot; + int ack_slot; + + struct mal_descriptor *rx_desc; + int rx_slot; + struct sk_buff *rx_sg_skb; /* 1 */ + int rx_skb_size; + int rx_sync_size; + + struct ibm_emac_stats stats; + struct ocp_device *tah_dev; + + struct ibm_ocp_mal *mal; + struct mal_commac commac; + + struct sk_buff *tx_skb[NUM_TX_BUFF]; + struct sk_buff *rx_skb[NUM_RX_BUFF]; + + struct ocp_device *zmii_dev; + int zmii_input; + struct ocp_enet_private *mdio_dev; + struct ocp_device *rgmii_dev; + int rgmii_input; + + struct ocp_def *def; + + struct mii_phy phy; + struct timer_list link_timer; + int reset_failed; + + struct ibm_emac_error_stats estats; + struct net_device_stats nstats; + + struct device* ldev; }; -#endif /* _IBM_EMAC_CORE_H_ */ + +/* Ethtool get_regs complex data. + * We want to get not just EMAC registers, but also MAL, ZMII, RGMII, TAH + * when available. + * + * Returned BLOB consists of the ibm_emac_ethtool_regs_hdr, + * MAL registers, EMAC registers and optional ZMII, RGMII, TAH registers. + * Each register component is preceded with emac_ethtool_regs_subhdr. + * Order of the optional headers follows their relative bit posititions + * in emac_ethtool_regs_hdr.components + */ +#define EMAC_ETHTOOL_REGS_ZMII 0x00000001 +#define EMAC_ETHTOOL_REGS_RGMII 0x00000002 +#define EMAC_ETHTOOL_REGS_TAH 0x00000004 + +struct emac_ethtool_regs_hdr { + u32 components; +}; + +struct emac_ethtool_regs_subhdr { + u32 version; + u32 index; +}; + +#endif /* __IBM_EMAC_CORE_H_ */ diff --git a/drivers/net/ibm_emac/ibm_emac_debug.c b/drivers/net/ibm_emac/ibm_emac_debug.c index c8512046cf84..75d3b8639041 100644 --- a/drivers/net/ibm_emac/ibm_emac_debug.c +++ b/drivers/net/ibm_emac/ibm_emac_debug.c @@ -1,224 +1,213 @@ /* - * ibm_ocp_debug.c + * drivers/net/ibm_emac/ibm_emac_debug.c * - * This has all the debug routines that where in *_enet.c + * Driver for PowerPC 4xx on-chip ethernet controller, debug print routines. * - * Armin Kuster akuster@mvista.com - * April , 2002 - * - * Copyright 2002 MontaVista Softare Inc. + * Copyright (c) 2004, 2005 Zultys Technologies + * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net> * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. + * */ - #include <linux/config.h> +#include <linux/init.h> +#include <linux/module.h> #include <linux/kernel.h> #include <linux/netdevice.h> +#include <linux/sysrq.h> #include <asm/io.h> -#include "ibm_ocp_mal.h" -#include "ibm_ocp_zmii.h" -#include "ibm_ocp_enet.h" -extern int emac_phy_read(struct net_device *dev, int mii_id, int reg); +#include "ibm_emac_core.h" + +static void emac_desc_dump(int idx, struct ocp_enet_private *p) +{ + int i; + printk("** EMAC%d TX BDs **\n" + " tx_cnt = %d tx_slot = %d ack_slot = %d\n", + idx, p->tx_cnt, p->tx_slot, p->ack_slot); + for (i = 0; i < NUM_TX_BUFF / 2; ++i) + printk + ("bd[%2d] 0x%08x %c 0x%04x %4u - bd[%2d] 0x%08x %c 0x%04x %4u\n", + i, p->tx_desc[i].data_ptr, p->tx_skb[i] ? 'V' : ' ', + p->tx_desc[i].ctrl, p->tx_desc[i].data_len, + NUM_TX_BUFF / 2 + i, + p->tx_desc[NUM_TX_BUFF / 2 + i].data_ptr, + p->tx_skb[NUM_TX_BUFF / 2 + i] ? 'V' : ' ', + p->tx_desc[NUM_TX_BUFF / 2 + i].ctrl, + p->tx_desc[NUM_TX_BUFF / 2 + i].data_len); + + printk("** EMAC%d RX BDs **\n" + " rx_slot = %d rx_stopped = %d rx_skb_size = %d rx_sync_size = %d\n" + " rx_sg_skb = 0x%p\n", + idx, p->rx_slot, p->commac.rx_stopped, p->rx_skb_size, + p->rx_sync_size, p->rx_sg_skb); + for (i = 0; i < NUM_RX_BUFF / 2; ++i) + printk + ("bd[%2d] 0x%08x %c 0x%04x %4u - bd[%2d] 0x%08x %c 0x%04x %4u\n", + i, p->rx_desc[i].data_ptr, p->rx_skb[i] ? 'V' : ' ', + p->rx_desc[i].ctrl, p->rx_desc[i].data_len, + NUM_RX_BUFF / 2 + i, + p->rx_desc[NUM_RX_BUFF / 2 + i].data_ptr, + p->rx_skb[NUM_RX_BUFF / 2 + i] ? 'V' : ' ', + p->rx_desc[NUM_RX_BUFF / 2 + i].ctrl, + p->rx_desc[NUM_RX_BUFF / 2 + i].data_len); +} + +static void emac_mac_dump(int idx, struct ocp_enet_private *dev) +{ + struct emac_regs *p = dev->emacp; + + printk("** EMAC%d registers **\n" + "MR0 = 0x%08x MR1 = 0x%08x TMR0 = 0x%08x TMR1 = 0x%08x\n" + "RMR = 0x%08x ISR = 0x%08x ISER = 0x%08x\n" + "IAR = %04x%08x VTPID = 0x%04x VTCI = 0x%04x\n" + "IAHT: 0x%04x 0x%04x 0x%04x 0x%04x " + "GAHT: 0x%04x 0x%04x 0x%04x 0x%04x\n" + "LSA = %04x%08x IPGVR = 0x%04x\n" + "STACR = 0x%08x TRTR = 0x%08x RWMR = 0x%08x\n" + "OCTX = 0x%08x OCRX = 0x%08x IPCR = 0x%08x\n", + idx, in_be32(&p->mr0), in_be32(&p->mr1), + in_be32(&p->tmr0), in_be32(&p->tmr1), + in_be32(&p->rmr), in_be32(&p->isr), in_be32(&p->iser), + in_be32(&p->iahr), in_be32(&p->ialr), in_be32(&p->vtpid), + in_be32(&p->vtci), + in_be32(&p->iaht1), in_be32(&p->iaht2), in_be32(&p->iaht3), + in_be32(&p->iaht4), + in_be32(&p->gaht1), in_be32(&p->gaht2), in_be32(&p->gaht3), + in_be32(&p->gaht4), + in_be32(&p->lsah), in_be32(&p->lsal), in_be32(&p->ipgvr), + in_be32(&p->stacr), in_be32(&p->trtr), in_be32(&p->rwmr), + in_be32(&p->octx), in_be32(&p->ocrx), in_be32(&p->ipcr) + ); + + emac_desc_dump(idx, dev); +} + +static void emac_mal_dump(struct ibm_ocp_mal *mal) +{ + struct ocp_func_mal_data *maldata = mal->def->additions; + int i; + + printk("** MAL%d Registers **\n" + "CFG = 0x%08x ESR = 0x%08x IER = 0x%08x\n" + "TX|CASR = 0x%08x CARR = 0x%08x EOBISR = 0x%08x DEIR = 0x%08x\n" + "RX|CASR = 0x%08x CARR = 0x%08x EOBISR = 0x%08x DEIR = 0x%08x\n", + mal->def->index, + get_mal_dcrn(mal, MAL_CFG), get_mal_dcrn(mal, MAL_ESR), + get_mal_dcrn(mal, MAL_IER), + get_mal_dcrn(mal, MAL_TXCASR), get_mal_dcrn(mal, MAL_TXCARR), + get_mal_dcrn(mal, MAL_TXEOBISR), get_mal_dcrn(mal, MAL_TXDEIR), + get_mal_dcrn(mal, MAL_RXCASR), get_mal_dcrn(mal, MAL_RXCARR), + get_mal_dcrn(mal, MAL_RXEOBISR), get_mal_dcrn(mal, MAL_RXDEIR) + ); + + printk("TX|"); + for (i = 0; i < maldata->num_tx_chans; ++i) { + if (i && !(i % 4)) + printk("\n "); + printk("CTP%d = 0x%08x ", i, get_mal_dcrn(mal, MAL_TXCTPR(i))); + } + printk("\nRX|"); + for (i = 0; i < maldata->num_rx_chans; ++i) { + if (i && !(i % 4)) + printk("\n "); + printk("CTP%d = 0x%08x ", i, get_mal_dcrn(mal, MAL_RXCTPR(i))); + } + printk("\n "); + for (i = 0; i < maldata->num_rx_chans; ++i) { + u32 r = get_mal_dcrn(mal, MAL_RCBS(i)); + if (i && !(i % 3)) + printk("\n "); + printk("RCBS%d = 0x%08x (%d) ", i, r, r * 16); + } + printk("\n"); +} + +static struct ocp_enet_private *__emacs[4]; +static struct ibm_ocp_mal *__mals[1]; -void emac_phy_dump(struct net_device *dev) +void emac_dbg_register(int idx, struct ocp_enet_private *dev) { - struct ocp_enet_private *fep = dev->priv; - unsigned long i; - uint data; - - printk(KERN_DEBUG " Prepare for Phy dump....\n"); - for (i = 0; i < 0x1A; i++) { - data = emac_phy_read(dev, fep->mii_phy_addr, i); - printk(KERN_DEBUG "Phy reg 0x%lx ==> %4x\n", i, data); - if (i == 0x07) - i = 0x0f; + unsigned long flags; + + if (idx >= sizeof(__emacs) / sizeof(__emacs[0])) { + printk(KERN_WARNING + "invalid index %d when registering EMAC for debugging\n", + idx); + return; } + + local_irq_save(flags); + __emacs[idx] = dev; + local_irq_restore(flags); } -void emac_desc_dump(struct net_device *dev) +void mal_dbg_register(int idx, struct ibm_ocp_mal *mal) { - struct ocp_enet_private *fep = dev->priv; - int curr_slot; - - printk(KERN_DEBUG - "dumping the receive descriptors: current slot is %d\n", - fep->rx_slot); - for (curr_slot = 0; curr_slot < NUM_RX_BUFF; curr_slot++) { - printk(KERN_DEBUG - "Desc %02d: status 0x%04x, length %3d, addr 0x%x\n", - curr_slot, fep->rx_desc[curr_slot].ctrl, - fep->rx_desc[curr_slot].data_len, - (unsigned int)fep->rx_desc[curr_slot].data_ptr); + unsigned long flags; + + if (idx >= sizeof(__mals) / sizeof(__mals[0])) { + printk(KERN_WARNING + "invalid index %d when registering MAL for debugging\n", + idx); + return; } + + local_irq_save(flags); + __mals[idx] = mal; + local_irq_restore(flags); } -void emac_mac_dump(struct net_device *dev) +void emac_dbg_dump_all(void) { - struct ocp_enet_private *fep = dev->priv; - volatile emac_t *emacp = fep->emacp; - - printk(KERN_DEBUG "EMAC DEBUG ********** \n"); - printk(KERN_DEBUG "EMAC_M0 ==> 0x%x\n", in_be32(&emacp->em0mr0)); - printk(KERN_DEBUG "EMAC_M1 ==> 0x%x\n", in_be32(&emacp->em0mr1)); - printk(KERN_DEBUG "EMAC_TXM0==> 0x%x\n", in_be32(&emacp->em0tmr0)); - printk(KERN_DEBUG "EMAC_TXM1==> 0x%x\n", in_be32(&emacp->em0tmr1)); - printk(KERN_DEBUG "EMAC_RXM ==> 0x%x\n", in_be32(&emacp->em0rmr)); - printk(KERN_DEBUG "EMAC_ISR ==> 0x%x\n", in_be32(&emacp->em0isr)); - printk(KERN_DEBUG "EMAC_IER ==> 0x%x\n", in_be32(&emacp->em0iser)); - printk(KERN_DEBUG "EMAC_IAH ==> 0x%x\n", in_be32(&emacp->em0iahr)); - printk(KERN_DEBUG "EMAC_IAL ==> 0x%x\n", in_be32(&emacp->em0ialr)); - printk(KERN_DEBUG "EMAC_VLAN_TPID_REG ==> 0x%x\n", - in_be32(&emacp->em0vtpid)); + unsigned int i; + unsigned long flags; + + local_irq_save(flags); + + for (i = 0; i < sizeof(__mals) / sizeof(__mals[0]); ++i) + if (__mals[i]) + emac_mal_dump(__mals[i]); + + for (i = 0; i < sizeof(__emacs) / sizeof(__emacs[0]); ++i) + if (__emacs[i]) + emac_mac_dump(i, __emacs[i]); + + local_irq_restore(flags); } -void emac_mal_dump(struct net_device *dev) +#if defined(CONFIG_MAGIC_SYSRQ) +static void emac_sysrq_handler(int key, struct pt_regs *pt_regs, + struct tty_struct *tty) { - struct ibm_ocp_mal *mal = ((struct ocp_enet_private *)dev->priv)->mal; - - printk(KERN_DEBUG " MAL DEBUG ********** \n"); - printk(KERN_DEBUG " MCR ==> 0x%x\n", - (unsigned int)get_mal_dcrn(mal, DCRN_MALCR)); - printk(KERN_DEBUG " ESR ==> 0x%x\n", - (unsigned int)get_mal_dcrn(mal, DCRN_MALESR)); - printk(KERN_DEBUG " IER ==> 0x%x\n", - (unsigned int)get_mal_dcrn(mal, DCRN_MALIER)); -#ifdef CONFIG_40x - printk(KERN_DEBUG " DBR ==> 0x%x\n", - (unsigned int)get_mal_dcrn(mal, DCRN_MALDBR)); -#endif /* CONFIG_40x */ - printk(KERN_DEBUG " TXCASR ==> 0x%x\n", - (unsigned int)get_mal_dcrn(mal, DCRN_MALTXCASR)); - printk(KERN_DEBUG " TXCARR ==> 0x%x\n", - (unsigned int)get_mal_dcrn(mal, DCRN_MALTXCARR)); - printk(KERN_DEBUG " TXEOBISR ==> 0x%x\n", - (unsigned int)get_mal_dcrn(mal, DCRN_MALTXEOBISR)); - printk(KERN_DEBUG " TXDEIR ==> 0x%x\n", - (unsigned int)get_mal_dcrn(mal, DCRN_MALTXDEIR)); - printk(KERN_DEBUG " RXCASR ==> 0x%x\n", - (unsigned int)get_mal_dcrn(mal, DCRN_MALRXCASR)); - printk(KERN_DEBUG " RXCARR ==> 0x%x\n", - (unsigned int)get_mal_dcrn(mal, DCRN_MALRXCARR)); - printk(KERN_DEBUG " RXEOBISR ==> 0x%x\n", - (unsigned int)get_mal_dcrn(mal, DCRN_MALRXEOBISR)); - printk(KERN_DEBUG " RXDEIR ==> 0x%x\n", - (unsigned int)get_mal_dcrn(mal, DCRN_MALRXDEIR)); - printk(KERN_DEBUG " TXCTP0R ==> 0x%x\n", - (unsigned int)get_mal_dcrn(mal, DCRN_MALTXCTP0R)); - printk(KERN_DEBUG " TXCTP1R ==> 0x%x\n", - (unsigned int)get_mal_dcrn(mal, DCRN_MALTXCTP1R)); - printk(KERN_DEBUG " TXCTP2R ==> 0x%x\n", - (unsigned int)get_mal_dcrn(mal, DCRN_MALTXCTP2R)); - printk(KERN_DEBUG " TXCTP3R ==> 0x%x\n", - (unsigned int)get_mal_dcrn(mal, DCRN_MALTXCTP3R)); - printk(KERN_DEBUG " RXCTP0R ==> 0x%x\n", - (unsigned int)get_mal_dcrn(mal, DCRN_MALRXCTP0R)); - printk(KERN_DEBUG " RXCTP1R ==> 0x%x\n", - (unsigned int)get_mal_dcrn(mal, DCRN_MALRXCTP1R)); - printk(KERN_DEBUG " RCBS0 ==> 0x%x\n", - (unsigned int)get_mal_dcrn(mal, DCRN_MALRCBS0)); - printk(KERN_DEBUG " RCBS1 ==> 0x%x\n", - (unsigned int)get_mal_dcrn(mal, DCRN_MALRCBS1)); + emac_dbg_dump_all(); } -void emac_serr_dump_0(struct net_device *dev) +static struct sysrq_key_op emac_sysrq_op = { + .handler = emac_sysrq_handler, + .help_msg = "emaC", + .action_msg = "Show EMAC(s) status", +}; + +int __init emac_init_debug(void) { - struct ibm_ocp_mal *mal = ((struct ocp_enet_private *)dev->priv)->mal; - unsigned long int mal_error, plb_error, plb_addr; - - mal_error = get_mal_dcrn(mal, DCRN_MALESR); - printk(KERN_DEBUG "ppc405_eth_serr: %s channel %ld \n", - (mal_error & 0x40000000) ? "Receive" : - "Transmit", (mal_error & 0x3e000000) >> 25); - printk(KERN_DEBUG " ----- latched error -----\n"); - if (mal_error & MALESR_DE) - printk(KERN_DEBUG " DE: descriptor error\n"); - if (mal_error & MALESR_OEN) - printk(KERN_DEBUG " ONE: OPB non-fullword error\n"); - if (mal_error & MALESR_OTE) - printk(KERN_DEBUG " OTE: OPB timeout error\n"); - if (mal_error & MALESR_OSE) - printk(KERN_DEBUG " OSE: OPB slave error\n"); - - if (mal_error & MALESR_PEIN) { - plb_error = mfdcr(DCRN_PLB0_BESR); - printk(KERN_DEBUG - " PEIN: PLB error, PLB0_BESR is 0x%x\n", - (unsigned int)plb_error); - plb_addr = mfdcr(DCRN_PLB0_BEAR); - printk(KERN_DEBUG - " PEIN: PLB error, PLB0_BEAR is 0x%x\n", - (unsigned int)plb_addr); - } + return register_sysrq_key('c', &emac_sysrq_op); } -void emac_serr_dump_1(struct net_device *dev) +void __exit emac_fini_debug(void) { - struct ibm_ocp_mal *mal = ((struct ocp_enet_private *)dev->priv)->mal; - int mal_error = get_mal_dcrn(mal, DCRN_MALESR); - - printk(KERN_DEBUG " ----- cumulative errors -----\n"); - if (mal_error & MALESR_DEI) - printk(KERN_DEBUG " DEI: descriptor error interrupt\n"); - if (mal_error & MALESR_ONEI) - printk(KERN_DEBUG " OPB non-fullword error interrupt\n"); - if (mal_error & MALESR_OTEI) - printk(KERN_DEBUG " OTEI: timeout error interrupt\n"); - if (mal_error & MALESR_OSEI) - printk(KERN_DEBUG " OSEI: slave error interrupt\n"); - if (mal_error & MALESR_PBEI) - printk(KERN_DEBUG " PBEI: PLB bus error interrupt\n"); + unregister_sysrq_key('c', &emac_sysrq_op); } -void emac_err_dump(struct net_device *dev, int em0isr) +#else +int __init emac_init_debug(void) +{ + return 0; +} +void __exit emac_fini_debug(void) { - printk(KERN_DEBUG "%s: on-chip ethernet error:\n", dev->name); - - if (em0isr & EMAC_ISR_OVR) - printk(KERN_DEBUG " OVR: overrun\n"); - if (em0isr & EMAC_ISR_PP) - printk(KERN_DEBUG " PP: control pause packet\n"); - if (em0isr & EMAC_ISR_BP) - printk(KERN_DEBUG " BP: packet error\n"); - if (em0isr & EMAC_ISR_RP) - printk(KERN_DEBUG " RP: runt packet\n"); - if (em0isr & EMAC_ISR_SE) - printk(KERN_DEBUG " SE: short event\n"); - if (em0isr & EMAC_ISR_ALE) - printk(KERN_DEBUG " ALE: odd number of nibbles in packet\n"); - if (em0isr & EMAC_ISR_BFCS) - printk(KERN_DEBUG " BFCS: bad FCS\n"); - if (em0isr & EMAC_ISR_PTLE) - printk(KERN_DEBUG " PTLE: oversized packet\n"); - if (em0isr & EMAC_ISR_ORE) - printk(KERN_DEBUG - " ORE: packet length field > max allowed LLC\n"); - if (em0isr & EMAC_ISR_IRE) - printk(KERN_DEBUG " IRE: In Range error\n"); - if (em0isr & EMAC_ISR_DBDM) - printk(KERN_DEBUG " DBDM: xmit error or SQE\n"); - if (em0isr & EMAC_ISR_DB0) - printk(KERN_DEBUG " DB0: xmit error or SQE on TX channel 0\n"); - if (em0isr & EMAC_ISR_SE0) - printk(KERN_DEBUG - " SE0: Signal Quality Error test failure from TX channel 0\n"); - if (em0isr & EMAC_ISR_TE0) - printk(KERN_DEBUG " TE0: xmit channel 0 aborted\n"); - if (em0isr & EMAC_ISR_DB1) - printk(KERN_DEBUG " DB1: xmit error or SQE on TX channel \n"); - if (em0isr & EMAC_ISR_SE1) - printk(KERN_DEBUG - " SE1: Signal Quality Error test failure from TX channel 1\n"); - if (em0isr & EMAC_ISR_TE1) - printk(KERN_DEBUG " TE1: xmit channel 1 aborted\n"); - if (em0isr & EMAC_ISR_MOS) - printk(KERN_DEBUG " MOS\n"); - if (em0isr & EMAC_ISR_MOF) - printk(KERN_DEBUG " MOF\n"); - - emac_mac_dump(dev); - emac_mal_dump(dev); } +#endif /* CONFIG_MAGIC_SYSRQ */ diff --git a/drivers/net/ibm_emac/ibm_emac_debug.h b/drivers/net/ibm_emac/ibm_emac_debug.h new file mode 100644 index 000000000000..e85fbe0a8da9 --- /dev/null +++ b/drivers/net/ibm_emac/ibm_emac_debug.h @@ -0,0 +1,63 @@ +/* + * drivers/net/ibm_emac/ibm_ocp_debug.h + * + * Driver for PowerPC 4xx on-chip ethernet controller, debug print routines. + * + * Copyright (c) 2004, 2005 Zultys Technologies + * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net> + * + * 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. + * + */ +#ifndef __IBM_EMAC_DEBUG_H_ +#define __IBM_EMAC_DEBUG_H_ + +#include <linux/config.h> +#include <linux/init.h> +#include "ibm_emac_core.h" +#include "ibm_emac_mal.h" + +#if defined(CONFIG_IBM_EMAC_DEBUG) +void emac_dbg_register(int idx, struct ocp_enet_private *dev); +void mal_dbg_register(int idx, struct ibm_ocp_mal *mal); +int emac_init_debug(void) __init; +void emac_fini_debug(void) __exit; +void emac_dbg_dump_all(void); +# define DBG_LEVEL 1 +#else +# define emac_dbg_register(x,y) ((void)0) +# define mal_dbg_register(x,y) ((void)0) +# define emac_init_debug() ((void)0) +# define emac_fini_debug() ((void)0) +# define emac_dbg_dump_all() ((void)0) +# define DBG_LEVEL 0 +#endif + +#if DBG_LEVEL > 0 +# define DBG(f,x...) printk("emac" f, ##x) +# define MAL_DBG(f,x...) printk("mal" f, ##x) +# define ZMII_DBG(f,x...) printk("zmii" f, ##x) +# define RGMII_DBG(f,x...) printk("rgmii" f, ##x) +# define NL "\n" +#else +# define DBG(f,x...) ((void)0) +# define MAL_DBG(f,x...) ((void)0) +# define ZMII_DBG(f,x...) ((void)0) +# define RGMII_DBG(f,x...) ((void)0) +#endif +#if DBG_LEVEL > 1 +# define DBG2(f,x...) DBG(f, ##x) +# define MAL_DBG2(f,x...) MAL_DBG(f, ##x) +# define ZMII_DBG2(f,x...) ZMII_DBG(f, ##x) +# define RGMII_DBG2(f,x...) RGMII_DBG(f, ##x) +#else +# define DBG2(f,x...) ((void)0) +# define MAL_DBG2(f,x...) ((void)0) +# define ZMII_DBG2(f,x...) ((void)0) +# define RGMII_DBG2(f,x...) ((void)0) +#endif + +#endif /* __IBM_EMAC_DEBUG_H_ */ diff --git a/drivers/net/ibm_emac/ibm_emac_mal.c b/drivers/net/ibm_emac/ibm_emac_mal.c index e59f57f363ca..da88d43081cc 100644 --- a/drivers/net/ibm_emac/ibm_emac_mal.c +++ b/drivers/net/ibm_emac/ibm_emac_mal.c @@ -1,436 +1,565 @@ /* - * ibm_ocp_mal.c + * drivers/net/ibm_emac/ibm_emac_mal.c * - * Armin Kuster akuster@mvista.com - * Juen, 2002 + * Memory Access Layer (MAL) support + * + * Copyright (c) 2004, 2005 Zultys Technologies. + * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net> * - * Copyright 2002 MontaVista Softare Inc. + * Based on original work by + * Benjamin Herrenschmidt <benh@kernel.crashing.org>, + * David Gibson <hermes@gibson.dropbear.id.au>, + * + * Armin Kuster <akuster@mvista.com> + * Copyright 2002 MontaVista Softare Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. + * */ - #include <linux/config.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/errno.h> #include <linux/netdevice.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/dma-mapping.h> -#include <asm/io.h> -#include <asm/irq.h> #include <asm/ocp.h> +#include "ibm_emac_core.h" #include "ibm_emac_mal.h" +#include "ibm_emac_debug.h" -// Locking: Should we share a lock with the client ? The client could provide -// a lock pointer (optionally) in the commac structure... I don't think this is -// really necessary though - -/* This lock protects the commac list. On today UP implementations, it's - * really only used as IRQ protection in mal_{register,unregister}_commac() - */ -static DEFINE_RWLOCK(mal_list_lock); - -int mal_register_commac(struct ibm_ocp_mal *mal, struct mal_commac *commac) +int __init mal_register_commac(struct ibm_ocp_mal *mal, + struct mal_commac *commac) { unsigned long flags; + local_irq_save(flags); - write_lock_irqsave(&mal_list_lock, flags); + MAL_DBG("%d: reg(%08x, %08x)" NL, mal->def->index, + commac->tx_chan_mask, commac->rx_chan_mask); - /* Don't let multiple commacs claim the same channel */ + /* Don't let multiple commacs claim the same channel(s) */ if ((mal->tx_chan_mask & commac->tx_chan_mask) || (mal->rx_chan_mask & commac->rx_chan_mask)) { - write_unlock_irqrestore(&mal_list_lock, flags); + local_irq_restore(flags); + printk(KERN_WARNING "mal%d: COMMAC channels conflict!\n", + mal->def->index); return -EBUSY; } mal->tx_chan_mask |= commac->tx_chan_mask; mal->rx_chan_mask |= commac->rx_chan_mask; + list_add(&commac->list, &mal->list); - list_add(&commac->list, &mal->commac); - - write_unlock_irqrestore(&mal_list_lock, flags); - + local_irq_restore(flags); return 0; } -int mal_unregister_commac(struct ibm_ocp_mal *mal, struct mal_commac *commac) +void __exit mal_unregister_commac(struct ibm_ocp_mal *mal, + struct mal_commac *commac) { unsigned long flags; + local_irq_save(flags); - write_lock_irqsave(&mal_list_lock, flags); + MAL_DBG("%d: unreg(%08x, %08x)" NL, mal->def->index, + commac->tx_chan_mask, commac->rx_chan_mask); mal->tx_chan_mask &= ~commac->tx_chan_mask; mal->rx_chan_mask &= ~commac->rx_chan_mask; - list_del_init(&commac->list); - write_unlock_irqrestore(&mal_list_lock, flags); - - return 0; + local_irq_restore(flags); } int mal_set_rcbs(struct ibm_ocp_mal *mal, int channel, unsigned long size) { - switch (channel) { - case 0: - set_mal_dcrn(mal, DCRN_MALRCBS0, size); - break; -#ifdef DCRN_MALRCBS1 - case 1: - set_mal_dcrn(mal, DCRN_MALRCBS1, size); - break; -#endif -#ifdef DCRN_MALRCBS2 - case 2: - set_mal_dcrn(mal, DCRN_MALRCBS2, size); - break; -#endif -#ifdef DCRN_MALRCBS3 - case 3: - set_mal_dcrn(mal, DCRN_MALRCBS3, size); - break; -#endif - default: + struct ocp_func_mal_data *maldata = mal->def->additions; + BUG_ON(channel < 0 || channel >= maldata->num_rx_chans || + size > MAL_MAX_RX_SIZE); + + MAL_DBG("%d: set_rbcs(%d, %lu)" NL, mal->def->index, channel, size); + + if (size & 0xf) { + printk(KERN_WARNING + "mal%d: incorrect RX size %lu for the channel %d\n", + mal->def->index, size, channel); return -EINVAL; } + set_mal_dcrn(mal, MAL_RCBS(channel), size >> 4); return 0; } -static irqreturn_t mal_serr(int irq, void *dev_instance, struct pt_regs *regs) +int mal_tx_bd_offset(struct ibm_ocp_mal *mal, int channel) { - struct ibm_ocp_mal *mal = dev_instance; - unsigned long mal_error; + struct ocp_func_mal_data *maldata = mal->def->additions; + BUG_ON(channel < 0 || channel >= maldata->num_tx_chans); + return channel * NUM_TX_BUFF; +} - /* - * This SERR applies to one of the devices on the MAL, here we charge - * it against the first EMAC registered for the MAL. - */ +int mal_rx_bd_offset(struct ibm_ocp_mal *mal, int channel) +{ + struct ocp_func_mal_data *maldata = mal->def->additions; + BUG_ON(channel < 0 || channel >= maldata->num_rx_chans); + return maldata->num_tx_chans * NUM_TX_BUFF + channel * NUM_RX_BUFF; +} - mal_error = get_mal_dcrn(mal, DCRN_MALESR); +void mal_enable_tx_channel(struct ibm_ocp_mal *mal, int channel) +{ + local_bh_disable(); + MAL_DBG("%d: enable_tx(%d)" NL, mal->def->index, channel); + set_mal_dcrn(mal, MAL_TXCASR, + get_mal_dcrn(mal, MAL_TXCASR) | MAL_CHAN_MASK(channel)); + local_bh_enable(); +} - printk(KERN_ERR "%s: System Error (MALESR=%lx)\n", - "MAL" /* FIXME: get the name right */ , mal_error); +void mal_disable_tx_channel(struct ibm_ocp_mal *mal, int channel) +{ + set_mal_dcrn(mal, MAL_TXCARR, MAL_CHAN_MASK(channel)); + MAL_DBG("%d: disable_tx(%d)" NL, mal->def->index, channel); +} - /* FIXME: decipher error */ - /* DIXME: distribute to commacs, if possible */ +void mal_enable_rx_channel(struct ibm_ocp_mal *mal, int channel) +{ + local_bh_disable(); + MAL_DBG("%d: enable_rx(%d)" NL, mal->def->index, channel); + set_mal_dcrn(mal, MAL_RXCASR, + get_mal_dcrn(mal, MAL_RXCASR) | MAL_CHAN_MASK(channel)); + local_bh_enable(); +} - /* Clear the error status register */ - set_mal_dcrn(mal, DCRN_MALESR, mal_error); +void mal_disable_rx_channel(struct ibm_ocp_mal *mal, int channel) +{ + set_mal_dcrn(mal, MAL_RXCARR, MAL_CHAN_MASK(channel)); + MAL_DBG("%d: disable_rx(%d)" NL, mal->def->index, channel); +} - return IRQ_HANDLED; +void mal_poll_add(struct ibm_ocp_mal *mal, struct mal_commac *commac) +{ + local_bh_disable(); + MAL_DBG("%d: poll_add(%p)" NL, mal->def->index, commac); + list_add_tail(&commac->poll_list, &mal->poll_list); + local_bh_enable(); } -static irqreturn_t mal_txeob(int irq, void *dev_instance, struct pt_regs *regs) +void mal_poll_del(struct ibm_ocp_mal *mal, struct mal_commac *commac) +{ + local_bh_disable(); + MAL_DBG("%d: poll_del(%p)" NL, mal->def->index, commac); + list_del(&commac->poll_list); + local_bh_enable(); +} + +/* synchronized by mal_poll() */ +static inline void mal_enable_eob_irq(struct ibm_ocp_mal *mal) +{ + MAL_DBG2("%d: enable_irq" NL, mal->def->index); + set_mal_dcrn(mal, MAL_CFG, get_mal_dcrn(mal, MAL_CFG) | MAL_CFG_EOPIE); +} + +/* synchronized by __LINK_STATE_RX_SCHED bit in ndev->state */ +static inline void mal_disable_eob_irq(struct ibm_ocp_mal *mal) +{ + set_mal_dcrn(mal, MAL_CFG, get_mal_dcrn(mal, MAL_CFG) & ~MAL_CFG_EOPIE); + MAL_DBG2("%d: disable_irq" NL, mal->def->index); +} + +static irqreturn_t mal_serr(int irq, void *dev_instance, struct pt_regs *regs) { struct ibm_ocp_mal *mal = dev_instance; - struct list_head *l; - unsigned long isr; + u32 esr = get_mal_dcrn(mal, MAL_ESR); - isr = get_mal_dcrn(mal, DCRN_MALTXEOBISR); - set_mal_dcrn(mal, DCRN_MALTXEOBISR, isr); + /* Clear the error status register */ + set_mal_dcrn(mal, MAL_ESR, esr); - read_lock(&mal_list_lock); - list_for_each(l, &mal->commac) { - struct mal_commac *mc = list_entry(l, struct mal_commac, list); + MAL_DBG("%d: SERR %08x" NL, mal->def->index, esr); - if (isr & mc->tx_chan_mask) { - mc->ops->txeob(mc->dev, isr & mc->tx_chan_mask); + if (esr & MAL_ESR_EVB) { + if (esr & MAL_ESR_DE) { + /* We ignore Descriptor error, + * TXDE or RXDE interrupt will be generated anyway. + */ + return IRQ_HANDLED; } + + if (esr & MAL_ESR_PEIN) { + /* PLB error, it's probably buggy hardware or + * incorrect physical address in BD (i.e. bug) + */ + if (net_ratelimit()) + printk(KERN_ERR + "mal%d: system error, PLB (ESR = 0x%08x)\n", + mal->def->index, esr); + return IRQ_HANDLED; + } + + /* OPB error, it's probably buggy hardware or incorrect EBC setup */ + if (net_ratelimit()) + printk(KERN_ERR + "mal%d: system error, OPB (ESR = 0x%08x)\n", + mal->def->index, esr); } - read_unlock(&mal_list_lock); + return IRQ_HANDLED; +} + +static inline void mal_schedule_poll(struct ibm_ocp_mal *mal) +{ + if (likely(netif_rx_schedule_prep(&mal->poll_dev))) { + MAL_DBG2("%d: schedule_poll" NL, mal->def->index); + mal_disable_eob_irq(mal); + __netif_rx_schedule(&mal->poll_dev); + } else + MAL_DBG2("%d: already in poll" NL, mal->def->index); +} +static irqreturn_t mal_txeob(int irq, void *dev_instance, struct pt_regs *regs) +{ + struct ibm_ocp_mal *mal = dev_instance; + u32 r = get_mal_dcrn(mal, MAL_TXEOBISR); + MAL_DBG2("%d: txeob %08x" NL, mal->def->index, r); + mal_schedule_poll(mal); + set_mal_dcrn(mal, MAL_TXEOBISR, r); return IRQ_HANDLED; } static irqreturn_t mal_rxeob(int irq, void *dev_instance, struct pt_regs *regs) { struct ibm_ocp_mal *mal = dev_instance; - struct list_head *l; - unsigned long isr; + u32 r = get_mal_dcrn(mal, MAL_RXEOBISR); + MAL_DBG2("%d: rxeob %08x" NL, mal->def->index, r); + mal_schedule_poll(mal); + set_mal_dcrn(mal, MAL_RXEOBISR, r); + return IRQ_HANDLED; +} - isr = get_mal_dcrn(mal, DCRN_MALRXEOBISR); - set_mal_dcrn(mal, DCRN_MALRXEOBISR, isr); +static irqreturn_t mal_txde(int irq, void *dev_instance, struct pt_regs *regs) +{ + struct ibm_ocp_mal *mal = dev_instance; + u32 deir = get_mal_dcrn(mal, MAL_TXDEIR); + set_mal_dcrn(mal, MAL_TXDEIR, deir); - read_lock(&mal_list_lock); - list_for_each(l, &mal->commac) { - struct mal_commac *mc = list_entry(l, struct mal_commac, list); + MAL_DBG("%d: txde %08x" NL, mal->def->index, deir); - if (isr & mc->rx_chan_mask) { - mc->ops->rxeob(mc->dev, isr & mc->rx_chan_mask); - } - } - read_unlock(&mal_list_lock); + if (net_ratelimit()) + printk(KERN_ERR + "mal%d: TX descriptor error (TXDEIR = 0x%08x)\n", + mal->def->index, deir); return IRQ_HANDLED; } -static irqreturn_t mal_txde(int irq, void *dev_instance, struct pt_regs *regs) +static irqreturn_t mal_rxde(int irq, void *dev_instance, struct pt_regs *regs) { struct ibm_ocp_mal *mal = dev_instance; struct list_head *l; - unsigned long deir; + u32 deir = get_mal_dcrn(mal, MAL_RXDEIR); - deir = get_mal_dcrn(mal, DCRN_MALTXDEIR); + MAL_DBG("%d: rxde %08x" NL, mal->def->index, deir); - /* FIXME: print which MAL correctly */ - printk(KERN_WARNING "%s: Tx descriptor error (MALTXDEIR=%lx)\n", - "MAL", deir); - - read_lock(&mal_list_lock); - list_for_each(l, &mal->commac) { + list_for_each(l, &mal->list) { struct mal_commac *mc = list_entry(l, struct mal_commac, list); - - if (deir & mc->tx_chan_mask) { - mc->ops->txde(mc->dev, deir & mc->tx_chan_mask); + if (deir & mc->rx_chan_mask) { + mc->rx_stopped = 1; + mc->ops->rxde(mc->dev); } } - read_unlock(&mal_list_lock); + + mal_schedule_poll(mal); + set_mal_dcrn(mal, MAL_RXDEIR, deir); return IRQ_HANDLED; } -/* - * This interrupt should be very rare at best. This occurs when - * the hardware has a problem with the receive descriptors. The manual - * states that it occurs when the hardware cannot the receive descriptor - * empty bit is not set. The recovery mechanism will be to - * traverse through the descriptors, handle any that are marked to be - * handled and reinitialize each along the way. At that point the driver - * will be restarted. - */ -static irqreturn_t mal_rxde(int irq, void *dev_instance, struct pt_regs *regs) +static int mal_poll(struct net_device *ndev, int *budget) { - struct ibm_ocp_mal *mal = dev_instance; + struct ibm_ocp_mal *mal = ndev->priv; struct list_head *l; - unsigned long deir; - - deir = get_mal_dcrn(mal, DCRN_MALRXDEIR); + int rx_work_limit = min(ndev->quota, *budget), received = 0, done; + + MAL_DBG2("%d: poll(%d) %d ->" NL, mal->def->index, *budget, + rx_work_limit); + again: + /* Process TX skbs */ + list_for_each(l, &mal->poll_list) { + struct mal_commac *mc = + list_entry(l, struct mal_commac, poll_list); + mc->ops->poll_tx(mc->dev); + } - /* - * This really is needed. This case encountered in stress testing. + /* Process RX skbs. + * We _might_ need something more smart here to enforce polling fairness. */ - if (deir == 0) - return IRQ_HANDLED; - - /* FIXME: print which MAL correctly */ - printk(KERN_WARNING "%s: Rx descriptor error (MALRXDEIR=%lx)\n", - "MAL", deir); - - read_lock(&mal_list_lock); - list_for_each(l, &mal->commac) { - struct mal_commac *mc = list_entry(l, struct mal_commac, list); + list_for_each(l, &mal->poll_list) { + struct mal_commac *mc = + list_entry(l, struct mal_commac, poll_list); + int n = mc->ops->poll_rx(mc->dev, rx_work_limit); + if (n) { + received += n; + rx_work_limit -= n; + if (rx_work_limit <= 0) { + done = 0; + goto more_work; // XXX What if this is the last one ? + } + } + } - if (deir & mc->rx_chan_mask) { - mc->ops->rxde(mc->dev, deir & mc->rx_chan_mask); + /* We need to disable IRQs to protect from RXDE IRQ here */ + local_irq_disable(); + __netif_rx_complete(ndev); + mal_enable_eob_irq(mal); + local_irq_enable(); + + done = 1; + + /* Check for "rotting" packet(s) */ + list_for_each(l, &mal->poll_list) { + struct mal_commac *mc = + list_entry(l, struct mal_commac, poll_list); + if (unlikely(mc->ops->peek_rx(mc->dev) || mc->rx_stopped)) { + MAL_DBG2("%d: rotting packet" NL, mal->def->index); + if (netif_rx_reschedule(ndev, received)) + mal_disable_eob_irq(mal); + else + MAL_DBG2("%d: already in poll list" NL, + mal->def->index); + + if (rx_work_limit > 0) + goto again; + else + goto more_work; } + mc->ops->poll_tx(mc->dev); } - read_unlock(&mal_list_lock); - return IRQ_HANDLED; + more_work: + ndev->quota -= received; + *budget -= received; + + MAL_DBG2("%d: poll() %d <- %d" NL, mal->def->index, *budget, + done ? 0 : 1); + return done ? 0 : 1; +} + +static void mal_reset(struct ibm_ocp_mal *mal) +{ + int n = 10; + MAL_DBG("%d: reset" NL, mal->def->index); + + set_mal_dcrn(mal, MAL_CFG, MAL_CFG_SR); + + /* Wait for reset to complete (1 system clock) */ + while ((get_mal_dcrn(mal, MAL_CFG) & MAL_CFG_SR) && n) + --n; + + if (unlikely(!n)) + printk(KERN_ERR "mal%d: reset timeout\n", mal->def->index); +} + +int mal_get_regs_len(struct ibm_ocp_mal *mal) +{ + return sizeof(struct emac_ethtool_regs_subhdr) + + sizeof(struct ibm_mal_regs); +} + +void *mal_dump_regs(struct ibm_ocp_mal *mal, void *buf) +{ + struct emac_ethtool_regs_subhdr *hdr = buf; + struct ibm_mal_regs *regs = (struct ibm_mal_regs *)(hdr + 1); + struct ocp_func_mal_data *maldata = mal->def->additions; + int i; + + hdr->version = MAL_VERSION; + hdr->index = mal->def->index; + + regs->tx_count = maldata->num_tx_chans; + regs->rx_count = maldata->num_rx_chans; + + regs->cfg = get_mal_dcrn(mal, MAL_CFG); + regs->esr = get_mal_dcrn(mal, MAL_ESR); + regs->ier = get_mal_dcrn(mal, MAL_IER); + regs->tx_casr = get_mal_dcrn(mal, MAL_TXCASR); + regs->tx_carr = get_mal_dcrn(mal, MAL_TXCARR); + regs->tx_eobisr = get_mal_dcrn(mal, MAL_TXEOBISR); + regs->tx_deir = get_mal_dcrn(mal, MAL_TXDEIR); + regs->rx_casr = get_mal_dcrn(mal, MAL_RXCASR); + regs->rx_carr = get_mal_dcrn(mal, MAL_RXCARR); + regs->rx_eobisr = get_mal_dcrn(mal, MAL_RXEOBISR); + regs->rx_deir = get_mal_dcrn(mal, MAL_RXDEIR); + + for (i = 0; i < regs->tx_count; ++i) + regs->tx_ctpr[i] = get_mal_dcrn(mal, MAL_TXCTPR(i)); + + for (i = 0; i < regs->rx_count; ++i) { + regs->rx_ctpr[i] = get_mal_dcrn(mal, MAL_RXCTPR(i)); + regs->rcbs[i] = get_mal_dcrn(mal, MAL_RCBS(i)); + } + return regs + 1; } static int __init mal_probe(struct ocp_device *ocpdev) { - struct ibm_ocp_mal *mal = NULL; + struct ibm_ocp_mal *mal; struct ocp_func_mal_data *maldata; - int err = 0; + int err = 0, i, bd_size; + + MAL_DBG("%d: probe" NL, ocpdev->def->index); - maldata = (struct ocp_func_mal_data *)ocpdev->def->additions; + maldata = ocpdev->def->additions; if (maldata == NULL) { - printk(KERN_ERR "mal%d: Missing additional datas !\n", + printk(KERN_ERR "mal%d: missing additional data!\n", ocpdev->def->index); return -ENODEV; } - mal = kmalloc(sizeof(struct ibm_ocp_mal), GFP_KERNEL); - if (mal == NULL) { + mal = kzalloc(sizeof(struct ibm_ocp_mal), GFP_KERNEL); + if (!mal) { printk(KERN_ERR - "mal%d: Out of memory allocating MAL structure !\n", + "mal%d: out of memory allocating MAL structure!\n", ocpdev->def->index); return -ENOMEM; } - memset(mal, 0, sizeof(*mal)); - - switch (ocpdev->def->index) { - case 0: - mal->dcrbase = DCRN_MAL_BASE; - break; -#ifdef DCRN_MAL1_BASE - case 1: - mal->dcrbase = DCRN_MAL1_BASE; - break; -#endif - default: - BUG(); - } - - /**************************/ + mal->dcrbase = maldata->dcr_base; + mal->def = ocpdev->def; - INIT_LIST_HEAD(&mal->commac); + INIT_LIST_HEAD(&mal->poll_list); + set_bit(__LINK_STATE_START, &mal->poll_dev.state); + mal->poll_dev.weight = CONFIG_IBM_EMAC_POLL_WEIGHT; + mal->poll_dev.poll = mal_poll; + mal->poll_dev.priv = mal; + atomic_set(&mal->poll_dev.refcnt, 1); - set_mal_dcrn(mal, DCRN_MALRXCARR, 0xFFFFFFFF); - set_mal_dcrn(mal, DCRN_MALTXCARR, 0xFFFFFFFF); + INIT_LIST_HEAD(&mal->list); - set_mal_dcrn(mal, DCRN_MALCR, MALCR_MMSR); /* 384 */ - /* FIXME: Add delay */ + /* Load power-on reset defaults */ + mal_reset(mal); /* Set the MAL configuration register */ - set_mal_dcrn(mal, DCRN_MALCR, - MALCR_PLBB | MALCR_OPBBL | MALCR_LEA | - MALCR_PLBLT_DEFAULT); - - /* It would be nice to allocate buffers separately for each - * channel, but we can't because the channels share the upper - * 13 bits of address lines. Each channels buffer must also - * be 4k aligned, so we allocate 4k for each channel. This is - * inefficient FIXME: do better, if possible */ - mal->tx_virt_addr = dma_alloc_coherent(&ocpdev->dev, - MAL_DT_ALIGN * - maldata->num_tx_chans, - &mal->tx_phys_addr, GFP_KERNEL); - if (mal->tx_virt_addr == NULL) { + set_mal_dcrn(mal, MAL_CFG, MAL_CFG_DEFAULT | MAL_CFG_PLBB | + MAL_CFG_OPBBL | MAL_CFG_LEA); + + mal_enable_eob_irq(mal); + + /* Allocate space for BD rings */ + BUG_ON(maldata->num_tx_chans <= 0 || maldata->num_tx_chans > 32); + BUG_ON(maldata->num_rx_chans <= 0 || maldata->num_rx_chans > 32); + bd_size = sizeof(struct mal_descriptor) * + (NUM_TX_BUFF * maldata->num_tx_chans + + NUM_RX_BUFF * maldata->num_rx_chans); + mal->bd_virt = + dma_alloc_coherent(&ocpdev->dev, bd_size, &mal->bd_dma, GFP_KERNEL); + + if (!mal->bd_virt) { printk(KERN_ERR - "mal%d: Out of memory allocating MAL descriptors !\n", - ocpdev->def->index); + "mal%d: out of memory allocating RX/TX descriptors!\n", + mal->def->index); err = -ENOMEM; goto fail; } + memset(mal->bd_virt, 0, bd_size); - /* God, oh, god, I hate DCRs */ - set_mal_dcrn(mal, DCRN_MALTXCTP0R, mal->tx_phys_addr); -#ifdef DCRN_MALTXCTP1R - if (maldata->num_tx_chans > 1) - set_mal_dcrn(mal, DCRN_MALTXCTP1R, - mal->tx_phys_addr + MAL_DT_ALIGN); -#endif /* DCRN_MALTXCTP1R */ -#ifdef DCRN_MALTXCTP2R - if (maldata->num_tx_chans > 2) - set_mal_dcrn(mal, DCRN_MALTXCTP2R, - mal->tx_phys_addr + 2 * MAL_DT_ALIGN); -#endif /* DCRN_MALTXCTP2R */ -#ifdef DCRN_MALTXCTP3R - if (maldata->num_tx_chans > 3) - set_mal_dcrn(mal, DCRN_MALTXCTP3R, - mal->tx_phys_addr + 3 * MAL_DT_ALIGN); -#endif /* DCRN_MALTXCTP3R */ -#ifdef DCRN_MALTXCTP4R - if (maldata->num_tx_chans > 4) - set_mal_dcrn(mal, DCRN_MALTXCTP4R, - mal->tx_phys_addr + 4 * MAL_DT_ALIGN); -#endif /* DCRN_MALTXCTP4R */ -#ifdef DCRN_MALTXCTP5R - if (maldata->num_tx_chans > 5) - set_mal_dcrn(mal, DCRN_MALTXCTP5R, - mal->tx_phys_addr + 5 * MAL_DT_ALIGN); -#endif /* DCRN_MALTXCTP5R */ -#ifdef DCRN_MALTXCTP6R - if (maldata->num_tx_chans > 6) - set_mal_dcrn(mal, DCRN_MALTXCTP6R, - mal->tx_phys_addr + 6 * MAL_DT_ALIGN); -#endif /* DCRN_MALTXCTP6R */ -#ifdef DCRN_MALTXCTP7R - if (maldata->num_tx_chans > 7) - set_mal_dcrn(mal, DCRN_MALTXCTP7R, - mal->tx_phys_addr + 7 * MAL_DT_ALIGN); -#endif /* DCRN_MALTXCTP7R */ - - mal->rx_virt_addr = dma_alloc_coherent(&ocpdev->dev, - MAL_DT_ALIGN * - maldata->num_rx_chans, - &mal->rx_phys_addr, GFP_KERNEL); - - set_mal_dcrn(mal, DCRN_MALRXCTP0R, mal->rx_phys_addr); -#ifdef DCRN_MALRXCTP1R - if (maldata->num_rx_chans > 1) - set_mal_dcrn(mal, DCRN_MALRXCTP1R, - mal->rx_phys_addr + MAL_DT_ALIGN); -#endif /* DCRN_MALRXCTP1R */ -#ifdef DCRN_MALRXCTP2R - if (maldata->num_rx_chans > 2) - set_mal_dcrn(mal, DCRN_MALRXCTP2R, - mal->rx_phys_addr + 2 * MAL_DT_ALIGN); -#endif /* DCRN_MALRXCTP2R */ -#ifdef DCRN_MALRXCTP3R - if (maldata->num_rx_chans > 3) - set_mal_dcrn(mal, DCRN_MALRXCTP3R, - mal->rx_phys_addr + 3 * MAL_DT_ALIGN); -#endif /* DCRN_MALRXCTP3R */ + for (i = 0; i < maldata->num_tx_chans; ++i) + set_mal_dcrn(mal, MAL_TXCTPR(i), mal->bd_dma + + sizeof(struct mal_descriptor) * + mal_tx_bd_offset(mal, i)); + + for (i = 0; i < maldata->num_rx_chans; ++i) + set_mal_dcrn(mal, MAL_RXCTPR(i), mal->bd_dma + + sizeof(struct mal_descriptor) * + mal_rx_bd_offset(mal, i)); err = request_irq(maldata->serr_irq, mal_serr, 0, "MAL SERR", mal); if (err) - goto fail; - err = request_irq(maldata->txde_irq, mal_txde, 0, "MAL TX DE ", mal); + goto fail2; + err = request_irq(maldata->txde_irq, mal_txde, 0, "MAL TX DE", mal); if (err) - goto fail; + goto fail3; err = request_irq(maldata->txeob_irq, mal_txeob, 0, "MAL TX EOB", mal); if (err) - goto fail; + goto fail4; err = request_irq(maldata->rxde_irq, mal_rxde, 0, "MAL RX DE", mal); if (err) - goto fail; + goto fail5; err = request_irq(maldata->rxeob_irq, mal_rxeob, 0, "MAL RX EOB", mal); if (err) - goto fail; + goto fail6; - set_mal_dcrn(mal, DCRN_MALIER, - MALIER_DE | MALIER_NE | MALIER_TE | - MALIER_OPBE | MALIER_PLBE); + /* Enable all MAL SERR interrupt sources */ + set_mal_dcrn(mal, MAL_IER, MAL_IER_EVENTS); - /* Advertise me to the rest of the world */ + /* Advertise this instance to the rest of the world */ ocp_set_drvdata(ocpdev, mal); - printk(KERN_INFO "mal%d: Initialized, %d tx channels, %d rx channels\n", - ocpdev->def->index, maldata->num_tx_chans, - maldata->num_rx_chans); + mal_dbg_register(mal->def->index, mal); + printk(KERN_INFO "mal%d: initialized, %d TX channels, %d RX channels\n", + mal->def->index, maldata->num_tx_chans, maldata->num_rx_chans); return 0; + fail6: + free_irq(maldata->rxde_irq, mal); + fail5: + free_irq(maldata->txeob_irq, mal); + fail4: + free_irq(maldata->txde_irq, mal); + fail3: + free_irq(maldata->serr_irq, mal); + fail2: + dma_free_coherent(&ocpdev->dev, bd_size, mal->bd_virt, mal->bd_dma); fail: - /* FIXME: dispose requested IRQs ! */ - if (err && mal) - kfree(mal); + kfree(mal); return err; } static void __exit mal_remove(struct ocp_device *ocpdev) { struct ibm_ocp_mal *mal = ocp_get_drvdata(ocpdev); - struct ocp_func_mal_data *maldata = ocpdev->def->additions; + struct ocp_func_mal_data *maldata = mal->def->additions; + + MAL_DBG("%d: remove" NL, mal->def->index); - BUG_ON(!maldata); + /* Syncronize with scheduled polling, + stolen from net/core/dev.c:dev_close() + */ + clear_bit(__LINK_STATE_START, &mal->poll_dev.state); + netif_poll_disable(&mal->poll_dev); + + if (!list_empty(&mal->list)) { + /* This is *very* bad */ + printk(KERN_EMERG + "mal%d: commac list is not empty on remove!\n", + mal->def->index); + } ocp_set_drvdata(ocpdev, NULL); - /* FIXME: shut down the MAL, deal with dependency with emac */ free_irq(maldata->serr_irq, mal); free_irq(maldata->txde_irq, mal); free_irq(maldata->txeob_irq, mal); free_irq(maldata->rxde_irq, mal); free_irq(maldata->rxeob_irq, mal); - if (mal->tx_virt_addr) - dma_free_coherent(&ocpdev->dev, - MAL_DT_ALIGN * maldata->num_tx_chans, - mal->tx_virt_addr, mal->tx_phys_addr); + mal_reset(mal); - if (mal->rx_virt_addr) - dma_free_coherent(&ocpdev->dev, - MAL_DT_ALIGN * maldata->num_rx_chans, - mal->rx_virt_addr, mal->rx_phys_addr); + mal_dbg_register(mal->def->index, NULL); + + dma_free_coherent(&ocpdev->dev, + sizeof(struct mal_descriptor) * + (NUM_TX_BUFF * maldata->num_tx_chans + + NUM_RX_BUFF * maldata->num_rx_chans), mal->bd_virt, + mal->bd_dma); kfree(mal); } /* Structure for a device driver */ static struct ocp_device_id mal_ids[] = { - {.vendor = OCP_ANY_ID,.function = OCP_FUNC_MAL}, - {.vendor = OCP_VENDOR_INVALID} + { .vendor = OCP_VENDOR_IBM, .function = OCP_FUNC_MAL }, + { .vendor = OCP_VENDOR_INVALID} }; static struct ocp_driver mal_driver = { @@ -441,23 +570,14 @@ static struct ocp_driver mal_driver = { .remove = mal_remove, }; -static int __init init_mals(void) +int __init mal_init(void) { - int rc; - - rc = ocp_register_driver(&mal_driver); - if (rc < 0) { - ocp_unregister_driver(&mal_driver); - return -ENODEV; - } - - return 0; + MAL_DBG(": init" NL); + return ocp_register_driver(&mal_driver); } -static void __exit exit_mals(void) +void __exit mal_exit(void) { + MAL_DBG(": exit" NL); ocp_unregister_driver(&mal_driver); } - -module_init(init_mals); -module_exit(exit_mals); diff --git a/drivers/net/ibm_emac/ibm_emac_mal.h b/drivers/net/ibm_emac/ibm_emac_mal.h index dd9f0dabc6e0..15b0bdae26ac 100644 --- a/drivers/net/ibm_emac/ibm_emac_mal.h +++ b/drivers/net/ibm_emac/ibm_emac_mal.h @@ -1,131 +1,267 @@ -#ifndef _IBM_EMAC_MAL_H -#define _IBM_EMAC_MAL_H +/* + * drivers/net/ibm_emac/ibm_emac_mal.h + * + * Memory Access Layer (MAL) support + * + * Copyright (c) 2004, 2005 Zultys Technologies. + * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net> + * + * Based on original work by + * Armin Kuster <akuster@mvista.com> + * Copyright 2002 MontaVista Softare Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ +#ifndef __IBM_EMAC_MAL_H_ +#define __IBM_EMAC_MAL_H_ +#include <linux/config.h> +#include <linux/init.h> #include <linux/list.h> +#include <linux/netdevice.h> -#define MAL_DT_ALIGN (4096) /* Alignment for each channel's descriptor table */ +#include <asm/io.h> -#define MAL_CHAN_MASK(chan) (0x80000000 >> (chan)) +/* + * These MAL "versions" probably aren't the real versions IBM uses for these + * MAL cores, I assigned them just to make #ifdefs in this file nicer and + * reflect the fact that 40x and 44x have slightly different MALs. --ebs + */ +#if defined(CONFIG_405GP) || defined(CONFIG_405GPR) || defined(CONFIG_405EP) || \ + defined(CONFIG_440EP) || defined(CONFIG_NP405H) +#define MAL_VERSION 1 +#elif defined(CONFIG_440GP) || defined(CONFIG_440GX) || defined(CONFIG_440SP) +#define MAL_VERSION 2 +#else +#error "Unknown SoC, please check chip manual and choose MAL 'version'" +#endif + +/* MALx DCR registers */ +#define MAL_CFG 0x00 +#define MAL_CFG_SR 0x80000000 +#define MAL_CFG_PLBB 0x00004000 +#define MAL_CFG_OPBBL 0x00000080 +#define MAL_CFG_EOPIE 0x00000004 +#define MAL_CFG_LEA 0x00000002 +#define MAL_CFG_SD 0x00000001 +#if MAL_VERSION == 1 +#define MAL_CFG_PLBP_MASK 0x00c00000 +#define MAL_CFG_PLBP_10 0x00800000 +#define MAL_CFG_GA 0x00200000 +#define MAL_CFG_OA 0x00100000 +#define MAL_CFG_PLBLE 0x00080000 +#define MAL_CFG_PLBT_MASK 0x00078000 +#define MAL_CFG_DEFAULT (MAL_CFG_PLBP_10 | MAL_CFG_PLBT_MASK) +#elif MAL_VERSION == 2 +#define MAL_CFG_RPP_MASK 0x00c00000 +#define MAL_CFG_RPP_10 0x00800000 +#define MAL_CFG_RMBS_MASK 0x00300000 +#define MAL_CFG_WPP_MASK 0x000c0000 +#define MAL_CFG_WPP_10 0x00080000 +#define MAL_CFG_WMBS_MASK 0x00030000 +#define MAL_CFG_PLBLE 0x00008000 +#define MAL_CFG_DEFAULT (MAL_CFG_RMBS_MASK | MAL_CFG_WMBS_MASK | \ + MAL_CFG_RPP_10 | MAL_CFG_WPP_10) +#else +#error "Unknown MAL version" +#endif + +#define MAL_ESR 0x01 +#define MAL_ESR_EVB 0x80000000 +#define MAL_ESR_CIDT 0x40000000 +#define MAL_ESR_CID_MASK 0x3e000000 +#define MAL_ESR_CID_SHIFT 25 +#define MAL_ESR_DE 0x00100000 +#define MAL_ESR_OTE 0x00040000 +#define MAL_ESR_OSE 0x00020000 +#define MAL_ESR_PEIN 0x00010000 +#define MAL_ESR_DEI 0x00000010 +#define MAL_ESR_OTEI 0x00000004 +#define MAL_ESR_OSEI 0x00000002 +#define MAL_ESR_PBEI 0x00000001 +#if MAL_VERSION == 1 +#define MAL_ESR_ONE 0x00080000 +#define MAL_ESR_ONEI 0x00000008 +#elif MAL_VERSION == 2 +#define MAL_ESR_PTE 0x00800000 +#define MAL_ESR_PRE 0x00400000 +#define MAL_ESR_PWE 0x00200000 +#define MAL_ESR_PTEI 0x00000080 +#define MAL_ESR_PREI 0x00000040 +#define MAL_ESR_PWEI 0x00000020 +#else +#error "Unknown MAL version" +#endif + +#define MAL_IER 0x02 +#define MAL_IER_DE 0x00000010 +#define MAL_IER_OTE 0x00000004 +#define MAL_IER_OE 0x00000002 +#define MAL_IER_PE 0x00000001 +#if MAL_VERSION == 1 +#define MAL_IER_NWE 0x00000008 +#define MAL_IER_SOC_EVENTS MAL_IER_NWE +#elif MAL_VERSION == 2 +#define MAL_IER_PT 0x00000080 +#define MAL_IER_PRE 0x00000040 +#define MAL_IER_PWE 0x00000020 +#define MAL_IER_SOC_EVENTS (MAL_IER_PT | MAL_IER_PRE | MAL_IER_PWE) +#else +#error "Unknown MAL version" +#endif +#define MAL_IER_EVENTS (MAL_IER_SOC_EVENTS | MAL_IER_OTE | \ + MAL_IER_OTE | MAL_IER_OE | MAL_IER_PE) + +#define MAL_TXCASR 0x04 +#define MAL_TXCARR 0x05 +#define MAL_TXEOBISR 0x06 +#define MAL_TXDEIR 0x07 +#define MAL_RXCASR 0x10 +#define MAL_RXCARR 0x11 +#define MAL_RXEOBISR 0x12 +#define MAL_RXDEIR 0x13 +#define MAL_TXCTPR(n) ((n) + 0x20) +#define MAL_RXCTPR(n) ((n) + 0x40) +#define MAL_RCBS(n) ((n) + 0x60) + +/* In reality MAL can handle TX buffers up to 4095 bytes long, + * but this isn't a good round number :) --ebs + */ +#define MAL_MAX_TX_SIZE 4080 +#define MAL_MAX_RX_SIZE 4080 + +static inline int mal_rx_size(int len) +{ + len = (len + 0xf) & ~0xf; + return len > MAL_MAX_RX_SIZE ? MAL_MAX_RX_SIZE : len; +} + +static inline int mal_tx_chunks(int len) +{ + return (len + MAL_MAX_TX_SIZE - 1) / MAL_MAX_TX_SIZE; +} + +#define MAL_CHAN_MASK(n) (0x80000000 >> (n)) /* MAL Buffer Descriptor structure */ struct mal_descriptor { - unsigned short ctrl; /* MAL / Commac status control bits */ - short data_len; /* Max length is 4K-1 (12 bits) */ - unsigned char *data_ptr; /* pointer to actual data buffer */ -} __attribute__ ((packed)); + u16 ctrl; /* MAL / Commac status control bits */ + u16 data_len; /* Max length is 4K-1 (12 bits) */ + u32 data_ptr; /* pointer to actual data buffer */ +}; /* the following defines are for the MadMAL status and control registers. */ /* MADMAL transmit and receive status/control bits */ -#define MAL_RX_CTRL_EMPTY 0x8000 -#define MAL_RX_CTRL_WRAP 0x4000 -#define MAL_RX_CTRL_CM 0x2000 -#define MAL_RX_CTRL_LAST 0x1000 -#define MAL_RX_CTRL_FIRST 0x0800 -#define MAL_RX_CTRL_INTR 0x0400 - -#define MAL_TX_CTRL_READY 0x8000 -#define MAL_TX_CTRL_WRAP 0x4000 -#define MAL_TX_CTRL_CM 0x2000 -#define MAL_TX_CTRL_LAST 0x1000 -#define MAL_TX_CTRL_INTR 0x0400 +#define MAL_RX_CTRL_EMPTY 0x8000 +#define MAL_RX_CTRL_WRAP 0x4000 +#define MAL_RX_CTRL_CM 0x2000 +#define MAL_RX_CTRL_LAST 0x1000 +#define MAL_RX_CTRL_FIRST 0x0800 +#define MAL_RX_CTRL_INTR 0x0400 +#define MAL_RX_CTRL_SINGLE (MAL_RX_CTRL_LAST | MAL_RX_CTRL_FIRST) +#define MAL_IS_SINGLE_RX(ctrl) (((ctrl) & MAL_RX_CTRL_SINGLE) == MAL_RX_CTRL_SINGLE) + +#define MAL_TX_CTRL_READY 0x8000 +#define MAL_TX_CTRL_WRAP 0x4000 +#define MAL_TX_CTRL_CM 0x2000 +#define MAL_TX_CTRL_LAST 0x1000 +#define MAL_TX_CTRL_INTR 0x0400 struct mal_commac_ops { - void (*txeob) (void *dev, u32 chanmask); - void (*txde) (void *dev, u32 chanmask); - void (*rxeob) (void *dev, u32 chanmask); - void (*rxde) (void *dev, u32 chanmask); + void (*poll_tx) (void *dev); + int (*poll_rx) (void *dev, int budget); + int (*peek_rx) (void *dev); + void (*rxde) (void *dev); }; struct mal_commac { - struct mal_commac_ops *ops; - void *dev; - u32 tx_chan_mask, rx_chan_mask; - struct list_head list; + struct mal_commac_ops *ops; + void *dev; + struct list_head poll_list; + int rx_stopped; + + u32 tx_chan_mask; + u32 rx_chan_mask; + struct list_head list; }; struct ibm_ocp_mal { - int dcrbase; + int dcrbase; - struct list_head commac; - u32 tx_chan_mask, rx_chan_mask; + struct list_head poll_list; + struct net_device poll_dev; - dma_addr_t tx_phys_addr; - struct mal_descriptor *tx_virt_addr; + struct list_head list; + u32 tx_chan_mask; + u32 rx_chan_mask; - dma_addr_t rx_phys_addr; - struct mal_descriptor *rx_virt_addr; -}; + dma_addr_t bd_dma; + struct mal_descriptor *bd_virt; -#define GET_MAL_STANZA(base,dcrn) \ - case base: \ - x = mfdcr(dcrn(base)); \ - break; - -#define SET_MAL_STANZA(base,dcrn, val) \ - case base: \ - mtdcr(dcrn(base), (val)); \ - break; - -#define GET_MAL0_STANZA(dcrn) GET_MAL_STANZA(DCRN_MAL_BASE,dcrn) -#define SET_MAL0_STANZA(dcrn,val) SET_MAL_STANZA(DCRN_MAL_BASE,dcrn,val) - -#ifdef DCRN_MAL1_BASE -#define GET_MAL1_STANZA(dcrn) GET_MAL_STANZA(DCRN_MAL1_BASE,dcrn) -#define SET_MAL1_STANZA(dcrn,val) SET_MAL_STANZA(DCRN_MAL1_BASE,dcrn,val) -#else /* ! DCRN_MAL1_BASE */ -#define GET_MAL1_STANZA(dcrn) -#define SET_MAL1_STANZA(dcrn,val) -#endif + struct ocp_def *def; +}; -#define get_mal_dcrn(mal, dcrn) ({ \ - u32 x; \ - switch ((mal)->dcrbase) { \ - GET_MAL0_STANZA(dcrn) \ - GET_MAL1_STANZA(dcrn) \ - default: \ - x = 0; \ - BUG(); \ - } \ -x; }) - -#define set_mal_dcrn(mal, dcrn, val) do { \ - switch ((mal)->dcrbase) { \ - SET_MAL0_STANZA(dcrn,val) \ - SET_MAL1_STANZA(dcrn,val) \ - default: \ - BUG(); \ - } } while (0) - -static inline void mal_enable_tx_channels(struct ibm_ocp_mal *mal, u32 chanmask) +static inline u32 get_mal_dcrn(struct ibm_ocp_mal *mal, int reg) { - set_mal_dcrn(mal, DCRN_MALTXCASR, - get_mal_dcrn(mal, DCRN_MALTXCASR) | chanmask); + return mfdcr(mal->dcrbase + reg); } -static inline void mal_disable_tx_channels(struct ibm_ocp_mal *mal, - u32 chanmask) +static inline void set_mal_dcrn(struct ibm_ocp_mal *mal, int reg, u32 val) { - set_mal_dcrn(mal, DCRN_MALTXCARR, chanmask); + mtdcr(mal->dcrbase + reg, val); } -static inline void mal_enable_rx_channels(struct ibm_ocp_mal *mal, u32 chanmask) -{ - set_mal_dcrn(mal, DCRN_MALRXCASR, - get_mal_dcrn(mal, DCRN_MALRXCASR) | chanmask); -} +/* Register MAL devices */ +int mal_init(void) __init; +void mal_exit(void) __exit; -static inline void mal_disable_rx_channels(struct ibm_ocp_mal *mal, - u32 chanmask) -{ - set_mal_dcrn(mal, DCRN_MALRXCARR, chanmask); -} +int mal_register_commac(struct ibm_ocp_mal *mal, + struct mal_commac *commac) __init; +void mal_unregister_commac(struct ibm_ocp_mal *mal, + struct mal_commac *commac) __exit; +int mal_set_rcbs(struct ibm_ocp_mal *mal, int channel, unsigned long size); + +/* Returns BD ring offset for a particular channel + (in 'struct mal_descriptor' elements) +*/ +int mal_tx_bd_offset(struct ibm_ocp_mal *mal, int channel); +int mal_rx_bd_offset(struct ibm_ocp_mal *mal, int channel); + +void mal_enable_tx_channel(struct ibm_ocp_mal *mal, int channel); +void mal_disable_tx_channel(struct ibm_ocp_mal *mal, int channel); +void mal_enable_rx_channel(struct ibm_ocp_mal *mal, int channel); +void mal_disable_rx_channel(struct ibm_ocp_mal *mal, int channel); -extern int mal_register_commac(struct ibm_ocp_mal *mal, - struct mal_commac *commac); -extern int mal_unregister_commac(struct ibm_ocp_mal *mal, - struct mal_commac *commac); +/* Add/remove EMAC to/from MAL polling list */ +void mal_poll_add(struct ibm_ocp_mal *mal, struct mal_commac *commac); +void mal_poll_del(struct ibm_ocp_mal *mal, struct mal_commac *commac); + +/* Ethtool MAL registers */ +struct ibm_mal_regs { + u32 tx_count; + u32 rx_count; + + u32 cfg; + u32 esr; + u32 ier; + u32 tx_casr; + u32 tx_carr; + u32 tx_eobisr; + u32 tx_deir; + u32 rx_casr; + u32 rx_carr; + u32 rx_eobisr; + u32 rx_deir; + u32 tx_ctpr[32]; + u32 rx_ctpr[32]; + u32 rcbs[32]; +}; -extern int mal_set_rcbs(struct ibm_ocp_mal *mal, int channel, - unsigned long size); +int mal_get_regs_len(struct ibm_ocp_mal *mal); +void *mal_dump_regs(struct ibm_ocp_mal *mal, void *buf); -#endif /* _IBM_EMAC_MAL_H */ +#endif /* __IBM_EMAC_MAL_H_ */ diff --git a/drivers/net/ibm_emac/ibm_emac_phy.c b/drivers/net/ibm_emac/ibm_emac_phy.c index 14213f090e91..a27e49cfe43b 100644 --- a/drivers/net/ibm_emac/ibm_emac_phy.c +++ b/drivers/net/ibm_emac/ibm_emac_phy.c @@ -1,96 +1,80 @@ /* - * ibm_ocp_phy.c + * drivers/net/ibm_emac/ibm_emac_phy.c * - * PHY drivers for the ibm ocp ethernet driver. Borrowed - * from sungem_phy.c, though I only kept the generic MII + * Driver for PowerPC 4xx on-chip ethernet controller, PHY support. + * Borrowed from sungem_phy.c, though I only kept the generic MII * driver for now. * * This file should be shared with other drivers or eventually * merged as the "low level" part of miilib * * (c) 2003, Benjamin Herrenscmidt (benh@kernel.crashing.org) + * (c) 2004-2005, Eugene Surovegin <ebs@ebshome.net> * */ - #include <linux/config.h> - #include <linux/module.h> - #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/types.h> #include <linux/netdevice.h> -#include <linux/etherdevice.h> #include <linux/mii.h> #include <linux/ethtool.h> #include <linux/delay.h> +#include <asm/ocp.h> + #include "ibm_emac_phy.h" -static int reset_one_mii_phy(struct mii_phy *phy, int phy_id) +static inline int phy_read(struct mii_phy *phy, int reg) +{ + return phy->mdio_read(phy->dev, phy->address, reg); +} + +static inline void phy_write(struct mii_phy *phy, int reg, int val) { - u16 val; + phy->mdio_write(phy->dev, phy->address, reg, val); +} + +int mii_reset_phy(struct mii_phy *phy) +{ + int val; int limit = 10000; - val = __phy_read(phy, phy_id, MII_BMCR); + val = phy_read(phy, MII_BMCR); val &= ~BMCR_ISOLATE; val |= BMCR_RESET; - __phy_write(phy, phy_id, MII_BMCR, val); + phy_write(phy, MII_BMCR, val); - udelay(100); + udelay(300); while (limit--) { - val = __phy_read(phy, phy_id, MII_BMCR); - if ((val & BMCR_RESET) == 0) + val = phy_read(phy, MII_BMCR); + if (val >= 0 && (val & BMCR_RESET) == 0) break; udelay(10); } if ((val & BMCR_ISOLATE) && limit > 0) - __phy_write(phy, phy_id, MII_BMCR, val & ~BMCR_ISOLATE); - - return (limit <= 0); -} - -static int cis8201_init(struct mii_phy *phy) -{ - u16 epcr; - - epcr = phy_read(phy, MII_CIS8201_EPCR); - epcr &= ~EPCR_MODE_MASK; - - switch (phy->mode) { - case PHY_MODE_TBI: - epcr |= EPCR_TBI_MODE; - break; - case PHY_MODE_RTBI: - epcr |= EPCR_RTBI_MODE; - break; - case PHY_MODE_GMII: - epcr |= EPCR_GMII_MODE; - break; - case PHY_MODE_RGMII: - default: - epcr |= EPCR_RGMII_MODE; - } + phy_write(phy, MII_BMCR, val & ~BMCR_ISOLATE); - phy_write(phy, MII_CIS8201_EPCR, epcr); - - return 0; + return limit <= 0; } static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise) { - u16 ctl, adv; + int ctl, adv; - phy->autoneg = 1; + phy->autoneg = AUTONEG_ENABLE; phy->speed = SPEED_10; phy->duplex = DUPLEX_HALF; - phy->pause = 0; + phy->pause = phy->asym_pause = 0; phy->advertising = advertise; /* Setup standard advertise */ adv = phy_read(phy, MII_ADVERTISE); - adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4); + if (adv < 0) + return adv; + adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4 | ADVERTISE_PAUSE_CAP | + ADVERTISE_PAUSE_ASYM); if (advertise & ADVERTISED_10baseT_Half) adv |= ADVERTISE_10HALF; if (advertise & ADVERTISED_10baseT_Full) @@ -99,8 +83,25 @@ static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise) adv |= ADVERTISE_100HALF; if (advertise & ADVERTISED_100baseT_Full) adv |= ADVERTISE_100FULL; + if (advertise & ADVERTISED_Pause) + adv |= ADVERTISE_PAUSE_CAP; + if (advertise & ADVERTISED_Asym_Pause) + adv |= ADVERTISE_PAUSE_ASYM; phy_write(phy, MII_ADVERTISE, adv); + if (phy->features & + (SUPPORTED_1000baseT_Full | SUPPORTED_1000baseT_Half)) { + adv = phy_read(phy, MII_CTRL1000); + if (adv < 0) + return adv; + adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF); + if (advertise & ADVERTISED_1000baseT_Full) + adv |= ADVERTISE_1000FULL; + if (advertise & ADVERTISED_1000baseT_Half) + adv |= ADVERTISE_1000HALF; + phy_write(phy, MII_CTRL1000, adv); + } + /* Start/Restart aneg */ ctl = phy_read(phy, MII_BMCR); ctl |= (BMCR_ANENABLE | BMCR_ANRESTART); @@ -111,14 +112,16 @@ static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise) static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd) { - u16 ctl; + int ctl; - phy->autoneg = 0; + phy->autoneg = AUTONEG_DISABLE; phy->speed = speed; phy->duplex = fd; - phy->pause = 0; + phy->pause = phy->asym_pause = 0; ctl = phy_read(phy, MII_BMCR); + if (ctl < 0) + return ctl; ctl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_ANENABLE); /* First reset the PHY */ @@ -132,6 +135,8 @@ static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd) ctl |= BMCR_SPEED100; break; case SPEED_1000: + ctl |= BMCR_SPEED1000; + break; default: return -EINVAL; } @@ -144,112 +149,143 @@ static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd) static int genmii_poll_link(struct mii_phy *phy) { - u16 status; + int status; - (void)phy_read(phy, MII_BMSR); + /* Clear latched value with dummy read */ + phy_read(phy, MII_BMSR); status = phy_read(phy, MII_BMSR); - if ((status & BMSR_LSTATUS) == 0) + if (status < 0 || (status & BMSR_LSTATUS) == 0) return 0; - if (phy->autoneg && !(status & BMSR_ANEGCOMPLETE)) + if (phy->autoneg == AUTONEG_ENABLE && !(status & BMSR_ANEGCOMPLETE)) return 0; return 1; } -#define MII_CIS8201_ACSR 0x1c -#define ACSR_DUPLEX_STATUS 0x0020 -#define ACSR_SPEED_1000BASET 0x0010 -#define ACSR_SPEED_100BASET 0x0008 - -static int cis8201_read_link(struct mii_phy *phy) +static int genmii_read_link(struct mii_phy *phy) { - u16 acsr; + if (phy->autoneg == AUTONEG_ENABLE) { + int glpa = 0; + int lpa = phy_read(phy, MII_LPA) & phy_read(phy, MII_ADVERTISE); + if (lpa < 0) + return lpa; + + if (phy->features & + (SUPPORTED_1000baseT_Full | SUPPORTED_1000baseT_Half)) { + int adv = phy_read(phy, MII_CTRL1000); + glpa = phy_read(phy, MII_STAT1000); + + if (glpa < 0 || adv < 0) + return adv; + + glpa &= adv << 2; + } + + phy->speed = SPEED_10; + phy->duplex = DUPLEX_HALF; + phy->pause = phy->asym_pause = 0; + + if (glpa & (LPA_1000FULL | LPA_1000HALF)) { + phy->speed = SPEED_1000; + if (glpa & LPA_1000FULL) + phy->duplex = DUPLEX_FULL; + } else if (lpa & (LPA_100FULL | LPA_100HALF)) { + phy->speed = SPEED_100; + if (lpa & LPA_100FULL) + phy->duplex = DUPLEX_FULL; + } else if (lpa & LPA_10FULL) + phy->duplex = DUPLEX_FULL; - if (phy->autoneg) { - acsr = phy_read(phy, MII_CIS8201_ACSR); + if (phy->duplex == DUPLEX_FULL) { + phy->pause = lpa & LPA_PAUSE_CAP ? 1 : 0; + phy->asym_pause = lpa & LPA_PAUSE_ASYM ? 1 : 0; + } + } else { + int bmcr = phy_read(phy, MII_BMCR); + if (bmcr < 0) + return bmcr; - if (acsr & ACSR_DUPLEX_STATUS) + if (bmcr & BMCR_FULLDPLX) phy->duplex = DUPLEX_FULL; else phy->duplex = DUPLEX_HALF; - if (acsr & ACSR_SPEED_1000BASET) { + if (bmcr & BMCR_SPEED1000) phy->speed = SPEED_1000; - } else if (acsr & ACSR_SPEED_100BASET) + else if (bmcr & BMCR_SPEED100) phy->speed = SPEED_100; else phy->speed = SPEED_10; - phy->pause = 0; - } - /* On non-aneg, we assume what we put in BMCR is the speed, - * though magic-aneg shouldn't prevent this case from occurring - */ + phy->pause = phy->asym_pause = 0; + } return 0; } -static int genmii_read_link(struct mii_phy *phy) +/* Generic implementation for most 10/100/1000 PHYs */ +static struct mii_phy_ops generic_phy_ops = { + .setup_aneg = genmii_setup_aneg, + .setup_forced = genmii_setup_forced, + .poll_link = genmii_poll_link, + .read_link = genmii_read_link +}; + +static struct mii_phy_def genmii_phy_def = { + .phy_id = 0x00000000, + .phy_id_mask = 0x00000000, + .name = "Generic MII", + .ops = &generic_phy_ops +}; + +/* CIS8201 */ +#define MII_CIS8201_EPCR 0x17 +#define EPCR_MODE_MASK 0x3000 +#define EPCR_GMII_MODE 0x0000 +#define EPCR_RGMII_MODE 0x1000 +#define EPCR_TBI_MODE 0x2000 +#define EPCR_RTBI_MODE 0x3000 + +static int cis8201_init(struct mii_phy *phy) { - u16 lpa; + int epcr; - if (phy->autoneg) { - lpa = phy_read(phy, MII_LPA) & phy_read(phy, MII_ADVERTISE); + epcr = phy_read(phy, MII_CIS8201_EPCR); + if (epcr < 0) + return epcr; - phy->speed = SPEED_10; - phy->duplex = DUPLEX_HALF; - phy->pause = 0; + epcr &= ~EPCR_MODE_MASK; - if (lpa & (LPA_100FULL | LPA_100HALF)) { - phy->speed = SPEED_100; - if (lpa & LPA_100FULL) - phy->duplex = DUPLEX_FULL; - } else if (lpa & LPA_10FULL) - phy->duplex = DUPLEX_FULL; + switch (phy->mode) { + case PHY_MODE_TBI: + epcr |= EPCR_TBI_MODE; + break; + case PHY_MODE_RTBI: + epcr |= EPCR_RTBI_MODE; + break; + case PHY_MODE_GMII: + epcr |= EPCR_GMII_MODE; + break; + case PHY_MODE_RGMII: + default: + epcr |= EPCR_RGMII_MODE; } - /* On non-aneg, we assume what we put in BMCR is the speed, - * though magic-aneg shouldn't prevent this case from occurring - */ + + phy_write(phy, MII_CIS8201_EPCR, epcr); return 0; } -#define MII_BASIC_FEATURES (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | \ - SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | \ - SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII) -#define MII_GBIT_FEATURES (MII_BASIC_FEATURES | \ - SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full) - -/* CIS8201 phy ops */ static struct mii_phy_ops cis8201_phy_ops = { - init:cis8201_init, - setup_aneg:genmii_setup_aneg, - setup_forced:genmii_setup_forced, - poll_link:genmii_poll_link, - read_link:cis8201_read_link -}; - -/* Generic implementation for most 10/100 PHYs */ -static struct mii_phy_ops generic_phy_ops = { - setup_aneg:genmii_setup_aneg, - setup_forced:genmii_setup_forced, - poll_link:genmii_poll_link, - read_link:genmii_read_link + .init = cis8201_init, + .setup_aneg = genmii_setup_aneg, + .setup_forced = genmii_setup_forced, + .poll_link = genmii_poll_link, + .read_link = genmii_read_link }; static struct mii_phy_def cis8201_phy_def = { - phy_id:0x000fc410, - phy_id_mask:0x000ffff0, - name:"CIS8201 Gigabit Ethernet", - features:MII_GBIT_FEATURES, - magic_aneg:0, - ops:&cis8201_phy_ops -}; - -static struct mii_phy_def genmii_phy_def = { - phy_id:0x00000000, - phy_id_mask:0x00000000, - name:"Generic MII", - features:MII_BASIC_FEATURES, - magic_aneg:0, - ops:&generic_phy_ops + .phy_id = 0x000fc410, + .phy_id_mask = 0x000ffff0, + .name = "CIS8201 Gigabit Ethernet", + .ops = &cis8201_phy_ops }; static struct mii_phy_def *mii_phy_table[] = { @@ -258,39 +294,60 @@ static struct mii_phy_def *mii_phy_table[] = { NULL }; -int mii_phy_probe(struct mii_phy *phy, int mii_id) +int mii_phy_probe(struct mii_phy *phy, int address) { - int rc; - u32 id; struct mii_phy_def *def; int i; + u32 id; - phy->autoneg = 0; + phy->autoneg = AUTONEG_DISABLE; phy->advertising = 0; - phy->mii_id = mii_id; - phy->speed = 0; - phy->duplex = 0; - phy->pause = 0; - - /* Take PHY out of isloate mode and reset it. */ - rc = reset_one_mii_phy(phy, mii_id); - if (rc) + phy->address = address; + phy->speed = SPEED_10; + phy->duplex = DUPLEX_HALF; + phy->pause = phy->asym_pause = 0; + + /* Take PHY out of isolate mode and reset it. */ + if (mii_reset_phy(phy)) return -ENODEV; /* Read ID and find matching entry */ - id = (phy_read(phy, MII_PHYSID1) << 16 | phy_read(phy, MII_PHYSID2)) - & 0xfffffff0; + id = (phy_read(phy, MII_PHYSID1) << 16) | phy_read(phy, MII_PHYSID2); for (i = 0; (def = mii_phy_table[i]) != NULL; i++) if ((id & def->phy_id_mask) == def->phy_id) break; /* Should never be NULL (we have a generic entry), but... */ - if (def == NULL) + if (!def) return -ENODEV; phy->def = def; + /* Determine PHY features if needed */ + phy->features = def->features; + if (!phy->features) { + u16 bmsr = phy_read(phy, MII_BMSR); + if (bmsr & BMSR_ANEGCAPABLE) + phy->features |= SUPPORTED_Autoneg; + if (bmsr & BMSR_10HALF) + phy->features |= SUPPORTED_10baseT_Half; + if (bmsr & BMSR_10FULL) + phy->features |= SUPPORTED_10baseT_Full; + if (bmsr & BMSR_100HALF) + phy->features |= SUPPORTED_100baseT_Half; + if (bmsr & BMSR_100FULL) + phy->features |= SUPPORTED_100baseT_Full; + if (bmsr & BMSR_ESTATEN) { + u16 esr = phy_read(phy, MII_ESTATUS); + if (esr & ESTATUS_1000_TFULL) + phy->features |= SUPPORTED_1000baseT_Full; + if (esr & ESTATUS_1000_THALF) + phy->features |= SUPPORTED_1000baseT_Half; + } + phy->features |= SUPPORTED_MII; + } + /* Setup default advertising */ - phy->advertising = def->features; + phy->advertising = phy->features; return 0; } diff --git a/drivers/net/ibm_emac/ibm_emac_phy.h b/drivers/net/ibm_emac/ibm_emac_phy.h index 61afbea96563..a70e0fea54c4 100644 --- a/drivers/net/ibm_emac/ibm_emac_phy.h +++ b/drivers/net/ibm_emac/ibm_emac_phy.h @@ -1,65 +1,25 @@ - /* - * ibm_emac_phy.h - * + * drivers/net/ibm_emac/ibm_emac_phy.h * - * Benjamin Herrenschmidt <benh@kernel.crashing.org> - * February 2003 + * Driver for PowerPC 4xx on-chip ethernet controller, PHY support * - * 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. + * Benjamin Herrenschmidt <benh@kernel.crashing.org> + * February 2003 * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * 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., - * 675 Mass Ave, Cambridge, MA 02139, USA. + * Minor additions by Eugene Surovegin <ebs@ebshome.net>, 2004 * + * 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 file basically duplicates sungem_phy.{c,h} with different PHYs * supported. I'm looking into merging that in a single mii layer more * flexible than mii.c */ -#ifndef _IBM_EMAC_PHY_H_ -#define _IBM_EMAC_PHY_H_ - -/* - * PHY mode settings - * Used for multi-mode capable PHYs - */ -#define PHY_MODE_NA 0 -#define PHY_MODE_MII 1 -#define PHY_MODE_RMII 2 -#define PHY_MODE_SMII 3 -#define PHY_MODE_RGMII 4 -#define PHY_MODE_TBI 5 -#define PHY_MODE_GMII 6 -#define PHY_MODE_RTBI 7 -#define PHY_MODE_SGMII 8 - -/* - * PHY specific registers/values - */ - -/* CIS8201 */ -#define MII_CIS8201_EPCR 0x17 -#define EPCR_MODE_MASK 0x3000 -#define EPCR_GMII_MODE 0x0000 -#define EPCR_RGMII_MODE 0x1000 -#define EPCR_TBI_MODE 0x2000 -#define EPCR_RTBI_MODE 0x3000 +#ifndef _IBM_OCP_PHY_H_ +#define _IBM_OCP_PHY_H_ struct mii_phy; @@ -77,7 +37,8 @@ struct mii_phy_ops { struct mii_phy_def { u32 phy_id; /* Concatenated ID1 << 16 | ID2 */ u32 phy_id_mask; /* Significant bits */ - u32 features; /* Ethtool SUPPORTED_* defines */ + u32 features; /* Ethtool SUPPORTED_* defines or + 0 for autodetect */ int magic_aneg; /* Autoneg does all speed test for us */ const char *name; const struct mii_phy_ops *ops; @@ -86,8 +47,11 @@ struct mii_phy_def { /* An instance of a PHY, partially borrowed from mii_if_info */ struct mii_phy { struct mii_phy_def *def; - int advertising; - int mii_id; + u32 advertising; /* Ethtool ADVERTISED_* defines */ + u32 features; /* Copied from mii_phy_def.features + or determined automaticaly */ + int address; /* PHY address */ + int mode; /* PHY mode */ /* 1: autoneg enabled, 0: disabled */ int autoneg; @@ -98,40 +62,19 @@ struct mii_phy { int speed; int duplex; int pause; - - /* PHY mode - if needed */ - int mode; + int asym_pause; /* Provided by host chip */ struct net_device *dev; - int (*mdio_read) (struct net_device * dev, int mii_id, int reg); - void (*mdio_write) (struct net_device * dev, int mii_id, int reg, + int (*mdio_read) (struct net_device * dev, int addr, int reg); + void (*mdio_write) (struct net_device * dev, int addr, int reg, int val); }; /* Pass in a struct mii_phy with dev, mdio_read and mdio_write * filled, the remaining fields will be filled on return */ -extern int mii_phy_probe(struct mii_phy *phy, int mii_id); - -static inline int __phy_read(struct mii_phy *phy, int id, int reg) -{ - return phy->mdio_read(phy->dev, id, reg); -} - -static inline void __phy_write(struct mii_phy *phy, int id, int reg, int val) -{ - phy->mdio_write(phy->dev, id, reg, val); -} - -static inline int phy_read(struct mii_phy *phy, int reg) -{ - return phy->mdio_read(phy->dev, phy->mii_id, reg); -} - -static inline void phy_write(struct mii_phy *phy, int reg, int val) -{ - phy->mdio_write(phy->dev, phy->mii_id, reg, val); -} +int mii_phy_probe(struct mii_phy *phy, int address); +int mii_reset_phy(struct mii_phy *phy); -#endif /* _IBM_EMAC_PHY_H_ */ +#endif /* _IBM_OCP_PHY_H_ */ diff --git a/drivers/net/ibm_emac/ibm_emac_rgmii.c b/drivers/net/ibm_emac/ibm_emac_rgmii.c new file mode 100644 index 000000000000..f0b1ffb2dbbf --- /dev/null +++ b/drivers/net/ibm_emac/ibm_emac_rgmii.c @@ -0,0 +1,201 @@ +/* + * drivers/net/ibm_emac/ibm_emac_rgmii.c + * + * Driver for PowerPC 4xx on-chip ethernet controller, RGMII bridge support. + * + * Copyright (c) 2004, 2005 Zultys Technologies. + * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net> + * + * Based on original work by + * Matt Porter <mporter@kernel.crashing.org> + * Copyright 2004 MontaVista Software, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/ethtool.h> +#include <asm/io.h> + +#include "ibm_emac_core.h" +#include "ibm_emac_debug.h" + +/* RGMIIx_FER */ +#define RGMII_FER_MASK(idx) (0x7 << ((idx) * 4)) +#define RGMII_FER_RTBI(idx) (0x4 << ((idx) * 4)) +#define RGMII_FER_RGMII(idx) (0x5 << ((idx) * 4)) +#define RGMII_FER_TBI(idx) (0x6 << ((idx) * 4)) +#define RGMII_FER_GMII(idx) (0x7 << ((idx) * 4)) + +/* RGMIIx_SSR */ +#define RGMII_SSR_MASK(idx) (0x7 << ((idx) * 8)) +#define RGMII_SSR_100(idx) (0x2 << ((idx) * 8)) +#define RGMII_SSR_1000(idx) (0x4 << ((idx) * 8)) + +/* RGMII bridge supports only GMII/TBI and RGMII/RTBI PHYs */ +static inline int rgmii_valid_mode(int phy_mode) +{ + return phy_mode == PHY_MODE_GMII || + phy_mode == PHY_MODE_RGMII || + phy_mode == PHY_MODE_TBI || + phy_mode == PHY_MODE_RTBI; +} + +static inline const char *rgmii_mode_name(int mode) +{ + switch (mode) { + case PHY_MODE_RGMII: + return "RGMII"; + case PHY_MODE_TBI: + return "TBI"; + case PHY_MODE_GMII: + return "GMII"; + case PHY_MODE_RTBI: + return "RTBI"; + default: + BUG(); + } +} + +static inline u32 rgmii_mode_mask(int mode, int input) +{ + switch (mode) { + case PHY_MODE_RGMII: + return RGMII_FER_RGMII(input); + case PHY_MODE_TBI: + return RGMII_FER_TBI(input); + case PHY_MODE_GMII: + return RGMII_FER_GMII(input); + case PHY_MODE_RTBI: + return RGMII_FER_RTBI(input); + default: + BUG(); + } +} + +static int __init rgmii_init(struct ocp_device *ocpdev, int input, int mode) +{ + struct ibm_ocp_rgmii *dev = ocp_get_drvdata(ocpdev); + struct rgmii_regs *p; + + RGMII_DBG("%d: init(%d, %d)" NL, ocpdev->def->index, input, mode); + + if (!dev) { + dev = kzalloc(sizeof(struct ibm_ocp_rgmii), GFP_KERNEL); + if (!dev) { + printk(KERN_ERR + "rgmii%d: couldn't allocate device structure!\n", + ocpdev->def->index); + return -ENOMEM; + } + + p = (struct rgmii_regs *)ioremap(ocpdev->def->paddr, + sizeof(struct rgmii_regs)); + if (!p) { + printk(KERN_ERR + "rgmii%d: could not ioremap device registers!\n", + ocpdev->def->index); + kfree(dev); + return -ENOMEM; + } + + dev->base = p; + ocp_set_drvdata(ocpdev, dev); + + /* Disable all inputs by default */ + out_be32(&p->fer, 0); + } else + p = dev->base; + + /* Enable this input */ + out_be32(&p->fer, in_be32(&p->fer) | rgmii_mode_mask(mode, input)); + + printk(KERN_NOTICE "rgmii%d: input %d in %s mode\n", + ocpdev->def->index, input, rgmii_mode_name(mode)); + + ++dev->users; + return 0; +} + +int __init rgmii_attach(void *emac) +{ + struct ocp_enet_private *dev = emac; + struct ocp_func_emac_data *emacdata = dev->def->additions; + + /* Check if we need to attach to a RGMII */ + if (emacdata->rgmii_idx >= 0 && rgmii_valid_mode(emacdata->phy_mode)) { + dev->rgmii_input = emacdata->rgmii_mux; + dev->rgmii_dev = + ocp_find_device(OCP_VENDOR_IBM, OCP_FUNC_RGMII, + emacdata->rgmii_idx); + if (!dev->rgmii_dev) { + printk(KERN_ERR "emac%d: unknown rgmii%d!\n", + dev->def->index, emacdata->rgmii_idx); + return -ENODEV; + } + if (rgmii_init + (dev->rgmii_dev, dev->rgmii_input, emacdata->phy_mode)) { + printk(KERN_ERR + "emac%d: rgmii%d initialization failed!\n", + dev->def->index, emacdata->rgmii_idx); + return -ENODEV; + } + } + return 0; +} + +void rgmii_set_speed(struct ocp_device *ocpdev, int input, int speed) +{ + struct ibm_ocp_rgmii *dev = ocp_get_drvdata(ocpdev); + u32 ssr = in_be32(&dev->base->ssr) & ~RGMII_SSR_MASK(input); + + RGMII_DBG("%d: speed(%d, %d)" NL, ocpdev->def->index, input, speed); + + if (speed == SPEED_1000) + ssr |= RGMII_SSR_1000(input); + else if (speed == SPEED_100) + ssr |= RGMII_SSR_100(input); + + out_be32(&dev->base->ssr, ssr); +} + +void __exit __rgmii_fini(struct ocp_device *ocpdev, int input) +{ + struct ibm_ocp_rgmii *dev = ocp_get_drvdata(ocpdev); + BUG_ON(!dev || dev->users == 0); + + RGMII_DBG("%d: fini(%d)" NL, ocpdev->def->index, input); + + /* Disable this input */ + out_be32(&dev->base->fer, + in_be32(&dev->base->fer) & ~RGMII_FER_MASK(input)); + + if (!--dev->users) { + /* Free everything if this is the last user */ + ocp_set_drvdata(ocpdev, NULL); + iounmap((void *)dev->base); + kfree(dev); + } +} + +int __rgmii_get_regs_len(struct ocp_device *ocpdev) +{ + return sizeof(struct emac_ethtool_regs_subhdr) + + sizeof(struct rgmii_regs); +} + +void *rgmii_dump_regs(struct ocp_device *ocpdev, void *buf) +{ + struct ibm_ocp_rgmii *dev = ocp_get_drvdata(ocpdev); + struct emac_ethtool_regs_subhdr *hdr = buf; + struct rgmii_regs *regs = (struct rgmii_regs *)(hdr + 1); + + hdr->version = 0; + hdr->index = ocpdev->def->index; + memcpy_fromio(regs, dev->base, sizeof(struct rgmii_regs)); + return regs + 1; +} diff --git a/drivers/net/ibm_emac/ibm_emac_rgmii.h b/drivers/net/ibm_emac/ibm_emac_rgmii.h index 49f188f4ea6e..a1ffb8a44fff 100644 --- a/drivers/net/ibm_emac/ibm_emac_rgmii.h +++ b/drivers/net/ibm_emac/ibm_emac_rgmii.h @@ -1,5 +1,7 @@ /* - * Defines for the IBM RGMII bridge + * drivers/net/ibm_emac/ibm_emac_rgmii.c + * + * Driver for PowerPC 4xx on-chip ethernet controller, RGMII bridge support. * * Based on ocp_zmii.h/ibm_emac_zmii.h * Armin Kuster akuster@mvista.com @@ -7,6 +9,9 @@ * Copyright 2004 MontaVista Software, Inc. * Matt Porter <mporter@kernel.crashing.org> * + * Copyright (c) 2004, 2005 Zultys Technologies. + * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net> + * * 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 @@ -19,47 +24,42 @@ #include <linux/config.h> /* RGMII bridge */ -typedef struct rgmii_regs { +struct rgmii_regs { u32 fer; /* Function enable register */ u32 ssr; /* Speed select register */ -} rgmii_t; - -#define RGMII_INPUTS 4 +}; /* RGMII device */ struct ibm_ocp_rgmii { struct rgmii_regs *base; - int mode[RGMII_INPUTS]; int users; /* number of EMACs using this RGMII bridge */ }; -/* Fuctional Enable Reg */ -#define RGMII_FER_MASK(x) (0x00000007 << (4*x)) -#define RGMII_RTBI 0x00000004 -#define RGMII_RGMII 0x00000005 -#define RGMII_TBI 0x00000006 -#define RGMII_GMII 0x00000007 - -/* Speed Selection reg */ +#ifdef CONFIG_IBM_EMAC_RGMII +int rgmii_attach(void *emac) __init; -#define RGMII_SP2_100 0x00000002 -#define RGMII_SP2_1000 0x00000004 -#define RGMII_SP3_100 0x00000200 -#define RGMII_SP3_1000 0x00000400 +void __rgmii_fini(struct ocp_device *ocpdev, int input) __exit; +static inline void rgmii_fini(struct ocp_device *ocpdev, int input) +{ + if (ocpdev) + __rgmii_fini(ocpdev, input); +} -#define RGMII_MII2_SPDMASK 0x00000007 -#define RGMII_MII3_SPDMASK 0x00000700 +void rgmii_set_speed(struct ocp_device *ocpdev, int input, int speed); -#define RGMII_MII2_100MB RGMII_SP2_100 & ~RGMII_SP2_1000 -#define RGMII_MII2_1000MB RGMII_SP2_1000 & ~RGMII_SP2_100 -#define RGMII_MII2_10MB ~(RGMII_SP2_100 | RGMII_SP2_1000) -#define RGMII_MII3_100MB RGMII_SP3_100 & ~RGMII_SP3_1000 -#define RGMII_MII3_1000MB RGMII_SP3_1000 & ~RGMII_SP3_100 -#define RGMII_MII3_10MB ~(RGMII_SP3_100 | RGMII_SP3_1000) +int __rgmii_get_regs_len(struct ocp_device *ocpdev); +static inline int rgmii_get_regs_len(struct ocp_device *ocpdev) +{ + return ocpdev ? __rgmii_get_regs_len(ocpdev) : 0; +} -#define RTBI 0 -#define RGMII 1 -#define TBI 2 -#define GMII 3 +void *rgmii_dump_regs(struct ocp_device *ocpdev, void *buf); +#else +# define rgmii_attach(x) 0 +# define rgmii_fini(x,y) ((void)0) +# define rgmii_set_speed(x,y,z) ((void)0) +# define rgmii_get_regs_len(x) 0 +# define rgmii_dump_regs(x,buf) (buf) +#endif /* !CONFIG_IBM_EMAC_RGMII */ #endif /* _IBM_EMAC_RGMII_H_ */ diff --git a/drivers/net/ibm_emac/ibm_emac_tah.c b/drivers/net/ibm_emac/ibm_emac_tah.c new file mode 100644 index 000000000000..af08afc22f9f --- /dev/null +++ b/drivers/net/ibm_emac/ibm_emac_tah.c @@ -0,0 +1,111 @@ +/* + * drivers/net/ibm_emac/ibm_emac_tah.c + * + * Driver for PowerPC 4xx on-chip ethernet controller, TAH support. + * + * Copyright 2004 MontaVista Software, Inc. + * Matt Porter <mporter@kernel.crashing.org> + * + * Copyright (c) 2005 Eugene Surovegin <ebs@ebshome.net> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ +#include <linux/config.h> +#include <asm/io.h> + +#include "ibm_emac_core.h" + +static int __init tah_init(struct ocp_device *ocpdev) +{ + struct tah_regs *p; + + if (ocp_get_drvdata(ocpdev)) { + printk(KERN_ERR "tah%d: already in use!\n", ocpdev->def->index); + return -EBUSY; + } + + /* Initialize TAH and enable IPv4 checksum verification, no TSO yet */ + p = (struct tah_regs *)ioremap(ocpdev->def->paddr, sizeof(*p)); + if (!p) { + printk(KERN_ERR "tah%d: could not ioremap device registers!\n", + ocpdev->def->index); + return -ENOMEM; + } + ocp_set_drvdata(ocpdev, p); + __tah_reset(ocpdev); + + return 0; +} + +int __init tah_attach(void *emac) +{ + struct ocp_enet_private *dev = emac; + struct ocp_func_emac_data *emacdata = dev->def->additions; + + /* Check if we need to attach to a TAH */ + if (emacdata->tah_idx >= 0) { + dev->tah_dev = ocp_find_device(OCP_ANY_ID, OCP_FUNC_TAH, + emacdata->tah_idx); + if (!dev->tah_dev) { + printk(KERN_ERR "emac%d: unknown tah%d!\n", + dev->def->index, emacdata->tah_idx); + return -ENODEV; + } + if (tah_init(dev->tah_dev)) { + printk(KERN_ERR + "emac%d: tah%d initialization failed!\n", + dev->def->index, emacdata->tah_idx); + return -ENODEV; + } + } + return 0; +} + +void __exit __tah_fini(struct ocp_device *ocpdev) +{ + struct tah_regs *p = ocp_get_drvdata(ocpdev); + BUG_ON(!p); + ocp_set_drvdata(ocpdev, NULL); + iounmap((void *)p); +} + +void __tah_reset(struct ocp_device *ocpdev) +{ + struct tah_regs *p = ocp_get_drvdata(ocpdev); + int n; + + /* Reset TAH */ + out_be32(&p->mr, TAH_MR_SR); + n = 100; + while ((in_be32(&p->mr) & TAH_MR_SR) && n) + --n; + + if (unlikely(!n)) + printk(KERN_ERR "tah%d: reset timeout\n", ocpdev->def->index); + + /* 10KB TAH TX FIFO accomodates the max MTU of 9000 */ + out_be32(&p->mr, + TAH_MR_CVR | TAH_MR_ST_768 | TAH_MR_TFS_10KB | TAH_MR_DTFP | + TAH_MR_DIG); +} + +int __tah_get_regs_len(struct ocp_device *ocpdev) +{ + return sizeof(struct emac_ethtool_regs_subhdr) + + sizeof(struct tah_regs); +} + +void *tah_dump_regs(struct ocp_device *ocpdev, void *buf) +{ + struct tah_regs *dev = ocp_get_drvdata(ocpdev); + struct emac_ethtool_regs_subhdr *hdr = buf; + struct tah_regs *regs = (struct tah_regs *)(hdr + 1); + + hdr->version = 0; + hdr->index = ocpdev->def->index; + memcpy_fromio(regs, dev, sizeof(struct tah_regs)); + return regs + 1; +} diff --git a/drivers/net/ibm_emac/ibm_emac_tah.h b/drivers/net/ibm_emac/ibm_emac_tah.h index ecfc69805521..9299b5dd7eb1 100644 --- a/drivers/net/ibm_emac/ibm_emac_tah.h +++ b/drivers/net/ibm_emac/ibm_emac_tah.h @@ -1,9 +1,13 @@ /* - * Defines for the IBM TAH + * drivers/net/ibm_emac/ibm_emac_tah.h + * + * Driver for PowerPC 4xx on-chip ethernet controller, TAH support. * * Copyright 2004 MontaVista Software, Inc. * Matt Porter <mporter@kernel.crashing.org> * + * Copyright (c) 2005 Eugene Surovegin <ebs@ebshome.net> + * * 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 @@ -13,36 +17,72 @@ #ifndef _IBM_EMAC_TAH_H #define _IBM_EMAC_TAH_H +#include <linux/config.h> +#include <linux/init.h> +#include <asm/ocp.h> + /* TAH */ -typedef struct tah_regs { - u32 tah_revid; +struct tah_regs { + u32 revid; u32 pad[3]; - u32 tah_mr; - u32 tah_ssr0; - u32 tah_ssr1; - u32 tah_ssr2; - u32 tah_ssr3; - u32 tah_ssr4; - u32 tah_ssr5; - u32 tah_tsr; -} tah_t; + u32 mr; + u32 ssr0; + u32 ssr1; + u32 ssr2; + u32 ssr3; + u32 ssr4; + u32 ssr5; + u32 tsr; +}; /* TAH engine */ -#define TAH_MR_CVR 0x80000000 -#define TAH_MR_SR 0x40000000 -#define TAH_MR_ST_256 0x01000000 -#define TAH_MR_ST_512 0x02000000 -#define TAH_MR_ST_768 0x03000000 -#define TAH_MR_ST_1024 0x04000000 -#define TAH_MR_ST_1280 0x05000000 -#define TAH_MR_ST_1536 0x06000000 -#define TAH_MR_TFS_16KB 0x00000000 -#define TAH_MR_TFS_2KB 0x00200000 -#define TAH_MR_TFS_4KB 0x00400000 -#define TAH_MR_TFS_6KB 0x00600000 -#define TAH_MR_TFS_8KB 0x00800000 -#define TAH_MR_TFS_10KB 0x00a00000 -#define TAH_MR_DTFP 0x00100000 -#define TAH_MR_DIG 0x00080000 +#define TAH_MR_CVR 0x80000000 +#define TAH_MR_SR 0x40000000 +#define TAH_MR_ST_256 0x01000000 +#define TAH_MR_ST_512 0x02000000 +#define TAH_MR_ST_768 0x03000000 +#define TAH_MR_ST_1024 0x04000000 +#define TAH_MR_ST_1280 0x05000000 +#define TAH_MR_ST_1536 0x06000000 +#define TAH_MR_TFS_16KB 0x00000000 +#define TAH_MR_TFS_2KB 0x00200000 +#define TAH_MR_TFS_4KB 0x00400000 +#define TAH_MR_TFS_6KB 0x00600000 +#define TAH_MR_TFS_8KB 0x00800000 +#define TAH_MR_TFS_10KB 0x00a00000 +#define TAH_MR_DTFP 0x00100000 +#define TAH_MR_DIG 0x00080000 + +#ifdef CONFIG_IBM_EMAC_TAH +int tah_attach(void *emac) __init; + +void __tah_fini(struct ocp_device *ocpdev) __exit; +static inline void tah_fini(struct ocp_device *ocpdev) +{ + if (ocpdev) + __tah_fini(ocpdev); +} + +void __tah_reset(struct ocp_device *ocpdev); +static inline void tah_reset(struct ocp_device *ocpdev) +{ + if (ocpdev) + __tah_reset(ocpdev); +} + +int __tah_get_regs_len(struct ocp_device *ocpdev); +static inline int tah_get_regs_len(struct ocp_device *ocpdev) +{ + return ocpdev ? __tah_get_regs_len(ocpdev) : 0; +} + +void *tah_dump_regs(struct ocp_device *ocpdev, void *buf); +#else +# define tah_attach(x) 0 +# define tah_fini(x) ((void)0) +# define tah_reset(x) ((void)0) +# define tah_get_regs_len(x) 0 +# define tah_dump_regs(x,buf) (buf) +#endif /* !CONFIG_IBM_EMAC_TAH */ #endif /* _IBM_EMAC_TAH_H */ diff --git a/drivers/net/ibm_emac/ibm_emac_zmii.c b/drivers/net/ibm_emac/ibm_emac_zmii.c new file mode 100644 index 000000000000..35c1185079ed --- /dev/null +++ b/drivers/net/ibm_emac/ibm_emac_zmii.c @@ -0,0 +1,255 @@ +/* + * drivers/net/ibm_emac/ibm_emac_zmii.c + * + * Driver for PowerPC 4xx on-chip ethernet controller, ZMII bridge support. + * + * Copyright (c) 2004, 2005 Zultys Technologies. + * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net> + * + * Based on original work by + * Armin Kuster <akuster@mvista.com> + * Copyright 2001 MontaVista Softare Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/ethtool.h> +#include <asm/io.h> + +#include "ibm_emac_core.h" +#include "ibm_emac_debug.h" + +/* ZMIIx_FER */ +#define ZMII_FER_MDI(idx) (0x80000000 >> ((idx) * 4)) +#define ZMII_FER_MDI_ALL (ZMII_FER_MDI(0) | ZMII_FER_MDI(1) | \ + ZMII_FER_MDI(2) | ZMII_FER_MDI(3)) + +#define ZMII_FER_SMII(idx) (0x40000000 >> ((idx) * 4)) +#define ZMII_FER_RMII(idx) (0x20000000 >> ((idx) * 4)) +#define ZMII_FER_MII(idx) (0x10000000 >> ((idx) * 4)) + +/* ZMIIx_SSR */ +#define ZMII_SSR_SCI(idx) (0x40000000 >> ((idx) * 4)) +#define ZMII_SSR_FSS(idx) (0x20000000 >> ((idx) * 4)) +#define ZMII_SSR_SP(idx) (0x10000000 >> ((idx) * 4)) + +/* ZMII only supports MII, RMII and SMII + * we also support autodetection for backward compatibility + */ +static inline int zmii_valid_mode(int mode) +{ + return mode == PHY_MODE_MII || + mode == PHY_MODE_RMII || + mode == PHY_MODE_SMII || + mode == PHY_MODE_NA; +} + +static inline const char *zmii_mode_name(int mode) +{ + switch (mode) { + case PHY_MODE_MII: + return "MII"; + case PHY_MODE_RMII: + return "RMII"; + case PHY_MODE_SMII: + return "SMII"; + default: + BUG(); + } +} + +static inline u32 zmii_mode_mask(int mode, int input) +{ + switch (mode) { + case PHY_MODE_MII: + return ZMII_FER_MII(input); + case PHY_MODE_RMII: + return ZMII_FER_RMII(input); + case PHY_MODE_SMII: + return ZMII_FER_SMII(input); + default: + return 0; + } +} + +static int __init zmii_init(struct ocp_device *ocpdev, int input, int *mode) +{ + struct ibm_ocp_zmii *dev = ocp_get_drvdata(ocpdev); + struct zmii_regs *p; + + ZMII_DBG("%d: init(%d, %d)" NL, ocpdev->def->index, input, *mode); + + if (!dev) { + dev = kzalloc(sizeof(struct ibm_ocp_zmii), GFP_KERNEL); + if (!dev) { + printk(KERN_ERR + "zmii%d: couldn't allocate device structure!\n", + ocpdev->def->index); + return -ENOMEM; + } + dev->mode = PHY_MODE_NA; + + p = (struct zmii_regs *)ioremap(ocpdev->def->paddr, + sizeof(struct zmii_regs)); + if (!p) { + printk(KERN_ERR + "zmii%d: could not ioremap device registers!\n", + ocpdev->def->index); + kfree(dev); + return -ENOMEM; + } + dev->base = p; + ocp_set_drvdata(ocpdev, dev); + + /* We may need FER value for autodetection later */ + dev->fer_save = in_be32(&p->fer); + + /* Disable all inputs by default */ + out_be32(&p->fer, 0); + } else + p = dev->base; + + if (!zmii_valid_mode(*mode)) { + /* Probably an EMAC connected to RGMII, + * but it still may need ZMII for MDIO + */ + goto out; + } + + /* Autodetect ZMII mode if not specified. + * This is only for backward compatibility with the old driver. + * Please, always specify PHY mode in your board port to avoid + * any surprises. + */ + if (dev->mode == PHY_MODE_NA) { + if (*mode == PHY_MODE_NA) { + u32 r = dev->fer_save; + + ZMII_DBG("%d: autodetecting mode, FER = 0x%08x" NL, + ocpdev->def->index, r); + + if (r & (ZMII_FER_MII(0) | ZMII_FER_MII(1))) + dev->mode = PHY_MODE_MII; + else if (r & (ZMII_FER_RMII(0) | ZMII_FER_RMII(1))) + dev->mode = PHY_MODE_RMII; + else + dev->mode = PHY_MODE_SMII; + } else + dev->mode = *mode; + + printk(KERN_NOTICE "zmii%d: bridge in %s mode\n", + ocpdev->def->index, zmii_mode_name(dev->mode)); + } else { + /* All inputs must use the same mode */ + if (*mode != PHY_MODE_NA && *mode != dev->mode) { + printk(KERN_ERR + "zmii%d: invalid mode %d specified for input %d\n", + ocpdev->def->index, *mode, input); + return -EINVAL; + } + } + + /* Report back correct PHY mode, + * it may be used during PHY initialization. + */ + *mode = dev->mode; + + /* Enable this input */ + out_be32(&p->fer, in_be32(&p->fer) | zmii_mode_mask(dev->mode, input)); + out: + ++dev->users; + return 0; +} + +int __init zmii_attach(void *emac) +{ + struct ocp_enet_private *dev = emac; + struct ocp_func_emac_data *emacdata = dev->def->additions; + + if (emacdata->zmii_idx >= 0) { + dev->zmii_input = emacdata->zmii_mux; + dev->zmii_dev = + ocp_find_device(OCP_VENDOR_IBM, OCP_FUNC_ZMII, + emacdata->zmii_idx); + if (!dev->zmii_dev) { + printk(KERN_ERR "emac%d: unknown zmii%d!\n", + dev->def->index, emacdata->zmii_idx); + return -ENODEV; + } + if (zmii_init + (dev->zmii_dev, dev->zmii_input, &emacdata->phy_mode)) { + printk(KERN_ERR + "emac%d: zmii%d initialization failed!\n", + dev->def->index, emacdata->zmii_idx); + return -ENODEV; + } + } + return 0; +} + +void __zmii_enable_mdio(struct ocp_device *ocpdev, int input) +{ + struct ibm_ocp_zmii *dev = ocp_get_drvdata(ocpdev); + u32 fer = in_be32(&dev->base->fer) & ~ZMII_FER_MDI_ALL; + + ZMII_DBG2("%d: mdio(%d)" NL, ocpdev->def->index, input); + + out_be32(&dev->base->fer, fer | ZMII_FER_MDI(input)); +} + +void __zmii_set_speed(struct ocp_device *ocpdev, int input, int speed) +{ + struct ibm_ocp_zmii *dev = ocp_get_drvdata(ocpdev); + u32 ssr = in_be32(&dev->base->ssr); + + ZMII_DBG("%d: speed(%d, %d)" NL, ocpdev->def->index, input, speed); + + if (speed == SPEED_100) + ssr |= ZMII_SSR_SP(input); + else + ssr &= ~ZMII_SSR_SP(input); + + out_be32(&dev->base->ssr, ssr); +} + +void __exit __zmii_fini(struct ocp_device *ocpdev, int input) +{ + struct ibm_ocp_zmii *dev = ocp_get_drvdata(ocpdev); + BUG_ON(!dev || dev->users == 0); + + ZMII_DBG("%d: fini(%d)" NL, ocpdev->def->index, input); + + /* Disable this input */ + out_be32(&dev->base->fer, + in_be32(&dev->base->fer) & ~zmii_mode_mask(dev->mode, input)); + + if (!--dev->users) { + /* Free everything if this is the last user */ + ocp_set_drvdata(ocpdev, NULL); + iounmap((void *)dev->base); + kfree(dev); + } +} + +int __zmii_get_regs_len(struct ocp_device *ocpdev) +{ + return sizeof(struct emac_ethtool_regs_subhdr) + + sizeof(struct zmii_regs); +} + +void *zmii_dump_regs(struct ocp_device *ocpdev, void *buf) +{ + struct ibm_ocp_zmii *dev = ocp_get_drvdata(ocpdev); + struct emac_ethtool_regs_subhdr *hdr = buf; + struct zmii_regs *regs = (struct zmii_regs *)(hdr + 1); + + hdr->version = 0; + hdr->index = ocpdev->def->index; + memcpy_fromio(regs, dev->base, sizeof(struct zmii_regs)); + return regs + 1; +} diff --git a/drivers/net/ibm_emac/ibm_emac_zmii.h b/drivers/net/ibm_emac/ibm_emac_zmii.h index 6f6cd2a39e38..0bb26062c0ad 100644 --- a/drivers/net/ibm_emac/ibm_emac_zmii.h +++ b/drivers/net/ibm_emac/ibm_emac_zmii.h @@ -1,23 +1,27 @@ /* - * ocp_zmii.h + * drivers/net/ibm_emac/ibm_emac_zmii.h * - * Defines for the IBM ZMII bridge + * Driver for PowerPC 4xx on-chip ethernet controller, ZMII bridge support. * - * Armin Kuster akuster@mvista.com - * Dec, 2001 + * Copyright (c) 2004, 2005 Zultys Technologies. + * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net> * - * Copyright 2001 MontaVista Softare Inc. + * Based on original work by + * Armin Kuster <akuster@mvista.com> + * Copyright 2001 MontaVista Softare Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. + * */ - #ifndef _IBM_EMAC_ZMII_H_ #define _IBM_EMAC_ZMII_H_ #include <linux/config.h> +#include <linux/init.h> +#include <asm/ocp.h> /* ZMII bridge registers */ struct zmii_regs { @@ -26,68 +30,54 @@ struct zmii_regs { u32 smiirs; /* SMII status reg */ }; -#define ZMII_INPUTS 4 - /* ZMII device */ struct ibm_ocp_zmii { struct zmii_regs *base; - int mode[ZMII_INPUTS]; + int mode; /* subset of PHY_MODE_XXXX */ int users; /* number of EMACs using this ZMII bridge */ + u32 fer_save; /* FER value left by firmware */ }; -/* Fuctional Enable Reg */ - -#define ZMII_FER_MASK(x) (0xf0000000 >> (4*x)) - -#define ZMII_MDI0 0x80000000 -#define ZMII_SMII0 0x40000000 -#define ZMII_RMII0 0x20000000 -#define ZMII_MII0 0x10000000 -#define ZMII_MDI1 0x08000000 -#define ZMII_SMII1 0x04000000 -#define ZMII_RMII1 0x02000000 -#define ZMII_MII1 0x01000000 -#define ZMII_MDI2 0x00800000 -#define ZMII_SMII2 0x00400000 -#define ZMII_RMII2 0x00200000 -#define ZMII_MII2 0x00100000 -#define ZMII_MDI3 0x00080000 -#define ZMII_SMII3 0x00040000 -#define ZMII_RMII3 0x00020000 -#define ZMII_MII3 0x00010000 +#ifdef CONFIG_IBM_EMAC_ZMII +int zmii_attach(void *emac) __init; -/* Speed Selection reg */ +void __zmii_fini(struct ocp_device *ocpdev, int input) __exit; +static inline void zmii_fini(struct ocp_device *ocpdev, int input) +{ + if (ocpdev) + __zmii_fini(ocpdev, input); +} -#define ZMII_SCI0 0x40000000 -#define ZMII_FSS0 0x20000000 -#define ZMII_SP0 0x10000000 -#define ZMII_SCI1 0x04000000 -#define ZMII_FSS1 0x02000000 -#define ZMII_SP1 0x01000000 -#define ZMII_SCI2 0x00400000 -#define ZMII_FSS2 0x00200000 -#define ZMII_SP2 0x00100000 -#define ZMII_SCI3 0x00040000 -#define ZMII_FSS3 0x00020000 -#define ZMII_SP3 0x00010000 +void __zmii_enable_mdio(struct ocp_device *ocpdev, int input); +static inline void zmii_enable_mdio(struct ocp_device *ocpdev, int input) +{ + if (ocpdev) + __zmii_enable_mdio(ocpdev, input); +} -#define ZMII_MII0_100MB ZMII_SP0 -#define ZMII_MII0_10MB ~ZMII_SP0 -#define ZMII_MII1_100MB ZMII_SP1 -#define ZMII_MII1_10MB ~ZMII_SP1 -#define ZMII_MII2_100MB ZMII_SP2 -#define ZMII_MII2_10MB ~ZMII_SP2 -#define ZMII_MII3_100MB ZMII_SP3 -#define ZMII_MII3_10MB ~ZMII_SP3 +void __zmii_set_speed(struct ocp_device *ocpdev, int input, int speed); +static inline void zmii_set_speed(struct ocp_device *ocpdev, int input, + int speed) +{ + if (ocpdev) + __zmii_set_speed(ocpdev, input, speed); +} -/* SMII Status reg */ +int __zmii_get_regs_len(struct ocp_device *ocpdev); +static inline int zmii_get_regs_len(struct ocp_device *ocpdev) +{ + return ocpdev ? __zmii_get_regs_len(ocpdev) : 0; +} -#define ZMII_STS0 0xFF000000 /* EMAC0 smii status mask */ -#define ZMII_STS1 0x00FF0000 /* EMAC1 smii status mask */ +void *zmii_dump_regs(struct ocp_device *ocpdev, void *buf); -#define SMII 0 -#define RMII 1 -#define MII 2 -#define MDI 3 +#else +# define zmii_attach(x) 0 +# define zmii_fini(x,y) ((void)0) +# define zmii_enable_mdio(x,y) ((void)0) +# define zmii_set_speed(x,y,z) ((void)0) +# define zmii_get_regs_len(x) 0 +# define zmii_dump_regs(x,buf) (buf) +#endif /* !CONFIG_IBM_EMAC_ZMII */ #endif /* _IBM_EMAC_ZMII_H_ */ diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index cbe9368a4d56..e5246f227c98 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -96,7 +96,7 @@ static void ibmveth_proc_unregister_driver(void); static void ibmveth_proc_register_adapter(struct ibmveth_adapter *adapter); static void ibmveth_proc_unregister_adapter(struct ibmveth_adapter *adapter); static irqreturn_t ibmveth_interrupt(int irq, void *dev_instance, struct pt_regs *regs); -static inline void ibmveth_schedule_replenishing(struct ibmveth_adapter*); +static inline void ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter); #ifdef CONFIG_PROC_FS #define IBMVETH_PROC_DIR "net/ibmveth" @@ -181,6 +181,7 @@ static int ibmveth_alloc_buffer_pool(struct ibmveth_buff_pool *pool) atomic_set(&pool->available, 0); pool->producer_index = 0; pool->consumer_index = 0; + pool->active = 0; return 0; } @@ -236,7 +237,7 @@ static void ibmveth_replenish_buffer_pool(struct ibmveth_adapter *adapter, struc lpar_rc = h_add_logical_lan_buffer(adapter->vdev->unit_address, desc.desc); if(lpar_rc != H_Success) { - pool->free_map[free_index] = IBM_VETH_INVALID_MAP; + pool->free_map[free_index] = index; pool->skbuff[index] = NULL; pool->consumer_index--; dma_unmap_single(&adapter->vdev->dev, @@ -255,37 +256,19 @@ static void ibmveth_replenish_buffer_pool(struct ibmveth_adapter *adapter, struc atomic_add(buffers_added, &(pool->available)); } -/* check if replenishing is needed. */ -static inline int ibmveth_is_replenishing_needed(struct ibmveth_adapter *adapter) -{ - return ((atomic_read(&adapter->rx_buff_pool[0].available) < adapter->rx_buff_pool[0].threshold) || - (atomic_read(&adapter->rx_buff_pool[1].available) < adapter->rx_buff_pool[1].threshold) || - (atomic_read(&adapter->rx_buff_pool[2].available) < adapter->rx_buff_pool[2].threshold)); -} - -/* kick the replenish tasklet if we need replenishing and it isn't already running */ -static inline void ibmveth_schedule_replenishing(struct ibmveth_adapter *adapter) -{ - if(ibmveth_is_replenishing_needed(adapter) && - (atomic_dec_if_positive(&adapter->not_replenishing) == 0)) { - schedule_work(&adapter->replenish_task); - } -} - -/* replenish tasklet routine */ +/* replenish routine */ static void ibmveth_replenish_task(struct ibmveth_adapter *adapter) { + int i; + adapter->replenish_task_cycles++; - ibmveth_replenish_buffer_pool(adapter, &adapter->rx_buff_pool[0]); - ibmveth_replenish_buffer_pool(adapter, &adapter->rx_buff_pool[1]); - ibmveth_replenish_buffer_pool(adapter, &adapter->rx_buff_pool[2]); + for(i = 0; i < IbmVethNumBufferPools; i++) + if(adapter->rx_buff_pool[i].active) + ibmveth_replenish_buffer_pool(adapter, + &adapter->rx_buff_pool[i]); adapter->rx_no_buffer = *(u64*)(((char*)adapter->buffer_list_addr) + 4096 - 8); - - atomic_inc(&adapter->not_replenishing); - - ibmveth_schedule_replenishing(adapter); } /* empty and free ana buffer pool - also used to do cleanup in error paths */ @@ -293,10 +276,8 @@ static void ibmveth_free_buffer_pool(struct ibmveth_adapter *adapter, struct ibm { int i; - if(pool->free_map) { - kfree(pool->free_map); - pool->free_map = NULL; - } + kfree(pool->free_map); + pool->free_map = NULL; if(pool->skbuff && pool->dma_addr) { for(i = 0; i < pool->size; ++i) { @@ -321,6 +302,7 @@ static void ibmveth_free_buffer_pool(struct ibmveth_adapter *adapter, struct ibm kfree(pool->skbuff); pool->skbuff = NULL; } + pool->active = 0; } /* remove a buffer from a pool */ @@ -379,6 +361,12 @@ static void ibmveth_rxq_recycle_buffer(struct ibmveth_adapter *adapter) ibmveth_assert(pool < IbmVethNumBufferPools); ibmveth_assert(index < adapter->rx_buff_pool[pool].size); + if(!adapter->rx_buff_pool[pool].active) { + ibmveth_rxq_harvest_buffer(adapter); + ibmveth_free_buffer_pool(adapter, &adapter->rx_buff_pool[pool]); + return; + } + desc.desc = 0; desc.fields.valid = 1; desc.fields.length = adapter->rx_buff_pool[pool].buff_size; @@ -409,6 +397,8 @@ static inline void ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter) static void ibmveth_cleanup(struct ibmveth_adapter *adapter) { + int i; + if(adapter->buffer_list_addr != NULL) { if(!dma_mapping_error(adapter->buffer_list_dma)) { dma_unmap_single(&adapter->vdev->dev, @@ -443,26 +433,24 @@ static void ibmveth_cleanup(struct ibmveth_adapter *adapter) adapter->rx_queue.queue_addr = NULL; } - ibmveth_free_buffer_pool(adapter, &adapter->rx_buff_pool[0]); - ibmveth_free_buffer_pool(adapter, &adapter->rx_buff_pool[1]); - ibmveth_free_buffer_pool(adapter, &adapter->rx_buff_pool[2]); + for(i = 0; i<IbmVethNumBufferPools; i++) + ibmveth_free_buffer_pool(adapter, &adapter->rx_buff_pool[i]); } static int ibmveth_open(struct net_device *netdev) { struct ibmveth_adapter *adapter = netdev->priv; u64 mac_address = 0; - int rxq_entries; + int rxq_entries = 1; unsigned long lpar_rc; int rc; union ibmveth_buf_desc rxq_desc; + int i; ibmveth_debug_printk("open starting\n"); - rxq_entries = - adapter->rx_buff_pool[0].size + - adapter->rx_buff_pool[1].size + - adapter->rx_buff_pool[2].size + 1; + for(i = 0; i<IbmVethNumBufferPools; i++) + rxq_entries += adapter->rx_buff_pool[i].size; adapter->buffer_list_addr = (void*) get_zeroed_page(GFP_KERNEL); adapter->filter_list_addr = (void*) get_zeroed_page(GFP_KERNEL); @@ -502,14 +490,8 @@ static int ibmveth_open(struct net_device *netdev) adapter->rx_queue.num_slots = rxq_entries; adapter->rx_queue.toggle = 1; - if(ibmveth_alloc_buffer_pool(&adapter->rx_buff_pool[0]) || - ibmveth_alloc_buffer_pool(&adapter->rx_buff_pool[1]) || - ibmveth_alloc_buffer_pool(&adapter->rx_buff_pool[2])) - { - ibmveth_error_printk("unable to allocate buffer pools\n"); - ibmveth_cleanup(adapter); - return -ENOMEM; - } + /* call change_mtu to init the buffer pools based in initial mtu */ + ibmveth_change_mtu(netdev, netdev->mtu); memcpy(&mac_address, netdev->dev_addr, netdev->addr_len); mac_address = mac_address >> 16; @@ -552,10 +534,10 @@ static int ibmveth_open(struct net_device *netdev) return rc; } - netif_start_queue(netdev); + ibmveth_debug_printk("initial replenish cycle\n"); + ibmveth_replenish_task(adapter); - ibmveth_debug_printk("scheduling initial replenish cycle\n"); - ibmveth_schedule_replenishing(adapter); + netif_start_queue(netdev); ibmveth_debug_printk("open complete\n"); @@ -573,9 +555,6 @@ static int ibmveth_close(struct net_device *netdev) free_irq(netdev->irq, netdev); - cancel_delayed_work(&adapter->replenish_task); - flush_scheduled_work(); - do { lpar_rc = h_free_logical_lan(adapter->vdev->unit_address); } while (H_isLongBusy(lpar_rc) || (lpar_rc == H_Busy)); @@ -640,12 +619,18 @@ static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev) unsigned long lpar_rc; int nfrags = 0, curfrag; unsigned long correlator; + unsigned long flags; unsigned int retry_count; + unsigned int tx_dropped = 0; + unsigned int tx_bytes = 0; + unsigned int tx_packets = 0; + unsigned int tx_send_failed = 0; + unsigned int tx_map_failed = 0; + if ((skb_shinfo(skb)->nr_frags + 1) > IbmVethMaxSendFrags) { - adapter->stats.tx_dropped++; - dev_kfree_skb(skb); - return 0; + tx_dropped++; + goto out; } memset(&desc, 0, sizeof(desc)); @@ -664,10 +649,9 @@ static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev) if(dma_mapping_error(desc[0].fields.address)) { ibmveth_error_printk("tx: unable to map initial fragment\n"); - adapter->tx_map_failed++; - adapter->stats.tx_dropped++; - dev_kfree_skb(skb); - return 0; + tx_map_failed++; + tx_dropped++; + goto out; } curfrag = nfrags; @@ -684,8 +668,8 @@ static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev) if(dma_mapping_error(desc[curfrag+1].fields.address)) { ibmveth_error_printk("tx: unable to map fragment %d\n", curfrag); - adapter->tx_map_failed++; - adapter->stats.tx_dropped++; + tx_map_failed++; + tx_dropped++; /* Free all the mappings we just created */ while(curfrag < nfrags) { dma_unmap_single(&adapter->vdev->dev, @@ -694,8 +678,7 @@ static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev) DMA_TO_DEVICE); curfrag++; } - dev_kfree_skb(skb); - return 0; + goto out; } } @@ -720,11 +703,12 @@ static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev) ibmveth_error_printk("tx: desc[%i] valid=%d, len=%d, address=0x%d\n", i, desc[i].fields.valid, desc[i].fields.length, desc[i].fields.address); } - adapter->tx_send_failed++; - adapter->stats.tx_dropped++; + tx_send_failed++; + tx_dropped++; } else { - adapter->stats.tx_packets++; - adapter->stats.tx_bytes += skb->len; + tx_packets++; + tx_bytes += skb->len; + netdev->trans_start = jiffies; } do { @@ -733,6 +717,14 @@ static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev) desc[nfrags].fields.length, DMA_TO_DEVICE); } while(--nfrags >= 0); +out: spin_lock_irqsave(&adapter->stats_lock, flags); + adapter->stats.tx_dropped += tx_dropped; + adapter->stats.tx_bytes += tx_bytes; + adapter->stats.tx_packets += tx_packets; + adapter->tx_send_failed += tx_send_failed; + adapter->tx_map_failed += tx_map_failed; + spin_unlock_irqrestore(&adapter->stats_lock, flags); + dev_kfree_skb(skb); return 0; } @@ -776,13 +768,14 @@ static int ibmveth_poll(struct net_device *netdev, int *budget) adapter->stats.rx_packets++; adapter->stats.rx_bytes += length; frames_processed++; + netdev->last_rx = jiffies; } } else { more_work = 0; } } while(more_work && (frames_processed < max_frames_to_process)); - ibmveth_schedule_replenishing(adapter); + ibmveth_replenish_task(adapter); if(more_work) { /* more work to do - return that we are not done yet */ @@ -883,17 +876,54 @@ static void ibmveth_set_multicast_list(struct net_device *netdev) static int ibmveth_change_mtu(struct net_device *dev, int new_mtu) { - if ((new_mtu < 68) || (new_mtu > (1<<20))) + struct ibmveth_adapter *adapter = dev->priv; + int i; + int prev_smaller = 1; + + if ((new_mtu < 68) || + (new_mtu > (pool_size[IbmVethNumBufferPools-1]) - IBMVETH_BUFF_OH)) return -EINVAL; + + for(i = 0; i<IbmVethNumBufferPools; i++) { + int activate = 0; + if (new_mtu > (pool_size[i] - IBMVETH_BUFF_OH)) { + activate = 1; + prev_smaller= 1; + } else { + if (prev_smaller) + activate = 1; + prev_smaller= 0; + } + + if (activate && !adapter->rx_buff_pool[i].active) { + struct ibmveth_buff_pool *pool = + &adapter->rx_buff_pool[i]; + if(ibmveth_alloc_buffer_pool(pool)) { + ibmveth_error_printk("unable to alloc pool\n"); + return -ENOMEM; + } + adapter->rx_buff_pool[i].active = 1; + } else if (!activate && adapter->rx_buff_pool[i].active) { + adapter->rx_buff_pool[i].active = 0; + h_free_logical_lan_buffer(adapter->vdev->unit_address, + (u64)pool_size[i]); + } + + } + + /* kick the interrupt handler so that the new buffer pools get + replenished or deallocated */ + ibmveth_interrupt(dev->irq, dev, NULL); + dev->mtu = new_mtu; return 0; } static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id) { - int rc; + int rc, i; struct net_device *netdev; - struct ibmveth_adapter *adapter; + struct ibmveth_adapter *adapter = NULL; unsigned char *mac_addr_p; unsigned int *mcastFilterSize_p; @@ -960,23 +990,21 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ netdev->ethtool_ops = &netdev_ethtool_ops; netdev->change_mtu = ibmveth_change_mtu; SET_NETDEV_DEV(netdev, &dev->dev); + netdev->features |= NETIF_F_LLTX; + spin_lock_init(&adapter->stats_lock); memcpy(&netdev->dev_addr, &adapter->mac_addr, netdev->addr_len); - ibmveth_init_buffer_pool(&adapter->rx_buff_pool[0], 0, IbmVethPool0DftCnt, IbmVethPool0DftSize); - ibmveth_init_buffer_pool(&adapter->rx_buff_pool[1], 1, IbmVethPool1DftCnt, IbmVethPool1DftSize); - ibmveth_init_buffer_pool(&adapter->rx_buff_pool[2], 2, IbmVethPool2DftCnt, IbmVethPool2DftSize); + for(i = 0; i<IbmVethNumBufferPools; i++) + ibmveth_init_buffer_pool(&adapter->rx_buff_pool[i], i, + pool_count[i], pool_size[i]); ibmveth_debug_printk("adapter @ 0x%p\n", adapter); - INIT_WORK(&adapter->replenish_task, (void*)ibmveth_replenish_task, (void*)adapter); - adapter->buffer_list_dma = DMA_ERROR_CODE; adapter->filter_list_dma = DMA_ERROR_CODE; adapter->rx_queue.queue_dma = DMA_ERROR_CODE; - atomic_set(&adapter->not_replenishing, 1); - ibmveth_debug_printk("registering netdev...\n"); rc = register_netdev(netdev); diff --git a/drivers/net/ibmveth.h b/drivers/net/ibmveth.h index 51a470da9686..46919a814fca 100644 --- a/drivers/net/ibmveth.h +++ b/drivers/net/ibmveth.h @@ -49,6 +49,7 @@ #define H_SEND_LOGICAL_LAN 0x120 #define H_MULTICAST_CTRL 0x130 #define H_CHANGE_LOGICAL_LAN_MAC 0x14C +#define H_FREE_LOGICAL_LAN_BUFFER 0x1D4 /* hcall macros */ #define h_register_logical_lan(ua, buflst, rxq, fltlst, mac) \ @@ -69,13 +70,15 @@ #define h_change_logical_lan_mac(ua, mac) \ plpar_hcall_norets(H_CHANGE_LOGICAL_LAN_MAC, ua, mac) -#define IbmVethNumBufferPools 3 -#define IbmVethPool0DftSize (1024 * 2) -#define IbmVethPool1DftSize (1024 * 4) -#define IbmVethPool2DftSize (1024 * 10) -#define IbmVethPool0DftCnt 256 -#define IbmVethPool1DftCnt 256 -#define IbmVethPool2DftCnt 256 +#define h_free_logical_lan_buffer(ua, bufsize) \ + plpar_hcall_norets(H_FREE_LOGICAL_LAN_BUFFER, ua, bufsize) + +#define IbmVethNumBufferPools 5 +#define IBMVETH_BUFF_OH 22 /* Overhead: 14 ethernet header + 8 opaque handle */ + +/* pool_size should be sorted */ +static int pool_size[] = { 512, 1024 * 2, 1024 * 16, 1024 * 32, 1024 * 64 }; +static int pool_count[] = { 256, 768, 256, 256, 256 }; #define IBM_VETH_INVALID_MAP ((u16)0xffff) @@ -90,6 +93,7 @@ struct ibmveth_buff_pool { u16 *free_map; dma_addr_t *dma_addr; struct sk_buff **skbuff; + int active; }; struct ibmveth_rx_q { @@ -114,10 +118,6 @@ struct ibmveth_adapter { dma_addr_t filter_list_dma; struct ibmveth_buff_pool rx_buff_pool[IbmVethNumBufferPools]; struct ibmveth_rx_q rx_queue; - atomic_t not_replenishing; - - /* helper tasks */ - struct work_struct replenish_task; /* adapter specific stats */ u64 replenish_task_cycles; @@ -131,6 +131,7 @@ struct ibmveth_adapter { u64 tx_linearize_failed; u64 tx_map_failed; u64 tx_send_failed; + spinlock_t stats_lock; }; struct ibmveth_buf_desc_fields { diff --git a/drivers/net/irda/Kconfig b/drivers/net/irda/Kconfig index ca5914091d3a..d54156f11e61 100644 --- a/drivers/net/irda/Kconfig +++ b/drivers/net/irda/Kconfig @@ -400,5 +400,15 @@ config VIA_FIR To compile it as a module, choose M here: the module will be called via-ircc. +config PXA_FICP + tristate "Intel PXA2xx Internal FICP" + depends on ARCH_PXA && IRDA + help + Say Y or M here if you want to build support for the PXA2xx + built-in IRDA interface which can support both SIR and FIR. + This driver relies on platform specific helper routines so + available capabilities may vary from one PXA2xx target to + another. + endmenu diff --git a/drivers/net/irda/Makefile b/drivers/net/irda/Makefile index 29a8bd812b21..e7a8b7f7f5dd 100644 --- a/drivers/net/irda/Makefile +++ b/drivers/net/irda/Makefile @@ -18,6 +18,7 @@ obj-$(CONFIG_SMC_IRCC_FIR) += smsc-ircc2.o obj-$(CONFIG_ALI_FIR) += ali-ircc.o obj-$(CONFIG_VLSI_FIR) += vlsi_ir.o obj-$(CONFIG_VIA_FIR) += via-ircc.o +obj-$(CONFIG_PXA_FICP) += pxaficp_ir.o # Old dongle drivers for old SIR drivers obj-$(CONFIG_ESI_DONGLE_OLD) += esi.o obj-$(CONFIG_TEKRAM_DONGLE_OLD) += tekram.o diff --git a/drivers/net/irda/donauboe.c b/drivers/net/irda/donauboe.c index 0a08c539c051..0282771b1cbb 100644 --- a/drivers/net/irda/donauboe.c +++ b/drivers/net/irda/donauboe.c @@ -1695,11 +1695,9 @@ toshoboe_open (struct pci_dev *pci_dev, const struct pci_device_id *pdid) freebufs: for (i = 0; i < TX_SLOTS; ++i) - if (self->tx_bufs[i]) - kfree (self->tx_bufs[i]); + kfree (self->tx_bufs[i]); for (i = 0; i < RX_SLOTS; ++i) - if (self->rx_bufs[i]) - kfree (self->rx_bufs[i]); + kfree (self->rx_bufs[i]); kfree(self->ringbuf); freeregion: diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c index 6c766fdc51a6..c22c0517883c 100644 --- a/drivers/net/irda/irda-usb.c +++ b/drivers/net/irda/irda-usb.c @@ -1168,10 +1168,8 @@ static inline void irda_usb_close(struct irda_usb_cb *self) unregister_netdev(self->netdev); /* Remove the speed buffer */ - if (self->speed_buff != NULL) { - kfree(self->speed_buff); - self->speed_buff = NULL; - } + kfree(self->speed_buff); + self->speed_buff = NULL; } /********************** USB CONFIG SUBROUTINES **********************/ diff --git a/drivers/net/irda/irport.c b/drivers/net/irda/irport.c index 5971315f3fa0..3d016a498e1d 100644 --- a/drivers/net/irda/irport.c +++ b/drivers/net/irda/irport.c @@ -235,8 +235,7 @@ static int irport_close(struct irport_cb *self) __FUNCTION__, self->io.sir_base); release_region(self->io.sir_base, self->io.sir_ext); - if (self->tx_buff.head) - kfree(self->tx_buff.head); + kfree(self->tx_buff.head); if (self->rx_buff.skb) kfree_skb(self->rx_buff.skb); diff --git a/drivers/net/irda/pxaficp_ir.c b/drivers/net/irda/pxaficp_ir.c new file mode 100644 index 000000000000..b886b07412a6 --- /dev/null +++ b/drivers/net/irda/pxaficp_ir.c @@ -0,0 +1,865 @@ +/* + * linux/drivers/net/irda/pxaficp_ir.c + * + * Based on sa1100_ir.c by Russell King + * + * Changes copyright (C) 2003-2005 MontaVista Software, Inc. + * + * 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. + * + * Infra-red driver (SIR/FIR) for the PXA2xx embedded microprocessor + * + */ +#include <linux/config.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/netdevice.h> +#include <linux/slab.h> +#include <linux/rtnetlink.h> +#include <linux/interrupt.h> +#include <linux/dma-mapping.h> +#include <linux/pm.h> + +#include <net/irda/irda.h> +#include <net/irda/irmod.h> +#include <net/irda/wrapper.h> +#include <net/irda/irda_device.h> + +#include <asm/irq.h> +#include <asm/dma.h> +#include <asm/delay.h> +#include <asm/hardware.h> +#include <asm/arch/irda.h> +#include <asm/arch/pxa-regs.h> + +#ifdef CONFIG_MACH_MAINSTONE +#include <asm/arch/mainstone.h> +#endif + +#define IrSR_RXPL_NEG_IS_ZERO (1<<4) +#define IrSR_RXPL_POS_IS_ZERO 0x0 +#define IrSR_TXPL_NEG_IS_ZERO (1<<3) +#define IrSR_TXPL_POS_IS_ZERO 0x0 +#define IrSR_XMODE_PULSE_1_6 (1<<2) +#define IrSR_XMODE_PULSE_3_16 0x0 +#define IrSR_RCVEIR_IR_MODE (1<<1) +#define IrSR_RCVEIR_UART_MODE 0x0 +#define IrSR_XMITIR_IR_MODE (1<<0) +#define IrSR_XMITIR_UART_MODE 0x0 + +#define IrSR_IR_RECEIVE_ON (\ + IrSR_RXPL_NEG_IS_ZERO | \ + IrSR_TXPL_POS_IS_ZERO | \ + IrSR_XMODE_PULSE_3_16 | \ + IrSR_RCVEIR_IR_MODE | \ + IrSR_XMITIR_UART_MODE) + +#define IrSR_IR_TRANSMIT_ON (\ + IrSR_RXPL_NEG_IS_ZERO | \ + IrSR_TXPL_POS_IS_ZERO | \ + IrSR_XMODE_PULSE_3_16 | \ + IrSR_RCVEIR_UART_MODE | \ + IrSR_XMITIR_IR_MODE) + +struct pxa_irda { + int speed; + int newspeed; + unsigned long last_oscr; + + unsigned char *dma_rx_buff; + unsigned char *dma_tx_buff; + dma_addr_t dma_rx_buff_phy; + dma_addr_t dma_tx_buff_phy; + unsigned int dma_tx_buff_len; + int txdma; + int rxdma; + + struct net_device_stats stats; + struct irlap_cb *irlap; + struct qos_info qos; + + iobuff_t tx_buff; + iobuff_t rx_buff; + + struct device *dev; + struct pxaficp_platform_data *pdata; +}; + + +#define IS_FIR(si) ((si)->speed >= 4000000) +#define IRDA_FRAME_SIZE_LIMIT 2047 + +inline static void pxa_irda_fir_dma_rx_start(struct pxa_irda *si) +{ + DCSR(si->rxdma) = DCSR_NODESC; + DSADR(si->rxdma) = __PREG(ICDR); + DTADR(si->rxdma) = si->dma_rx_buff_phy; + DCMD(si->rxdma) = DCMD_INCTRGADDR | DCMD_FLOWSRC | DCMD_WIDTH1 | DCMD_BURST32 | IRDA_FRAME_SIZE_LIMIT; + DCSR(si->rxdma) |= DCSR_RUN; +} + +inline static void pxa_irda_fir_dma_tx_start(struct pxa_irda *si) +{ + DCSR(si->txdma) = DCSR_NODESC; + DSADR(si->txdma) = si->dma_tx_buff_phy; + DTADR(si->txdma) = __PREG(ICDR); + DCMD(si->txdma) = DCMD_INCSRCADDR | DCMD_FLOWTRG | DCMD_ENDIRQEN | DCMD_WIDTH1 | DCMD_BURST32 | si->dma_tx_buff_len; + DCSR(si->txdma) |= DCSR_RUN; +} + +/* + * Set the IrDA communications speed. + */ +static int pxa_irda_set_speed(struct pxa_irda *si, int speed) +{ + unsigned long flags; + unsigned int divisor; + + switch (speed) { + case 9600: case 19200: case 38400: + case 57600: case 115200: + + /* refer to PXA250/210 Developer's Manual 10-7 */ + /* BaudRate = 14.7456 MHz / (16*Divisor) */ + divisor = 14745600 / (16 * speed); + + local_irq_save(flags); + + if (IS_FIR(si)) { + /* stop RX DMA */ + DCSR(si->rxdma) &= ~DCSR_RUN; + /* disable FICP */ + ICCR0 = 0; + pxa_set_cken(CKEN13_FICP, 0); + + /* set board transceiver to SIR mode */ + si->pdata->transceiver_mode(si->dev, IR_SIRMODE); + + /* configure GPIO46/47 */ + pxa_gpio_mode(GPIO46_STRXD_MD); + pxa_gpio_mode(GPIO47_STTXD_MD); + + /* enable the STUART clock */ + pxa_set_cken(CKEN5_STUART, 1); + } + + /* disable STUART first */ + STIER = 0; + + /* access DLL & DLH */ + STLCR |= LCR_DLAB; + STDLL = divisor & 0xff; + STDLH = divisor >> 8; + STLCR &= ~LCR_DLAB; + + si->speed = speed; + STISR = IrSR_IR_RECEIVE_ON | IrSR_XMODE_PULSE_1_6; + STIER = IER_UUE | IER_RLSE | IER_RAVIE | IER_RTIOE; + + local_irq_restore(flags); + break; + + case 4000000: + local_irq_save(flags); + + /* disable STUART */ + STIER = 0; + STISR = 0; + pxa_set_cken(CKEN5_STUART, 0); + + /* disable FICP first */ + ICCR0 = 0; + + /* set board transceiver to FIR mode */ + si->pdata->transceiver_mode(si->dev, IR_FIRMODE); + + /* configure GPIO46/47 */ + pxa_gpio_mode(GPIO46_ICPRXD_MD); + pxa_gpio_mode(GPIO47_ICPTXD_MD); + + /* enable the FICP clock */ + pxa_set_cken(CKEN13_FICP, 1); + + si->speed = speed; + pxa_irda_fir_dma_rx_start(si); + ICCR0 = ICCR0_ITR | ICCR0_RXE; + + local_irq_restore(flags); + break; + + default: + return -EINVAL; + } + + return 0; +} + +/* SIR interrupt service routine. */ +static irqreturn_t pxa_irda_sir_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = dev_id; + struct pxa_irda *si = netdev_priv(dev); + int iir, lsr, data; + + iir = STIIR; + + switch (iir & 0x0F) { + case 0x06: /* Receiver Line Status */ + lsr = STLSR; + while (lsr & LSR_FIFOE) { + data = STRBR; + if (lsr & (LSR_OE | LSR_PE | LSR_FE | LSR_BI)) { + printk(KERN_DEBUG "pxa_ir: sir receiving error\n"); + si->stats.rx_errors++; + if (lsr & LSR_FE) + si->stats.rx_frame_errors++; + if (lsr & LSR_OE) + si->stats.rx_fifo_errors++; + } else { + si->stats.rx_bytes++; + async_unwrap_char(dev, &si->stats, &si->rx_buff, data); + } + lsr = STLSR; + } + dev->last_rx = jiffies; + si->last_oscr = OSCR; + break; + + case 0x04: /* Received Data Available */ + /* forth through */ + + case 0x0C: /* Character Timeout Indication */ + do { + si->stats.rx_bytes++; + async_unwrap_char(dev, &si->stats, &si->rx_buff, STRBR); + } while (STLSR & LSR_DR); + dev->last_rx = jiffies; + si->last_oscr = OSCR; + break; + + case 0x02: /* Transmit FIFO Data Request */ + while ((si->tx_buff.len) && (STLSR & LSR_TDRQ)) { + STTHR = *si->tx_buff.data++; + si->tx_buff.len -= 1; + } + + if (si->tx_buff.len == 0) { + si->stats.tx_packets++; + si->stats.tx_bytes += si->tx_buff.data - + si->tx_buff.head; + + /* We need to ensure that the transmitter has finished. */ + while ((STLSR & LSR_TEMT) == 0) + cpu_relax(); + si->last_oscr = OSCR; + + /* + * Ok, we've finished transmitting. Now enable + * the receiver. Sometimes we get a receive IRQ + * immediately after a transmit... + */ + if (si->newspeed) { + pxa_irda_set_speed(si, si->newspeed); + si->newspeed = 0; + } else { + /* enable IR Receiver, disable IR Transmitter */ + STISR = IrSR_IR_RECEIVE_ON | IrSR_XMODE_PULSE_1_6; + /* enable STUART and receive interrupts */ + STIER = IER_UUE | IER_RLSE | IER_RAVIE | IER_RTIOE; + } + /* I'm hungry! */ + netif_wake_queue(dev); + } + break; + } + + return IRQ_HANDLED; +} + +/* FIR Receive DMA interrupt handler */ +static void pxa_irda_fir_dma_rx_irq(int channel, void *data, struct pt_regs *regs) +{ + int dcsr = DCSR(channel); + + DCSR(channel) = dcsr & ~DCSR_RUN; + + printk(KERN_DEBUG "pxa_ir: fir rx dma bus error %#x\n", dcsr); +} + +/* FIR Transmit DMA interrupt handler */ +static void pxa_irda_fir_dma_tx_irq(int channel, void *data, struct pt_regs *regs) +{ + struct net_device *dev = data; + struct pxa_irda *si = netdev_priv(dev); + int dcsr; + + dcsr = DCSR(channel); + DCSR(channel) = dcsr & ~DCSR_RUN; + + if (dcsr & DCSR_ENDINTR) { + si->stats.tx_packets++; + si->stats.tx_bytes += si->dma_tx_buff_len; + } else { + si->stats.tx_errors++; + } + + while (ICSR1 & ICSR1_TBY) + cpu_relax(); + si->last_oscr = OSCR; + + /* + * HACK: It looks like the TBY bit is dropped too soon. + * Without this delay things break. + */ + udelay(120); + + if (si->newspeed) { + pxa_irda_set_speed(si, si->newspeed); + si->newspeed = 0; + } else { + ICCR0 = 0; + pxa_irda_fir_dma_rx_start(si); + ICCR0 = ICCR0_ITR | ICCR0_RXE; + } + netif_wake_queue(dev); +} + +/* EIF(Error in FIFO/End in Frame) handler for FIR */ +static void pxa_irda_fir_irq_eif(struct pxa_irda *si, struct net_device *dev) +{ + unsigned int len, stat, data; + + /* Get the current data position. */ + len = DTADR(si->rxdma) - si->dma_rx_buff_phy; + + do { + /* Read Status, and then Data. */ + stat = ICSR1; + rmb(); + data = ICDR; + + if (stat & (ICSR1_CRE | ICSR1_ROR)) { + si->stats.rx_errors++; + if (stat & ICSR1_CRE) { + printk(KERN_DEBUG "pxa_ir: fir receive CRC error\n"); + si->stats.rx_crc_errors++; + } + if (stat & ICSR1_ROR) { + printk(KERN_DEBUG "pxa_ir: fir receive overrun\n"); + si->stats.rx_frame_errors++; + } + } else { + si->dma_rx_buff[len++] = data; + } + /* If we hit the end of frame, there's no point in continuing. */ + if (stat & ICSR1_EOF) + break; + } while (ICSR0 & ICSR0_EIF); + + if (stat & ICSR1_EOF) { + /* end of frame. */ + struct sk_buff *skb = alloc_skb(len+1,GFP_ATOMIC); + if (!skb) { + printk(KERN_ERR "pxa_ir: fir out of memory for receive skb\n"); + si->stats.rx_dropped++; + return; + } + + /* Align IP header to 20 bytes */ + skb_reserve(skb, 1); + memcpy(skb->data, si->dma_rx_buff, len); + skb_put(skb, len); + + /* Feed it to IrLAP */ + skb->dev = dev; + skb->mac.raw = skb->data; + skb->protocol = htons(ETH_P_IRDA); + netif_rx(skb); + + si->stats.rx_packets++; + si->stats.rx_bytes += len; + + dev->last_rx = jiffies; + } +} + +/* FIR interrupt handler */ +static irqreturn_t pxa_irda_fir_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = dev_id; + struct pxa_irda *si = netdev_priv(dev); + int icsr0; + + /* stop RX DMA */ + DCSR(si->rxdma) &= ~DCSR_RUN; + si->last_oscr = OSCR; + icsr0 = ICSR0; + + if (icsr0 & (ICSR0_FRE | ICSR0_RAB)) { + if (icsr0 & ICSR0_FRE) { + printk(KERN_DEBUG "pxa_ir: fir receive frame error\n"); + si->stats.rx_frame_errors++; + } else { + printk(KERN_DEBUG "pxa_ir: fir receive abort\n"); + si->stats.rx_errors++; + } + ICSR0 = icsr0 & (ICSR0_FRE | ICSR0_RAB); + } + + if (icsr0 & ICSR0_EIF) { + /* An error in FIFO occured, or there is a end of frame */ + pxa_irda_fir_irq_eif(si, dev); + } + + ICCR0 = 0; + pxa_irda_fir_dma_rx_start(si); + ICCR0 = ICCR0_ITR | ICCR0_RXE; + + return IRQ_HANDLED; +} + +/* hard_xmit interface of irda device */ +static int pxa_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct pxa_irda *si = netdev_priv(dev); + int speed = irda_get_next_speed(skb); + + /* + * Does this packet contain a request to change the interface + * speed? If so, remember it until we complete the transmission + * of this frame. + */ + if (speed != si->speed && speed != -1) + si->newspeed = speed; + + /* + * If this is an empty frame, we can bypass a lot. + */ + if (skb->len == 0) { + if (si->newspeed) { + si->newspeed = 0; + pxa_irda_set_speed(si, speed); + } + dev_kfree_skb(skb); + return 0; + } + + netif_stop_queue(dev); + + if (!IS_FIR(si)) { + si->tx_buff.data = si->tx_buff.head; + si->tx_buff.len = async_wrap_skb(skb, si->tx_buff.data, si->tx_buff.truesize); + + /* Disable STUART interrupts and switch to transmit mode. */ + STIER = 0; + STISR = IrSR_IR_TRANSMIT_ON | IrSR_XMODE_PULSE_1_6; + + /* enable STUART and transmit interrupts */ + STIER = IER_UUE | IER_TIE; + } else { + unsigned long mtt = irda_get_mtt(skb); + + si->dma_tx_buff_len = skb->len; + memcpy(si->dma_tx_buff, skb->data, skb->len); + + if (mtt) + while ((unsigned)(OSCR - si->last_oscr)/4 < mtt) + cpu_relax(); + + /* stop RX DMA, disable FICP */ + DCSR(si->rxdma) &= ~DCSR_RUN; + ICCR0 = 0; + + pxa_irda_fir_dma_tx_start(si); + ICCR0 = ICCR0_ITR | ICCR0_TXE; + } + + dev_kfree_skb(skb); + dev->trans_start = jiffies; + return 0; +} + +static int pxa_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd) +{ + struct if_irda_req *rq = (struct if_irda_req *)ifreq; + struct pxa_irda *si = netdev_priv(dev); + int ret; + + switch (cmd) { + case SIOCSBANDWIDTH: + ret = -EPERM; + if (capable(CAP_NET_ADMIN)) { + /* + * We are unable to set the speed if the + * device is not running. + */ + if (netif_running(dev)) { + ret = pxa_irda_set_speed(si, + rq->ifr_baudrate); + } else { + printk(KERN_INFO "pxa_ir: SIOCSBANDWIDTH: !netif_running\n"); + ret = 0; + } + } + break; + + case SIOCSMEDIABUSY: + ret = -EPERM; + if (capable(CAP_NET_ADMIN)) { + irda_device_set_media_busy(dev, TRUE); + ret = 0; + } + break; + + case SIOCGRECEIVING: + ret = 0; + rq->ifr_receiving = IS_FIR(si) ? 0 + : si->rx_buff.state != OUTSIDE_FRAME; + break; + + default: + ret = -EOPNOTSUPP; + break; + } + + return ret; +} + +static struct net_device_stats *pxa_irda_stats(struct net_device *dev) +{ + struct pxa_irda *si = netdev_priv(dev); + return &si->stats; +} + +static void pxa_irda_startup(struct pxa_irda *si) +{ + /* Disable STUART interrupts */ + STIER = 0; + /* enable STUART interrupt to the processor */ + STMCR = MCR_OUT2; + /* configure SIR frame format: StartBit - Data 7 ... Data 0 - Stop Bit */ + STLCR = LCR_WLS0 | LCR_WLS1; + /* enable FIFO, we use FIFO to improve performance */ + STFCR = FCR_TRFIFOE | FCR_ITL_32; + + /* disable FICP */ + ICCR0 = 0; + /* configure FICP ICCR2 */ + ICCR2 = ICCR2_TXP | ICCR2_TRIG_32; + + /* configure DMAC */ + DRCMR17 = si->rxdma | DRCMR_MAPVLD; + DRCMR18 = si->txdma | DRCMR_MAPVLD; + + /* force SIR reinitialization */ + si->speed = 4000000; + pxa_irda_set_speed(si, 9600); + + printk(KERN_DEBUG "pxa_ir: irda startup\n"); +} + +static void pxa_irda_shutdown(struct pxa_irda *si) +{ + unsigned long flags; + + local_irq_save(flags); + + /* disable STUART and interrupt */ + STIER = 0; + /* disable STUART SIR mode */ + STISR = 0; + /* disable the STUART clock */ + pxa_set_cken(CKEN5_STUART, 0); + + /* disable DMA */ + DCSR(si->txdma) &= ~DCSR_RUN; + DCSR(si->rxdma) &= ~DCSR_RUN; + /* disable FICP */ + ICCR0 = 0; + /* disable the FICP clock */ + pxa_set_cken(CKEN13_FICP, 0); + + DRCMR17 = 0; + DRCMR18 = 0; + + local_irq_restore(flags); + + /* power off board transceiver */ + si->pdata->transceiver_mode(si->dev, IR_OFF); + + printk(KERN_DEBUG "pxa_ir: irda shutdown\n"); +} + +static int pxa_irda_start(struct net_device *dev) +{ + struct pxa_irda *si = netdev_priv(dev); + int err; + + si->speed = 9600; + + err = request_irq(IRQ_STUART, pxa_irda_sir_irq, 0, dev->name, dev); + if (err) + goto err_irq1; + + err = request_irq(IRQ_ICP, pxa_irda_fir_irq, 0, dev->name, dev); + if (err) + goto err_irq2; + + /* + * The interrupt must remain disabled for now. + */ + disable_irq(IRQ_STUART); + disable_irq(IRQ_ICP); + + err = -EBUSY; + si->rxdma = pxa_request_dma("FICP_RX",DMA_PRIO_LOW, pxa_irda_fir_dma_rx_irq, dev); + if (si->rxdma < 0) + goto err_rx_dma; + + si->txdma = pxa_request_dma("FICP_TX",DMA_PRIO_LOW, pxa_irda_fir_dma_tx_irq, dev); + if (si->txdma < 0) + goto err_tx_dma; + + err = -ENOMEM; + si->dma_rx_buff = dma_alloc_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT, + &si->dma_rx_buff_phy, GFP_KERNEL ); + if (!si->dma_rx_buff) + goto err_dma_rx_buff; + + si->dma_tx_buff = dma_alloc_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT, + &si->dma_tx_buff_phy, GFP_KERNEL ); + if (!si->dma_tx_buff) + goto err_dma_tx_buff; + + /* Setup the serial port for the initial speed. */ + pxa_irda_startup(si); + + /* + * Open a new IrLAP layer instance. + */ + si->irlap = irlap_open(dev, &si->qos, "pxa"); + err = -ENOMEM; + if (!si->irlap) + goto err_irlap; + + /* + * Now enable the interrupt and start the queue + */ + enable_irq(IRQ_STUART); + enable_irq(IRQ_ICP); + netif_start_queue(dev); + + printk(KERN_DEBUG "pxa_ir: irda driver opened\n"); + + return 0; + +err_irlap: + pxa_irda_shutdown(si); + dma_free_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT, si->dma_tx_buff, si->dma_tx_buff_phy); +err_dma_tx_buff: + dma_free_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT, si->dma_rx_buff, si->dma_rx_buff_phy); +err_dma_rx_buff: + pxa_free_dma(si->txdma); +err_tx_dma: + pxa_free_dma(si->rxdma); +err_rx_dma: + free_irq(IRQ_ICP, dev); +err_irq2: + free_irq(IRQ_STUART, dev); +err_irq1: + + return err; +} + +static int pxa_irda_stop(struct net_device *dev) +{ + struct pxa_irda *si = netdev_priv(dev); + + netif_stop_queue(dev); + + pxa_irda_shutdown(si); + + /* Stop IrLAP */ + if (si->irlap) { + irlap_close(si->irlap); + si->irlap = NULL; + } + + free_irq(IRQ_STUART, dev); + free_irq(IRQ_ICP, dev); + + pxa_free_dma(si->rxdma); + pxa_free_dma(si->txdma); + + if (si->dma_rx_buff) + dma_free_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT, si->dma_tx_buff, si->dma_tx_buff_phy); + if (si->dma_tx_buff) + dma_free_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT, si->dma_rx_buff, si->dma_rx_buff_phy); + + printk(KERN_DEBUG "pxa_ir: irda driver closed\n"); + return 0; +} + +static int pxa_irda_suspend(struct device *_dev, pm_message_t state) +{ + struct net_device *dev = dev_get_drvdata(_dev); + struct pxa_irda *si; + + if (dev && netif_running(dev)) { + si = netdev_priv(dev); + netif_device_detach(dev); + pxa_irda_shutdown(si); + } + + return 0; +} + +static int pxa_irda_resume(struct device *_dev) +{ + struct net_device *dev = dev_get_drvdata(_dev); + struct pxa_irda *si; + + if (dev && netif_running(dev)) { + si = netdev_priv(dev); + pxa_irda_startup(si); + netif_device_attach(dev); + netif_wake_queue(dev); + } + + return 0; +} + + +static int pxa_irda_init_iobuf(iobuff_t *io, int size) +{ + io->head = kmalloc(size, GFP_KERNEL | GFP_DMA); + if (io->head != NULL) { + io->truesize = size; + io->in_frame = FALSE; + io->state = OUTSIDE_FRAME; + io->data = io->head; + } + return io->head ? 0 : -ENOMEM; +} + +static int pxa_irda_probe(struct device *_dev) +{ + struct platform_device *pdev = to_platform_device(_dev); + struct net_device *dev; + struct pxa_irda *si; + unsigned int baudrate_mask; + int err; + + if (!pdev->dev.platform_data) + return -ENODEV; + + err = request_mem_region(__PREG(STUART), 0x24, "IrDA") ? 0 : -EBUSY; + if (err) + goto err_mem_1; + + err = request_mem_region(__PREG(FICP), 0x1c, "IrDA") ? 0 : -EBUSY; + if (err) + goto err_mem_2; + + dev = alloc_irdadev(sizeof(struct pxa_irda)); + if (!dev) + goto err_mem_3; + + si = netdev_priv(dev); + si->dev = &pdev->dev; + si->pdata = pdev->dev.platform_data; + + /* + * Initialise the SIR buffers + */ + err = pxa_irda_init_iobuf(&si->rx_buff, 14384); + if (err) + goto err_mem_4; + err = pxa_irda_init_iobuf(&si->tx_buff, 4000); + if (err) + goto err_mem_5; + + dev->hard_start_xmit = pxa_irda_hard_xmit; + dev->open = pxa_irda_start; + dev->stop = pxa_irda_stop; + dev->do_ioctl = pxa_irda_ioctl; + dev->get_stats = pxa_irda_stats; + + irda_init_max_qos_capabilies(&si->qos); + + baudrate_mask = 0; + if (si->pdata->transceiver_cap & IR_SIRMODE) + baudrate_mask |= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200; + if (si->pdata->transceiver_cap & IR_FIRMODE) + baudrate_mask |= IR_4000000 << 8; + + si->qos.baud_rate.bits &= baudrate_mask; + si->qos.min_turn_time.bits = 7; /* 1ms or more */ + + irda_qos_bits_to_value(&si->qos); + + err = register_netdev(dev); + + if (err == 0) + dev_set_drvdata(&pdev->dev, dev); + + if (err) { + kfree(si->tx_buff.head); +err_mem_5: + kfree(si->rx_buff.head); +err_mem_4: + free_netdev(dev); +err_mem_3: + release_mem_region(__PREG(FICP), 0x1c); +err_mem_2: + release_mem_region(__PREG(STUART), 0x24); + } +err_mem_1: + return err; +} + +static int pxa_irda_remove(struct device *_dev) +{ + struct net_device *dev = dev_get_drvdata(_dev); + + if (dev) { + struct pxa_irda *si = netdev_priv(dev); + unregister_netdev(dev); + kfree(si->tx_buff.head); + kfree(si->rx_buff.head); + free_netdev(dev); + } + + release_mem_region(__PREG(STUART), 0x24); + release_mem_region(__PREG(FICP), 0x1c); + + return 0; +} + +static struct device_driver pxa_ir_driver = { + .name = "pxa2xx-ir", + .bus = &platform_bus_type, + .probe = pxa_irda_probe, + .remove = pxa_irda_remove, + .suspend = pxa_irda_suspend, + .resume = pxa_irda_resume, +}; + +static int __init pxa_irda_init(void) +{ + return driver_register(&pxa_ir_driver); +} + +static void __exit pxa_irda_exit(void) +{ + driver_unregister(&pxa_ir_driver); +} + +module_init(pxa_irda_init); +module_exit(pxa_irda_exit); + +MODULE_LICENSE("GPL"); diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c index 8d34ac60d906..06883309916d 100644 --- a/drivers/net/irda/sa1100_ir.c +++ b/drivers/net/irda/sa1100_ir.c @@ -291,12 +291,12 @@ static void sa1100_irda_shutdown(struct sa1100_irda *si) /* * Suspend the IrDA interface. */ -static int sa1100_irda_suspend(struct device *_dev, pm_message_t state, u32 level) +static int sa1100_irda_suspend(struct device *_dev, pm_message_t state) { struct net_device *dev = dev_get_drvdata(_dev); struct sa1100_irda *si; - if (!dev || level != SUSPEND_DISABLE) + if (!dev) return 0; si = dev->priv; @@ -316,12 +316,12 @@ static int sa1100_irda_suspend(struct device *_dev, pm_message_t state, u32 leve /* * Resume the IrDA interface. */ -static int sa1100_irda_resume(struct device *_dev, u32 level) +static int sa1100_irda_resume(struct device *_dev) { struct net_device *dev = dev_get_drvdata(_dev); struct sa1100_irda *si; - if (!dev || level != RESUME_ENABLE) + if (!dev) return 0; si = dev->priv; diff --git a/drivers/net/irda/sir_dev.c b/drivers/net/irda/sir_dev.c index efc5a8870565..df22b8b532e7 100644 --- a/drivers/net/irda/sir_dev.c +++ b/drivers/net/irda/sir_dev.c @@ -490,8 +490,7 @@ static void sirdev_free_buffers(struct sir_dev *dev) { if (dev->rx_buff.skb) kfree_skb(dev->rx_buff.skb); - if (dev->tx_buff.head) - kfree(dev->tx_buff.head); + kfree(dev->tx_buff.head); dev->rx_buff.head = dev->tx_buff.head = NULL; dev->rx_buff.skb = NULL; } diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c index dd89bda1f131..140b7cdb1f7e 100644 --- a/drivers/net/irda/smsc-ircc2.c +++ b/drivers/net/irda/smsc-ircc2.c @@ -213,8 +213,8 @@ static int smsc_ircc_probe_transceiver_smsc_ircc_atc(int fir_base); /* Power Management */ -static int smsc_ircc_suspend(struct device *dev, pm_message_t state, u32 level); -static int smsc_ircc_resume(struct device *dev, u32 level); +static int smsc_ircc_suspend(struct device *dev, pm_message_t state); +static int smsc_ircc_resume(struct device *dev); static struct device_driver smsc_ircc_driver = { .name = SMSC_IRCC2_DRIVER_NAME, @@ -638,21 +638,14 @@ static void smsc_ircc_setup_qos(struct smsc_ircc_cb *self) */ static void smsc_ircc_init_chip(struct smsc_ircc_cb *self) { - int iobase, ir_mode, ctrl, fast; - - IRDA_ASSERT(self != NULL, return;); - - iobase = self->io.fir_base; - ir_mode = IRCC_CFGA_IRDA_SIR_A; - ctrl = 0; - fast = 0; + int iobase = self->io.fir_base; register_bank(iobase, 0); outb(IRCC_MASTER_RESET, iobase + IRCC_MASTER); outb(0x00, iobase + IRCC_MASTER); register_bank(iobase, 1); - outb(((inb(iobase + IRCC_SCE_CFGA) & 0x87) | ir_mode), + outb(((inb(iobase + IRCC_SCE_CFGA) & 0x87) | IRCC_CFGA_IRDA_SIR_A), iobase + IRCC_SCE_CFGA); #ifdef smsc_669 /* Uses pin 88/89 for Rx/Tx */ @@ -666,10 +659,10 @@ static void smsc_ircc_init_chip(struct smsc_ircc_cb *self) outb(SMSC_IRCC2_FIFO_THRESHOLD, iobase + IRCC_FIFO_THRESHOLD); register_bank(iobase, 4); - outb((inb(iobase + IRCC_CONTROL) & 0x30) | ctrl, iobase + IRCC_CONTROL); + outb((inb(iobase + IRCC_CONTROL) & 0x30), iobase + IRCC_CONTROL); register_bank(iobase, 0); - outb(fast, iobase + IRCC_LCR_A); + outb(0, iobase + IRCC_LCR_A); smsc_ircc_set_sir_speed(self, SMSC_IRCC2_C_IRDA_FALLBACK_SPEED); @@ -1556,6 +1549,46 @@ static int ircc_is_receiving(struct smsc_ircc_cb *self) } #endif /* unused */ +static int smsc_ircc_request_irq(struct smsc_ircc_cb *self) +{ + int error; + + error = request_irq(self->io.irq, smsc_ircc_interrupt, 0, + self->netdev->name, self->netdev); + if (error) + IRDA_DEBUG(0, "%s(), unable to allocate irq=%d, err=%d\n", + __FUNCTION__, self->io.irq, error); + + return error; +} + +static void smsc_ircc_start_interrupts(struct smsc_ircc_cb *self) +{ + unsigned long flags; + + spin_lock_irqsave(&self->lock, flags); + + self->io.speed = 0; + smsc_ircc_change_speed(self, SMSC_IRCC2_C_IRDA_FALLBACK_SPEED); + + spin_unlock_irqrestore(&self->lock, flags); +} + +static void smsc_ircc_stop_interrupts(struct smsc_ircc_cb *self) +{ + int iobase = self->io.fir_base; + unsigned long flags; + + spin_lock_irqsave(&self->lock, flags); + + register_bank(iobase, 0); + outb(0, iobase + IRCC_IER); + outb(IRCC_MASTER_RESET, iobase + IRCC_MASTER); + outb(0x00, iobase + IRCC_MASTER); + + spin_unlock_irqrestore(&self->lock, flags); +} + /* * Function smsc_ircc_net_open (dev) @@ -1567,7 +1600,6 @@ static int smsc_ircc_net_open(struct net_device *dev) { struct smsc_ircc_cb *self; char hwname[16]; - unsigned long flags; IRDA_DEBUG(1, "%s\n", __FUNCTION__); @@ -1575,6 +1607,11 @@ static int smsc_ircc_net_open(struct net_device *dev) self = netdev_priv(dev); IRDA_ASSERT(self != NULL, return 0;); + if (self->io.suspended) { + IRDA_DEBUG(0, "%s(), device is suspended\n", __FUNCTION__); + return -EAGAIN; + } + if (request_irq(self->io.irq, smsc_ircc_interrupt, 0, dev->name, (void *) dev)) { IRDA_DEBUG(0, "%s(), unable to allocate irq=%d\n", @@ -1582,11 +1619,7 @@ static int smsc_ircc_net_open(struct net_device *dev) return -EAGAIN; } - spin_lock_irqsave(&self->lock, flags); - /*smsc_ircc_sir_start(self);*/ - self->io.speed = 0; - smsc_ircc_change_speed(self, SMSC_IRCC2_C_IRDA_FALLBACK_SPEED); - spin_unlock_irqrestore(&self->lock, flags); + smsc_ircc_start_interrupts(self); /* Give self a hardware name */ /* It would be cool to offer the chip revision here - Jean II */ @@ -1639,37 +1672,63 @@ static int smsc_ircc_net_close(struct net_device *dev) irlap_close(self->irlap); self->irlap = NULL; - free_irq(self->io.irq, dev); + smsc_ircc_stop_interrupts(self); + + /* if we are called from smsc_ircc_resume we don't have IRQ reserved */ + if (!self->io.suspended) + free_irq(self->io.irq, dev); + disable_dma(self->io.dma); free_dma(self->io.dma); return 0; } -static int smsc_ircc_suspend(struct device *dev, pm_message_t state, u32 level) +static int smsc_ircc_suspend(struct device *dev, pm_message_t state) { struct smsc_ircc_cb *self = dev_get_drvdata(dev); - IRDA_MESSAGE("%s, Suspending\n", driver_name); + if (!self->io.suspended) { + IRDA_DEBUG(1, "%s, Suspending\n", driver_name); - if (level == SUSPEND_DISABLE && !self->io.suspended) { - smsc_ircc_net_close(self->netdev); + rtnl_lock(); + if (netif_running(self->netdev)) { + netif_device_detach(self->netdev); + smsc_ircc_stop_interrupts(self); + free_irq(self->io.irq, self->netdev); + disable_dma(self->io.dma); + } self->io.suspended = 1; + rtnl_unlock(); } return 0; } -static int smsc_ircc_resume(struct device *dev, u32 level) +static int smsc_ircc_resume(struct device *dev) { struct smsc_ircc_cb *self = dev_get_drvdata(dev); - if (level == RESUME_ENABLE && self->io.suspended) { - - smsc_ircc_net_open(self->netdev); + if (self->io.suspended) { + IRDA_DEBUG(1, "%s, Waking up\n", driver_name); + + rtnl_lock(); + smsc_ircc_init_chip(self); + if (netif_running(self->netdev)) { + if (smsc_ircc_request_irq(self)) { + /* + * Don't fail resume process, just kill this + * network interface + */ + unregister_netdevice(self->netdev); + } else { + enable_dma(self->io.dma); + smsc_ircc_start_interrupts(self); + netif_device_attach(self->netdev); + } + } self->io.suspended = 0; - - IRDA_MESSAGE("%s, Waking up\n", driver_name); + rtnl_unlock(); } return 0; } @@ -1682,9 +1741,6 @@ static int smsc_ircc_resume(struct device *dev, u32 level) */ static int __exit smsc_ircc_close(struct smsc_ircc_cb *self) { - int iobase; - unsigned long flags; - IRDA_DEBUG(1, "%s\n", __FUNCTION__); IRDA_ASSERT(self != NULL, return -1;); @@ -1694,22 +1750,7 @@ static int __exit smsc_ircc_close(struct smsc_ircc_cb *self) /* Remove netdevice */ unregister_netdev(self->netdev); - /* Make sure the irq handler is not exectuting */ - spin_lock_irqsave(&self->lock, flags); - - /* Stop interrupts */ - iobase = self->io.fir_base; - register_bank(iobase, 0); - outb(0, iobase + IRCC_IER); - outb(IRCC_MASTER_RESET, iobase + IRCC_MASTER); - outb(0x00, iobase + IRCC_MASTER); -#if 0 - /* Reset to SIR mode */ - register_bank(iobase, 1); - outb(IRCC_CFGA_IRDA_SIR_A|IRCC_CFGA_TX_POLARITY, iobase + IRCC_SCE_CFGA); - outb(IRCC_CFGB_IR, iobase + IRCC_SCE_CFGB); -#endif - spin_unlock_irqrestore(&self->lock, flags); + smsc_ircc_stop_interrupts(self); /* Release the PORTS that this driver is using */ IRDA_DEBUG(0, "%s(), releasing 0x%03x\n", __FUNCTION__, diff --git a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c index 15f207323d97..3961a754e920 100644 --- a/drivers/net/irda/stir4200.c +++ b/drivers/net/irda/stir4200.c @@ -678,10 +678,9 @@ static void turnaround_delay(const struct stir_cb *stir, long us) return; ticks = us / (1000000 / HZ); - if (ticks > 0) { - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(1 + ticks); - } else + if (ticks > 0) + schedule_timeout_interruptible(1 + ticks); + else udelay(us); } diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c index 651c5a6578fd..a9f49f058cfb 100644 --- a/drivers/net/irda/vlsi_ir.c +++ b/drivers/net/irda/vlsi_ir.c @@ -473,8 +473,7 @@ static int vlsi_free_ring(struct vlsi_ring *r) rd_set_addr_status(rd, 0, 0); if (busaddr) pci_unmap_single(r->pdev, busaddr, r->len, r->dir); - if (rd->buf) - kfree(rd->buf); + kfree(rd->buf); } kfree(r); return 0; diff --git a/drivers/net/ixgb/ixgb_ethtool.c b/drivers/net/ixgb/ixgb_ethtool.c index 9d026ed77ddd..04e47189d830 100644 --- a/drivers/net/ixgb/ixgb_ethtool.c +++ b/drivers/net/ixgb/ixgb_ethtool.c @@ -645,11 +645,10 @@ ixgb_phys_id(struct net_device *netdev, uint32_t data) mod_timer(&adapter->blink_timer, jiffies); - set_current_state(TASK_INTERRUPTIBLE); - if(data) - schedule_timeout(data * HZ); + if (data) + schedule_timeout_interruptible(data * HZ); else - schedule_timeout(MAX_SCHEDULE_TIMEOUT); + schedule_timeout_interruptible(MAX_SCHEDULE_TIMEOUT); del_timer_sync(&adapter->blink_timer); ixgb_led_off(&adapter->hw); @@ -723,6 +722,7 @@ struct ethtool_ops ixgb_ethtool_ops = { .phys_id = ixgb_phys_id, .get_stats_count = ixgb_get_stats_count, .get_ethtool_stats = ixgb_get_ethtool_stats, + .get_perm_addr = ethtool_op_get_perm_addr, }; void ixgb_set_ethtool_ops(struct net_device *netdev) diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index 89d6d69be382..176680cb153e 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -460,8 +460,9 @@ ixgb_probe(struct pci_dev *pdev, } ixgb_get_ee_mac_addr(&adapter->hw, netdev->dev_addr); + memcpy(netdev->perm_addr, netdev->dev_addr, netdev->addr_len); - if(!is_valid_ether_addr(netdev->dev_addr)) { + if(!is_valid_ether_addr(netdev->perm_addr)) { err = -EIO; goto err_eeprom; } diff --git a/drivers/net/lance.c b/drivers/net/lance.c index b4929beb33b2..1d75ca0bb939 100644 --- a/drivers/net/lance.c +++ b/drivers/net/lance.c @@ -298,7 +298,7 @@ enum {OLD_LANCE = 0, PCNET_ISA=1, PCNET_ISAP=2, PCNET_PCI=3, PCNET_VLB=4, PCNET_ static unsigned char lance_need_isa_bounce_buffers = 1; static int lance_open(struct net_device *dev); -static void lance_init_ring(struct net_device *dev, int mode); +static void lance_init_ring(struct net_device *dev, gfp_t mode); static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev); static int lance_rx(struct net_device *dev); static irqreturn_t lance_interrupt(int irq, void *dev_id, struct pt_regs *regs); @@ -846,7 +846,7 @@ lance_purge_ring(struct net_device *dev) /* Initialize the LANCE Rx and Tx rings. */ static void -lance_init_ring(struct net_device *dev, int gfp) +lance_init_ring(struct net_device *dev, gfp_t gfp) { struct lance_private *lp = dev->priv; int i; diff --git a/drivers/net/lasi_82596.c b/drivers/net/lasi_82596.c index 41bad07ac1ac..f7b7238d8352 100644 --- a/drivers/net/lasi_82596.c +++ b/drivers/net/lasi_82596.c @@ -415,6 +415,10 @@ static int rx_ring_size = RX_RING_SIZE; static int ticks_limit = 100; static int max_cmd_backlog = TX_RING_SIZE-1; +#ifdef CONFIG_NET_POLL_CONTROLLER +static void i596_poll_controller(struct net_device *dev); +#endif + static inline void CA(struct net_device *dev) { @@ -636,11 +640,11 @@ static int init_i596_mem(struct net_device *dev) disable_irq(dev->irq); /* disable IRQs from LAN */ DEB(DEB_INIT, - printk("RESET 82596 port: %p (with IRQ %d disabled)\n", - (void*)(dev->base_addr + PA_I82596_RESET), + printk("RESET 82596 port: %lx (with IRQ %d disabled)\n", + (dev->base_addr + PA_I82596_RESET), dev->irq)); - gsc_writel(0, (void*)(dev->base_addr + PA_I82596_RESET)); /* Hard Reset */ + gsc_writel(0, (dev->base_addr + PA_I82596_RESET)); /* Hard Reset */ udelay(100); /* Wait 100us - seems to help */ /* change the scp address */ @@ -1209,6 +1213,9 @@ static int __devinit i82596_probe(struct net_device *dev, dev->set_multicast_list = set_multicast_list; dev->tx_timeout = i596_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = i596_poll_controller; +#endif dev->priv = (void *)(dev->mem_start); @@ -1242,6 +1249,14 @@ static int __devinit i82596_probe(struct net_device *dev, return 0; } +#ifdef CONFIG_NET_POLL_CONTROLLER +static void i596_poll_controller(struct net_device *dev) +{ + disable_irq(dev->irq); + i596_interrupt(dev->irq, dev, NULL); + enable_irq(dev->irq); +} +#endif static irqreturn_t i596_interrupt(int irq, void *dev_id, struct pt_regs *regs) { @@ -1528,17 +1543,18 @@ lan_init_chip(struct parisc_device *dev) if (!dev->irq) { printk(KERN_ERR "%s: IRQ not found for i82596 at 0x%lx\n", - __FILE__, dev->hpa); + __FILE__, dev->hpa.start); return -ENODEV; } - printk(KERN_INFO "Found i82596 at 0x%lx, IRQ %d\n", dev->hpa, dev->irq); + printk(KERN_INFO "Found i82596 at 0x%lx, IRQ %d\n", dev->hpa.start, + dev->irq); netdevice = alloc_etherdev(0); if (!netdevice) return -ENOMEM; - netdevice->base_addr = dev->hpa; + netdevice->base_addr = dev->hpa.start; netdevice->irq = dev->irq; retval = i82596_probe(netdevice, &dev->dev); @@ -1566,7 +1582,7 @@ static struct parisc_device_id lan_tbl[] = { MODULE_DEVICE_TABLE(parisc, lan_tbl); static struct parisc_driver lan_driver = { - .name = "Apricot", + .name = "lasi_82596", .id_table = lan_tbl, .probe = lan_init_chip, }; diff --git a/drivers/net/lne390.c b/drivers/net/lne390.c index 27f0d8ac4c40..309d254842cf 100644 --- a/drivers/net/lne390.c +++ b/drivers/net/lne390.c @@ -298,7 +298,7 @@ static int __init lne390_probe1(struct net_device *dev, int ioaddr) return 0; unmap: if (ei_status.reg0) - iounmap((void *)dev->mem_start); + iounmap(ei_status.mem); cleanup: free_irq(dev->irq, dev); return ret; diff --git a/drivers/net/mace.c b/drivers/net/mace.c index f2fc1f26cd4b..2a5add257b8f 100644 --- a/drivers/net/mace.c +++ b/drivers/net/mace.c @@ -1036,10 +1036,8 @@ static void __exit mace_cleanup(void) { macio_unregister_driver(&mace_driver); - if (dummy_buf) { - kfree(dummy_buf); - dummy_buf = NULL; - } + kfree(dummy_buf); + dummy_buf = NULL; } MODULE_AUTHOR("Paul Mackerras"); diff --git a/drivers/net/mii.c b/drivers/net/mii.c index c33cb3dc942b..e42aa797f08b 100644 --- a/drivers/net/mii.c +++ b/drivers/net/mii.c @@ -207,6 +207,20 @@ int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) return 0; } +int mii_check_gmii_support(struct mii_if_info *mii) +{ + int reg; + + reg = mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR); + if (reg & BMSR_ESTATEN) { + reg = mii->mdio_read(mii->dev, mii->phy_id, MII_ESTATUS); + if (reg & (ESTATUS_1000_TFULL | ESTATUS_1000_THALF)) + return 1; + } + + return 0; +} + int mii_link_ok (struct mii_if_info *mii) { /* first, a dummy read, needed to latch some MII phys */ @@ -394,5 +408,6 @@ EXPORT_SYMBOL(mii_ethtool_gset); EXPORT_SYMBOL(mii_ethtool_sset); EXPORT_SYMBOL(mii_check_link); EXPORT_SYMBOL(mii_check_media); +EXPORT_SYMBOL(mii_check_gmii_support); EXPORT_SYMBOL(generic_mii_ioctl); diff --git a/drivers/net/mipsnet.c b/drivers/net/mipsnet.c new file mode 100644 index 000000000000..f79f7ee72ab8 --- /dev/null +++ b/drivers/net/mipsnet.c @@ -0,0 +1,371 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#define DEBUG + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/netdevice.h> +#include <linux/sched.h> +#include <linux/etherdevice.h> +#include <linux/netdevice.h> +#include <asm/io.h> +#include <asm/mips-boards/simint.h> + +#include "mipsnet.h" /* actual device IO mapping */ + +#define MIPSNET_VERSION "2005-06-20" + +#define mipsnet_reg_address(dev, field) (dev->base_addr + field_offset(field)) + +struct mipsnet_priv { + struct net_device_stats stats; +}; + +static struct platform_device *mips_plat_dev; + +static char mipsnet_string[] = "mipsnet"; + +/* + * Copy data from the MIPSNET rx data port + */ +static int ioiocpy_frommipsnet(struct net_device *dev, unsigned char *kdata, + int len) +{ + uint32_t available_len = inl(mipsnet_reg_address(dev, rxDataCount)); + if (available_len < len) + return -EFAULT; + + for (; len > 0; len--, kdata++) { + *kdata = inb(mipsnet_reg_address(dev, rxDataBuffer)); + } + + return inl(mipsnet_reg_address(dev, rxDataCount)); +} + +static inline ssize_t mipsnet_put_todevice(struct net_device *dev, + struct sk_buff *skb) +{ + int count_to_go = skb->len; + char *buf_ptr = skb->data; + struct mipsnet_priv *mp = netdev_priv(dev); + + pr_debug("%s: %s(): telling MIPSNET txDataCount(%d)\n", + dev->name, __FUNCTION__, skb->len); + + outl(skb->len, mipsnet_reg_address(dev, txDataCount)); + + pr_debug("%s: %s(): sending data to MIPSNET txDataBuffer(%d)\n", + dev->name, __FUNCTION__, skb->len); + + for (; count_to_go; buf_ptr++, count_to_go--) { + outb(*buf_ptr, mipsnet_reg_address(dev, txDataBuffer)); + } + + mp->stats.tx_packets++; + mp->stats.tx_bytes += skb->len; + + return skb->len; +} + +static int mipsnet_xmit(struct sk_buff *skb, struct net_device *dev) +{ + pr_debug("%s:%s(): transmitting %d bytes\n", + dev->name, __FUNCTION__, skb->len); + + /* Only one packet at a time. Once TXDONE interrupt is serviced, the + * queue will be restarted. + */ + netif_stop_queue(dev); + mipsnet_put_todevice(dev, skb); + + return 0; +} + +static inline ssize_t mipsnet_get_fromdev(struct net_device *dev, size_t count) +{ + struct sk_buff *skb; + size_t len = count; + struct mipsnet_priv *mp = netdev_priv(dev); + + if (!(skb = alloc_skb(len + 2, GFP_KERNEL))) { + mp->stats.rx_dropped++; + return -ENOMEM; + } + + skb_reserve(skb, 2); + if (ioiocpy_frommipsnet(dev, skb_put(skb, len), len)) + return -EFAULT; + + skb->dev = dev; + skb->protocol = eth_type_trans(skb, dev); + skb->ip_summed = CHECKSUM_UNNECESSARY; + + pr_debug("%s:%s(): pushing RXed data to kernel\n", + dev->name, __FUNCTION__); + netif_rx(skb); + + mp->stats.rx_packets++; + mp->stats.rx_bytes += len; + + return count; +} + +static irqreturn_t +mipsnet_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = dev_id; + + irqreturn_t retval = IRQ_NONE; + uint64_t interruptFlags; + + if (irq == dev->irq) { + pr_debug("%s:%s(): irq %d for device\n", + dev->name, __FUNCTION__, irq); + + retval = IRQ_HANDLED; + + interruptFlags = + inl(mipsnet_reg_address(dev, interruptControl)); + pr_debug("%s:%s(): intCtl=0x%016llx\n", dev->name, + __FUNCTION__, interruptFlags); + + if (interruptFlags & MIPSNET_INTCTL_TXDONE) { + pr_debug("%s:%s(): got TXDone\n", + dev->name, __FUNCTION__); + outl(MIPSNET_INTCTL_TXDONE, + mipsnet_reg_address(dev, interruptControl)); + // only one packet at a time, we are done. + netif_wake_queue(dev); + } else if (interruptFlags & MIPSNET_INTCTL_RXDONE) { + pr_debug("%s:%s(): got RX data\n", + dev->name, __FUNCTION__); + mipsnet_get_fromdev(dev, + inl(mipsnet_reg_address(dev, rxDataCount))); + pr_debug("%s:%s(): clearing RX int\n", + dev->name, __FUNCTION__); + outl(MIPSNET_INTCTL_RXDONE, + mipsnet_reg_address(dev, interruptControl)); + + } else if (interruptFlags & MIPSNET_INTCTL_TESTBIT) { + pr_debug("%s:%s(): got test interrupt\n", + dev->name, __FUNCTION__); + // TESTBIT is cleared on read. + // And takes effect after a write with 0 + outl(0, mipsnet_reg_address(dev, interruptControl)); + } else { + pr_debug("%s:%s(): no valid fags 0x%016llx\n", + dev->name, __FUNCTION__, interruptFlags); + // Maybe shared IRQ, just ignore, no clearing. + retval = IRQ_NONE; + } + + } else { + printk(KERN_INFO "%s: %s(): irq %d for unknown device\n", + dev->name, __FUNCTION__, irq); + retval = IRQ_NONE; + } + return retval; +} //mipsnet_interrupt() + +static int mipsnet_open(struct net_device *dev) +{ + int err; + pr_debug("%s: mipsnet_open\n", dev->name); + + err = request_irq(dev->irq, &mipsnet_interrupt, + SA_SHIRQ, dev->name, (void *) dev); + + if (err) { + pr_debug("%s: %s(): can't get irq %d\n", + dev->name, __FUNCTION__, dev->irq); + release_region(dev->base_addr, MIPSNET_IO_EXTENT); + return err; + } + + pr_debug("%s: %s(): got IO region at 0x%04lx and irq %d for dev.\n", + dev->name, __FUNCTION__, dev->base_addr, dev->irq); + + + netif_start_queue(dev); + + // test interrupt handler + outl(MIPSNET_INTCTL_TESTBIT, + mipsnet_reg_address(dev, interruptControl)); + + + return 0; +} + +static int mipsnet_close(struct net_device *dev) +{ + pr_debug("%s: %s()\n", dev->name, __FUNCTION__); + netif_stop_queue(dev); + return 0; +} + +static struct net_device_stats *mipsnet_get_stats(struct net_device *dev) +{ + struct mipsnet_priv *mp = netdev_priv(dev); + + return &mp->stats; +} + +static void mipsnet_set_mclist(struct net_device *dev) +{ + // we don't do anything + return; +} + +static int __init mipsnet_probe(struct device *dev) +{ + struct net_device *netdev; + int err; + + netdev = alloc_etherdev(sizeof(struct mipsnet_priv)); + if (!netdev) { + err = -ENOMEM; + goto out; + } + + dev_set_drvdata(dev, netdev); + + netdev->open = mipsnet_open; + netdev->stop = mipsnet_close; + netdev->hard_start_xmit = mipsnet_xmit; + netdev->get_stats = mipsnet_get_stats; + netdev->set_multicast_list = mipsnet_set_mclist; + + /* + * TODO: probe for these or load them from PARAM + */ + netdev->base_addr = 0x4200; + netdev->irq = MIPSCPU_INT_BASE + MIPSCPU_INT_MB0 + + inl(mipsnet_reg_address(netdev, interruptInfo)); + + // Get the io region now, get irq on open() + if (!request_region(netdev->base_addr, MIPSNET_IO_EXTENT, "mipsnet")) { + pr_debug("%s: %s(): IO region {start: 0x%04lux, len: %d} " + "for dev is not availble.\n", netdev->name, + __FUNCTION__, netdev->base_addr, MIPSNET_IO_EXTENT); + err = -EBUSY; + goto out_free_netdev; + } + + /* + * Lacking any better mechanism to allocate a MAC address we use a + * random one ... + */ + random_ether_addr(netdev->dev_addr); + + err = register_netdev(netdev); + if (err) { + printk(KERN_ERR "MIPSNet: failed to register netdev.\n"); + goto out_free_region; + } + + return 0; + +out_free_region: + release_region(netdev->base_addr, MIPSNET_IO_EXTENT); + +out_free_netdev: + free_netdev(netdev); + +out: + return err; +} + +static int __devexit mipsnet_device_remove(struct device *device) +{ + struct net_device *dev = dev_get_drvdata(device); + + unregister_netdev(dev); + release_region(dev->base_addr, MIPSNET_IO_EXTENT); + free_netdev(dev); + dev_set_drvdata(device, NULL); + + return 0; +} + +static struct device_driver mipsnet_driver = { + .name = mipsnet_string, + .bus = &platform_bus_type, + .probe = mipsnet_probe, + .remove = __devexit_p(mipsnet_device_remove), +}; + +static void mipsnet_platform_release(struct device *device) +{ + struct platform_device *pldev; + + /* free device */ + pldev = to_platform_device(device); + kfree(pldev); +} + +static int __init mipsnet_init_module(void) +{ + struct platform_device *pldev; + int err; + + printk(KERN_INFO "MIPSNet Ethernet driver. Version: %s. " + "(c)2005 MIPS Technologies, Inc.\n", MIPSNET_VERSION); + + if (driver_register(&mipsnet_driver)) { + printk(KERN_ERR "Driver registration failed\n"); + err = -ENODEV; + goto out; + } + + if (!(pldev = kmalloc (sizeof (*pldev), GFP_KERNEL))) { + err = -ENOMEM; + goto out_unregister_driver; + } + + memset (pldev, 0, sizeof (*pldev)); + pldev->name = mipsnet_string; + pldev->id = 0; + pldev->dev.release = mipsnet_platform_release; + + if (platform_device_register(pldev)) { + err = -ENODEV; + goto out_free_pldev; + } + + if (!pldev->dev.driver) { + /* + * The driver was not bound to this device, there was + * no hardware at this address. Unregister it, as the + * release fuction will take care of freeing the + * allocated structure + */ + platform_device_unregister (pldev); + } + + mips_plat_dev = pldev; + + return 0; + +out_free_pldev: + kfree(pldev); + +out_unregister_driver: + driver_unregister(&mipsnet_driver); +out: + return err; +} + +static void __exit mipsnet_exit_module(void) +{ + pr_debug("MIPSNet Ethernet driver exiting\n"); + + driver_unregister(&mipsnet_driver); +} + +module_init(mipsnet_init_module); +module_exit(mipsnet_exit_module); diff --git a/drivers/net/mipsnet.h b/drivers/net/mipsnet.h new file mode 100644 index 000000000000..878535953cb1 --- /dev/null +++ b/drivers/net/mipsnet.h @@ -0,0 +1,127 @@ +// +// <COPYRIGHT CLASS="1B" YEAR="2005"> +// Unpublished work (c) MIPS Technologies, Inc. All rights reserved. +// Unpublished rights reserved under the copyright laws of the U.S.A. and +// other countries. +// +// PROPRIETARY / SECRET CONFIDENTIAL INFORMATION OF MIPS TECHNOLOGIES, INC. +// FOR INTERNAL USE ONLY. +// +// Under no circumstances (contract or otherwise) may this information be +// disclosed to, or copied, modified or used by anyone other than employees +// or contractors of MIPS Technologies having a need to know. +// </COPYRIGHT> +// +//++ +// File: MIPS_Net.h +// +// Description: +// The definition of the emulated MIPSNET device's interface. +// +// Notes: This include file needs to work from a Linux device drivers. +// +//-- +// + +#ifndef __MIPSNET_H +#define __MIPSNET_H + +/* + * Id of this Net device, as seen by the core. + */ +#define MIPS_NET_DEV_ID ((uint64_t) \ + ((uint64_t)'M'<< 0)| \ + ((uint64_t)'I'<< 8)| \ + ((uint64_t)'P'<<16)| \ + ((uint64_t)'S'<<24)| \ + ((uint64_t)'N'<<32)| \ + ((uint64_t)'E'<<40)| \ + ((uint64_t)'T'<<48)| \ + ((uint64_t)'0'<<56)) + +/* + * Net status/control block as seen by sw in the core. + * (Why not use bit fields? can't be bothered with cross-platform struct + * packing.) + */ +typedef struct _net_control_block { + /// dev info for probing + /// reads as MIPSNET%d where %d is some form of version + uint64_t devId; /*0x00 */ + + /* + * read only busy flag. + * Set and cleared by the Net Device to indicate that an rx or a tx + * is in progress. + */ + uint32_t busy; /*0x08 */ + + /* + * Set by the Net Device. + * The device will set it once data has been received. + * The value is the number of bytes that should be read from + * rxDataBuffer. The value will decrease till 0 until all the data + * from rxDataBuffer has been read. + */ + uint32_t rxDataCount; /*0x0c */ +#define MIPSNET_MAX_RXTX_DATACOUNT (1<<16) + + /* + * Settable from the MIPS core, cleared by the Net Device. + * The core should set the number of bytes it wants to send, + * then it should write those bytes of data to txDataBuffer. + * The device will clear txDataCount has been processed (not necessarily sent). + */ + uint32_t txDataCount; /*0x10 */ + + /* + * Interrupt control + * + * Used to clear the interrupted generated by this dev. + * Write a 1 to clear the interrupt. (except bit31). + * + * Bit0 is set if it was a tx-done interrupt. + * Bit1 is set when new rx-data is available. + * Until this bit is cleared there will be no other RXs. + * + * Bit31 is used for testing, it clears after a read. + * Writing 1 to this bit will cause an interrupt to be generated. + * To clear the test interrupt, write 0 to this register. + */ + uint32_t interruptControl; /*0x14 */ +#define MIPSNET_INTCTL_TXDONE ((uint32_t)(1<< 0)) +#define MIPSNET_INTCTL_RXDONE ((uint32_t)(1<< 1)) +#define MIPSNET_INTCTL_TESTBIT ((uint32_t)(1<<31)) +#define MIPSNET_INTCTL_ALLSOURCES (MIPSNET_INTCTL_TXDONE|MIPSNET_INTCTL_RXDONE|MIPSNET_INTCTL_TESTBIT) + + /* + * Readonly core-specific interrupt info for the device to signal the core. + * The meaning of the contents of this field might change. + */ + /*###\todo: the whole memIntf interrupt scheme is messy: the device should have + * no control what so ever of what VPE/register set is being used. + * The MemIntf should only expose interrupt lines, and something in the + * config should be responsible for the line<->core/vpe bindings. + */ + uint32_t interruptInfo; /*0x18 */ + + /* + * This is where the received data is read out. + * There is more data to read until rxDataReady is 0. + * Only 1 byte at this regs offset is used. + */ + uint32_t rxDataBuffer; /*0x1c */ + + /* + * This is where the data to transmit is written. + * Data should be written for the amount specified in the txDataCount register. + * Only 1 byte at this regs offset is used. + */ + uint32_t txDataBuffer; /*0x20 */ +} MIPS_T_NetControl; + +#define MIPSNET_IO_EXTENT 0x40 /* being generous */ + +#define field_offset(field) ((int)&((MIPS_T_NetControl*)(0))->field) + +#endif /* __MIPSNET_H */ diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c index f0996ce5c268..6c86dca62e2a 100644 --- a/drivers/net/myri_sbus.c +++ b/drivers/net/myri_sbus.c @@ -277,7 +277,7 @@ static void myri_init_rings(struct myri_eth *mp, int from_irq) struct recvq __iomem *rq = mp->rq; struct myri_rxd __iomem *rxd = &rq->myri_rxd[0]; struct net_device *dev = mp->dev; - int gfp_flags = GFP_KERNEL; + gfp_t gfp_flags = GFP_KERNEL; int i; if (from_irq || in_interrupt()) diff --git a/drivers/net/myri_sbus.h b/drivers/net/myri_sbus.h index 9391e55a5e92..47722f708a41 100644 --- a/drivers/net/myri_sbus.h +++ b/drivers/net/myri_sbus.h @@ -296,7 +296,7 @@ struct myri_eth { /* We use this to acquire receive skb's that we can DMA directly into. */ #define ALIGNED_RX_SKB_ADDR(addr) \ ((((unsigned long)(addr) + (64 - 1)) & ~(64 - 1)) - (unsigned long)(addr)) -static inline struct sk_buff *myri_alloc_skb(unsigned int length, int gfp_flags) +static inline struct sk_buff *myri_alloc_skb(unsigned int length, gfp_t gfp_flags) { struct sk_buff *skb; diff --git a/drivers/net/ne.c b/drivers/net/ne.c index d209a1556b2e..0de8fdd2aa86 100644 --- a/drivers/net/ne.c +++ b/drivers/net/ne.c @@ -54,6 +54,10 @@ static const char version2[] = #include <asm/system.h> #include <asm/io.h> +#if defined(CONFIG_TOSHIBA_RBTX4927) || defined(CONFIG_TOSHIBA_RBTX4938) +#include <asm/tx4938/rbtx4938.h> +#endif + #include "8390.h" #define DRV_NAME "ne" @@ -111,6 +115,9 @@ bad_clone_list[] __initdata = { {"E-LAN100", "E-LAN200", {0x00, 0x00, 0x5d}}, /* Broken ne1000 clones */ {"PCM-4823", "PCM-4823", {0x00, 0xc0, 0x6c}}, /* Broken Advantech MoBo */ {"REALTEK", "RTL8019", {0x00, 0x00, 0xe8}}, /* no-name with Realtek chip */ +#if defined(CONFIG_TOSHIBA_RBTX4927) || defined(CONFIG_TOSHIBA_RBTX4938) + {"RBHMA4X00-RTL8019", "RBHMA4X00/RTL8019", {0x00, 0x60, 0x0a}}, /* Toshiba built-in */ +#endif {"LCS-8834", "LCS-8836", {0x04, 0x04, 0x37}}, /* ShinyNet (SET) */ {NULL,} }; @@ -226,6 +233,10 @@ struct net_device * __init ne_probe(int unit) sprintf(dev->name, "eth%d", unit); netdev_boot_setup_check(dev); +#ifdef CONFIG_TOSHIBA_RBTX4938 + dev->base_addr = 0x07f20280; + dev->irq = RBTX4938_RTL_8019_IRQ; +#endif err = do_ne_probe(dev); if (err) goto out; @@ -506,6 +517,10 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr) ei_status.name = name; ei_status.tx_start_page = start_page; ei_status.stop_page = stop_page; +#if defined(CONFIG_TOSHIBA_RBTX4927) || defined(CONFIG_TOSHIBA_RBTX4938) + wordlength = 1; +#endif + #ifdef CONFIG_PLAT_OAKS32R ei_status.word16 = 0; #else diff --git a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c index f1c01ac29102..d11821dd86ed 100644 --- a/drivers/net/ne2k-pci.c +++ b/drivers/net/ne2k-pci.c @@ -372,6 +372,7 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev, printk("%2.2X%s", SA_prom[i], i == 5 ? ".\n": ":"); dev->dev_addr[i] = SA_prom[i]; } + memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); return 0; @@ -637,6 +638,7 @@ static struct ethtool_ops ne2k_pci_ethtool_ops = { .get_drvinfo = ne2k_pci_get_drvinfo, .get_tx_csum = ethtool_op_get_tx_csum, .get_sg = ethtool_op_get_sg, + .get_perm_addr = ethtool_op_get_perm_addr, }; static void __devexit ne2k_pci_remove_one (struct pci_dev *pdev) @@ -673,7 +675,6 @@ static int ne2k_pci_resume (struct pci_dev *pdev) pci_set_power_state(pdev, 0); pci_restore_state(pdev); pci_enable_device(pdev); - pci_set_master(pdev); NS8390_init(dev, 1); netif_device_attach(dev); diff --git a/drivers/net/ni65.c b/drivers/net/ni65.c index 925d1dfcc4dc..bb42ff218484 100644 --- a/drivers/net/ni65.c +++ b/drivers/net/ni65.c @@ -696,8 +696,7 @@ static void ni65_free_buffer(struct priv *p) return; for(i=0;i<TMDNUM;i++) { - if(p->tmdbounce[i]) - kfree(p->tmdbounce[i]); + kfree(p->tmdbounce[i]); #ifdef XMT_VIA_SKB if(p->tmd_skb[i]) dev_kfree_skb(p->tmd_skb[i]); @@ -710,12 +709,10 @@ static void ni65_free_buffer(struct priv *p) if(p->recv_skb[i]) dev_kfree_skb(p->recv_skb[i]); #else - if(p->recvbounce[i]) - kfree(p->recvbounce[i]); + kfree(p->recvbounce[i]); #endif } - if(p->self) - kfree(p->self); + kfree(p->self); } diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c index e4811b42a6b7..a3c3fc9c0d8a 100644 --- a/drivers/net/ns83820.c +++ b/drivers/net/ns83820.c @@ -1632,8 +1632,7 @@ static void ns83820_run_bist(struct net_device *ndev, const char *name, u32 enab timed_out = 1; break; } - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_uninterruptible(1); } if (status & fail) diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c index 9f22d138e3ad..818c185d6438 100644 --- a/drivers/net/pcmcia/pcnet_cs.c +++ b/drivers/net/pcmcia/pcnet_cs.c @@ -1020,6 +1020,12 @@ static void set_misc_reg(struct net_device *dev) } else { outb(full_duplex ? 4 : 0, nic_base + DLINK_DIAG); } + } else if (info->flags & IS_DL10019) { + /* Advertise 100F, 100H, 10F, 10H */ + mdio_write(nic_base + DLINK_GPIO, info->eth_phy, 4, 0x01e1); + /* Restart MII autonegotiation */ + mdio_write(nic_base + DLINK_GPIO, info->eth_phy, 0, 0x0000); + mdio_write(nic_base + DLINK_GPIO, info->eth_phy, 0, 0x1200); } } diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index 113b68099216..70fe81a89df9 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -22,8 +22,8 @@ *************************************************************************/ #define DRV_NAME "pcnet32" -#define DRV_VERSION "1.30j" -#define DRV_RELDATE "29.04.2005" +#define DRV_VERSION "1.31a" +#define DRV_RELDATE "12.Sep.2005" #define PFX DRV_NAME ": " static const char *version = @@ -257,6 +257,9 @@ static int homepna[MAX_UNITS]; * v1.30h 24 Jun 2004 Don Fry correctly select auto, speed, duplex in bcr32. * v1.30i 28 Jun 2004 Don Fry change to use module_param. * v1.30j 29 Apr 2005 Don Fry fix skb/map leak with loopback test. + * v1.31 02 Sep 2005 Hubert WS Lin <wslin@tw.ibm.c0m> added set_ringparam(). + * v1.31a 12 Sep 2005 Hubert WS Lin <wslin@tw.ibm.c0m> set min ring size to 4 + * to allow loopback test to work unchanged. */ @@ -266,17 +269,17 @@ static int homepna[MAX_UNITS]; * That translates to 2 (4 == 2^^2) and 4 (16 == 2^^4). */ #ifndef PCNET32_LOG_TX_BUFFERS -#define PCNET32_LOG_TX_BUFFERS 4 -#define PCNET32_LOG_RX_BUFFERS 5 +#define PCNET32_LOG_TX_BUFFERS 4 +#define PCNET32_LOG_RX_BUFFERS 5 +#define PCNET32_LOG_MAX_TX_BUFFERS 9 /* 2^9 == 512 */ +#define PCNET32_LOG_MAX_RX_BUFFERS 9 #endif #define TX_RING_SIZE (1 << (PCNET32_LOG_TX_BUFFERS)) -#define TX_RING_MOD_MASK (TX_RING_SIZE - 1) -#define TX_RING_LEN_BITS ((PCNET32_LOG_TX_BUFFERS) << 12) +#define TX_MAX_RING_SIZE (1 << (PCNET32_LOG_MAX_TX_BUFFERS)) #define RX_RING_SIZE (1 << (PCNET32_LOG_RX_BUFFERS)) -#define RX_RING_MOD_MASK (RX_RING_SIZE - 1) -#define RX_RING_LEN_BITS ((PCNET32_LOG_RX_BUFFERS) << 4) +#define RX_MAX_RING_SIZE (1 << (PCNET32_LOG_MAX_RX_BUFFERS)) #define PKT_BUF_SZ 1544 @@ -334,14 +337,14 @@ struct pcnet32_access { }; /* - * The first three fields of pcnet32_private are read by the ethernet device - * so we allocate the structure should be allocated by pci_alloc_consistent(). + * The first field of pcnet32_private is read by the ethernet device + * so the structure should be allocated using pci_alloc_consistent(). */ struct pcnet32_private { - /* The Tx and Rx ring entries must be aligned on 16-byte boundaries in 32bit mode. */ - struct pcnet32_rx_head rx_ring[RX_RING_SIZE]; - struct pcnet32_tx_head tx_ring[TX_RING_SIZE]; struct pcnet32_init_block init_block; + /* The Tx and Rx ring entries must be aligned on 16-byte boundaries in 32bit mode. */ + struct pcnet32_rx_head *rx_ring; + struct pcnet32_tx_head *tx_ring; dma_addr_t dma_addr; /* DMA address of beginning of this object, returned by pci_alloc_consistent */ @@ -349,13 +352,21 @@ struct pcnet32_private { structure */ const char *name; /* The saved address of a sent-in-place packet/buffer, for skfree(). */ - struct sk_buff *tx_skbuff[TX_RING_SIZE]; - struct sk_buff *rx_skbuff[RX_RING_SIZE]; - dma_addr_t tx_dma_addr[TX_RING_SIZE]; - dma_addr_t rx_dma_addr[RX_RING_SIZE]; + struct sk_buff **tx_skbuff; + struct sk_buff **rx_skbuff; + dma_addr_t *tx_dma_addr; + dma_addr_t *rx_dma_addr; struct pcnet32_access a; spinlock_t lock; /* Guard lock */ unsigned int cur_rx, cur_tx; /* The next free ring entry */ + unsigned int rx_ring_size; /* current rx ring size */ + unsigned int tx_ring_size; /* current tx ring size */ + unsigned int rx_mod_mask; /* rx ring modular mask */ + unsigned int tx_mod_mask; /* tx ring modular mask */ + unsigned short rx_len_bits; + unsigned short tx_len_bits; + dma_addr_t rx_ring_dma_addr; + dma_addr_t tx_ring_dma_addr; unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */ struct net_device_stats stats; char tx_full; @@ -397,6 +408,9 @@ static int pcnet32_get_regs_len(struct net_device *dev); static void pcnet32_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *ptr); static void pcnet32_purge_tx_ring(struct net_device *dev); +static int pcnet32_alloc_ring(struct net_device *dev); +static void pcnet32_free_ring(struct net_device *dev); + enum pci_flags_bit { PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4, @@ -613,10 +627,62 @@ static void pcnet32_get_ringparam(struct net_device *dev, struct ethtool_ringpar { struct pcnet32_private *lp = dev->priv; - ering->tx_max_pending = TX_RING_SIZE - 1; - ering->tx_pending = lp->cur_tx - lp->dirty_tx; - ering->rx_max_pending = RX_RING_SIZE - 1; - ering->rx_pending = lp->cur_rx & RX_RING_MOD_MASK; + ering->tx_max_pending = TX_MAX_RING_SIZE - 1; + ering->tx_pending = lp->tx_ring_size - 1; + ering->rx_max_pending = RX_MAX_RING_SIZE - 1; + ering->rx_pending = lp->rx_ring_size - 1; +} + +static int pcnet32_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering) +{ + struct pcnet32_private *lp = dev->priv; + unsigned long flags; + int i; + + if (ering->rx_mini_pending || ering->rx_jumbo_pending) + return -EINVAL; + + if (netif_running(dev)) + pcnet32_close(dev); + + spin_lock_irqsave(&lp->lock, flags); + pcnet32_free_ring(dev); + lp->tx_ring_size = min(ering->tx_pending, (unsigned int) TX_MAX_RING_SIZE); + lp->rx_ring_size = min(ering->rx_pending, (unsigned int) RX_MAX_RING_SIZE); + + /* set the minimum ring size to 4, to allow the loopback test to work + * unchanged. + */ + for (i = 2; i <= PCNET32_LOG_MAX_TX_BUFFERS; i++) { + if (lp->tx_ring_size <= (1 << i)) + break; + } + lp->tx_ring_size = (1 << i); + lp->tx_mod_mask = lp->tx_ring_size - 1; + lp->tx_len_bits = (i << 12); + + for (i = 2; i <= PCNET32_LOG_MAX_RX_BUFFERS; i++) { + if (lp->rx_ring_size <= (1 << i)) + break; + } + lp->rx_ring_size = (1 << i); + lp->rx_mod_mask = lp->rx_ring_size - 1; + lp->rx_len_bits = (i << 4); + + if (pcnet32_alloc_ring(dev)) { + pcnet32_free_ring(dev); + return -ENOMEM; + } + + spin_unlock_irqrestore(&lp->lock, flags); + + if (pcnet32_debug & NETIF_MSG_DRV) + printk(KERN_INFO PFX "Ring Param Settings: RX: %d, TX: %d\n", lp->rx_ring_size, lp->tx_ring_size); + + if (netif_running(dev)) + pcnet32_open(dev); + + return 0; } static void pcnet32_get_strings(struct net_device *dev, u32 stringset, u8 *data) @@ -948,6 +1014,7 @@ static struct ethtool_ops pcnet32_ethtool_ops = { .nway_reset = pcnet32_nway_reset, .get_link = pcnet32_get_link, .get_ringparam = pcnet32_get_ringparam, + .set_ringparam = pcnet32_set_ringparam, .get_tx_csum = ethtool_op_get_tx_csum, .get_sg = ethtool_op_get_sg, .get_tso = ethtool_op_get_tso, @@ -957,6 +1024,7 @@ static struct ethtool_ops pcnet32_ethtool_ops = { .phys_id = pcnet32_phys_id, .get_regs_len = pcnet32_get_regs_len, .get_regs = pcnet32_get_regs, + .get_perm_addr = ethtool_op_get_perm_addr, }; /* only probes for non-PCI devices, the rest are handled by @@ -1185,9 +1253,10 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) memcpy(dev->dev_addr, promaddr, 6); } } + memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); /* if the ethernet address is not valid, force to 00:00:00:00:00:00 */ - if (!is_valid_ether_addr(dev->dev_addr)) + if (!is_valid_ether_addr(dev->perm_addr)) memset(dev->dev_addr, 0, sizeof(dev->dev_addr)); if (pcnet32_debug & NETIF_MSG_PROBE) { @@ -1239,6 +1308,12 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) dev->priv = lp; lp->name = chipname; lp->shared_irq = shared; + lp->tx_ring_size = TX_RING_SIZE; /* default tx ring size */ + lp->rx_ring_size = RX_RING_SIZE; /* default rx ring size */ + lp->tx_mod_mask = lp->tx_ring_size - 1; + lp->rx_mod_mask = lp->rx_ring_size - 1; + lp->tx_len_bits = (PCNET32_LOG_TX_BUFFERS << 12); + lp->rx_len_bits = (PCNET32_LOG_RX_BUFFERS << 4); lp->mii_if.full_duplex = fdx; lp->mii_if.phy_id_mask = 0x1f; lp->mii_if.reg_num_mask = 0x1f; @@ -1265,21 +1340,23 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) } lp->a = *a; + if (pcnet32_alloc_ring(dev)) { + ret = -ENOMEM; + goto err_free_ring; + } /* detect special T1/E1 WAN card by checking for MAC address */ if (dev->dev_addr[0] == 0x00 && dev->dev_addr[1] == 0xe0 && dev->dev_addr[2] == 0x75) lp->options = PCNET32_PORT_FD | PCNET32_PORT_GPSI; lp->init_block.mode = le16_to_cpu(0x0003); /* Disable Rx and Tx. */ - lp->init_block.tlen_rlen = le16_to_cpu(TX_RING_LEN_BITS | RX_RING_LEN_BITS); + lp->init_block.tlen_rlen = le16_to_cpu(lp->tx_len_bits | lp->rx_len_bits); for (i = 0; i < 6; i++) lp->init_block.phys_addr[i] = dev->dev_addr[i]; lp->init_block.filter[0] = 0x00000000; lp->init_block.filter[1] = 0x00000000; - lp->init_block.rx_ring = (u32)le32_to_cpu(lp->dma_addr + - offsetof(struct pcnet32_private, rx_ring)); - lp->init_block.tx_ring = (u32)le32_to_cpu(lp->dma_addr + - offsetof(struct pcnet32_private, tx_ring)); + lp->init_block.rx_ring = (u32)le32_to_cpu(lp->rx_ring_dma_addr); + lp->init_block.tx_ring = (u32)le32_to_cpu(lp->tx_ring_dma_addr); /* switch pcnet32 to 32bit mode */ a->write_bcr(ioaddr, 20, 2); @@ -1310,7 +1387,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) if (pcnet32_debug & NETIF_MSG_PROBE) printk(", failed to detect IRQ line.\n"); ret = -ENODEV; - goto err_free_consistent; + goto err_free_ring; } if (pcnet32_debug & NETIF_MSG_PROBE) printk(", probed IRQ %d.\n", dev->irq); @@ -1341,7 +1418,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) /* Fill in the generic fields of the device structure. */ if (register_netdev(dev)) - goto err_free_consistent; + goto err_free_ring; if (pdev) { pci_set_drvdata(pdev, dev); @@ -1359,6 +1436,8 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) return 0; +err_free_ring: + pcnet32_free_ring(dev); err_free_consistent: pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr); err_free_netdev: @@ -1369,6 +1448,86 @@ err_release_region: } +static int pcnet32_alloc_ring(struct net_device *dev) +{ + struct pcnet32_private *lp = dev->priv; + + if ((lp->tx_ring = pci_alloc_consistent(lp->pci_dev, sizeof(struct pcnet32_tx_head) * lp->tx_ring_size, + &lp->tx_ring_dma_addr)) == NULL) { + if (pcnet32_debug & NETIF_MSG_DRV) + printk(KERN_ERR PFX "Consistent memory allocation failed.\n"); + return -ENOMEM; + } + + if ((lp->rx_ring = pci_alloc_consistent(lp->pci_dev, sizeof(struct pcnet32_rx_head) * lp->rx_ring_size, + &lp->rx_ring_dma_addr)) == NULL) { + if (pcnet32_debug & NETIF_MSG_DRV) + printk(KERN_ERR PFX "Consistent memory allocation failed.\n"); + return -ENOMEM; + } + + if (!(lp->tx_dma_addr = kmalloc(sizeof(dma_addr_t) * lp->tx_ring_size, GFP_ATOMIC))) { + if (pcnet32_debug & NETIF_MSG_DRV) + printk(KERN_ERR PFX "Memory allocation failed.\n"); + return -ENOMEM; + } + memset(lp->tx_dma_addr, 0, sizeof(dma_addr_t) * lp->tx_ring_size); + + if (!(lp->rx_dma_addr = kmalloc(sizeof(dma_addr_t) * lp->rx_ring_size, GFP_ATOMIC))) { + if (pcnet32_debug & NETIF_MSG_DRV) + printk(KERN_ERR PFX "Memory allocation failed.\n"); + return -ENOMEM; + } + memset(lp->rx_dma_addr, 0, sizeof(dma_addr_t) * lp->rx_ring_size); + + if (!(lp->tx_skbuff = kmalloc(sizeof(struct sk_buff *) * lp->tx_ring_size, GFP_ATOMIC))) { + if (pcnet32_debug & NETIF_MSG_DRV) + printk(KERN_ERR PFX "Memory allocation failed.\n"); + return -ENOMEM; + } + memset(lp->tx_skbuff, 0, sizeof(struct sk_buff *) * lp->tx_ring_size); + + if (!(lp->rx_skbuff = kmalloc(sizeof(struct sk_buff *) * lp->rx_ring_size, GFP_ATOMIC))) { + if (pcnet32_debug & NETIF_MSG_DRV) + printk(KERN_ERR PFX "Memory allocation failed.\n"); + return -ENOMEM; + } + memset(lp->rx_skbuff, 0, sizeof(struct sk_buff *) * lp->rx_ring_size); + + return 0; +} + + +static void pcnet32_free_ring(struct net_device *dev) +{ + struct pcnet32_private *lp = dev->priv; + + kfree(lp->tx_skbuff); + lp->tx_skbuff = NULL; + + kfree(lp->rx_skbuff); + lp->rx_skbuff = NULL; + + kfree(lp->tx_dma_addr); + lp->tx_dma_addr = NULL; + + kfree(lp->rx_dma_addr); + lp->rx_dma_addr = NULL; + + if (lp->tx_ring) { + pci_free_consistent(lp->pci_dev, sizeof(struct pcnet32_tx_head) * lp->tx_ring_size, + lp->tx_ring, lp->tx_ring_dma_addr); + lp->tx_ring = NULL; + } + + if (lp->rx_ring) { + pci_free_consistent(lp->pci_dev, sizeof(struct pcnet32_rx_head) * lp->rx_ring_size, + lp->rx_ring, lp->rx_ring_dma_addr); + lp->rx_ring = NULL; + } +} + + static int pcnet32_open(struct net_device *dev) { @@ -1400,8 +1559,8 @@ pcnet32_open(struct net_device *dev) if (netif_msg_ifup(lp)) printk(KERN_DEBUG "%s: pcnet32_open() irq %d tx/rx rings %#x/%#x init %#x.\n", dev->name, dev->irq, - (u32) (lp->dma_addr + offsetof(struct pcnet32_private, tx_ring)), - (u32) (lp->dma_addr + offsetof(struct pcnet32_private, rx_ring)), + (u32) (lp->tx_ring_dma_addr), + (u32) (lp->rx_ring_dma_addr), (u32) (lp->dma_addr + offsetof(struct pcnet32_private, init_block))); /* set/reset autoselect bit */ @@ -1521,7 +1680,7 @@ pcnet32_open(struct net_device *dev) err_free_ring: /* free any allocated skbuffs */ - for (i = 0; i < RX_RING_SIZE; i++) { + for (i = 0; i < lp->rx_ring_size; i++) { lp->rx_ring[i].status = 0; if (lp->rx_skbuff[i]) { pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[i], PKT_BUF_SZ-2, @@ -1531,6 +1690,9 @@ err_free_ring: lp->rx_skbuff[i] = NULL; lp->rx_dma_addr[i] = 0; } + + pcnet32_free_ring(dev); + /* * Switch back to 16bit mode to avoid problems with dumb * DOS packet driver after a warm reboot @@ -1562,7 +1724,7 @@ pcnet32_purge_tx_ring(struct net_device *dev) struct pcnet32_private *lp = dev->priv; int i; - for (i = 0; i < TX_RING_SIZE; i++) { + for (i = 0; i < lp->tx_ring_size; i++) { lp->tx_ring[i].status = 0; /* CPU owns buffer */ wmb(); /* Make sure adapter sees owner change */ if (lp->tx_skbuff[i]) { @@ -1587,7 +1749,7 @@ pcnet32_init_ring(struct net_device *dev) lp->cur_rx = lp->cur_tx = 0; lp->dirty_rx = lp->dirty_tx = 0; - for (i = 0; i < RX_RING_SIZE; i++) { + for (i = 0; i < lp->rx_ring_size; i++) { struct sk_buff *rx_skbuff = lp->rx_skbuff[i]; if (rx_skbuff == NULL) { if (!(rx_skbuff = lp->rx_skbuff[i] = dev_alloc_skb (PKT_BUF_SZ))) { @@ -1611,20 +1773,18 @@ pcnet32_init_ring(struct net_device *dev) } /* The Tx buffer address is filled in as needed, but we do need to clear * the upper ownership bit. */ - for (i = 0; i < TX_RING_SIZE; i++) { + for (i = 0; i < lp->tx_ring_size; i++) { lp->tx_ring[i].status = 0; /* CPU owns buffer */ wmb(); /* Make sure adapter sees owner change */ lp->tx_ring[i].base = 0; lp->tx_dma_addr[i] = 0; } - lp->init_block.tlen_rlen = le16_to_cpu(TX_RING_LEN_BITS | RX_RING_LEN_BITS); + lp->init_block.tlen_rlen = le16_to_cpu(lp->tx_len_bits | lp->rx_len_bits); for (i = 0; i < 6; i++) lp->init_block.phys_addr[i] = dev->dev_addr[i]; - lp->init_block.rx_ring = (u32)le32_to_cpu(lp->dma_addr + - offsetof(struct pcnet32_private, rx_ring)); - lp->init_block.tx_ring = (u32)le32_to_cpu(lp->dma_addr + - offsetof(struct pcnet32_private, tx_ring)); + lp->init_block.rx_ring = (u32)le32_to_cpu(lp->rx_ring_dma_addr); + lp->init_block.tx_ring = (u32)le32_to_cpu(lp->tx_ring_dma_addr); wmb(); /* Make sure all changes are visible */ return 0; } @@ -1682,13 +1842,13 @@ pcnet32_tx_timeout (struct net_device *dev) printk(KERN_DEBUG " Ring data dump: dirty_tx %d cur_tx %d%s cur_rx %d.", lp->dirty_tx, lp->cur_tx, lp->tx_full ? " (full)" : "", lp->cur_rx); - for (i = 0 ; i < RX_RING_SIZE; i++) + for (i = 0 ; i < lp->rx_ring_size; i++) printk("%s %08x %04x %08x %04x", i & 1 ? "" : "\n ", le32_to_cpu(lp->rx_ring[i].base), (-le16_to_cpu(lp->rx_ring[i].buf_length)) & 0xffff, le32_to_cpu(lp->rx_ring[i].msg_length), le16_to_cpu(lp->rx_ring[i].status)); - for (i = 0 ; i < TX_RING_SIZE; i++) + for (i = 0 ; i < lp->tx_ring_size; i++) printk("%s %08x %04x %08x %04x", i & 1 ? "" : "\n ", le32_to_cpu(lp->tx_ring[i].base), (-le16_to_cpu(lp->tx_ring[i].length)) & 0xffff, @@ -1729,7 +1889,7 @@ pcnet32_start_xmit(struct sk_buff *skb, struct net_device *dev) /* Fill in a Tx ring entry */ /* Mask to ring buffer boundary. */ - entry = lp->cur_tx & TX_RING_MOD_MASK; + entry = lp->cur_tx & lp->tx_mod_mask; /* Caution: the write order is important here, set the status * with the "ownership" bits last. */ @@ -1753,7 +1913,7 @@ pcnet32_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; - if (lp->tx_ring[(entry+1) & TX_RING_MOD_MASK].base != 0) { + if (lp->tx_ring[(entry+1) & lp->tx_mod_mask].base != 0) { lp->tx_full = 1; netif_stop_queue(dev); } @@ -1806,7 +1966,7 @@ pcnet32_interrupt(int irq, void *dev_id, struct pt_regs * regs) int delta; while (dirty_tx != lp->cur_tx) { - int entry = dirty_tx & TX_RING_MOD_MASK; + int entry = dirty_tx & lp->tx_mod_mask; int status = (short)le16_to_cpu(lp->tx_ring[entry].status); if (status < 0) @@ -1864,18 +2024,18 @@ pcnet32_interrupt(int irq, void *dev_id, struct pt_regs * regs) dirty_tx++; } - delta = (lp->cur_tx - dirty_tx) & (TX_RING_MOD_MASK + TX_RING_SIZE); - if (delta > TX_RING_SIZE) { + delta = (lp->cur_tx - dirty_tx) & (lp->tx_mod_mask + lp->tx_ring_size); + if (delta > lp->tx_ring_size) { if (netif_msg_drv(lp)) printk(KERN_ERR "%s: out-of-sync dirty pointer, %d vs. %d, full=%d.\n", dev->name, dirty_tx, lp->cur_tx, lp->tx_full); - dirty_tx += TX_RING_SIZE; - delta -= TX_RING_SIZE; + dirty_tx += lp->tx_ring_size; + delta -= lp->tx_ring_size; } if (lp->tx_full && netif_queue_stopped(dev) && - delta < TX_RING_SIZE - 2) { + delta < lp->tx_ring_size - 2) { /* The ring is no longer full, clear tbusy. */ lp->tx_full = 0; netif_wake_queue (dev); @@ -1932,8 +2092,8 @@ static int pcnet32_rx(struct net_device *dev) { struct pcnet32_private *lp = dev->priv; - int entry = lp->cur_rx & RX_RING_MOD_MASK; - int boguscnt = RX_RING_SIZE / 2; + int entry = lp->cur_rx & lp->rx_mod_mask; + int boguscnt = lp->rx_ring_size / 2; /* If we own the next entry, it's a new packet. Send it up. */ while ((short)le16_to_cpu(lp->rx_ring[entry].status) >= 0) { @@ -1998,12 +2158,12 @@ pcnet32_rx(struct net_device *dev) if (netif_msg_drv(lp)) printk(KERN_ERR "%s: Memory squeeze, deferring packet.\n", dev->name); - for (i = 0; i < RX_RING_SIZE; i++) + for (i = 0; i < lp->rx_ring_size; i++) if ((short)le16_to_cpu(lp->rx_ring[(entry+i) - & RX_RING_MOD_MASK].status) < 0) + & lp->rx_mod_mask].status) < 0) break; - if (i > RX_RING_SIZE -2) { + if (i > lp->rx_ring_size -2) { lp->stats.rx_dropped++; lp->rx_ring[entry].status |= le16_to_cpu(0x8000); wmb(); /* Make sure adapter sees owner change */ @@ -2041,7 +2201,7 @@ pcnet32_rx(struct net_device *dev) lp->rx_ring[entry].buf_length = le16_to_cpu(2-PKT_BUF_SZ); wmb(); /* Make sure owner changes after all others are visible */ lp->rx_ring[entry].status |= le16_to_cpu(0x8000); - entry = (++lp->cur_rx) & RX_RING_MOD_MASK; + entry = (++lp->cur_rx) & lp->rx_mod_mask; if (--boguscnt <= 0) break; /* don't stay in loop forever */ } @@ -2084,7 +2244,7 @@ pcnet32_close(struct net_device *dev) spin_lock_irqsave(&lp->lock, flags); /* free all allocated skbuffs */ - for (i = 0; i < RX_RING_SIZE; i++) { + for (i = 0; i < lp->rx_ring_size; i++) { lp->rx_ring[i].status = 0; wmb(); /* Make sure adapter sees owner change */ if (lp->rx_skbuff[i]) { @@ -2096,7 +2256,7 @@ pcnet32_close(struct net_device *dev) lp->rx_dma_addr[i] = 0; } - for (i = 0; i < TX_RING_SIZE; i++) { + for (i = 0; i < lp->tx_ring_size; i++) { lp->tx_ring[i].status = 0; /* CPU owns buffer */ wmb(); /* Make sure adapter sees owner change */ if (lp->tx_skbuff[i]) { @@ -2265,6 +2425,7 @@ static void __devexit pcnet32_remove_one(struct pci_dev *pdev) struct pcnet32_private *lp = dev->priv; unregister_netdev(dev); + pcnet32_free_ring(dev); release_region(dev->base_addr, PCNET32_TOTAL_SIZE); pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr); free_netdev(dev); @@ -2340,6 +2501,7 @@ static void __exit pcnet32_cleanup_module(void) struct pcnet32_private *lp = pcnet32_dev->priv; next_dev = lp->next; unregister_netdev(pcnet32_dev); + pcnet32_free_ring(pcnet32_dev); release_region(pcnet32_dev->base_addr, PCNET32_TOTAL_SIZE); pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr); free_netdev(pcnet32_dev); diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 14f4de1a8180..c782a6329805 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -12,14 +12,6 @@ config PHYLIB devices. This option provides infrastructure for managing PHY devices. -config PHYCONTROL - bool " Support for automatically handling PHY state changes" - depends on PHYLIB - help - Adds code to perform all the work for keeping PHY link - state (speed/duplex/etc) up-to-date. Also handles - interrupts. - comment "MII PHY device drivers" depends on PHYLIB diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index 90630672703d..ad93b0da87f0 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -133,13 +133,9 @@ static int mdio_bus_suspend(struct device * dev, pm_message_t state) int ret = 0; struct device_driver *drv = dev->driver; - if (drv && drv->suspend) { - ret = drv->suspend(dev, state, SUSPEND_DISABLE); - if (ret == 0) - ret = drv->suspend(dev, state, SUSPEND_SAVE_STATE); - if (ret == 0) - ret = drv->suspend(dev, state, SUSPEND_POWER_DOWN); - } + if (drv && drv->suspend) + ret = drv->suspend(dev, state); + return ret; } @@ -148,13 +144,9 @@ static int mdio_bus_resume(struct device * dev) int ret = 0; struct device_driver *drv = dev->driver; - if (drv && drv->resume) { - ret = drv->resume(dev, RESUME_POWER_ON); - if (ret == 0) - ret = drv->resume(dev, RESUME_RESTORE_STATE); - if (ret == 0) - ret = drv->resume(dev, RESUME_ENABLE); - } + if (drv && drv->resume) + ret = drv->resume(dev); + return ret; } diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index d9e11f93bf3a..9209da9dde0d 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -242,10 +242,6 @@ EXPORT_SYMBOL(phy_sanitize_settings); * choose the next best ones from the ones selected, so we don't * care if ethtool tries to give us bad values * - * A note about the PHYCONTROL Layer. If you turn off - * CONFIG_PHYCONTROL, you will need to read the PHY status - * registers after this function completes, and update your - * controller manually. */ int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd) { @@ -380,7 +376,6 @@ int phy_start_aneg(struct phy_device *phydev) err = phydev->drv->config_aneg(phydev); -#ifdef CONFIG_PHYCONTROL if (err < 0) goto out_unlock; @@ -395,14 +390,12 @@ int phy_start_aneg(struct phy_device *phydev) } out_unlock: -#endif spin_unlock(&phydev->lock); return err; } EXPORT_SYMBOL(phy_start_aneg); -#ifdef CONFIG_PHYCONTROL static void phy_change(void *data); static void phy_timer(unsigned long data); @@ -868,4 +861,3 @@ static void phy_timer(unsigned long data) mod_timer(&phydev->phy_timer, jiffies + PHY_STATE_TIME * HZ); } -#endif /* CONFIG_PHYCONTROL */ diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 33f7bdb5857c..6da1aa0706a1 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -101,7 +101,6 @@ struct phy_device * get_phy_device(struct mii_bus *bus, int addr) return dev; } -#ifdef CONFIG_PHYCONTROL /* phy_prepare_link: * * description: Tells the PHY infrastructure to handle the @@ -160,8 +159,6 @@ void phy_disconnect(struct phy_device *phydev) } EXPORT_SYMBOL(phy_disconnect); -#endif /* CONFIG_PHYCONTROL */ - /* phy_attach: * * description: Called by drivers to attach to a particular PHY diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index 0df7e92b0bf8..d3c9958b00d0 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c @@ -863,7 +863,7 @@ static int __init ppp_init(void) err = PTR_ERR(ppp_class); goto out_chrdev; } - class_device_create(ppp_class, MKDEV(PPP_MAJOR, 0), NULL, "ppp"); + class_device_create(ppp_class, NULL, MKDEV(PPP_MAJOR, 0), NULL, "ppp"); err = devfs_mk_cdev(MKDEV(PPP_MAJOR, 0), S_IFCHR|S_IRUSR|S_IWUSR, "ppp"); if (err) diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index afb3f186b884..159b56a56ef4 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -1027,6 +1027,7 @@ static struct ethtool_ops rtl8169_ethtool_ops = { .get_strings = rtl8169_get_strings, .get_stats_count = rtl8169_get_stats_count, .get_ethtool_stats = rtl8169_get_ethtool_stats, + .get_perm_addr = ethtool_op_get_perm_addr, }; static void rtl8169_write_gmii_reg_bit(void __iomem *ioaddr, int reg, int bitnum, @@ -1511,6 +1512,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) /* Get MAC address. FIXME: read EEPROM */ for (i = 0; i < MAC_ADDR_LEN; i++) dev->dev_addr[i] = RTL_R8(MAC0 + i); + memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); dev->open = rtl8169_open; dev->hard_start_xmit = rtl8169_start_xmit; diff --git a/drivers/net/rionet.c b/drivers/net/rionet.c new file mode 100644 index 000000000000..12cde0604580 --- /dev/null +++ b/drivers/net/rionet.c @@ -0,0 +1,574 @@ +/* + * rionet - Ethernet driver over RapidIO messaging services + * + * Copyright 2005 MontaVista Software, Inc. + * Matt Porter <mporter@kernel.crashing.org> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/dma-mapping.h> +#include <linux/delay.h> +#include <linux/rio.h> +#include <linux/rio_drv.h> +#include <linux/rio_ids.h> + +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/crc32.h> +#include <linux/ethtool.h> + +#define DRV_NAME "rionet" +#define DRV_VERSION "0.2" +#define DRV_AUTHOR "Matt Porter <mporter@kernel.crashing.org>" +#define DRV_DESC "Ethernet over RapidIO" + +MODULE_AUTHOR(DRV_AUTHOR); +MODULE_DESCRIPTION(DRV_DESC); +MODULE_LICENSE("GPL"); + +#define RIONET_DEFAULT_MSGLEVEL \ + (NETIF_MSG_DRV | \ + NETIF_MSG_LINK | \ + NETIF_MSG_RX_ERR | \ + NETIF_MSG_TX_ERR) + +#define RIONET_DOORBELL_JOIN 0x1000 +#define RIONET_DOORBELL_LEAVE 0x1001 + +#define RIONET_MAILBOX 0 + +#define RIONET_TX_RING_SIZE CONFIG_RIONET_TX_SIZE +#define RIONET_RX_RING_SIZE CONFIG_RIONET_RX_SIZE + +static LIST_HEAD(rionet_peers); + +struct rionet_private { + struct rio_mport *mport; + struct sk_buff *rx_skb[RIONET_RX_RING_SIZE]; + struct sk_buff *tx_skb[RIONET_TX_RING_SIZE]; + struct net_device_stats stats; + int rx_slot; + int tx_slot; + int tx_cnt; + int ack_slot; + spinlock_t lock; + spinlock_t tx_lock; + u32 msg_enable; +}; + +struct rionet_peer { + struct list_head node; + struct rio_dev *rdev; + struct resource *res; +}; + +static int rionet_check = 0; +static int rionet_capable = 1; + +/* + * This is a fast lookup table for for translating TX + * Ethernet packets into a destination RIO device. It + * could be made into a hash table to save memory depending + * on system trade-offs. + */ +static struct rio_dev *rionet_active[RIO_MAX_ROUTE_ENTRIES]; + +#define is_rionet_capable(pef, src_ops, dst_ops) \ + ((pef & RIO_PEF_INB_MBOX) && \ + (pef & RIO_PEF_INB_DOORBELL) && \ + (src_ops & RIO_SRC_OPS_DOORBELL) && \ + (dst_ops & RIO_DST_OPS_DOORBELL)) +#define dev_rionet_capable(dev) \ + is_rionet_capable(dev->pef, dev->src_ops, dev->dst_ops) + +#define RIONET_MAC_MATCH(x) (*(u32 *)x == 0x00010001) +#define RIONET_GET_DESTID(x) (*(u16 *)(x + 4)) + +static struct net_device_stats *rionet_stats(struct net_device *ndev) +{ + struct rionet_private *rnet = ndev->priv; + return &rnet->stats; +} + +static int rionet_rx_clean(struct net_device *ndev) +{ + int i; + int error = 0; + struct rionet_private *rnet = ndev->priv; + void *data; + + i = rnet->rx_slot; + + do { + if (!rnet->rx_skb[i]) + continue; + + if (!(data = rio_get_inb_message(rnet->mport, RIONET_MAILBOX))) + break; + + rnet->rx_skb[i]->data = data; + skb_put(rnet->rx_skb[i], RIO_MAX_MSG_SIZE); + rnet->rx_skb[i]->dev = ndev; + rnet->rx_skb[i]->protocol = + eth_type_trans(rnet->rx_skb[i], ndev); + error = netif_rx(rnet->rx_skb[i]); + + if (error == NET_RX_DROP) { + rnet->stats.rx_dropped++; + } else if (error == NET_RX_BAD) { + if (netif_msg_rx_err(rnet)) + printk(KERN_WARNING "%s: bad rx packet\n", + DRV_NAME); + rnet->stats.rx_errors++; + } else { + rnet->stats.rx_packets++; + rnet->stats.rx_bytes += RIO_MAX_MSG_SIZE; + } + + } while ((i = (i + 1) % RIONET_RX_RING_SIZE) != rnet->rx_slot); + + return i; +} + +static void rionet_rx_fill(struct net_device *ndev, int end) +{ + int i; + struct rionet_private *rnet = ndev->priv; + + i = rnet->rx_slot; + do { + rnet->rx_skb[i] = dev_alloc_skb(RIO_MAX_MSG_SIZE); + + if (!rnet->rx_skb[i]) + break; + + rio_add_inb_buffer(rnet->mport, RIONET_MAILBOX, + rnet->rx_skb[i]->data); + } while ((i = (i + 1) % RIONET_RX_RING_SIZE) != end); + + rnet->rx_slot = i; +} + +static int rionet_queue_tx_msg(struct sk_buff *skb, struct net_device *ndev, + struct rio_dev *rdev) +{ + struct rionet_private *rnet = ndev->priv; + + rio_add_outb_message(rnet->mport, rdev, 0, skb->data, skb->len); + rnet->tx_skb[rnet->tx_slot] = skb; + + rnet->stats.tx_packets++; + rnet->stats.tx_bytes += skb->len; + + if (++rnet->tx_cnt == RIONET_TX_RING_SIZE) + netif_stop_queue(ndev); + + ++rnet->tx_slot; + rnet->tx_slot &= (RIONET_TX_RING_SIZE - 1); + + if (netif_msg_tx_queued(rnet)) + printk(KERN_INFO "%s: queued skb %8.8x len %8.8x\n", DRV_NAME, + (u32) skb, skb->len); + + return 0; +} + +static int rionet_start_xmit(struct sk_buff *skb, struct net_device *ndev) +{ + int i; + struct rionet_private *rnet = ndev->priv; + struct ethhdr *eth = (struct ethhdr *)skb->data; + u16 destid; + unsigned long flags; + + local_irq_save(flags); + if (!spin_trylock(&rnet->tx_lock)) { + local_irq_restore(flags); + return NETDEV_TX_LOCKED; + } + + if ((rnet->tx_cnt + 1) > RIONET_TX_RING_SIZE) { + netif_stop_queue(ndev); + spin_unlock_irqrestore(&rnet->tx_lock, flags); + printk(KERN_ERR "%s: BUG! Tx Ring full when queue awake!\n", + ndev->name); + return NETDEV_TX_BUSY; + } + + if (eth->h_dest[0] & 0x01) { + for (i = 0; i < RIO_MAX_ROUTE_ENTRIES; i++) + if (rionet_active[i]) + rionet_queue_tx_msg(skb, ndev, + rionet_active[i]); + } else if (RIONET_MAC_MATCH(eth->h_dest)) { + destid = RIONET_GET_DESTID(eth->h_dest); + if (rionet_active[destid]) + rionet_queue_tx_msg(skb, ndev, rionet_active[destid]); + } + + spin_unlock_irqrestore(&rnet->tx_lock, flags); + + return 0; +} + +static void rionet_dbell_event(struct rio_mport *mport, void *dev_id, u16 sid, u16 tid, + u16 info) +{ + struct net_device *ndev = dev_id; + struct rionet_private *rnet = ndev->priv; + struct rionet_peer *peer; + + if (netif_msg_intr(rnet)) + printk(KERN_INFO "%s: doorbell sid %4.4x tid %4.4x info %4.4x", + DRV_NAME, sid, tid, info); + if (info == RIONET_DOORBELL_JOIN) { + if (!rionet_active[sid]) { + list_for_each_entry(peer, &rionet_peers, node) { + if (peer->rdev->destid == sid) + rionet_active[sid] = peer->rdev; + } + rio_mport_send_doorbell(mport, sid, + RIONET_DOORBELL_JOIN); + } + } else if (info == RIONET_DOORBELL_LEAVE) { + rionet_active[sid] = NULL; + } else { + if (netif_msg_intr(rnet)) + printk(KERN_WARNING "%s: unhandled doorbell\n", + DRV_NAME); + } +} + +static void rionet_inb_msg_event(struct rio_mport *mport, void *dev_id, int mbox, int slot) +{ + int n; + struct net_device *ndev = dev_id; + struct rionet_private *rnet = (struct rionet_private *)ndev->priv; + + if (netif_msg_intr(rnet)) + printk(KERN_INFO "%s: inbound message event, mbox %d slot %d\n", + DRV_NAME, mbox, slot); + + spin_lock(&rnet->lock); + if ((n = rionet_rx_clean(ndev)) != rnet->rx_slot) + rionet_rx_fill(ndev, n); + spin_unlock(&rnet->lock); +} + +static void rionet_outb_msg_event(struct rio_mport *mport, void *dev_id, int mbox, int slot) +{ + struct net_device *ndev = dev_id; + struct rionet_private *rnet = ndev->priv; + + spin_lock(&rnet->lock); + + if (netif_msg_intr(rnet)) + printk(KERN_INFO + "%s: outbound message event, mbox %d slot %d\n", + DRV_NAME, mbox, slot); + + while (rnet->tx_cnt && (rnet->ack_slot != slot)) { + /* dma unmap single */ + dev_kfree_skb_irq(rnet->tx_skb[rnet->ack_slot]); + rnet->tx_skb[rnet->ack_slot] = NULL; + ++rnet->ack_slot; + rnet->ack_slot &= (RIONET_TX_RING_SIZE - 1); + rnet->tx_cnt--; + } + + if (rnet->tx_cnt < RIONET_TX_RING_SIZE) + netif_wake_queue(ndev); + + spin_unlock(&rnet->lock); +} + +static int rionet_open(struct net_device *ndev) +{ + int i, rc = 0; + struct rionet_peer *peer, *tmp; + u32 pwdcsr; + struct rionet_private *rnet = ndev->priv; + + if (netif_msg_ifup(rnet)) + printk(KERN_INFO "%s: open\n", DRV_NAME); + + if ((rc = rio_request_inb_dbell(rnet->mport, + (void *)ndev, + RIONET_DOORBELL_JOIN, + RIONET_DOORBELL_LEAVE, + rionet_dbell_event)) < 0) + goto out; + + if ((rc = rio_request_inb_mbox(rnet->mport, + (void *)ndev, + RIONET_MAILBOX, + RIONET_RX_RING_SIZE, + rionet_inb_msg_event)) < 0) + goto out; + + if ((rc = rio_request_outb_mbox(rnet->mport, + (void *)ndev, + RIONET_MAILBOX, + RIONET_TX_RING_SIZE, + rionet_outb_msg_event)) < 0) + goto out; + + /* Initialize inbound message ring */ + for (i = 0; i < RIONET_RX_RING_SIZE; i++) + rnet->rx_skb[i] = NULL; + rnet->rx_slot = 0; + rionet_rx_fill(ndev, 0); + + rnet->tx_slot = 0; + rnet->tx_cnt = 0; + rnet->ack_slot = 0; + + netif_carrier_on(ndev); + netif_start_queue(ndev); + + list_for_each_entry_safe(peer, tmp, &rionet_peers, node) { + if (!(peer->res = rio_request_outb_dbell(peer->rdev, + RIONET_DOORBELL_JOIN, + RIONET_DOORBELL_LEAVE))) + { + printk(KERN_ERR "%s: error requesting doorbells\n", + DRV_NAME); + continue; + } + + /* + * If device has initialized inbound doorbells, + * send a join message + */ + rio_read_config_32(peer->rdev, RIO_WRITE_PORT_CSR, &pwdcsr); + if (pwdcsr & RIO_DOORBELL_AVAIL) + rio_send_doorbell(peer->rdev, RIONET_DOORBELL_JOIN); + } + + out: + return rc; +} + +static int rionet_close(struct net_device *ndev) +{ + struct rionet_private *rnet = (struct rionet_private *)ndev->priv; + struct rionet_peer *peer, *tmp; + int i; + + if (netif_msg_ifup(rnet)) + printk(KERN_INFO "%s: close\n", DRV_NAME); + + netif_stop_queue(ndev); + netif_carrier_off(ndev); + + for (i = 0; i < RIONET_RX_RING_SIZE; i++) + if (rnet->rx_skb[i]) + kfree_skb(rnet->rx_skb[i]); + + list_for_each_entry_safe(peer, tmp, &rionet_peers, node) { + if (rionet_active[peer->rdev->destid]) { + rio_send_doorbell(peer->rdev, RIONET_DOORBELL_LEAVE); + rionet_active[peer->rdev->destid] = NULL; + } + rio_release_outb_dbell(peer->rdev, peer->res); + } + + rio_release_inb_dbell(rnet->mport, RIONET_DOORBELL_JOIN, + RIONET_DOORBELL_LEAVE); + rio_release_inb_mbox(rnet->mport, RIONET_MAILBOX); + rio_release_outb_mbox(rnet->mport, RIONET_MAILBOX); + + return 0; +} + +static void rionet_remove(struct rio_dev *rdev) +{ + struct net_device *ndev = NULL; + struct rionet_peer *peer, *tmp; + + unregister_netdev(ndev); + kfree(ndev); + + list_for_each_entry_safe(peer, tmp, &rionet_peers, node) { + list_del(&peer->node); + kfree(peer); + } +} + +static void rionet_get_drvinfo(struct net_device *ndev, + struct ethtool_drvinfo *info) +{ + struct rionet_private *rnet = ndev->priv; + + strcpy(info->driver, DRV_NAME); + strcpy(info->version, DRV_VERSION); + strcpy(info->fw_version, "n/a"); + strcpy(info->bus_info, rnet->mport->name); +} + +static u32 rionet_get_msglevel(struct net_device *ndev) +{ + struct rionet_private *rnet = ndev->priv; + + return rnet->msg_enable; +} + +static void rionet_set_msglevel(struct net_device *ndev, u32 value) +{ + struct rionet_private *rnet = ndev->priv; + + rnet->msg_enable = value; +} + +static struct ethtool_ops rionet_ethtool_ops = { + .get_drvinfo = rionet_get_drvinfo, + .get_msglevel = rionet_get_msglevel, + .set_msglevel = rionet_set_msglevel, + .get_link = ethtool_op_get_link, +}; + +static int rionet_setup_netdev(struct rio_mport *mport) +{ + int rc = 0; + struct net_device *ndev = NULL; + struct rionet_private *rnet; + u16 device_id; + + /* Allocate our net_device structure */ + ndev = alloc_etherdev(sizeof(struct rionet_private)); + if (ndev == NULL) { + printk(KERN_INFO "%s: could not allocate ethernet device.\n", + DRV_NAME); + rc = -ENOMEM; + goto out; + } + + /* Set up private area */ + rnet = (struct rionet_private *)ndev->priv; + rnet->mport = mport; + + /* Set the default MAC address */ + device_id = rio_local_get_device_id(mport); + ndev->dev_addr[0] = 0x00; + ndev->dev_addr[1] = 0x01; + ndev->dev_addr[2] = 0x00; + ndev->dev_addr[3] = 0x01; + ndev->dev_addr[4] = device_id >> 8; + ndev->dev_addr[5] = device_id & 0xff; + + /* Fill in the driver function table */ + ndev->open = &rionet_open; + ndev->hard_start_xmit = &rionet_start_xmit; + ndev->stop = &rionet_close; + ndev->get_stats = &rionet_stats; + ndev->mtu = RIO_MAX_MSG_SIZE - 14; + ndev->features = NETIF_F_LLTX; + SET_ETHTOOL_OPS(ndev, &rionet_ethtool_ops); + + SET_MODULE_OWNER(ndev); + + spin_lock_init(&rnet->lock); + spin_lock_init(&rnet->tx_lock); + + rnet->msg_enable = RIONET_DEFAULT_MSGLEVEL; + + rc = register_netdev(ndev); + if (rc != 0) + goto out; + + printk("%s: %s %s Version %s, MAC %02x:%02x:%02x:%02x:%02x:%02x\n", + ndev->name, + DRV_NAME, + DRV_DESC, + DRV_VERSION, + ndev->dev_addr[0], ndev->dev_addr[1], ndev->dev_addr[2], + ndev->dev_addr[3], ndev->dev_addr[4], ndev->dev_addr[5]); + + out: + return rc; +} + +/* + * XXX Make multi-net safe + */ +static int rionet_probe(struct rio_dev *rdev, const struct rio_device_id *id) +{ + int rc = -ENODEV; + u32 lpef, lsrc_ops, ldst_ops; + struct rionet_peer *peer; + + /* If local device is not rionet capable, give up quickly */ + if (!rionet_capable) + goto out; + + /* + * First time through, make sure local device is rionet + * capable, setup netdev, and set flags so this is skipped + * on later probes + */ + if (!rionet_check) { + rio_local_read_config_32(rdev->net->hport, RIO_PEF_CAR, &lpef); + rio_local_read_config_32(rdev->net->hport, RIO_SRC_OPS_CAR, + &lsrc_ops); + rio_local_read_config_32(rdev->net->hport, RIO_DST_OPS_CAR, + &ldst_ops); + if (!is_rionet_capable(lpef, lsrc_ops, ldst_ops)) { + printk(KERN_ERR + "%s: local device is not network capable\n", + DRV_NAME); + rionet_check = 1; + rionet_capable = 0; + goto out; + } + + rc = rionet_setup_netdev(rdev->net->hport); + rionet_check = 1; + } + + /* + * If the remote device has mailbox/doorbell capabilities, + * add it to the peer list. + */ + if (dev_rionet_capable(rdev)) { + if (!(peer = kmalloc(sizeof(struct rionet_peer), GFP_KERNEL))) { + rc = -ENOMEM; + goto out; + } + peer->rdev = rdev; + list_add_tail(&peer->node, &rionet_peers); + } + + out: + return rc; +} + +static struct rio_device_id rionet_id_table[] = { + {RIO_DEVICE(RIO_ANY_ID, RIO_ANY_ID)} +}; + +static struct rio_driver rionet_driver = { + .name = "rionet", + .id_table = rionet_id_table, + .probe = rionet_probe, + .remove = rionet_remove, +}; + +static int __init rionet_init(void) +{ + return rio_register_driver(&rionet_driver); +} + +static void __exit rionet_exit(void) +{ + rio_unregister_driver(&rionet_driver); +} + +module_init(rionet_init); +module_exit(rionet_exit); diff --git a/drivers/net/rrunner.c b/drivers/net/rrunner.c index ec1a18d189a1..19c2df9c86fe 100644 --- a/drivers/net/rrunner.c +++ b/drivers/net/rrunner.c @@ -1710,10 +1710,8 @@ static int rr_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) error = -EFAULT; } wf_out: - if (oldimage) - kfree(oldimage); - if (image) - kfree(image); + kfree(oldimage); + kfree(image); return error; case SIOCRRID: diff --git a/drivers/net/s2io-regs.h b/drivers/net/s2io-regs.h index 7cefe5507b9e..00179bc3437f 100644 --- a/drivers/net/s2io-regs.h +++ b/drivers/net/s2io-regs.h @@ -814,6 +814,17 @@ typedef struct _XENA_dev_config { u64 rxgxs_ber_0; /* CHANGED */ u64 rxgxs_ber_1; /* CHANGED */ + u64 spi_control; +#define SPI_CONTROL_KEY(key) vBIT(key,0,4) +#define SPI_CONTROL_BYTECNT(cnt) vBIT(cnt,29,3) +#define SPI_CONTROL_CMD(cmd) vBIT(cmd,32,8) +#define SPI_CONTROL_ADDR(addr) vBIT(addr,40,24) +#define SPI_CONTROL_SEL1 BIT(4) +#define SPI_CONTROL_REQ BIT(7) +#define SPI_CONTROL_NACK BIT(5) +#define SPI_CONTROL_DONE BIT(6) + u64 spi_data; +#define SPI_DATA_WRITE(data,len) vBIT(data,0,len) } XENA_dev_config_t; #define XENA_REG_SPACE sizeof(XENA_dev_config_t) diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index dd451e099a4c..3f5e93aad5c7 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -65,9 +65,11 @@ #include "s2io.h" #include "s2io-regs.h" +#define DRV_VERSION "Version 2.0.9.1" + /* S2io Driver name & version. */ static char s2io_driver_name[] = "Neterion"; -static char s2io_driver_version[] = "Version 2.0.8.1"; +static char s2io_driver_version[] = DRV_VERSION; static inline int RXD_IS_UP2DT(RxD_t *rxdp) { @@ -307,6 +309,8 @@ static unsigned int indicate_max_pkts; #endif /* Frequency of Rx desc syncs expressed as power of 2 */ static unsigned int rxsync_frequency = 3; +/* Interrupt type. Values can be 0(INTA), 1(MSI), 2(MSI_X) */ +static unsigned int intr_type = 0; /* * S2IO device table. @@ -701,8 +705,7 @@ static void free_shared_mem(struct s2io_nic *nic) } kfree(mac_control->rings[i].ba[j]); } - if (mac_control->rings[i].ba) - kfree(mac_control->rings[i].ba); + kfree(mac_control->rings[i].ba); } #endif @@ -1396,8 +1399,13 @@ static int init_nic(struct s2io_nic *nic) writeq(val64, &bar0->rti_data1_mem); val64 = RTI_DATA2_MEM_RX_UFC_A(0x1) | - RTI_DATA2_MEM_RX_UFC_B(0x2) | - RTI_DATA2_MEM_RX_UFC_C(0x40) | RTI_DATA2_MEM_RX_UFC_D(0x80); + RTI_DATA2_MEM_RX_UFC_B(0x2) ; + if (nic->intr_type == MSI_X) + val64 |= (RTI_DATA2_MEM_RX_UFC_C(0x20) | \ + RTI_DATA2_MEM_RX_UFC_D(0x40)); + else + val64 |= (RTI_DATA2_MEM_RX_UFC_C(0x40) | \ + RTI_DATA2_MEM_RX_UFC_D(0x80)); writeq(val64, &bar0->rti_data2_mem); for (i = 0; i < config->rx_ring_num; i++) { @@ -1507,17 +1515,15 @@ static int init_nic(struct s2io_nic *nic) #define LINK_UP_DOWN_INTERRUPT 1 #define MAC_RMAC_ERR_TIMER 2 -#if defined(CONFIG_MSI_MODE) || defined(CONFIG_MSIX_MODE) -#define s2io_link_fault_indication(x) MAC_RMAC_ERR_TIMER -#else int s2io_link_fault_indication(nic_t *nic) { + if (nic->intr_type != INTA) + return MAC_RMAC_ERR_TIMER; if (nic->device_type == XFRAME_II_DEVICE) return LINK_UP_DOWN_INTERRUPT; else return MAC_RMAC_ERR_TIMER; } -#endif /** * en_dis_able_nic_intrs - Enable or Disable the interrupts @@ -1941,11 +1947,14 @@ static int start_nic(struct s2io_nic *nic) } /* Enable select interrupts */ - interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR; - interruptible |= TX_PIC_INTR | RX_PIC_INTR; - interruptible |= TX_MAC_INTR | RX_MAC_INTR; - - en_dis_able_nic_intrs(nic, interruptible, ENABLE_INTRS); + if (nic->intr_type != INTA) + en_dis_able_nic_intrs(nic, ENA_ALL_INTRS, DISABLE_INTRS); + else { + interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR; + interruptible |= TX_PIC_INTR | RX_PIC_INTR; + interruptible |= TX_MAC_INTR | RX_MAC_INTR; + en_dis_able_nic_intrs(nic, interruptible, ENABLE_INTRS); + } /* * With some switches, link might be already up at this point. @@ -2633,11 +2642,11 @@ static void tx_intr_handler(fifo_info_t *fifo_data) err = txdlp->Control_1 & TXD_T_CODE; if ((err >> 48) == 0xA) { DBG_PRINT(TX_DBG, "TxD returned due \ - to loss of link\n"); +to loss of link\n"); } else { DBG_PRINT(ERR_DBG, "***TxD error \ - %llx\n", err); +%llx\n", err); } } @@ -2854,6 +2863,9 @@ void s2io_reset(nic_t * sp) /* Set swapper to enable I/O register access */ s2io_set_swapper(sp); + /* Restore the MSIX table entries from local variables */ + restore_xmsi_data(sp); + /* Clear certain PCI/PCI-X fields after reset */ if (sp->device_type == XFRAME_II_DEVICE) { /* Clear parity err detect bit */ @@ -2983,8 +2995,9 @@ int s2io_set_swapper(nic_t * sp) SWAPPER_CTRL_RXD_W_FE | SWAPPER_CTRL_RXF_W_FE | SWAPPER_CTRL_XMSI_FE | - SWAPPER_CTRL_XMSI_SE | SWAPPER_CTRL_STATS_FE | SWAPPER_CTRL_STATS_SE); + if (sp->intr_type == INTA) + val64 |= SWAPPER_CTRL_XMSI_SE; writeq(val64, &bar0->swapper_ctrl); #else /* @@ -3005,8 +3018,9 @@ int s2io_set_swapper(nic_t * sp) SWAPPER_CTRL_RXD_W_SE | SWAPPER_CTRL_RXF_W_FE | SWAPPER_CTRL_XMSI_FE | - SWAPPER_CTRL_XMSI_SE | SWAPPER_CTRL_STATS_FE | SWAPPER_CTRL_STATS_SE); + if (sp->intr_type == INTA) + val64 |= SWAPPER_CTRL_XMSI_SE; writeq(val64, &bar0->swapper_ctrl); #endif val64 = readq(&bar0->swapper_ctrl); @@ -3028,6 +3042,201 @@ int s2io_set_swapper(nic_t * sp) return SUCCESS; } +int wait_for_msix_trans(nic_t *nic, int i) +{ + XENA_dev_config_t __iomem *bar0 = nic->bar0; + u64 val64; + int ret = 0, cnt = 0; + + do { + val64 = readq(&bar0->xmsi_access); + if (!(val64 & BIT(15))) + break; + mdelay(1); + cnt++; + } while(cnt < 5); + if (cnt == 5) { + DBG_PRINT(ERR_DBG, "XMSI # %d Access failed\n", i); + ret = 1; + } + + return ret; +} + +void restore_xmsi_data(nic_t *nic) +{ + XENA_dev_config_t __iomem *bar0 = nic->bar0; + u64 val64; + int i; + + for (i=0; i< MAX_REQUESTED_MSI_X; i++) { + writeq(nic->msix_info[i].addr, &bar0->xmsi_address); + writeq(nic->msix_info[i].data, &bar0->xmsi_data); + val64 = (BIT(7) | BIT(15) | vBIT(i, 26, 6)); + writeq(val64, &bar0->xmsi_access); + if (wait_for_msix_trans(nic, i)) { + DBG_PRINT(ERR_DBG, "failed in %s\n", __FUNCTION__); + continue; + } + } +} + +void store_xmsi_data(nic_t *nic) +{ + XENA_dev_config_t __iomem *bar0 = nic->bar0; + u64 val64, addr, data; + int i; + + /* Store and display */ + for (i=0; i< MAX_REQUESTED_MSI_X; i++) { + val64 = (BIT(15) | vBIT(i, 26, 6)); + writeq(val64, &bar0->xmsi_access); + if (wait_for_msix_trans(nic, i)) { + DBG_PRINT(ERR_DBG, "failed in %s\n", __FUNCTION__); + continue; + } + addr = readq(&bar0->xmsi_address); + data = readq(&bar0->xmsi_data); + if (addr && data) { + nic->msix_info[i].addr = addr; + nic->msix_info[i].data = data; + } + } +} + +int s2io_enable_msi(nic_t *nic) +{ + XENA_dev_config_t __iomem *bar0 = nic->bar0; + u16 msi_ctrl, msg_val; + struct config_param *config = &nic->config; + struct net_device *dev = nic->dev; + u64 val64, tx_mat, rx_mat; + int i, err; + + val64 = readq(&bar0->pic_control); + val64 &= ~BIT(1); + writeq(val64, &bar0->pic_control); + + err = pci_enable_msi(nic->pdev); + if (err) { + DBG_PRINT(ERR_DBG, "%s: enabling MSI failed\n", + nic->dev->name); + return err; + } + + /* + * Enable MSI and use MSI-1 in stead of the standard MSI-0 + * for interrupt handling. + */ + pci_read_config_word(nic->pdev, 0x4c, &msg_val); + msg_val ^= 0x1; + pci_write_config_word(nic->pdev, 0x4c, msg_val); + pci_read_config_word(nic->pdev, 0x4c, &msg_val); + + pci_read_config_word(nic->pdev, 0x42, &msi_ctrl); + msi_ctrl |= 0x10; + pci_write_config_word(nic->pdev, 0x42, msi_ctrl); + + /* program MSI-1 into all usable Tx_Mat and Rx_Mat fields */ + tx_mat = readq(&bar0->tx_mat0_n[0]); + for (i=0; i<config->tx_fifo_num; i++) { + tx_mat |= TX_MAT_SET(i, 1); + } + writeq(tx_mat, &bar0->tx_mat0_n[0]); + + rx_mat = readq(&bar0->rx_mat); + for (i=0; i<config->rx_ring_num; i++) { + rx_mat |= RX_MAT_SET(i, 1); + } + writeq(rx_mat, &bar0->rx_mat); + + dev->irq = nic->pdev->irq; + return 0; +} + +int s2io_enable_msi_x(nic_t *nic) +{ + XENA_dev_config_t __iomem *bar0 = nic->bar0; + u64 tx_mat, rx_mat; + u16 msi_control; /* Temp variable */ + int ret, i, j, msix_indx = 1; + + nic->entries = kmalloc(MAX_REQUESTED_MSI_X * sizeof(struct msix_entry), + GFP_KERNEL); + if (nic->entries == NULL) { + DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n", __FUNCTION__); + return -ENOMEM; + } + memset(nic->entries, 0, MAX_REQUESTED_MSI_X * sizeof(struct msix_entry)); + + nic->s2io_entries = + kmalloc(MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry), + GFP_KERNEL); + if (nic->s2io_entries == NULL) { + DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n", __FUNCTION__); + kfree(nic->entries); + return -ENOMEM; + } + memset(nic->s2io_entries, 0, + MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry)); + + for (i=0; i< MAX_REQUESTED_MSI_X; i++) { + nic->entries[i].entry = i; + nic->s2io_entries[i].entry = i; + nic->s2io_entries[i].arg = NULL; + nic->s2io_entries[i].in_use = 0; + } + + tx_mat = readq(&bar0->tx_mat0_n[0]); + for (i=0; i<nic->config.tx_fifo_num; i++, msix_indx++) { + tx_mat |= TX_MAT_SET(i, msix_indx); + nic->s2io_entries[msix_indx].arg = &nic->mac_control.fifos[i]; + nic->s2io_entries[msix_indx].type = MSIX_FIFO_TYPE; + nic->s2io_entries[msix_indx].in_use = MSIX_FLG; + } + writeq(tx_mat, &bar0->tx_mat0_n[0]); + + if (!nic->config.bimodal) { + rx_mat = readq(&bar0->rx_mat); + for (j=0; j<nic->config.rx_ring_num; j++, msix_indx++) { + rx_mat |= RX_MAT_SET(j, msix_indx); + nic->s2io_entries[msix_indx].arg = &nic->mac_control.rings[j]; + nic->s2io_entries[msix_indx].type = MSIX_RING_TYPE; + nic->s2io_entries[msix_indx].in_use = MSIX_FLG; + } + writeq(rx_mat, &bar0->rx_mat); + } else { + tx_mat = readq(&bar0->tx_mat0_n[7]); + for (j=0; j<nic->config.rx_ring_num; j++, msix_indx++) { + tx_mat |= TX_MAT_SET(i, msix_indx); + nic->s2io_entries[msix_indx].arg = &nic->mac_control.rings[j]; + nic->s2io_entries[msix_indx].type = MSIX_RING_TYPE; + nic->s2io_entries[msix_indx].in_use = MSIX_FLG; + } + writeq(tx_mat, &bar0->tx_mat0_n[7]); + } + + ret = pci_enable_msix(nic->pdev, nic->entries, MAX_REQUESTED_MSI_X); + if (ret) { + DBG_PRINT(ERR_DBG, "%s: Enabling MSIX failed\n", nic->dev->name); + kfree(nic->entries); + kfree(nic->s2io_entries); + nic->entries = NULL; + nic->s2io_entries = NULL; + return -ENOMEM; + } + + /* + * To enable MSI-X, MSI also needs to be enabled, due to a bug + * in the herc NIC. (Temp change, needs to be removed later) + */ + pci_read_config_word(nic->pdev, 0x42, &msi_control); + msi_control |= 0x1; /* Enable MSI */ + pci_write_config_word(nic->pdev, 0x42, msi_control); + + return 0; +} + /* ********************************************************* * * Functions defined below concern the OS part of the driver * * ********************************************************* */ @@ -3048,6 +3257,8 @@ int s2io_open(struct net_device *dev) { nic_t *sp = dev->priv; int err = 0; + int i; + u16 msi_control; /* Temp variable */ /* * Make sure you have link off by default every time @@ -3064,13 +3275,55 @@ int s2io_open(struct net_device *dev) goto hw_init_failed; } + /* Store the values of the MSIX table in the nic_t structure */ + store_xmsi_data(sp); + /* After proper initialization of H/W, register ISR */ - err = request_irq((int) sp->pdev->irq, s2io_isr, SA_SHIRQ, - sp->name, dev); - if (err) { - DBG_PRINT(ERR_DBG, "%s: ISR registration failed\n", - dev->name); - goto isr_registration_failed; + if (sp->intr_type == MSI) { + err = request_irq((int) sp->pdev->irq, s2io_msi_handle, + SA_SHIRQ, sp->name, dev); + if (err) { + DBG_PRINT(ERR_DBG, "%s: MSI registration \ +failed\n", dev->name); + goto isr_registration_failed; + } + } + if (sp->intr_type == MSI_X) { + for (i=1; (sp->s2io_entries[i].in_use == MSIX_FLG); i++) { + if (sp->s2io_entries[i].type == MSIX_FIFO_TYPE) { + sprintf(sp->desc1, "%s:MSI-X-%d-TX", + dev->name, i); + err = request_irq(sp->entries[i].vector, + s2io_msix_fifo_handle, 0, sp->desc1, + sp->s2io_entries[i].arg); + DBG_PRINT(ERR_DBG, "%s @ 0x%llx\n", sp->desc1, + sp->msix_info[i].addr); + } else { + sprintf(sp->desc2, "%s:MSI-X-%d-RX", + dev->name, i); + err = request_irq(sp->entries[i].vector, + s2io_msix_ring_handle, 0, sp->desc2, + sp->s2io_entries[i].arg); + DBG_PRINT(ERR_DBG, "%s @ 0x%llx\n", sp->desc2, + sp->msix_info[i].addr); + } + if (err) { + DBG_PRINT(ERR_DBG, "%s: MSI-X-%d registration \ +failed\n", dev->name, i); + DBG_PRINT(ERR_DBG, "Returned: %d\n", err); + goto isr_registration_failed; + } + sp->s2io_entries[i].in_use = MSIX_REGISTERED_SUCCESS; + } + } + if (sp->intr_type == INTA) { + err = request_irq((int) sp->pdev->irq, s2io_isr, SA_SHIRQ, + sp->name, dev); + if (err) { + DBG_PRINT(ERR_DBG, "%s: ISR registration failed\n", + dev->name); + goto isr_registration_failed; + } } if (s2io_set_mac_addr(dev, dev->dev_addr) == FAILURE) { @@ -3083,11 +3336,37 @@ int s2io_open(struct net_device *dev) return 0; setting_mac_address_failed: - free_irq(sp->pdev->irq, dev); + if (sp->intr_type != MSI_X) + free_irq(sp->pdev->irq, dev); isr_registration_failed: del_timer_sync(&sp->alarm_timer); + if (sp->intr_type == MSI_X) { + if (sp->device_type == XFRAME_II_DEVICE) { + for (i=1; (sp->s2io_entries[i].in_use == + MSIX_REGISTERED_SUCCESS); i++) { + int vector = sp->entries[i].vector; + void *arg = sp->s2io_entries[i].arg; + + free_irq(vector, arg); + } + pci_disable_msix(sp->pdev); + + /* Temp */ + pci_read_config_word(sp->pdev, 0x42, &msi_control); + msi_control &= 0xFFFE; /* Disable MSI */ + pci_write_config_word(sp->pdev, 0x42, msi_control); + } + } + else if (sp->intr_type == MSI) + pci_disable_msi(sp->pdev); s2io_reset(sp); hw_init_failed: + if (sp->intr_type == MSI_X) { + if (sp->entries) + kfree(sp->entries); + if (sp->s2io_entries) + kfree(sp->s2io_entries); + } return err; } @@ -3107,12 +3386,35 @@ hw_init_failed: int s2io_close(struct net_device *dev) { nic_t *sp = dev->priv; + int i; + u16 msi_control; + flush_scheduled_work(); netif_stop_queue(dev); /* Reset card, kill tasklet and free Tx and Rx buffers. */ s2io_card_down(sp); - free_irq(sp->pdev->irq, dev); + if (sp->intr_type == MSI_X) { + if (sp->device_type == XFRAME_II_DEVICE) { + for (i=1; (sp->s2io_entries[i].in_use == + MSIX_REGISTERED_SUCCESS); i++) { + int vector = sp->entries[i].vector; + void *arg = sp->s2io_entries[i].arg; + + free_irq(vector, arg); + } + pci_read_config_word(sp->pdev, 0x42, &msi_control); + msi_control &= 0xFFFE; /* Disable MSI */ + pci_write_config_word(sp->pdev, 0x42, msi_control); + + pci_disable_msix(sp->pdev); + } + } + else { + free_irq(sp->pdev->irq, dev); + if (sp->intr_type == MSI) + pci_disable_msi(sp->pdev); + } sp->device_close_flag = TRUE; /* Device is shut down. */ return 0; } @@ -3278,6 +3580,104 @@ s2io_alarm_handle(unsigned long data) mod_timer(&sp->alarm_timer, jiffies + HZ / 2); } +static irqreturn_t +s2io_msi_handle(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *) dev_id; + nic_t *sp = dev->priv; + int i; + int ret; + mac_info_t *mac_control; + struct config_param *config; + + atomic_inc(&sp->isr_cnt); + mac_control = &sp->mac_control; + config = &sp->config; + DBG_PRINT(INTR_DBG, "%s: MSI handler\n", __FUNCTION__); + + /* If Intr is because of Rx Traffic */ + for (i = 0; i < config->rx_ring_num; i++) + rx_intr_handler(&mac_control->rings[i]); + + /* If Intr is because of Tx Traffic */ + for (i = 0; i < config->tx_fifo_num; i++) + tx_intr_handler(&mac_control->fifos[i]); + + /* + * If the Rx buffer count is below the panic threshold then + * reallocate the buffers from the interrupt handler itself, + * else schedule a tasklet to reallocate the buffers. + */ + for (i = 0; i < config->rx_ring_num; i++) { + int rxb_size = atomic_read(&sp->rx_bufs_left[i]); + int level = rx_buffer_level(sp, rxb_size, i); + + if ((level == PANIC) && (!TASKLET_IN_USE)) { + DBG_PRINT(INTR_DBG, "%s: Rx BD hit ", dev->name); + DBG_PRINT(INTR_DBG, "PANIC levels\n"); + if ((ret = fill_rx_buffers(sp, i)) == -ENOMEM) { + DBG_PRINT(ERR_DBG, "%s:Out of memory", + dev->name); + DBG_PRINT(ERR_DBG, " in ISR!!\n"); + clear_bit(0, (&sp->tasklet_status)); + atomic_dec(&sp->isr_cnt); + return IRQ_HANDLED; + } + clear_bit(0, (&sp->tasklet_status)); + } else if (level == LOW) { + tasklet_schedule(&sp->task); + } + } + + atomic_dec(&sp->isr_cnt); + return IRQ_HANDLED; +} + +static irqreturn_t +s2io_msix_ring_handle(int irq, void *dev_id, struct pt_regs *regs) +{ + ring_info_t *ring = (ring_info_t *)dev_id; + nic_t *sp = ring->nic; + int rxb_size, level, rng_n; + + atomic_inc(&sp->isr_cnt); + rx_intr_handler(ring); + + rng_n = ring->ring_no; + rxb_size = atomic_read(&sp->rx_bufs_left[rng_n]); + level = rx_buffer_level(sp, rxb_size, rng_n); + + if ((level == PANIC) && (!TASKLET_IN_USE)) { + int ret; + DBG_PRINT(INTR_DBG, "%s: Rx BD hit ", __FUNCTION__); + DBG_PRINT(INTR_DBG, "PANIC levels\n"); + if ((ret = fill_rx_buffers(sp, rng_n)) == -ENOMEM) { + DBG_PRINT(ERR_DBG, "Out of memory in %s", + __FUNCTION__); + clear_bit(0, (&sp->tasklet_status)); + return IRQ_HANDLED; + } + clear_bit(0, (&sp->tasklet_status)); + } else if (level == LOW) { + tasklet_schedule(&sp->task); + } + atomic_dec(&sp->isr_cnt); + + return IRQ_HANDLED; +} + +static irqreturn_t +s2io_msix_fifo_handle(int irq, void *dev_id, struct pt_regs *regs) +{ + fifo_info_t *fifo = (fifo_info_t *)dev_id; + nic_t *sp = fifo->nic; + + atomic_inc(&sp->isr_cnt); + tx_intr_handler(fifo); + atomic_dec(&sp->isr_cnt); + return IRQ_HANDLED; +} + static void s2io_txpic_intr_handle(nic_t *sp) { XENA_dev_config_t __iomem *bar0 = sp->bar0; @@ -3778,11 +4178,10 @@ static void s2io_ethtool_gdrvinfo(struct net_device *dev, { nic_t *sp = dev->priv; - strncpy(info->driver, s2io_driver_name, sizeof(s2io_driver_name)); - strncpy(info->version, s2io_driver_version, - sizeof(s2io_driver_version)); - strncpy(info->fw_version, "", 32); - strncpy(info->bus_info, pci_name(sp->pdev), 32); + strncpy(info->driver, s2io_driver_name, sizeof(info->driver)); + strncpy(info->version, s2io_driver_version, sizeof(info->version)); + strncpy(info->fw_version, "", sizeof(info->fw_version)); + strncpy(info->bus_info, pci_name(sp->pdev), sizeof(info->bus_info)); info->regdump_len = XENA_REG_SPACE; info->eedump_len = XENA_EEPROM_SPACE; info->testinfo_len = S2IO_TEST_LEN; @@ -3978,29 +4377,53 @@ static int s2io_ethtool_setpause_data(struct net_device *dev, */ #define S2IO_DEV_ID 5 -static int read_eeprom(nic_t * sp, int off, u32 * data) +static int read_eeprom(nic_t * sp, int off, u64 * data) { int ret = -1; u32 exit_cnt = 0; u64 val64; XENA_dev_config_t __iomem *bar0 = sp->bar0; - val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | I2C_CONTROL_ADDR(off) | - I2C_CONTROL_BYTE_CNT(0x3) | I2C_CONTROL_READ | - I2C_CONTROL_CNTL_START; - SPECIAL_REG_WRITE(val64, &bar0->i2c_control, LF); + if (sp->device_type == XFRAME_I_DEVICE) { + val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | I2C_CONTROL_ADDR(off) | + I2C_CONTROL_BYTE_CNT(0x3) | I2C_CONTROL_READ | + I2C_CONTROL_CNTL_START; + SPECIAL_REG_WRITE(val64, &bar0->i2c_control, LF); - while (exit_cnt < 5) { - val64 = readq(&bar0->i2c_control); - if (I2C_CONTROL_CNTL_END(val64)) { - *data = I2C_CONTROL_GET_DATA(val64); - ret = 0; - break; + while (exit_cnt < 5) { + val64 = readq(&bar0->i2c_control); + if (I2C_CONTROL_CNTL_END(val64)) { + *data = I2C_CONTROL_GET_DATA(val64); + ret = 0; + break; + } + msleep(50); + exit_cnt++; } - msleep(50); - exit_cnt++; } + if (sp->device_type == XFRAME_II_DEVICE) { + val64 = SPI_CONTROL_KEY(0x9) | SPI_CONTROL_SEL1 | + SPI_CONTROL_BYTECNT(0x3) | + SPI_CONTROL_CMD(0x3) | SPI_CONTROL_ADDR(off); + SPECIAL_REG_WRITE(val64, &bar0->spi_control, LF); + val64 |= SPI_CONTROL_REQ; + SPECIAL_REG_WRITE(val64, &bar0->spi_control, LF); + while (exit_cnt < 5) { + val64 = readq(&bar0->spi_control); + if (val64 & SPI_CONTROL_NACK) { + ret = 1; + break; + } else if (val64 & SPI_CONTROL_DONE) { + *data = readq(&bar0->spi_data); + *data &= 0xffffff; + ret = 0; + break; + } + msleep(50); + exit_cnt++; + } + } return ret; } @@ -4019,28 +4442,53 @@ static int read_eeprom(nic_t * sp, int off, u32 * data) * 0 on success, -1 on failure. */ -static int write_eeprom(nic_t * sp, int off, u32 data, int cnt) +static int write_eeprom(nic_t * sp, int off, u64 data, int cnt) { int exit_cnt = 0, ret = -1; u64 val64; XENA_dev_config_t __iomem *bar0 = sp->bar0; - val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | I2C_CONTROL_ADDR(off) | - I2C_CONTROL_BYTE_CNT(cnt) | I2C_CONTROL_SET_DATA(data) | - I2C_CONTROL_CNTL_START; - SPECIAL_REG_WRITE(val64, &bar0->i2c_control, LF); + if (sp->device_type == XFRAME_I_DEVICE) { + val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | I2C_CONTROL_ADDR(off) | + I2C_CONTROL_BYTE_CNT(cnt) | I2C_CONTROL_SET_DATA((u32)data) | + I2C_CONTROL_CNTL_START; + SPECIAL_REG_WRITE(val64, &bar0->i2c_control, LF); + + while (exit_cnt < 5) { + val64 = readq(&bar0->i2c_control); + if (I2C_CONTROL_CNTL_END(val64)) { + if (!(val64 & I2C_CONTROL_NACK)) + ret = 0; + break; + } + msleep(50); + exit_cnt++; + } + } - while (exit_cnt < 5) { - val64 = readq(&bar0->i2c_control); - if (I2C_CONTROL_CNTL_END(val64)) { - if (!(val64 & I2C_CONTROL_NACK)) + if (sp->device_type == XFRAME_II_DEVICE) { + int write_cnt = (cnt == 8) ? 0 : cnt; + writeq(SPI_DATA_WRITE(data,(cnt<<3)), &bar0->spi_data); + + val64 = SPI_CONTROL_KEY(0x9) | SPI_CONTROL_SEL1 | + SPI_CONTROL_BYTECNT(write_cnt) | + SPI_CONTROL_CMD(0x2) | SPI_CONTROL_ADDR(off); + SPECIAL_REG_WRITE(val64, &bar0->spi_control, LF); + val64 |= SPI_CONTROL_REQ; + SPECIAL_REG_WRITE(val64, &bar0->spi_control, LF); + while (exit_cnt < 5) { + val64 = readq(&bar0->spi_control); + if (val64 & SPI_CONTROL_NACK) { + ret = 1; + break; + } else if (val64 & SPI_CONTROL_DONE) { ret = 0; - break; + break; + } + msleep(50); + exit_cnt++; } - msleep(50); - exit_cnt++; } - return ret; } @@ -4060,7 +4508,8 @@ static int write_eeprom(nic_t * sp, int off, u32 data, int cnt) static int s2io_ethtool_geeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u8 * data_buf) { - u32 data, i, valid; + u32 i, valid; + u64 data; nic_t *sp = dev->priv; eeprom->magic = sp->pdev->vendor | (sp->pdev->device << 16); @@ -4098,7 +4547,7 @@ static int s2io_ethtool_seeprom(struct net_device *dev, u8 * data_buf) { int len = eeprom->len, cnt = 0; - u32 valid = 0, data; + u64 valid = 0, data; nic_t *sp = dev->priv; if (eeprom->magic != (sp->pdev->vendor | (sp->pdev->device << 16))) { @@ -4146,7 +4595,7 @@ static int s2io_ethtool_seeprom(struct net_device *dev, static int s2io_register_test(nic_t * sp, uint64_t * data) { XENA_dev_config_t __iomem *bar0 = sp->bar0; - u64 val64 = 0; + u64 val64 = 0, exp_val; int fail = 0; val64 = readq(&bar0->pif_rd_swapper_fb); @@ -4162,7 +4611,11 @@ static int s2io_register_test(nic_t * sp, uint64_t * data) } val64 = readq(&bar0->rx_queue_cfg); - if (val64 != 0x0808080808080808ULL) { + if (sp->device_type == XFRAME_II_DEVICE) + exp_val = 0x0404040404040404ULL; + else + exp_val = 0x0808080808080808ULL; + if (val64 != exp_val) { fail = 1; DBG_PRINT(INFO_DBG, "Read Test level 3 fails\n"); } @@ -4190,7 +4643,7 @@ static int s2io_register_test(nic_t * sp, uint64_t * data) } *data = fail; - return 0; + return fail; } /** @@ -4209,58 +4662,83 @@ static int s2io_register_test(nic_t * sp, uint64_t * data) static int s2io_eeprom_test(nic_t * sp, uint64_t * data) { int fail = 0; - u32 ret_data; + u64 ret_data, org_4F0, org_7F0; + u8 saved_4F0 = 0, saved_7F0 = 0; + struct net_device *dev = sp->dev; /* Test Write Error at offset 0 */ - if (!write_eeprom(sp, 0, 0, 3)) - fail = 1; + /* Note that SPI interface allows write access to all areas + * of EEPROM. Hence doing all negative testing only for Xframe I. + */ + if (sp->device_type == XFRAME_I_DEVICE) + if (!write_eeprom(sp, 0, 0, 3)) + fail = 1; + + /* Save current values at offsets 0x4F0 and 0x7F0 */ + if (!read_eeprom(sp, 0x4F0, &org_4F0)) + saved_4F0 = 1; + if (!read_eeprom(sp, 0x7F0, &org_7F0)) + saved_7F0 = 1; /* Test Write at offset 4f0 */ - if (write_eeprom(sp, 0x4F0, 0x01234567, 3)) + if (write_eeprom(sp, 0x4F0, 0x012345, 3)) fail = 1; if (read_eeprom(sp, 0x4F0, &ret_data)) fail = 1; - if (ret_data != 0x01234567) + if (ret_data != 0x012345) { + DBG_PRINT(ERR_DBG, "%s: eeprom test error at offset 0x4F0. Data written %llx Data read %llx\n", dev->name, (u64)0x12345, ret_data); fail = 1; + } /* Reset the EEPROM data go FFFF */ - write_eeprom(sp, 0x4F0, 0xFFFFFFFF, 3); + write_eeprom(sp, 0x4F0, 0xFFFFFF, 3); /* Test Write Request Error at offset 0x7c */ - if (!write_eeprom(sp, 0x07C, 0, 3)) - fail = 1; + if (sp->device_type == XFRAME_I_DEVICE) + if (!write_eeprom(sp, 0x07C, 0, 3)) + fail = 1; - /* Test Write Request at offset 0x7fc */ - if (write_eeprom(sp, 0x7FC, 0x01234567, 3)) + /* Test Write Request at offset 0x7f0 */ + if (write_eeprom(sp, 0x7F0, 0x012345, 3)) fail = 1; - if (read_eeprom(sp, 0x7FC, &ret_data)) + if (read_eeprom(sp, 0x7F0, &ret_data)) fail = 1; - if (ret_data != 0x01234567) + if (ret_data != 0x012345) { + DBG_PRINT(ERR_DBG, "%s: eeprom test error at offset 0x7F0. Data written %llx Data read %llx\n", dev->name, (u64)0x12345, ret_data); fail = 1; + } /* Reset the EEPROM data go FFFF */ - write_eeprom(sp, 0x7FC, 0xFFFFFFFF, 3); + write_eeprom(sp, 0x7F0, 0xFFFFFF, 3); - /* Test Write Error at offset 0x80 */ - if (!write_eeprom(sp, 0x080, 0, 3)) - fail = 1; + if (sp->device_type == XFRAME_I_DEVICE) { + /* Test Write Error at offset 0x80 */ + if (!write_eeprom(sp, 0x080, 0, 3)) + fail = 1; - /* Test Write Error at offset 0xfc */ - if (!write_eeprom(sp, 0x0FC, 0, 3)) - fail = 1; + /* Test Write Error at offset 0xfc */ + if (!write_eeprom(sp, 0x0FC, 0, 3)) + fail = 1; - /* Test Write Error at offset 0x100 */ - if (!write_eeprom(sp, 0x100, 0, 3)) - fail = 1; + /* Test Write Error at offset 0x100 */ + if (!write_eeprom(sp, 0x100, 0, 3)) + fail = 1; - /* Test Write Error at offset 4ec */ - if (!write_eeprom(sp, 0x4EC, 0, 3)) - fail = 1; + /* Test Write Error at offset 4ec */ + if (!write_eeprom(sp, 0x4EC, 0, 3)) + fail = 1; + } + + /* Restore values at offsets 0x4F0 and 0x7F0 */ + if (saved_4F0) + write_eeprom(sp, 0x4F0, org_4F0, 3); + if (saved_7F0) + write_eeprom(sp, 0x7F0, org_7F0, 3); *data = fail; - return 0; + return fail; } /** @@ -4342,7 +4820,7 @@ static int s2io_rldram_test(nic_t * sp, uint64_t * data) { XENA_dev_config_t __iomem *bar0 = sp->bar0; u64 val64; - int cnt, iteration = 0, test_pass = 0; + int cnt, iteration = 0, test_fail = 0; val64 = readq(&bar0->adapter_control); val64 &= ~ADAPTER_ECC_EN; @@ -4350,7 +4828,7 @@ static int s2io_rldram_test(nic_t * sp, uint64_t * data) val64 = readq(&bar0->mc_rldram_test_ctrl); val64 |= MC_RLDRAM_TEST_MODE; - writeq(val64, &bar0->mc_rldram_test_ctrl); + SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_test_ctrl, LF); val64 = readq(&bar0->mc_rldram_mrs); val64 |= MC_RLDRAM_QUEUE_SIZE_ENABLE; @@ -4378,17 +4856,12 @@ static int s2io_rldram_test(nic_t * sp, uint64_t * data) } writeq(val64, &bar0->mc_rldram_test_d2); - val64 = (u64) (0x0000003fffff0000ULL); + val64 = (u64) (0x0000003ffffe0100ULL); writeq(val64, &bar0->mc_rldram_test_add); - - val64 = MC_RLDRAM_TEST_MODE; - writeq(val64, &bar0->mc_rldram_test_ctrl); - - val64 |= - MC_RLDRAM_TEST_MODE | MC_RLDRAM_TEST_WRITE | - MC_RLDRAM_TEST_GO; - writeq(val64, &bar0->mc_rldram_test_ctrl); + val64 = MC_RLDRAM_TEST_MODE | MC_RLDRAM_TEST_WRITE | + MC_RLDRAM_TEST_GO; + SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_test_ctrl, LF); for (cnt = 0; cnt < 5; cnt++) { val64 = readq(&bar0->mc_rldram_test_ctrl); @@ -4400,11 +4873,8 @@ static int s2io_rldram_test(nic_t * sp, uint64_t * data) if (cnt == 5) break; - val64 = MC_RLDRAM_TEST_MODE; - writeq(val64, &bar0->mc_rldram_test_ctrl); - - val64 |= MC_RLDRAM_TEST_MODE | MC_RLDRAM_TEST_GO; - writeq(val64, &bar0->mc_rldram_test_ctrl); + val64 = MC_RLDRAM_TEST_MODE | MC_RLDRAM_TEST_GO; + SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_test_ctrl, LF); for (cnt = 0; cnt < 5; cnt++) { val64 = readq(&bar0->mc_rldram_test_ctrl); @@ -4417,18 +4887,18 @@ static int s2io_rldram_test(nic_t * sp, uint64_t * data) break; val64 = readq(&bar0->mc_rldram_test_ctrl); - if (val64 & MC_RLDRAM_TEST_PASS) - test_pass = 1; + if (!(val64 & MC_RLDRAM_TEST_PASS)) + test_fail = 1; iteration++; } - if (!test_pass) - *data = 1; - else - *data = 0; + *data = test_fail; - return 0; + /* Bring the adapter out of test mode */ + SPECIAL_REG_WRITE(0, &bar0->mc_rldram_test_ctrl, LF); + + return test_fail; } /** @@ -4932,7 +5402,7 @@ static void s2io_card_down(nic_t * sp) static int s2io_card_up(nic_t * sp) { - int i, ret; + int i, ret = 0; mac_info_t *mac_control; struct config_param *config; struct net_device *dev = (struct net_device *) sp->dev; @@ -4944,6 +5414,15 @@ static int s2io_card_up(nic_t * sp) return -ENODEV; } + if (sp->intr_type == MSI) + ret = s2io_enable_msi(sp); + else if (sp->intr_type == MSI_X) + ret = s2io_enable_msi_x(sp); + if (ret) { + DBG_PRINT(ERR_DBG, "%s: Defaulting to INTA\n", dev->name); + sp->intr_type = INTA; + } + /* * Initializing the Rx buffers. For now we are considering only 1 * Rx ring and initializing buffers into 30 Rx blocks @@ -5228,6 +5707,8 @@ static void s2io_init_pci(nic_t * sp) MODULE_AUTHOR("Raghavendra Koushik <raghavendra.koushik@neterion.com>"); MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_VERSION); + module_param(tx_fifo_num, int, 0); module_param(rx_ring_num, int, 0); module_param_array(tx_fifo_len, uint, NULL, 0); @@ -5245,6 +5726,7 @@ module_param(bimodal, bool, 0); module_param(indicate_max_pkts, int, 0); #endif module_param(rxsync_frequency, int, 0); +module_param(intr_type, int, 0); /** * s2io_init_nic - Initialization of the adapter . @@ -5274,9 +5756,16 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) mac_info_t *mac_control; struct config_param *config; int mode; + u8 dev_intr_type = intr_type; #ifdef CONFIG_S2IO_NAPI - DBG_PRINT(ERR_DBG, "NAPI support has been enabled\n"); + if (dev_intr_type != INTA) { + DBG_PRINT(ERR_DBG, "NAPI cannot be enabled when MSI/MSI-X \ +is enabled. Defaulting to INTA\n"); + dev_intr_type = INTA; + } + else + DBG_PRINT(ERR_DBG, "NAPI support has been enabled\n"); #endif if ((ret = pci_enable_device(pdev))) { @@ -5303,10 +5792,35 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) return -ENOMEM; } - if (pci_request_regions(pdev, s2io_driver_name)) { - DBG_PRINT(ERR_DBG, "Request Regions failed\n"), - pci_disable_device(pdev); - return -ENODEV; + if ((dev_intr_type == MSI_X) && + ((pdev->device != PCI_DEVICE_ID_HERC_WIN) && + (pdev->device != PCI_DEVICE_ID_HERC_UNI))) { + DBG_PRINT(ERR_DBG, "Xframe I does not support MSI_X. \ +Defaulting to INTA\n"); + dev_intr_type = INTA; + } + if (dev_intr_type != MSI_X) { + if (pci_request_regions(pdev, s2io_driver_name)) { + DBG_PRINT(ERR_DBG, "Request Regions failed\n"), + pci_disable_device(pdev); + return -ENODEV; + } + } + else { + if (!(request_mem_region(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0), s2io_driver_name))) { + DBG_PRINT(ERR_DBG, "bar0 Request Regions failed\n"); + pci_disable_device(pdev); + return -ENODEV; + } + if (!(request_mem_region(pci_resource_start(pdev, 2), + pci_resource_len(pdev, 2), s2io_driver_name))) { + DBG_PRINT(ERR_DBG, "bar1 Request Regions failed\n"); + release_mem_region(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + pci_disable_device(pdev); + return -ENODEV; + } } dev = alloc_etherdev(sizeof(nic_t)); @@ -5329,6 +5843,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) sp->pdev = pdev; sp->high_dma_flag = dma_flag; sp->device_enabled_once = FALSE; + sp->intr_type = dev_intr_type; if ((pdev->device == PCI_DEVICE_ID_HERC_WIN) || (pdev->device == PCI_DEVICE_ID_HERC_UNI)) @@ -5336,6 +5851,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) else sp->device_type = XFRAME_I_DEVICE; + /* Initialize some PCI/PCI-X fields of the NIC. */ s2io_init_pci(sp); @@ -5571,12 +6087,23 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) if (sp->device_type & XFRAME_II_DEVICE) { DBG_PRINT(ERR_DBG, "%s: Neterion Xframe II 10GbE adapter ", dev->name); - DBG_PRINT(ERR_DBG, "(rev %d), %s", + DBG_PRINT(ERR_DBG, "(rev %d), Version %s", get_xena_rev_id(sp->pdev), s2io_driver_version); #ifdef CONFIG_2BUFF_MODE DBG_PRINT(ERR_DBG, ", Buffer mode %d",2); #endif + switch(sp->intr_type) { + case INTA: + DBG_PRINT(ERR_DBG, ", Intr type INTA"); + break; + case MSI: + DBG_PRINT(ERR_DBG, ", Intr type MSI"); + break; + case MSI_X: + DBG_PRINT(ERR_DBG, ", Intr type MSI-X"); + break; + } DBG_PRINT(ERR_DBG, "\nCopyright(c) 2002-2005 Neterion Inc.\n"); DBG_PRINT(ERR_DBG, "MAC ADDR: %02x:%02x:%02x:%02x:%02x:%02x\n", @@ -5595,12 +6122,23 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) } else { DBG_PRINT(ERR_DBG, "%s: Neterion Xframe I 10GbE adapter ", dev->name); - DBG_PRINT(ERR_DBG, "(rev %d), %s", + DBG_PRINT(ERR_DBG, "(rev %d), Version %s", get_xena_rev_id(sp->pdev), s2io_driver_version); #ifdef CONFIG_2BUFF_MODE DBG_PRINT(ERR_DBG, ", Buffer mode %d",2); #endif + switch(sp->intr_type) { + case INTA: + DBG_PRINT(ERR_DBG, ", Intr type INTA"); + break; + case MSI: + DBG_PRINT(ERR_DBG, ", Intr type MSI"); + break; + case MSI_X: + DBG_PRINT(ERR_DBG, ", Intr type MSI-X"); + break; + } DBG_PRINT(ERR_DBG, "\nCopyright(c) 2002-2005 Neterion Inc.\n"); DBG_PRINT(ERR_DBG, "MAC ADDR: %02x:%02x:%02x:%02x:%02x:%02x\n", sp->def_mac_addr[0].mac_addr[0], @@ -5644,7 +6182,14 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) mem_alloc_failed: free_shared_mem(sp); pci_disable_device(pdev); - pci_release_regions(pdev); + if (dev_intr_type != MSI_X) + pci_release_regions(pdev); + else { + release_mem_region(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + release_mem_region(pci_resource_start(pdev, 2), + pci_resource_len(pdev, 2)); + } pci_set_drvdata(pdev, NULL); free_netdev(dev); @@ -5678,7 +6223,14 @@ static void __devexit s2io_rem_nic(struct pci_dev *pdev) iounmap(sp->bar0); iounmap(sp->bar1); pci_disable_device(pdev); - pci_release_regions(pdev); + if (sp->intr_type != MSI_X) + pci_release_regions(pdev); + else { + release_mem_region(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + release_mem_region(pci_resource_start(pdev, 2), + pci_resource_len(pdev, 2)); + } pci_set_drvdata(pdev, NULL); free_netdev(dev); } diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index 89151cb52181..1cc24b56760e 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h @@ -652,6 +652,30 @@ typedef struct { #define SMALL_BLK_CNT 30 #define LARGE_BLK_CNT 100 +/* + * Structure to keep track of the MSI-X vectors and the corresponding + * argument registered against each vector + */ +#define MAX_REQUESTED_MSI_X 17 +struct s2io_msix_entry +{ + u16 vector; + u16 entry; + void *arg; + + u8 type; +#define MSIX_FIFO_TYPE 1 +#define MSIX_RING_TYPE 2 + + u8 in_use; +#define MSIX_REGISTERED_SUCCESS 0xAA +}; + +struct msix_info_st { + u64 addr; + u64 data; +}; + /* Structure representing one instance of the NIC */ struct s2io_nic { #ifdef CONFIG_S2IO_NAPI @@ -719,13 +743,8 @@ struct s2io_nic { * a schedule task that will set the correct Link state once the * NIC's PHY has stabilized after a state change. */ -#ifdef INIT_TQUEUE - struct tq_struct rst_timer_task; - struct tq_struct set_link_task; -#else struct work_struct rst_timer_task; struct work_struct set_link_task; -#endif /* Flag that can be used to turn on or turn off the Rx checksum * offload feature. @@ -748,10 +767,23 @@ struct s2io_nic { atomic_t card_state; volatile unsigned long link_state; struct vlan_group *vlgrp; +#define MSIX_FLG 0xA5 + struct msix_entry *entries; + struct s2io_msix_entry *s2io_entries; + char desc1[35]; + char desc2[35]; + + struct msix_info_st msix_info[0x3f]; + #define XFRAME_I_DEVICE 1 #define XFRAME_II_DEVICE 2 u8 device_type; +#define INTA 0 +#define MSI 1 +#define MSI_X 2 + u8 intr_type; + spinlock_t rx_lock; atomic_t isr_cnt; }; @@ -886,6 +918,13 @@ static int s2io_poll(struct net_device *dev, int *budget); static void s2io_init_pci(nic_t * sp); int s2io_set_mac_addr(struct net_device *dev, u8 * addr); static void s2io_alarm_handle(unsigned long data); +static int s2io_enable_msi(nic_t *nic); +static irqreturn_t s2io_msi_handle(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t +s2io_msix_ring_handle(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t +s2io_msix_fifo_handle(int irq, void *dev_id, struct pt_regs *regs); +int s2io_enable_msi_x(nic_t *nic); static irqreturn_t s2io_isr(int irq, void *dev_id, struct pt_regs *regs); static int verify_xena_quiescence(nic_t *sp, u64 val64, int flag); static struct ethtool_ops netdev_ethtool_ops; @@ -894,4 +933,5 @@ int s2io_set_swapper(nic_t * sp); static void s2io_card_down(nic_t *nic); static int s2io_card_up(nic_t *nic); int get_xena_rev_id(struct pci_dev *pdev); +void restore_xmsi_data(nic_t *nic); #endif /* _S2IO_H */ diff --git a/drivers/net/saa9730.c b/drivers/net/saa9730.c index fd0167077fbe..110e777f206e 100644 --- a/drivers/net/saa9730.c +++ b/drivers/net/saa9730.c @@ -997,10 +997,7 @@ static void __devexit saa9730_remove_one(struct pci_dev *pdev) if (dev) { unregister_netdev(dev); - - if (dev->priv) - kfree(dev->priv); - + kfree(dev->priv); free_netdev(dev); pci_release_regions(pdev); pci_disable_device(pdev); @@ -1096,8 +1093,7 @@ static int lan_saa9730_init(struct net_device *dev, int ioaddr, int irq) return 0; out: - if (dev->priv) - kfree(dev->priv); + kfree(dev->priv); return ret; } diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c index 7abd55a4fb21..aa4ca1821759 100644 --- a/drivers/net/sb1250-mac.c +++ b/drivers/net/sb1250-mac.c @@ -10,7 +10,7 @@ * 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. @@ -118,8 +118,6 @@ MODULE_PARM_DESC(int_timeout, "Timeout value"); ********************************************************************* */ -typedef unsigned long sbmac_port_t; - typedef enum { sbmac_speed_auto, sbmac_speed_10, sbmac_speed_100, sbmac_speed_1000 } sbmac_speed_t; @@ -129,7 +127,7 @@ typedef enum { sbmac_duplex_auto, sbmac_duplex_half, typedef enum { sbmac_fc_auto, sbmac_fc_disabled, sbmac_fc_frame, sbmac_fc_collision, sbmac_fc_carrier } sbmac_fc_t; -typedef enum { sbmac_state_uninit, sbmac_state_off, sbmac_state_on, +typedef enum { sbmac_state_uninit, sbmac_state_off, sbmac_state_on, sbmac_state_broken } sbmac_state_t; @@ -144,17 +142,13 @@ typedef enum { sbmac_state_uninit, sbmac_state_off, sbmac_state_on, #define NUMCACHEBLKS(x) (((x)+SMP_CACHE_BYTES-1)/SMP_CACHE_BYTES) -#define SBMAC_READCSR(t) __raw_readq((unsigned long)t) -#define SBMAC_WRITECSR(t,v) __raw_writeq(v, (unsigned long)t) - - #define SBMAC_MAX_TXDESCR 32 #define SBMAC_MAX_RXDESCR 32 #define ETHER_ALIGN 2 #define ETHER_ADDR_LEN 6 -#define ENET_PACKET_SIZE 1518 -/*#define ENET_PACKET_SIZE 9216 */ +#define ENET_PACKET_SIZE 1518 +/*#define ENET_PACKET_SIZE 9216 */ /********************************************************************** * DMA Descriptor structure @@ -172,12 +166,12 @@ typedef unsigned long paddr_t; ********************************************************************* */ typedef struct sbmacdma_s { - - /* + + /* * This stuff is used to identify the channel and the registers * associated with it. */ - + struct sbmac_softc *sbdma_eth; /* back pointer to associated MAC */ int sbdma_channel; /* channel number */ int sbdma_txdir; /* direction (1=transmit) */ @@ -187,21 +181,21 @@ typedef struct sbmacdma_s { int sbdma_int_timeout; /* # usec rx/tx interrupt */ #endif - sbmac_port_t sbdma_config0; /* DMA config register 0 */ - sbmac_port_t sbdma_config1; /* DMA config register 1 */ - sbmac_port_t sbdma_dscrbase; /* Descriptor base address */ - sbmac_port_t sbdma_dscrcnt; /* Descriptor count register */ - sbmac_port_t sbdma_curdscr; /* current descriptor address */ - + volatile void __iomem *sbdma_config0; /* DMA config register 0 */ + volatile void __iomem *sbdma_config1; /* DMA config register 1 */ + volatile void __iomem *sbdma_dscrbase; /* Descriptor base address */ + volatile void __iomem *sbdma_dscrcnt; /* Descriptor count register */ + volatile void __iomem *sbdma_curdscr; /* current descriptor address */ + /* * This stuff is for maintenance of the ring */ - + sbdmadscr_t *sbdma_dscrtable; /* base of descriptor table */ sbdmadscr_t *sbdma_dscrtable_end; /* end of descriptor table */ - + struct sk_buff **sbdma_ctxtable; /* context table, one per descr */ - + paddr_t sbdma_dscrtable_phys; /* and also the phys addr */ sbdmadscr_t *sbdma_addptr; /* next dscr for sw to add */ sbdmadscr_t *sbdma_remptr; /* next dscr for sw to remove */ @@ -213,15 +207,15 @@ typedef struct sbmacdma_s { ********************************************************************* */ struct sbmac_softc { - + /* * Linux-specific things */ - + struct net_device *sbm_dev; /* pointer to linux device */ spinlock_t sbm_lock; /* spin lock */ struct timer_list sbm_timer; /* for monitoring MII */ - struct net_device_stats sbm_stats; + struct net_device_stats sbm_stats; int sbm_devflags; /* current device flags */ int sbm_phy_oldbmsr; @@ -229,31 +223,31 @@ struct sbmac_softc { int sbm_phy_oldk1stsr; int sbm_phy_oldlinkstat; int sbm_buffersize; - + unsigned char sbm_phys[2]; - + /* * Controller-specific things */ - - unsigned long sbm_base; /* MAC's base address */ + + volatile void __iomem *sbm_base; /* MAC's base address */ sbmac_state_t sbm_state; /* current state */ - - sbmac_port_t sbm_macenable; /* MAC Enable Register */ - sbmac_port_t sbm_maccfg; /* MAC Configuration Register */ - sbmac_port_t sbm_fifocfg; /* FIFO configuration register */ - sbmac_port_t sbm_framecfg; /* Frame configuration register */ - sbmac_port_t sbm_rxfilter; /* receive filter register */ - sbmac_port_t sbm_isr; /* Interrupt status register */ - sbmac_port_t sbm_imr; /* Interrupt mask register */ - sbmac_port_t sbm_mdio; /* MDIO register */ - + + volatile void __iomem *sbm_macenable; /* MAC Enable Register */ + volatile void __iomem *sbm_maccfg; /* MAC Configuration Register */ + volatile void __iomem *sbm_fifocfg; /* FIFO configuration register */ + volatile void __iomem *sbm_framecfg; /* Frame configuration register */ + volatile void __iomem *sbm_rxfilter; /* receive filter register */ + volatile void __iomem *sbm_isr; /* Interrupt status register */ + volatile void __iomem *sbm_imr; /* Interrupt mask register */ + volatile void __iomem *sbm_mdio; /* MDIO register */ + sbmac_speed_t sbm_speed; /* current speed */ sbmac_duplex_t sbm_duplex; /* current duplex */ sbmac_fc_t sbm_fc; /* current flow control setting */ - + unsigned char sbm_hwaddr[ETHER_ADDR_LEN]; - + sbmacdma_t sbm_txdma; /* for now, only use channel 0 */ sbmacdma_t sbm_rxdma; int rx_hw_checksum; @@ -302,6 +296,7 @@ static void sbmac_set_rx_mode(struct net_device *dev); static int sbmac_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static int sbmac_close(struct net_device *dev); static int sbmac_mii_poll(struct sbmac_softc *s,int noisy); +static int sbmac_mii_probe(struct net_device *dev); static void sbmac_mii_sync(struct sbmac_softc *s); static void sbmac_mii_senddata(struct sbmac_softc *s,unsigned int data, int bitcnt); @@ -439,6 +434,9 @@ static uint64_t sbmac_orig_hwaddr[MAX_UNITS]; #define MII_BMCR 0x00 /* Basic mode control register (rw) */ #define MII_BMSR 0x01 /* Basic mode status register (ro) */ +#define MII_PHYIDR1 0x02 +#define MII_PHYIDR2 0x03 + #define MII_K1STSR 0x0A /* 1K Status Register (ro) */ #define MII_ANLPAR 0x05 /* Autonegotiation lnk partner abilities (rw) */ @@ -450,13 +448,13 @@ static uint64_t sbmac_orig_hwaddr[MAX_UNITS]; /********************************************************************** * SBMAC_MII_SYNC(s) - * + * * Synchronize with the MII - send a pattern of bits to the MII * that will guarantee that it is ready to accept a command. - * - * Input parameters: + * + * Input parameters: * s - sbmac structure - * + * * Return value: * nothing ********************************************************************* */ @@ -467,25 +465,25 @@ static void sbmac_mii_sync(struct sbmac_softc *s) uint64_t bits; int mac_mdio_genc; - mac_mdio_genc = SBMAC_READCSR(s->sbm_mdio) & M_MAC_GENC; - + mac_mdio_genc = __raw_readq(s->sbm_mdio) & M_MAC_GENC; + bits = M_MAC_MDIO_DIR_OUTPUT | M_MAC_MDIO_OUT; - - SBMAC_WRITECSR(s->sbm_mdio,bits | mac_mdio_genc); - + + __raw_writeq(bits | mac_mdio_genc, s->sbm_mdio); + for (cnt = 0; cnt < 32; cnt++) { - SBMAC_WRITECSR(s->sbm_mdio,bits | M_MAC_MDC | mac_mdio_genc); - SBMAC_WRITECSR(s->sbm_mdio,bits | mac_mdio_genc); + __raw_writeq(bits | M_MAC_MDC | mac_mdio_genc, s->sbm_mdio); + __raw_writeq(bits | mac_mdio_genc, s->sbm_mdio); } } /********************************************************************** * SBMAC_MII_SENDDATA(s,data,bitcnt) - * + * * Send some bits to the MII. The bits to be sent are right- * justified in the 'data' parameter. - * - * Input parameters: + * + * Input parameters: * s - sbmac structure * data - data to send * bitcnt - number of bits to send @@ -498,20 +496,20 @@ static void sbmac_mii_senddata(struct sbmac_softc *s,unsigned int data, int bitc unsigned int curmask; int mac_mdio_genc; - mac_mdio_genc = SBMAC_READCSR(s->sbm_mdio) & M_MAC_GENC; - + mac_mdio_genc = __raw_readq(s->sbm_mdio) & M_MAC_GENC; + bits = M_MAC_MDIO_DIR_OUTPUT; - SBMAC_WRITECSR(s->sbm_mdio,bits | mac_mdio_genc); - + __raw_writeq(bits | mac_mdio_genc, s->sbm_mdio); + curmask = 1 << (bitcnt - 1); - + for (i = 0; i < bitcnt; i++) { if (data & curmask) bits |= M_MAC_MDIO_OUT; else bits &= ~M_MAC_MDIO_OUT; - SBMAC_WRITECSR(s->sbm_mdio,bits | mac_mdio_genc); - SBMAC_WRITECSR(s->sbm_mdio,bits | M_MAC_MDC | mac_mdio_genc); - SBMAC_WRITECSR(s->sbm_mdio,bits | mac_mdio_genc); + __raw_writeq(bits | mac_mdio_genc, s->sbm_mdio); + __raw_writeq(bits | M_MAC_MDC | mac_mdio_genc, s->sbm_mdio); + __raw_writeq(bits | mac_mdio_genc, s->sbm_mdio); curmask >>= 1; } } @@ -520,14 +518,14 @@ static void sbmac_mii_senddata(struct sbmac_softc *s,unsigned int data, int bitc /********************************************************************** * SBMAC_MII_READ(s,phyaddr,regidx) - * + * * Read a PHY register. - * - * Input parameters: + * + * Input parameters: * s - sbmac structure * phyaddr - PHY's address * regidx = index of register to read - * + * * Return value: * value read, or 0 if an error occurred. ********************************************************************* */ @@ -543,9 +541,9 @@ static unsigned int sbmac_mii_read(struct sbmac_softc *s,int phyaddr,int regidx) * Synchronize ourselves so that the PHY knows the next * thing coming down is a command */ - + sbmac_mii_sync(s); - + /* * Send the data to the PHY. The sequence is * a "start" command (2 bits) @@ -553,59 +551,55 @@ static unsigned int sbmac_mii_read(struct sbmac_softc *s,int phyaddr,int regidx) * the PHY addr (5 bits) * the register index (5 bits) */ - + sbmac_mii_senddata(s,MII_COMMAND_START, 2); sbmac_mii_senddata(s,MII_COMMAND_READ, 2); sbmac_mii_senddata(s,phyaddr, 5); sbmac_mii_senddata(s,regidx, 5); - - mac_mdio_genc = SBMAC_READCSR(s->sbm_mdio) & M_MAC_GENC; - - /* + + mac_mdio_genc = __raw_readq(s->sbm_mdio) & M_MAC_GENC; + + /* * Switch the port around without a clock transition. */ - SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT | mac_mdio_genc); - + __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, s->sbm_mdio); + /* * Send out a clock pulse to signal we want the status */ - - SBMAC_WRITECSR(s->sbm_mdio, - M_MAC_MDIO_DIR_INPUT | M_MAC_MDC | mac_mdio_genc); - SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT | mac_mdio_genc); - - /* + + __raw_writeq(M_MAC_MDIO_DIR_INPUT | M_MAC_MDC | mac_mdio_genc, s->sbm_mdio); + __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, s->sbm_mdio); + + /* * If an error occurred, the PHY will signal '1' back */ - error = SBMAC_READCSR(s->sbm_mdio) & M_MAC_MDIO_IN; - - /* + error = __raw_readq(s->sbm_mdio) & M_MAC_MDIO_IN; + + /* * Issue an 'idle' clock pulse, but keep the direction * the same. */ - SBMAC_WRITECSR(s->sbm_mdio, - M_MAC_MDIO_DIR_INPUT | M_MAC_MDC | mac_mdio_genc); - SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT | mac_mdio_genc); - + __raw_writeq(M_MAC_MDIO_DIR_INPUT | M_MAC_MDC | mac_mdio_genc, s->sbm_mdio); + __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, s->sbm_mdio); + regval = 0; - + for (idx = 0; idx < 16; idx++) { regval <<= 1; - + if (error == 0) { - if (SBMAC_READCSR(s->sbm_mdio) & M_MAC_MDIO_IN) + if (__raw_readq(s->sbm_mdio) & M_MAC_MDIO_IN) regval |= 1; } - - SBMAC_WRITECSR(s->sbm_mdio, - M_MAC_MDIO_DIR_INPUT|M_MAC_MDC | mac_mdio_genc); - SBMAC_WRITECSR(s->sbm_mdio, - M_MAC_MDIO_DIR_INPUT | mac_mdio_genc); + + __raw_writeq(M_MAC_MDIO_DIR_INPUT|M_MAC_MDC | mac_mdio_genc, s->sbm_mdio); + __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, s->sbm_mdio); } - + /* Switch back to output */ - SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_OUTPUT | mac_mdio_genc); - + __raw_writeq(M_MAC_MDIO_DIR_OUTPUT | mac_mdio_genc, s->sbm_mdio); + if (error == 0) return regval; return 0; @@ -614,15 +608,15 @@ static unsigned int sbmac_mii_read(struct sbmac_softc *s,int phyaddr,int regidx) /********************************************************************** * SBMAC_MII_WRITE(s,phyaddr,regidx,regval) - * + * * Write a value to a PHY register. - * - * Input parameters: + * + * Input parameters: * s - sbmac structure * phyaddr - PHY to use * regidx - register within the PHY * regval - data to write to register - * + * * Return value: * nothing ********************************************************************* */ @@ -633,7 +627,7 @@ static void sbmac_mii_write(struct sbmac_softc *s,int phyaddr,int regidx, int mac_mdio_genc; sbmac_mii_sync(s); - + sbmac_mii_senddata(s,MII_COMMAND_START,2); sbmac_mii_senddata(s,MII_COMMAND_WRITE,2); sbmac_mii_senddata(s,phyaddr, 5); @@ -641,27 +635,27 @@ static void sbmac_mii_write(struct sbmac_softc *s,int phyaddr,int regidx, sbmac_mii_senddata(s,MII_COMMAND_ACK,2); sbmac_mii_senddata(s,regval,16); - mac_mdio_genc = SBMAC_READCSR(s->sbm_mdio) & M_MAC_GENC; + mac_mdio_genc = __raw_readq(s->sbm_mdio) & M_MAC_GENC; - SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_OUTPUT | mac_mdio_genc); + __raw_writeq(M_MAC_MDIO_DIR_OUTPUT | mac_mdio_genc, s->sbm_mdio); } /********************************************************************** * SBDMA_INITCTX(d,s,chan,txrx,maxdescr) - * + * * Initialize a DMA channel context. Since there are potentially * eight DMA channels per MAC, it's nice to do this in a standard - * way. - * - * Input parameters: + * way. + * + * Input parameters: * d - sbmacdma_t structure (DMA channel context) * s - sbmac_softc structure (pointer to a MAC) * chan - channel number (0..1 right now) * txrx - Identifies DMA_TX or DMA_RX for channel direction * maxdescr - number of descriptors - * + * * Return value: * nothing ********************************************************************* */ @@ -672,101 +666,87 @@ static void sbdma_initctx(sbmacdma_t *d, int txrx, int maxdescr) { - /* - * Save away interesting stuff in the structure + /* + * Save away interesting stuff in the structure */ - + d->sbdma_eth = s; d->sbdma_channel = chan; d->sbdma_txdir = txrx; - + #if 0 /* RMON clearing */ s->sbe_idx =(s->sbm_base - A_MAC_BASE_0)/MAC_SPACING; #endif - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_BYTES)), 0); - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_COLLISIONS)), 0); - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_LATE_COL)), 0); - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_EX_COL)), 0); - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_FCS_ERROR)), 0); - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_ABORT)), 0); - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_BAD)), 0); - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_GOOD)), 0); - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_RUNT)), 0); - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_OVERSIZE)), 0); - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_BYTES)), 0); - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_MCAST)), 0); - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_BCAST)), 0); - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_BAD)), 0); - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_GOOD)), 0); - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_RUNT)), 0); - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_OVERSIZE)), 0); - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_FCS_ERROR)), 0); - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_LENGTH_ERROR)), 0); - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_CODE_ERROR)), 0); - SBMAC_WRITECSR(IOADDR( - A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_ALIGN_ERROR)), 0); - - /* - * initialize register pointers - */ - - d->sbdma_config0 = + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_BYTES))); + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_COLLISIONS))); + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_LATE_COL))); + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_EX_COL))); + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_FCS_ERROR))); + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_ABORT))); + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_BAD))); + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_GOOD))); + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_RUNT))); + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_OVERSIZE))); + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_BYTES))); + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_MCAST))); + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_BCAST))); + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_BAD))); + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_GOOD))); + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_RUNT))); + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_OVERSIZE))); + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_FCS_ERROR))); + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_LENGTH_ERROR))); + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_CODE_ERROR))); + __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_ALIGN_ERROR))); + + /* + * initialize register pointers + */ + + d->sbdma_config0 = s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_CONFIG0); - d->sbdma_config1 = + d->sbdma_config1 = s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_CONFIG1); - d->sbdma_dscrbase = + d->sbdma_dscrbase = s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_DSCR_BASE); - d->sbdma_dscrcnt = + d->sbdma_dscrcnt = s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_DSCR_CNT); - d->sbdma_curdscr = + d->sbdma_curdscr = s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_CUR_DSCRADDR); - + /* * Allocate memory for the ring */ - + d->sbdma_maxdescr = maxdescr; - - d->sbdma_dscrtable = (sbdmadscr_t *) - kmalloc(d->sbdma_maxdescr*sizeof(sbdmadscr_t), GFP_KERNEL); - + + d->sbdma_dscrtable = (sbdmadscr_t *) + kmalloc((d->sbdma_maxdescr+1)*sizeof(sbdmadscr_t), GFP_KERNEL); + + /* + * The descriptor table must be aligned to at least 16 bytes or the + * MAC will corrupt it. + */ + d->sbdma_dscrtable = (sbdmadscr_t *) + ALIGN((unsigned long)d->sbdma_dscrtable, sizeof(sbdmadscr_t)); + memset(d->sbdma_dscrtable,0,d->sbdma_maxdescr*sizeof(sbdmadscr_t)); - + d->sbdma_dscrtable_end = d->sbdma_dscrtable + d->sbdma_maxdescr; - + d->sbdma_dscrtable_phys = virt_to_phys(d->sbdma_dscrtable); - + /* * And context table */ - - d->sbdma_ctxtable = (struct sk_buff **) + + d->sbdma_ctxtable = (struct sk_buff **) kmalloc(d->sbdma_maxdescr*sizeof(struct sk_buff *), GFP_KERNEL); - + memset(d->sbdma_ctxtable,0,d->sbdma_maxdescr*sizeof(struct sk_buff *)); - + #ifdef CONFIG_SBMAC_COALESCE /* * Setup Rx/Tx DMA coalescing defaults @@ -777,7 +757,7 @@ static void sbdma_initctx(sbmacdma_t *d, } else { d->sbdma_int_pktcnt = 1; } - + if ( int_timeout ) { d->sbdma_int_timeout = int_timeout; } else { @@ -789,13 +769,13 @@ static void sbdma_initctx(sbmacdma_t *d, /********************************************************************** * SBDMA_CHANNEL_START(d) - * + * * Initialize the hardware registers for a DMA channel. - * - * Input parameters: + * + * Input parameters: * d - DMA channel to init (context must be previously init'd * rxtx - DMA_RX or DMA_TX depending on what type of channel - * + * * Return value: * nothing ********************************************************************* */ @@ -805,24 +785,21 @@ static void sbdma_channel_start(sbmacdma_t *d, int rxtx ) /* * Turn on the DMA channel */ - + #ifdef CONFIG_SBMAC_COALESCE - SBMAC_WRITECSR(d->sbdma_config1, - V_DMA_INT_TIMEOUT(d->sbdma_int_timeout) | - 0); - SBMAC_WRITECSR(d->sbdma_config0, - M_DMA_EOP_INT_EN | + __raw_writeq(V_DMA_INT_TIMEOUT(d->sbdma_int_timeout) | + 0, d->sbdma_config1); + __raw_writeq(M_DMA_EOP_INT_EN | V_DMA_RINGSZ(d->sbdma_maxdescr) | V_DMA_INT_PKTCNT(d->sbdma_int_pktcnt) | - 0); + 0, d->sbdma_config0); #else - SBMAC_WRITECSR(d->sbdma_config1,0); - SBMAC_WRITECSR(d->sbdma_config0, - V_DMA_RINGSZ(d->sbdma_maxdescr) | - 0); + __raw_writeq(0, d->sbdma_config1); + __raw_writeq(V_DMA_RINGSZ(d->sbdma_maxdescr) | + 0, d->sbdma_config0); #endif - SBMAC_WRITECSR(d->sbdma_dscrbase,d->sbdma_dscrtable_phys); + __raw_writeq(d->sbdma_dscrtable_phys, d->sbdma_dscrbase); /* * Initialize ring pointers @@ -834,12 +811,12 @@ static void sbdma_channel_start(sbmacdma_t *d, int rxtx ) /********************************************************************** * SBDMA_CHANNEL_STOP(d) - * + * * Initialize the hardware registers for a DMA channel. - * - * Input parameters: + * + * Input parameters: * d - DMA channel to init (context must be previously init'd - * + * * Return value: * nothing ********************************************************************* */ @@ -849,44 +826,44 @@ static void sbdma_channel_stop(sbmacdma_t *d) /* * Turn off the DMA channel */ - - SBMAC_WRITECSR(d->sbdma_config1,0); - - SBMAC_WRITECSR(d->sbdma_dscrbase,0); - - SBMAC_WRITECSR(d->sbdma_config0,0); - + + __raw_writeq(0, d->sbdma_config1); + + __raw_writeq(0, d->sbdma_dscrbase); + + __raw_writeq(0, d->sbdma_config0); + /* * Zero ring pointers */ - - d->sbdma_addptr = 0; - d->sbdma_remptr = 0; + + d->sbdma_addptr = NULL; + d->sbdma_remptr = NULL; } static void sbdma_align_skb(struct sk_buff *skb,int power2,int offset) { unsigned long addr; unsigned long newaddr; - + addr = (unsigned long) skb->data; - + newaddr = (addr + power2 - 1) & ~(power2 - 1); - + skb_reserve(skb,newaddr-addr+offset); } /********************************************************************** * SBDMA_ADD_RCVBUFFER(d,sb) - * + * * Add a buffer to the specified DMA channel. For receive channels, * this queues a buffer for inbound packets. - * - * Input parameters: + * + * Input parameters: * d - DMA channel descriptor * sb - sk_buff to add, or NULL if we should allocate one - * + * * Return value: * 0 if buffer could not be added (ring is full) * 1 if buffer added successfully @@ -899,24 +876,24 @@ static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *sb) sbdmadscr_t *nextdsc; struct sk_buff *sb_new = NULL; int pktsize = ENET_PACKET_SIZE; - + /* get pointer to our current place in the ring */ - + dsc = d->sbdma_addptr; nextdsc = SBDMA_NEXTBUF(d,sbdma_addptr); - + /* * figure out if the ring is full - if the next descriptor * is the same as the one that we're going to remove from * the ring, the ring is full */ - + if (nextdsc == d->sbdma_remptr) { return -ENOSPC; } - /* - * Allocate a sk_buff if we don't already have one. + /* + * Allocate a sk_buff if we don't already have one. * If we do have an sk_buff, reset it so that it's empty. * * Note: sk_buffs don't seem to be guaranteed to have any sort @@ -925,7 +902,7 @@ static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *sb) * * 1. the data does not start in the middle of a cache line. * 2. The data does not end in the middle of a cache line - * 3. The buffer can be aligned such that the IP addresses are + * 3. The buffer can be aligned such that the IP addresses are * naturally aligned. * * Remember, the SOCs MAC writes whole cache lines at a time, @@ -933,7 +910,7 @@ static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *sb) * data portion starts in the middle of a cache line, the SOC * DMA will trash the beginning (and ending) portions. */ - + if (sb == NULL) { sb_new = dev_alloc_skb(ENET_PACKET_SIZE + SMP_CACHE_BYTES * 2 + ETHER_ALIGN); if (sb_new == NULL) { @@ -949,23 +926,22 @@ static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *sb) } else { sb_new = sb; - /* + /* * nothing special to reinit buffer, it's already aligned * and sb->data already points to a good place. */ } - + /* - * fill in the descriptor + * fill in the descriptor */ - + #ifdef CONFIG_SBMAC_COALESCE /* * Do not interrupt per DMA transfer. */ dsc->dscr_a = virt_to_phys(sb_new->data) | - V_DMA_DSCRA_A_SIZE(NUMCACHEBLKS(pktsize+ETHER_ALIGN)) | - 0; + V_DMA_DSCRA_A_SIZE(NUMCACHEBLKS(pktsize+ETHER_ALIGN)) | 0; #else dsc->dscr_a = virt_to_phys(sb_new->data) | V_DMA_DSCRA_A_SIZE(NUMCACHEBLKS(pktsize+ETHER_ALIGN)) | @@ -974,38 +950,38 @@ static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *sb) /* receiving: no options */ dsc->dscr_b = 0; - + /* - * fill in the context + * fill in the context */ - + d->sbdma_ctxtable[dsc-d->sbdma_dscrtable] = sb_new; - - /* - * point at next packet + + /* + * point at next packet */ - + d->sbdma_addptr = nextdsc; - - /* + + /* * Give the buffer to the DMA engine. */ - - SBMAC_WRITECSR(d->sbdma_dscrcnt,1); - + + __raw_writeq(1, d->sbdma_dscrcnt); + return 0; /* we did it */ } /********************************************************************** * SBDMA_ADD_TXBUFFER(d,sb) - * + * * Add a transmit buffer to the specified DMA channel, causing a * transmit to start. - * - * Input parameters: + * + * Input parameters: * d - DMA channel descriptor * sb - sk_buff to add - * + * * Return value: * 0 transmit queued successfully * otherwise error code @@ -1019,70 +995,70 @@ static int sbdma_add_txbuffer(sbmacdma_t *d,struct sk_buff *sb) uint64_t phys; uint64_t ncb; int length; - + /* get pointer to our current place in the ring */ - + dsc = d->sbdma_addptr; nextdsc = SBDMA_NEXTBUF(d,sbdma_addptr); - + /* * figure out if the ring is full - if the next descriptor * is the same as the one that we're going to remove from * the ring, the ring is full */ - + if (nextdsc == d->sbdma_remptr) { return -ENOSPC; } - + /* * Under Linux, it's not necessary to copy/coalesce buffers * like it is on NetBSD. We think they're all contiguous, * but that may not be true for GBE. */ - + length = sb->len; - + /* * fill in the descriptor. Note that the number of cache * blocks in the descriptor is the number of blocks * *spanned*, so we need to add in the offset (if any) * while doing the calculation. */ - + phys = virt_to_phys(sb->data); ncb = NUMCACHEBLKS(length+(phys & (SMP_CACHE_BYTES - 1))); - dsc->dscr_a = phys | + dsc->dscr_a = phys | V_DMA_DSCRA_A_SIZE(ncb) | #ifndef CONFIG_SBMAC_COALESCE M_DMA_DSCRA_INTERRUPT | #endif M_DMA_ETHTX_SOP; - + /* transmitting: set outbound options and length */ dsc->dscr_b = V_DMA_DSCRB_OPTIONS(K_DMA_ETHTX_APPENDCRC_APPENDPAD) | V_DMA_DSCRB_PKT_SIZE(length); - + /* - * fill in the context + * fill in the context */ - + d->sbdma_ctxtable[dsc-d->sbdma_dscrtable] = sb; - - /* - * point at next packet + + /* + * point at next packet */ - + d->sbdma_addptr = nextdsc; - - /* + + /* * Give the buffer to the DMA engine. */ - - SBMAC_WRITECSR(d->sbdma_dscrcnt,1); - + + __raw_writeq(1, d->sbdma_dscrcnt); + return 0; /* we did it */ } @@ -1091,12 +1067,12 @@ static int sbdma_add_txbuffer(sbmacdma_t *d,struct sk_buff *sb) /********************************************************************** * SBDMA_EMPTYRING(d) - * + * * Free all allocated sk_buffs on the specified DMA channel; - * - * Input parameters: + * + * Input parameters: * d - DMA channel - * + * * Return value: * nothing ********************************************************************* */ @@ -1105,7 +1081,7 @@ static void sbdma_emptyring(sbmacdma_t *d) { int idx; struct sk_buff *sb; - + for (idx = 0; idx < d->sbdma_maxdescr; idx++) { sb = d->sbdma_ctxtable[idx]; if (sb) { @@ -1118,13 +1094,13 @@ static void sbdma_emptyring(sbmacdma_t *d) /********************************************************************** * SBDMA_FILLRING(d) - * + * * Fill the specified DMA channel (must be receive channel) * with sk_buffs - * - * Input parameters: + * + * Input parameters: * d - DMA channel - * + * * Return value: * nothing ********************************************************************* */ @@ -1132,7 +1108,7 @@ static void sbdma_emptyring(sbmacdma_t *d) static void sbdma_fillring(sbmacdma_t *d) { int idx; - + for (idx = 0; idx < SBMAC_MAX_RXDESCR-1; idx++) { if (sbdma_add_rcvbuffer(d,NULL) != 0) break; @@ -1142,16 +1118,16 @@ static void sbdma_fillring(sbmacdma_t *d) /********************************************************************** * SBDMA_RX_PROCESS(sc,d) - * - * Process "completed" receive buffers on the specified DMA channel. + * + * Process "completed" receive buffers on the specified DMA channel. * Note that this isn't really ideal for priority channels, since - * it processes all of the packets on a given channel before - * returning. + * it processes all of the packets on a given channel before + * returning. * - * Input parameters: + * Input parameters: * sc - softc structure * d - DMA channel context - * + * * Return value: * nothing ********************************************************************* */ @@ -1163,56 +1139,56 @@ static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d) sbdmadscr_t *dsc; struct sk_buff *sb; int len; - + for (;;) { - /* + /* * figure out where we are (as an index) and where * the hardware is (also as an index) * - * This could be done faster if (for example) the + * This could be done faster if (for example) the * descriptor table was page-aligned and contiguous in * both virtual and physical memory -- you could then * just compare the low-order bits of the virtual address * (sbdma_remptr) and the physical address (sbdma_curdscr CSR) */ - + curidx = d->sbdma_remptr - d->sbdma_dscrtable; - hwidx = (int) (((SBMAC_READCSR(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) - + hwidx = (int) (((__raw_readq(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) - d->sbdma_dscrtable_phys) / sizeof(sbdmadscr_t)); - + /* * If they're the same, that means we've processed all * of the descriptors up to (but not including) the one that * the hardware is working on right now. */ - + if (curidx == hwidx) break; - + /* * Otherwise, get the packet's sk_buff ptr back */ - + dsc = &(d->sbdma_dscrtable[curidx]); sb = d->sbdma_ctxtable[curidx]; d->sbdma_ctxtable[curidx] = NULL; - + len = (int)G_DMA_DSCRB_PKT_SIZE(dsc->dscr_b) - 4; - + /* * Check packet status. If good, process it. * If not, silently drop it and put it back on the * receive ring. */ - + if (!(dsc->dscr_a & M_DMA_ETHRX_BAD)) { - + /* * Add a new buffer to replace the old one. If we fail * to allocate a buffer, we're going to drop this * packet and put it right back on the receive ring. */ - + if (sbdma_add_rcvbuffer(d,NULL) == -ENOBUFS) { sc->sbm_stats.rx_dropped++; sbdma_add_rcvbuffer(d,sb); /* re-add old buffer */ @@ -1221,7 +1197,7 @@ static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d) * Set length into the packet */ skb_put(sb,len); - + /* * Buffer has been replaced on the * receive ring. Pass the buffer to @@ -1240,7 +1216,7 @@ static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d) sb->ip_summed = CHECKSUM_NONE; } } - + netif_rx(sb); } } else { @@ -1251,14 +1227,14 @@ static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d) sc->sbm_stats.rx_errors++; sbdma_add_rcvbuffer(d,sb); } - - - /* + + + /* * .. and advance to the next buffer. */ - + d->sbdma_remptr = SBDMA_NEXTBUF(d,sbdma_remptr); - + } } @@ -1266,17 +1242,17 @@ static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d) /********************************************************************** * SBDMA_TX_PROCESS(sc,d) - * - * Process "completed" transmit buffers on the specified DMA channel. + * + * Process "completed" transmit buffers on the specified DMA channel. * This is normally called within the interrupt service routine. * Note that this isn't really ideal for priority channels, since - * it processes all of the packets on a given channel before - * returning. + * it processes all of the packets on a given channel before + * returning. * - * Input parameters: + * Input parameters: * sc - softc structure * d - DMA channel context - * + * * Return value: * nothing ********************************************************************* */ @@ -1290,21 +1266,21 @@ static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d) unsigned long flags; spin_lock_irqsave(&(sc->sbm_lock), flags); - + for (;;) { - /* + /* * figure out where we are (as an index) and where * the hardware is (also as an index) * - * This could be done faster if (for example) the + * This could be done faster if (for example) the * descriptor table was page-aligned and contiguous in * both virtual and physical memory -- you could then * just compare the low-order bits of the virtual address * (sbdma_remptr) and the physical address (sbdma_curdscr CSR) */ - + curidx = d->sbdma_remptr - d->sbdma_dscrtable; - hwidx = (int) (((SBMAC_READCSR(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) - + hwidx = (int) (((__raw_readq(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) - d->sbdma_dscrtable_phys) / sizeof(sbdmadscr_t)); /* @@ -1312,75 +1288,75 @@ static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d) * of the descriptors up to (but not including) the one that * the hardware is working on right now. */ - + if (curidx == hwidx) break; - + /* * Otherwise, get the packet's sk_buff ptr back */ - + dsc = &(d->sbdma_dscrtable[curidx]); sb = d->sbdma_ctxtable[curidx]; d->sbdma_ctxtable[curidx] = NULL; - + /* * Stats */ - + sc->sbm_stats.tx_bytes += sb->len; sc->sbm_stats.tx_packets++; - + /* * for transmits, we just free buffers. */ - + dev_kfree_skb_irq(sb); - - /* + + /* * .. and advance to the next buffer. */ d->sbdma_remptr = SBDMA_NEXTBUF(d,sbdma_remptr); - + } - + /* * Decide if we should wake up the protocol or not. * Other drivers seem to do this when we reach a low * watermark on the transmit queue. */ - + netif_wake_queue(d->sbdma_eth->sbm_dev); - + spin_unlock_irqrestore(&(sc->sbm_lock), flags); - + } /********************************************************************** * SBMAC_INITCTX(s) - * + * * Initialize an Ethernet context structure - this is called * once per MAC on the 1250. Memory is allocated here, so don't * call it again from inside the ioctl routines that bring the * interface up/down - * - * Input parameters: + * + * Input parameters: * s - sbmac context structure - * + * * Return value: * 0 ********************************************************************* */ static int sbmac_initctx(struct sbmac_softc *s) { - - /* - * figure out the addresses of some ports + + /* + * figure out the addresses of some ports */ - + s->sbm_macenable = s->sbm_base + R_MAC_ENABLE; s->sbm_maccfg = s->sbm_base + R_MAC_CFG; s->sbm_fifocfg = s->sbm_base + R_MAC_THRSH_CFG; @@ -1397,29 +1373,29 @@ static int sbmac_initctx(struct sbmac_softc *s) s->sbm_phy_oldanlpar = 0; s->sbm_phy_oldk1stsr = 0; s->sbm_phy_oldlinkstat = 0; - + /* * Initialize the DMA channels. Right now, only one per MAC is used * Note: Only do this _once_, as it allocates memory from the kernel! */ - + sbdma_initctx(&(s->sbm_txdma),s,0,DMA_TX,SBMAC_MAX_TXDESCR); sbdma_initctx(&(s->sbm_rxdma),s,0,DMA_RX,SBMAC_MAX_RXDESCR); - + /* * initial state is OFF */ - + s->sbm_state = sbmac_state_off; - + /* * Initial speed is (XXX TEMP) 10MBit/s HDX no FC */ - + s->sbm_speed = sbmac_speed_10; s->sbm_duplex = sbmac_duplex_half; s->sbm_fc = sbmac_fc_disabled; - + return 0; } @@ -1430,7 +1406,7 @@ static void sbdma_uninitctx(struct sbmacdma_s *d) kfree(d->sbdma_dscrtable); d->sbdma_dscrtable = NULL; } - + if (d->sbdma_ctxtable) { kfree(d->sbdma_ctxtable); d->sbdma_ctxtable = NULL; @@ -1447,12 +1423,12 @@ static void sbmac_uninitctx(struct sbmac_softc *sc) /********************************************************************** * SBMAC_CHANNEL_START(s) - * + * * Start packet processing on this MAC. - * - * Input parameters: + * + * Input parameters: * s - sbmac structure - * + * * Return value: * nothing ********************************************************************* */ @@ -1460,49 +1436,49 @@ static void sbmac_uninitctx(struct sbmac_softc *sc) static void sbmac_channel_start(struct sbmac_softc *s) { uint64_t reg; - sbmac_port_t port; + volatile void __iomem *port; uint64_t cfg,fifo,framecfg; int idx, th_value; - + /* * Don't do this if running */ if (s->sbm_state == sbmac_state_on) return; - + /* * Bring the controller out of reset, but leave it off. */ - - SBMAC_WRITECSR(s->sbm_macenable,0); - + + __raw_writeq(0, s->sbm_macenable); + /* * Ignore all received packets */ - - SBMAC_WRITECSR(s->sbm_rxfilter,0); - - /* + + __raw_writeq(0, s->sbm_rxfilter); + + /* * Calculate values for various control registers. */ - + cfg = M_MAC_RETRY_EN | - M_MAC_TX_HOLD_SOP_EN | + M_MAC_TX_HOLD_SOP_EN | V_MAC_TX_PAUSE_CNT_16K | M_MAC_AP_STAT_EN | M_MAC_FAST_SYNC | M_MAC_SS_EN | 0; - - /* + + /* * Be sure that RD_THRSH+WR_THRSH <= 32 for pass1 pars * and make sure that RD_THRSH + WR_THRSH <=128 for pass2 and above * Use a larger RD_THRSH for gigabit */ - if (periph_rev >= 2) + if (periph_rev >= 2) th_value = 64; - else + else th_value = 28; fifo = V_MAC_TX_WR_THRSH(4) | /* Must be '4' or '8' */ @@ -1520,51 +1496,51 @@ static void sbmac_channel_start(struct sbmac_softc *s) V_MAC_BACKOFF_SEL(1); /* - * Clear out the hash address map + * Clear out the hash address map */ - + port = s->sbm_base + R_MAC_HASH_BASE; for (idx = 0; idx < MAC_HASH_COUNT; idx++) { - SBMAC_WRITECSR(port,0); + __raw_writeq(0, port); port += sizeof(uint64_t); } - + /* * Clear out the exact-match table */ - + port = s->sbm_base + R_MAC_ADDR_BASE; for (idx = 0; idx < MAC_ADDR_COUNT; idx++) { - SBMAC_WRITECSR(port,0); + __raw_writeq(0, port); port += sizeof(uint64_t); } - + /* * Clear out the DMA Channel mapping table registers */ - + port = s->sbm_base + R_MAC_CHUP0_BASE; for (idx = 0; idx < MAC_CHMAP_COUNT; idx++) { - SBMAC_WRITECSR(port,0); + __raw_writeq(0, port); port += sizeof(uint64_t); } port = s->sbm_base + R_MAC_CHLO0_BASE; for (idx = 0; idx < MAC_CHMAP_COUNT; idx++) { - SBMAC_WRITECSR(port,0); + __raw_writeq(0, port); port += sizeof(uint64_t); } - + /* * Program the hardware address. It goes into the hardware-address * register as well as the first filter register. */ - + reg = sbmac_addr2reg(s->sbm_hwaddr); - + port = s->sbm_base + R_MAC_ADDR_BASE; - SBMAC_WRITECSR(port,reg); + __raw_writeq(reg, port); port = s->sbm_base + R_MAC_ETHERNET_ADDR; #ifdef CONFIG_SB1_PASS_1_WORKAROUNDS @@ -1573,108 +1549,105 @@ static void sbmac_channel_start(struct sbmac_softc *s) * destination address in the R_MAC_ETHERNET_ADDR register. * Set the value to zero. */ - SBMAC_WRITECSR(port,0); + __raw_writeq(0, port); #else - SBMAC_WRITECSR(port,reg); + __raw_writeq(reg, port); #endif - + /* * Set the receive filter for no packets, and write values * to the various config registers */ - - SBMAC_WRITECSR(s->sbm_rxfilter,0); - SBMAC_WRITECSR(s->sbm_imr,0); - SBMAC_WRITECSR(s->sbm_framecfg,framecfg); - SBMAC_WRITECSR(s->sbm_fifocfg,fifo); - SBMAC_WRITECSR(s->sbm_maccfg,cfg); - + + __raw_writeq(0, s->sbm_rxfilter); + __raw_writeq(0, s->sbm_imr); + __raw_writeq(framecfg, s->sbm_framecfg); + __raw_writeq(fifo, s->sbm_fifocfg); + __raw_writeq(cfg, s->sbm_maccfg); + /* * Initialize DMA channels (rings should be ok now) */ - + sbdma_channel_start(&(s->sbm_rxdma), DMA_RX); sbdma_channel_start(&(s->sbm_txdma), DMA_TX); - + /* * Configure the speed, duplex, and flow control */ sbmac_set_speed(s,s->sbm_speed); sbmac_set_duplex(s,s->sbm_duplex,s->sbm_fc); - + /* * Fill the receive ring */ - + sbdma_fillring(&(s->sbm_rxdma)); - - /* + + /* * Turn on the rest of the bits in the enable register - */ - - SBMAC_WRITECSR(s->sbm_macenable, - M_MAC_RXDMA_EN0 | + */ + + __raw_writeq(M_MAC_RXDMA_EN0 | M_MAC_TXDMA_EN0 | M_MAC_RX_ENABLE | - M_MAC_TX_ENABLE); - - + M_MAC_TX_ENABLE, s->sbm_macenable); + + #ifdef CONFIG_SBMAC_COALESCE /* * Accept any TX interrupt and EOP count/timer RX interrupts on ch 0 */ - SBMAC_WRITECSR(s->sbm_imr, - ((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_TX_CH0) | - ((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_RX_CH0)); + __raw_writeq(((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_TX_CH0) | + ((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_RX_CH0), s->sbm_imr); #else /* * Accept any kind of interrupt on TX and RX DMA channel 0 */ - SBMAC_WRITECSR(s->sbm_imr, - (M_MAC_INT_CHANNEL << S_MAC_TX_CH0) | - (M_MAC_INT_CHANNEL << S_MAC_RX_CH0)); + __raw_writeq((M_MAC_INT_CHANNEL << S_MAC_TX_CH0) | + (M_MAC_INT_CHANNEL << S_MAC_RX_CH0), s->sbm_imr); #endif - - /* - * Enable receiving unicasts and broadcasts + + /* + * Enable receiving unicasts and broadcasts */ - - SBMAC_WRITECSR(s->sbm_rxfilter,M_MAC_UCAST_EN | M_MAC_BCAST_EN); - + + __raw_writeq(M_MAC_UCAST_EN | M_MAC_BCAST_EN, s->sbm_rxfilter); + /* - * we're running now. + * we're running now. */ - + s->sbm_state = sbmac_state_on; - - /* - * Program multicast addresses + + /* + * Program multicast addresses */ - + sbmac_setmulti(s); - - /* - * If channel was in promiscuous mode before, turn that on + + /* + * If channel was in promiscuous mode before, turn that on */ - + if (s->sbm_devflags & IFF_PROMISC) { sbmac_promiscuous_mode(s,1); } - + } /********************************************************************** * SBMAC_CHANNEL_STOP(s) - * + * * Stop packet processing on this MAC. - * - * Input parameters: + * + * Input parameters: * s - sbmac structure - * + * * Return value: * nothing ********************************************************************* */ @@ -1682,49 +1655,49 @@ static void sbmac_channel_start(struct sbmac_softc *s) static void sbmac_channel_stop(struct sbmac_softc *s) { /* don't do this if already stopped */ - + if (s->sbm_state == sbmac_state_off) return; - + /* don't accept any packets, disable all interrupts */ - - SBMAC_WRITECSR(s->sbm_rxfilter,0); - SBMAC_WRITECSR(s->sbm_imr,0); - + + __raw_writeq(0, s->sbm_rxfilter); + __raw_writeq(0, s->sbm_imr); + /* Turn off ticker */ - + /* XXX */ - + /* turn off receiver and transmitter */ - - SBMAC_WRITECSR(s->sbm_macenable,0); - + + __raw_writeq(0, s->sbm_macenable); + /* We're stopped now. */ - + s->sbm_state = sbmac_state_off; - + /* * Stop DMA channels (rings should be ok now) */ - + sbdma_channel_stop(&(s->sbm_rxdma)); sbdma_channel_stop(&(s->sbm_txdma)); - + /* Empty the receive and transmit rings */ - + sbdma_emptyring(&(s->sbm_rxdma)); sbdma_emptyring(&(s->sbm_txdma)); - + } /********************************************************************** * SBMAC_SET_CHANNEL_STATE(state) - * + * * Set the channel's state ON or OFF - * - * Input parameters: + * + * Input parameters: * state - new state - * + * * Return value: * old state ********************************************************************* */ @@ -1732,43 +1705,43 @@ static sbmac_state_t sbmac_set_channel_state(struct sbmac_softc *sc, sbmac_state_t state) { sbmac_state_t oldstate = sc->sbm_state; - + /* * If same as previous state, return */ - + if (state == oldstate) { return oldstate; } - + /* - * If new state is ON, turn channel on + * If new state is ON, turn channel on */ - + if (state == sbmac_state_on) { sbmac_channel_start(sc); } else { sbmac_channel_stop(sc); } - + /* * Return previous state */ - + return oldstate; } /********************************************************************** * SBMAC_PROMISCUOUS_MODE(sc,onoff) - * + * * Turn on or off promiscuous mode - * - * Input parameters: + * + * Input parameters: * sc - softc * onoff - 1 to turn on, 0 to turn off - * + * * Return value: * nothing ********************************************************************* */ @@ -1776,30 +1749,30 @@ static sbmac_state_t sbmac_set_channel_state(struct sbmac_softc *sc, static void sbmac_promiscuous_mode(struct sbmac_softc *sc,int onoff) { uint64_t reg; - + if (sc->sbm_state != sbmac_state_on) return; - + if (onoff) { - reg = SBMAC_READCSR(sc->sbm_rxfilter); + reg = __raw_readq(sc->sbm_rxfilter); reg |= M_MAC_ALLPKT_EN; - SBMAC_WRITECSR(sc->sbm_rxfilter,reg); - } + __raw_writeq(reg, sc->sbm_rxfilter); + } else { - reg = SBMAC_READCSR(sc->sbm_rxfilter); + reg = __raw_readq(sc->sbm_rxfilter); reg &= ~M_MAC_ALLPKT_EN; - SBMAC_WRITECSR(sc->sbm_rxfilter,reg); + __raw_writeq(reg, sc->sbm_rxfilter); } } /********************************************************************** * SBMAC_SETIPHDR_OFFSET(sc,onoff) - * + * * Set the iphdr offset as 15 assuming ethernet encapsulation - * - * Input parameters: + * + * Input parameters: * sc - softc - * + * * Return value: * nothing ********************************************************************* */ @@ -1807,12 +1780,12 @@ static void sbmac_promiscuous_mode(struct sbmac_softc *sc,int onoff) static void sbmac_set_iphdr_offset(struct sbmac_softc *sc) { uint64_t reg; - + /* Hard code the off set to 15 for now */ - reg = SBMAC_READCSR(sc->sbm_rxfilter); + reg = __raw_readq(sc->sbm_rxfilter); reg &= ~M_MAC_IPHDR_OFFSET | V_MAC_IPHDR_OFFSET(15); - SBMAC_WRITECSR(sc->sbm_rxfilter,reg); - + __raw_writeq(reg, sc->sbm_rxfilter); + /* read system identification to determine revision */ if (periph_rev >= 2) { sc->rx_hw_checksum = ENABLE; @@ -1824,13 +1797,13 @@ static void sbmac_set_iphdr_offset(struct sbmac_softc *sc) /********************************************************************** * SBMAC_ADDR2REG(ptr) - * + * * Convert six bytes into the 64-bit register value that * we typically write into the SBMAC's address/mcast registers - * - * Input parameters: + * + * Input parameters: * ptr - pointer to 6 bytes - * + * * Return value: * register value ********************************************************************* */ @@ -1838,35 +1811,35 @@ static void sbmac_set_iphdr_offset(struct sbmac_softc *sc) static uint64_t sbmac_addr2reg(unsigned char *ptr) { uint64_t reg = 0; - + ptr += 6; - - reg |= (uint64_t) *(--ptr); + + reg |= (uint64_t) *(--ptr); reg <<= 8; - reg |= (uint64_t) *(--ptr); + reg |= (uint64_t) *(--ptr); reg <<= 8; - reg |= (uint64_t) *(--ptr); + reg |= (uint64_t) *(--ptr); reg <<= 8; - reg |= (uint64_t) *(--ptr); + reg |= (uint64_t) *(--ptr); reg <<= 8; - reg |= (uint64_t) *(--ptr); + reg |= (uint64_t) *(--ptr); reg <<= 8; - reg |= (uint64_t) *(--ptr); - + reg |= (uint64_t) *(--ptr); + return reg; } /********************************************************************** * SBMAC_SET_SPEED(s,speed) - * + * * Configure LAN speed for the specified MAC. * Warning: must be called when MAC is off! - * - * Input parameters: + * + * Input parameters: * s - sbmac structure * speed - speed to set MAC to (see sbmac_speed_t enum) - * + * * Return value: * 1 if successful * 0 indicates invalid parameters @@ -1880,31 +1853,31 @@ static int sbmac_set_speed(struct sbmac_softc *s,sbmac_speed_t speed) /* * Save new current values */ - + s->sbm_speed = speed; - + if (s->sbm_state == sbmac_state_on) return 0; /* save for next restart */ /* - * Read current register values + * Read current register values */ - - cfg = SBMAC_READCSR(s->sbm_maccfg); - framecfg = SBMAC_READCSR(s->sbm_framecfg); - + + cfg = __raw_readq(s->sbm_maccfg); + framecfg = __raw_readq(s->sbm_framecfg); + /* * Mask out the stuff we want to change */ - + cfg &= ~(M_MAC_BURST_EN | M_MAC_SPEED_SEL); framecfg &= ~(M_MAC_IFG_RX | M_MAC_IFG_TX | M_MAC_IFG_THRSH | M_MAC_SLOT_SIZE); - + /* * Now add in the new bits */ - + switch (speed) { case sbmac_speed_10: framecfg |= V_MAC_IFG_RX_10 | @@ -1913,7 +1886,7 @@ static int sbmac_set_speed(struct sbmac_softc *s,sbmac_speed_t speed) V_MAC_SLOT_SIZE_10; cfg |= V_MAC_SPEED_SEL_10MBPS; break; - + case sbmac_speed_100: framecfg |= V_MAC_IFG_RX_100 | V_MAC_IFG_TX_100 | @@ -1921,7 +1894,7 @@ static int sbmac_set_speed(struct sbmac_softc *s,sbmac_speed_t speed) V_MAC_SLOT_SIZE_100; cfg |= V_MAC_SPEED_SEL_100MBPS ; break; - + case sbmac_speed_1000: framecfg |= V_MAC_IFG_RX_1000 | V_MAC_IFG_TX_1000 | @@ -1929,34 +1902,34 @@ static int sbmac_set_speed(struct sbmac_softc *s,sbmac_speed_t speed) V_MAC_SLOT_SIZE_1000; cfg |= V_MAC_SPEED_SEL_1000MBPS | M_MAC_BURST_EN; break; - + case sbmac_speed_auto: /* XXX not implemented */ /* fall through */ default: return 0; } - + /* - * Send the bits back to the hardware + * Send the bits back to the hardware */ - - SBMAC_WRITECSR(s->sbm_framecfg,framecfg); - SBMAC_WRITECSR(s->sbm_maccfg,cfg); - + + __raw_writeq(framecfg, s->sbm_framecfg); + __raw_writeq(cfg, s->sbm_maccfg); + return 1; } /********************************************************************** * SBMAC_SET_DUPLEX(s,duplex,fc) - * + * * Set Ethernet duplex and flow control options for this MAC * Warning: must be called when MAC is off! - * - * Input parameters: + * + * Input parameters: * s - sbmac structure * duplex - duplex setting (see sbmac_duplex_t) * fc - flow control setting (see sbmac_fc_t) - * + * * Return value: * 1 if ok * 0 if an invalid parameter combination was specified @@ -1965,67 +1938,67 @@ static int sbmac_set_speed(struct sbmac_softc *s,sbmac_speed_t speed) static int sbmac_set_duplex(struct sbmac_softc *s,sbmac_duplex_t duplex,sbmac_fc_t fc) { uint64_t cfg; - + /* * Save new current values */ - + s->sbm_duplex = duplex; s->sbm_fc = fc; - + if (s->sbm_state == sbmac_state_on) return 0; /* save for next restart */ - + /* - * Read current register values + * Read current register values */ - - cfg = SBMAC_READCSR(s->sbm_maccfg); - + + cfg = __raw_readq(s->sbm_maccfg); + /* * Mask off the stuff we're about to change */ - + cfg &= ~(M_MAC_FC_SEL | M_MAC_FC_CMD | M_MAC_HDX_EN); - - + + switch (duplex) { case sbmac_duplex_half: switch (fc) { case sbmac_fc_disabled: cfg |= M_MAC_HDX_EN | V_MAC_FC_CMD_DISABLED; break; - + case sbmac_fc_collision: cfg |= M_MAC_HDX_EN | V_MAC_FC_CMD_ENABLED; break; - + case sbmac_fc_carrier: cfg |= M_MAC_HDX_EN | V_MAC_FC_CMD_ENAB_FALSECARR; break; - + case sbmac_fc_auto: /* XXX not implemented */ - /* fall through */ + /* fall through */ case sbmac_fc_frame: /* not valid in half duplex */ default: /* invalid selection */ return 0; } break; - + case sbmac_duplex_full: switch (fc) { case sbmac_fc_disabled: cfg |= V_MAC_FC_CMD_DISABLED; break; - + case sbmac_fc_frame: cfg |= V_MAC_FC_CMD_ENABLED; break; - + case sbmac_fc_collision: /* not valid in full duplex */ case sbmac_fc_carrier: /* not valid in full duplex */ case sbmac_fc_auto: /* XXX not implemented */ - /* fall through */ + /* fall through */ default: return 0; } @@ -2034,13 +2007,13 @@ static int sbmac_set_duplex(struct sbmac_softc *s,sbmac_duplex_t duplex,sbmac_fc /* XXX not implemented */ break; } - + /* - * Send the bits back to the hardware + * Send the bits back to the hardware */ - - SBMAC_WRITECSR(s->sbm_maccfg,cfg); - + + __raw_writeq(cfg, s->sbm_maccfg); + return 1; } @@ -2049,12 +2022,12 @@ static int sbmac_set_duplex(struct sbmac_softc *s,sbmac_duplex_t duplex,sbmac_fc /********************************************************************** * SBMAC_INTR() - * + * * Interrupt handler for MAC interrupts - * - * Input parameters: + * + * Input parameters: * MAC structure - * + * * Return value: * nothing ********************************************************************* */ @@ -2066,27 +2039,27 @@ static irqreturn_t sbmac_intr(int irq,void *dev_instance,struct pt_regs *rgs) int handled = 0; for (;;) { - + /* * Read the ISR (this clears the bits in the real * register, except for counter addr) */ - - isr = SBMAC_READCSR(sc->sbm_isr) & ~M_MAC_COUNTER_ADDR; - + + isr = __raw_readq(sc->sbm_isr) & ~M_MAC_COUNTER_ADDR; + if (isr == 0) break; handled = 1; - + /* * Transmits on channel 0 */ - + if (isr & (M_MAC_INT_CHANNEL << S_MAC_TX_CH0)) { sbdma_tx_process(sc,&(sc->sbm_txdma)); } - + /* * Receives on channel 0 */ @@ -2106,8 +2079,8 @@ static irqreturn_t sbmac_intr(int irq,void *dev_instance,struct pt_regs *rgs) * EOP_SEEN here takes care of this case. * (EOP_SEEN is part of M_MAC_INT_CHANNEL << S_MAC_RX_CH0) */ - - + + if (isr & (M_MAC_INT_CHANNEL << S_MAC_RX_CH0)) { sbdma_rx_process(sc,&(sc->sbm_rxdma)); } @@ -2118,29 +2091,29 @@ static irqreturn_t sbmac_intr(int irq,void *dev_instance,struct pt_regs *rgs) /********************************************************************** * SBMAC_START_TX(skb,dev) - * - * Start output on the specified interface. Basically, we + * + * Start output on the specified interface. Basically, we * queue as many buffers as we can until the ring fills up, or * we run off the end of the queue, whichever comes first. - * - * Input parameters: - * - * + * + * Input parameters: + * + * * Return value: * nothing ********************************************************************* */ static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev) { struct sbmac_softc *sc = netdev_priv(dev); - + /* lock eth irq */ spin_lock_irq (&sc->sbm_lock); - + /* - * Put the buffer on the transmit ring. If we + * Put the buffer on the transmit ring. If we * don't have room, stop the queue. */ - + if (sbdma_add_txbuffer(&(sc->sbm_txdma),skb)) { /* XXX save skb that we could not send */ netif_stop_queue(dev); @@ -2148,24 +2121,24 @@ static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev) return 1; } - + dev->trans_start = jiffies; - + spin_unlock_irq (&sc->sbm_lock); - + return 0; } /********************************************************************** * SBMAC_SETMULTI(sc) - * + * * Reprogram the multicast table into the hardware, given * the list of multicasts associated with the interface * structure. - * - * Input parameters: + * + * Input parameters: * sc - softc - * + * * Return value: * nothing ********************************************************************* */ @@ -2173,75 +2146,75 @@ static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev) static void sbmac_setmulti(struct sbmac_softc *sc) { uint64_t reg; - sbmac_port_t port; + volatile void __iomem *port; int idx; struct dev_mc_list *mclist; struct net_device *dev = sc->sbm_dev; - - /* + + /* * Clear out entire multicast table. We do this by nuking * the entire hash table and all the direct matches except - * the first one, which is used for our station address + * the first one, which is used for our station address */ - + for (idx = 1; idx < MAC_ADDR_COUNT; idx++) { port = sc->sbm_base + R_MAC_ADDR_BASE+(idx*sizeof(uint64_t)); - SBMAC_WRITECSR(port,0); + __raw_writeq(0, port); } - + for (idx = 0; idx < MAC_HASH_COUNT; idx++) { port = sc->sbm_base + R_MAC_HASH_BASE+(idx*sizeof(uint64_t)); - SBMAC_WRITECSR(port,0); + __raw_writeq(0, port); } - + /* * Clear the filter to say we don't want any multicasts. */ - - reg = SBMAC_READCSR(sc->sbm_rxfilter); + + reg = __raw_readq(sc->sbm_rxfilter); reg &= ~(M_MAC_MCAST_INV | M_MAC_MCAST_EN); - SBMAC_WRITECSR(sc->sbm_rxfilter,reg); - + __raw_writeq(reg, sc->sbm_rxfilter); + if (dev->flags & IFF_ALLMULTI) { - /* - * Enable ALL multicasts. Do this by inverting the - * multicast enable bit. + /* + * Enable ALL multicasts. Do this by inverting the + * multicast enable bit. */ - reg = SBMAC_READCSR(sc->sbm_rxfilter); + reg = __raw_readq(sc->sbm_rxfilter); reg |= (M_MAC_MCAST_INV | M_MAC_MCAST_EN); - SBMAC_WRITECSR(sc->sbm_rxfilter,reg); + __raw_writeq(reg, sc->sbm_rxfilter); return; } - - /* + + /* * Progam new multicast entries. For now, only use the * perfect filter. In the future we'll need to use the * hash filter if the perfect filter overflows */ - + /* XXX only using perfect filter for now, need to use hash * XXX if the table overflows */ - + idx = 1; /* skip station address */ mclist = dev->mc_list; while (mclist && (idx < MAC_ADDR_COUNT)) { reg = sbmac_addr2reg(mclist->dmi_addr); port = sc->sbm_base + R_MAC_ADDR_BASE+(idx * sizeof(uint64_t)); - SBMAC_WRITECSR(port,reg); + __raw_writeq(reg, port); idx++; mclist = mclist->next; } - - /* + + /* * Enable the "accept multicast bits" if we programmed at least one - * multicast. + * multicast. */ - + if (idx > 1) { - reg = SBMAC_READCSR(sc->sbm_rxfilter); + reg = __raw_readq(sc->sbm_rxfilter); reg |= M_MAC_MCAST_EN; - SBMAC_WRITECSR(sc->sbm_rxfilter,reg); + __raw_writeq(reg, sc->sbm_rxfilter); } } @@ -2250,12 +2223,12 @@ static void sbmac_setmulti(struct sbmac_softc *sc) #if defined(SBMAC_ETH0_HWADDR) || defined(SBMAC_ETH1_HWADDR) || defined(SBMAC_ETH2_HWADDR) /********************************************************************** * SBMAC_PARSE_XDIGIT(str) - * + * * Parse a hex digit, returning its value - * - * Input parameters: + * + * Input parameters: * str - character - * + * * Return value: * hex value, or -1 if invalid ********************************************************************* */ @@ -2263,7 +2236,7 @@ static void sbmac_setmulti(struct sbmac_softc *sc) static int sbmac_parse_xdigit(char str) { int digit; - + if ((str >= '0') && (str <= '9')) digit = str - '0'; else if ((str >= 'a') && (str <= 'f')) @@ -2272,20 +2245,20 @@ static int sbmac_parse_xdigit(char str) digit = str - 'A' + 10; else return -1; - + return digit; } /********************************************************************** * SBMAC_PARSE_HWADDR(str,hwaddr) - * + * * Convert a string in the form xx:xx:xx:xx:xx:xx into a 6-byte * Ethernet address. - * - * Input parameters: + * + * Input parameters: * str - string * hwaddr - pointer to hardware address - * + * * Return value: * 0 if ok, else -1 ********************************************************************* */ @@ -2294,7 +2267,7 @@ static int sbmac_parse_hwaddr(char *str, unsigned char *hwaddr) { int digit1,digit2; int idx = 6; - + while (*str && (idx > 0)) { digit1 = sbmac_parse_xdigit(*str); if (digit1 < 0) @@ -2302,7 +2275,7 @@ static int sbmac_parse_hwaddr(char *str, unsigned char *hwaddr) str++; if (!*str) return -1; - + if ((*str == ':') || (*str == '-')) { digit2 = digit1; digit1 = 0; @@ -2313,10 +2286,10 @@ static int sbmac_parse_hwaddr(char *str, unsigned char *hwaddr) return -1; str++; } - + *hwaddr++ = (digit1 << 4) | digit2; idx--; - + if (*str == '-') str++; if (*str == ':') @@ -2337,12 +2310,12 @@ static int sb1250_change_mtu(struct net_device *_dev, int new_mtu) /********************************************************************** * SBMAC_INIT(dev) - * + * * Attach routine - init hardware and hook ourselves into linux - * - * Input parameters: + * + * Input parameters: * dev - net_device structure - * + * * Return value: * status ********************************************************************* */ @@ -2354,53 +2327,53 @@ static int sbmac_init(struct net_device *dev, int idx) uint64_t ea_reg; int i; int err; - + sc = netdev_priv(dev); - + /* Determine controller base address */ - + sc->sbm_base = IOADDR(dev->base_addr); sc->sbm_dev = dev; sc->sbe_idx = idx; - + eaddr = sc->sbm_hwaddr; - - /* + + /* * Read the ethernet address. The firwmare left this programmed * for us in the ethernet address register for each mac. */ - - ea_reg = SBMAC_READCSR(sc->sbm_base + R_MAC_ETHERNET_ADDR); - SBMAC_WRITECSR(sc->sbm_base + R_MAC_ETHERNET_ADDR, 0); + + ea_reg = __raw_readq(sc->sbm_base + R_MAC_ETHERNET_ADDR); + __raw_writeq(0, sc->sbm_base + R_MAC_ETHERNET_ADDR); for (i = 0; i < 6; i++) { eaddr[i] = (uint8_t) (ea_reg & 0xFF); ea_reg >>= 8; } - + for (i = 0; i < 6; i++) { dev->dev_addr[i] = eaddr[i]; } - - + + /* - * Init packet size + * Init packet size */ - + sc->sbm_buffersize = ENET_PACKET_SIZE + SMP_CACHE_BYTES * 2 + ETHER_ALIGN; - /* + /* * Initialize context (get pointers to registers and stuff), then * allocate the memory for the descriptor tables. */ - + sbmac_initctx(sc); - + /* * Set up Linux device callins */ - + spin_lock_init(&(sc->sbm_lock)); - + dev->open = sbmac_open; dev->hard_start_xmit = sbmac_start_tx; dev->stop = sbmac_close; @@ -2419,7 +2392,7 @@ static int sbmac_init(struct net_device *dev, int idx) if (err) goto out_uninit; - if (periph_rev >= 2) { + if (sc->rx_hw_checksum == ENABLE) { printk(KERN_INFO "%s: enabling TCP rcv checksum\n", sc->sbm_dev->name); } @@ -2430,10 +2403,10 @@ static int sbmac_init(struct net_device *dev, int idx) * was being displayed) */ printk(KERN_INFO - "%s: SiByte Ethernet at 0x%08lX, address: %02X:%02X:%02X:%02X:%02X:%02X\n", + "%s: SiByte Ethernet at 0x%08lX, address: %02X:%02X:%02X:%02X:%02X:%02X\n", dev->name, dev->base_addr, eaddr[0],eaddr[1],eaddr[2],eaddr[3],eaddr[4],eaddr[5]); - + return 0; @@ -2447,54 +2420,86 @@ out_uninit: static int sbmac_open(struct net_device *dev) { struct sbmac_softc *sc = netdev_priv(dev); - + if (debug > 1) { printk(KERN_DEBUG "%s: sbmac_open() irq %d.\n", dev->name, dev->irq); } - - /* + + /* * map/route interrupt (clear status first, in case something * weird is pending; we haven't initialized the mac registers * yet) */ - SBMAC_READCSR(sc->sbm_isr); + __raw_readq(sc->sbm_isr); if (request_irq(dev->irq, &sbmac_intr, SA_SHIRQ, dev->name, dev)) return -EBUSY; /* - * Configure default speed + * Probe phy address + */ + + if(sbmac_mii_probe(dev) == -1) { + printk("%s: failed to probe PHY.\n", dev->name); + return -EINVAL; + } + + /* + * Configure default speed */ sbmac_mii_poll(sc,noisy_mii); - + /* * Turn on the channel */ sbmac_set_channel_state(sc,sbmac_state_on); - + /* * XXX Station address is in dev->dev_addr */ - + if (dev->if_port == 0) - dev->if_port = 0; - + dev->if_port = 0; + netif_start_queue(dev); - + sbmac_set_rx_mode(dev); - + /* Set the timer to check for link beat. */ init_timer(&sc->sbm_timer); sc->sbm_timer.expires = jiffies + 2 * HZ/100; sc->sbm_timer.data = (unsigned long)dev; sc->sbm_timer.function = &sbmac_timer; add_timer(&sc->sbm_timer); - + return 0; } +static int sbmac_mii_probe(struct net_device *dev) +{ + int i; + struct sbmac_softc *s = netdev_priv(dev); + u16 bmsr, id1, id2; + u32 vendor, device; + + for (i=1; i<31; i++) { + bmsr = sbmac_mii_read(s, i, MII_BMSR); + if (bmsr != 0) { + s->sbm_phys[0] = i; + id1 = sbmac_mii_read(s, i, MII_PHYIDR1); + id2 = sbmac_mii_read(s, i, MII_PHYIDR2); + vendor = ((u32)id1 << 6) | ((id2 >> 10) & 0x3f); + device = (id2 >> 4) & 0x3f; + + printk(KERN_INFO "%s: found phy %d, vendor %06x part %02x\n", + dev->name, i, vendor, device); + return i; + } + } + return -1; +} static int sbmac_mii_poll(struct sbmac_softc *s,int noisy) @@ -2609,20 +2614,20 @@ static void sbmac_timer(unsigned long data) int mii_status; spin_lock_irq (&sc->sbm_lock); - + /* make IFF_RUNNING follow the MII status bit "Link established" */ mii_status = sbmac_mii_read(sc, sc->sbm_phys[0], MII_BMSR); - + if ( (mii_status & BMSR_LINKSTAT) != (sc->sbm_phy_oldlinkstat) ) { sc->sbm_phy_oldlinkstat = mii_status & BMSR_LINKSTAT; if (mii_status & BMSR_LINKSTAT) { netif_carrier_on(dev); } else { - netif_carrier_off(dev); + netif_carrier_off(dev); } } - + /* * Poll the PHY to see what speed we should be running at */ @@ -2640,9 +2645,9 @@ static void sbmac_timer(unsigned long data) sbmac_channel_start(sc); } } - + spin_unlock_irq (&sc->sbm_lock); - + sc->sbm_timer.expires = jiffies + next_tick; add_timer(&sc->sbm_timer); } @@ -2651,13 +2656,13 @@ static void sbmac_timer(unsigned long data) static void sbmac_tx_timeout (struct net_device *dev) { struct sbmac_softc *sc = netdev_priv(dev); - + spin_lock_irq (&sc->sbm_lock); - - + + dev->trans_start = jiffies; sc->sbm_stats.tx_errors++; - + spin_unlock_irq (&sc->sbm_lock); printk (KERN_WARNING "%s: Transmit timed out\n",dev->name); @@ -2670,13 +2675,13 @@ static struct net_device_stats *sbmac_get_stats(struct net_device *dev) { struct sbmac_softc *sc = netdev_priv(dev); unsigned long flags; - + spin_lock_irqsave(&sc->sbm_lock, flags); - + /* XXX update other stats here */ - + spin_unlock_irqrestore(&sc->sbm_lock, flags); - + return &sc->sbm_stats; } @@ -2693,8 +2698,8 @@ static void sbmac_set_rx_mode(struct net_device *dev) /* * Promiscuous changed. */ - - if (dev->flags & IFF_PROMISC) { + + if (dev->flags & IFF_PROMISC) { /* Unconditionally log net taps. */ msg_flag = 1; sbmac_promiscuous_mode(sc,1); @@ -2705,18 +2710,18 @@ static void sbmac_set_rx_mode(struct net_device *dev) } } spin_unlock_irqrestore(&sc->sbm_lock, flags); - + if (msg_flag) { printk(KERN_NOTICE "%s: Promiscuous mode %sabled.\n", dev->name,(msg_flag==1)?"en":"dis"); } - + /* * Program the multicasts. Do this every time. */ - + sbmac_setmulti(sc); - + } static int sbmac_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) @@ -2725,10 +2730,10 @@ static int sbmac_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) u16 *data = (u16 *)&rq->ifr_ifru; unsigned long flags; int retval; - + spin_lock_irqsave(&sc->sbm_lock, flags); retval = 0; - + switch(cmd) { case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ data[0] = sc->sbm_phys[0] & 0x1f; @@ -2750,7 +2755,7 @@ static int sbmac_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) default: retval = -EOPNOTSUPP; } - + spin_unlock_irqrestore(&sc->sbm_lock, flags); return retval; } @@ -2781,7 +2786,7 @@ static int sbmac_close(struct net_device *dev) sbdma_emptyring(&(sc->sbm_txdma)); sbdma_emptyring(&(sc->sbm_rxdma)); - + return 0; } @@ -2793,13 +2798,13 @@ sbmac_setup_hwaddr(int chan,char *addr) { uint8_t eaddr[6]; uint64_t val; - sbmac_port_t port; + unsigned long port; port = A_MAC_CHANNEL_BASE(chan); sbmac_parse_hwaddr(addr,eaddr); val = sbmac_addr2reg(eaddr); - SBMAC_WRITECSR(IOADDR(port+R_MAC_ETHERNET_ADDR),val); - val = SBMAC_READCSR(IOADDR(port+R_MAC_ETHERNET_ADDR)); + __raw_writeq(val, IOADDR(port+R_MAC_ETHERNET_ADDR)); + val = __raw_readq(IOADDR(port+R_MAC_ETHERNET_ADDR)); } #endif @@ -2810,9 +2815,9 @@ sbmac_init_module(void) { int idx; struct net_device *dev; - sbmac_port_t port; + unsigned long port; int chip_max_units; - + /* * For bringup when not using the firmware, we can pre-fill * the MAC addresses using the environment variables @@ -2858,13 +2863,13 @@ sbmac_init_module(void) port = A_MAC_CHANNEL_BASE(idx); - /* + /* * The R_MAC_ETHERNET_ADDR register will be set to some nonzero * value for us by the firmware if we're going to use this MAC. * If we find a zero, skip this MAC. */ - sbmac_orig_hwaddr[idx] = SBMAC_READCSR(IOADDR(port+R_MAC_ETHERNET_ADDR)); + sbmac_orig_hwaddr[idx] = __raw_readq(IOADDR(port+R_MAC_ETHERNET_ADDR)); if (sbmac_orig_hwaddr[idx] == 0) { printk(KERN_DEBUG "sbmac: not configuring MAC at " "%lx\n", port); @@ -2876,7 +2881,7 @@ sbmac_init_module(void) */ dev = alloc_etherdev(sizeof(struct sbmac_softc)); - if (!dev) + if (!dev) return -ENOMEM; /* return ENOMEM */ printk(KERN_DEBUG "sbmac: configuring MAC at %lx\n", port); @@ -2886,8 +2891,7 @@ sbmac_init_module(void) dev->mem_end = 0; if (sbmac_init(dev, idx)) { port = A_MAC_CHANNEL_BASE(idx); - SBMAC_WRITECSR(IOADDR(port+R_MAC_ETHERNET_ADDR), - sbmac_orig_hwaddr[idx]); + __raw_writeq(sbmac_orig_hwaddr[idx], IOADDR(port+R_MAC_ETHERNET_ADDR)); free_netdev(dev); continue; } diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c index 9bc3b1c0dd6a..a4614df38a90 100644 --- a/drivers/net/sgiseeq.c +++ b/drivers/net/sgiseeq.c @@ -32,8 +32,6 @@ #include "sgiseeq.h" -static char *version = "sgiseeq.c: David S. Miller (dm@engr.sgi.com)\n"; - static char *sgiseeqstr = "SGI Seeq8003"; /* @@ -113,9 +111,9 @@ static struct net_device *root_sgiseeq_dev; static inline void hpc3_eth_reset(struct hpc3_ethregs *hregs) { - hregs->rx_reset = HPC3_ERXRST_CRESET | HPC3_ERXRST_CLRIRQ; + hregs->reset = HPC3_ERST_CRESET | HPC3_ERST_CLRIRQ; udelay(20); - hregs->rx_reset = 0; + hregs->reset = 0; } static inline void reset_hpc3_and_seeq(struct hpc3_ethregs *hregs, @@ -252,7 +250,6 @@ void sgiseeq_dump_rings(void) #define TSTAT_INIT_SEEQ (SEEQ_TCMD_IPT|SEEQ_TCMD_I16|SEEQ_TCMD_IC|SEEQ_TCMD_IUF) #define TSTAT_INIT_EDLC ((TSTAT_INIT_SEEQ) | SEEQ_TCMD_RB2) -#define RDMACFG_INIT (HPC3_ERXDCFG_FRXDC | HPC3_ERXDCFG_FEOP | HPC3_ERXDCFG_FIRQ) static int init_seeq(struct net_device *dev, struct sgiseeq_private *sp, struct sgiseeq_regs *sregs) @@ -274,8 +271,6 @@ static int init_seeq(struct net_device *dev, struct sgiseeq_private *sp, sregs->tstat = TSTAT_INIT_SEEQ; } - hregs->rx_dconfig |= RDMACFG_INIT; - hregs->rx_ndptr = CPHYSADDR(sp->rx_desc); hregs->tx_ndptr = CPHYSADDR(sp->tx_desc); @@ -446,7 +441,7 @@ static irqreturn_t sgiseeq_interrupt(int irq, void *dev_id, struct pt_regs *regs spin_lock(&sp->tx_lock); /* Ack the IRQ and set software state. */ - hregs->rx_reset = HPC3_ERXRST_CLRIRQ; + hregs->reset = HPC3_ERST_CLRIRQ; /* Always check for received packets. */ sgiseeq_rx(dev, sp, hregs, sregs); @@ -493,11 +488,13 @@ static int sgiseeq_close(struct net_device *dev) { struct sgiseeq_private *sp = netdev_priv(dev); struct sgiseeq_regs *sregs = sp->sregs; + unsigned int irq = dev->irq; netif_stop_queue(dev); /* Shutdown the Seeq. */ reset_hpc3_and_seeq(sp->hregs, sregs); + free_irq(irq, dev); return 0; } @@ -644,7 +641,7 @@ static inline void setup_rx_ring(struct sgiseeq_rx_desc *buf, int nbufs) #define ALIGNED(x) ((((unsigned long)(x)) + 0xf) & ~(0xf)) -static int sgiseeq_init(struct hpc3_regs* regs, int irq) +static int sgiseeq_init(struct hpc3_regs* hpcregs, int irq) { struct sgiseeq_init_block *sr; struct sgiseeq_private *sp; @@ -680,8 +677,8 @@ static int sgiseeq_init(struct hpc3_regs* regs, int irq) gpriv = sp; gdev = dev; #endif - sp->sregs = (struct sgiseeq_regs *) &hpc3c0->eth_ext[0]; - sp->hregs = &hpc3c0->ethregs; + sp->sregs = (struct sgiseeq_regs *) &hpcregs->eth_ext[0]; + sp->hregs = &hpcregs->ethregs; sp->name = sgiseeqstr; sp->mode = SEEQ_RCMD_RBCAST; @@ -698,6 +695,11 @@ static int sgiseeq_init(struct hpc3_regs* regs, int irq) setup_rx_ring(sp->rx_desc, SEEQ_RX_BUFFERS); setup_tx_ring(sp->tx_desc, SEEQ_TX_BUFFERS); + /* Setup PIO and DMA transfer timing */ + sp->hregs->pconfig = 0x161; + sp->hregs->dconfig = HPC3_EDCFG_FIRQ | HPC3_EDCFG_FEOP | + HPC3_EDCFG_FRXDC | HPC3_EDCFG_PTO | 0x026; + /* Reset the chip. */ hpc3_eth_reset(sp->hregs); @@ -724,7 +726,7 @@ static int sgiseeq_init(struct hpc3_regs* regs, int irq) goto err_out_free_page; } - printk(KERN_INFO "%s: SGI Seeq8003 ", dev->name); + printk(KERN_INFO "%s: %s ", dev->name, sgiseeqstr); for (i = 0; i < 6; i++) printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':'); @@ -734,7 +736,7 @@ static int sgiseeq_init(struct hpc3_regs* regs, int irq) return 0; err_out_free_page: - free_page((unsigned long) sp); + free_page((unsigned long) sp->srings); err_out_free_dev: kfree(dev); @@ -744,8 +746,6 @@ err_out: static int __init sgiseeq_probe(void) { - printk(version); - /* On board adapter on 1st HPC is always present */ return sgiseeq_init(hpc3c0, SGI_ENET_IRQ); } @@ -754,15 +754,12 @@ static void __exit sgiseeq_exit(void) { struct net_device *next, *dev; struct sgiseeq_private *sp; - int irq; for (dev = root_sgiseeq_dev; dev; dev = next) { sp = (struct sgiseeq_private *) netdev_priv(dev); next = sp->next_module; - irq = dev->irq; unregister_netdev(dev); - free_irq(irq, dev); - free_page((unsigned long) sp); + free_page((unsigned long) sp->srings); free_netdev(dev); } } @@ -770,4 +767,6 @@ static void __exit sgiseeq_exit(void) module_init(sgiseeq_probe); module_exit(sgiseeq_exit); +MODULE_DESCRIPTION("SGI Seeq 8003 driver"); +MODULE_AUTHOR("Linux/MIPS Mailing List <linux-mips@linux-mips.org>"); MODULE_LICENSE("GPL"); diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c index 92f75529eff8..478791e09bf7 100644 --- a/drivers/net/sis190.c +++ b/drivers/net/sis190.c @@ -842,7 +842,7 @@ static void sis190_set_rx_mode(struct net_device *dev) for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; i++, mclist = mclist->next) { int bit_nr = - ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26; + ether_crc(ETH_ALEN, mclist->dmi_addr) & 0x3f; mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31); rx_mode |= AcceptMulticast; } diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c index 23b713c700b3..1d4d88680db1 100644 --- a/drivers/net/sis900.c +++ b/drivers/net/sis900.c @@ -1696,15 +1696,20 @@ static int sis900_rx(struct net_device *net_dev) long ioaddr = net_dev->base_addr; unsigned int entry = sis_priv->cur_rx % NUM_RX_DESC; u32 rx_status = sis_priv->rx_ring[entry].cmdsts; + int rx_work_limit; if (netif_msg_rx_status(sis_priv)) printk(KERN_DEBUG "sis900_rx, cur_rx:%4.4d, dirty_rx:%4.4d " "status:0x%8.8x\n", sis_priv->cur_rx, sis_priv->dirty_rx, rx_status); + rx_work_limit = sis_priv->dirty_rx + NUM_RX_DESC - sis_priv->cur_rx; while (rx_status & OWN) { unsigned int rx_size; + if (--rx_work_limit < 0) + break; + rx_size = (rx_status & DSIZE) - CRC_SIZE; if (rx_status & (ABORT|OVERRUN|TOOLONG|RUNT|RXISERR|CRCERR|FAERR)) { @@ -1732,9 +1737,11 @@ static int sis900_rx(struct net_device *net_dev) we are working on NULL sk_buff :-( */ if (sis_priv->rx_skbuff[entry] == NULL) { if (netif_msg_rx_err(sis_priv)) - printk(KERN_INFO "%s: NULL pointer " - "encountered in Rx ring, skipping\n", - net_dev->name); + printk(KERN_WARNING "%s: NULL pointer " + "encountered in Rx ring\n" + "cur_rx:%4.4d, dirty_rx:%4.4d\n", + net_dev->name, sis_priv->cur_rx, + sis_priv->dirty_rx); break; } @@ -1770,6 +1777,7 @@ static int sis900_rx(struct net_device *net_dev) sis_priv->rx_ring[entry].cmdsts = 0; sis_priv->rx_ring[entry].bufptr = 0; sis_priv->stats.rx_dropped++; + sis_priv->cur_rx++; break; } skb->dev = net_dev; @@ -1787,7 +1795,7 @@ static int sis900_rx(struct net_device *net_dev) /* refill the Rx buffer, what if the rate of refilling is slower * than consuming ?? */ - for (;sis_priv->cur_rx - sis_priv->dirty_rx > 0; sis_priv->dirty_rx++) { + for (; sis_priv->cur_rx != sis_priv->dirty_rx; sis_priv->dirty_rx++) { struct sk_buff *skb; entry = sis_priv->dirty_rx % NUM_RX_DESC; diff --git a/drivers/net/skfp/smt.c b/drivers/net/skfp/smt.c index f17c05cbe44b..99a776a51fb5 100644 --- a/drivers/net/skfp/smt.c +++ b/drivers/net/skfp/smt.c @@ -1896,7 +1896,7 @@ void smt_swap_para(struct smt_header *sm, int len, int direction) static void smt_string_swap(char *data, const char *format, int len) { - const char *open_paren = 0 ; + const char *open_paren = NULL ; int x ; while (len > 0 && *format) { diff --git a/drivers/net/skge.c b/drivers/net/skge.c index c2e6484ef138..572f121b1f4e 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -730,6 +730,7 @@ static struct ethtool_ops skge_ethtool_ops = { .phys_id = skge_phys_id, .get_stats_count = skge_get_stats_count, .get_ethtool_stats = skge_get_ethtool_stats, + .get_perm_addr = ethtool_op_get_perm_addr, }; /* @@ -3096,6 +3097,7 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port, /* read the mac address */ memcpy_fromio(dev->dev_addr, hw->regs + B2_MAC_1 + port*8, ETH_ALEN); + memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); /* device is off until link detection */ netif_carrier_off(dev); diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c index 1438fdd20826..c573bb351d4c 100644 --- a/drivers/net/smc91x.c +++ b/drivers/net/smc91x.c @@ -1983,6 +1983,10 @@ static int __init smc_probe(struct net_device *dev, void __iomem *ioaddr) if (lp->version >= (CHIP_91100 << 4)) smc_phy_detect(dev); + /* then shut everything down to save power */ + smc_shutdown(dev); + smc_phy_powerdown(dev); + /* Set default parameters */ lp->msg_enable = NETIF_MSG_LINK; lp->ctl_rfduplx = 0; @@ -2291,11 +2295,11 @@ static int smc_drv_remove(struct device *dev) return 0; } -static int smc_drv_suspend(struct device *dev, pm_message_t state, u32 level) +static int smc_drv_suspend(struct device *dev, pm_message_t state) { struct net_device *ndev = dev_get_drvdata(dev); - if (ndev && level == SUSPEND_DISABLE) { + if (ndev) { if (netif_running(ndev)) { netif_device_detach(ndev); smc_shutdown(ndev); @@ -2305,12 +2309,12 @@ static int smc_drv_suspend(struct device *dev, pm_message_t state, u32 level) return 0; } -static int smc_drv_resume(struct device *dev, u32 level) +static int smc_drv_resume(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct net_device *ndev = dev_get_drvdata(dev); - if (ndev && level == RESUME_ENABLE) { + if (ndev) { struct smc_local *lp = netdev_priv(ndev); smc_enable_device(pdev); if (netif_running(ndev)) { diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h index ac9ce6509eee..817f200742c3 100644 --- a/drivers/net/smc91x.h +++ b/drivers/net/smc91x.h @@ -230,12 +230,12 @@ SMC_outw(u16 val, void __iomem *ioaddr, int reg) #define SMC_CAN_USE_16BIT 1 #define SMC_CAN_USE_32BIT 0 -#define SMC_inb(a, r) inb((a) + (r) - 0xa0000000) -#define SMC_inw(a, r) inw((a) + (r) - 0xa0000000) -#define SMC_outb(v, a, r) outb(v, (a) + (r) - 0xa0000000) -#define SMC_outw(v, a, r) outw(v, (a) + (r) - 0xa0000000) -#define SMC_insw(a, r, p, l) insw((a) + (r) - 0xa0000000, p, l) -#define SMC_outsw(a, r, p, l) outsw((a) + (r) - 0xa0000000, p, l) +#define SMC_inb(a, r) inb((u32)a) + (r)) +#define SMC_inw(a, r) inw(((u32)a) + (r)) +#define SMC_outb(v, a, r) outb(v, ((u32)a) + (r)) +#define SMC_outw(v, a, r) outw(v, ((u32)a) + (r)) +#define SMC_insw(a, r, p, l) insw(((u32)a) + (r), p, l) +#define SMC_outsw(a, r, p, l) outsw(((u32)a) + (r), p, l) #define set_irq_type(irq, type) do {} while(0) diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c index efdb179ecc8c..38b2b0a3ce96 100644 --- a/drivers/net/starfire.c +++ b/drivers/net/starfire.c @@ -1091,8 +1091,10 @@ static int netdev_open(struct net_device *dev) rx_ring_size = sizeof(struct starfire_rx_desc) * RX_RING_SIZE; np->queue_mem_size = tx_done_q_size + rx_done_q_size + tx_ring_size + rx_ring_size; np->queue_mem = pci_alloc_consistent(np->pci_dev, np->queue_mem_size, &np->queue_mem_dma); - if (np->queue_mem == 0) + if (np->queue_mem == NULL) { + free_irq(dev->irq, dev); return -ENOMEM; + } np->tx_done_q = np->queue_mem; np->tx_done_q_dma = np->queue_mem_dma; diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c index f88f5e32b714..cfaf47c63c58 100644 --- a/drivers/net/sunbmac.c +++ b/drivers/net/sunbmac.c @@ -214,7 +214,8 @@ static void bigmac_init_rings(struct bigmac *bp, int from_irq) { struct bmac_init_block *bb = bp->bmac_block; struct net_device *dev = bp->dev; - int i, gfp_flags = GFP_KERNEL; + int i; + gfp_t gfp_flags = GFP_KERNEL; if (from_irq || in_interrupt()) gfp_flags = GFP_ATOMIC; diff --git a/drivers/net/sunbmac.h b/drivers/net/sunbmac.h index 5674003fc38a..b0dbc5187143 100644 --- a/drivers/net/sunbmac.h +++ b/drivers/net/sunbmac.h @@ -339,7 +339,7 @@ struct bigmac { #define ALIGNED_RX_SKB_ADDR(addr) \ ((((unsigned long)(addr) + (64 - 1)) & ~(64 - 1)) - (unsigned long)(addr)) -static inline struct sk_buff *big_mac_alloc_skb(unsigned int length, int gfp_flags) +static inline struct sk_buff *big_mac_alloc_skb(unsigned int length, gfp_t gfp_flags) { struct sk_buff *skb; diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c index d500a5771dbc..0ab9c38b4a34 100644 --- a/drivers/net/sundance.c +++ b/drivers/net/sundance.c @@ -80,7 +80,7 @@ I/O access could affect performance in ARM-based system - Add Linux software VLAN support - Version LK1.08 (D-Link): + Version LK1.08 (Philippe De Muyter phdm@macqel.be): - Fix bug of custom mac address (StationAddr register only accept word write) @@ -91,11 +91,14 @@ Version LK1.09a (ICPlus): - Add the delay time in reading the contents of EEPROM + Version LK1.10 (Philippe De Muyter phdm@macqel.be): + - Make 'unblock interface after Tx underrun' work + */ #define DRV_NAME "sundance" -#define DRV_VERSION "1.01+LK1.09a" -#define DRV_RELDATE "10-Jul-2003" +#define DRV_VERSION "1.01+LK1.10" +#define DRV_RELDATE "28-Oct-2005" /* The user-configurable values. @@ -263,8 +266,10 @@ IV. Notes IVb. References The Sundance ST201 datasheet, preliminary version. -http://cesdis.gsfc.nasa.gov/linux/misc/100mbps.html -http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html +The Kendin KS8723 datasheet, preliminary version. +The ICplus IP100 datasheet, preliminary version. +http://www.scyld.com/expert/100mbps.html +http://www.scyld.com/expert/NWay.html IVc. Errata @@ -500,6 +505,25 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static int netdev_close(struct net_device *dev); static struct ethtool_ops ethtool_ops; +static void sundance_reset(struct net_device *dev, unsigned long reset_cmd) +{ + struct netdev_private *np = netdev_priv(dev); + void __iomem *ioaddr = np->base + ASICCtrl; + int countdown; + + /* ST201 documentation states ASICCtrl is a 32bit register */ + iowrite32 (reset_cmd | ioread32 (ioaddr), ioaddr); + /* ST201 documentation states reset can take up to 1 ms */ + countdown = 10 + 1; + while (ioread32 (ioaddr) & (ResetBusy << 16)) { + if (--countdown == 0) { + printk(KERN_WARNING "%s : reset not completed !!\n", dev->name); + break; + } + udelay(100); + } +} + static int __devinit sundance_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -518,6 +542,7 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev, #else int bar = 1; #endif + int phy, phy_idx = 0; /* when built into the kernel, we only print version if device is found */ @@ -549,6 +574,7 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev, for (i = 0; i < 3; i++) ((u16 *)dev->dev_addr)[i] = le16_to_cpu(eeprom_read(ioaddr, i + EEPROM_SA_OFFSET)); + memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); dev->base_addr = (unsigned long)ioaddr; dev->irq = irq; @@ -605,33 +631,31 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev, printk("%2.2x:", dev->dev_addr[i]); printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); - if (1) { - int phy, phy_idx = 0; - np->phys[0] = 1; /* Default setting */ - np->mii_preamble_required++; - for (phy = 1; phy < 32 && phy_idx < MII_CNT; phy++) { - int mii_status = mdio_read(dev, phy, MII_BMSR); - if (mii_status != 0xffff && mii_status != 0x0000) { - np->phys[phy_idx++] = phy; - np->mii_if.advertising = mdio_read(dev, phy, MII_ADVERTISE); - if ((mii_status & 0x0040) == 0) - np->mii_preamble_required++; - printk(KERN_INFO "%s: MII PHY found at address %d, status " - "0x%4.4x advertising %4.4x.\n", - dev->name, phy, mii_status, np->mii_if.advertising); - } - } - np->mii_preamble_required--; - - if (phy_idx == 0) { - printk(KERN_INFO "%s: No MII transceiver found, aborting. ASIC status %x\n", - dev->name, ioread32(ioaddr + ASICCtrl)); - goto err_out_unregister; + np->phys[0] = 1; /* Default setting */ + np->mii_preamble_required++; + for (phy = 1; phy <= 32 && phy_idx < MII_CNT; phy++) { + int mii_status = mdio_read(dev, phy, MII_BMSR); + int phyx = phy & 0x1f; + if (mii_status != 0xffff && mii_status != 0x0000) { + np->phys[phy_idx++] = phyx; + np->mii_if.advertising = mdio_read(dev, phyx, MII_ADVERTISE); + if ((mii_status & 0x0040) == 0) + np->mii_preamble_required++; + printk(KERN_INFO "%s: MII PHY found at address %d, status " + "0x%4.4x advertising %4.4x.\n", + dev->name, phyx, mii_status, np->mii_if.advertising); } + } + np->mii_preamble_required--; - np->mii_if.phy_id = np->phys[0]; + if (phy_idx == 0) { + printk(KERN_INFO "%s: No MII transceiver found, aborting. ASIC status %x\n", + dev->name, ioread32(ioaddr + ASICCtrl)); + goto err_out_unregister; } + np->mii_if.phy_id = np->phys[0]; + /* Parse override configuration */ np->an_enable = 1; if (card_idx < MAX_UNITS) { @@ -692,7 +716,7 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev, /* Reset the chip to erase previous misconfiguration. */ if (netif_msg_hw(np)) printk("ASIC Control is %x.\n", ioread32(ioaddr + ASICCtrl)); - iowrite16(0x007f, ioaddr + ASICCtrl + 2); + iowrite16(0x00ff, ioaddr + ASICCtrl + 2); if (netif_msg_hw(np)) printk("ASIC Control is now %x.\n", ioread32(ioaddr + ASICCtrl)); @@ -1190,23 +1214,33 @@ static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs ("%s: Transmit status is %2.2x.\n", dev->name, tx_status); if (tx_status & 0x1e) { + if (netif_msg_tx_err(np)) + printk("%s: Transmit error status %4.4x.\n", + dev->name, tx_status); np->stats.tx_errors++; if (tx_status & 0x10) np->stats.tx_fifo_errors++; if (tx_status & 0x08) np->stats.collisions++; + if (tx_status & 0x04) + np->stats.tx_fifo_errors++; if (tx_status & 0x02) np->stats.tx_window_errors++; - /* This reset has not been verified!. */ - if (tx_status & 0x10) { /* Reset the Tx. */ - np->stats.tx_fifo_errors++; - spin_lock(&np->lock); - reset_tx(dev); - spin_unlock(&np->lock); + /* + ** This reset has been verified on + ** DFE-580TX boards ! phdm@macqel.be. + */ + if (tx_status & 0x10) { /* TxUnderrun */ + unsigned short txthreshold; + + txthreshold = ioread16 (ioaddr + TxStartThresh); + /* Restart Tx FIFO and transmitter */ + sundance_reset(dev, (NetworkReset|FIFOReset|TxReset) << 16); + iowrite16 (txthreshold, ioaddr + TxStartThresh); + /* No need to reset the Tx pointer here */ } - if (tx_status & 0x1e) /* Restart the Tx. */ - iowrite16 (TxEnable, - ioaddr + MACCtrl1); + /* Restart the Tx. */ + iowrite16 (TxEnable, ioaddr + MACCtrl1); } /* Yup, this is a documentation bug. It cost me *hours*. */ iowrite16 (0, ioaddr + TxStatus); @@ -1619,6 +1653,7 @@ static struct ethtool_ops ethtool_ops = { .get_link = get_link, .get_msglevel = get_msglevel, .set_msglevel = set_msglevel, + .get_perm_addr = ethtool_op_get_perm_addr, }; static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 1802c3b48799..1828a6bf8458 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -37,6 +37,7 @@ #include <linux/tcp.h> #include <linux/workqueue.h> #include <linux/prefetch.h> +#include <linux/dma-mapping.h> #include <net/checksum.h> @@ -67,8 +68,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.42" -#define DRV_MODULE_RELDATE "Oct 3, 2005" +#define DRV_MODULE_VERSION "3.43" +#define DRV_MODULE_RELDATE "Oct 24, 2005" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 @@ -219,6 +220,10 @@ static struct pci_device_id tg3_pci_tbl[] = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5753F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, + { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5714, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, + { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5715, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5780, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5780S, @@ -466,6 +471,15 @@ static void tg3_write_mem(struct tg3 *tp, u32 off, u32 val) spin_unlock_irqrestore(&tp->indirect_lock, flags); } +static void tg3_write_mem_fast(struct tg3 *tp, u32 off, u32 val) +{ + /* If no workaround is needed, write to mem space directly */ + if (tp->write32 != tg3_write_indirect_reg32) + tw32(NIC_SRAM_WIN_BASE + off, val); + else + tg3_write_mem(tp, off, val); +} + static void tg3_read_mem(struct tg3 *tp, u32 off, u32 *val) { unsigned long flags; @@ -570,7 +584,7 @@ static void tg3_switch_clocks(struct tg3 *tp) u32 clock_ctrl = tr32(TG3PCI_CLOCK_CTRL); u32 orig_clock_ctrl; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780) + if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) return; orig_clock_ctrl = clock_ctrl; @@ -1210,7 +1224,7 @@ static int tg3_set_power_state(struct tg3 *tp, int state) CLOCK_CTRL_ALTCLK | CLOCK_CTRL_PWRDOWN_PLL133); udelay(40); - } else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780) { + } else if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) { /* do nothing */ } else if (!((tp->tg3_flags2 & TG3_FLG2_5750_PLUS) && (tp->tg3_flags & TG3_FLAG_ENABLE_ASF))) { @@ -3712,14 +3726,14 @@ static inline void tg3_set_mtu(struct net_device *dev, struct tg3 *tp, dev->mtu = new_mtu; if (new_mtu > ETH_DATA_LEN) { - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780) { + if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) { tp->tg3_flags2 &= ~TG3_FLG2_TSO_CAPABLE; ethtool_op_set_tso(dev, 0); } else tp->tg3_flags |= TG3_FLAG_JUMBO_RING_ENABLE; } else { - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780) + if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) tp->tg3_flags2 |= TG3_FLG2_TSO_CAPABLE; tp->tg3_flags &= ~TG3_FLAG_JUMBO_RING_ENABLE; } @@ -3850,7 +3864,7 @@ static void tg3_init_rings(struct tg3 *tp) memset(tp->tx_ring, 0, TG3_TX_RING_BYTES); tp->rx_pkt_buf_sz = RX_PKT_BUF_SZ; - if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780) && + if ((tp->tg3_flags2 & TG3_FLG2_5780_CLASS) && (tp->dev->mtu > ETH_DATA_LEN)) tp->rx_pkt_buf_sz = RX_JUMBO_PKT_BUF_SZ; @@ -3905,10 +3919,8 @@ static void tg3_init_rings(struct tg3 *tp) */ static void tg3_free_consistent(struct tg3 *tp) { - if (tp->rx_std_buffers) { - kfree(tp->rx_std_buffers); - tp->rx_std_buffers = NULL; - } + kfree(tp->rx_std_buffers); + tp->rx_std_buffers = NULL; if (tp->rx_std) { pci_free_consistent(tp->pdev, TG3_RX_RING_BYTES, tp->rx_std, tp->rx_std_mapping); @@ -4347,7 +4359,7 @@ static int tg3_chip_reset(struct tg3 *tp) val &= ~PCIX_CAPS_RELAXED_ORDERING; pci_write_config_dword(tp->pdev, TG3PCI_X_CAPS, val); - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780) { + if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) { u32 val; /* Chip reset on 5780 will reset MSI enable bit, @@ -6003,7 +6015,7 @@ static int tg3_reset_hw(struct tg3 *tp) tw32(MAC_RCV_VALUE_1, 0xffffffff & RCV_RULE_DISABLE_MASK); if ((tp->tg3_flags2 & TG3_FLG2_5705_PLUS) && - (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5780)) + !(tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) limit = 8; else limit = 16; @@ -6191,14 +6203,16 @@ static void tg3_timer(unsigned long __opaque) tp->timer_counter = tp->timer_multiplier; } - /* Heartbeat is only sent once every 120 seconds. */ + /* Heartbeat is only sent once every 2 seconds. */ if (!--tp->asf_counter) { if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) { u32 val; - tg3_write_mem(tp, NIC_SRAM_FW_CMD_MBOX, FWCMD_NICDRV_ALIVE); - tg3_write_mem(tp, NIC_SRAM_FW_CMD_LEN_MBOX, 4); - tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX, 3); + tg3_write_mem_fast(tp, NIC_SRAM_FW_CMD_MBOX, + FWCMD_NICDRV_ALIVE2); + tg3_write_mem_fast(tp, NIC_SRAM_FW_CMD_LEN_MBOX, 4); + /* 5 seconds timeout */ + tg3_write_mem_fast(tp, NIC_SRAM_FW_CMD_DATA_MBOX, 5); val = tr32(GRC_RX_CPU_EVENT); val |= (1 << 14); tw32(GRC_RX_CPU_EVENT, val); @@ -6409,7 +6423,7 @@ static int tg3_open(struct net_device *dev) tp->timer_counter = tp->timer_multiplier = (HZ / tp->timer_offset); tp->asf_counter = tp->asf_multiplier = - ((HZ / tp->timer_offset) * 120); + ((HZ / tp->timer_offset) * 2); init_timer(&tp->timer); tp->timer.expires = jiffies + tp->timer_offset; @@ -7237,7 +7251,7 @@ static int tg3_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) cmd->supported |= (SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full); - if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) + if (!(tp->tg3_flags2 & TG3_FLG2_ANY_SERDES)) cmd->supported |= (SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | SUPPORTED_10baseT_Half | @@ -7264,7 +7278,7 @@ static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct tg3 *tp = netdev_priv(dev); - if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) { + if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) { /* These are the only valid advertisement bits allowed. */ if (cmd->autoneg == AUTONEG_ENABLE && (cmd->advertising & ~(ADVERTISED_1000baseT_Half | @@ -7272,7 +7286,17 @@ static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) ADVERTISED_Autoneg | ADVERTISED_FIBRE))) return -EINVAL; - } + /* Fiber can only do SPEED_1000. */ + else if ((cmd->autoneg != AUTONEG_ENABLE) && + (cmd->speed != SPEED_1000)) + return -EINVAL; + /* Copper cannot force SPEED_1000. */ + } else if ((cmd->autoneg != AUTONEG_ENABLE) && + (cmd->speed == SPEED_1000)) + return -EINVAL; + else if ((cmd->speed == SPEED_1000) && + (tp->tg3_flags2 & TG3_FLAG_10_100_ONLY)) + return -EINVAL; tg3_full_lock(tp, 0); @@ -8380,7 +8404,7 @@ static void __devinit tg3_get_nvram_info(struct tg3 *tp) } if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) || - (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780)) { + (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) { switch (nvcfg1 & NVRAM_CFG1_VENDOR_MASK) { case FLASH_VENDOR_ATMEL_FLASH_BUFFERED: tp->nvram_jedecnum = JEDEC_ATMEL; @@ -8980,7 +9004,7 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) tp->phy_id = eeprom_phy_id; if (eeprom_phy_serdes) { - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780) + if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) tp->tg3_flags2 |= TG3_FLG2_MII_SERDES; else tp->tg3_flags2 |= TG3_FLG2_PHY_SERDES; @@ -9393,8 +9417,11 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) } /* Find msi capability. */ - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780) + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714) { + tp->tg3_flags2 |= TG3_FLG2_5780_CLASS; tp->msi_cap = pci_find_capability(tp->pdev, PCI_CAP_ID_MSI); + } /* Initialize misc host control in PCI block. */ tp->misc_host_ctrl |= (misc_ctrl_reg & @@ -9412,7 +9439,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780) + (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) tp->tg3_flags2 |= TG3_FLG2_5750_PLUS; if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) || @@ -9607,7 +9634,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) * ether_setup() via the alloc_etherdev() call */ if (tp->dev->mtu > ETH_DATA_LEN && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5780) + !(tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) tp->tg3_flags |= TG3_FLAG_JUMBO_RING_ENABLE; /* Determine WakeOnLan speed to use. */ @@ -9830,7 +9857,7 @@ static int __devinit tg3_get_device_address(struct tg3 *tp) mac_offset = 0x7c; if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 && !(tp->tg3_flags & TG3_FLG2_SUN_570X)) || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780) { + (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) { if (tr32(TG3PCI_DUAL_MAC_CTRL) & DUAL_MAC_CTRL_ID) mac_offset = 0xcc; if (tg3_nvram_lock(tp)) @@ -10148,6 +10175,9 @@ static int __devinit tg3_test_dma(struct tg3 *tp) } else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780) { /* 5780 always in PCIX mode */ tp->dma_rwctrl |= 0x00144000; + } else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714) { + /* 5714 always in PCIX mode */ + tp->dma_rwctrl |= 0x00148000; } else { tp->dma_rwctrl |= 0x001b000f; } @@ -10347,6 +10377,7 @@ static char * __devinit tg3_phy_string(struct tg3 *tp) case PHY_ID_BCM5705: return "5705"; case PHY_ID_BCM5750: return "5750"; case PHY_ID_BCM5752: return "5752"; + case PHY_ID_BCM5714: return "5714"; case PHY_ID_BCM5780: return "5780"; case PHY_ID_BCM8002: return "8002/serdes"; case 0: return "serdes"; @@ -10492,17 +10523,17 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, } /* Configure DMA attributes. */ - err = pci_set_dma_mask(pdev, 0xffffffffffffffffULL); + err = pci_set_dma_mask(pdev, DMA_64BIT_MASK); if (!err) { pci_using_dac = 1; - err = pci_set_consistent_dma_mask(pdev, 0xffffffffffffffffULL); + err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK); if (err < 0) { printk(KERN_ERR PFX "Unable to obtain 64 bit DMA " "for consistent allocations\n"); goto err_out_free_res; } } else { - err = pci_set_dma_mask(pdev, 0xffffffffULL); + err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); if (err) { printk(KERN_ERR PFX "No usable DMA configuration, " "aborting.\n"); diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 2e733c60bfa4..fb7e2a5f4a08 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -137,6 +137,7 @@ #define ASIC_REV_5750 0x04 #define ASIC_REV_5752 0x06 #define ASIC_REV_5780 0x08 +#define ASIC_REV_5714 0x09 #define GET_CHIP_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 8) #define CHIPREV_5700_AX 0x70 #define CHIPREV_5700_BX 0x71 @@ -531,6 +532,8 @@ #define MAC_SERDES_CFG_EDGE_SELECT 0x00001000 #define MAC_SERDES_STAT 0x00000594 /* 0x598 --> 0x5b0 unused */ +#define SERDES_RX_CTRL 0x000005b0 /* 5780/5714 only */ +#define SERDES_RX_SIG_DETECT 0x00000400 #define SG_DIG_CTRL 0x000005b0 #define SG_DIG_USING_HW_AUTONEG 0x80000000 #define SG_DIG_SOFT_RESET 0x40000000 @@ -1329,6 +1332,8 @@ #define GRC_LCLCTRL_CLEARINT 0x00000002 #define GRC_LCLCTRL_SETINT 0x00000004 #define GRC_LCLCTRL_INT_ON_ATTN 0x00000008 +#define GRC_LCLCTRL_USE_SIG_DETECT 0x00000010 /* 5714/5780 only */ +#define GRC_LCLCTRL_USE_EXT_SIG_DETECT 0x00000020 /* 5714/5780 only */ #define GRC_LCLCTRL_GPIO_INPUT3 0x00000020 #define GRC_LCLCTRL_GPIO_OE3 0x00000040 #define GRC_LCLCTRL_GPIO_OUTPUT3 0x00000080 @@ -1507,6 +1512,7 @@ #define FWCMD_NICDRV_IPV6ADDR_CHG 0x00000004 #define FWCMD_NICDRV_FIX_DMAR 0x00000005 #define FWCMD_NICDRV_FIX_DMAW 0x00000006 +#define FWCMD_NICDRV_ALIVE2 0x0000000d #define NIC_SRAM_FW_CMD_LEN_MBOX 0x00000b7c #define NIC_SRAM_FW_CMD_DATA_MBOX 0x00000b80 #define NIC_SRAM_FW_ASF_STATUS_MBOX 0x00000c00 @@ -2175,6 +2181,7 @@ struct tg3 { TG3_FLG2_MII_SERDES) #define TG3_FLG2_PARALLEL_DETECT 0x01000000 #define TG3_FLG2_ICH_WORKAROUND 0x02000000 +#define TG3_FLG2_5780_CLASS 0x04000000 u32 split_mode_max_reqs; #define SPLIT_MODE_5704_MAX_REQ 3 @@ -2222,6 +2229,7 @@ struct tg3 { #define PHY_ID_BCM5705 0x600081a0 #define PHY_ID_BCM5750 0x60008180 #define PHY_ID_BCM5752 0x60008100 +#define PHY_ID_BCM5714 0x60008340 #define PHY_ID_BCM5780 0x60008350 #define PHY_ID_BCM8002 0x60010140 #define PHY_ID_INVALID 0xffffffff @@ -2246,8 +2254,8 @@ struct tg3 { (X) == PHY_ID_BCM5411 || (X) == PHY_ID_BCM5701 || \ (X) == PHY_ID_BCM5703 || (X) == PHY_ID_BCM5704 || \ (X) == PHY_ID_BCM5705 || (X) == PHY_ID_BCM5750 || \ - (X) == PHY_ID_BCM5752 || (X) == PHY_ID_BCM5780 || \ - (X) == PHY_ID_BCM8002) + (X) == PHY_ID_BCM5752 || (X) == PHY_ID_BCM5714 || \ + (X) == PHY_ID_BCM5780 || (X) == PHY_ID_BCM8002) struct tg3_hw_stats *hw_stats; dma_addr_t stats_mapping; diff --git a/drivers/net/tokenring/ibmtr.c b/drivers/net/tokenring/ibmtr.c index 32057e65808b..9f491563944e 100644 --- a/drivers/net/tokenring/ibmtr.c +++ b/drivers/net/tokenring/ibmtr.c @@ -318,7 +318,7 @@ static void ibmtr_cleanup_card(struct net_device *dev) if (dev->base_addr) { outb(0,dev->base_addr+ADAPTRESET); - schedule_timeout(TR_RST_TIME); /* wait 50ms */ + schedule_timeout_uninterruptible(TR_RST_TIME); /* wait 50ms */ outb(0,dev->base_addr+ADAPTRESETREL); } @@ -854,8 +854,7 @@ static int tok_init_card(struct net_device *dev) writeb(~INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_EVEN); outb(0, PIOaddr + ADAPTRESET); - current->state=TASK_UNINTERRUPTIBLE; - schedule_timeout(TR_RST_TIME); /* wait 50ms */ + schedule_timeout_uninterruptible(TR_RST_TIME); /* wait 50ms */ outb(0, PIOaddr + ADAPTRESETREL); #ifdef ENABLE_PAGING @@ -903,8 +902,8 @@ static int tok_open(struct net_device *dev) DPRINTK("Adapter is up and running\n"); return 0; } - current->state=TASK_INTERRUPTIBLE; - i=schedule_timeout(TR_RETRY_INTERVAL); /* wait 30 seconds */ + i=schedule_timeout_interruptible(TR_RETRY_INTERVAL); + /* wait 30 seconds */ if(i!=0) break; /*prob. a signal, like the i>24*HZ case above */ } outb(0, dev->base_addr + ADAPTRESET);/* kill pending interrupts*/ diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c index 9e7923192a49..05477d24fd49 100644 --- a/drivers/net/tokenring/olympic.c +++ b/drivers/net/tokenring/olympic.c @@ -1101,7 +1101,7 @@ static int olympic_close(struct net_device *dev) while(olympic_priv->srb_queued) { - t = schedule_timeout(60*HZ); + t = schedule_timeout_interruptible(60*HZ); if(signal_pending(current)) { printk(KERN_WARNING "%s: SRB timed out.\n",dev->name); diff --git a/drivers/net/tokenring/tms380tr.c b/drivers/net/tokenring/tms380tr.c index 2e39bf1f7462..c1925590a0e1 100644 --- a/drivers/net/tokenring/tms380tr.c +++ b/drivers/net/tokenring/tms380tr.c @@ -1243,8 +1243,7 @@ void tms380tr_wait(unsigned long time) tmp = jiffies + time/(1000000/HZ); do { - current->state = TASK_INTERRUPTIBLE; - tmp = schedule_timeout(tmp); + tmp = schedule_timeout_interruptible(tmp); } while(time_after(tmp, jiffies)); #else udelay(time); diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c index a22d00198e4d..d7fb3ffe06ac 100644 --- a/drivers/net/tulip/de2104x.c +++ b/drivers/net/tulip/de2104x.c @@ -1787,10 +1787,15 @@ static void __init de21041_get_srom_info (struct de_private *de) /* DEC now has a specification but early board makers just put the address in the first EEPROM locations. */ /* This does memcmp(eedata, eedata+16, 8) */ + +#ifndef CONFIG_MIPS_COBALT + for (i = 0; i < 8; i ++) if (ee_data[i] != ee_data[16+i]) sa_offset = 20; +#endif + /* store MAC address */ for (i = 0; i < 6; i ++) de->dev->dev_addr[i] = ee_data[i + sa_offset]; @@ -2071,8 +2076,7 @@ static int __init de_init_one (struct pci_dev *pdev, return 0; err_out_iomap: - if (de->ee_data) - kfree(de->ee_data); + kfree(de->ee_data); iounmap(regs); err_out_res: pci_release_regions(pdev); @@ -2091,8 +2095,7 @@ static void __exit de_remove_one (struct pci_dev *pdev) if (!dev) BUG(); unregister_netdev(dev); - if (de->ee_data) - kfree(de->ee_data); + kfree(de->ee_data); iounmap(de->regs); pci_release_regions(pdev); pci_disable_device(pdev); diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index 6266a9a7e6e3..125ed00e95a5 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -1727,8 +1727,7 @@ err_out_free_ring: tp->rx_ring, tp->rx_ring_dma); err_out_mtable: - if (tp->mtable) - kfree (tp->mtable); + kfree (tp->mtable); pci_iounmap(pdev, ioaddr); err_out_free_res: @@ -1806,8 +1805,7 @@ static void __devexit tulip_remove_one (struct pci_dev *pdev) sizeof (struct tulip_rx_desc) * RX_RING_SIZE + sizeof (struct tulip_tx_desc) * TX_RING_SIZE, tp->rx_ring, tp->rx_ring_dma); - if (tp->mtable) - kfree (tp->mtable); + kfree (tp->mtable); pci_iounmap(pdev, tp->base_addr); free_netdev (dev); pci_release_regions (pdev); diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c index ecfa6f8805ce..4c76cb794bfb 100644 --- a/drivers/net/typhoon.c +++ b/drivers/net/typhoon.c @@ -419,10 +419,9 @@ typhoon_reset(void __iomem *ioaddr, int wait_type) TYPHOON_STATUS_WAITING_FOR_HOST) goto out; - if(wait_type == WaitSleep) { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); - } else + if(wait_type == WaitSleep) + schedule_timeout_uninterruptible(1); + else udelay(TYPHOON_UDELAY); } diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index fc7738ffbfff..241871589283 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -490,6 +490,8 @@ struct rhine_private { u8 tx_thresh, rx_thresh; struct mii_if_info mii_if; + struct work_struct tx_timeout_task; + struct work_struct check_media_task; void __iomem *base; }; @@ -497,6 +499,8 @@ static int mdio_read(struct net_device *dev, int phy_id, int location); static void mdio_write(struct net_device *dev, int phy_id, int location, int value); static int rhine_open(struct net_device *dev); static void rhine_tx_timeout(struct net_device *dev); +static void rhine_tx_timeout_task(struct net_device *dev); +static void rhine_check_media_task(struct net_device *dev); static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev); static irqreturn_t rhine_interrupt(int irq, void *dev_instance, struct pt_regs *regs); static void rhine_tx(struct net_device *dev); @@ -814,8 +818,9 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, for (i = 0; i < 6; i++) dev->dev_addr[i] = ioread8(ioaddr + StationAddr + i); + memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); - if (!is_valid_ether_addr(dev->dev_addr)) { + if (!is_valid_ether_addr(dev->perm_addr)) { rc = -EIO; printk(KERN_ERR "Invalid MAC address\n"); goto err_out_unmap; @@ -850,6 +855,12 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, if (rp->quirks & rqRhineI) dev->features |= NETIF_F_SG|NETIF_F_HW_CSUM; + INIT_WORK(&rp->tx_timeout_task, + (void (*)(void *))rhine_tx_timeout_task, dev); + + INIT_WORK(&rp->check_media_task, + (void (*)(void *))rhine_check_media_task, dev); + /* dev->name not defined before register_netdev()! */ rc = register_netdev(dev); if (rc) @@ -1076,6 +1087,11 @@ static void rhine_check_media(struct net_device *dev, unsigned int init_media) ioaddr + ChipCmd1); } +static void rhine_check_media_task(struct net_device *dev) +{ + rhine_check_media(dev, 0); +} + static void init_registers(struct net_device *dev) { struct rhine_private *rp = netdev_priv(dev); @@ -1129,8 +1145,8 @@ static void rhine_disable_linkmon(void __iomem *ioaddr, u32 quirks) if (quirks & rqRhineI) { iowrite8(0x01, ioaddr + MIIRegAddr); // MII_BMSR - /* Can be called from ISR. Evil. */ - mdelay(1); + /* Do not call from ISR! */ + msleep(1); /* 0x80 must be set immediately before turning it off */ iowrite8(0x80, ioaddr + MIICmd); @@ -1220,6 +1236,16 @@ static int rhine_open(struct net_device *dev) static void rhine_tx_timeout(struct net_device *dev) { struct rhine_private *rp = netdev_priv(dev); + + /* + * Move bulk of work outside of interrupt context + */ + schedule_work(&rp->tx_timeout_task); +} + +static void rhine_tx_timeout_task(struct net_device *dev) +{ + struct rhine_private *rp = netdev_priv(dev); void __iomem *ioaddr = rp->base; printk(KERN_WARNING "%s: Transmit timed out, status %4.4x, PHY status " @@ -1625,7 +1651,7 @@ static void rhine_error(struct net_device *dev, int intr_status) spin_lock(&rp->lock); if (intr_status & IntrLinkChange) - rhine_check_media(dev, 0); + schedule_work(&rp->check_media_task); if (intr_status & IntrStatsMax) { rp->stats.rx_crc_errors += ioread16(ioaddr + RxCRCErrs); rp->stats.rx_missed_errors += ioread16(ioaddr + RxMissed); @@ -1829,6 +1855,7 @@ static struct ethtool_ops netdev_ethtool_ops = { .set_wol = rhine_set_wol, .get_sg = ethtool_op_get_sg, .get_tx_csum = ethtool_op_get_tx_csum, + .get_perm_addr = ethtool_op_get_perm_addr, }; static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) @@ -1872,6 +1899,9 @@ static int rhine_close(struct net_device *dev) spin_unlock_irq(&rp->lock); free_irq(rp->pdev->irq, dev); + + flush_scheduled_work(); + free_rbufs(dev); free_tbufs(dev); free_ring(dev); diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index abc5cee6eedc..a368d08e7d19 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -1212,10 +1212,8 @@ static void velocity_free_td_ring(struct velocity_info *vptr) velocity_free_td_ring_entry(vptr, j, i); } - if (vptr->td_infos[j]) { - kfree(vptr->td_infos[j]); - vptr->td_infos[j] = NULL; - } + kfree(vptr->td_infos[j]); + vptr->td_infos[j] = NULL; } } diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c index 7ff814fd65d0..e392ee8b37a1 100644 --- a/drivers/net/wan/cosa.c +++ b/drivers/net/wan/cosa.c @@ -400,7 +400,7 @@ static int __init cosa_init(void) goto out_chrdev; } for (i=0; i<nr_cards; i++) { - class_device_create(cosa_class, MKDEV(cosa_major, i), + class_device_create(cosa_class, NULL, MKDEV(cosa_major, i), NULL, "cosa%d", i); err = devfs_mk_cdev(MKDEV(cosa_major, i), S_IFCHR|S_IRUSR|S_IWUSR, @@ -1617,8 +1617,7 @@ static int get_wait_data(struct cosa_data *cosa) return r; } /* sleep if not ready to read */ - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_interruptible(1); } printk(KERN_INFO "cosa: timeout in get_wait_data (status 0x%x)\n", cosa_getstatus(cosa)); @@ -1644,8 +1643,7 @@ static int put_wait_data(struct cosa_data *cosa, int data) } #if 0 /* sleep if not ready to read */ - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(1); + schedule_timeout_interruptible(1); #endif } printk(KERN_INFO "cosa%d: timeout in put_wait_data (status 0x%x)\n", diff --git a/drivers/net/wan/cycx_drv.c b/drivers/net/wan/cycx_drv.c index 9e56fc346ba4..e6d005726aad 100644 --- a/drivers/net/wan/cycx_drv.c +++ b/drivers/net/wan/cycx_drv.c @@ -109,7 +109,7 @@ static long cycx_2x_irq_options[] = { 7, 3, 5, 9, 10, 11, 12, 15 }; * < 0 error. * Context: process */ -int __init cycx_drv_init(void) +static int __init cycx_drv_init(void) { printk(KERN_INFO "%s v%u.%u %s\n", fullname, MOD_VERSION, MOD_RELEASE, copyright); @@ -119,7 +119,7 @@ int __init cycx_drv_init(void) /* Module 'remove' entry point. * o release all remaining system resources */ -void cycx_drv_cleanup(void) +static void cycx_drv_cleanup(void) { } @@ -184,8 +184,7 @@ int cycx_down(struct cycx_hw *hw) } /* Enable interrupt generation. */ -EXPORT_SYMBOL(cycx_inten); -void cycx_inten(struct cycx_hw *hw) +static void cycx_inten(struct cycx_hw *hw) { writeb(0, hw->dpmbase); } diff --git a/drivers/net/wan/cycx_main.c b/drivers/net/wan/cycx_main.c index 7b48064364dc..430b1f630fb4 100644 --- a/drivers/net/wan/cycx_main.c +++ b/drivers/net/wan/cycx_main.c @@ -103,7 +103,7 @@ static struct cycx_device *cycx_card_array; /* adapter data space */ * < 0 error. * Context: process */ -int __init cycx_init(void) +static int __init cycx_init(void) { int cnt, err = -ENOMEM; diff --git a/drivers/net/wan/cycx_x25.c b/drivers/net/wan/cycx_x25.c index 02d57c0b4243..a631d1c2fa14 100644 --- a/drivers/net/wan/cycx_x25.c +++ b/drivers/net/wan/cycx_x25.c @@ -78,6 +78,7 @@ #define CYCLOMX_X25_DEBUG 1 +#include <linux/ctype.h> /* isdigit() */ #include <linux/errno.h> /* return codes */ #include <linux/if_arp.h> /* ARPHRD_HWX25 */ #include <linux/kernel.h> /* printk(), and other useful stuff */ @@ -418,7 +419,7 @@ static int cycx_wan_new_if(struct wan_device *wandev, struct net_device *dev, /* Set channel timeouts (default if not specified) */ chan->idle_tmout = conf->idle_timeout ? conf->idle_timeout : 90; - } else if (is_digit(conf->addr[0])) { /* PVC */ + } else if (isdigit(conf->addr[0])) { /* PVC */ s16 lcn = dec_to_uint(conf->addr, 0); if (lcn >= card->u.x.lo_pvc && lcn <= card->u.x.hi_pvc) @@ -1531,7 +1532,7 @@ static unsigned dec_to_uint(u8 *str, int len) if (!len) len = strlen(str); - for (; len && is_digit(*str); ++str, --len) + for (; len && isdigit(*str); ++str, --len) val = (val * 10) + (*str - (unsigned) '0'); return val; diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c index 520a77a798e2..2f61a47b4716 100644 --- a/drivers/net/wan/dscc4.c +++ b/drivers/net/wan/dscc4.c @@ -446,8 +446,8 @@ static inline unsigned int dscc4_tx_quiescent(struct dscc4_dev_priv *dpriv, return readl(dpriv->base_addr + CH0FTDA + dpriv->dev_id*4) == dpriv->ltda; } -int state_check(u32 state, struct dscc4_dev_priv *dpriv, struct net_device *dev, - const char *msg) +static int state_check(u32 state, struct dscc4_dev_priv *dpriv, + struct net_device *dev, const char *msg) { int ret = 0; @@ -466,8 +466,9 @@ int state_check(u32 state, struct dscc4_dev_priv *dpriv, struct net_device *dev, return ret; } -void dscc4_tx_print(struct net_device *dev, struct dscc4_dev_priv *dpriv, - char *msg) +static void dscc4_tx_print(struct net_device *dev, + struct dscc4_dev_priv *dpriv, + char *msg) { printk(KERN_DEBUG "%s: tx_current=%02d tx_dirty=%02d (%s)\n", dev->name, dpriv->tx_current, dpriv->tx_dirty, msg); @@ -507,7 +508,8 @@ static void dscc4_release_ring(struct dscc4_dev_priv *dpriv) } } -inline int try_get_rx_skb(struct dscc4_dev_priv *dpriv, struct net_device *dev) +static inline int try_get_rx_skb(struct dscc4_dev_priv *dpriv, + struct net_device *dev) { unsigned int dirty = dpriv->rx_dirty%RX_RING_SIZE; struct RxFD *rx_fd = dpriv->rx_fd + dirty; @@ -542,8 +544,7 @@ static int dscc4_wait_ack_cec(struct dscc4_dev_priv *dpriv, msg, i); goto done; } - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(10); + schedule_timeout_uninterruptible(10); rmb(); } while (++i > 0); printk(KERN_ERR "%s: %s timeout\n", dev->name, msg); @@ -588,8 +589,7 @@ static inline int dscc4_xpr_ack(struct dscc4_dev_priv *dpriv) (dpriv->iqtx[cur] & Xpr)) break; smp_rmb(); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(10); + schedule_timeout_uninterruptible(10); } while (++i > 0); return (i >= 0 ) ? i : -EAGAIN; @@ -1035,8 +1035,7 @@ static void dscc4_pci_reset(struct pci_dev *pdev, void __iomem *ioaddr) /* Flush posted writes */ readl(ioaddr + GSTAR); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(10); + schedule_timeout_uninterruptible(10); for (i = 0; i < 16; i++) pci_write_config_dword(pdev, i << 2, dscc4_pci_config_store[i]); @@ -1894,7 +1893,7 @@ try: * It failed and locked solid. Thus the introduction of a dummy skb. * Problem is acknowledged in errata sheet DS5. Joy :o/ */ -struct sk_buff *dscc4_init_dummy_skb(struct dscc4_dev_priv *dpriv) +static struct sk_buff *dscc4_init_dummy_skb(struct dscc4_dev_priv *dpriv) { struct sk_buff *skb; diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c index 2c83cca34b86..7981a2c7906e 100644 --- a/drivers/net/wan/farsync.c +++ b/drivers/net/wan/farsync.c @@ -74,11 +74,11 @@ MODULE_LICENSE("GPL"); /* * Modules parameters and associated varaibles */ -int fst_txq_low = FST_LOW_WATER_MARK; -int fst_txq_high = FST_HIGH_WATER_MARK; -int fst_max_reads = 7; -int fst_excluded_cards = 0; -int fst_excluded_list[FST_MAX_CARDS]; +static int fst_txq_low = FST_LOW_WATER_MARK; +static int fst_txq_high = FST_HIGH_WATER_MARK; +static int fst_max_reads = 7; +static int fst_excluded_cards = 0; +static int fst_excluded_list[FST_MAX_CARDS]; module_param(fst_txq_low, int, 0); module_param(fst_txq_high, int, 0); @@ -572,13 +572,13 @@ static void do_bottom_half_rx(struct fst_card_info *card); static void fst_process_tx_work_q(unsigned long work_q); static void fst_process_int_work_q(unsigned long work_q); -DECLARE_TASKLET(fst_tx_task, fst_process_tx_work_q, 0); -DECLARE_TASKLET(fst_int_task, fst_process_int_work_q, 0); +static DECLARE_TASKLET(fst_tx_task, fst_process_tx_work_q, 0); +static DECLARE_TASKLET(fst_int_task, fst_process_int_work_q, 0); -struct fst_card_info *fst_card_array[FST_MAX_CARDS]; -spinlock_t fst_work_q_lock; -u64 fst_work_txq; -u64 fst_work_intq; +static struct fst_card_info *fst_card_array[FST_MAX_CARDS]; +static spinlock_t fst_work_q_lock; +static u64 fst_work_txq; +static u64 fst_work_intq; static void fst_q_work_item(u64 * queue, int card_index) @@ -980,8 +980,7 @@ fst_issue_cmd(struct fst_port_info *port, unsigned short cmd) /* Wait for any previous command to complete */ while (mbval > NAK) { spin_unlock_irqrestore(&card->card_lock, flags); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_uninterruptible(1); spin_lock_irqsave(&card->card_lock, flags); if (++safety > 2000) { @@ -1498,7 +1497,7 @@ do_bottom_half_rx(struct fst_card_info *card) * The interrupt service routine * Dev_id is our fst_card_info pointer */ -irqreturn_t +static irqreturn_t fst_intr(int irq, void *dev_id, struct pt_regs *regs) { struct fst_card_info *card; diff --git a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c index a5d6891c9d4c..e1601d35dced 100644 --- a/drivers/net/wan/hdlc_fr.c +++ b/drivers/net/wan/hdlc_fr.c @@ -330,7 +330,7 @@ static int pvc_close(struct net_device *dev) -int pvc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +static int pvc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { pvc_device *pvc = dev_to_pvc(dev); fr_proto_pvc_info info; diff --git a/drivers/net/wan/lmc/lmc_debug.c b/drivers/net/wan/lmc/lmc_debug.c index 9dccd9546a17..3b94352b0d03 100644 --- a/drivers/net/wan/lmc/lmc_debug.c +++ b/drivers/net/wan/lmc/lmc_debug.c @@ -8,10 +8,10 @@ /* * Prints out len, max to 80 octets using printk, 20 per line */ -void lmcConsoleLog(char *type, unsigned char *ucData, int iLen) -{ #ifdef DEBUG #ifdef LMC_PACKET_LOG +void lmcConsoleLog(char *type, unsigned char *ucData, int iLen) +{ int iNewLine = 1; char str[80], *pstr; @@ -43,26 +43,24 @@ void lmcConsoleLog(char *type, unsigned char *ucData, int iLen) } sprintf(pstr, "\n"); printk(str); +} #endif #endif -} #ifdef DEBUG u_int32_t lmcEventLogIndex = 0; u_int32_t lmcEventLogBuf[LMC_EVENTLOGSIZE * LMC_EVENTLOGARGS]; -#endif void lmcEventLog (u_int32_t EventNum, u_int32_t arg2, u_int32_t arg3) { -#ifdef DEBUG lmcEventLogBuf[lmcEventLogIndex++] = EventNum; lmcEventLogBuf[lmcEventLogIndex++] = arg2; lmcEventLogBuf[lmcEventLogIndex++] = arg3; lmcEventLogBuf[lmcEventLogIndex++] = jiffies; lmcEventLogIndex &= (LMC_EVENTLOGSIZE * LMC_EVENTLOGARGS) - 1; -#endif } +#endif /* DEBUG */ void lmc_trace(struct net_device *dev, char *msg){ #ifdef LMC_TRACE diff --git a/drivers/net/wan/lmc/lmc_media.c b/drivers/net/wan/lmc/lmc_media.c index f55ce76b00ed..af8b55fdd9d9 100644 --- a/drivers/net/wan/lmc/lmc_media.c +++ b/drivers/net/wan/lmc/lmc_media.c @@ -48,14 +48,6 @@ */ /* - * For lack of a better place, put the SSI cable stuff here. - */ -char *lmc_t1_cables[] = { - "V.10/RS423", "EIA530A", "reserved", "X.21", "V.35", - "EIA449/EIA530/V.36", "V.28/EIA232", "none", NULL -}; - -/* * protocol independent method. */ static void lmc_set_protocol (lmc_softc_t * const, lmc_ctl_t *); diff --git a/drivers/net/wan/pc300.h b/drivers/net/wan/pc300.h index 73401b0f0151..2024b26b99e6 100644 --- a/drivers/net/wan/pc300.h +++ b/drivers/net/wan/pc300.h @@ -472,24 +472,8 @@ enum pc300_loopback_cmds { #ifdef __KERNEL__ /* Function Prototypes */ -int dma_buf_write(pc300_t *, int, ucchar *, int); -int dma_buf_read(pc300_t *, int, struct sk_buff *); void tx_dma_start(pc300_t *, int); -void rx_dma_start(pc300_t *, int); -void tx_dma_stop(pc300_t *, int); -void rx_dma_stop(pc300_t *, int); -int cpc_queue_xmit(struct sk_buff *, struct net_device *); -void cpc_net_rx(struct net_device *); -void cpc_sca_status(pc300_t *, int); -int cpc_change_mtu(struct net_device *, int); -int cpc_ioctl(struct net_device *, struct ifreq *, int); -int ch_config(pc300dev_t *); -int rx_config(pc300dev_t *); -int tx_config(pc300dev_t *); -void cpc_opench(pc300dev_t *); -void cpc_closech(pc300dev_t *); int cpc_open(struct net_device *dev); -int cpc_close(struct net_device *dev); int cpc_set_media(hdlc_device *, int); #endif /* __KERNEL__ */ diff --git a/drivers/net/wan/pc300_drv.c b/drivers/net/wan/pc300_drv.c index 3e7753b10717..a3e65d1bc19b 100644 --- a/drivers/net/wan/pc300_drv.c +++ b/drivers/net/wan/pc300_drv.c @@ -291,6 +291,7 @@ static uclong detect_ram(pc300_t *); static void plx_init(pc300_t *); static void cpc_trace(struct net_device *, struct sk_buff *, char); static int cpc_attach(struct net_device *, unsigned short, unsigned short); +static int cpc_close(struct net_device *dev); #ifdef CONFIG_PC300_MLPPP void cpc_tty_init(pc300dev_t * dev); @@ -437,7 +438,7 @@ static void rx_dma_buf_check(pc300_t * card, int ch) printk("\n"); } -int dma_get_rx_frame_size(pc300_t * card, int ch) +static int dma_get_rx_frame_size(pc300_t * card, int ch) { volatile pcsca_bd_t __iomem *ptdescr; ucshort first_bd = card->chan[ch].rx_first_bd; @@ -462,7 +463,7 @@ int dma_get_rx_frame_size(pc300_t * card, int ch) * dma_buf_write: writes a frame to the Tx DMA buffers * NOTE: this function writes one frame at a time. */ -int dma_buf_write(pc300_t * card, int ch, ucchar * ptdata, int len) +static int dma_buf_write(pc300_t * card, int ch, ucchar * ptdata, int len) { int i, nchar; volatile pcsca_bd_t __iomem *ptdescr; @@ -503,7 +504,7 @@ int dma_buf_write(pc300_t * card, int ch, ucchar * ptdata, int len) * dma_buf_read: reads a frame from the Rx DMA buffers * NOTE: this function reads one frame at a time. */ -int dma_buf_read(pc300_t * card, int ch, struct sk_buff *skb) +static int dma_buf_read(pc300_t * card, int ch, struct sk_buff *skb) { int nchar; pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; @@ -560,7 +561,7 @@ int dma_buf_read(pc300_t * card, int ch, struct sk_buff *skb) return (rcvd); } -void tx_dma_stop(pc300_t * card, int ch) +static void tx_dma_stop(pc300_t * card, int ch) { void __iomem *scabase = card->hw.scabase; ucchar drr_ena_bit = 1 << (5 + 2 * ch); @@ -571,7 +572,7 @@ void tx_dma_stop(pc300_t * card, int ch) cpc_writeb(scabase + DRR, drr_rst_bit & ~drr_ena_bit); } -void rx_dma_stop(pc300_t * card, int ch) +static void rx_dma_stop(pc300_t * card, int ch) { void __iomem *scabase = card->hw.scabase; ucchar drr_ena_bit = 1 << (4 + 2 * ch); @@ -582,7 +583,7 @@ void rx_dma_stop(pc300_t * card, int ch) cpc_writeb(scabase + DRR, drr_rst_bit & ~drr_ena_bit); } -void rx_dma_start(pc300_t * card, int ch) +static void rx_dma_start(pc300_t * card, int ch) { void __iomem *scabase = card->hw.scabase; pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; @@ -607,7 +608,7 @@ void rx_dma_start(pc300_t * card, int ch) /*************************/ /*** FALC Routines ***/ /*************************/ -void falc_issue_cmd(pc300_t * card, int ch, ucchar cmd) +static void falc_issue_cmd(pc300_t * card, int ch, ucchar cmd) { void __iomem *falcbase = card->hw.falcbase; unsigned long i = 0; @@ -622,7 +623,7 @@ void falc_issue_cmd(pc300_t * card, int ch, ucchar cmd) cpc_writeb(falcbase + F_REG(CMDR, ch), cmd); } -void falc_intr_enable(pc300_t * card, int ch) +static void falc_intr_enable(pc300_t * card, int ch) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; @@ -672,7 +673,7 @@ void falc_intr_enable(pc300_t * card, int ch) } } -void falc_open_timeslot(pc300_t * card, int ch, int timeslot) +static void falc_open_timeslot(pc300_t * card, int ch, int timeslot) { void __iomem *falcbase = card->hw.falcbase; ucchar tshf = card->chan[ch].falc.offset; @@ -688,7 +689,7 @@ void falc_open_timeslot(pc300_t * card, int ch, int timeslot) (0x80 >> (timeslot & 0x07))); } -void falc_close_timeslot(pc300_t * card, int ch, int timeslot) +static void falc_close_timeslot(pc300_t * card, int ch, int timeslot) { void __iomem *falcbase = card->hw.falcbase; ucchar tshf = card->chan[ch].falc.offset; @@ -704,7 +705,7 @@ void falc_close_timeslot(pc300_t * card, int ch, int timeslot) ~(0x80 >> (timeslot & 0x07))); } -void falc_close_all_timeslots(pc300_t * card, int ch) +static void falc_close_all_timeslots(pc300_t * card, int ch) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; @@ -726,7 +727,7 @@ void falc_close_all_timeslots(pc300_t * card, int ch) } } -void falc_open_all_timeslots(pc300_t * card, int ch) +static void falc_open_all_timeslots(pc300_t * card, int ch) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; @@ -758,7 +759,7 @@ void falc_open_all_timeslots(pc300_t * card, int ch) } } -void falc_init_timeslot(pc300_t * card, int ch) +static void falc_init_timeslot(pc300_t * card, int ch) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; @@ -776,7 +777,7 @@ void falc_init_timeslot(pc300_t * card, int ch) } } -void falc_enable_comm(pc300_t * card, int ch) +static void falc_enable_comm(pc300_t * card, int ch) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; falc_t *pfalc = (falc_t *) & chan->falc; @@ -792,7 +793,7 @@ void falc_enable_comm(pc300_t * card, int ch) ~((CPLD_REG1_FALC_DCD | CPLD_REG1_FALC_CTS) << (2 * ch))); } -void falc_disable_comm(pc300_t * card, int ch) +static void falc_disable_comm(pc300_t * card, int ch) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; falc_t *pfalc = (falc_t *) & chan->falc; @@ -806,7 +807,7 @@ void falc_disable_comm(pc300_t * card, int ch) ((CPLD_REG1_FALC_DCD | CPLD_REG1_FALC_CTS) << (2 * ch))); } -void falc_init_t1(pc300_t * card, int ch) +static void falc_init_t1(pc300_t * card, int ch) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; @@ -975,7 +976,7 @@ void falc_init_t1(pc300_t * card, int ch) falc_close_all_timeslots(card, ch); } -void falc_init_e1(pc300_t * card, int ch) +static void falc_init_e1(pc300_t * card, int ch) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; @@ -1155,7 +1156,7 @@ void falc_init_e1(pc300_t * card, int ch) falc_close_all_timeslots(card, ch); } -void falc_init_hdlc(pc300_t * card, int ch) +static void falc_init_hdlc(pc300_t * card, int ch) { void __iomem *falcbase = card->hw.falcbase; pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; @@ -1181,7 +1182,7 @@ void falc_init_hdlc(pc300_t * card, int ch) falc_intr_enable(card, ch); } -void te_config(pc300_t * card, int ch) +static void te_config(pc300_t * card, int ch) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; @@ -1241,7 +1242,7 @@ void te_config(pc300_t * card, int ch) CPC_UNLOCK(card, flags); } -void falc_check_status(pc300_t * card, int ch, unsigned char frs0) +static void falc_check_status(pc300_t * card, int ch, unsigned char frs0) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; @@ -1397,7 +1398,7 @@ void falc_check_status(pc300_t * card, int ch, unsigned char frs0) } } -void falc_update_stats(pc300_t * card, int ch) +static void falc_update_stats(pc300_t * card, int ch) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; @@ -1450,7 +1451,7 @@ void falc_update_stats(pc300_t * card, int ch) * the synchronizer and then sent to the system interface. *---------------------------------------------------------------------------- */ -void falc_remote_loop(pc300_t * card, int ch, int loop_on) +static void falc_remote_loop(pc300_t * card, int ch, int loop_on) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; @@ -1495,7 +1496,7 @@ void falc_remote_loop(pc300_t * card, int ch, int loop_on) * coding must be identical. *---------------------------------------------------------------------------- */ -void falc_local_loop(pc300_t * card, int ch, int loop_on) +static void falc_local_loop(pc300_t * card, int ch, int loop_on) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; falc_t *pfalc = (falc_t *) & chan->falc; @@ -1522,7 +1523,7 @@ void falc_local_loop(pc300_t * card, int ch, int loop_on) * looped. They are originated by the FALC-LH transmitter. *---------------------------------------------------------------------------- */ -void falc_payload_loop(pc300_t * card, int ch, int loop_on) +static void falc_payload_loop(pc300_t * card, int ch, int loop_on) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; @@ -1576,7 +1577,7 @@ void falc_payload_loop(pc300_t * card, int ch, int loop_on) * Description: Turns XLU bit off in the proper register *---------------------------------------------------------------------------- */ -void turn_off_xlu(pc300_t * card, int ch) +static void turn_off_xlu(pc300_t * card, int ch) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; @@ -1597,7 +1598,7 @@ void turn_off_xlu(pc300_t * card, int ch) * Description: Turns XLD bit off in the proper register *---------------------------------------------------------------------------- */ -void turn_off_xld(pc300_t * card, int ch) +static void turn_off_xld(pc300_t * card, int ch) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; @@ -1619,7 +1620,7 @@ void turn_off_xld(pc300_t * card, int ch) * to generate a LOOP activation code over a T1/E1 line. *---------------------------------------------------------------------------- */ -void falc_generate_loop_up_code(pc300_t * card, int ch) +static void falc_generate_loop_up_code(pc300_t * card, int ch) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; @@ -1652,7 +1653,7 @@ void falc_generate_loop_up_code(pc300_t * card, int ch) * to generate a LOOP deactivation code over a T1/E1 line. *---------------------------------------------------------------------------- */ -void falc_generate_loop_down_code(pc300_t * card, int ch) +static void falc_generate_loop_down_code(pc300_t * card, int ch) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; @@ -1682,7 +1683,7 @@ void falc_generate_loop_down_code(pc300_t * card, int ch) * it on the reception side. *---------------------------------------------------------------------------- */ -void falc_pattern_test(pc300_t * card, int ch, unsigned int activate) +static void falc_pattern_test(pc300_t * card, int ch, unsigned int activate) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; @@ -1729,7 +1730,7 @@ void falc_pattern_test(pc300_t * card, int ch, unsigned int activate) * Description: This routine returns the bit error counter value *---------------------------------------------------------------------------- */ -ucshort falc_pattern_test_error(pc300_t * card, int ch) +static ucshort falc_pattern_test_error(pc300_t * card, int ch) { pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; falc_t *pfalc = (falc_t *) & chan->falc; @@ -1769,7 +1770,7 @@ cpc_trace(struct net_device *dev, struct sk_buff *skb_main, char rx_tx) netif_rx(skb); } -void cpc_tx_timeout(struct net_device *dev) +static void cpc_tx_timeout(struct net_device *dev) { pc300dev_t *d = (pc300dev_t *) dev->priv; pc300ch_t *chan = (pc300ch_t *) d->chan; @@ -1797,7 +1798,7 @@ void cpc_tx_timeout(struct net_device *dev) netif_wake_queue(dev); } -int cpc_queue_xmit(struct sk_buff *skb, struct net_device *dev) +static int cpc_queue_xmit(struct sk_buff *skb, struct net_device *dev) { pc300dev_t *d = (pc300dev_t *) dev->priv; pc300ch_t *chan = (pc300ch_t *) d->chan; @@ -1880,7 +1881,7 @@ int cpc_queue_xmit(struct sk_buff *skb, struct net_device *dev) return 0; } -void cpc_net_rx(struct net_device *dev) +static void cpc_net_rx(struct net_device *dev) { pc300dev_t *d = (pc300dev_t *) dev->priv; pc300ch_t *chan = (pc300ch_t *) d->chan; @@ -2403,7 +2404,7 @@ static irqreturn_t cpc_intr(int irq, void *dev_id, struct pt_regs *regs) return IRQ_HANDLED; } -void cpc_sca_status(pc300_t * card, int ch) +static void cpc_sca_status(pc300_t * card, int ch) { ucchar ilar; void __iomem *scabase = card->hw.scabase; @@ -2495,7 +2496,7 @@ void cpc_sca_status(pc300_t * card, int ch) } } -void cpc_falc_status(pc300_t * card, int ch) +static void cpc_falc_status(pc300_t * card, int ch) { pc300ch_t *chan = &card->chan[ch]; falc_t *pfalc = (falc_t *) & chan->falc; @@ -2523,7 +2524,7 @@ void cpc_falc_status(pc300_t * card, int ch) CPC_UNLOCK(card, flags); } -int cpc_change_mtu(struct net_device *dev, int new_mtu) +static int cpc_change_mtu(struct net_device *dev, int new_mtu) { if ((new_mtu < 128) || (new_mtu > PC300_DEF_MTU)) return -EINVAL; @@ -2531,7 +2532,7 @@ int cpc_change_mtu(struct net_device *dev, int new_mtu) return 0; } -int cpc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +static int cpc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { hdlc_device *hdlc = dev_to_hdlc(dev); pc300dev_t *d = (pc300dev_t *) dev->priv; @@ -2856,7 +2857,7 @@ static int clock_rate_calc(uclong rate, uclong clock, int *br_io) } } -int ch_config(pc300dev_t * d) +static int ch_config(pc300dev_t * d) { pc300ch_t *chan = (pc300ch_t *) d->chan; pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; @@ -3004,7 +3005,7 @@ int ch_config(pc300dev_t * d) return 0; } -int rx_config(pc300dev_t * d) +static int rx_config(pc300dev_t * d) { pc300ch_t *chan = (pc300ch_t *) d->chan; pc300_t *card = (pc300_t *) chan->card; @@ -3035,7 +3036,7 @@ int rx_config(pc300dev_t * d) return 0; } -int tx_config(pc300dev_t * d) +static int tx_config(pc300dev_t * d) { pc300ch_t *chan = (pc300ch_t *) d->chan; pc300_t *card = (pc300_t *) chan->card; @@ -3098,7 +3099,7 @@ static int cpc_attach(struct net_device *dev, unsigned short encoding, return 0; } -void cpc_opench(pc300dev_t * d) +static void cpc_opench(pc300dev_t * d) { pc300ch_t *chan = (pc300ch_t *) d->chan; pc300_t *card = (pc300_t *) chan->card; @@ -3116,7 +3117,7 @@ void cpc_opench(pc300dev_t * d) cpc_readb(scabase + M_REG(CTL, ch)) & ~(CTL_RTS | CTL_DTR)); } -void cpc_closech(pc300dev_t * d) +static void cpc_closech(pc300dev_t * d) { pc300ch_t *chan = (pc300ch_t *) d->chan; pc300_t *card = (pc300_t *) chan->card; @@ -3173,7 +3174,7 @@ int cpc_open(struct net_device *dev) return 0; } -int cpc_close(struct net_device *dev) +static int cpc_close(struct net_device *dev) { hdlc_device *hdlc = dev_to_hdlc(dev); pc300dev_t *d = (pc300dev_t *) dev->priv; diff --git a/drivers/net/wan/pc300_tty.c b/drivers/net/wan/pc300_tty.c index 8454bf6caaa7..52f26b9c69d2 100644 --- a/drivers/net/wan/pc300_tty.c +++ b/drivers/net/wan/pc300_tty.c @@ -112,10 +112,10 @@ typedef struct _st_cpc_tty_area { static struct tty_driver serial_drv; /* local variables */ -st_cpc_tty_area cpc_tty_area[CPC_TTY_NPORTS]; +static st_cpc_tty_area cpc_tty_area[CPC_TTY_NPORTS]; -int cpc_tty_cnt=0; /* number of intrfaces configured with MLPPP */ -int cpc_tty_unreg_flag = 0; +static int cpc_tty_cnt = 0; /* number of intrfaces configured with MLPPP */ +static int cpc_tty_unreg_flag = 0; /* TTY functions prototype */ static int cpc_tty_open(struct tty_struct *tty, struct file *flip); @@ -132,9 +132,9 @@ static void cpc_tty_trace(pc300dev_t *dev, char* buf, int len, char rxtx); static void cpc_tty_signal_off(pc300dev_t *pc300dev, unsigned char); static void cpc_tty_signal_on(pc300dev_t *pc300dev, unsigned char); -int pc300_tiocmset(struct tty_struct *, struct file *, - unsigned int, unsigned int); -int pc300_tiocmget(struct tty_struct *, struct file *); +static int pc300_tiocmset(struct tty_struct *, struct file *, + unsigned int, unsigned int); +static int pc300_tiocmget(struct tty_struct *, struct file *); /* functions called by PC300 driver */ void cpc_tty_init(pc300dev_t *dev); @@ -538,8 +538,8 @@ static int cpc_tty_chars_in_buffer(struct tty_struct *tty) return(0); } -int pc300_tiocmset(struct tty_struct *tty, struct file *file, - unsigned int set, unsigned int clear) +static int pc300_tiocmset(struct tty_struct *tty, struct file *file, + unsigned int set, unsigned int clear) { st_cpc_tty_area *cpc_tty; @@ -565,7 +565,7 @@ int pc300_tiocmset(struct tty_struct *tty, struct file *file, return 0; } -int pc300_tiocmget(struct tty_struct *tty, struct file *file) +static int pc300_tiocmget(struct tty_struct *tty, struct file *file) { unsigned int result; unsigned char status; diff --git a/drivers/net/wan/sdla.c b/drivers/net/wan/sdla.c index 3ac9a45b20fa..036adc4f8ba7 100644 --- a/drivers/net/wan/sdla.c +++ b/drivers/net/wan/sdla.c @@ -182,7 +182,7 @@ static char sdla_byte(struct net_device *dev, int addr) return(byte); } -void sdla_stop(struct net_device *dev) +static void sdla_stop(struct net_device *dev) { struct frad_local *flp; @@ -209,7 +209,7 @@ void sdla_stop(struct net_device *dev) } } -void sdla_start(struct net_device *dev) +static void sdla_start(struct net_device *dev) { struct frad_local *flp; @@ -247,7 +247,7 @@ void sdla_start(struct net_device *dev) * ***************************************************/ -int sdla_z80_poll(struct net_device *dev, int z80_addr, int jiffs, char resp1, char resp2) +static int sdla_z80_poll(struct net_device *dev, int z80_addr, int jiffs, char resp1, char resp2) { unsigned long start, done, now; char resp, *temp; @@ -505,7 +505,7 @@ static int sdla_cmd(struct net_device *dev, int cmd, short dlci, short flags, static int sdla_reconfig(struct net_device *dev); -int sdla_activate(struct net_device *slave, struct net_device *master) +static int sdla_activate(struct net_device *slave, struct net_device *master) { struct frad_local *flp; int i; @@ -527,7 +527,7 @@ int sdla_activate(struct net_device *slave, struct net_device *master) return(0); } -int sdla_deactivate(struct net_device *slave, struct net_device *master) +static int sdla_deactivate(struct net_device *slave, struct net_device *master) { struct frad_local *flp; int i; @@ -549,7 +549,7 @@ int sdla_deactivate(struct net_device *slave, struct net_device *master) return(0); } -int sdla_assoc(struct net_device *slave, struct net_device *master) +static int sdla_assoc(struct net_device *slave, struct net_device *master) { struct frad_local *flp; int i; @@ -585,7 +585,7 @@ int sdla_assoc(struct net_device *slave, struct net_device *master) return(0); } -int sdla_deassoc(struct net_device *slave, struct net_device *master) +static int sdla_deassoc(struct net_device *slave, struct net_device *master) { struct frad_local *flp; int i; @@ -613,7 +613,7 @@ int sdla_deassoc(struct net_device *slave, struct net_device *master) return(0); } -int sdla_dlci_conf(struct net_device *slave, struct net_device *master, int get) +static int sdla_dlci_conf(struct net_device *slave, struct net_device *master, int get) { struct frad_local *flp; struct dlci_local *dlp; @@ -1324,7 +1324,7 @@ NOTE: This is rather a useless action right now, as the return(0); } -int sdla_change_mtu(struct net_device *dev, int new_mtu) +static int sdla_change_mtu(struct net_device *dev, int new_mtu) { struct frad_local *flp; @@ -1337,7 +1337,7 @@ int sdla_change_mtu(struct net_device *dev, int new_mtu) return(-EOPNOTSUPP); } -int sdla_set_config(struct net_device *dev, struct ifmap *map) +static int sdla_set_config(struct net_device *dev, struct ifmap *map) { struct frad_local *flp; int i; diff --git a/drivers/net/wan/sdla_fr.c b/drivers/net/wan/sdla_fr.c index 0497dbdb8631..7f1ce9d4333e 100644 --- a/drivers/net/wan/sdla_fr.c +++ b/drivers/net/wan/sdla_fr.c @@ -822,7 +822,7 @@ static int new_if(struct wan_device* wandev, struct net_device* dev, chan->card = card; /* verify media address */ - if (is_digit(conf->addr[0])) { + if (isdigit(conf->addr[0])) { dlci = dec_to_uint(conf->addr, 0); @@ -3456,7 +3456,7 @@ static unsigned int dec_to_uint (unsigned char* str, int len) if (!len) len = strlen(str); - for (val = 0; len && is_digit(*str); ++str, --len) + for (val = 0; len && isdigit(*str); ++str, --len) val = (val * 10) + (*str - (unsigned)'0'); return val; diff --git a/drivers/net/wan/sdla_x25.c b/drivers/net/wan/sdla_x25.c index 8a95d61a2f8f..63f846d6f3a6 100644 --- a/drivers/net/wan/sdla_x25.c +++ b/drivers/net/wan/sdla_x25.c @@ -957,7 +957,7 @@ static int new_if(struct wan_device* wandev, struct net_device* dev, chan->hold_timeout = (conf->hold_timeout) ? conf->hold_timeout : 10; - }else if (is_digit(conf->addr[0])){ /* PVC */ + }else if (isdigit(conf->addr[0])){ /* PVC */ int lcn = dec_to_uint(conf->addr, 0); if ((lcn >= card->u.x.lo_pvc) && (lcn <= card->u.x.hi_pvc)){ @@ -3875,7 +3875,7 @@ static unsigned int dec_to_uint (unsigned char* str, int len) if (!len) len = strlen(str); - for (val = 0; len && is_digit(*str); ++str, --len) + for (val = 0; len && isdigit(*str); ++str, --len) val = (val * 10) + (*str - (unsigned)'0'); return val; @@ -3896,9 +3896,9 @@ static unsigned int hex_to_uint (unsigned char* str, int len) for (val = 0; len; ++str, --len) { ch = *str; - if (is_digit(ch)) + if (isdigit(ch)) val = (val << 4) + (ch - (unsigned)'0'); - else if (is_hex_digit(ch)) + else if (isxdigit(ch)) val = (val << 4) + ((ch & 0xDF) - (unsigned)'A' + 10); else break; } diff --git a/drivers/net/wan/sdladrv.c b/drivers/net/wan/sdladrv.c index c8bc6da57a41..7c2cf2e76300 100644 --- a/drivers/net/wan/sdladrv.c +++ b/drivers/net/wan/sdladrv.c @@ -642,9 +642,7 @@ int sdla_mapmem (sdlahw_t* hw, unsigned long addr) * Enable interrupt generation. */ -EXPORT_SYMBOL(sdla_inten); - -int sdla_inten (sdlahw_t* hw) +static int sdla_inten (sdlahw_t* hw) { unsigned port = hw->port; int tmp, i; @@ -698,8 +696,7 @@ int sdla_inten (sdlahw_t* hw) * Disable interrupt generation. */ -EXPORT_SYMBOL(sdla_intde); - +#if 0 int sdla_intde (sdlahw_t* hw) { unsigned port = hw->port; @@ -748,14 +745,13 @@ int sdla_intde (sdlahw_t* hw) } return 0; } +#endif /* 0 */ /*============================================================================ * Acknowledge SDLA hardware interrupt. */ -EXPORT_SYMBOL(sdla_intack); - -int sdla_intack (sdlahw_t* hw) +static int sdla_intack (sdlahw_t* hw) { unsigned port = hw->port; int tmp; @@ -827,8 +823,7 @@ void read_S514_int_stat (sdlahw_t* hw, u32* int_status) * Generate an interrupt to adapter's CPU. */ -EXPORT_SYMBOL(sdla_intr); - +#if 0 int sdla_intr (sdlahw_t* hw) { unsigned port = hw->port; @@ -863,6 +858,7 @@ int sdla_intr (sdlahw_t* hw) } return 0; } +#endif /* 0 */ /*============================================================================ * Execute Adapter Command. diff --git a/drivers/net/wan/syncppp.c b/drivers/net/wan/syncppp.c index a6d3b55013a5..2d1bba06a085 100644 --- a/drivers/net/wan/syncppp.c +++ b/drivers/net/wan/syncppp.c @@ -221,7 +221,7 @@ static void sppp_clear_timeout(struct sppp *p) * here. */ -void sppp_input (struct net_device *dev, struct sk_buff *skb) +static void sppp_input (struct net_device *dev, struct sk_buff *skb) { struct ppp_header *h; struct sppp *sp = (struct sppp *)sppp_of(dev); @@ -355,8 +355,6 @@ done: return; } -EXPORT_SYMBOL(sppp_input); - /* * Handle transmit packets. */ @@ -990,7 +988,7 @@ EXPORT_SYMBOL(sppp_reopen); * the mtu is out of range. */ -int sppp_change_mtu(struct net_device *dev, int new_mtu) +static int sppp_change_mtu(struct net_device *dev, int new_mtu) { if(new_mtu<128||new_mtu>PPP_MTU||(dev->flags&IFF_UP)) return -EINVAL; @@ -998,8 +996,6 @@ int sppp_change_mtu(struct net_device *dev, int new_mtu) return 0; } -EXPORT_SYMBOL(sppp_change_mtu); - /** * sppp_do_ioctl - Ioctl handler for ppp/hdlc * @dev: Device subject to ioctl @@ -1456,7 +1452,7 @@ static int sppp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_t return 0; } -struct packet_type sppp_packet_type = { +static struct packet_type sppp_packet_type = { .type = __constant_htons(ETH_P_WAN_PPP), .func = sppp_rcv, }; diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 06998c2240d9..750c0167539c 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -35,6 +35,7 @@ #include <linux/interrupt.h> #include <linux/in.h> #include <linux/bitops.h> +#include <linux/scatterlist.h> #include <asm/io.h> #include <asm/system.h> @@ -1046,7 +1047,6 @@ static WifiCtlHdr wifictlhdr8023 = { } }; -#ifdef WIRELESS_EXT // Frequency list (map channels to frequencies) static const long frequency_list[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447, 2452, 2457, 2462, 2467, 2472, 2484 }; @@ -1067,7 +1067,6 @@ typedef struct wep_key_t { /* List of Wireless Handlers (new API) */ static const struct iw_handler_def airo_handler_def; -#endif /* WIRELESS_EXT */ static const char version[] = "airo.c 0.6 (Ben Reed & Javier Achirica)"; @@ -1110,10 +1109,8 @@ static irqreturn_t airo_interrupt( int irq, void* dev_id, struct pt_regs static int airo_thread(void *data); static void timer_func( struct net_device *dev ); static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -#ifdef WIRELESS_EXT static struct iw_statistics *airo_get_wireless_stats (struct net_device *dev); static void airo_read_wireless_stats (struct airo_info *local); -#endif /* WIRELESS_EXT */ #ifdef CISCO_EXT static int readrids(struct net_device *dev, aironet_ioctl *comp); static int writerids(struct net_device *dev, aironet_ioctl *comp); @@ -1187,12 +1184,10 @@ struct airo_info { int fid; } xmit, xmit11; struct net_device *wifidev; -#ifdef WIRELESS_EXT struct iw_statistics wstats; // wireless stats unsigned long scan_timestamp; /* Time started to scan */ struct iw_spy_data spy_data; struct iw_public_data wireless_data; -#endif /* WIRELESS_EXT */ #ifdef MICSUPPORT /* MIC stuff */ struct crypto_tfm *tfm; @@ -1596,11 +1591,9 @@ static void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, struct aes_counter[12] = (u8)(counter >> 24); counter++; memcpy (plain, aes_counter, 16); - sg[0].page = virt_to_page(plain); - sg[0].offset = ((long) plain & ~PAGE_MASK); - sg[0].length = 16; + sg_set_buf(sg, plain, 16); crypto_cipher_encrypt(tfm, sg, sg, 16); - cipher = kmap(sg[0].page) + sg[0].offset; + cipher = kmap(sg->page) + sg->offset; for (j=0; (j<16) && (i< (sizeof(context->coeff)/sizeof(context->coeff[0]))); ) { context->coeff[i++] = ntohl(*(u32 *)&cipher[j]); j += 4; @@ -2387,14 +2380,10 @@ void stop_airo_card( struct net_device *dev, int freeres ) dev_kfree_skb(skb); } - if (ai->flash) - kfree(ai->flash); - if (ai->rssi) - kfree(ai->rssi); - if (ai->APList) - kfree(ai->APList); - if (ai->SSID) - kfree(ai->SSID); + kfree(ai->flash); + kfree(ai->rssi); + kfree(ai->APList); + kfree(ai->SSID); if (freeres) { /* PCMCIA frees this stuff, so only for PCI and ISA */ release_region( dev->base_addr, 64 ); @@ -2527,7 +2516,8 @@ static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci, unsigned long mem_start, mem_len, aux_start, aux_len; int rc = -1; int i; - unsigned char *busaddroff,*vpackoff; + dma_addr_t busaddroff; + unsigned char *vpackoff; unsigned char __iomem *pciaddroff; mem_start = pci_resource_start(pci, 1); @@ -2570,7 +2560,7 @@ static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci, /* * Setup descriptor RX, TX, CONFIG */ - busaddroff = (unsigned char *)ai->shared_dma; + busaddroff = ai->shared_dma; pciaddroff = ai->pciaux + AUX_OFFSET; vpackoff = ai->shared; @@ -2579,7 +2569,7 @@ static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci, ai->rxfids[i].pending = 0; ai->rxfids[i].card_ram_off = pciaddroff; ai->rxfids[i].virtual_host_addr = vpackoff; - ai->rxfids[i].rx_desc.host_addr = (dma_addr_t) busaddroff; + ai->rxfids[i].rx_desc.host_addr = busaddroff; ai->rxfids[i].rx_desc.valid = 1; ai->rxfids[i].rx_desc.len = PKTSIZE; ai->rxfids[i].rx_desc.rdy = 0; @@ -2594,7 +2584,7 @@ static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci, ai->txfids[i].card_ram_off = pciaddroff; ai->txfids[i].virtual_host_addr = vpackoff; ai->txfids[i].tx_desc.valid = 1; - ai->txfids[i].tx_desc.host_addr = (dma_addr_t) busaddroff; + ai->txfids[i].tx_desc.host_addr = busaddroff; memcpy(ai->txfids[i].virtual_host_addr, &wifictlhdr8023, sizeof(wifictlhdr8023)); @@ -2607,8 +2597,8 @@ static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci, /* Rid descriptor setup */ ai->config_desc.card_ram_off = pciaddroff; ai->config_desc.virtual_host_addr = vpackoff; - ai->config_desc.rid_desc.host_addr = (dma_addr_t) busaddroff; - ai->ridbus = (dma_addr_t)busaddroff; + ai->config_desc.rid_desc.host_addr = busaddroff; + ai->ridbus = busaddroff; ai->config_desc.rid_desc.rid = 0; ai->config_desc.rid_desc.len = RIDSIZE; ai->config_desc.rid_desc.valid = 1; @@ -2647,9 +2637,7 @@ static void wifi_setup(struct net_device *dev) dev->get_stats = &airo_get_stats; dev->set_mac_address = &airo_set_mac_address; dev->do_ioctl = &airo_ioctl; -#ifdef WIRELESS_EXT dev->wireless_handlers = &airo_handler_def; -#endif /* WIRELESS_EXT */ dev->change_mtu = &airo_change_mtu; dev->open = &airo_open; dev->stop = &airo_close; @@ -2675,9 +2663,7 @@ static struct net_device *init_wifidev(struct airo_info *ai, dev->priv = ethdev->priv; dev->irq = ethdev->irq; dev->base_addr = ethdev->base_addr; -#ifdef WIRELESS_EXT dev->wireless_data = ethdev->wireless_data; -#endif /* WIRELESS_EXT */ memcpy(dev->dev_addr, ethdev->dev_addr, dev->addr_len); err = register_netdev(dev); if (err<0) { @@ -2755,11 +2741,9 @@ static struct net_device *_init_airo_card( unsigned short irq, int port, dev->set_multicast_list = &airo_set_multicast_list; dev->set_mac_address = &airo_set_mac_address; dev->do_ioctl = &airo_ioctl; -#ifdef WIRELESS_EXT dev->wireless_handlers = &airo_handler_def; ai->wireless_data.spy_data = &ai->spy_data; dev->wireless_data = &ai->wireless_data; -#endif /* WIRELESS_EXT */ dev->change_mtu = &airo_change_mtu; dev->open = &airo_open; dev->stop = &airo_close; @@ -3637,10 +3621,8 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock) int rc; memset( &mySsid, 0, sizeof( mySsid ) ); - if (ai->flash) { - kfree (ai->flash); - ai->flash = NULL; - } + kfree (ai->flash); + ai->flash = NULL; /* The NOP is the first step in getting the card going */ cmd.cmd = NOP; @@ -3677,14 +3659,10 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock) tdsRssiRid rssi_rid; CapabilityRid cap_rid; - if (ai->APList) { - kfree(ai->APList); - ai->APList = NULL; - } - if (ai->SSID) { - kfree(ai->SSID); - ai->SSID = NULL; - } + kfree(ai->APList); + ai->APList = NULL; + kfree(ai->SSID); + ai->SSID = NULL; // general configuration (read/modify/write) status = readConfigRid(ai, lock); if ( status != SUCCESS ) return ERROR; @@ -3698,10 +3676,8 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock) memcpy(ai->rssi, (u8*)&rssi_rid + 2, 512); /* Skip RID length member */ } else { - if (ai->rssi) { - kfree(ai->rssi); - ai->rssi = NULL; - } + kfree(ai->rssi); + ai->rssi = NULL; if (cap_rid.softCap & 8) ai->config.rmode |= RXMODE_NORMALIZED_RSSI; else @@ -5380,11 +5356,13 @@ static int proc_BSSList_open( struct inode *inode, struct file *file ) { static int proc_close( struct inode *inode, struct file *file ) { - struct proc_data *data = (struct proc_data *)file->private_data; - if ( data->on_close != NULL ) data->on_close( inode, file ); - if ( data->rbuffer ) kfree( data->rbuffer ); - if ( data->wbuffer ) kfree( data->wbuffer ); - kfree( data ); + struct proc_data *data = file->private_data; + + if (data->on_close != NULL) + data->on_close(inode, file); + kfree(data->rbuffer); + kfree(data->wbuffer); + kfree(data); return 0; } @@ -5515,12 +5493,13 @@ static int airo_pci_resume(struct pci_dev *pdev) struct net_device *dev = pci_get_drvdata(pdev); struct airo_info *ai = dev->priv; Resp rsp; + pci_power_t prev_state = pdev->current_state; - pci_set_power_state(pdev, 0); + pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); - pci_enable_wake(pdev, pci_choose_state(pdev, ai->power), 0); + pci_enable_wake(pdev, PCI_D0, 0); - if (ai->power.event > 1) { + if (prev_state != PCI_D1) { reset_card(dev, 0); mpi_init_descriptors(ai); setup_card(ai, dev->dev_addr, 0); @@ -5598,7 +5577,6 @@ static void __exit airo_cleanup_module( void ) remove_proc_entry("aironet", proc_root_driver); } -#ifdef WIRELESS_EXT /* * Initial Wireless Extension code for Aironet driver by : * Jean Tourrilhes <jt@hpl.hp.com> - HPL - 17 November 00 @@ -7107,8 +7085,6 @@ static const struct iw_handler_def airo_handler_def = .get_wireless_stats = airo_get_wireless_stats, }; -#endif /* WIRELESS_EXT */ - /* * This defines the configuration part of the Wireless Extensions * Note : irq and spinlock protection will occur in the subroutines @@ -7187,7 +7163,6 @@ static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) return rc; } -#ifdef WIRELESS_EXT /* * Get the Wireless stats out of the driver * Note : irq and spinlock protection will occur in the subroutines @@ -7260,7 +7235,6 @@ static struct iw_statistics *airo_get_wireless_stats(struct net_device *dev) return &local->wstats; } -#endif /* WIRELESS_EXT */ #ifdef CISCO_EXT /* diff --git a/drivers/net/wireless/airo_cs.c b/drivers/net/wireless/airo_cs.c index bf25584d68d3..784de9109113 100644 --- a/drivers/net/wireless/airo_cs.c +++ b/drivers/net/wireless/airo_cs.c @@ -258,9 +258,7 @@ static void airo_detach(dev_link_t *link) /* Unlink device structure, free pieces */ *linkp = link->next; - if (link->priv) { - kfree(link->priv); - } + kfree(link->priv); kfree(link); } /* airo_detach */ diff --git a/drivers/net/wireless/airport.c b/drivers/net/wireless/airport.c index 9d496703c465..7b321f7cf358 100644 --- a/drivers/net/wireless/airport.c +++ b/drivers/net/wireless/airport.c @@ -15,28 +15,11 @@ #define PFX DRIVER_NAME ": " #include <linux/config.h> - #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> -#include <linux/ptrace.h> -#include <linux/slab.h> -#include <linux/string.h> -#include <linux/timer.h> -#include <linux/ioport.h> -#include <linux/netdevice.h> -#include <linux/if_arp.h> -#include <linux/etherdevice.h> -#include <linux/wireless.h> - -#include <asm/io.h> -#include <asm/system.h> -#include <asm/current.h> -#include <asm/prom.h> -#include <asm/machdep.h> +#include <linux/delay.h> #include <asm/pmac_feature.h> -#include <asm/irq.h> -#include <asm/uaccess.h> #include "orinoco.h" diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c index 587869d86eee..1fbe027d26b6 100644 --- a/drivers/net/wireless/atmel.c +++ b/drivers/net/wireless/atmel.c @@ -618,12 +618,12 @@ static int atmel_lock_mac(struct atmel_private *priv); static void atmel_wmem32(struct atmel_private *priv, u16 pos, u32 data); static void atmel_command_irq(struct atmel_private *priv); static int atmel_validate_channel(struct atmel_private *priv, int channel); -static void atmel_management_frame(struct atmel_private *priv, struct ieee80211_hdr *header, +static void atmel_management_frame(struct atmel_private *priv, struct ieee80211_hdr_4addr *header, u16 frame_len, u8 rssi); static void atmel_management_timer(u_long a); static void atmel_send_command(struct atmel_private *priv, int command, void *cmd, int cmd_size); static int atmel_send_command_wait(struct atmel_private *priv, int command, void *cmd, int cmd_size); -static void atmel_transmit_management_frame(struct atmel_private *priv, struct ieee80211_hdr *header, +static void atmel_transmit_management_frame(struct atmel_private *priv, struct ieee80211_hdr_4addr *header, u8 *body, int body_len); static u8 atmel_get_mib8(struct atmel_private *priv, u8 type, u8 index); @@ -827,7 +827,7 @@ static void tx_update_descriptor(struct atmel_private *priv, int is_bcast, u16 l static int start_tx (struct sk_buff *skb, struct net_device *dev) { struct atmel_private *priv = netdev_priv(dev); - struct ieee80211_hdr header; + struct ieee80211_hdr_4addr header; unsigned long flags; u16 buff, frame_ctl, len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN; u8 SNAP_RFC1024[6] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00}; @@ -902,7 +902,7 @@ static int start_tx (struct sk_buff *skb, struct net_device *dev) } static void atmel_transmit_management_frame(struct atmel_private *priv, - struct ieee80211_hdr *header, + struct ieee80211_hdr_4addr *header, u8 *body, int body_len) { u16 buff; @@ -917,7 +917,7 @@ static void atmel_transmit_management_frame(struct atmel_private *priv, tx_update_descriptor(priv, header->addr1[0] & 0x01, len, buff, TX_PACKET_TYPE_MGMT); } -static void fast_rx_path(struct atmel_private *priv, struct ieee80211_hdr *header, +static void fast_rx_path(struct atmel_private *priv, struct ieee80211_hdr_4addr *header, u16 msdu_size, u16 rx_packet_loc, u32 crc) { /* fast path: unfragmented packet copy directly into skbuf */ @@ -990,7 +990,7 @@ static int probe_crc(struct atmel_private *priv, u16 packet_loc, u16 msdu_size) return (crc ^ 0xffffffff) == netcrc; } -static void frag_rx_path(struct atmel_private *priv, struct ieee80211_hdr *header, +static void frag_rx_path(struct atmel_private *priv, struct ieee80211_hdr_4addr *header, u16 msdu_size, u16 rx_packet_loc, u32 crc, u16 seq_no, u8 frag_no, int more_frags) { u8 mac4[6]; @@ -1082,7 +1082,7 @@ static void frag_rx_path(struct atmel_private *priv, struct ieee80211_hdr *heade static void rx_done_irq(struct atmel_private *priv) { int i; - struct ieee80211_hdr header; + struct ieee80211_hdr_4addr header; for (i = 0; atmel_rmem8(priv, atmel_rx(priv, RX_DESC_FLAGS_OFFSET, priv->rx_desc_head)) == RX_DESC_FLAG_VALID && @@ -1653,8 +1653,7 @@ void stop_atmel_card(struct net_device *dev, int freeres) unregister_netdev(dev); remove_proc_entry("driver/atmel", NULL); free_irq(dev->irq, dev); - if (priv->firmware) - kfree(priv->firmware); + kfree(priv->firmware); if (freeres) { /* PCMCIA frees this stuff, so only for PCI */ release_region(dev->base_addr, 64); @@ -2450,8 +2449,7 @@ static int atmel_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) break; } - if (priv->firmware) - kfree(priv->firmware); + kfree(priv->firmware); priv->firmware = new_firmware; priv->firmware_length = com.len; @@ -2650,7 +2648,7 @@ static void handle_beacon_probe(struct atmel_private *priv, u16 capability, u8 c static void send_authentication_request(struct atmel_private *priv, u8 *challenge, int challenge_len) { - struct ieee80211_hdr header; + struct ieee80211_hdr_4addr header; struct auth_body auth; header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH); @@ -2688,7 +2686,7 @@ static void send_association_request(struct atmel_private *priv, int is_reassoc) { u8 *ssid_el_p; int bodysize; - struct ieee80211_hdr header; + struct ieee80211_hdr_4addr header; struct ass_req_format { u16 capability; u16 listen_interval; @@ -2738,7 +2736,7 @@ static void send_association_request(struct atmel_private *priv, int is_reassoc) atmel_transmit_management_frame(priv, &header, (void *)&body, bodysize); } -static int is_frame_from_current_bss(struct atmel_private *priv, struct ieee80211_hdr *header) +static int is_frame_from_current_bss(struct atmel_private *priv, struct ieee80211_hdr_4addr *header) { if (le16_to_cpu(header->frame_ctl) & IEEE80211_FCTL_FROMDS) return memcmp(header->addr3, priv->CurrentBSSID, 6) == 0; @@ -2788,7 +2786,7 @@ static int retrieve_bss(struct atmel_private *priv) } -static void store_bss_info(struct atmel_private *priv, struct ieee80211_hdr *header, +static void store_bss_info(struct atmel_private *priv, struct ieee80211_hdr_4addr *header, u16 capability, u16 beacon_period, u8 channel, u8 rssi, u8 ssid_len, u8 *ssid, int is_beacon) { @@ -3072,7 +3070,7 @@ static void atmel_smooth_qual(struct atmel_private *priv) } /* deals with incoming managment frames. */ -static void atmel_management_frame(struct atmel_private *priv, struct ieee80211_hdr *header, +static void atmel_management_frame(struct atmel_private *priv, struct ieee80211_hdr_4addr *header, u16 frame_len, u8 rssi) { u16 subtype; diff --git a/drivers/net/wireless/atmel_cs.c b/drivers/net/wireless/atmel_cs.c index ff031a3985b3..195cb36619e8 100644 --- a/drivers/net/wireless/atmel_cs.c +++ b/drivers/net/wireless/atmel_cs.c @@ -259,8 +259,7 @@ static void atmel_detach(dev_link_t *link) /* Unlink device structure, free pieces */ *linkp = link->next; - if (link->priv) - kfree(link->priv); + kfree(link->priv); kfree(link); } diff --git a/drivers/net/wireless/hermes.c b/drivers/net/wireless/hermes.c index 21c3d0d227e6..579480dad374 100644 --- a/drivers/net/wireless/hermes.c +++ b/drivers/net/wireless/hermes.c @@ -39,17 +39,10 @@ */ #include <linux/config.h> - #include <linux/module.h> -#include <linux/types.h> -#include <linux/threads.h> -#include <linux/smp.h> -#include <asm/io.h> -#include <linux/delay.h> -#include <linux/init.h> #include <linux/kernel.h> -#include <linux/net.h> -#include <asm/errno.h> +#include <linux/init.h> +#include <linux/delay.h> #include "hermes.h" @@ -451,6 +444,43 @@ int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, unsigned len, return err; } +/* Write a block of data to the chip's buffer with padding if + * neccessary, via the BAP. Synchronization/serialization is the + * caller's problem. len must be even. + * + * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware + */ +int hermes_bap_pwrite_pad(hermes_t *hw, int bap, const void *buf, unsigned data_len, unsigned len, + u16 id, u16 offset) +{ + int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; + int err = 0; + + if (len < 0 || len % 2 || data_len > len) + return -EINVAL; + + err = hermes_bap_seek(hw, bap, id, offset); + if (err) + goto out; + + /* Transfer all the complete words of data */ + hermes_write_words(hw, dreg, buf, data_len/2); + /* If there is an odd byte left over pad and transfer it */ + if (data_len & 1) { + u8 end[2]; + end[1] = 0; + end[0] = ((unsigned char *)buf)[data_len - 1]; + hermes_write_words(hw, dreg, end, 1); + data_len ++; + } + /* Now send zeros for the padding */ + if (data_len < len) + hermes_clear_words(hw, dreg, (len - data_len) / 2); + /* Complete */ + out: + return err; +} + /* Read a Length-Type-Value record from the card. * * If length is NULL, we ignore the length read from the card, and @@ -538,6 +568,7 @@ EXPORT_SYMBOL(hermes_allocate); EXPORT_SYMBOL(hermes_bap_pread); EXPORT_SYMBOL(hermes_bap_pwrite); +EXPORT_SYMBOL(hermes_bap_pwrite_pad); EXPORT_SYMBOL(hermes_read_ltv); EXPORT_SYMBOL(hermes_write_ltv); diff --git a/drivers/net/wireless/hermes.h b/drivers/net/wireless/hermes.h index 8c9e874c9118..a6bd472d75d4 100644 --- a/drivers/net/wireless/hermes.h +++ b/drivers/net/wireless/hermes.h @@ -30,9 +30,8 @@ * access to the hermes_t structure, and to the hardware */ -#include <linux/delay.h> #include <linux/if_ether.h> -#include <asm/byteorder.h> +#include <asm/io.h> /* * Limits and constants @@ -192,13 +191,13 @@ #define HERMES_RXSTAT_WMP (0x6000) /* Wavelan-II Management Protocol frame */ struct hermes_tx_descriptor { - u16 status; - u16 reserved1; - u16 reserved2; - u32 sw_support; + __le16 status; + __le16 reserved1; + __le16 reserved2; + __le32 sw_support; u8 retry_count; u8 tx_rate; - u16 tx_control; + __le16 tx_control; } __attribute__ ((packed)); #define HERMES_TXSTAT_RETRYERR (0x0001) @@ -222,60 +221,60 @@ struct hermes_tx_descriptor { #define HERMES_INQ_SEC_STAT_AGERE (0xF202) struct hermes_tallies_frame { - u16 TxUnicastFrames; - u16 TxMulticastFrames; - u16 TxFragments; - u16 TxUnicastOctets; - u16 TxMulticastOctets; - u16 TxDeferredTransmissions; - u16 TxSingleRetryFrames; - u16 TxMultipleRetryFrames; - u16 TxRetryLimitExceeded; - u16 TxDiscards; - u16 RxUnicastFrames; - u16 RxMulticastFrames; - u16 RxFragments; - u16 RxUnicastOctets; - u16 RxMulticastOctets; - u16 RxFCSErrors; - u16 RxDiscards_NoBuffer; - u16 TxDiscardsWrongSA; - u16 RxWEPUndecryptable; - u16 RxMsgInMsgFragments; - u16 RxMsgInBadMsgFragments; + __le16 TxUnicastFrames; + __le16 TxMulticastFrames; + __le16 TxFragments; + __le16 TxUnicastOctets; + __le16 TxMulticastOctets; + __le16 TxDeferredTransmissions; + __le16 TxSingleRetryFrames; + __le16 TxMultipleRetryFrames; + __le16 TxRetryLimitExceeded; + __le16 TxDiscards; + __le16 RxUnicastFrames; + __le16 RxMulticastFrames; + __le16 RxFragments; + __le16 RxUnicastOctets; + __le16 RxMulticastOctets; + __le16 RxFCSErrors; + __le16 RxDiscards_NoBuffer; + __le16 TxDiscardsWrongSA; + __le16 RxWEPUndecryptable; + __le16 RxMsgInMsgFragments; + __le16 RxMsgInBadMsgFragments; /* Those last are probably not available in very old firmwares */ - u16 RxDiscards_WEPICVError; - u16 RxDiscards_WEPExcluded; + __le16 RxDiscards_WEPICVError; + __le16 RxDiscards_WEPExcluded; } __attribute__ ((packed)); /* Grabbed from wlan-ng - Thanks Mark... - Jean II * This is the result of a scan inquiry command */ /* Structure describing info about an Access Point */ struct prism2_scan_apinfo { - u16 channel; /* Channel where the AP sits */ - u16 noise; /* Noise level */ - u16 level; /* Signal level */ + __le16 channel; /* Channel where the AP sits */ + __le16 noise; /* Noise level */ + __le16 level; /* Signal level */ u8 bssid[ETH_ALEN]; /* MAC address of the Access Point */ - u16 beacon_interv; /* Beacon interval */ - u16 capabilities; /* Capabilities */ - u16 essid_len; /* ESSID length */ + __le16 beacon_interv; /* Beacon interval */ + __le16 capabilities; /* Capabilities */ + __le16 essid_len; /* ESSID length */ u8 essid[32]; /* ESSID of the network */ u8 rates[10]; /* Bit rate supported */ - u16 proberesp_rate; /* Data rate of the response frame */ - u16 atim; /* ATIM window time, Kus (hostscan only) */ + __le16 proberesp_rate; /* Data rate of the response frame */ + __le16 atim; /* ATIM window time, Kus (hostscan only) */ } __attribute__ ((packed)); /* Same stuff for the Lucent/Agere card. * Thanks to h1kari <h1kari AT dachb0den.com> - Jean II */ struct agere_scan_apinfo { - u16 channel; /* Channel where the AP sits */ - u16 noise; /* Noise level */ - u16 level; /* Signal level */ + __le16 channel; /* Channel where the AP sits */ + __le16 noise; /* Noise level */ + __le16 level; /* Signal level */ u8 bssid[ETH_ALEN]; /* MAC address of the Access Point */ - u16 beacon_interv; /* Beacon interval */ - u16 capabilities; /* Capabilities */ + __le16 beacon_interv; /* Beacon interval */ + __le16 capabilities; /* Capabilities */ /* bits: 0-ess, 1-ibss, 4-privacy [wep] */ - u16 essid_len; /* ESSID length */ + __le16 essid_len; /* ESSID length */ u8 essid[32]; /* ESSID of the network */ } __attribute__ ((packed)); @@ -283,16 +282,16 @@ struct agere_scan_apinfo { struct symbol_scan_apinfo { u8 channel; /* Channel where the AP sits */ u8 unknown1; /* 8 in 2.9x and 3.9x f/w, 0 otherwise */ - u16 noise; /* Noise level */ - u16 level; /* Signal level */ + __le16 noise; /* Noise level */ + __le16 level; /* Signal level */ u8 bssid[ETH_ALEN]; /* MAC address of the Access Point */ - u16 beacon_interv; /* Beacon interval */ - u16 capabilities; /* Capabilities */ + __le16 beacon_interv; /* Beacon interval */ + __le16 capabilities; /* Capabilities */ /* bits: 0-ess, 1-ibss, 4-privacy [wep] */ - u16 essid_len; /* ESSID length */ + __le16 essid_len; /* ESSID length */ u8 essid[32]; /* ESSID of the network */ - u16 rates[5]; /* Bit rate supported */ - u16 basic_rates; /* Basic rates bitmask */ + __le16 rates[5]; /* Bit rate supported */ + __le16 basic_rates; /* Basic rates bitmask */ u8 unknown2[6]; /* Always FF:FF:FF:FF:00:00 */ u8 unknown3[8]; /* Always 0, appeared in f/w 3.91-68 */ } __attribute__ ((packed)); @@ -312,7 +311,7 @@ union hermes_scan_info { #define HERMES_LINKSTATUS_ASSOC_FAILED (0x0006) struct hermes_linkstatus { - u16 linkstatus; /* Link status */ + __le16 linkstatus; /* Link status */ } __attribute__ ((packed)); struct hermes_response { @@ -321,8 +320,8 @@ struct hermes_response { /* "ID" structure - used for ESSID and station nickname */ struct hermes_idstring { - u16 len; - u16 val[16]; + __le16 len; + __le16 val[16]; } __attribute__ ((packed)); struct hermes_multicast { @@ -377,6 +376,8 @@ int hermes_bap_pread(hermes_t *hw, int bap, void *buf, unsigned len, u16 id, u16 offset); int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, unsigned len, u16 id, u16 offset); +int hermes_bap_pwrite_pad(hermes_t *hw, int bap, const void *buf, + unsigned data_len, unsigned len, u16 id, u16 offset); int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, unsigned buflen, u16 *length, void *buf); int hermes_write_ltv(hermes_t *hw, int bap, u16 rid, @@ -447,7 +448,7 @@ static inline void hermes_clear_words(struct hermes *hw, int off, unsigned count static inline int hermes_read_wordrec(hermes_t *hw, int bap, u16 rid, u16 *word) { - u16 rec; + __le16 rec; int err; err = HERMES_READ_RECORD(hw, bap, rid, &rec); @@ -457,7 +458,7 @@ static inline int hermes_read_wordrec(hermes_t *hw, int bap, u16 rid, u16 *word) static inline int hermes_write_wordrec(hermes_t *hw, int bap, u16 rid, u16 word) { - u16 rec = cpu_to_le16(word); + __le16 rec = cpu_to_le16(word); return HERMES_WRITE_RECORD(hw, bap, rid, &rec); } diff --git a/drivers/net/wireless/hostap/hostap.c b/drivers/net/wireless/hostap/hostap.c index e7f5821b4942..6a96cd9f2685 100644 --- a/drivers/net/wireless/hostap/hostap.c +++ b/drivers/net/wireless/hostap/hostap.c @@ -716,9 +716,6 @@ static int prism2_close(struct net_device *dev) hostap_deauth_all_stas(dev, local->ap, 1); #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - if (local->func->dev_close && local->func->dev_close(local)) - return 0; - if (dev == local->dev) { local->func->hw_shutdown(dev, HOSTAP_HW_ENABLE_CMDCOMPL); } @@ -766,9 +763,6 @@ static int prism2_open(struct net_device *dev) local->hw_downloading) return -ENODEV; - if (local->func->dev_open && local->func->dev_open(local)) - return 1; - if (!try_module_get(local->hw_module)) return -ENODEV; local->num_dev_open++; diff --git a/drivers/net/wireless/hostap/hostap_80211_rx.c b/drivers/net/wireless/hostap/hostap_80211_rx.c index b0501243b175..ffac50899454 100644 --- a/drivers/net/wireless/hostap/hostap_80211_rx.c +++ b/drivers/net/wireless/hostap/hostap_80211_rx.c @@ -6,10 +6,10 @@ void hostap_dump_rx_80211(const char *name, struct sk_buff *skb, struct hostap_80211_rx_status *rx_stats) { - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; u16 fc; - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; printk(KERN_DEBUG "%s: RX signal=%d noise=%d rate=%d len=%d " "jiffies=%ld\n", @@ -51,7 +51,7 @@ int prism2_rx_80211(struct net_device *dev, struct sk_buff *skb, int hdrlen, phdrlen, head_need, tail_need; u16 fc; int prism_header, ret; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; iface = netdev_priv(dev); local = iface->local; @@ -70,7 +70,7 @@ int prism2_rx_80211(struct net_device *dev, struct sk_buff *skb, phdrlen = 0; } - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; fc = le16_to_cpu(hdr->frame_ctl); if (type == PRISM2_RX_MGMT && (fc & IEEE80211_FCTL_VERS)) { @@ -215,7 +215,7 @@ prism2_frag_cache_find(local_info_t *local, unsigned int seq, /* Called only as a tasklet (software IRQ) */ static struct sk_buff * -prism2_frag_cache_get(local_info_t *local, struct ieee80211_hdr *hdr) +prism2_frag_cache_get(local_info_t *local, struct ieee80211_hdr_4addr *hdr) { struct sk_buff *skb = NULL; u16 sc; @@ -229,7 +229,7 @@ prism2_frag_cache_get(local_info_t *local, struct ieee80211_hdr *hdr) if (frag == 0) { /* Reserve enough space to fit maximum frame length */ skb = dev_alloc_skb(local->dev->mtu + - sizeof(struct ieee80211_hdr) + + sizeof(struct ieee80211_hdr_4addr) + 8 /* LLC */ + 2 /* alignment */ + 8 /* WEP */ + ETH_ALEN /* WDS */); @@ -267,7 +267,7 @@ prism2_frag_cache_get(local_info_t *local, struct ieee80211_hdr *hdr) /* Called only as a tasklet (software IRQ) */ static int prism2_frag_cache_invalidate(local_info_t *local, - struct ieee80211_hdr *hdr) + struct ieee80211_hdr_4addr *hdr) { u16 sc; unsigned int seq; @@ -441,7 +441,7 @@ hostap_rx_frame_mgmt(local_info_t *local, struct sk_buff *skb, u16 stype) { if (local->iw_mode == IW_MODE_MASTER) { - hostap_update_sta_ps(local, (struct ieee80211_hdr *) + hostap_update_sta_ps(local, (struct ieee80211_hdr_4addr *) skb->data); } @@ -520,7 +520,7 @@ static inline struct net_device *prism2_rx_get_wds(local_info_t *local, static inline int -hostap_rx_frame_wds(local_info_t *local, struct ieee80211_hdr *hdr, +hostap_rx_frame_wds(local_info_t *local, struct ieee80211_hdr_4addr *hdr, u16 fc, struct net_device **wds) { /* FIX: is this really supposed to accept WDS frames only in Master @@ -579,13 +579,13 @@ static int hostap_is_eapol_frame(local_info_t *local, struct sk_buff *skb) { struct net_device *dev = local->dev; u16 fc, ethertype; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; u8 *pos; if (skb->len < 24) return 0; - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; fc = le16_to_cpu(hdr->frame_ctl); /* check that the frame is unicast frame to us */ @@ -619,13 +619,13 @@ static inline int hostap_rx_frame_decrypt(local_info_t *local, struct sk_buff *skb, struct ieee80211_crypt_data *crypt) { - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; int res, hdrlen; if (crypt == NULL || crypt->ops->decrypt_mpdu == NULL) return 0; - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; hdrlen = hostap_80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); if (local->tkip_countermeasures && @@ -658,13 +658,13 @@ static inline int hostap_rx_frame_decrypt_msdu(local_info_t *local, struct sk_buff *skb, int keyidx, struct ieee80211_crypt_data *crypt) { - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; int res, hdrlen; if (crypt == NULL || crypt->ops->decrypt_msdu == NULL) return 0; - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; hdrlen = hostap_80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); atomic_inc(&crypt->refcnt); @@ -689,7 +689,7 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, { struct hostap_interface *iface; local_info_t *local; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; size_t hdrlen; u16 fc, type, stype, sc; struct net_device *wds = NULL; @@ -716,7 +716,7 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, dev = local->ddev; iface = netdev_priv(dev); - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; stats = hostap_get_stats(dev); if (skb->len < 10) @@ -737,7 +737,8 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, struct iw_quality wstats; wstats.level = rx_stats->signal; wstats.noise = rx_stats->noise; - wstats.updated = 6; /* No qual value */ + wstats.updated = IW_QUAL_LEVEL_UPDATED | IW_QUAL_NOISE_UPDATED + | IW_QUAL_QUAL_INVALID | IW_QUAL_DBM; /* Update spy records */ wireless_spy_update(dev, hdr->addr2, &wstats); } @@ -889,7 +890,7 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, if (local->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) && (keyidx = hostap_rx_frame_decrypt(local, skb, crypt)) < 0) goto rx_dropped; - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; /* skb: hdr + (possibly fragmented) plaintext payload */ @@ -941,7 +942,7 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, /* this was the last fragment and the frame will be * delivered, so remove skb from fragment cache */ skb = frag_skb; - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; prism2_frag_cache_invalidate(local, hdr); } @@ -952,7 +953,7 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, hostap_rx_frame_decrypt_msdu(local, skb, keyidx, crypt)) goto rx_dropped; - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; if (crypt && !(fc & IEEE80211_FCTL_PROTECTED) && !local->open_wep) { if (local->ieee_802_1x && hostap_is_eapol_frame(local, skb)) { diff --git a/drivers/net/wireless/hostap/hostap_80211_tx.c b/drivers/net/wireless/hostap/hostap_80211_tx.c index 6358015f6526..9d24f8a38ac5 100644 --- a/drivers/net/wireless/hostap/hostap_80211_tx.c +++ b/drivers/net/wireless/hostap/hostap_80211_tx.c @@ -1,9 +1,9 @@ void hostap_dump_tx_80211(const char *name, struct sk_buff *skb) { - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; u16 fc; - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; printk(KERN_DEBUG "%s: TX len=%d jiffies=%ld\n", name, skb->len, jiffies); @@ -41,7 +41,7 @@ int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev) struct hostap_interface *iface; local_info_t *local; int need_headroom, need_tailroom = 0; - struct ieee80211_hdr hdr; + struct ieee80211_hdr_4addr hdr; u16 fc, ethertype = 0; enum { WDS_NO = 0, WDS_OWN_FRAME, WDS_COMPLIANT_FRAME @@ -244,7 +244,7 @@ int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev) struct hostap_interface *iface; local_info_t *local; struct hostap_skb_tx_data *meta; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; u16 fc; iface = netdev_priv(dev); @@ -266,7 +266,7 @@ int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev) meta->iface = iface; if (skb->len >= IEEE80211_DATA_HDR3_LEN + sizeof(rfc1042_header) + 2) { - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; fc = le16_to_cpu(hdr->frame_ctl); if (WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA && WLAN_FC_GET_STYPE(fc) == IEEE80211_STYPE_DATA) { @@ -289,7 +289,7 @@ struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb, { struct hostap_interface *iface; local_info_t *local; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; u16 fc; int hdr_len, res; @@ -303,7 +303,7 @@ struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb, if (local->tkip_countermeasures && crypt && crypt->ops && strcmp(crypt->ops->name, "TKIP") == 0) { - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; if (net_ratelimit()) { printk(KERN_DEBUG "%s: TKIP countermeasures: dropped " "TX packet to " MACSTR "\n", @@ -317,15 +317,15 @@ struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb, if (skb == NULL) return NULL; - if ((skb_headroom(skb) < crypt->ops->extra_prefix_len || - skb_tailroom(skb) < crypt->ops->extra_postfix_len) && - pskb_expand_head(skb, crypt->ops->extra_prefix_len, - crypt->ops->extra_postfix_len, GFP_ATOMIC)) { + if ((skb_headroom(skb) < crypt->ops->extra_mpdu_prefix_len || + skb_tailroom(skb) < crypt->ops->extra_mpdu_postfix_len) && + pskb_expand_head(skb, crypt->ops->extra_mpdu_prefix_len, + crypt->ops->extra_mpdu_postfix_len, GFP_ATOMIC)) { kfree_skb(skb); return NULL; } - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; fc = le16_to_cpu(hdr->frame_ctl); hdr_len = hostap_80211_get_hdrlen(fc); @@ -360,7 +360,7 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev) ap_tx_ret tx_ret; struct hostap_skb_tx_data *meta; int no_encrypt = 0; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; iface = netdev_priv(dev); local = iface->local; @@ -403,7 +403,7 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev) tx_ret = hostap_handle_sta_tx(local, &tx); skb = tx.skb; meta = (struct hostap_skb_tx_data *) skb->cb; - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; fc = le16_to_cpu(hdr->frame_ctl); switch (tx_ret) { case AP_TX_CONTINUE: diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c index 930cef8367f2..9da94ab7f05f 100644 --- a/drivers/net/wireless/hostap/hostap_ap.c +++ b/drivers/net/wireless/hostap/hostap_ap.c @@ -591,14 +591,14 @@ static void hostap_ap_tx_cb(struct sk_buff *skb, int ok, void *data) { struct ap_data *ap = data; u16 fc; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; if (!ap->local->hostapd || !ap->local->apdev) { dev_kfree_skb(skb); return; } - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; fc = le16_to_cpu(hdr->frame_ctl); /* Pass the TX callback frame to the hostapd; use 802.11 header version @@ -623,7 +623,7 @@ static void hostap_ap_tx_cb_auth(struct sk_buff *skb, int ok, void *data) { struct ap_data *ap = data; struct net_device *dev = ap->local->dev; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; u16 fc, *pos, auth_alg, auth_transaction, status; struct sta_info *sta = NULL; char *txt = NULL; @@ -633,7 +633,7 @@ static void hostap_ap_tx_cb_auth(struct sk_buff *skb, int ok, void *data) return; } - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; fc = le16_to_cpu(hdr->frame_ctl); if (WLAN_FC_GET_TYPE(fc) != IEEE80211_FTYPE_MGMT || WLAN_FC_GET_STYPE(fc) != IEEE80211_STYPE_AUTH || @@ -692,7 +692,7 @@ static void hostap_ap_tx_cb_assoc(struct sk_buff *skb, int ok, void *data) { struct ap_data *ap = data; struct net_device *dev = ap->local->dev; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; u16 fc, *pos, status; struct sta_info *sta = NULL; char *txt = NULL; @@ -702,7 +702,7 @@ static void hostap_ap_tx_cb_assoc(struct sk_buff *skb, int ok, void *data) return; } - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; fc = le16_to_cpu(hdr->frame_ctl); if (WLAN_FC_GET_TYPE(fc) != IEEE80211_FTYPE_MGMT || (WLAN_FC_GET_STYPE(fc) != IEEE80211_STYPE_ASSOC_RESP && @@ -757,12 +757,12 @@ static void hostap_ap_tx_cb_assoc(struct sk_buff *skb, int ok, void *data) static void hostap_ap_tx_cb_poll(struct sk_buff *skb, int ok, void *data) { struct ap_data *ap = data; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; struct sta_info *sta; if (skb->len < 24) goto fail; - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; if (ok) { spin_lock(&ap->sta_table_lock); sta = ap_get_sta(ap, hdr->addr1); @@ -918,7 +918,7 @@ static void prism2_send_mgmt(struct net_device *dev, { struct hostap_interface *iface; local_info_t *local; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; u16 fc; struct sk_buff *skb; struct hostap_skb_tx_data *meta; @@ -944,7 +944,7 @@ static void prism2_send_mgmt(struct net_device *dev, fc = type_subtype; hdrlen = hostap_80211_get_hdrlen(fc); - hdr = (struct ieee80211_hdr *) skb_put(skb, hdrlen); + hdr = (struct ieee80211_hdr_4addr *) skb_put(skb, hdrlen); if (body) memcpy(skb_put(skb, body_len), body, body_len); @@ -1256,14 +1256,14 @@ static char * ap_auth_make_challenge(struct ap_data *ap) } skb = dev_alloc_skb(WLAN_AUTH_CHALLENGE_LEN + - ap->crypt->extra_prefix_len + - ap->crypt->extra_postfix_len); + ap->crypt->extra_mpdu_prefix_len + + ap->crypt->extra_mpdu_postfix_len); if (skb == NULL) { kfree(tmpbuf); return NULL; } - skb_reserve(skb, ap->crypt->extra_prefix_len); + skb_reserve(skb, ap->crypt->extra_mpdu_prefix_len); memset(skb_put(skb, WLAN_AUTH_CHALLENGE_LEN), 0, WLAN_AUTH_CHALLENGE_LEN); if (ap->crypt->encrypt_mpdu(skb, 0, ap->crypt_priv)) { @@ -1272,7 +1272,7 @@ static char * ap_auth_make_challenge(struct ap_data *ap) return NULL; } - memcpy(tmpbuf, skb->data + ap->crypt->extra_prefix_len, + memcpy(tmpbuf, skb->data + ap->crypt->extra_mpdu_prefix_len, WLAN_AUTH_CHALLENGE_LEN); dev_kfree_skb(skb); @@ -1285,7 +1285,7 @@ static void handle_authen(local_info_t *local, struct sk_buff *skb, struct hostap_80211_rx_status *rx_stats) { struct net_device *dev = local->dev; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + struct ieee80211_hdr_4addr *hdr = (struct ieee80211_hdr_4addr *) skb->data; size_t hdrlen; struct ap_data *ap = local->ap; char body[8 + WLAN_AUTH_CHALLENGE_LEN], *challenge = NULL; @@ -1498,7 +1498,7 @@ static void handle_assoc(local_info_t *local, struct sk_buff *skb, struct hostap_80211_rx_status *rx_stats, int reassoc) { struct net_device *dev = local->dev; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + struct ieee80211_hdr_4addr *hdr = (struct ieee80211_hdr_4addr *) skb->data; char body[12], *p, *lpos; int len, left; u16 *pos; @@ -1705,7 +1705,7 @@ static void handle_deauth(local_info_t *local, struct sk_buff *skb, struct hostap_80211_rx_status *rx_stats) { struct net_device *dev = local->dev; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + struct ieee80211_hdr_4addr *hdr = (struct ieee80211_hdr_4addr *) skb->data; char *body = (char *) (skb->data + IEEE80211_MGMT_HDR_LEN); int len; u16 reason_code, *pos; @@ -1746,7 +1746,7 @@ static void handle_disassoc(local_info_t *local, struct sk_buff *skb, struct hostap_80211_rx_status *rx_stats) { struct net_device *dev = local->dev; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + struct ieee80211_hdr_4addr *hdr = (struct ieee80211_hdr_4addr *) skb->data; char *body = skb->data + IEEE80211_MGMT_HDR_LEN; int len; u16 reason_code, *pos; @@ -1784,7 +1784,7 @@ static void handle_disassoc(local_info_t *local, struct sk_buff *skb, /* Called only as a scheduled task for pending AP frames. */ static void ap_handle_data_nullfunc(local_info_t *local, - struct ieee80211_hdr *hdr) + struct ieee80211_hdr_4addr *hdr) { struct net_device *dev = local->dev; @@ -1801,7 +1801,7 @@ static void ap_handle_data_nullfunc(local_info_t *local, /* Called only as a scheduled task for pending AP frames. */ static void ap_handle_dropped_data(local_info_t *local, - struct ieee80211_hdr *hdr) + struct ieee80211_hdr_4addr *hdr) { struct net_device *dev = local->dev; struct sta_info *sta; @@ -1860,7 +1860,7 @@ static void pspoll_send_buffered(local_info_t *local, struct sta_info *sta, /* Called only as a scheduled task for pending AP frames. */ static void handle_pspoll(local_info_t *local, - struct ieee80211_hdr *hdr, + struct ieee80211_hdr_4addr *hdr, struct hostap_80211_rx_status *rx_stats) { struct net_device *dev = local->dev; @@ -1979,7 +1979,7 @@ static void handle_wds_oper_queue(void *data) static void handle_beacon(local_info_t *local, struct sk_buff *skb, struct hostap_80211_rx_status *rx_stats) { - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + struct ieee80211_hdr_4addr *hdr = (struct ieee80211_hdr_4addr *) skb->data; char *body = skb->data + IEEE80211_MGMT_HDR_LEN; int len, left; u16 *pos, beacon_int, capability; @@ -2137,11 +2137,11 @@ static void handle_ap_item(local_info_t *local, struct sk_buff *skb, struct net_device *dev = local->dev; #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ u16 fc, type, stype; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; /* FIX: should give skb->len to handler functions and check that the * buffer is long enough */ - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; fc = le16_to_cpu(hdr->frame_ctl); type = WLAN_FC_GET_TYPE(fc); stype = WLAN_FC_GET_STYPE(fc); @@ -2258,7 +2258,7 @@ void hostap_rx(struct net_device *dev, struct sk_buff *skb, struct hostap_interface *iface; local_info_t *local; u16 fc; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; iface = netdev_priv(dev); local = iface->local; @@ -2268,7 +2268,7 @@ void hostap_rx(struct net_device *dev, struct sk_buff *skb, local->stats.rx_packets++; - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; fc = le16_to_cpu(hdr->frame_ctl); if (local->ap->ap_policy == AP_OTHER_AP_SKIP_ALL && @@ -2289,7 +2289,7 @@ void hostap_rx(struct net_device *dev, struct sk_buff *skb, static void schedule_packet_send(local_info_t *local, struct sta_info *sta) { struct sk_buff *skb; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; struct hostap_80211_rx_status rx_stats; if (skb_queue_empty(&sta->tx_buf)) @@ -2302,7 +2302,7 @@ static void schedule_packet_send(local_info_t *local, struct sta_info *sta) return; } - hdr = (struct ieee80211_hdr *) skb_put(skb, 16); + hdr = (struct ieee80211_hdr_4addr *) skb_put(skb, 16); /* Generate a fake pspoll frame to start packet delivery */ hdr->frame_ctl = __constant_cpu_to_le16( @@ -2349,7 +2349,7 @@ static int prism2_ap_get_sta_qual(local_info_t *local, struct sockaddr addr[], qual[count].noise = HFA384X_LEVEL_TO_dBm(sta->last_rx_silence); qual[count].updated = sta->last_rx_updated; - sta->last_rx_updated = 0; + sta->last_rx_updated = IW_QUAL_DBM; count++; if (count >= buf_size) @@ -2467,7 +2467,7 @@ static int prism2_ap_translate_scan(struct net_device *dev, char *buffer) } #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ - sta->last_rx_updated = 0; + sta->last_rx_updated = IW_QUAL_DBM; /* To be continued, we should make good use of IWEVCUSTOM */ } @@ -2685,7 +2685,7 @@ ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx) struct sta_info *sta = NULL; struct sk_buff *skb = tx->skb; int set_tim, ret; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; struct hostap_skb_tx_data *meta; meta = (struct hostap_skb_tx_data *) skb->cb; @@ -2694,7 +2694,7 @@ ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx) meta->iface->type == HOSTAP_INTERFACE_STA) goto out; - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; if (hdr->addr1[0] & 0x01) { /* broadcast/multicast frame - no AP related processing */ @@ -2821,10 +2821,10 @@ void hostap_handle_sta_release(void *ptr) void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb) { struct sta_info *sta; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; struct hostap_skb_tx_data *meta; - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; meta = (struct hostap_skb_tx_data *) skb->cb; spin_lock(&local->ap->sta_table_lock); @@ -2892,7 +2892,7 @@ static void hostap_update_sta_ps2(local_info_t *local, struct sta_info *sta, /* Called only as a tasklet (software IRQ). Called for each RX frame to update * STA power saving state. pwrmgt is a flag from 802.11 frame_ctl field. */ -int hostap_update_sta_ps(local_info_t *local, struct ieee80211_hdr *hdr) +int hostap_update_sta_ps(local_info_t *local, struct ieee80211_hdr_4addr *hdr) { struct sta_info *sta; u16 fc; @@ -2925,12 +2925,12 @@ ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev, int ret; struct sta_info *sta; u16 fc, type, stype; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_4addr *hdr; if (local->ap == NULL) return AP_RX_CONTINUE; - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr_4addr *) skb->data; fc = le16_to_cpu(hdr->frame_ctl); type = WLAN_FC_GET_TYPE(fc); @@ -3058,7 +3058,7 @@ ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev, /* Called only as a tasklet (software IRQ) */ int hostap_handle_sta_crypto(local_info_t *local, - struct ieee80211_hdr *hdr, + struct ieee80211_hdr_4addr *hdr, struct ieee80211_crypt_data **crypt, void **sta_ptr) { @@ -3160,7 +3160,7 @@ int hostap_add_sta(struct ap_data *ap, u8 *sta_addr) /* Called only as a tasklet (software IRQ) */ int hostap_update_rx_stats(struct ap_data *ap, - struct ieee80211_hdr *hdr, + struct ieee80211_hdr_4addr *hdr, struct hostap_80211_rx_status *rx_stats) { struct sta_info *sta; @@ -3174,7 +3174,7 @@ int hostap_update_rx_stats(struct ap_data *ap, sta->last_rx_silence = rx_stats->noise; sta->last_rx_signal = rx_stats->signal; sta->last_rx_rate = rx_stats->rate; - sta->last_rx_updated = 7; + sta->last_rx_updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; if (rx_stats->rate == 10) sta->rx_count[0]++; else if (rx_stats->rate == 20) diff --git a/drivers/net/wireless/hostap/hostap_ap.h b/drivers/net/wireless/hostap/hostap_ap.h index 816a52bcea8f..6d00df69c2e3 100644 --- a/drivers/net/wireless/hostap/hostap_ap.h +++ b/drivers/net/wireless/hostap/hostap_ap.h @@ -233,7 +233,7 @@ struct hostap_tx_data { ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx); void hostap_handle_sta_release(void *ptr); void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb); -int hostap_update_sta_ps(local_info_t *local, struct ieee80211_hdr *hdr); +int hostap_update_sta_ps(local_info_t *local, struct ieee80211_hdr_4addr *hdr); typedef enum { AP_RX_CONTINUE, AP_RX_DROP, AP_RX_EXIT, AP_RX_CONTINUE_NOT_AUTHORIZED } ap_rx_ret; @@ -241,13 +241,13 @@ ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev, struct sk_buff *skb, struct hostap_80211_rx_status *rx_stats, int wds); -int hostap_handle_sta_crypto(local_info_t *local, struct ieee80211_hdr *hdr, +int hostap_handle_sta_crypto(local_info_t *local, struct ieee80211_hdr_4addr *hdr, struct ieee80211_crypt_data **crypt, void **sta_ptr); int hostap_is_sta_assoc(struct ap_data *ap, u8 *sta_addr); int hostap_is_sta_authorized(struct ap_data *ap, u8 *sta_addr); int hostap_add_sta(struct ap_data *ap, u8 *sta_addr); -int hostap_update_rx_stats(struct ap_data *ap, struct ieee80211_hdr *hdr, +int hostap_update_rx_stats(struct ap_data *ap, struct ieee80211_hdr_4addr *hdr, struct hostap_80211_rx_status *rx_stats); void hostap_update_rates(local_info_t *local); void hostap_add_wds_links(local_info_t *local); diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c index faa83badf0a1..2643976a6677 100644 --- a/drivers/net/wireless/hostap/hostap_cs.c +++ b/drivers/net/wireless/hostap/hostap_cs.c @@ -492,42 +492,10 @@ static void prism2_pccard_genesis_reset(local_info_t *local, int hcr) } -static int prism2_pccard_dev_open(local_info_t *local) -{ - struct hostap_cs_priv *hw_priv = local->hw_priv; - hw_priv->link->open++; - return 0; -} - - -static int prism2_pccard_dev_close(local_info_t *local) -{ - struct hostap_cs_priv *hw_priv; - - if (local == NULL || local->hw_priv == NULL) - return 1; - hw_priv = local->hw_priv; - if (hw_priv->link == NULL) - return 1; - - if (!hw_priv->link->open) { - printk(KERN_WARNING "%s: prism2_pccard_dev_close(): " - "link not open?!\n", local->dev->name); - return 1; - } - - hw_priv->link->open--; - - return 0; -} - - static struct prism2_helper_functions prism2_pccard_funcs = { .card_present = prism2_pccard_card_present, .cor_sreset = prism2_pccard_cor_sreset, - .dev_open = prism2_pccard_dev_open, - .dev_close = prism2_pccard_dev_close, .genesis_reset = prism2_pccard_genesis_reset, .hw_type = HOSTAP_HW_PCCARD, }; @@ -597,13 +565,14 @@ static void prism2_detach(dev_link_t *link) *linkp = link->next; /* release net devices */ if (link->priv) { + struct hostap_cs_priv *hw_priv; struct net_device *dev; struct hostap_interface *iface; dev = link->priv; iface = netdev_priv(dev); - kfree(iface->local->hw_priv); - iface->local->hw_priv = NULL; + hw_priv = iface->local->hw_priv; prism2_free_local_data(dev); + kfree(hw_priv); } kfree(link); } @@ -883,6 +852,13 @@ static int prism2_event(event_t event, int priority, { dev_link_t *link = args->client_data; struct net_device *dev = (struct net_device *) link->priv; + int dev_open = 0; + + if (link->state & DEV_CONFIG) { + struct hostap_interface *iface = netdev_priv(dev); + if (iface && iface->local) + dev_open = iface->local->num_dev_open > 0; + } switch (event) { case CS_EVENT_CARD_INSERTION: @@ -911,7 +887,7 @@ static int prism2_event(event_t event, int priority, case CS_EVENT_RESET_PHYSICAL: PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_RESET_PHYSICAL\n", dev_info); if (link->state & DEV_CONFIG) { - if (link->open) { + if (dev_open) { netif_stop_queue(dev); netif_device_detach(dev); } @@ -931,8 +907,8 @@ static int prism2_event(event_t event, int priority, pcmcia_request_configuration(link->handle, &link->conf); prism2_hw_shutdown(dev, 1); - prism2_hw_config(dev, link->open ? 0 : 1); - if (link->open) { + prism2_hw_config(dev, dev_open ? 0 : 1); + if (dev_open) { netif_device_attach(dev); netif_start_queue(dev); } diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c index e533a663deda..59fc15572395 100644 --- a/drivers/net/wireless/hostap/hostap_hw.c +++ b/drivers/net/wireless/hostap/hostap_hw.c @@ -3322,6 +3322,18 @@ static void prism2_free_local_data(struct net_device *dev) iface = netdev_priv(dev); local = iface->local; + /* Unregister all netdevs before freeing local data. */ + list_for_each_safe(ptr, n, &local->hostap_interfaces) { + iface = list_entry(ptr, struct hostap_interface, list); + if (iface->type == HOSTAP_INTERFACE_MASTER) { + /* special handling for this interface below */ + continue; + } + hostap_remove_interface(iface->dev, 0, 1); + } + + unregister_netdev(local->dev); + flush_scheduled_work(); if (timer_pending(&local->crypt_deinit_timer)) @@ -3382,15 +3394,6 @@ static void prism2_free_local_data(struct net_device *dev) prism2_download_free_data(local->dl_sec); #endif /* PRISM2_DOWNLOAD_SUPPORT */ - list_for_each_safe(ptr, n, &local->hostap_interfaces) { - iface = list_entry(ptr, struct hostap_interface, list); - if (iface->type == HOSTAP_INTERFACE_MASTER) { - /* special handling for this interface below */ - continue; - } - hostap_remove_interface(iface->dev, 0, 1); - } - prism2_clear_set_tim_queue(local); list_for_each_safe(ptr, n, &local->bss_list) { @@ -3403,7 +3406,6 @@ static void prism2_free_local_data(struct net_device *dev) kfree(local->last_scan_results); kfree(local->generic_elem); - unregister_netdev(local->dev); free_netdev(local->dev); } diff --git a/drivers/net/wireless/hostap/hostap_ioctl.c b/drivers/net/wireless/hostap/hostap_ioctl.c index e720369a3515..2617d70bcda9 100644 --- a/drivers/net/wireless/hostap/hostap_ioctl.c +++ b/drivers/net/wireless/hostap/hostap_ioctl.c @@ -50,7 +50,8 @@ static struct iw_statistics *hostap_get_wireless_stats(struct net_device *dev) #endif /* in_atomic */ if (update && prism2_update_comms_qual(dev) == 0) - wstats->qual.updated = 7; + wstats->qual.updated = IW_QUAL_ALL_UPDATED | + IW_QUAL_DBM; wstats->qual.qual = local->comms_qual; wstats->qual.level = local->avg_signal; @@ -59,7 +60,7 @@ static struct iw_statistics *hostap_get_wireless_stats(struct net_device *dev) wstats->qual.qual = 0; wstats->qual.level = 0; wstats->qual.noise = 0; - wstats->qual.updated = 0; + wstats->qual.updated = IW_QUAL_ALL_INVALID; } return wstats; @@ -551,7 +552,6 @@ static int prism2_ioctl_giwaplist(struct net_device *dev, kfree(addr); kfree(qual); - return 0; } @@ -1827,13 +1827,6 @@ static char * __prism2_translate_scan(local_info_t *local, iwe.cmd = SIOCGIWAP; iwe.u.ap_addr.sa_family = ARPHRD_ETHER; memcpy(iwe.u.ap_addr.sa_data, bssid, ETH_ALEN); - /* FIX: - * I do not know how this is possible, but iwe_stream_add_event - * seems to re-order memcpy execution so that len is set only - * after copying.. Pre-setting len here "fixes" this, but real - * problems should be solved (after which these iwe.len - * settings could be removed from this function). */ - iwe.len = IW_EV_ADDR_LEN; current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_ADDR_LEN); @@ -1843,7 +1836,6 @@ static char * __prism2_translate_scan(local_info_t *local, iwe.cmd = SIOCGIWESSID; iwe.u.data.length = ssid_len; iwe.u.data.flags = 1; - iwe.len = IW_EV_POINT_LEN + iwe.u.data.length; current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, ssid); memset(&iwe, 0, sizeof(iwe)); @@ -1859,7 +1851,6 @@ static char * __prism2_translate_scan(local_info_t *local, iwe.u.mode = IW_MODE_MASTER; else iwe.u.mode = IW_MODE_ADHOC; - iwe.len = IW_EV_UINT_LEN; current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_UINT_LEN); } @@ -1877,7 +1868,6 @@ static char * __prism2_translate_scan(local_info_t *local, if (chan > 0) { iwe.u.freq.m = freq_list[le16_to_cpu(chan - 1)] * 100000; iwe.u.freq.e = 1; - iwe.len = IW_EV_FREQ_LEN; current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_FREQ_LEN); } @@ -1894,7 +1884,10 @@ static char * __prism2_translate_scan(local_info_t *local, iwe.u.qual.noise = HFA384X_LEVEL_TO_dBm(le16_to_cpu(scan->anl)); } - iwe.len = IW_EV_QUAL_LEN; + iwe.u.qual.updated = IW_QUAL_LEVEL_UPDATED + | IW_QUAL_NOISE_UPDATED + | IW_QUAL_QUAL_INVALID + | IW_QUAL_DBM; current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN); } @@ -1906,7 +1899,6 @@ static char * __prism2_translate_scan(local_info_t *local, else iwe.u.data.flags = IW_ENCODE_DISABLED; iwe.u.data.length = 0; - iwe.len = IW_EV_POINT_LEN + iwe.u.data.length; current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, ""); /* TODO: add SuppRates into BSS table */ @@ -1930,7 +1922,7 @@ static char * __prism2_translate_scan(local_info_t *local, } /* TODO: add BeaconInt,resp_rate,atim into BSS table */ - buf = kmalloc(MAX_WPA_IE_LEN * 2 + 30, GFP_KERNEL); + buf = kmalloc(MAX_WPA_IE_LEN * 2 + 30, GFP_ATOMIC); if (buf && scan) { memset(&iwe, 0, sizeof(iwe)); iwe.cmd = IWEVCUSTOM; @@ -3088,9 +3080,7 @@ static int prism2_ioctl_priv_download(local_info_t *local, struct iw_point *p) ret = local->func->download(local, param); out: - if (param != NULL) - kfree(param); - + kfree(param); return ret; } #endif /* PRISM2_DOWNLOAD_SUPPORT */ @@ -3897,9 +3887,7 @@ static int prism2_ioctl_priv_hostapd(local_info_t *local, struct iw_point *p) } out: - if (param != NULL) - kfree(param); - + kfree(param); return ret; } diff --git a/drivers/net/wireless/hostap/hostap_pci.c b/drivers/net/wireless/hostap/hostap_pci.c index 025f8cdb5566..da0c80fb941c 100644 --- a/drivers/net/wireless/hostap/hostap_pci.c +++ b/drivers/net/wireless/hostap/hostap_pci.c @@ -59,11 +59,13 @@ static struct pci_device_id prism2_pci_id_table[] __devinitdata = { static inline void hfa384x_outb_debug(struct net_device *dev, int a, u8 v) { struct hostap_interface *iface; + struct hostap_pci_priv *hw_priv; local_info_t *local; unsigned long flags; iface = netdev_priv(dev); local = iface->local; + hw_priv = local->hw_priv; spin_lock_irqsave(&local->lock, flags); prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTB, a, v); @@ -74,12 +76,14 @@ static inline void hfa384x_outb_debug(struct net_device *dev, int a, u8 v) static inline u8 hfa384x_inb_debug(struct net_device *dev, int a) { struct hostap_interface *iface; + struct hostap_pci_priv *hw_priv; local_info_t *local; unsigned long flags; u8 v; iface = netdev_priv(dev); local = iface->local; + hw_priv = local->hw_priv; spin_lock_irqsave(&local->lock, flags); v = readb(hw_priv->mem_start + a); @@ -91,11 +95,13 @@ static inline u8 hfa384x_inb_debug(struct net_device *dev, int a) static inline void hfa384x_outw_debug(struct net_device *dev, int a, u16 v) { struct hostap_interface *iface; + struct hostap_pci_priv *hw_priv; local_info_t *local; unsigned long flags; iface = netdev_priv(dev); local = iface->local; + hw_priv = local->hw_priv; spin_lock_irqsave(&local->lock, flags); prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTW, a, v); @@ -106,12 +112,14 @@ static inline void hfa384x_outw_debug(struct net_device *dev, int a, u16 v) static inline u16 hfa384x_inw_debug(struct net_device *dev, int a) { struct hostap_interface *iface; + struct hostap_pci_priv *hw_priv; local_info_t *local; unsigned long flags; u16 v; iface = netdev_priv(dev); local = iface->local; + hw_priv = local->hw_priv; spin_lock_irqsave(&local->lock, flags); v = readw(hw_priv->mem_start + a); @@ -277,8 +285,6 @@ static struct prism2_helper_functions prism2_pci_funcs = { .card_present = NULL, .cor_sreset = prism2_pci_cor_sreset, - .dev_open = NULL, - .dev_close = NULL, .genesis_reset = prism2_pci_genesis_reset, .hw_type = HOSTAP_HW_PCI, }; @@ -352,8 +358,6 @@ static int prism2_pci_probe(struct pci_dev *pdev, return hostap_hw_ready(dev); fail: - kfree(hw_priv); - if (irq_registered && dev) free_irq(dev->irq, dev); @@ -364,10 +368,8 @@ static int prism2_pci_probe(struct pci_dev *pdev, err_out_disable: pci_disable_device(pdev); - kfree(hw_priv); - if (local) - local->hw_priv = NULL; prism2_free_local_data(dev); + kfree(hw_priv); return -ENODEV; } @@ -392,9 +394,8 @@ static void prism2_pci_remove(struct pci_dev *pdev) free_irq(dev->irq, dev); mem_start = hw_priv->mem_start; - kfree(hw_priv); - iface->local->hw_priv = NULL; prism2_free_local_data(dev); + kfree(hw_priv); iounmap(mem_start); @@ -441,7 +442,7 @@ static int prism2_pci_resume(struct pci_dev *pdev) MODULE_DEVICE_TABLE(pci, prism2_pci_id_table); static struct pci_driver prism2_pci_drv_id = { - .name = "prism2_pci", + .name = "hostap_pci", .id_table = prism2_pci_id_table, .probe = prism2_pci_probe, .remove = prism2_pci_remove, diff --git a/drivers/net/wireless/hostap/hostap_plx.c b/drivers/net/wireless/hostap/hostap_plx.c index 474ef83d813e..78d67b408b2f 100644 --- a/drivers/net/wireless/hostap/hostap_plx.c +++ b/drivers/net/wireless/hostap/hostap_plx.c @@ -328,8 +328,6 @@ static struct prism2_helper_functions prism2_plx_funcs = { .card_present = NULL, .cor_sreset = prism2_plx_cor_sreset, - .dev_open = NULL, - .dev_close = NULL, .genesis_reset = prism2_plx_genesis_reset, .hw_type = HOSTAP_HW_PLX, }; @@ -570,10 +568,8 @@ static int prism2_plx_probe(struct pci_dev *pdev, return hostap_hw_ready(dev); fail: - kfree(hw_priv); - if (local) - local->hw_priv = NULL; prism2_free_local_data(dev); + kfree(hw_priv); if (irq_registered && dev) free_irq(dev->irq, dev); @@ -606,9 +602,8 @@ static void prism2_plx_remove(struct pci_dev *pdev) if (dev->irq) free_irq(dev->irq, dev); - kfree(iface->local->hw_priv); - iface->local->hw_priv = NULL; prism2_free_local_data(dev); + kfree(hw_priv); pci_disable_device(pdev); } @@ -616,7 +611,7 @@ static void prism2_plx_remove(struct pci_dev *pdev) MODULE_DEVICE_TABLE(pci, prism2_plx_id_table); static struct pci_driver prism2_plx_drv_id = { - .name = "prism2_plx", + .name = "hostap_plx", .id_table = prism2_plx_id_table, .probe = prism2_plx_probe, .remove = prism2_plx_remove, diff --git a/drivers/net/wireless/hostap/hostap_wlan.h b/drivers/net/wireless/hostap/hostap_wlan.h index cc061e1560d3..cfd801559492 100644 --- a/drivers/net/wireless/hostap/hostap_wlan.h +++ b/drivers/net/wireless/hostap/hostap_wlan.h @@ -552,8 +552,6 @@ struct prism2_helper_functions { * (hostap_{cs,plx,pci}.c */ int (*card_present)(local_info_t *local); void (*cor_sreset)(local_info_t *local); - int (*dev_open)(local_info_t *local); - int (*dev_close)(local_info_t *local); void (*genesis_reset)(local_info_t *local, int hcr); /* the following functions are from hostap_hw.c, but they may have some diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index 2414e6493aa5..ad7f8cd76db9 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c @@ -800,8 +800,7 @@ static int ipw2100_hw_send_command(struct ipw2100_priv *priv, * doesn't seem to have as many firmware restart cycles... * * As a test, we're sticking in a 1/100s delay here */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ / 100); + schedule_timeout_uninterruptible(msecs_to_jiffies(10)); return 0; @@ -1256,8 +1255,7 @@ static int ipw2100_start_adapter(struct ipw2100_priv *priv) IPW_DEBUG_FW("Waiting for f/w initialization to complete...\n"); i = 5000; do { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(40 * HZ / 1000); + schedule_timeout_uninterruptible(msecs_to_jiffies(40)); /* Todo... wait for sync command ... */ read_register(priv->net_dev, IPW_REG_INTA, &inta); @@ -1411,8 +1409,7 @@ static int ipw2100_hw_phy_off(struct ipw2100_priv *priv) (val2 & IPW2100_COMMAND_PHY_OFF)) return 0; - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HW_PHY_OFF_LOOP_DELAY); + schedule_timeout_uninterruptible(HW_PHY_OFF_LOOP_DELAY); } return -EIO; @@ -1466,7 +1463,7 @@ fail_up: static int ipw2100_hw_stop_adapter(struct ipw2100_priv *priv) { -#define HW_POWER_DOWN_DELAY (HZ / 10) +#define HW_POWER_DOWN_DELAY (msecs_to_jiffies(100)) struct host_command cmd = { .host_command = HOST_PRE_POWER_DOWN, @@ -1520,10 +1517,8 @@ static int ipw2100_hw_stop_adapter(struct ipw2100_priv *priv) printk(KERN_WARNING DRV_NAME ": " "%s: Power down command failed: Error %d\n", priv->net_dev->name, err); - else { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HW_POWER_DOWN_DELAY); - } + else + schedule_timeout_uninterruptible(HW_POWER_DOWN_DELAY); } priv->status &= ~STATUS_ENABLED; @@ -2953,7 +2948,7 @@ static void ipw2100_tx_send_data(struct ipw2100_priv *priv) int next = txq->next; int i = 0; struct ipw2100_data_header *ipw_hdr; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr_3addr *hdr; while (!list_empty(&priv->tx_pend_list)) { /* if there isn't enough space in TBD queue, then @@ -2989,7 +2984,7 @@ static void ipw2100_tx_send_data(struct ipw2100_priv *priv) packet->index = txq->next; ipw_hdr = packet->info.d_struct.data; - hdr = (struct ieee80211_hdr *)packet->info.d_struct.txb-> + hdr = (struct ieee80211_hdr_3addr *)packet->info.d_struct.txb-> fragments[0]->data; if (priv->ieee->iw_mode == IW_MODE_INFRA) { @@ -3274,7 +3269,8 @@ static irqreturn_t ipw2100_interrupt(int irq, void *data, return IRQ_NONE; } -static int ipw2100_tx(struct ieee80211_txb *txb, struct net_device *dev) +static int ipw2100_tx(struct ieee80211_txb *txb, struct net_device *dev, + int pri) { struct ipw2100_priv *priv = ieee80211_priv(dev); struct list_head *element; diff --git a/drivers/net/wireless/ipw2100.h b/drivers/net/wireless/ipw2100.h index 2a3cdbd50168..c9e99ce15d66 100644 --- a/drivers/net/wireless/ipw2100.h +++ b/drivers/net/wireless/ipw2100.h @@ -808,7 +808,7 @@ struct ipw2100_priv { struct ipw2100_rx { union { unsigned char payload[IPW_RX_NIC_BUFFER_LENGTH]; - struct ieee80211_hdr header; + struct ieee80211_hdr_4addr header; u32 status; struct ipw2100_notification notification; struct ipw2100_cmd_header command; diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index b7f275c00de3..3db0c32afe82 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -4030,6 +4030,10 @@ static struct ipw_rx_queue *ipw_rx_queue_alloc(struct ipw_priv *priv) int i; rxq = (struct ipw_rx_queue *)kmalloc(sizeof(*rxq), GFP_KERNEL); + if (unlikely(!rxq)) { + IPW_ERROR("memory allocation failed\n"); + return NULL; + } memset(rxq, 0, sizeof(*rxq)); spin_lock_init(&rxq->lock); INIT_LIST_HEAD(&rxq->rx_free); @@ -4904,7 +4908,7 @@ static void ipw_rx(struct ipw_priv *priv) { struct ipw_rx_mem_buffer *rxb; struct ipw_rx_packet *pkt; - struct ieee80211_hdr *header; + struct ieee80211_hdr_4addr *header; u32 r, w, i; u8 network_packet; @@ -4967,8 +4971,9 @@ static void ipw_rx(struct ipw_priv *priv) #endif header = - (struct ieee80211_hdr *)(rxb->skb->data + - IPW_RX_FRAME_SIZE); + (struct ieee80211_hdr_4addr *)(rxb->skb-> + data + + IPW_RX_FRAME_SIZE); /* TODO: Check Ad-Hoc dest/source and make sure * that we are actually parsing these packets * correctly -- we should probably use the @@ -5317,8 +5322,6 @@ static int ipw_wx_set_freq(struct net_device *dev, IPW_DEBUG_WX("SET Freq/Channel -> %d \n", fwrq->m); return ipw_set_channel(priv, (u8) fwrq->m); - - return 0; } static int ipw_wx_get_freq(struct net_device *dev, @@ -6010,12 +6013,12 @@ static int ipw_wx_set_wireless_mode(struct net_device *dev, } if (priv->adapter == IPW_2915ABG) { - priv->ieee->abg_ture = 1; + priv->ieee->abg_true = 1; if (mode & IEEE_A) { band |= IEEE80211_52GHZ_BAND; modulation |= IEEE80211_OFDM_MODULATION; } else - priv->ieee->abg_ture = 0; + priv->ieee->abg_true = 0; } else { if (mode & IEEE_A) { IPW_WARNING("Attempt to set 2200BG into " @@ -6023,20 +6026,20 @@ static int ipw_wx_set_wireless_mode(struct net_device *dev, return -EINVAL; } - priv->ieee->abg_ture = 0; + priv->ieee->abg_true = 0; } if (mode & IEEE_B) { band |= IEEE80211_24GHZ_BAND; modulation |= IEEE80211_CCK_MODULATION; } else - priv->ieee->abg_ture = 0; + priv->ieee->abg_true = 0; if (mode & IEEE_G) { band |= IEEE80211_24GHZ_BAND; modulation |= IEEE80211_OFDM_MODULATION; } else - priv->ieee->abg_ture = 0; + priv->ieee->abg_true = 0; priv->ieee->mode = mode; priv->ieee->freq_band = band; @@ -6325,7 +6328,7 @@ we need to heavily modify the ieee80211_skb_to_txb. static inline void ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb) { - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) + struct ieee80211_hdr_3addr *hdr = (struct ieee80211_hdr_3addr *) txb->fragments[0]->data; int i = 0; struct tfd_frame *tfd; @@ -6448,7 +6451,7 @@ static inline void ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb) } static int ipw_net_hard_start_xmit(struct ieee80211_txb *txb, - struct net_device *dev) + struct net_device *dev, int pri) { struct ipw_priv *priv = ieee80211_priv(dev); unsigned long flags; @@ -7108,7 +7111,7 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) printk(KERN_INFO DRV_NAME ": Detected Intel PRO/Wireless 2915ABG Network " "Connection\n"); - priv->ieee->abg_ture = 1; + priv->ieee->abg_true = 1; band = IEEE80211_52GHZ_BAND | IEEE80211_24GHZ_BAND; modulation = IEEE80211_OFDM_MODULATION | IEEE80211_CCK_MODULATION; @@ -7124,7 +7127,7 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ": Detected Intel PRO/Wireless 2200BG Network " "Connection\n"); - priv->ieee->abg_ture = 0; + priv->ieee->abg_true = 0; band = IEEE80211_24GHZ_BAND; modulation = IEEE80211_OFDM_MODULATION | IEEE80211_CCK_MODULATION; diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h index 5b00882133f9..e9cf32bf3e31 100644 --- a/drivers/net/wireless/ipw2200.h +++ b/drivers/net/wireless/ipw2200.h @@ -1654,12 +1654,12 @@ static const long ipw_frequencies[] = { #define IPW_MAX_CONFIG_RETRIES 10 -static inline u32 frame_hdr_len(struct ieee80211_hdr *hdr) +static inline u32 frame_hdr_len(struct ieee80211_hdr_4addr *hdr) { u32 retval; u16 fc; - retval = sizeof(struct ieee80211_hdr); + retval = sizeof(struct ieee80211_hdr_3addr); fc = le16_to_cpu(hdr->frame_ctl); /* diff --git a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c index ca6c03c89926..92793b958e32 100644 --- a/drivers/net/wireless/netwave_cs.c +++ b/drivers/net/wireless/netwave_cs.c @@ -57,9 +57,7 @@ #include <linux/bitops.h> #ifdef CONFIG_NET_RADIO #include <linux/wireless.h> -#if WIRELESS_EXT > 12 #include <net/iw_handler.h> -#endif /* WIRELESS_EXT > 12 */ #endif #include <pcmcia/cs_types.h> @@ -225,10 +223,7 @@ static void update_stats(struct net_device *dev); static struct net_device_stats *netwave_get_stats(struct net_device *dev); /* Wireless extensions */ -#ifdef WIRELESS_EXT static struct iw_statistics* netwave_get_wireless_stats(struct net_device *dev); -#endif -static int netwave_ioctl(struct net_device *, struct ifreq *, int); static void set_multicast_list(struct net_device *dev); @@ -260,26 +255,7 @@ static dev_link_t *dev_list; because they generally can't be allocated dynamically. */ -#if WIRELESS_EXT <= 12 -/* Wireless extensions backward compatibility */ - -/* Part of iw_handler prototype we need */ -struct iw_request_info -{ - __u16 cmd; /* Wireless Extension command */ - __u16 flags; /* More to come ;-) */ -}; - -/* Wireless Extension Backward compatibility - Jean II - * If the new wireless device private ioctl range is not defined, - * default to standard device private ioctl range */ -#ifndef SIOCIWFIRSTPRIV -#define SIOCIWFIRSTPRIV SIOCDEVPRIVATE -#endif /* SIOCIWFIRSTPRIV */ - -#else /* WIRELESS_EXT <= 12 */ static const struct iw_handler_def netwave_handler_def; -#endif /* WIRELESS_EXT <= 12 */ #define SIOCGIPSNAP SIOCIWFIRSTPRIV + 1 /* Site Survey Snapshot */ @@ -319,9 +295,7 @@ typedef struct netwave_private { struct timer_list watchdog; /* To avoid blocking state */ struct site_survey nss; struct net_device_stats stats; -#ifdef WIRELESS_EXT struct iw_statistics iw_stats; /* Wireless stats */ -#endif } netwave_private; #ifdef NETWAVE_STATS @@ -353,7 +327,6 @@ static inline void wait_WOC(unsigned int iobase) while ((inb(iobase + NETWAVE_REG_ASR) & 0x8) != 0x8) ; } -#ifdef WIRELESS_EXT static void netwave_snapshot(netwave_private *priv, u_char __iomem *ramBase, kio_addr_t iobase) { u_short resultBuffer; @@ -376,9 +349,7 @@ static void netwave_snapshot(netwave_private *priv, u_char __iomem *ramBase, sizeof(struct site_survey)); } } -#endif -#ifdef WIRELESS_EXT /* * Function netwave_get_wireless_stats (dev) * @@ -411,7 +382,6 @@ static struct iw_statistics *netwave_get_wireless_stats(struct net_device *dev) return &priv->iw_stats; } -#endif /* * Function netwave_attach (void) @@ -471,13 +441,7 @@ static dev_link_t *netwave_attach(void) dev->get_stats = &netwave_get_stats; dev->set_multicast_list = &set_multicast_list; /* wireless extensions */ -#if WIRELESS_EXT <= 16 - dev->get_wireless_stats = &netwave_get_wireless_stats; -#endif /* WIRELESS_EXT <= 16 */ -#if WIRELESS_EXT > 12 dev->wireless_handlers = (struct iw_handler_def *)&netwave_handler_def; -#endif /* WIRELESS_EXT > 12 */ - dev->do_ioctl = &netwave_ioctl; dev->tx_timeout = &netwave_watchdog; dev->watchdog_timeo = TX_TIMEOUT; @@ -576,13 +540,8 @@ static int netwave_set_nwid(struct net_device *dev, /* Disable interrupts & save flags */ spin_lock_irqsave(&priv->spinlock, flags); -#if WIRELESS_EXT > 8 if(!wrqu->nwid.disabled) { domain = wrqu->nwid.value; -#else /* WIRELESS_EXT > 8 */ - if(wrqu->nwid.on) { - domain = wrqu->nwid.nwid; -#endif /* WIRELESS_EXT > 8 */ printk( KERN_DEBUG "Setting domain to 0x%x%02x\n", (domain >> 8) & 0x01, domain & 0xff); wait_WOC(iobase); @@ -606,15 +565,9 @@ static int netwave_get_nwid(struct net_device *dev, union iwreq_data *wrqu, char *extra) { -#if WIRELESS_EXT > 8 wrqu->nwid.value = domain; wrqu->nwid.disabled = 0; wrqu->nwid.fixed = 1; -#else /* WIRELESS_EXT > 8 */ - wrqu->nwid.nwid = domain; - wrqu->nwid.on = 1; -#endif /* WIRELESS_EXT > 8 */ - return 0; } @@ -657,17 +610,11 @@ static int netwave_get_scramble(struct net_device *dev, { key[1] = scramble_key & 0xff; key[0] = (scramble_key>>8) & 0xff; -#if WIRELESS_EXT > 8 wrqu->encoding.flags = IW_ENCODE_ENABLED; wrqu->encoding.length = 2; -#else /* WIRELESS_EXT > 8 */ - wrqu->encoding.method = 1; -#endif /* WIRELESS_EXT > 8 */ - return 0; } -#if WIRELESS_EXT > 8 /* * Wireless Handler : get mode */ @@ -683,7 +630,6 @@ static int netwave_get_mode(struct net_device *dev, return 0; } -#endif /* WIRELESS_EXT > 8 */ /* * Wireless Handler : get range info @@ -702,11 +648,9 @@ static int netwave_get_range(struct net_device *dev, /* Set all the info we don't care or don't know about to zero */ memset(range, 0, sizeof(struct iw_range)); -#if WIRELESS_EXT > 10 /* Set the Wireless Extension versions */ range->we_version_compiled = WIRELESS_EXT; range->we_version_source = 9; /* Nothing for us in v10 and v11 */ -#endif /* WIRELESS_EXT > 10 */ /* Set information in the range struct */ range->throughput = 450 * 1000; /* don't argue on this ! */ @@ -720,16 +664,12 @@ static int netwave_get_range(struct net_device *dev, range->max_qual.level = 255; range->max_qual.noise = 0; -#if WIRELESS_EXT > 7 range->num_bitrates = 1; range->bitrate[0] = 1000000; /* 1 Mb/s */ -#endif /* WIRELESS_EXT > 7 */ -#if WIRELESS_EXT > 8 range->encoding_size[0] = 2; /* 16 bits scrambling */ range->num_encoding_sizes = 1; range->max_encoding_tokens = 1; /* Only one key possible */ -#endif /* WIRELESS_EXT > 8 */ return ret; } @@ -775,8 +715,6 @@ static const struct iw_priv_args netwave_private_args[] = { "getsitesurvey" }, }; -#if WIRELESS_EXT > 12 - static const iw_handler netwave_handler[] = { NULL, /* SIOCSIWNAME */ @@ -839,131 +777,8 @@ static const struct iw_handler_def netwave_handler_def = .standard = (iw_handler *) netwave_handler, .private = (iw_handler *) netwave_private_handler, .private_args = (struct iw_priv_args *) netwave_private_args, -#if WIRELESS_EXT > 16 .get_wireless_stats = netwave_get_wireless_stats, -#endif /* WIRELESS_EXT > 16 */ }; -#endif /* WIRELESS_EXT > 12 */ - -/* - * Function netwave_ioctl (dev, rq, cmd) - * - * Perform ioctl : config & info stuff - * This is the stuff that are treated the wireless extensions (iwconfig) - * - */ -static int netwave_ioctl(struct net_device *dev, /* ioctl device */ - struct ifreq *rq, /* Data passed */ - int cmd) /* Ioctl number */ -{ - int ret = 0; -#ifdef WIRELESS_EXT -#if WIRELESS_EXT <= 12 - struct iwreq *wrq = (struct iwreq *) rq; -#endif -#endif - - DEBUG(0, "%s: ->netwave_ioctl(cmd=0x%X)\n", dev->name, cmd); - - /* Look what is the request */ - switch(cmd) { - /* --------------- WIRELESS EXTENSIONS --------------- */ -#ifdef WIRELESS_EXT -#if WIRELESS_EXT <= 12 - case SIOCGIWNAME: - netwave_get_name(dev, NULL, &(wrq->u), NULL); - break; - case SIOCSIWNWID: - ret = netwave_set_nwid(dev, NULL, &(wrq->u), NULL); - break; - case SIOCGIWNWID: - ret = netwave_get_nwid(dev, NULL, &(wrq->u), NULL); - break; -#if WIRELESS_EXT > 8 /* Note : The API did change... */ - case SIOCGIWENCODE: - /* Get scramble key */ - if(wrq->u.encoding.pointer != (caddr_t) 0) - { - char key[2]; - ret = netwave_get_scramble(dev, NULL, &(wrq->u), key); - if(copy_to_user(wrq->u.encoding.pointer, key, 2)) - ret = -EFAULT; - } - break; - case SIOCSIWENCODE: - /* Set scramble key */ - if(wrq->u.encoding.pointer != (caddr_t) 0) - { - char key[2]; - if(copy_from_user(key, wrq->u.encoding.pointer, 2)) - { - ret = -EFAULT; - break; - } - ret = netwave_set_scramble(dev, NULL, &(wrq->u), key); - } - break; - case SIOCGIWMODE: - /* Mode of operation */ - ret = netwave_get_mode(dev, NULL, &(wrq->u), NULL); - break; -#else /* WIRELESS_EXT > 8 */ - case SIOCGIWENCODE: - /* Get scramble key */ - ret = netwave_get_scramble(dev, NULL, &(wrq->u), - (char *) &wrq->u.encoding.code); - break; - case SIOCSIWENCODE: - /* Set scramble key */ - ret = netwave_set_scramble(dev, NULL, &(wrq->u), - (char *) &wrq->u.encoding.code); - break; -#endif /* WIRELESS_EXT > 8 */ - case SIOCGIWRANGE: - /* Basic checking... */ - if(wrq->u.data.pointer != (caddr_t) 0) { - struct iw_range range; - ret = netwave_get_range(dev, NULL, &(wrq->u), (char *) &range); - if (copy_to_user(wrq->u.data.pointer, &range, - sizeof(struct iw_range))) - ret = -EFAULT; - } - break; - case SIOCGIWPRIV: - /* Basic checking... */ - if(wrq->u.data.pointer != (caddr_t) 0) { - /* Set the number of ioctl available */ - wrq->u.data.length = sizeof(netwave_private_args) / sizeof(netwave_private_args[0]); - - /* Copy structure to the user buffer */ - if(copy_to_user(wrq->u.data.pointer, - (u_char *) netwave_private_args, - sizeof(netwave_private_args))) - ret = -EFAULT; - } - break; - case SIOCGIPSNAP: - if(wrq->u.data.pointer != (caddr_t) 0) { - char buffer[sizeof( struct site_survey)]; - ret = netwave_get_snap(dev, NULL, &(wrq->u), buffer); - /* Copy structure to the user buffer */ - if(copy_to_user(wrq->u.data.pointer, - buffer, - sizeof( struct site_survey))) - { - printk(KERN_DEBUG "Bad buffer!\n"); - break; - } - } - break; -#endif /* WIRELESS_EXT <= 12 */ -#endif /* WIRELESS_EXT */ - default: - ret = -EOPNOTSUPP; - } - - return ret; -} /* * Function netwave_pcmcia_config (link) diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index 15ceaf615756..488ab06fb79f 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -77,30 +77,16 @@ #define DRIVER_NAME "orinoco" #include <linux/config.h> - #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> -#include <linux/ptrace.h> -#include <linux/slab.h> -#include <linux/string.h> -#include <linux/timer.h> -#include <linux/ioport.h> #include <linux/netdevice.h> -#include <linux/if_arp.h> #include <linux/etherdevice.h> #include <linux/ethtool.h> #include <linux/wireless.h> #include <net/iw_handler.h> #include <net/ieee80211.h> -#include <net/ieee80211.h> - -#include <asm/uaccess.h> -#include <asm/io.h> -#include <asm/system.h> - -#include "hermes.h" #include "hermes_rid.h" #include "orinoco.h" @@ -137,7 +123,7 @@ MODULE_PARM_DESC(force_monitor, "Allow monitor mode for all firmware versions"); /* We do this this way to avoid ifdefs in the actual code */ #ifdef WIRELESS_SPY -#define SPY_NUMBER(priv) (priv->spy_number) +#define SPY_NUMBER(priv) (priv->spy_data.spy_number) #else #define SPY_NUMBER(priv) 0 #endif /* WIRELESS_SPY */ @@ -216,31 +202,32 @@ static struct { /********************************************************************/ /* Used in Event handling. - * We avoid nested structres as they break on ARM -- Moustafa */ + * We avoid nested structures as they break on ARM -- Moustafa */ struct hermes_tx_descriptor_802_11 { /* hermes_tx_descriptor */ - u16 status; - u16 reserved1; - u16 reserved2; - u32 sw_support; + __le16 status; + __le16 reserved1; + __le16 reserved2; + __le32 sw_support; u8 retry_count; u8 tx_rate; - u16 tx_control; + __le16 tx_control; - /* ieee802_11_hdr */ - u16 frame_ctl; - u16 duration_id; + /* ieee80211_hdr */ + __le16 frame_ctl; + __le16 duration_id; u8 addr1[ETH_ALEN]; u8 addr2[ETH_ALEN]; u8 addr3[ETH_ALEN]; - u16 seq_ctl; + __le16 seq_ctl; u8 addr4[ETH_ALEN]; - u16 data_len; + + __le16 data_len; /* ethhdr */ - unsigned char h_dest[ETH_ALEN]; /* destination eth addr */ - unsigned char h_source[ETH_ALEN]; /* source ether addr */ - unsigned short h_proto; /* packet type ID field */ + u8 h_dest[ETH_ALEN]; /* destination eth addr */ + u8 h_source[ETH_ALEN]; /* source ether addr */ + __be16 h_proto; /* packet type ID field */ /* p8022_hdr */ u8 dsap; @@ -248,31 +235,31 @@ struct hermes_tx_descriptor_802_11 { u8 ctrl; u8 oui[3]; - u16 ethertype; + __be16 ethertype; } __attribute__ ((packed)); /* Rx frame header except compatibility 802.3 header */ struct hermes_rx_descriptor { /* Control */ - u16 status; - u32 time; + __le16 status; + __le32 time; u8 silence; u8 signal; u8 rate; u8 rxflow; - u32 reserved; + __le32 reserved; /* 802.11 header */ - u16 frame_ctl; - u16 duration_id; + __le16 frame_ctl; + __le16 duration_id; u8 addr1[ETH_ALEN]; u8 addr2[ETH_ALEN]; u8 addr3[ETH_ALEN]; - u16 seq_ctl; + __le16 seq_ctl; u8 addr4[ETH_ALEN]; /* Data length */ - u16 data_len; + __le16 data_len; } __attribute__ ((packed)); /********************************************************************/ @@ -396,14 +383,14 @@ static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev) /* If a spy address is defined, we report stats of the * first spy address - Jean II */ if (SPY_NUMBER(priv)) { - wstats->qual.qual = priv->spy_stat[0].qual; - wstats->qual.level = priv->spy_stat[0].level; - wstats->qual.noise = priv->spy_stat[0].noise; - wstats->qual.updated = priv->spy_stat[0].updated; + wstats->qual.qual = priv->spy_data.spy_stat[0].qual; + wstats->qual.level = priv->spy_data.spy_stat[0].level; + wstats->qual.noise = priv->spy_data.spy_stat[0].noise; + wstats->qual.updated = priv->spy_data.spy_stat[0].updated; } } else { struct { - u16 qual, signal, noise; + __le16 qual, signal, noise; } __attribute__ ((packed)) cq; err = HERMES_READ_RECORD(hw, USER_BAP, @@ -503,13 +490,12 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev) return 0; } - /* Check packet length, pad short packets, round up odd length */ + /* Length of the packet body */ + /* FIXME: what if the skb is smaller than this? */ len = max_t(int, ALIGN(skb->len, 2), ETH_ZLEN); - if (skb->len < len) { - skb = skb_padto(skb, len); - if (skb == NULL) - goto fail; - } + skb = skb_padto(skb, len); + if (skb == NULL) + goto fail; len -= ETH_HLEN; eh = (struct ethhdr *)skb->data; @@ -556,13 +542,21 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev) stats->tx_errors++; goto fail; } + /* Actual xfer length - allow for padding */ + len = ALIGN(data_len, 2); + if (len < ETH_ZLEN - ETH_HLEN) + len = ETH_ZLEN - ETH_HLEN; } else { /* IEEE 802.3 frame */ data_len = len + ETH_HLEN; data_off = HERMES_802_3_OFFSET; p = skb->data; + /* Actual xfer length - round up for odd length packets */ + len = ALIGN(data_len, 2); + if (len < ETH_ZLEN) + len = ETH_ZLEN; } - err = hermes_bap_pwrite(hw, USER_BAP, p, data_len, + err = hermes_bap_pwrite_pad(hw, USER_BAP, p, data_len, len, txfid, data_off); if (err) { printk(KERN_ERR "%s: Error %d writing packet to BAP\n", @@ -634,16 +628,17 @@ static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw) struct orinoco_private *priv = netdev_priv(dev); struct net_device_stats *stats = &priv->stats; u16 fid = hermes_read_regn(hw, TXCOMPLFID); + u16 status; struct hermes_tx_descriptor_802_11 hdr; int err = 0; if (fid == DUMMY_FID) return; /* Nothing's really happened */ - /* Read the frame header */ + /* Read part of the frame header - we need status and addr1 */ err = hermes_bap_pread(hw, IRQ_BAP, &hdr, - sizeof(struct hermes_tx_descriptor) + - sizeof(struct ieee80211_hdr), + offsetof(struct hermes_tx_descriptor_802_11, + addr2), fid, 0); hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID); @@ -663,8 +658,8 @@ static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw) * exceeded, because that's the only status that really mean * that this particular node went away. * Other errors means that *we* screwed up. - Jean II */ - hdr.status = le16_to_cpu(hdr.status); - if (hdr.status & (HERMES_TXSTAT_RETRYERR | HERMES_TXSTAT_AGEDERR)) { + status = le16_to_cpu(hdr.status); + if (status & (HERMES_TXSTAT_RETRYERR | HERMES_TXSTAT_AGEDERR)) { union iwreq_data wrqu; /* Copy 802.11 dest address. @@ -723,18 +718,13 @@ static inline int is_ethersnap(void *_hdr) static inline void orinoco_spy_gather(struct net_device *dev, u_char *mac, int level, int noise) { - struct orinoco_private *priv = netdev_priv(dev); - int i; - - /* Gather wireless spy statistics: for each packet, compare the - * source address with out list, and if match, get the stats... */ - for (i = 0; i < priv->spy_number; i++) - if (!memcmp(mac, priv->spy_address[i], ETH_ALEN)) { - priv->spy_stat[i].level = level - 0x95; - priv->spy_stat[i].noise = noise - 0x95; - priv->spy_stat[i].qual = (level > noise) ? (level - noise) : 0; - priv->spy_stat[i].updated = 7; - } + struct iw_quality wstats; + wstats.level = level - 0x95; + wstats.noise = noise - 0x95; + wstats.qual = (level > noise) ? (level - noise) : 0; + wstats.updated = 7; + /* Update spy records */ + wireless_spy_update(dev, mac, &wstats); } static void orinoco_stat_gather(struct net_device *dev, @@ -1055,7 +1045,7 @@ static void orinoco_join_ap(struct net_device *dev) unsigned long flags; struct join_req { u8 bssid[ETH_ALEN]; - u16 channel; + __le16 channel; } __attribute__ ((packed)) req; const int atom_len = offsetof(struct prism2_scan_apinfo, atim); struct prism2_scan_apinfo *atom = NULL; @@ -1070,7 +1060,7 @@ static void orinoco_join_ap(struct net_device *dev) return; if (orinoco_lock(priv, &flags) != 0) - goto out; + goto fail_lock; /* Sanity checks in case user changed something in the meantime */ if (! priv->bssid_fixed) @@ -1115,8 +1105,10 @@ static void orinoco_join_ap(struct net_device *dev) printk(KERN_ERR "%s: Error issuing join request\n", dev->name); out: - kfree(buf); orinoco_unlock(priv, &flags); + + fail_lock: + kfree(buf); } /* Send new BSSID to userspace */ @@ -1134,12 +1126,14 @@ static void orinoco_send_wevents(struct net_device *dev) err = hermes_read_ltv(hw, IRQ_BAP, HERMES_RID_CURRENTBSSID, ETH_ALEN, NULL, wrqu.ap_addr.sa_data); if (err != 0) - return; + goto out; wrqu.ap_addr.sa_family = ARPHRD_ETHER; /* Send event to user space */ wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); + + out: orinoco_unlock(priv, &flags); } @@ -1148,8 +1142,8 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) struct orinoco_private *priv = netdev_priv(dev); u16 infofid; struct { - u16 len; - u16 type; + __le16 len; + __le16 type; } __attribute__ ((packed)) info; int len, type; int err; @@ -2464,6 +2458,10 @@ struct net_device *alloc_orinocodev(int sizeof_card, dev->get_stats = orinoco_get_stats; dev->ethtool_ops = &orinoco_ethtool_ops; dev->wireless_handlers = (struct iw_handler_def *)&orinoco_handler_def; +#ifdef WIRELESS_SPY + priv->wireless_data.spy_data = &priv->spy_data; + dev->wireless_data = &priv->wireless_data; +#endif dev->change_mtu = orinoco_change_mtu; dev->set_multicast_list = orinoco_set_multicast_list; /* we use the default eth_mac_addr for setting the MAC addr */ @@ -2835,7 +2833,7 @@ static int orinoco_ioctl_getiwrange(struct net_device *dev, } } - if ((priv->iw_mode == IW_MODE_ADHOC) && (priv->spy_number == 0)){ + if ((priv->iw_mode == IW_MODE_ADHOC) && (!SPY_NUMBER(priv))){ /* Quality stats meaningless in ad-hoc mode */ } else { range->max_qual.qual = 0x8b - 0x2f; @@ -2882,6 +2880,14 @@ static int orinoco_ioctl_getiwrange(struct net_device *dev, range->min_r_time = 0; range->max_r_time = 65535 * 1000; /* ??? */ + /* Event capability (kernel) */ + IW_EVENT_CAPA_SET_KERNEL(range->event_capa); + /* Event capability (driver) */ + IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWTHRSPY); + IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP); + IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN); + IW_EVENT_CAPA_SET(range->event_capa, IWEVTXDROP); + TRACE_EXIT(dev->name); return 0; @@ -3841,92 +3847,6 @@ static int orinoco_ioctl_getrid(struct net_device *dev, return err; } -/* Spy is used for link quality/strength measurements in Ad-Hoc mode - * Jean II */ -static int orinoco_ioctl_setspy(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *srq, - char *extra) - -{ - struct orinoco_private *priv = netdev_priv(dev); - struct sockaddr *address = (struct sockaddr *) extra; - int number = srq->length; - int i; - unsigned long flags; - - /* Make sure nobody mess with the structure while we do */ - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - /* orinoco_lock() doesn't disable interrupts, so make sure the - * interrupt rx path don't get confused while we copy */ - priv->spy_number = 0; - - if (number > 0) { - /* Extract the addresses */ - for (i = 0; i < number; i++) - memcpy(priv->spy_address[i], address[i].sa_data, - ETH_ALEN); - /* Reset stats */ - memset(priv->spy_stat, 0, - sizeof(struct iw_quality) * IW_MAX_SPY); - /* Set number of addresses */ - priv->spy_number = number; - } - - /* Now, let the others play */ - orinoco_unlock(priv, &flags); - - /* Do NOT call commit handler */ - return 0; -} - -static int orinoco_ioctl_getspy(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *srq, - char *extra) -{ - struct orinoco_private *priv = netdev_priv(dev); - struct sockaddr *address = (struct sockaddr *) extra; - int number; - int i; - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - number = priv->spy_number; - /* Create address struct */ - for (i = 0; i < number; i++) { - memcpy(address[i].sa_data, priv->spy_address[i], ETH_ALEN); - address[i].sa_family = AF_UNIX; - } - if (number > 0) { - /* Create address struct */ - for (i = 0; i < number; i++) { - memcpy(address[i].sa_data, priv->spy_address[i], - ETH_ALEN); - address[i].sa_family = AF_UNIX; - } - /* Copy stats */ - /* In theory, we should disable irqs while copying the stats - * because the rx path might update it in the middle... - * Bah, who care ? - Jean II */ - memcpy(extra + (sizeof(struct sockaddr) * number), - priv->spy_stat, sizeof(struct iw_quality) * number); - } - /* Reset updated flags. */ - for (i = 0; i < number; i++) - priv->spy_stat[i].updated = 0; - - orinoco_unlock(priv, &flags); - - srq->length = number; - - return 0; -} - /* Trigger a scan (look for other cells in the vicinity */ static int orinoco_ioctl_setscan(struct net_device *dev, struct iw_request_info *info, @@ -3999,7 +3919,7 @@ static int orinoco_ioctl_setscan(struct net_device *dev, HERMES_HOSTSCAN_SYMBOL_BCAST); break; case FIRMWARE_TYPE_INTERSIL: { - u16 req[3]; + __le16 req[3]; req[0] = cpu_to_le16(0x3fff); /* All channels */ req[1] = cpu_to_le16(0x0001); /* rate 1 Mbps */ @@ -4073,7 +3993,7 @@ static inline int orinoco_translate_scan(struct net_device *dev, case FIRMWARE_TYPE_INTERSIL: offset = 4; if (priv->has_hostscan) { - atom_len = le16_to_cpup((u16 *)scan); + atom_len = le16_to_cpup((__le16 *)scan); /* Sanity check for atom_len */ if (atom_len < sizeof(struct prism2_scan_apinfo)) { printk(KERN_ERR "%s: Invalid atom_len in scan data: %d\n", @@ -4357,8 +4277,10 @@ static const iw_handler orinoco_handler[] = { [SIOCSIWSENS -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setsens, [SIOCGIWSENS -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getsens, [SIOCGIWRANGE -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getiwrange, - [SIOCSIWSPY -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setspy, - [SIOCGIWSPY -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getspy, + [SIOCSIWSPY -SIOCIWFIRST] = (iw_handler) iw_handler_set_spy, + [SIOCGIWSPY -SIOCIWFIRST] = (iw_handler) iw_handler_get_spy, + [SIOCSIWTHRSPY-SIOCIWFIRST] = (iw_handler) iw_handler_set_thrspy, + [SIOCGIWTHRSPY-SIOCIWFIRST] = (iw_handler) iw_handler_get_thrspy, [SIOCSIWAP -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setwap, [SIOCGIWAP -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getwap, [SIOCSIWSCAN -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setscan, diff --git a/drivers/net/wireless/orinoco.h b/drivers/net/wireless/orinoco.h index 2f213a7103fe..7a17bb31fc89 100644 --- a/drivers/net/wireless/orinoco.h +++ b/drivers/net/wireless/orinoco.h @@ -7,12 +7,11 @@ #ifndef _ORINOCO_H #define _ORINOCO_H -#define DRIVER_VERSION "0.15rc2" +#define DRIVER_VERSION "0.15rc3" -#include <linux/types.h> -#include <linux/spinlock.h> #include <linux/netdevice.h> #include <linux/wireless.h> +#include <net/iw_handler.h> #include <linux/version.h> #include "hermes.h" @@ -28,7 +27,7 @@ #define ORINOCO_MAX_KEYS 4 struct orinoco_key { - u16 len; /* always stored as little-endian */ + __le16 len; /* always stored as little-endian */ char data[ORINOCO_MAX_KEY_SIZE]; } __attribute__ ((packed)); @@ -36,14 +35,14 @@ struct header_struct { /* 802.3 */ u8 dest[ETH_ALEN]; u8 src[ETH_ALEN]; - u16 len; + __be16 len; /* 802.2 */ u8 dsap; u8 ssap; u8 ctrl; /* SNAP */ u8 oui[3]; - u16 ethertype; + unsigned short ethertype; } __attribute__ ((packed)); typedef enum { @@ -112,9 +111,8 @@ struct orinoco_private { u16 pm_on, pm_mcast, pm_period, pm_timeout; u16 preamble; #ifdef WIRELESS_SPY - int spy_number; - u_char spy_address[IW_MAX_SPY][ETH_ALEN]; - struct iw_quality spy_stat[IW_MAX_SPY]; + struct iw_spy_data spy_data; /* iwspy support */ + struct iw_public_data wireless_data; #endif /* Configuration dependent variables */ diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c index bedd7f9f23e4..dc1128a00971 100644 --- a/drivers/net/wireless/orinoco_cs.c +++ b/drivers/net/wireless/orinoco_cs.c @@ -14,33 +14,16 @@ #define PFX DRIVER_NAME ": " #include <linux/config.h> -#ifdef __IN_PCMCIA_PACKAGE__ -#include <pcmcia/k_compat.h> -#endif /* __IN_PCMCIA_PACKAGE__ */ - #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> -#include <linux/sched.h> -#include <linux/ptrace.h> -#include <linux/slab.h> -#include <linux/string.h> -#include <linux/ioport.h> -#include <linux/netdevice.h> -#include <linux/if_arp.h> -#include <linux/etherdevice.h> -#include <linux/wireless.h> - +#include <linux/delay.h> #include <pcmcia/cs_types.h> #include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/cisreg.h> #include <pcmcia/ds.h> -#include <asm/uaccess.h> -#include <asm/io.h> -#include <asm/system.h> - #include "orinoco.h" /********************************************************************/ @@ -97,17 +80,8 @@ static dev_link_t *dev_list; /* = NULL */ /* Function prototypes */ /********************************************************************/ -/* device methods */ -static int orinoco_cs_hard_reset(struct orinoco_private *priv); - -/* PCMCIA gumpf */ -static void orinoco_cs_config(dev_link_t * link); -static void orinoco_cs_release(dev_link_t * link); -static int orinoco_cs_event(event_t event, int priority, - event_callback_args_t * args); - -static dev_link_t *orinoco_cs_attach(void); -static void orinoco_cs_detach(dev_link_t *); +static void orinoco_cs_release(dev_link_t *link); +static void orinoco_cs_detach(dev_link_t *link); /********************************************************************/ /* Device methods */ @@ -603,49 +577,85 @@ static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION "Pavel Roskin <proski@gnu.org>, et al)"; static struct pcmcia_device_id orinoco_cs_ids[] = { - PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7300), - PCMCIA_DEVICE_MANF_CARD(0x0138, 0x0002), - PCMCIA_DEVICE_MANF_CARD(0x0156, 0x0002), - PCMCIA_DEVICE_MANF_CARD(0x01eb, 0x080a), - PCMCIA_DEVICE_MANF_CARD(0x0261, 0x0002), - PCMCIA_DEVICE_MANF_CARD(0x0268, 0x0001), - PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0305), - PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1613), - PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0002), - PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0673), - PCMCIA_DEVICE_MANF_CARD(0x02aa, 0x0002), - PCMCIA_DEVICE_MANF_CARD(0x02ac, 0x0002), - PCMCIA_DEVICE_MANF_CARD(0x14ea, 0xb001), - PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x7300), - PCMCIA_DEVICE_MANF_CARD(0x9005, 0x0021), - PCMCIA_DEVICE_MANF_CARD(0xc250, 0x0002), - PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0002), - PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0005), + PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7100), /* SonicWALL Long Range Wireless Card */ + PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7300), /* Sohoware NCP110, Philips 802.11b */ + PCMCIA_DEVICE_MANF_CARD(0x0089, 0x0002), /* AnyPoint(TM) Wireless II PC Card */ + PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0777), /* 3Com AirConnect PCI 777A */ + PCMCIA_DEVICE_MANF_CARD(0x0126, 0x8000), /* PROXIM RangeLAN-DS/LAN PC CARD */ + PCMCIA_DEVICE_MANF_CARD(0x0138, 0x0002), /* Compaq WL100 11 Mbps Wireless Adapter */ + PCMCIA_DEVICE_MANF_CARD(0x0156, 0x0002), /* Lucent Orinoco and old Intersil */ + PCMCIA_DEVICE_MANF_CARD(0x016b, 0x0001), /* Ericsson WLAN Card C11 */ + PCMCIA_DEVICE_MANF_CARD(0x01eb, 0x080a), /* Nortel Networks eMobility 802.11 Wireless Adapter */ + PCMCIA_DEVICE_MANF_CARD(0x01ff, 0x0008), /* Intermec MobileLAN 11Mbps 802.11b WLAN Card */ + PCMCIA_DEVICE_MANF_CARD(0x0250, 0x0002), /* Samsung SWL2000-N 11Mb/s WLAN Card */ + PCMCIA_DEVICE_MANF_CARD(0x0261, 0x0002), /* AirWay 802.11 Adapter (PCMCIA) */ + PCMCIA_DEVICE_MANF_CARD(0x0268, 0x0001), /* ARtem Onair */ + PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0305), /* Buffalo WLI-PCM-S11 */ + PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1612), /* Linksys WPC11 Version 2.5 */ + PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1613), /* Linksys WPC11 Version 3 */ + PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0002), /* Compaq HNW-100 11 Mbps Wireless Adapter */ + PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0673), /* Linksys WCF12 Wireless CompactFlash Card */ + PCMCIA_DEVICE_MANF_CARD(0x02aa, 0x0002), /* ASUS SpaceLink WL-100 */ + PCMCIA_DEVICE_MANF_CARD(0x02ac, 0x0002), /* SpeedStream SS1021 Wireless Adapter */ + PCMCIA_DEVICE_MANF_CARD(0x14ea, 0xb001), /* PLANEX RoadLannerWave GW-NS11H */ + PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x7300), /* Airvast WN-100 */ + PCMCIA_DEVICE_MANF_CARD(0x9005, 0x0021), /* Adaptec Ultra Wireless ANW-8030 */ + PCMCIA_DEVICE_MANF_CARD(0xc001, 0x0008), /* CONTEC FLEXSCAN/FX-DDS110-PCC */ + PCMCIA_DEVICE_MANF_CARD(0xc250, 0x0002), /* Conceptronic CON11Cpro, EMTAC A2424i */ + PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0002), /* Safeway 802.11b, ZCOMAX AirRunner/XI-300 */ + PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0005), /* D-Link DCF660, Sandisk Connect SDWCFB-000 */ + PCMCIA_DEVICE_PROD_ID12(" ", "IEEE 802.11 Wireless LAN/PC Card", 0x3b6e20c8, 0xefccafe9), PCMCIA_DEVICE_PROD_ID12("3Com", "3CRWE737A AirConnect Wireless LAN PC Card", 0x41240e5b, 0x56010af3), - PCMCIA_DEVICE_PROD_ID123("Instant Wireless ", " Network PC CARD", "Version 01.02", 0x11d901af, 0x6e9bd926, 0x4b74baa0), PCMCIA_DEVICE_PROD_ID12("ACTIONTEC", "PRISM Wireless LAN PC Card", 0x393089da, 0xa71e69d5), + PCMCIA_DEVICE_PROD_ID12("Addtron", "AWP-100 Wireless PCMCIA", 0xe6ec52ce, 0x08649af2), + PCMCIA_DEVICE_PROD_ID123("AIRVAST", "IEEE 802.11b Wireless PCMCIA Card", "HFA3863", 0xea569531, 0x4bcb9645, 0x355cb092), + PCMCIA_DEVICE_PROD_ID12("Allied Telesyn", "AT-WCL452 Wireless PCMCIA Radio", 0x5cd01705, 0x4271660f), + PCMCIA_DEVICE_PROD_ID12("ASUS", "802_11b_PC_CARD_25", 0x78fc06ee, 0xdb9aa842), + PCMCIA_DEVICE_PROD_ID12("ASUS", "802_11B_CF_CARD_25", 0x78fc06ee, 0x45a50c1e), PCMCIA_DEVICE_PROD_ID12("Avaya Communication", "Avaya Wireless PC Card", 0xd8a43b78, 0x0d341169), + PCMCIA_DEVICE_PROD_ID12("BENQ", "AWL100 PCMCIA ADAPTER", 0x35dadc74, 0x01f7fedb), PCMCIA_DEVICE_PROD_ID12("BUFFALO", "WLI-PCM-L11G", 0x2decece3, 0xf57ca4b3), + PCMCIA_DEVICE_PROD_ID12("BUFFALO", "WLI-CF-S11G", 0x2decece3, 0x82067c18), PCMCIA_DEVICE_PROD_ID12("Cabletron", "RoamAbout 802.11 DS", 0x32d445f5, 0xedeffd90), + PCMCIA_DEVICE_PROD_ID12("Compaq", "WL200_11Mbps_Wireless_PCI_Card", 0x54f7c49c, 0x15a75e5b), + PCMCIA_DEVICE_PROD_ID123("corega", "WL PCCL-11", "ISL37300P", 0x0a21501a, 0x59868926, 0xc9049a39), PCMCIA_DEVICE_PROD_ID12("corega K.K.", "Wireless LAN PCC-11", 0x5261440f, 0xa6405584), PCMCIA_DEVICE_PROD_ID12("corega K.K.", "Wireless LAN PCCA-11", 0x5261440f, 0xdf6115f9), PCMCIA_DEVICE_PROD_ID12("corega_K.K.", "Wireless_LAN_PCCB-11", 0x29e33311, 0xee7a27ae), PCMCIA_DEVICE_PROD_ID12("D", "Link DRC-650 11Mbps WLAN Card", 0x71b18589, 0xf144e3ac), PCMCIA_DEVICE_PROD_ID12("D", "Link DWL-650 11Mbps WLAN Card", 0x71b18589, 0xb6f1b0ab), + PCMCIA_DEVICE_PROD_ID12("D-Link Corporation", "D-Link DWL-650H 11Mbps WLAN Adapter", 0xef544d24, 0xcd8ea916), + PCMCIA_DEVICE_PROD_ID12("Digital Data Communications", "WPC-0100", 0xfdd73470, 0xe0b6f146), PCMCIA_DEVICE_PROD_ID12("ELSA", "AirLancer MC-11", 0x4507a33a, 0xef54f0e3), PCMCIA_DEVICE_PROD_ID12("HyperLink", "Wireless PC Card 11Mbps", 0x56cc3f1a, 0x0bcf220c), + PCMCIA_DEVICE_PROD_ID123("Instant Wireless ", " Network PC CARD", "Version 01.02", 0x11d901af, 0x6e9bd926, 0x4b74baa0), + PCMCIA_DEVICE_PROD_ID12("Intel", "PRO/Wireless 2011 LAN PC Card", 0x816cc815, 0x07f58077), PCMCIA_DEVICE_PROD_ID12("INTERSIL", "HFA384x/IEEE", 0x74c5e40d, 0xdb472a18), + PCMCIA_DEVICE_PROD_ID12("INTERSIL", "I-GATE 11M PC Card / PC Card plus", 0x74c5e40d, 0x8304ff77), + PCMCIA_DEVICE_PROD_ID12("Intersil", "PRISM 2_5 PCMCIA ADAPTER", 0x4b801a17, 0x6345a0bf), + PCMCIA_DEVICE_PROD_ID123("Intersil", "PRISM Freedom PCMCIA Adapter", "ISL37100P", 0x4b801a17, 0xf222ec2d, 0x630d52b2), + PCMCIA_DEVICE_PROD_ID12("LeArtery", "SYNCBYAIR 11Mbps Wireless LAN PC Card", 0x7e3b326a, 0x49893e92), + PCMCIA_DEVICE_PROD_ID12("Linksys", "Wireless CompactFlash Card", 0x0733cc81, 0x0c52f395), PCMCIA_DEVICE_PROD_ID12("Lucent Technologies", "WaveLAN/IEEE", 0x23eb9949, 0xc562e72a), PCMCIA_DEVICE_PROD_ID12("MELCO", "WLI-PCM-L11", 0x481e0094, 0x7360e410), PCMCIA_DEVICE_PROD_ID12("MELCO", "WLI-PCM-L11G", 0x481e0094, 0xf57ca4b3), PCMCIA_DEVICE_PROD_ID12("Microsoft", "Wireless Notebook Adapter MN-520", 0x5961bf85, 0x6eec8c01), PCMCIA_DEVICE_PROD_ID12("NCR", "WaveLAN/IEEE", 0x24358cd4, 0xc562e72a), + PCMCIA_DEVICE_PROD_ID12("NETGEAR MA401 Wireless PC", "Card", 0xa37434e9, 0x9762e8f1), PCMCIA_DEVICE_PROD_ID12("NETGEAR MA401RA Wireless PC", "Card", 0x0306467f, 0x9762e8f1), + PCMCIA_DEVICE_PROD_ID12("Nortel Networks", "emobility 802.11 Wireless LAN PC Card", 0x2d617ea0, 0x88cd5767), + PCMCIA_DEVICE_PROD_ID12("OEM", "PRISM2 IEEE 802.11 PC-Card", 0xfea54c90, 0x48f2bdd6), + PCMCIA_DEVICE_PROD_ID12("OTC", "Wireless AirEZY 2411-PCC WLAN Card", 0x4ac44287, 0x235a6bed), + PCMCIA_DEVICE_PROD_ID123("PCMCIA", "11M WLAN Card v2.5", "ISL37300P", 0x281f1c5d, 0x6e440487, 0xc9049a39), PCMCIA_DEVICE_PROD_ID12("PLANEX", "GeoWave/GW-CF110", 0x209f40ab, 0xd9715264), + PCMCIA_DEVICE_PROD_ID12("PLANEX", "GeoWave/GW-NS110", 0x209f40ab, 0x46263178), PCMCIA_DEVICE_PROD_ID12("PROXIM", "LAN PC CARD HARMONY 80211B", 0xc6536a5e, 0x090c3cd9), PCMCIA_DEVICE_PROD_ID12("PROXIM", "LAN PCI CARD HARMONY 80211B", 0xc6536a5e, 0x9f494e26), PCMCIA_DEVICE_PROD_ID12("SAMSUNG", "11Mbps WLAN Card", 0x43d74cb4, 0x579bd91b), - PCMCIA_DEVICE_PROD_ID1("Symbol Technologies", 0x3f02b4d6), + PCMCIA_DEVICE_PROD_ID12("SMC", "SMC2632W", 0xc4f8b18b, 0x474a1f2a), + PCMCIA_DEVICE_PROD_ID12("Symbol Technologies", "LA4111 Spectrum24 Wireless LAN PC Card", 0x3f02b4d6, 0x3663cb0e), + PCMCIA_DEVICE_PROD_ID123("The Linksys Group, Inc.", "Instant Wireless Network PC Card", "ISL37300P", 0xa5f472c2, 0x590eb502, 0xc9049a39), + PCMCIA_DEVICE_PROD_ID12("ZoomAir 11Mbps High", "Rate wireless Networking", 0x273fe3db, 0x32a1eaee), PCMCIA_DEVICE_NULL, }; MODULE_DEVICE_TABLE(pcmcia, orinoco_cs_ids); @@ -656,8 +666,8 @@ static struct pcmcia_driver orinoco_driver = { .name = DRIVER_NAME, }, .attach = orinoco_cs_attach, - .event = orinoco_cs_event, .detach = orinoco_cs_detach, + .event = orinoco_cs_event, .id_table = orinoco_cs_ids, }; diff --git a/drivers/net/wireless/orinoco_nortel.c b/drivers/net/wireless/orinoco_nortel.c index 86fa58e5cfac..d8afd51ff8a5 100644 --- a/drivers/net/wireless/orinoco_nortel.c +++ b/drivers/net/wireless/orinoco_nortel.c @@ -40,29 +40,13 @@ #define PFX DRIVER_NAME ": " #include <linux/config.h> - #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> -#include <linux/sched.h> -#include <linux/ptrace.h> -#include <linux/slab.h> -#include <linux/string.h> -#include <linux/timer.h> -#include <linux/ioport.h> -#include <asm/uaccess.h> -#include <asm/io.h> -#include <asm/system.h> -#include <linux/netdevice.h> -#include <linux/if_arp.h> -#include <linux/etherdevice.h> -#include <linux/list.h> +#include <linux/delay.h> #include <linux/pci.h> -#include <linux/fcntl.h> - #include <pcmcia/cisreg.h> -#include "hermes.h" #include "orinoco.h" #define COR_OFFSET (0xe0) /* COR attribute offset of Prism2 PC card */ @@ -108,7 +92,7 @@ static int nortel_pci_cor_reset(struct orinoco_private *priv) return 0; } -int nortel_pci_hw_init(struct nortel_pci_card *card) +static int nortel_pci_hw_init(struct nortel_pci_card *card) { int i; u32 reg; diff --git a/drivers/net/wireless/orinoco_pci.c b/drivers/net/wireless/orinoco_pci.c index 42e03438291b..5362c214fc8e 100644 --- a/drivers/net/wireless/orinoco_pci.c +++ b/drivers/net/wireless/orinoco_pci.c @@ -93,28 +93,12 @@ #define PFX DRIVER_NAME ": " #include <linux/config.h> - #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> -#include <linux/sched.h> -#include <linux/ptrace.h> -#include <linux/slab.h> -#include <linux/string.h> -#include <linux/timer.h> -#include <linux/ioport.h> -#include <linux/netdevice.h> -#include <linux/if_arp.h> -#include <linux/etherdevice.h> -#include <linux/list.h> +#include <linux/delay.h> #include <linux/pci.h> -#include <linux/fcntl.h> - -#include <asm/uaccess.h> -#include <asm/io.h> -#include <asm/system.h> -#include "hermes.h" #include "orinoco.h" /* All the magic there is from wlan-ng */ diff --git a/drivers/net/wireless/orinoco_plx.c b/drivers/net/wireless/orinoco_plx.c index 7ab05b89fb3f..210e73776545 100644 --- a/drivers/net/wireless/orinoco_plx.c +++ b/drivers/net/wireless/orinoco_plx.c @@ -117,29 +117,13 @@ #define PFX DRIVER_NAME ": " #include <linux/config.h> - #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> -#include <linux/sched.h> -#include <linux/ptrace.h> -#include <linux/slab.h> -#include <linux/string.h> -#include <linux/timer.h> -#include <linux/ioport.h> -#include <asm/uaccess.h> -#include <asm/io.h> -#include <asm/system.h> -#include <linux/netdevice.h> -#include <linux/if_arp.h> -#include <linux/etherdevice.h> -#include <linux/list.h> +#include <linux/delay.h> #include <linux/pci.h> -#include <linux/fcntl.h> - #include <pcmcia/cisreg.h> -#include "hermes.h" #include "orinoco.h" #define COR_OFFSET (0x3e0) /* COR attribute offset of Prism2 PC card */ diff --git a/drivers/net/wireless/orinoco_tmd.c b/drivers/net/wireless/orinoco_tmd.c index 85893f42445b..5e68b7026186 100644 --- a/drivers/net/wireless/orinoco_tmd.c +++ b/drivers/net/wireless/orinoco_tmd.c @@ -53,29 +53,13 @@ #define PFX DRIVER_NAME ": " #include <linux/config.h> - #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> -#include <linux/sched.h> -#include <linux/ptrace.h> -#include <linux/slab.h> -#include <linux/string.h> -#include <linux/timer.h> -#include <linux/ioport.h> -#include <asm/uaccess.h> -#include <asm/io.h> -#include <asm/system.h> -#include <linux/netdevice.h> -#include <linux/if_arp.h> -#include <linux/etherdevice.h> -#include <linux/list.h> +#include <linux/delay.h> #include <linux/pci.h> -#include <linux/fcntl.h> - #include <pcmcia/cisreg.h> -#include "hermes.h" #include "orinoco.h" #define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */ diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c index 9a8790e3580c..5c1a1adf1ff8 100644 --- a/drivers/net/wireless/prism54/isl_ioctl.c +++ b/drivers/net/wireless/prism54/isl_ioctl.c @@ -462,14 +462,12 @@ prism54_get_range(struct net_device *ndev, struct iw_request_info *info, /* txpower is supported in dBm's */ range->txpower_capa = IW_TXPOW_DBM; -#if WIRELESS_EXT > 16 /* Event capability (kernel + driver) */ range->event_capa[0] = (IW_EVENT_CAPA_K_0 | IW_EVENT_CAPA_MASK(SIOCGIWTHRSPY) | IW_EVENT_CAPA_MASK(SIOCGIWAP)); range->event_capa[1] = IW_EVENT_CAPA_K_1; range->event_capa[4] = IW_EVENT_CAPA_MASK(IWEVCUSTOM); -#endif /* WIRELESS_EXT > 16 */ if (islpci_get_state(priv) < PRV_STATE_INIT) return 0; @@ -693,14 +691,13 @@ prism54_get_scan(struct net_device *ndev, struct iw_request_info *info, extra + dwrq->length, &(bsslist->bsslist[i]), noise); -#if WIRELESS_EXT > 16 + /* Check if there is space for one more entry */ if((extra + dwrq->length - current_ev) <= IW_EV_ADDR_LEN) { /* Ask user space to try again with a bigger buffer */ rvalue = -E2BIG; break; } -#endif /* WIRELESS_EXT > 16 */ } kfree(bsslist); @@ -2727,12 +2724,7 @@ const struct iw_handler_def prism54_handler_def = { .standard = (iw_handler *) prism54_handler, .private = (iw_handler *) prism54_private_handler, .private_args = (struct iw_priv_args *) prism54_private_args, -#if WIRELESS_EXT > 16 .get_wireless_stats = prism54_get_wireless_stats, -#endif /* WIRELESS_EXT > 16 */ -#if WIRELESS_EXT == 16 - .spy_offset = offsetof(islpci_private, spy_data), -#endif /* WIRELESS_EXT == 16 */ }; /* For wpa_supplicant */ diff --git a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c index 6f13d4a8e2d3..78bdb359835e 100644 --- a/drivers/net/wireless/prism54/islpci_dev.c +++ b/drivers/net/wireless/prism54/islpci_dev.c @@ -439,8 +439,7 @@ prism54_bring_down(islpci_private *priv) wmb(); /* wait a while for the device to reset */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(50*HZ/1000); + schedule_timeout_uninterruptible(msecs_to_jiffies(50)); return 0; } @@ -491,8 +490,7 @@ islpci_reset_if(islpci_private *priv) /* The software reset acknowledge needs about 220 msec here. * Be conservative and wait for up to one second. */ - set_current_state(TASK_UNINTERRUPTIBLE); - remaining = schedule_timeout(HZ); + remaining = schedule_timeout_uninterruptible(HZ); if(remaining > 0) { result = 0; @@ -756,8 +754,7 @@ islpci_free_memory(islpci_private *priv) pci_unmap_single(priv->pdev, buf->pci_addr, buf->size, PCI_DMA_FROMDEVICE); buf->pci_addr = 0; - if (buf->mem) - kfree(buf->mem); + kfree(buf->mem); buf->size = 0; buf->mem = NULL; } @@ -839,13 +836,9 @@ islpci_setup(struct pci_dev *pdev) priv->ndev->type = (priv->iw_mode == IW_MODE_MONITOR) ? priv->monitor_type : ARPHRD_ETHER; -#if WIRELESS_EXT > 16 /* Add pointers to enable iwspy support. */ priv->wireless_data.spy_data = &priv->spy_data; ndev->wireless_data = &priv->wireless_data; -#else /* WIRELESS_EXT > 16 */ - ndev->get_wireless_stats = &prism54_get_wireless_stats; -#endif /* WIRELESS_EXT > 16 */ /* save the start and end address of the PCI memory area */ ndev->mem_start = (unsigned long) priv->device_base; diff --git a/drivers/net/wireless/prism54/islpci_dev.h b/drivers/net/wireless/prism54/islpci_dev.h index 32a1019f1b36..efbed4397951 100644 --- a/drivers/net/wireless/prism54/islpci_dev.h +++ b/drivers/net/wireless/prism54/islpci_dev.h @@ -100,9 +100,7 @@ typedef struct { struct iw_spy_data spy_data; /* iwspy support */ -#if WIRELESS_EXT > 16 struct iw_public_data wireless_data; -#endif /* WIRELESS_EXT > 16 */ int monitor_type; /* ARPHRD_IEEE80211 or ARPHRD_IEEE80211_PRISM */ diff --git a/drivers/net/wireless/prism54/islpci_eth.c b/drivers/net/wireless/prism54/islpci_eth.c index 5952e9960499..3b49efa37ee5 100644 --- a/drivers/net/wireless/prism54/islpci_eth.c +++ b/drivers/net/wireless/prism54/islpci_eth.c @@ -97,12 +97,6 @@ islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev) /* lock the driver code */ spin_lock_irqsave(&priv->slock, flags); - /* determine the amount of fragments needed to store the frame */ - - frame_size = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len; - if (init_wds) - frame_size += 6; - /* check whether the destination queue has enough fragments for the frame */ curr_frag = le32_to_cpu(cb->driver_curr_frag[ISL38XX_CB_TX_DATA_LQ]); if (unlikely(curr_frag - priv->free_data_tx >= ISL38XX_CB_TX_QSIZE)) { @@ -213,6 +207,7 @@ islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev) /* store the skb address for future freeing */ priv->data_low_tx[index] = skb; /* set the proper fragment start address and size information */ + frame_size = skb->len; fragment->size = cpu_to_le16(frame_size); fragment->flags = cpu_to_le16(0); /* set to 1 if more fragments */ fragment->address = cpu_to_le32(pci_map_address); @@ -246,12 +241,10 @@ islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev) return 0; drop_free: - /* free the skbuf structure before aborting */ - dev_kfree_skb(skb); - skb = NULL; - priv->statistics.tx_dropped++; spin_unlock_irqrestore(&priv->slock, flags); + dev_kfree_skb(skb); + skb = NULL; return err; } diff --git a/drivers/net/wireless/prism54/islpci_mgt.c b/drivers/net/wireless/prism54/islpci_mgt.c index b6f2e5a223be..6a60c5970cb5 100644 --- a/drivers/net/wireless/prism54/islpci_mgt.c +++ b/drivers/net/wireless/prism54/islpci_mgt.c @@ -137,7 +137,7 @@ islpci_mgmt_rx_fill(struct net_device *ndev) PCI_DMA_FROMDEVICE); if (!buf->pci_addr) { printk(KERN_WARNING - "Failed to make memory DMA'able\n."); + "Failed to make memory DMA'able.\n"); return -ENOMEM; } } @@ -455,7 +455,7 @@ islpci_mgt_transaction(struct net_device *ndev, struct islpci_mgmtframe **recvframe) { islpci_private *priv = netdev_priv(ndev); - const long wait_cycle_jiffies = (ISL38XX_WAIT_CYCLE * 10 * HZ) / 1000; + const long wait_cycle_jiffies = msecs_to_jiffies(ISL38XX_WAIT_CYCLE * 10); long timeout_left = ISL38XX_MAX_WAIT_CYCLES * wait_cycle_jiffies; int err; DEFINE_WAIT(wait); @@ -475,8 +475,7 @@ islpci_mgt_transaction(struct net_device *ndev, int timeleft; struct islpci_mgmtframe *frame; - set_current_state(TASK_UNINTERRUPTIBLE); - timeleft = schedule_timeout(wait_cycle_jiffies); + timeleft = schedule_timeout_uninterruptible(wait_cycle_jiffies); frame = xchg(&priv->mgmt_received, NULL); if (frame) { if (frame->header->oid == oid) { diff --git a/drivers/net/wireless/prism54/oid_mgt.c b/drivers/net/wireless/prism54/oid_mgt.c index 12123e24b113..eea2f04c8c6d 100644 --- a/drivers/net/wireless/prism54/oid_mgt.c +++ b/drivers/net/wireless/prism54/oid_mgt.c @@ -268,11 +268,10 @@ mgt_clean(islpci_private *priv) if (!priv->mib) return; - for (i = 0; i < OID_NUM_LAST; i++) - if (priv->mib[i]) { - kfree(priv->mib[i]); - priv->mib[i] = NULL; - } + for (i = 0; i < OID_NUM_LAST; i++) { + kfree(priv->mib[i]); + priv->mib[i] = NULL; + } kfree(priv->mib); priv->mib = NULL; } diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index e9c5ea0f5535..70fd6fd8feb9 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -1649,28 +1649,28 @@ static iw_stats * ray_get_wireless_stats(struct net_device * dev) */ static const iw_handler ray_handler[] = { - [SIOCSIWCOMMIT-SIOCIWFIRST] (iw_handler) ray_commit, - [SIOCGIWNAME -SIOCIWFIRST] (iw_handler) ray_get_name, - [SIOCSIWFREQ -SIOCIWFIRST] (iw_handler) ray_set_freq, - [SIOCGIWFREQ -SIOCIWFIRST] (iw_handler) ray_get_freq, - [SIOCSIWMODE -SIOCIWFIRST] (iw_handler) ray_set_mode, - [SIOCGIWMODE -SIOCIWFIRST] (iw_handler) ray_get_mode, - [SIOCGIWRANGE -SIOCIWFIRST] (iw_handler) ray_get_range, + [SIOCSIWCOMMIT-SIOCIWFIRST] = (iw_handler) ray_commit, + [SIOCGIWNAME -SIOCIWFIRST] = (iw_handler) ray_get_name, + [SIOCSIWFREQ -SIOCIWFIRST] = (iw_handler) ray_set_freq, + [SIOCGIWFREQ -SIOCIWFIRST] = (iw_handler) ray_get_freq, + [SIOCSIWMODE -SIOCIWFIRST] = (iw_handler) ray_set_mode, + [SIOCGIWMODE -SIOCIWFIRST] = (iw_handler) ray_get_mode, + [SIOCGIWRANGE -SIOCIWFIRST] = (iw_handler) ray_get_range, #ifdef WIRELESS_SPY - [SIOCSIWSPY -SIOCIWFIRST] (iw_handler) iw_handler_set_spy, - [SIOCGIWSPY -SIOCIWFIRST] (iw_handler) iw_handler_get_spy, - [SIOCSIWTHRSPY-SIOCIWFIRST] (iw_handler) iw_handler_set_thrspy, - [SIOCGIWTHRSPY-SIOCIWFIRST] (iw_handler) iw_handler_get_thrspy, + [SIOCSIWSPY -SIOCIWFIRST] = (iw_handler) iw_handler_set_spy, + [SIOCGIWSPY -SIOCIWFIRST] = (iw_handler) iw_handler_get_spy, + [SIOCSIWTHRSPY-SIOCIWFIRST] = (iw_handler) iw_handler_set_thrspy, + [SIOCGIWTHRSPY-SIOCIWFIRST] = (iw_handler) iw_handler_get_thrspy, #endif /* WIRELESS_SPY */ - [SIOCGIWAP -SIOCIWFIRST] (iw_handler) ray_get_wap, - [SIOCSIWESSID -SIOCIWFIRST] (iw_handler) ray_set_essid, - [SIOCGIWESSID -SIOCIWFIRST] (iw_handler) ray_get_essid, - [SIOCSIWRATE -SIOCIWFIRST] (iw_handler) ray_set_rate, - [SIOCGIWRATE -SIOCIWFIRST] (iw_handler) ray_get_rate, - [SIOCSIWRTS -SIOCIWFIRST] (iw_handler) ray_set_rts, - [SIOCGIWRTS -SIOCIWFIRST] (iw_handler) ray_get_rts, - [SIOCSIWFRAG -SIOCIWFIRST] (iw_handler) ray_set_frag, - [SIOCGIWFRAG -SIOCIWFIRST] (iw_handler) ray_get_frag, + [SIOCGIWAP -SIOCIWFIRST] = (iw_handler) ray_get_wap, + [SIOCSIWESSID -SIOCIWFIRST] = (iw_handler) ray_set_essid, + [SIOCGIWESSID -SIOCIWFIRST] = (iw_handler) ray_get_essid, + [SIOCSIWRATE -SIOCIWFIRST] = (iw_handler) ray_set_rate, + [SIOCGIWRATE -SIOCIWFIRST] = (iw_handler) ray_get_rate, + [SIOCSIWRTS -SIOCIWFIRST] = (iw_handler) ray_set_rts, + [SIOCGIWRTS -SIOCIWFIRST] = (iw_handler) ray_get_rts, + [SIOCSIWFRAG -SIOCIWFIRST] = (iw_handler) ray_set_frag, + [SIOCGIWFRAG -SIOCIWFIRST] = (iw_handler) ray_get_frag, }; #define SIOCSIPFRAMING SIOCIWFIRSTPRIV /* Set framing mode */ @@ -1678,9 +1678,9 @@ static const iw_handler ray_handler[] = { #define SIOCGIPCOUNTRY SIOCIWFIRSTPRIV + 3 /* Get country code */ static const iw_handler ray_private_handler[] = { - [0] (iw_handler) ray_set_framing, - [1] (iw_handler) ray_get_framing, - [3] (iw_handler) ray_get_country, + [0] = (iw_handler) ray_set_framing, + [1] = (iw_handler) ray_get_framing, + [3] = (iw_handler) ray_get_country, }; static const struct iw_priv_args ray_private_args[] = { diff --git a/drivers/net/wireless/spectrum_cs.c b/drivers/net/wireless/spectrum_cs.c index 39c6cdf7f3f7..b1bbc8e8e91f 100644 --- a/drivers/net/wireless/spectrum_cs.c +++ b/drivers/net/wireless/spectrum_cs.c @@ -22,58 +22,23 @@ #define PFX DRIVER_NAME ": " #include <linux/config.h> -#ifdef __IN_PCMCIA_PACKAGE__ -#include <pcmcia/k_compat.h> -#endif /* __IN_PCMCIA_PACKAGE__ */ - #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> -#include <linux/sched.h> -#include <linux/ptrace.h> -#include <linux/slab.h> -#include <linux/string.h> -#include <linux/ioport.h> -#include <linux/netdevice.h> -#include <linux/if_arp.h> -#include <linux/etherdevice.h> -#include <linux/wireless.h> - +#include <linux/delay.h> +#include <linux/firmware.h> #include <pcmcia/cs_types.h> #include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/cisreg.h> #include <pcmcia/ds.h> -#include <asm/uaccess.h> -#include <asm/io.h> -#include <asm/system.h> - #include "orinoco.h" -/* - * If SPECTRUM_FW_INCLUDED is defined, the firmware is hardcoded into - * the driver. Use get_symbol_fw script to generate spectrum_fw.h and - * copy it to the same directory as spectrum_cs.c. - * - * If SPECTRUM_FW_INCLUDED is not defined, the firmware is loaded at the - * runtime using hotplug. Use the same get_symbol_fw script to generate - * files symbol_sp24t_prim_fw symbol_sp24t_sec_fw, copy them to the - * hotplug firmware directory (typically /usr/lib/hotplug/firmware) and - * make sure that you have hotplug installed and enabled in the kernel. - */ -/* #define SPECTRUM_FW_INCLUDED 1 */ - -#ifdef SPECTRUM_FW_INCLUDED -/* Header with the firmware */ -#include "spectrum_fw.h" -#else /* !SPECTRUM_FW_INCLUDED */ -#include <linux/firmware.h> static unsigned char *primsym; static unsigned char *secsym; static const char primary_fw_name[] = "symbol_sp24t_prim_fw"; static const char secondary_fw_name[] = "symbol_sp24t_sec_fw"; -#endif /* !SPECTRUM_FW_INCLUDED */ /********************************************************************/ /* Module stuff */ @@ -124,17 +89,8 @@ static dev_link_t *dev_list; /* = NULL */ /* Function prototypes */ /********************************************************************/ -/* device methods */ -static int spectrum_cs_hard_reset(struct orinoco_private *priv); - -/* PCMCIA gumpf */ -static void spectrum_cs_config(dev_link_t * link); -static void spectrum_cs_release(dev_link_t * link); -static int spectrum_cs_event(event_t event, int priority, - event_callback_args_t * args); - -static dev_link_t *spectrum_cs_attach(void); -static void spectrum_cs_detach(dev_link_t *); +static void spectrum_cs_release(dev_link_t *link); +static void spectrum_cs_detach(dev_link_t *link); /********************************************************************/ /* Firmware downloader */ @@ -182,8 +138,8 @@ static void spectrum_cs_detach(dev_link_t *); * Each block has the following structure. */ struct dblock { - u32 _addr; /* adapter address where to write the block */ - u16 _len; /* length of the data only, in bytes */ + __le32 _addr; /* adapter address where to write the block */ + __le16 _len; /* length of the data only, in bytes */ char data[0]; /* data to be written */ } __attribute__ ((packed)); @@ -193,9 +149,9 @@ struct dblock { * items with matching ID should be written. */ struct pdr { - u32 _id; /* record ID */ - u32 _addr; /* adapter address where to write the data */ - u32 _len; /* expected length of the data, in bytes */ + __le32 _id; /* record ID */ + __le32 _addr; /* adapter address where to write the data */ + __le32 _len; /* expected length of the data, in bytes */ char next[0]; /* next PDR starts here */ } __attribute__ ((packed)); @@ -206,8 +162,8 @@ struct pdr { * be plugged into the secondary firmware. */ struct pdi { - u16 _len; /* length of ID and data, in words */ - u16 _id; /* record ID */ + __le16 _len; /* length of ID and data, in words */ + __le16 _id; /* record ID */ char data[0]; /* plug data */ } __attribute__ ((packed));; @@ -414,7 +370,7 @@ spectrum_plug_pdi(hermes_t *hw, struct pdr *first_pdr, struct pdi *pdi) /* Read PDA from the adapter */ static int -spectrum_read_pda(hermes_t *hw, u16 *pda, int pda_len) +spectrum_read_pda(hermes_t *hw, __le16 *pda, int pda_len) { int ret; int pda_size; @@ -445,7 +401,7 @@ spectrum_read_pda(hermes_t *hw, u16 *pda, int pda_len) /* Parse PDA and write the records into the adapter */ static int spectrum_apply_pda(hermes_t *hw, const struct dblock *first_block, - u16 *pda) + __le16 *pda) { int ret; struct pdi *pdi; @@ -511,7 +467,7 @@ spectrum_dl_image(hermes_t *hw, dev_link_t *link, const struct dblock *first_block; /* Plug Data Area (PDA) */ - u16 pda[PDA_WORDS]; + __le16 pda[PDA_WORDS]; /* Binary block begins after the 0x1A marker */ ptr = image; @@ -571,8 +527,6 @@ spectrum_dl_firmware(hermes_t *hw, dev_link_t *link) { int ret; client_handle_t handle = link->handle; - -#ifndef SPECTRUM_FW_INCLUDED const struct firmware *fw_entry; if (request_firmware(&fw_entry, primary_fw_name, @@ -592,7 +546,6 @@ spectrum_dl_firmware(hermes_t *hw, dev_link_t *link) secondary_fw_name); return -ENOENT; } -#endif /* Load primary firmware */ ret = spectrum_dl_image(hw, link, primsym); @@ -1085,7 +1038,7 @@ static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION static struct pcmcia_device_id spectrum_cs_ids[] = { PCMCIA_DEVICE_MANF_CARD(0x026c, 0x0001), /* Symbol Spectrum24 LA4100 */ PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0001), /* Socket Communications CF */ - PCMCIA_DEVICE_MANF_CARD(0x0089, 0x0001), /* Intel PRO/Wireless 2011B */ + PCMCIA_DEVICE_PROD_ID12("Intel", "PRO/Wireless LAN PC Card", 0x816cc815, 0x6fbf459a), /* 2011B, not 2011 */ PCMCIA_DEVICE_NULL, }; MODULE_DEVICE_TABLE(pcmcia, spectrum_cs_ids); @@ -1096,8 +1049,8 @@ static struct pcmcia_driver orinoco_driver = { .name = DRIVER_NAME, }, .attach = spectrum_cs_attach, - .event = spectrum_cs_event, .detach = spectrum_cs_detach, + .event = spectrum_cs_event, .id_table = spectrum_cs_ids, }; diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c index 7bc7fc823128..d25264ba0c0e 100644 --- a/drivers/net/wireless/strip.c +++ b/drivers/net/wireless/strip.c @@ -860,12 +860,9 @@ static int allocate_buffers(struct strip *strip_info, int mtu) strip_info->mtu = dev->mtu = mtu; return (1); } - if (r) - kfree(r); - if (s) - kfree(s); - if (t) - kfree(t); + kfree(r); + kfree(s); + kfree(t); return (0); } @@ -922,13 +919,9 @@ static int strip_change_mtu(struct net_device *dev, int new_mtu) printk(KERN_NOTICE "%s: strip MTU changed fom %d to %d.\n", strip_info->dev->name, old_mtu, strip_info->mtu); - if (orbuff) - kfree(orbuff); - if (osbuff) - kfree(osbuff); - if (otbuff) - kfree(otbuff); - + kfree(orbuff); + kfree(osbuff); + kfree(otbuff); return 0; } @@ -2498,18 +2491,13 @@ static int strip_close_low(struct net_device *dev) /* * Free all STRIP frame buffers. */ - if (strip_info->rx_buff) { - kfree(strip_info->rx_buff); - strip_info->rx_buff = NULL; - } - if (strip_info->sx_buff) { - kfree(strip_info->sx_buff); - strip_info->sx_buff = NULL; - } - if (strip_info->tx_buff) { - kfree(strip_info->tx_buff); - strip_info->tx_buff = NULL; - } + kfree(strip_info->rx_buff); + strip_info->rx_buff = NULL; + kfree(strip_info->sx_buff); + strip_info->sx_buff = NULL; + kfree(strip_info->tx_buff); + strip_info->tx_buff = NULL; + del_timer(&strip_info->idle_timer); return 0; } diff --git a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c index 7a5e20a17890..b0d8b5b03152 100644 --- a/drivers/net/wireless/wavelan.c +++ b/drivers/net/wireless/wavelan.c @@ -430,7 +430,6 @@ static void fee_read(unsigned long ioaddr, /* I/O port of the card */ } } -#ifdef WIRELESS_EXT /* if the wireless extension exists in the kernel */ /*------------------------------------------------------------------*/ /* @@ -514,7 +513,6 @@ static void fee_write(unsigned long ioaddr, /* I/O port of the card */ fee_wait(ioaddr, 10, 100); #endif /* EEPROM_IS_PROTECTED */ } -#endif /* WIRELESS_EXT */ /************************ I82586 SUBROUTINES *************************/ /* @@ -973,11 +971,9 @@ static void wv_mmc_show(struct net_device * dev) mmc_read(ioaddr, 0, (u8 *) & m, sizeof(m)); mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0); -#ifdef WIRELESS_EXT /* if wireless extension exists in the kernel */ /* Don't forget to update statistics */ lp->wstats.discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l; -#endif /* WIRELESS_EXT */ printk(KERN_DEBUG "##### WaveLAN modem status registers: #####\n"); #ifdef DEBUG_SHOW_UNUSED @@ -1499,7 +1495,6 @@ static int wavelan_set_mac_address(struct net_device * dev, void *addr) } #endif /* SET_MAC_ADDRESS */ -#ifdef WIRELESS_EXT /* if wireless extensions exist in the kernel */ /*------------------------------------------------------------------*/ /* @@ -2473,7 +2468,6 @@ static iw_stats *wavelan_get_wireless_stats(struct net_device * dev) #endif return &lp->wstats; } -#endif /* WIRELESS_EXT */ /************************* PACKET RECEPTION *************************/ /* @@ -4194,11 +4188,9 @@ static int __init wavelan_config(struct net_device *dev, unsigned short ioaddr) dev->set_mac_address = &wavelan_set_mac_address; #endif /* SET_MAC_ADDRESS */ -#ifdef WIRELESS_EXT /* if wireless extension exists in the kernel */ dev->wireless_handlers = &wavelan_handler_def; lp->wireless_data.spy_data = &lp->spy_data; dev->wireless_data = &lp->wireless_data; -#endif dev->mtu = WAVELAN_MTU; diff --git a/drivers/net/wireless/wavelan.p.h b/drivers/net/wireless/wavelan.p.h index 509ff22a6caa..166e28b9a4f7 100644 --- a/drivers/net/wireless/wavelan.p.h +++ b/drivers/net/wireless/wavelan.p.h @@ -409,11 +409,9 @@ #define MULTICAST_AVOID /* Avoid extra multicast (I'm sceptical). */ #undef SET_MAC_ADDRESS /* Experimental */ -#ifdef WIRELESS_EXT /* If wireless extensions exist in the kernel */ /* Warning: this stuff will slow down the driver. */ #define WIRELESS_SPY /* Enable spying addresses. */ #undef HISTOGRAM /* Enable histogram of signal level. */ -#endif /****************************** DEBUG ******************************/ @@ -506,12 +504,10 @@ struct net_local u_short tx_first_free; u_short tx_first_in_use; -#ifdef WIRELESS_EXT iw_stats wstats; /* Wireless-specific statistics */ struct iw_spy_data spy_data; struct iw_public_data wireless_data; -#endif #ifdef HISTOGRAM int his_number; /* number of intervals */ diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c index 183c4732ef65..4b3c98f5c564 100644 --- a/drivers/net/wireless/wavelan_cs.c +++ b/drivers/net/wireless/wavelan_cs.c @@ -415,7 +415,6 @@ fee_read(u_long base, /* i/o port of the card */ } } -#ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */ /*------------------------------------------------------------------*/ /* @@ -500,7 +499,6 @@ fee_write(u_long base, /* i/o port of the card */ fee_wait(base, 10, 100); #endif /* EEPROM_IS_PROTECTED */ } -#endif /* WIRELESS_EXT */ /******************* WaveLAN Roaming routines... ********************/ @@ -1161,10 +1159,8 @@ wv_mmc_show(struct net_device * dev) mmc_read(base, 0, (u_char *)&m, sizeof(m)); mmc_out(base, mmwoff(0, mmw_freeze), 0); -#ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */ /* Don't forget to update statistics */ lp->wstats.discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l; -#endif /* WIRELESS_EXT */ spin_unlock_irqrestore(&lp->spinlock, flags); @@ -1550,7 +1546,6 @@ wavelan_set_mac_address(struct net_device * dev, } #endif /* SET_MAC_ADDRESS */ -#ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */ /*------------------------------------------------------------------*/ /* @@ -2793,7 +2788,6 @@ wavelan_get_wireless_stats(struct net_device * dev) #endif return &lp->wstats; } -#endif /* WIRELESS_EXT */ /************************* PACKET RECEPTION *************************/ /* @@ -4679,11 +4673,9 @@ wavelan_attach(void) dev->watchdog_timeo = WATCHDOG_JIFFIES; SET_ETHTOOL_OPS(dev, &ops); -#ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */ dev->wireless_handlers = &wavelan_handler_def; lp->wireless_data.spy_data = &lp->spy_data; dev->wireless_data = &lp->wireless_data; -#endif /* Other specific data */ dev->mtu = WAVELAN_MTU; diff --git a/drivers/net/wireless/wavelan_cs.p.h b/drivers/net/wireless/wavelan_cs.p.h index 01d882be8790..724a715089c9 100644 --- a/drivers/net/wireless/wavelan_cs.p.h +++ b/drivers/net/wireless/wavelan_cs.p.h @@ -472,11 +472,9 @@ #define MULTICAST_AVOID /* Avoid extra multicast (I'm sceptical) */ #undef SET_MAC_ADDRESS /* Experimental */ -#ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */ /* Warning : these stuff will slow down the driver... */ #define WIRELESS_SPY /* Enable spying addresses */ #undef HISTOGRAM /* Enable histogram of sig level... */ -#endif /****************************** DEBUG ******************************/ @@ -624,12 +622,10 @@ struct net_local int rfp; /* Last DMA machine receive pointer */ int overrunning; /* Receiver overrun flag */ -#ifdef WIRELESS_EXT iw_stats wstats; /* Wireless specific stats */ struct iw_spy_data spy_data; struct iw_public_data wireless_data; -#endif #ifdef HISTOGRAM int his_number; /* Number of intervals */ diff --git a/drivers/net/wireless/wl3501.h b/drivers/net/wireless/wl3501.h index 7fcbe589c3f2..4303c50c2ab6 100644 --- a/drivers/net/wireless/wl3501.h +++ b/drivers/net/wireless/wl3501.h @@ -548,7 +548,7 @@ struct wl3501_80211_tx_plcp_hdr { struct wl3501_80211_tx_hdr { struct wl3501_80211_tx_plcp_hdr pclp_hdr; - struct ieee80211_hdr mac_hdr; + struct ieee80211_hdr_4addr mac_hdr; } __attribute__ ((packed)); /* diff --git a/drivers/parisc/asp.c b/drivers/parisc/asp.c index 388609967133..558420bc9f88 100644 --- a/drivers/parisc/asp.c +++ b/drivers/parisc/asp.c @@ -77,12 +77,12 @@ asp_init_chip(struct parisc_device *dev) struct gsc_irq gsc_irq; int ret; - asp.version = gsc_readb(dev->hpa + ASP_VER_OFFSET) & 0xf; + asp.version = gsc_readb(dev->hpa.start + ASP_VER_OFFSET) & 0xf; asp.name = (asp.version == 1) ? "Asp" : "Cutoff"; asp.hpa = ASP_INTERRUPT_ADDR; printk(KERN_INFO "%s version %d at 0x%lx found.\n", - asp.name, asp.version, dev->hpa); + asp.name, asp.version, dev->hpa.start); /* the IRQ ASP should use */ ret = -EBUSY; @@ -126,7 +126,7 @@ static struct parisc_device_id asp_tbl[] = { }; struct parisc_driver asp_driver = { - .name = "Asp", + .name = "asp", .id_table = asp_tbl, .probe = asp_init_chip, }; diff --git a/drivers/parisc/ccio-dma.c b/drivers/parisc/ccio-dma.c index 0e98a9d9834c..9e0229f7e25f 100644 --- a/drivers/parisc/ccio-dma.c +++ b/drivers/parisc/ccio-dma.c @@ -100,9 +100,9 @@ #define DBG_RUN_SG(x...) #endif -#define CCIO_INLINE /* inline */ -#define WRITE_U32(value, addr) gsc_writel(value, (u32 *)(addr)) -#define READ_U32(addr) gsc_readl((u32 *)(addr)) +#define CCIO_INLINE inline +#define WRITE_U32(value, addr) __raw_writel(value, addr) +#define READ_U32(addr) __raw_readl(addr) #define U2_IOA_RUNWAY 0x580 #define U2_BC_GSC 0x501 @@ -115,28 +115,28 @@ struct ioa_registers { /* Runway Supervisory Set */ - volatile int32_t unused1[12]; - volatile uint32_t io_command; /* Offset 12 */ - volatile uint32_t io_status; /* Offset 13 */ - volatile uint32_t io_control; /* Offset 14 */ - volatile int32_t unused2[1]; + int32_t unused1[12]; + uint32_t io_command; /* Offset 12 */ + uint32_t io_status; /* Offset 13 */ + uint32_t io_control; /* Offset 14 */ + int32_t unused2[1]; /* Runway Auxiliary Register Set */ - volatile uint32_t io_err_resp; /* Offset 0 */ - volatile uint32_t io_err_info; /* Offset 1 */ - volatile uint32_t io_err_req; /* Offset 2 */ - volatile uint32_t io_err_resp_hi; /* Offset 3 */ - volatile uint32_t io_tlb_entry_m; /* Offset 4 */ - volatile uint32_t io_tlb_entry_l; /* Offset 5 */ - volatile uint32_t unused3[1]; - volatile uint32_t io_pdir_base; /* Offset 7 */ - volatile uint32_t io_io_low_hv; /* Offset 8 */ - volatile uint32_t io_io_high_hv; /* Offset 9 */ - volatile uint32_t unused4[1]; - volatile uint32_t io_chain_id_mask; /* Offset 11 */ - volatile uint32_t unused5[2]; - volatile uint32_t io_io_low; /* Offset 14 */ - volatile uint32_t io_io_high; /* Offset 15 */ + uint32_t io_err_resp; /* Offset 0 */ + uint32_t io_err_info; /* Offset 1 */ + uint32_t io_err_req; /* Offset 2 */ + uint32_t io_err_resp_hi; /* Offset 3 */ + uint32_t io_tlb_entry_m; /* Offset 4 */ + uint32_t io_tlb_entry_l; /* Offset 5 */ + uint32_t unused3[1]; + uint32_t io_pdir_base; /* Offset 7 */ + uint32_t io_io_low_hv; /* Offset 8 */ + uint32_t io_io_high_hv; /* Offset 9 */ + uint32_t unused4[1]; + uint32_t io_chain_id_mask; /* Offset 11 */ + uint32_t unused5[2]; + uint32_t io_io_low; /* Offset 14 */ + uint32_t io_io_high; /* Offset 15 */ }; /* @@ -226,7 +226,7 @@ struct ioa_registers { */ struct ioc { - struct ioa_registers *ioc_hpa; /* I/O MMU base address */ + struct ioa_registers __iomem *ioc_regs; /* I/O MMU base address */ u8 *res_map; /* resource map, bit == pdir entry */ u64 *pdir_base; /* physical base address */ u32 pdir_size; /* bytes, function of IOV Space size */ @@ -595,7 +595,7 @@ ccio_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba, ** Grab virtual index [0:11] ** Deposit virt_idx bits into I/O PDIR word */ - asm volatile ("lci 0(%%sr1, %1), %0" : "=r" (ci) : "r" (vba)); + asm volatile ("lci %%r0(%%sr1, %1), %0" : "=r" (ci) : "r" (vba)); asm volatile ("extru %1,19,12,%0" : "+r" (ci) : "r" (ci)); asm volatile ("depw %1,15,12,%0" : "+r" (pa) : "r" (ci)); @@ -613,7 +613,7 @@ ccio_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba, ** the real mode coherence index generation of U2, the PDIR entry ** must be flushed to memory to retain coherence." */ - asm volatile("fdc 0(%0)" : : "r" (pdir_ptr)); + asm volatile("fdc %%r0(%0)" : : "r" (pdir_ptr)); asm volatile("sync"); } @@ -636,7 +636,7 @@ ccio_clear_io_tlb(struct ioc *ioc, dma_addr_t iovp, size_t byte_cnt) byte_cnt += chain_size; while(byte_cnt > chain_size) { - WRITE_U32(CMD_TLB_PURGE | iovp, &ioc->ioc_hpa->io_command); + WRITE_U32(CMD_TLB_PURGE | iovp, &ioc->ioc_regs->io_command); iovp += chain_size; byte_cnt -= chain_size; } @@ -684,7 +684,7 @@ ccio_mark_invalid(struct ioc *ioc, dma_addr_t iova, size_t byte_cnt) ** Hopefully someone figures out how to patch (NOP) the ** FDC/SYNC out at boot time. */ - asm volatile("fdc 0(%0)" : : "r" (pdir_ptr[7])); + asm volatile("fdc %%r0(%0)" : : "r" (pdir_ptr[7])); iovp += IOVP_SIZE; byte_cnt -= IOVP_SIZE; @@ -836,7 +836,7 @@ ccio_unmap_single(struct device *dev, dma_addr_t iova, size_t size, * This function implements the pci_alloc_consistent function. */ static void * -ccio_alloc_consistent(struct device *dev, size_t size, dma_addr_t *dma_handle, int flag) +ccio_alloc_consistent(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flag) { void *ret; #if 0 @@ -1251,7 +1251,7 @@ static struct parisc_device_id ccio_tbl[] = { static int ccio_probe(struct parisc_device *dev); static struct parisc_driver ccio_driver = { - .name = "U2:Uturn", + .name = "ccio", .id_table = ccio_tbl, .probe = ccio_probe, }; @@ -1314,14 +1314,13 @@ ccio_ioc_init(struct ioc *ioc) ioc->pdir_size = (iova_space_size / IOVP_SIZE) * sizeof(u64); - BUG_ON(ioc->pdir_size >= 4 * 1024 * 1024); /* max pdir size < 4MB */ + BUG_ON(ioc->pdir_size > 8 * 1024 * 1024); /* max pdir size <= 8MB */ /* Verify it's a power of two */ BUG_ON((1 << get_order(ioc->pdir_size)) != (ioc->pdir_size >> PAGE_SHIFT)); - DBG_INIT("%s() hpa 0x%lx mem %luMB IOV %dMB (%d bits)\n", - __FUNCTION__, - ioc->ioc_hpa, + DBG_INIT("%s() hpa 0x%p mem %luMB IOV %dMB (%d bits)\n", + __FUNCTION__, ioc->ioc_regs, (unsigned long) num_physpages >> (20 - PAGE_SHIFT), iova_space_size>>20, iov_order + PAGE_SHIFT); @@ -1329,13 +1328,12 @@ ccio_ioc_init(struct ioc *ioc) ioc->pdir_base = (u64 *)__get_free_pages(GFP_KERNEL, get_order(ioc->pdir_size)); if(NULL == ioc->pdir_base) { - panic("%s:%s() could not allocate I/O Page Table\n", __FILE__, - __FUNCTION__); + panic("%s() could not allocate I/O Page Table\n", __FUNCTION__); } memset(ioc->pdir_base, 0, ioc->pdir_size); BUG_ON((((unsigned long)ioc->pdir_base) & PAGE_MASK) != (unsigned long)ioc->pdir_base); - DBG_INIT(" base %p", ioc->pdir_base); + DBG_INIT(" base %p\n", ioc->pdir_base); /* resource map size dictated by pdir_size */ ioc->res_size = (ioc->pdir_size / sizeof(u64)) >> 3; @@ -1344,8 +1342,7 @@ ccio_ioc_init(struct ioc *ioc) ioc->res_map = (u8 *)__get_free_pages(GFP_KERNEL, get_order(ioc->res_size)); if(NULL == ioc->res_map) { - panic("%s:%s() could not allocate resource map\n", __FILE__, - __FUNCTION__); + panic("%s() could not allocate resource map\n", __FUNCTION__); } memset(ioc->res_map, 0, ioc->res_size); @@ -1366,44 +1363,58 @@ ccio_ioc_init(struct ioc *ioc) ** Initialize IOA hardware */ WRITE_U32(CCIO_CHAINID_MASK << ioc->chainid_shift, - &ioc->ioc_hpa->io_chain_id_mask); + &ioc->ioc_regs->io_chain_id_mask); WRITE_U32(virt_to_phys(ioc->pdir_base), - &ioc->ioc_hpa->io_pdir_base); + &ioc->ioc_regs->io_pdir_base); /* ** Go to "Virtual Mode" */ - WRITE_U32(IOA_NORMAL_MODE, &ioc->ioc_hpa->io_control); + WRITE_U32(IOA_NORMAL_MODE, &ioc->ioc_regs->io_control); /* ** Initialize all I/O TLB entries to 0 (Valid bit off). */ - WRITE_U32(0, &ioc->ioc_hpa->io_tlb_entry_m); - WRITE_U32(0, &ioc->ioc_hpa->io_tlb_entry_l); + WRITE_U32(0, &ioc->ioc_regs->io_tlb_entry_m); + WRITE_U32(0, &ioc->ioc_regs->io_tlb_entry_l); for(i = 1 << CCIO_CHAINID_SHIFT; i ; i--) { WRITE_U32((CMD_TLB_DIRECT_WRITE | (i << ioc->chainid_shift)), - &ioc->ioc_hpa->io_command); + &ioc->ioc_regs->io_command); } } static void -ccio_init_resource(struct resource *res, char *name, unsigned long ioaddr) +ccio_init_resource(struct resource *res, char *name, void __iomem *ioaddr) { int result; res->parent = NULL; res->flags = IORESOURCE_MEM; - res->start = (unsigned long)(signed) __raw_readl(ioaddr) << 16; - res->end = (unsigned long)(signed) (__raw_readl(ioaddr + 4) << 16) - 1; + /* + * bracing ((signed) ...) are required for 64bit kernel because + * we only want to sign extend the lower 16 bits of the register. + * The upper 16-bits of range registers are hardcoded to 0xffff. + */ + res->start = (unsigned long)((signed) READ_U32(ioaddr) << 16); + res->end = (unsigned long)((signed) (READ_U32(ioaddr + 4) << 16) - 1); res->name = name; + /* + * Check if this MMIO range is disable + */ if (res->end + 1 == res->start) return; - result = request_resource(&iomem_resource, res); + + /* On some platforms (e.g. K-Class), we have already registered + * resources for devices reported by firmware. Some are children + * of ccio. + * "insert" ccio ranges in the mmio hierarchy (/proc/iomem). + */ + result = insert_resource(&iomem_resource, res); if (result < 0) { - printk(KERN_ERR "%s: failed to claim CCIO bus address space (%08lx,%08lx)\n", - __FILE__, res->start, res->end); + printk(KERN_ERR "%s() failed to claim CCIO bus address space (%08lx,%08lx)\n", + __FUNCTION__, res->start, res->end); } } @@ -1414,9 +1425,8 @@ static void __init ccio_init_resources(struct ioc *ioc) sprintf(name, "GSC Bus [%d/]", ioc->hw_path); - ccio_init_resource(res, name, (unsigned long)&ioc->ioc_hpa->io_io_low); - ccio_init_resource(res + 1, name, - (unsigned long)&ioc->ioc_hpa->io_io_low_hv); + ccio_init_resource(res, name, &ioc->ioc_regs->io_io_low); + ccio_init_resource(res + 1, name, &ioc->ioc_regs->io_io_low_hv); } static int new_ioc_area(struct resource *res, unsigned long size, @@ -1427,7 +1437,12 @@ static int new_ioc_area(struct resource *res, unsigned long size, res->start = (max - size + 1) &~ (align - 1); res->end = res->start + size; - if (!request_resource(&iomem_resource, res)) + + /* We might be trying to expand the MMIO range to include + * a child device that has already registered it's MMIO space. + * Use "insert" instead of request_resource(). + */ + if (!insert_resource(&iomem_resource, res)) return 0; return new_ioc_area(res, size, min, max - size, align); @@ -1486,15 +1501,15 @@ int ccio_allocate_resource(const struct parisc_device *dev, if (!expand_ioc_area(parent, size, min, max, align)) { __raw_writel(((parent->start)>>16) | 0xffff0000, - (unsigned long)&(ioc->ioc_hpa->io_io_low)); + &ioc->ioc_regs->io_io_low); __raw_writel(((parent->end)>>16) | 0xffff0000, - (unsigned long)&(ioc->ioc_hpa->io_io_high)); + &ioc->ioc_regs->io_io_high); } else if (!expand_ioc_area(parent + 1, size, min, max, align)) { parent++; __raw_writel(((parent->start)>>16) | 0xffff0000, - (unsigned long)&(ioc->ioc_hpa->io_io_low_hv)); + &ioc->ioc_regs->io_io_low_hv); __raw_writel(((parent->end)>>16) | 0xffff0000, - (unsigned long)&(ioc->ioc_hpa->io_io_high_hv)); + &ioc->ioc_regs->io_io_high_hv); } else { return -EBUSY; } @@ -1521,7 +1536,12 @@ int ccio_request_resource(const struct parisc_device *dev, return -EBUSY; } - return request_resource(parent, res); + /* "transparent" bus bridges need to register MMIO resources + * firmware assigned them. e.g. children of hppb.c (e.g. K-class) + * registered their resources in the PDC "bus walk" (See + * arch/parisc/kernel/inventory.c). + */ + return insert_resource(parent, res); } /** @@ -1546,7 +1566,7 @@ static int ccio_probe(struct parisc_device *dev) ioc->name = dev->id.hversion == U2_IOA_RUNWAY ? "U2" : "UTurn"; - printk(KERN_INFO "Found %s at 0x%lx\n", ioc->name, dev->hpa); + printk(KERN_INFO "Found %s at 0x%lx\n", ioc->name, dev->hpa.start); for (i = 0; i < ioc_count; i++) { ioc_p = &(*ioc_p)->next; @@ -1554,7 +1574,7 @@ static int ccio_probe(struct parisc_device *dev) *ioc_p = ioc; ioc->hw_path = dev->hw_path; - ioc->ioc_hpa = (struct ioa_registers *)dev->hpa; + ioc->ioc_regs = ioremap(dev->hpa.start, 4096); ccio_ioc_init(ioc); ccio_init_resources(ioc); hppa_dma_ops = &ccio_ops; diff --git a/drivers/parisc/ccio-rm-dma.c b/drivers/parisc/ccio-rm-dma.c index 57e6385976e2..356b8357bccc 100644 --- a/drivers/parisc/ccio-rm-dma.c +++ b/drivers/parisc/ccio-rm-dma.c @@ -167,7 +167,7 @@ ccio_probe(struct parisc_device *dev) { printk(KERN_INFO "%s found %s at 0x%lx\n", MODULE_NAME, dev->id.hversion == U2_BC_GSC ? "U2" : "UTurn", - dev->hpa); + dev->hpa.start); /* ** FIXME - should check U2 registers to verify it's really running diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c index 2f2dbef2c3b7..5ab75334c579 100644 --- a/drivers/parisc/dino.c +++ b/drivers/parisc/dino.c @@ -178,6 +178,8 @@ static int dino_cfg_read(struct pci_bus *bus, unsigned int devfn, int where, void __iomem *base_addr = d->hba.base_addr; unsigned long flags; + DBG("%s: %p, %d, %d, %d\n", __FUNCTION__, base_addr, devfn, where, + size); spin_lock_irqsave(&d->dinosaur_pen, flags); /* tell HW which CFG address */ @@ -211,6 +213,8 @@ static int dino_cfg_write(struct pci_bus *bus, unsigned int devfn, int where, void __iomem *base_addr = d->hba.base_addr; unsigned long flags; + DBG("%s: %p, %d, %d, %d\n", __FUNCTION__, base_addr, devfn, where, + size); spin_lock_irqsave(&d->dinosaur_pen, flags); /* avoid address stepping feature */ @@ -295,7 +299,7 @@ static void dino_disable_irq(unsigned int irq) struct dino_device *dino_dev = irq_desc[irq].handler_data; int local_irq = gsc_find_local_irq(irq, dino_dev->global_irq, irq); - DBG(KERN_WARNING "%s(0x%p, %d)\n", __FUNCTION__, irq_dev, irq); + DBG(KERN_WARNING "%s(0x%p, %d)\n", __FUNCTION__, dino_dev, irq); /* Clear the matching bit in the IMR register */ dino_dev->imr &= ~(DINO_MASK_IRQ(local_irq)); @@ -308,7 +312,7 @@ static void dino_enable_irq(unsigned int irq) int local_irq = gsc_find_local_irq(irq, dino_dev->global_irq, irq); u32 tmp; - DBG(KERN_WARNING "%s(0x%p, %d)\n", __FUNCTION__, irq_dev, irq); + DBG(KERN_WARNING "%s(0x%p, %d)\n", __FUNCTION__, dino_dev, irq); /* ** clear pending IRQ bits @@ -490,7 +494,7 @@ dino_card_setup(struct pci_bus *bus, void __iomem *base_addr) if (res->start == F_EXTEND(0xf0000000UL | (i * _8MB))) break; } - DBG("DINO GSC WRITE i=%d, start=%lx, dino addr = %lx\n", + DBG("DINO GSC WRITE i=%d, start=%lx, dino addr = %p\n", i, res->start, base_addr + DINO_IO_ADDR_EN); __raw_writel(1 << i, base_addr + DINO_IO_ADDR_EN); } @@ -683,6 +687,14 @@ static void __init dino_card_init(struct dino_device *dino_dev) { u32 brdg_feat = 0x00784e05; + unsigned long status; + + status = __raw_readl(dino_dev->hba.base_addr+DINO_IO_STATUS); + if (status & 0x0000ff80) { + __raw_writel(0x00000005, + dino_dev->hba.base_addr+DINO_IO_COMMAND); + udelay(1); + } __raw_writel(0x00000000, dino_dev->hba.base_addr+DINO_GMASK); __raw_writel(0x00000001, dino_dev->hba.base_addr+DINO_IO_FBB_EN); @@ -902,15 +914,15 @@ void ccio_cujo20_fixup(struct parisc_device *dev, u32 iovp); ** If so, initialize the chip appropriately (card-mode vs bridge mode). ** Much of the initialization is common though. */ -static int __init -dino_driver_callback(struct parisc_device *dev) +static int __init dino_probe(struct parisc_device *dev) { struct dino_device *dino_dev; // Dino specific control struct const char *version = "unknown"; char *name; int is_cujo = 0; struct pci_bus *bus; - + unsigned long hpa = dev->hpa.start; + name = "Dino"; if (is_card_dino(&dev->id)) { version = "3.x (card mode)"; @@ -928,11 +940,11 @@ dino_driver_callback(struct parisc_device *dev) } } - printk("%s version %s found at 0x%lx\n", name, version, dev->hpa); + printk("%s version %s found at 0x%lx\n", name, version, hpa); - if (!request_mem_region(dev->hpa, PAGE_SIZE, name)) { + if (!request_mem_region(hpa, PAGE_SIZE, name)) { printk(KERN_ERR "DINO: Hey! Someone took my MMIO space (0x%ld)!\n", - dev->hpa); + hpa); return 1; } @@ -940,12 +952,12 @@ dino_driver_callback(struct parisc_device *dev) if (is_cujo && dev->id.hversion_rev == 1) { #ifdef CONFIG_IOMMU_CCIO printk(KERN_WARNING "Enabling Cujo 2.0 bug workaround\n"); - if (dev->hpa == (unsigned long)CUJO_RAVEN_ADDR) { + if (hpa == (unsigned long)CUJO_RAVEN_ADDR) { ccio_cujo20_fixup(dev, CUJO_RAVEN_BADPAGE); - } else if (dev->hpa == (unsigned long)CUJO_FIREHAWK_ADDR) { + } else if (hpa == (unsigned long)CUJO_FIREHAWK_ADDR) { ccio_cujo20_fixup(dev, CUJO_FIREHAWK_BADPAGE); } else { - printk("Don't recognise Cujo at address 0x%lx, not enabling workaround\n", dev->hpa); + printk("Don't recognise Cujo at address 0x%lx, not enabling workaround\n", hpa); } #endif } else if (!is_cujo && !is_card_dino(&dev->id) && @@ -970,7 +982,7 @@ dino_driver_callback(struct parisc_device *dev) memset(dino_dev, 0, sizeof(struct dino_device)); dino_dev->hba.dev = dev; - dino_dev->hba.base_addr = ioremap(dev->hpa, 4096); /* faster access */ + dino_dev->hba.base_addr = ioremap(hpa, 4096); dino_dev->hba.lmmio_space_offset = 0; /* CPU addrs == bus addrs */ spin_lock_init(&dino_dev->dinosaur_pen); dino_dev->hba.iommu = ccio_get_iommu(dev); @@ -1027,9 +1039,9 @@ static struct parisc_device_id dino_tbl[] = { }; static struct parisc_driver dino_driver = { - .name = "Dino", + .name = "dino", .id_table = dino_tbl, - .probe = dino_driver_callback, + .probe = dino_probe, }; /* diff --git a/drivers/parisc/eisa.c b/drivers/parisc/eisa.c index 043d47aea75b..6362bf99eff6 100644 --- a/drivers/parisc/eisa.c +++ b/drivers/parisc/eisa.c @@ -315,7 +315,7 @@ static int __devinit eisa_probe(struct parisc_device *dev) char *name = is_mongoose(dev) ? "Mongoose" : "Wax"; printk(KERN_INFO "%s EISA Adapter found at 0x%08lx\n", - name, dev->hpa); + name, dev->hpa.start); eisa_dev.hba.dev = dev; eisa_dev.hba.iommu = ccio_get_iommu(dev); @@ -397,7 +397,7 @@ static struct parisc_device_id eisa_tbl[] = { MODULE_DEVICE_TABLE(parisc, eisa_tbl); static struct parisc_driver eisa_driver = { - .name = "EISA Bus Adapter", + .name = "eisa_ba", .id_table = eisa_tbl, .probe = eisa_probe, }; diff --git a/drivers/parisc/gsc.c b/drivers/parisc/gsc.c index af5e02526a18..16d40f95978d 100644 --- a/drivers/parisc/gsc.c +++ b/drivers/parisc/gsc.c @@ -183,12 +183,20 @@ void gsc_asic_assign_irq(struct gsc_asic *asic, int local_irq, int *irqp) *irqp = irq; } +static struct device *next_device(struct klist_iter *i) +{ + struct klist_node * n = klist_next(i); + return n ? container_of(n, struct device, knode_parent) : NULL; +} + void gsc_fixup_irqs(struct parisc_device *parent, void *ctrl, void (*choose_irq)(struct parisc_device *, void *)) { struct device *dev; + struct klist_iter i; - list_for_each_entry(dev, &parent->dev.children, node) { + klist_iter_init(&parent->dev.klist_children, &i); + while ((dev = next_device(&i))) { struct parisc_device *padev = to_parisc_device(dev); /* work-around for 715/64 and others which have parent @@ -197,6 +205,7 @@ void gsc_fixup_irqs(struct parisc_device *parent, void *ctrl, return gsc_fixup_irqs(padev, ctrl, choose_irq); choose_irq(padev, ctrl); } + klist_iter_exit(&i); } int gsc_common_setup(struct parisc_device *parent, struct gsc_asic *gsc_asic) diff --git a/drivers/parisc/hppb.c b/drivers/parisc/hppb.c index e869c6020370..5edf93f80757 100644 --- a/drivers/parisc/hppb.c +++ b/drivers/parisc/hppb.c @@ -68,14 +68,14 @@ static int hppb_probe(struct parisc_device *dev) memset(card->next, '\0', sizeof(struct hppb_card)); card = card->next; } - printk(KERN_INFO "Found GeckoBoa at 0x%lx\n", dev->hpa); + printk(KERN_INFO "Found GeckoBoa at 0x%lx\n", dev->hpa.start); - card->hpa = dev->hpa; + card->hpa = dev->hpa.start; card->mmio_region.name = "HP-PB Bus"; card->mmio_region.flags = IORESOURCE_MEM; - card->mmio_region.start = __raw_readl(dev->hpa + IO_IO_LOW); - card->mmio_region.end = __raw_readl(dev->hpa + IO_IO_HIGH) - 1; + card->mmio_region.start = gsc_readl(dev->hpa.start + IO_IO_LOW); + card->mmio_region.end = gsc_readl(dev->hpa.start + IO_IO_HIGH) - 1; status = ccio_request_resource(dev, &card->mmio_region); if(status < 0) { @@ -93,7 +93,7 @@ static struct parisc_device_id hppb_tbl[] = { }; static struct parisc_driver hppb_driver = { - .name = "Gecko Boa", + .name = "gecko_boa", .id_table = hppb_tbl, .probe = hppb_probe, }; diff --git a/drivers/parisc/iosapic.c b/drivers/parisc/iosapic.c index 7a57c1b8373f..a39fbfef789a 100644 --- a/drivers/parisc/iosapic.c +++ b/drivers/parisc/iosapic.c @@ -244,7 +244,7 @@ static struct irt_entry *iosapic_alloc_irt(int num_entries) * 4-byte alignment on 32-bit kernels */ a = (unsigned long)kmalloc(sizeof(struct irt_entry) * num_entries + 8, GFP_KERNEL); - a = (a + 7) & ~7; + a = (a + 7UL) & ~7UL; return (struct irt_entry *)a; } diff --git a/drivers/parisc/lasi.c b/drivers/parisc/lasi.c index cb84a4e84a2f..a8c20396ffbe 100644 --- a/drivers/parisc/lasi.c +++ b/drivers/parisc/lasi.c @@ -175,7 +175,7 @@ lasi_init_chip(struct parisc_device *dev) return -ENOMEM; lasi->name = "Lasi"; - lasi->hpa = dev->hpa; + lasi->hpa = dev->hpa.start; /* Check the 4-bit (yes, only 4) version register */ lasi->version = gsc_readl(lasi->hpa + LASI_VER) & 0xf; @@ -233,7 +233,7 @@ static struct parisc_device_id lasi_tbl[] = { }; struct parisc_driver lasi_driver = { - .name = "Lasi", + .name = "lasi", .id_table = lasi_tbl, .probe = lasi_init_chip, }; diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c index 7fdd80b7eb47..5e495dcbc58a 100644 --- a/drivers/parisc/lba_pci.c +++ b/drivers/parisc/lba_pci.c @@ -1288,7 +1288,7 @@ lba_legacy_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev) ** Adjust "window" for this rope. */ rsize /= ROPES_PER_IOC; - r->start += (rsize + 1) * LBA_NUM(pa_dev->hpa); + r->start += (rsize + 1) * LBA_NUM(pa_dev->hpa.start); r->end = r->start + rsize; } else { r->end = r->start = 0; /* Not enabled. */ @@ -1458,7 +1458,7 @@ lba_driver_probe(struct parisc_device *dev) u32 func_class; void *tmp_obj; char *version; - void __iomem *addr = ioremap(dev->hpa, 4096); + void __iomem *addr = ioremap(dev->hpa.start, 4096); /* Read HW Rev First */ func_class = READ_REG32(addr + LBA_FCLASS); @@ -1476,7 +1476,7 @@ lba_driver_probe(struct parisc_device *dev) } printk(KERN_INFO "%s version %s (0x%x) found at 0x%lx\n", - MODULE_NAME, version, func_class & 0xf, dev->hpa); + MODULE_NAME, version, func_class & 0xf, dev->hpa.start); if (func_class < 2) { printk(KERN_WARNING "Can't support LBA older than " @@ -1503,17 +1503,17 @@ lba_driver_probe(struct parisc_device *dev) * but for the mask for func_class. */ printk(KERN_INFO "%s version %s (0x%x) found at 0x%lx\n", - MODULE_NAME, version, func_class & 0xff, dev->hpa); + MODULE_NAME, version, func_class & 0xff, dev->hpa.start); cfg_ops = &mercury_cfg_ops; } else { - printk(KERN_ERR "Unknown LBA found at 0x%lx\n", dev->hpa); + printk(KERN_ERR "Unknown LBA found at 0x%lx\n", dev->hpa.start); return -ENODEV; } /* ** Tell I/O SAPIC driver we have a IRQ handler/region. */ - tmp_obj = iosapic_register(dev->hpa + LBA_IOSAPIC_BASE); + tmp_obj = iosapic_register(dev->hpa.start + LBA_IOSAPIC_BASE); /* NOTE: PCI devices (e.g. 103c:1005 graphics card) which don't ** have an IRT entry will get NULL back from iosapic code. @@ -1635,7 +1635,7 @@ void __init lba_init(void) */ void lba_set_iregs(struct parisc_device *lba, u32 ibase, u32 imask) { - void __iomem * base_addr = ioremap(lba->hpa, 4096); + void __iomem * base_addr = ioremap(lba->hpa.start, 4096); imask <<= 2; /* adjust for hints - 2 more bits */ diff --git a/drivers/parisc/led.c b/drivers/parisc/led.c index 286902298e33..95bd07b8b61b 100644 --- a/drivers/parisc/led.c +++ b/drivers/parisc/led.c @@ -18,6 +18,9 @@ * Changes: * - Audit copy_from_user in led_proc_write. * Daniele Bellucci <bellucda@tiscali.it> + * - Switch from using a tasklet to a work queue, so the led_LCD_driver + * can sleep. + * David Pye <dmp@davidmpye.dyndns.org> */ #include <linux/config.h> @@ -37,6 +40,7 @@ #include <linux/proc_fs.h> #include <linux/ctype.h> #include <linux/blkdev.h> +#include <linux/workqueue.h> #include <linux/rcupdate.h> #include <asm/io.h> #include <asm/processor.h> @@ -47,25 +51,30 @@ #include <asm/uaccess.h> /* The control of the LEDs and LCDs on PARISC-machines have to be done - completely in software. The necessary calculations are done in a tasklet - which is scheduled at every timer interrupt and since the calculations - may consume relatively much CPU-time some of the calculations can be + completely in software. The necessary calculations are done in a work queue + task which is scheduled regularly, and since the calculations may consume a + relatively large amount of CPU time, some of the calculations can be turned off with the following variables (controlled via procfs) */ static int led_type = -1; -static int led_heartbeat = 1; -static int led_diskio = 1; -static int led_lanrxtx = 1; +static unsigned char lastleds; /* LED state from most recent update */ +static unsigned int led_heartbeat = 1; +static unsigned int led_diskio = 1; +static unsigned int led_lanrxtx = 1; static char lcd_text[32]; static char lcd_text_default[32]; + +static struct workqueue_struct *led_wq; +static void led_work_func(void *); +static DECLARE_WORK(led_task, led_work_func, NULL); + #if 0 #define DPRINTK(x) printk x #else #define DPRINTK(x) #endif - struct lcd_block { unsigned char command; /* stores the command byte */ unsigned char on; /* value for turning LED on */ @@ -116,12 +125,27 @@ lcd_info __attribute__((aligned(8))) = #define LCD_DATA_REG lcd_info.lcd_data_reg_addr #define LED_DATA_REG lcd_info.lcd_cmd_reg_addr /* LASI & ASP only */ +#define LED_HASLCD 1 +#define LED_NOLCD 0 + +/* The workqueue must be created at init-time */ +static int start_task(void) +{ + /* Display the default text now */ + if (led_type == LED_HASLCD) lcd_print( lcd_text_default ); + + /* Create the work queue and queue the LED task */ + led_wq = create_singlethread_workqueue("led_wq"); + queue_work(led_wq, &led_task); + + return 0; +} + +device_initcall(start_task); /* ptr to LCD/LED-specific function */ static void (*led_func_ptr) (unsigned char); -#define LED_HASLCD 1 -#define LED_NOLCD 0 #ifdef CONFIG_PROC_FS static int led_proc_read(char *page, char **start, off_t off, int count, int *eof, void *data) @@ -286,52 +310,35 @@ static void led_LASI_driver(unsigned char leds) /* ** ** led_LCD_driver() - ** - ** The logic of the LCD driver is, that we write at every scheduled call - ** only to one of LCD_CMD_REG _or_ LCD_DATA_REG - registers. - ** That way we don't need to let this tasklet busywait for min_cmd_delay - ** milliseconds. - ** - ** TODO: check the value of "min_cmd_delay" against the value of HZ. ** */ static void led_LCD_driver(unsigned char leds) { - static int last_index; /* 0:heartbeat, 1:disk, 2:lan_in, 3:lan_out */ - static int last_was_cmd;/* 0: CMD was written last, 1: DATA was last */ - struct lcd_block *block_ptr; - int value; - - switch (last_index) { - case 0: block_ptr = &lcd_info.heartbeat; - value = leds & LED_HEARTBEAT; - break; - case 1: block_ptr = &lcd_info.disk_io; - value = leds & LED_DISK_IO; - break; - case 2: block_ptr = &lcd_info.lan_rcv; - value = leds & LED_LAN_RCV; - break; - case 3: block_ptr = &lcd_info.lan_tx; - value = leds & LED_LAN_TX; - break; - default: /* should never happen: */ - return; - } - - if (last_was_cmd) { - /* write the value to the LCD data port */ - gsc_writeb( value ? block_ptr->on : block_ptr->off, LCD_DATA_REG ); - } else { - /* write the command-byte to the LCD command register */ - gsc_writeb( block_ptr->command, LCD_CMD_REG ); - } + static int i; + static unsigned char mask[4] = { LED_HEARTBEAT, LED_DISK_IO, + LED_LAN_RCV, LED_LAN_TX }; - /* now update the vars for the next interrupt iteration */ - if (++last_was_cmd == 2) { /* switch between cmd & data */ - last_was_cmd = 0; - if (++last_index == 4) - last_index = 0; /* switch back to heartbeat index */ + static struct lcd_block * blockp[4] = { + &lcd_info.heartbeat, + &lcd_info.disk_io, + &lcd_info.lan_rcv, + &lcd_info.lan_tx + }; + + /* Convert min_cmd_delay to milliseconds */ + unsigned int msec_cmd_delay = 1 + (lcd_info.min_cmd_delay / 1000); + + for (i=0; i<4; ++i) + { + if ((leds & mask[i]) != (lastleds & mask[i])) + { + gsc_writeb( blockp[i]->command, LCD_CMD_REG ); + msleep(msec_cmd_delay); + + gsc_writeb( leds & mask[i] ? blockp[i]->on : + blockp[i]->off, LCD_DATA_REG ); + msleep(msec_cmd_delay); + } } } @@ -356,7 +363,7 @@ static __inline__ int led_get_net_activity(void) rx_total = tx_total = 0; - /* we are running as tasklet, so locking dev_base + /* we are running as a workqueue task, so locking dev_base * for reading should be OK */ read_lock(&dev_base_lock); rcu_read_lock(); @@ -405,7 +412,7 @@ static __inline__ int led_get_diskio_activity(void) static unsigned long last_pgpgin, last_pgpgout; struct page_state pgstat; int changed; - + get_full_page_state(&pgstat); /* get no of sectors in & out */ /* Just use a very simple calculation here. Do not care about overflow, @@ -413,86 +420,70 @@ static __inline__ int led_get_diskio_activity(void) changed = (pgstat.pgpgin != last_pgpgin) || (pgstat.pgpgout != last_pgpgout); last_pgpgin = pgstat.pgpgin; last_pgpgout = pgstat.pgpgout; - + return (changed ? LED_DISK_IO : 0); } /* - ** led_tasklet_func() + ** led_work_func() ** - ** is scheduled at every timer interrupt from time.c and - ** updates the chassis LCD/LED + ** manages when and which chassis LCD/LED gets updated TODO: - display load average (older machines like 715/64 have 4 "free" LED's for that) - optimizations */ -#define HEARTBEAT_LEN (HZ*6/100) -#define HEARTBEAT_2ND_RANGE_START (HZ*22/100) +#define HEARTBEAT_LEN (HZ*10/100) +#define HEARTBEAT_2ND_RANGE_START (HZ*28/100) #define HEARTBEAT_2ND_RANGE_END (HEARTBEAT_2ND_RANGE_START + HEARTBEAT_LEN) -#define NORMALIZED_COUNT(count) (count/(HZ/100)) +#define LED_UPDATE_INTERVAL (1 + (HZ*19/1000)) -static void led_tasklet_func(unsigned long unused) +static void led_work_func (void *unused) { - static unsigned char lastleds; - unsigned char currentleds; /* stores current value of the LEDs */ - static unsigned long count; /* static incremented value, not wrapped */ + static unsigned long last_jiffies; static unsigned long count_HZ; /* counter in range 0..HZ */ + unsigned char currentleds = 0; /* stores current value of the LEDs */ /* exit if not initialized */ if (!led_func_ptr) return; - /* increment the local counters */ - ++count; - if (++count_HZ == HZ) + /* increment the heartbeat timekeeper */ + count_HZ += jiffies - last_jiffies; + last_jiffies = jiffies; + if (count_HZ >= HZ) count_HZ = 0; - currentleds = lastleds; - - if (led_heartbeat) - { - /* flash heartbeat-LED like a real heart (2 x short then a long delay) */ - if (count_HZ<HEARTBEAT_LEN || - (count_HZ>=HEARTBEAT_2ND_RANGE_START && count_HZ<HEARTBEAT_2ND_RANGE_END)) - currentleds |= LED_HEARTBEAT; - else - currentleds &= ~LED_HEARTBEAT; - } - - /* look for network activity and flash LEDs respectively */ - if (led_lanrxtx && ((NORMALIZED_COUNT(count)+(8/2)) & 7) == 0) + if (likely(led_heartbeat)) { - currentleds &= ~(LED_LAN_RCV | LED_LAN_TX); - currentleds |= led_get_net_activity(); + /* flash heartbeat-LED like a real heart + * (2 x short then a long delay) + */ + if (count_HZ < HEARTBEAT_LEN || + (count_HZ >= HEARTBEAT_2ND_RANGE_START && + count_HZ < HEARTBEAT_2ND_RANGE_END)) + currentleds |= LED_HEARTBEAT; } - /* avoid to calculate diskio-stats at same irq as netio-stats */ - if (led_diskio && (NORMALIZED_COUNT(count) & 7) == 0) - { - currentleds &= ~LED_DISK_IO; - currentleds |= led_get_diskio_activity(); - } + if (likely(led_lanrxtx)) currentleds |= led_get_net_activity(); + if (likely(led_diskio)) currentleds |= led_get_diskio_activity(); /* blink all LEDs twice a second if we got an Oops (HPMC) */ - if (oops_in_progress) { + if (unlikely(oops_in_progress)) currentleds = (count_HZ<=(HZ/2)) ? 0 : 0xff; - } - - /* update the LCD/LEDs */ - if (currentleds != lastleds) { - led_func_ptr(currentleds); - lastleds = currentleds; - } -} -/* main led tasklet struct (scheduled from time.c) */ -DECLARE_TASKLET_DISABLED(led_tasklet, led_tasklet_func, 0); + if (currentleds != lastleds) + { + led_func_ptr(currentleds); /* Update the LCD/LEDs */ + lastleds = currentleds; + } + queue_delayed_work(led_wq, &led_task, LED_UPDATE_INTERVAL); +} /* ** led_halt() @@ -522,9 +513,13 @@ static int led_halt(struct notifier_block *nb, unsigned long event, void *buf) default: return NOTIFY_DONE; } - /* completely stop the LED/LCD tasklet */ - tasklet_disable(&led_tasklet); - + /* Cancel the work item and delete the queue */ + if (led_wq) { + cancel_rearming_delayed_workqueue(led_wq, &led_task); + destroy_workqueue(led_wq); + led_wq = NULL; + } + if (lcd_info.model == DISPLAY_MODEL_LCD) lcd_print(txt); else @@ -559,7 +554,6 @@ int __init register_led_driver(int model, unsigned long cmd_reg, unsigned long d printk(KERN_INFO "LCD display at %lx,%lx registered\n", LCD_CMD_REG , LCD_DATA_REG); led_func_ptr = led_LCD_driver; - lcd_print( lcd_text_default ); led_type = LED_HASLCD; break; @@ -589,9 +583,11 @@ int __init register_led_driver(int model, unsigned long cmd_reg, unsigned long d initialized++; register_reboot_notifier(&led_notifier); - /* start the led tasklet for the first time */ - tasklet_enable(&led_tasklet); - + /* Ensure the work is queued */ + if (led_wq) { + queue_work(led_wq, &led_task); + } + return 0; } @@ -626,8 +622,8 @@ void __init register_led_regions(void) ** lcd_print() ** ** Displays the given string on the LCD-Display of newer machines. - ** lcd_print() disables the timer-based led tasklet during its - ** execution and enables it afterwards again. + ** lcd_print() disables/enables the timer-based led work queue to + ** avoid a race condition while writing the CMD/DATA register pair. ** */ int lcd_print( char *str ) @@ -637,12 +633,13 @@ int lcd_print( char *str ) if (!led_func_ptr || lcd_info.model != DISPLAY_MODEL_LCD) return 0; - /* temporarily disable the led tasklet */ - tasklet_disable(&led_tasklet); + /* temporarily disable the led work task */ + if (led_wq) + cancel_rearming_delayed_workqueue(led_wq, &led_task); /* copy display string to buffer for procfs */ strlcpy(lcd_text, str, sizeof(lcd_text)); - + /* Set LCD Cursor to 1st character */ gsc_writeb(lcd_info.reset_cmd1, LCD_CMD_REG); udelay(lcd_info.min_cmd_delay); @@ -656,8 +653,10 @@ int lcd_print( char *str ) udelay(lcd_info.min_cmd_delay); } - /* re-enable the led tasklet */ - tasklet_enable(&led_tasklet); + /* re-queue the work */ + if (led_wq) { + queue_work(led_wq, &led_task); + } return lcd_info.lcd_width; } diff --git a/drivers/parisc/pdc_stable.c b/drivers/parisc/pdc_stable.c index 67c8f3b44848..273a74179720 100644 --- a/drivers/parisc/pdc_stable.c +++ b/drivers/parisc/pdc_stable.c @@ -536,7 +536,7 @@ pdcs_info_read(struct subsystem *entry, char *buf) out += sprintf(out, "Memory tested: "); if ((result & 0x0F) < 0x0E) - out += sprintf(out, "%.3f MB", 0.256*(1<<(result & 0x0F))); + out += sprintf(out, "%d kB", (1<<(result & 0x0F))*256); else out += sprintf(out, "All"); out += sprintf(out, "\n"); diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c index 82ea68b55df4..c85653f315aa 100644 --- a/drivers/parisc/sba_iommu.c +++ b/drivers/parisc/sba_iommu.c @@ -91,8 +91,8 @@ extern struct proc_dir_entry * proc_mckinley_root; #define DBG_RES(x...) #endif -#if defined(__LP64__) && !defined(CONFIG_PDC_NARROW) -/* "low end" PA8800 machines use ZX1 chipset */ +#if defined(CONFIG_64BIT) +/* "low end" PA8800 machines use ZX1 chipset: PAT PDC and only run 64-bit */ #define ZX1_SUPPORT #endif @@ -231,7 +231,7 @@ struct ioc { spinlock_t res_lock; unsigned int res_bitshift; /* from the LEFT! */ unsigned int res_size; /* size of resource map in bytes */ -#if SBA_HINT_SUPPORT +#ifdef SBA_HINT_SUPPORT /* FIXME : DMA HINTs not used */ unsigned long hint_mask_pdir; /* bits used for DMA hints */ unsigned int hint_shift_pdir; @@ -294,7 +294,7 @@ static unsigned long piranha_bad_128k = 0; /* Looks nice and keeps the compiler happy */ #define SBA_DEV(d) ((struct sba_device *) (d)) -#if SBA_AGP_SUPPORT +#ifdef SBA_AGP_SUPPORT static int reserve_sba_gart = 1; #endif @@ -314,7 +314,7 @@ static int reserve_sba_gart = 1; #define WRITE_REG32(val, addr) __raw_writel(cpu_to_le32(val), addr) #define WRITE_REG64(val, addr) __raw_writeq(cpu_to_le64(val), addr) -#ifdef __LP64__ +#ifdef CONFIG_64BIT #define READ_REG(addr) READ_REG64(addr) #define WRITE_REG(value, addr) WRITE_REG64(value, addr) #else @@ -324,7 +324,7 @@ static int reserve_sba_gart = 1; #ifdef DEBUG_SBA_INIT -/* NOTE: When __LP64__ isn't defined, READ_REG64() is two 32-bit reads */ +/* NOTE: When CONFIG_64BIT isn't defined, READ_REG64() is two 32-bit reads */ /** * sba_dump_ranges - debugging only - print ranges assigned to this IOA @@ -364,7 +364,7 @@ static void sba_dump_tlb(void __iomem *hpa) #else #define sba_dump_ranges(x) #define sba_dump_tlb(x) -#endif +#endif /* DEBUG_SBA_INIT */ #ifdef ASSERT_PDIR_SANITY @@ -674,7 +674,7 @@ sba_free_range(struct ioc *ioc, dma_addr_t iova, size_t size) * ***************************************************************/ -#if SBA_HINT_SUPPORT +#ifdef SBA_HINT_SUPPORT #define SBA_DMA_HINT(ioc, val) ((val) << (ioc)->hint_shift_pdir) #endif @@ -743,9 +743,8 @@ sba_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba, * (bit #61, big endian), we have to flush and sync every time * IO-PDIR is changed in Ike/Astro. */ - if (ioc_needs_fdc) { - asm volatile("fdc 0(%%sr1,%0)\n\tsync" : : "r" (pdir_ptr)); - } + if (ioc_needs_fdc) + asm volatile("fdc %%r0(%0)" : : "r" (pdir_ptr)); } @@ -769,42 +768,57 @@ static SBA_INLINE void sba_mark_invalid(struct ioc *ioc, dma_addr_t iova, size_t byte_cnt) { u32 iovp = (u32) SBA_IOVP(ioc,iova); - - /* Even though this is a big-endian machine, the entries - ** in the iopdir are little endian. That's why we clear the byte - ** at +7 instead of at +0. - */ - int off = PDIR_INDEX(iovp)*sizeof(u64)+7; + u64 *pdir_ptr = &ioc->pdir_base[PDIR_INDEX(iovp)]; #ifdef ASSERT_PDIR_SANITY - /* Assert first pdir entry is set */ - if (0x80 != (((u8 *) ioc->pdir_base)[off])) { + /* Assert first pdir entry is set. + ** + ** Even though this is a big-endian machine, the entries + ** in the iopdir are little endian. That's why we look at + ** the byte at +7 instead of at +0. + */ + if (0x80 != (((u8 *) pdir_ptr)[7])) { sba_dump_pdir_entry(ioc,"sba_mark_invalid()", PDIR_INDEX(iovp)); } #endif - if (byte_cnt <= IOVP_SIZE) + if (byte_cnt > IOVP_SIZE) { - iovp |= IOVP_SHIFT; /* set "size" field for PCOM */ +#if 0 + unsigned long entries_per_cacheline = ioc_needs_fdc ? + L1_CACHE_ALIGN(((unsigned long) pdir_ptr)) + - (unsigned long) pdir_ptr; + : 262144; +#endif - /* - ** clear I/O PDIR entry "valid" bit - ** Do NOT clear the rest - save it for debugging. - ** We should only clear bits that have previously - ** been enabled. - */ - ((u8 *)(ioc->pdir_base))[off] = 0; - } else { - u32 t = get_order(byte_cnt) + PAGE_SHIFT; + /* set "size" field for PCOM */ + iovp |= get_order(byte_cnt) + PAGE_SHIFT; - iovp |= t; do { /* clear I/O Pdir entry "valid" bit first */ - ((u8 *)(ioc->pdir_base))[off] = 0; - off += sizeof(u64); + ((u8 *) pdir_ptr)[7] = 0; + if (ioc_needs_fdc) { + asm volatile("fdc %%r0(%0)" : : "r" (pdir_ptr)); +#if 0 + entries_per_cacheline = L1_CACHE_SHIFT - 3; +#endif + } + pdir_ptr++; byte_cnt -= IOVP_SIZE; - } while (byte_cnt > 0); - } + } while (byte_cnt > IOVP_SIZE); + } else + iovp |= IOVP_SHIFT; /* set "size" field for PCOM */ + + /* + ** clear I/O PDIR entry "valid" bit. + ** We have to R/M/W the cacheline regardless how much of the + ** pdir entry that we clobber. + ** The rest of the entry would be useful for debugging if we + ** could dump core on HPMC. + */ + ((u8 *) pdir_ptr)[7] = 0; + if (ioc_needs_fdc) + asm volatile("fdc %%r0(%0)" : : "r" (pdir_ptr)); WRITE_REG( SBA_IOVA(ioc, iovp, 0, 0), ioc->ioc_hpa+IOC_PCOM); } @@ -819,18 +833,29 @@ sba_mark_invalid(struct ioc *ioc, dma_addr_t iova, size_t byte_cnt) static int sba_dma_supported( struct device *dev, u64 mask) { struct ioc *ioc; + if (dev == NULL) { printk(KERN_ERR MODULE_NAME ": EISA/ISA/et al not supported\n"); BUG(); return(0); } - ioc = GET_IOC(dev); + /* Documentation/DMA-mapping.txt tells drivers to try 64-bit first, + * then fall back to 32-bit if that fails. + * We are just "encouraging" 32-bit DMA masks here since we can + * never allow IOMMU bypass unless we add special support for ZX1. + */ + if (mask > ~0U) + return 0; - /* check if mask is > than the largest IO Virt Address */ + ioc = GET_IOC(dev); - return((int) (mask >= (ioc->ibase + - (ioc->pdir_size / sizeof(u64) * IOVP_SIZE) ))); + /* + * check if mask is >= than the current max IO Virt Address + * The max IO Virt address will *always* < 30 bits. + */ + return((int)(mask >= (ioc->ibase - 1 + + (ioc->pdir_size / sizeof(u64) * IOVP_SIZE) ))); } @@ -898,11 +923,17 @@ sba_map_single(struct device *dev, void *addr, size_t size, size -= IOVP_SIZE; pdir_start++; } - /* form complete address */ + + /* force FDC ops in io_pdir_entry() to be visible to IOMMU */ + if (ioc_needs_fdc) + asm volatile("sync" : : ); + #ifdef ASSERT_PDIR_SANITY sba_check_pdir(ioc,"Check after sba_map_single()"); #endif spin_unlock_irqrestore(&ioc->res_lock, flags); + + /* form complete address */ return SBA_IOVA(ioc, iovp, offset, DEFAULT_DMA_HINT_REG); } @@ -958,12 +989,19 @@ sba_unmap_single(struct device *dev, dma_addr_t iova, size_t size, d--; } ioc->saved_cnt = 0; + READ_REG(ioc->ioc_hpa+IOC_PCOM); /* flush purges */ } #else /* DELAYED_RESOURCE_CNT == 0 */ sba_free_range(ioc, iova, size); + + /* If fdc's were issued, force fdc's to be visible now */ + if (ioc_needs_fdc) + asm volatile("sync" : : ); + READ_REG(ioc->ioc_hpa+IOC_PCOM); /* flush purges */ #endif /* DELAYED_RESOURCE_CNT == 0 */ + spin_unlock_irqrestore(&ioc->res_lock, flags); /* XXX REVISIT for 2.5 Linux - need syncdma for zero-copy support. @@ -986,7 +1024,7 @@ sba_unmap_single(struct device *dev, dma_addr_t iova, size_t size, * See Documentation/DMA-mapping.txt */ static void *sba_alloc_consistent(struct device *hwdev, size_t size, - dma_addr_t *dma_handle, int gfp) + dma_addr_t *dma_handle, gfp_t gfp) { void *ret; @@ -1106,6 +1144,10 @@ sba_map_sg(struct device *dev, struct scatterlist *sglist, int nents, */ filled = iommu_fill_pdir(ioc, sglist, nents, 0, sba_io_pdir_entry); + /* force FDC ops in io_pdir_entry() to be visible to IOMMU */ + if (ioc_needs_fdc) + asm volatile("sync" : : ); + #ifdef ASSERT_PDIR_SANITY if (sba_check_pdir(ioc,"Check after sba_map_sg()")) { @@ -1234,8 +1276,10 @@ sba_alloc_pdir(unsigned int pdir_size) unsigned long pdir_order = get_order(pdir_size); pdir_base = __get_free_pages(GFP_KERNEL, pdir_order); - if (NULL == (void *) pdir_base) - panic("sba_ioc_init() could not allocate I/O Page Table\n"); + if (NULL == (void *) pdir_base) { + panic("%s() could not allocate I/O Page Table\n", + __FUNCTION__); + } /* If this is not PA8700 (PCX-W2) ** OR newer than ver 2.2 @@ -1322,19 +1366,29 @@ sba_alloc_pdir(unsigned int pdir_size) return (void *) pdir_base; } +static struct device *next_device(struct klist_iter *i) +{ + struct klist_node * n = klist_next(i); + return n ? container_of(n, struct device, knode_parent) : NULL; +} + /* setup Mercury or Elroy IBASE/IMASK registers. */ -static void setup_ibase_imask(struct parisc_device *sba, struct ioc *ioc, int ioc_num) +static void +setup_ibase_imask(struct parisc_device *sba, struct ioc *ioc, int ioc_num) { - /* lba_set_iregs() is in drivers/parisc/lba_pci.c */ + /* lba_set_iregs() is in drivers/parisc/lba_pci.c */ extern void lba_set_iregs(struct parisc_device *, u32, u32); struct device *dev; + struct klist_iter i; - list_for_each_entry(dev, &sba->dev.children, node) { + klist_iter_init(&sba->dev.klist_children, &i); + while ((dev = next_device(&i))) { struct parisc_device *lba = to_parisc_device(dev); - int rope_num = (lba->hpa >> 13) & 0xf; + int rope_num = (lba->hpa.start >> 13) & 0xf; if (rope_num >> 3 == ioc_num) lba_set_iregs(lba, ioc->ibase, ioc->imask); } + klist_iter_exit(&i); } static void @@ -1343,7 +1397,7 @@ sba_ioc_init_pluto(struct parisc_device *sba, struct ioc *ioc, int ioc_num) u32 iova_space_mask; u32 iova_space_size; int iov_order, tcnfg; -#if SBA_AGP_SUPPORT +#ifdef SBA_AGP_SUPPORT int agp_found = 0; #endif /* @@ -1380,7 +1434,7 @@ sba_ioc_init_pluto(struct parisc_device *sba, struct ioc *ioc, int ioc_num) DBG_INIT("%s() pdir %p size %x\n", __FUNCTION__, ioc->pdir_base, ioc->pdir_size); -#if SBA_HINT_SUPPORT +#ifdef SBA_HINT_SUPPORT ioc->hint_shift_pdir = iov_order + PAGE_SHIFT; ioc->hint_mask_pdir = ~(0x3 << (iov_order + PAGE_SHIFT)); @@ -1404,7 +1458,7 @@ sba_ioc_init_pluto(struct parisc_device *sba, struct ioc *ioc, int ioc_num) WRITE_REG(ioc->imask, ioc->ioc_hpa + IOC_IMASK); -#ifdef __LP64__ +#ifdef CONFIG_64BIT /* ** Setting the upper bits makes checking for bypass addresses ** a little faster later on. @@ -1437,7 +1491,7 @@ sba_ioc_init_pluto(struct parisc_device *sba, struct ioc *ioc, int ioc_num) */ WRITE_REG(ioc->ibase | 31, ioc->ioc_hpa + IOC_PCOM); -#if SBA_AGP_SUPPORT +#ifdef SBA_AGP_SUPPORT /* ** If an AGP device is present, only use half of the IOV space ** for PCI DMA. Unfortunately we can't know ahead of time @@ -1489,11 +1543,9 @@ sba_ioc_init(struct parisc_device *sba, struct ioc *ioc, int ioc_num) if (iova_space_size < (1 << (20 - PAGE_SHIFT))) { iova_space_size = 1 << (20 - PAGE_SHIFT); } -#ifdef __LP64__ else if (iova_space_size > (1 << (30 - PAGE_SHIFT))) { iova_space_size = 1 << (30 - PAGE_SHIFT); } -#endif /* ** iova space must be log2() in size. @@ -1519,7 +1571,7 @@ sba_ioc_init(struct parisc_device *sba, struct ioc *ioc, int ioc_num) DBG_INIT("%s() pdir %p size %x\n", __FUNCTION__, ioc->pdir_base, pdir_size); -#if SBA_HINT_SUPPORT +#ifdef SBA_HINT_SUPPORT /* FIXME : DMA HINTs not used */ ioc->hint_shift_pdir = iov_order + PAGE_SHIFT; ioc->hint_mask_pdir = ~(0x3 << (iov_order + PAGE_SHIFT)); @@ -1590,7 +1642,7 @@ sba_ioc_init(struct parisc_device *sba, struct ioc *ioc, int ioc_num) static void __iomem *ioc_remap(struct sba_device *sba_dev, int offset) { - return ioremap(sba_dev->dev->hpa + offset, SBA_FUNC_SIZE); + return ioremap(sba_dev->dev->hpa.start + offset, SBA_FUNC_SIZE); } static void sba_hw_init(struct sba_device *sba_dev) @@ -1968,7 +2020,7 @@ sba_driver_callback(struct parisc_device *dev) u32 func_class; int i; char *version; - void __iomem *sba_addr = ioremap(dev->hpa, SBA_FUNC_SIZE); + void __iomem *sba_addr = ioremap(dev->hpa.start, SBA_FUNC_SIZE); sba_dump_ranges(sba_addr); @@ -2010,7 +2062,7 @@ sba_driver_callback(struct parisc_device *dev) } printk(KERN_INFO "%s found %s at 0x%lx\n", - MODULE_NAME, version, dev->hpa); + MODULE_NAME, version, dev->hpa.start); sba_dev = kmalloc(sizeof(struct sba_device), GFP_KERNEL); if (!sba_dev) { diff --git a/drivers/parisc/superio.c b/drivers/parisc/superio.c index e0efed796b92..bab3bcabcb6e 100644 --- a/drivers/parisc/superio.c +++ b/drivers/parisc/superio.c @@ -11,6 +11,7 @@ * (C) Copyright 2000 Alex deVries <alex@onefishtwo.ca> * (C) Copyright 2001 John Marvin <jsm fc hp com> * (C) Copyright 2003 Grant Grundler <grundler parisc-linux org> + * (C) Copyright 2005 Kyle McMartin <kyle@parisc-linux.org> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -405,6 +406,7 @@ static void __devinit superio_serial_init(void) serial[0].iobase = sio_dev.sp1_base; serial[0].irq = SP1_IRQ; + spin_lock_init(&serial[0].lock); retval = early_serial_setup(&serial[0]); if (retval < 0) { @@ -414,6 +416,7 @@ static void __devinit superio_serial_init(void) serial[1].iobase = sio_dev.sp2_base; serial[1].irq = SP2_IRQ; + spin_lock_init(&serial[1].lock); retval = early_serial_setup(&serial[1]); if (retval < 0) diff --git a/drivers/parisc/wax.c b/drivers/parisc/wax.c index e547d7d024d8..17dce2adf7fe 100644 --- a/drivers/parisc/wax.c +++ b/drivers/parisc/wax.c @@ -81,7 +81,7 @@ wax_init_chip(struct parisc_device *dev) return -ENOMEM; wax->name = "wax"; - wax->hpa = dev->hpa; + wax->hpa = dev->hpa.start; wax->version = 0; /* gsc_readb(wax->hpa+WAX_VER); */ printk(KERN_INFO "%s at 0x%lx found.\n", wax->name, wax->hpa); diff --git a/drivers/parport/parport_gsc.c b/drivers/parport/parport_gsc.c index 02d72acd1c89..fde29a75f888 100644 --- a/drivers/parport/parport_gsc.c +++ b/drivers/parport/parport_gsc.c @@ -359,11 +359,12 @@ static int __devinit parport_init_chip(struct parisc_device *dev) unsigned long port; if (!dev->irq) { - printk("IRQ not found for parallel device at 0x%lx\n", dev->hpa); + printk(KERN_WARNING "IRQ not found for parallel device at 0x%lx\n", + dev->hpa.start); return -ENODEV; } - port = dev->hpa + PARPORT_GSC_OFFSET; + port = dev->hpa.start + PARPORT_GSC_OFFSET; /* some older machines with ASP-chip don't support * the enhanced parport modes. diff --git a/drivers/pci/access.c b/drivers/pci/access.c index 24a76de49f41..2a42add7f563 100644 --- a/drivers/pci/access.c +++ b/drivers/pci/access.c @@ -60,3 +60,92 @@ EXPORT_SYMBOL(pci_bus_read_config_dword); EXPORT_SYMBOL(pci_bus_write_config_byte); EXPORT_SYMBOL(pci_bus_write_config_word); EXPORT_SYMBOL(pci_bus_write_config_dword); + +static u32 pci_user_cached_config(struct pci_dev *dev, int pos) +{ + u32 data; + + data = dev->saved_config_space[pos/sizeof(dev->saved_config_space[0])]; + data >>= (pos % sizeof(dev->saved_config_space[0])) * 8; + return data; +} + +#define PCI_USER_READ_CONFIG(size,type) \ +int pci_user_read_config_##size \ + (struct pci_dev *dev, int pos, type *val) \ +{ \ + unsigned long flags; \ + int ret = 0; \ + u32 data = -1; \ + if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER; \ + spin_lock_irqsave(&pci_lock, flags); \ + if (likely(!dev->block_ucfg_access)) \ + ret = dev->bus->ops->read(dev->bus, dev->devfn, \ + pos, sizeof(type), &data); \ + else if (pos < sizeof(dev->saved_config_space)) \ + data = pci_user_cached_config(dev, pos); \ + spin_unlock_irqrestore(&pci_lock, flags); \ + *val = (type)data; \ + return ret; \ +} + +#define PCI_USER_WRITE_CONFIG(size,type) \ +int pci_user_write_config_##size \ + (struct pci_dev *dev, int pos, type val) \ +{ \ + unsigned long flags; \ + int ret = -EIO; \ + if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER; \ + spin_lock_irqsave(&pci_lock, flags); \ + if (likely(!dev->block_ucfg_access)) \ + ret = dev->bus->ops->write(dev->bus, dev->devfn, \ + pos, sizeof(type), val); \ + spin_unlock_irqrestore(&pci_lock, flags); \ + return ret; \ +} + +PCI_USER_READ_CONFIG(byte, u8) +PCI_USER_READ_CONFIG(word, u16) +PCI_USER_READ_CONFIG(dword, u32) +PCI_USER_WRITE_CONFIG(byte, u8) +PCI_USER_WRITE_CONFIG(word, u16) +PCI_USER_WRITE_CONFIG(dword, u32) + +/** + * pci_block_user_cfg_access - Block userspace PCI config reads/writes + * @dev: pci device struct + * + * This function blocks any userspace PCI config accesses from occurring. + * When blocked, any writes will be bit bucketed and reads will return the + * data saved using pci_save_state for the first 64 bytes of config + * space and return 0xff for all other config reads. + **/ +void pci_block_user_cfg_access(struct pci_dev *dev) +{ + unsigned long flags; + + pci_save_state(dev); + + /* spinlock to synchronize with anyone reading config space now */ + spin_lock_irqsave(&pci_lock, flags); + dev->block_ucfg_access = 1; + spin_unlock_irqrestore(&pci_lock, flags); +} +EXPORT_SYMBOL_GPL(pci_block_user_cfg_access); + +/** + * pci_unblock_user_cfg_access - Unblock userspace PCI config reads/writes + * @dev: pci device struct + * + * This function allows userspace PCI config accesses to resume. + **/ +void pci_unblock_user_cfg_access(struct pci_dev *dev) +{ + unsigned long flags; + + /* spinlock to synchronize with anyone reading saved config space */ + spin_lock_irqsave(&pci_lock, flags); + dev->block_ucfg_access = 0; + spin_unlock_irqrestore(&pci_lock, flags); +} +EXPORT_SYMBOL_GPL(pci_unblock_user_cfg_access); diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 424e7de181ae..8e21f6ab89a1 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -58,6 +58,9 @@ static LIST_HEAD(bridge_list); static void handle_hotplug_event_bridge (acpi_handle, u32, void *); static void handle_hotplug_event_func (acpi_handle, u32, void *); +static void acpiphp_sanitize_bus(struct pci_bus *bus); +static void acpiphp_set_hpp_values(acpi_handle handle, struct pci_bus *bus); + /* * initialization & terminatation routines @@ -796,8 +799,13 @@ static int enable_device(struct acpiphp_slot *slot) } } + pci_bus_size_bridges(bus); pci_bus_assign_resources(bus); + acpiphp_sanitize_bus(bus); + pci_enable_bridges(bus); pci_bus_add_devices(bus); + acpiphp_set_hpp_values(DEVICE_ACPI_HANDLE(&bus->self->dev), bus); + acpiphp_configure_ioapics(DEVICE_ACPI_HANDLE(&bus->self->dev)); /* associate pci_dev to our representation */ list_for_each (l, &slot->funcs) { diff --git a/drivers/pci/hotplug/cpcihp_generic.c b/drivers/pci/hotplug/cpcihp_generic.c index a62a4345b466..2d4639d6841f 100644 --- a/drivers/pci/hotplug/cpcihp_generic.c +++ b/drivers/pci/hotplug/cpcihp_generic.c @@ -39,6 +39,7 @@ #include <linux/init.h> #include <linux/errno.h> #include <linux/pci.h> +#include <linux/string.h> #include "cpci_hotplug.h" #define DRIVER_VERSION "0.1" diff --git a/drivers/pci/hotplug/cpcihp_zt5550.c b/drivers/pci/hotplug/cpcihp_zt5550.c index e9928024be78..f7cb00da38df 100644 --- a/drivers/pci/hotplug/cpcihp_zt5550.c +++ b/drivers/pci/hotplug/cpcihp_zt5550.c @@ -36,6 +36,7 @@ #include <linux/init.h> #include <linux/errno.h> #include <linux/pci.h> +#include <linux/signal.h> /* SA_SHIRQ */ #include "cpci_hotplug.h" #include "cpcihp_zt5550.h" @@ -78,11 +79,20 @@ static void __iomem *csr_int_mask; static int zt5550_hc_config(struct pci_dev *pdev) { + int ret; + /* Since we know that no boards exist with two HC chips, treat it as an error */ if(hc_dev) { err("too many host controller devices?"); return -EBUSY; } + + ret = pci_enable_device(pdev); + if(ret) { + err("cannot enable %s\n", pci_name(pdev)); + return ret; + } + hc_dev = pdev; dbg("hc_dev = %p", hc_dev); dbg("pci resource start %lx", pci_resource_start(hc_dev, 1)); @@ -91,7 +101,8 @@ static int zt5550_hc_config(struct pci_dev *pdev) if(!request_mem_region(pci_resource_start(hc_dev, 1), pci_resource_len(hc_dev, 1), MY_NAME)) { err("cannot reserve MMIO region"); - return -ENOMEM; + ret = -ENOMEM; + goto exit_disable_device; } hc_registers = @@ -99,9 +110,8 @@ static int zt5550_hc_config(struct pci_dev *pdev) if(!hc_registers) { err("cannot remap MMIO region %lx @ %lx", pci_resource_len(hc_dev, 1), pci_resource_start(hc_dev, 1)); - release_mem_region(pci_resource_start(hc_dev, 1), - pci_resource_len(hc_dev, 1)); - return -ENODEV; + ret = -ENODEV; + goto exit_release_region; } csr_hc_index = hc_registers + CSR_HCINDEX; @@ -124,6 +134,13 @@ static int zt5550_hc_config(struct pci_dev *pdev) writeb((u8) ALL_DIRECT_INTS_MASK, csr_int_mask); dbg("disabled timer0, timer1 and ENUM interrupts"); return 0; + +exit_release_region: + release_mem_region(pci_resource_start(hc_dev, 1), + pci_resource_len(hc_dev, 1)); +exit_disable_device: + pci_disable_device(hc_dev); + return ret; } static int zt5550_hc_cleanup(void) @@ -134,6 +151,7 @@ static int zt5550_hc_cleanup(void) iounmap(hc_registers); release_mem_region(pci_resource_start(hc_dev, 1), pci_resource_len(hc_dev, 1)); + pci_disable_device(hc_dev); return 0; } diff --git a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c index 8c6d3987d461..9aed8efe6a11 100644 --- a/drivers/pci/hotplug/cpqphp_core.c +++ b/drivers/pci/hotplug/cpqphp_core.c @@ -794,12 +794,21 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) u32 rc; struct controller *ctrl; struct pci_func *func; + int err; + + err = pci_enable_device(pdev); + if (err) { + printk(KERN_ERR MY_NAME ": cannot enable PCI device %s (%d)\n", + pci_name(pdev), err); + return err; + } // Need to read VID early b/c it's used to differentiate CPQ and INTC discovery rc = pci_read_config_word(pdev, PCI_VENDOR_ID, &vendor_id); if (rc || ((vendor_id != PCI_VENDOR_ID_COMPAQ) && (vendor_id != PCI_VENDOR_ID_INTEL))) { err(msg_HPC_non_compaq_or_intel); - return -ENODEV; + rc = -ENODEV; + goto err_disable_device; } dbg("Vendor ID: %x\n", vendor_id); @@ -807,7 +816,8 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) dbg("revision: %d\n", rev); if (rc || ((vendor_id == PCI_VENDOR_ID_COMPAQ) && (!rev))) { err(msg_HPC_rev_error); - return -ENODEV; + rc = -ENODEV; + goto err_disable_device; } /* Check for the proper subsytem ID's @@ -820,18 +830,20 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) rc = pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vid); if (rc) { err("%s : pci_read_config_word failed\n", __FUNCTION__); - return rc; + goto err_disable_device; } dbg("Subsystem Vendor ID: %x\n", subsystem_vid); if ((subsystem_vid != PCI_VENDOR_ID_COMPAQ) && (subsystem_vid != PCI_VENDOR_ID_INTEL)) { err(msg_HPC_non_compaq_or_intel); - return -ENODEV; + rc = -ENODEV; + goto err_disable_device; } ctrl = (struct controller *) kmalloc(sizeof(struct controller), GFP_KERNEL); if (!ctrl) { err("%s : out of memory\n", __FUNCTION__); - return -ENOMEM; + rc = -ENOMEM; + goto err_disable_device; } memset(ctrl, 0, sizeof(struct controller)); @@ -1264,6 +1276,8 @@ err_free_bus: kfree(ctrl->pci_bus); err_free_ctrl: kfree(ctrl); +err_disable_device: + pci_disable_device(pdev); return rc; } diff --git a/drivers/pci/hotplug/fakephp.c b/drivers/pci/hotplug/fakephp.c index 8e47fa66e25e..060d74775d7b 100644 --- a/drivers/pci/hotplug/fakephp.c +++ b/drivers/pci/hotplug/fakephp.c @@ -37,6 +37,8 @@ #include <linux/module.h> #include <linux/pci.h> #include <linux/init.h> +#include <linux/string.h> +#include <linux/slab.h> #include "pci_hotplug.h" #include "../pci.h" diff --git a/drivers/pci/hotplug/ibmphp_core.c b/drivers/pci/hotplug/ibmphp_core.c index 0392e004258f..aabf1e70b528 100644 --- a/drivers/pci/hotplug/ibmphp_core.c +++ b/drivers/pci/hotplug/ibmphp_core.c @@ -1077,7 +1077,7 @@ static int enable_slot(struct hotplug_slot *hs) if (rc) { err("Adding this card exceeds the limitations of this bus.\n"); err("(i.e., >1 133MHz cards running on same bus, or " - ">2 66 PCI cards running on same bus\n."); + ">2 66 PCI cards running on same bus.\n"); err("Try hot-adding into another bus\n"); rc = -EINVAL; goto error_nopower; diff --git a/drivers/pci/hotplug/pciehp_pci.c b/drivers/pci/hotplug/pciehp_pci.c index 33b539b34f7e..ff17d8e07e94 100644 --- a/drivers/pci/hotplug/pciehp_pci.c +++ b/drivers/pci/hotplug/pciehp_pci.c @@ -113,7 +113,7 @@ int pciehp_unconfigure_device(struct pci_func* func) */ int pciehp_set_irq (u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num) { -#if defined(CONFIG_X86) && !defined(CONFIG_X86_IO_APIC) && !defined(CONFIG_X86_64) +#if defined(CONFIG_X86_32) && !defined(CONFIG_X86_IO_APIC) int rc; u16 temp_word; struct pci_dev fakedev; diff --git a/drivers/pci/hotplug/pciehprm_nonacpi.c b/drivers/pci/hotplug/pciehprm_nonacpi.c index 3622965f8961..33b2c69a0829 100644 --- a/drivers/pci/hotplug/pciehprm_nonacpi.c +++ b/drivers/pci/hotplug/pciehprm_nonacpi.c @@ -33,10 +33,13 @@ #include <linux/types.h> #include <linux/pci.h> #include <linux/init.h> +#include <linux/slab.h> + #include <asm/uaccess.h> #ifdef CONFIG_IA64 #include <asm/iosapic.h> #endif + #include "pciehp.h" #include "pciehprm.h" #include "pciehprm_nonacpi.h" diff --git a/drivers/pci/hotplug/rpadlpar_core.c b/drivers/pci/hotplug/rpadlpar_core.c index ad1017da8656..fcb66b9a0e28 100644 --- a/drivers/pci/hotplug/rpadlpar_core.c +++ b/drivers/pci/hotplug/rpadlpar_core.c @@ -16,10 +16,13 @@ */ #include <linux/init.h> #include <linux/pci.h> +#include <linux/string.h> + #include <asm/pci-bridge.h> #include <asm/semaphore.h> #include <asm/rtas.h> #include <asm/vio.h> + #include "../pci.h" #include "rpaphp.h" #include "rpadlpar.h" diff --git a/drivers/pci/hotplug/rpaphp.h b/drivers/pci/hotplug/rpaphp.h index 61d94d1e29cb..71ea5f9bb284 100644 --- a/drivers/pci/hotplug/rpaphp.h +++ b/drivers/pci/hotplug/rpaphp.h @@ -92,9 +92,10 @@ extern struct pci_bus *rpaphp_find_pci_bus(struct device_node *dn); extern int rpaphp_claim_resource(struct pci_dev *dev, int resource); extern int rpaphp_enable_pci_slot(struct slot *slot); extern int register_pci_slot(struct slot *slot); -extern int rpaphp_unconfig_pci_adapter(struct slot *slot); extern int rpaphp_get_pci_adapter_status(struct slot *slot, int is_init, u8 * value); + extern int rpaphp_config_pci_adapter(struct pci_bus *bus); +extern int rpaphp_unconfig_pci_adapter(struct pci_bus *bus); /* rpaphp_core.c */ extern int rpaphp_add_slot(struct device_node *dn); diff --git a/drivers/pci/hotplug/rpaphp_core.c b/drivers/pci/hotplug/rpaphp_core.c index c830ff0acdc3..cf075c34b578 100644 --- a/drivers/pci/hotplug/rpaphp_core.c +++ b/drivers/pci/hotplug/rpaphp_core.c @@ -426,8 +426,11 @@ static int disable_slot(struct hotplug_slot *hotplug_slot) dbg("DISABLING SLOT %s\n", slot->name); down(&rpaphp_sem); - retval = rpaphp_unconfig_pci_adapter(slot); + retval = rpaphp_unconfig_pci_adapter(slot->bus); up(&rpaphp_sem); + slot->state = NOT_CONFIGURED; + info("%s: devices in slot[%s] unconfigured.\n", __FUNCTION__, + slot->name); exit: dbg("%s - Exit: rc[%d]\n", __FUNCTION__, retval); return retval; diff --git a/drivers/pci/hotplug/rpaphp_pci.c b/drivers/pci/hotplug/rpaphp_pci.c index 49e4d10a6488..f7c12d7dfcfc 100644 --- a/drivers/pci/hotplug/rpaphp_pci.c +++ b/drivers/pci/hotplug/rpaphp_pci.c @@ -23,11 +23,13 @@ * */ #include <linux/pci.h> +#include <linux/string.h> + #include <asm/pci-bridge.h> #include <asm/rtas.h> #include <asm/machdep.h> -#include "../pci.h" /* for pci_add_new_bus */ +#include "../pci.h" /* for pci_add_new_bus */ #include "rpaphp.h" static struct pci_bus *find_bus_among_children(struct pci_bus *bus, @@ -319,20 +321,15 @@ static void rpaphp_eeh_remove_bus_device(struct pci_dev *dev) return; } -int rpaphp_unconfig_pci_adapter(struct slot *slot) +int rpaphp_unconfig_pci_adapter(struct pci_bus *bus) { struct pci_dev *dev, *tmp; - int retval = 0; - list_for_each_entry_safe(dev, tmp, slot->pci_devs, bus_list) { + list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) { rpaphp_eeh_remove_bus_device(dev); pci_remove_bus_device(dev); } - - slot->state = NOT_CONFIGURED; - info("%s: devices in slot[%s] unconfigured.\n", __FUNCTION__, - slot->name); - return retval; + return 0; } static int setup_pci_hotplug_slot_info(struct slot *slot) diff --git a/drivers/pci/hotplug/rpaphp_slot.c b/drivers/pci/hotplug/rpaphp_slot.c index 0e8815495083..daa89ae57123 100644 --- a/drivers/pci/hotplug/rpaphp_slot.c +++ b/drivers/pci/hotplug/rpaphp_slot.c @@ -27,6 +27,9 @@ #include <linux/kobject.h> #include <linux/sysfs.h> #include <linux/pci.h> +#include <linux/string.h> +#include <linux/slab.h> + #include <asm/rtas.h> #include "rpaphp.h" diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h index b7d1c61d6bbb..08ad26a0cae7 100644 --- a/drivers/pci/hotplug/shpchp.h +++ b/drivers/pci/hotplug/shpchp.h @@ -32,8 +32,8 @@ #include <linux/types.h> #include <linux/pci.h> #include <linux/delay.h> -#include <asm/semaphore.h> -#include <asm/io.h> +#include <linux/sched.h> /* signal_pending(), struct timer_list */ + #include "pci_hotplug.h" #if !defined(MODULE) @@ -52,42 +52,18 @@ extern int shpchp_debug; #define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg) #define warn(format, arg...) printk(KERN_WARNING "%s: " format, MY_NAME , ## arg) -struct pci_func { - struct pci_func *next; - u8 bus; - u8 device; - u8 function; - u8 is_a_board; - u16 status; - u8 configured; - u8 switch_save; - u8 presence_save; - u8 pwr_save; - u32 base_length[0x06]; - u8 base_type[0x06]; - u16 reserved2; - u32 config_space[0x20]; - struct pci_resource *mem_head; - struct pci_resource *p_mem_head; - struct pci_resource *io_head; - struct pci_resource *bus_head; - struct pci_dev* pci_dev; -}; - #define SLOT_MAGIC 0x67267321 struct slot { u32 magic; struct slot *next; u8 bus; u8 device; + u16 status; u32 number; u8 is_a_board; - u8 configured; u8 state; - u8 switch_save; u8 presence_save; - u32 capabilities; - u16 reserved2; + u8 pwr_save; struct timer_list task_event; u8 hp_slot; struct controller *ctrl; @@ -96,12 +72,6 @@ struct slot { struct list_head slot_list; }; -struct pci_resource { - struct pci_resource * next; - u32 base; - u32 length; -}; - struct event_info { u32 event_type; u8 hp_slot; @@ -110,13 +80,9 @@ struct event_info { struct controller { struct controller *next; struct semaphore crit_sect; /* critical section semaphore */ - void * hpc_ctlr_handle; /* HPC controller handle */ + struct php_ctlr_state_s *hpc_ctlr_handle; /* HPC controller handle */ int num_slots; /* Number of slots on ctlr */ int slot_num_inc; /* 1 or -1 */ - struct pci_resource *mem_head; - struct pci_resource *p_mem_head; - struct pci_resource *io_head; - struct pci_resource *bus_head; struct pci_dev *pci_dev; struct pci_bus *pci_bus; struct event_info event_queue[10]; @@ -124,33 +90,21 @@ struct controller { struct hpc_ops *hpc_ops; wait_queue_head_t queue; /* sleep & wake process */ u8 next_event; - u8 seg; u8 bus; u8 device; u8 function; - u8 rev; u8 slot_device_offset; u8 add_support; enum pci_bus_speed speed; u32 first_slot; /* First physical slot number */ u8 slot_bus; /* Bus where the slots handled by this controller sit */ - u8 push_flag; - u16 ctlrcap; - u16 vendor_id; -}; - -struct irq_mapping { - u8 barber_pole; - u8 valid_INT; - u8 interrupt[4]; }; -struct resource_lists { - struct pci_resource *mem_head; - struct pci_resource *p_mem_head; - struct pci_resource *io_head; - struct pci_resource *bus_head; - struct irq_mapping *irqs; +struct hotplug_params { + u8 cache_line_size; + u8 latency_timer; + u8 enable_serr; + u8 enable_perr; }; /* Define AMD SHPC ID */ @@ -194,24 +148,16 @@ struct resource_lists { * error Messages */ #define msg_initialization_err "Initialization failure, error=%d\n" -#define msg_HPC_rev_error "Unsupported revision of the PCI hot plug controller found.\n" -#define msg_HPC_non_shpc "The PCI hot plug controller is not supported by this driver.\n" -#define msg_HPC_not_supported "This system is not supported by this version of shpcphd mdoule. Upgrade to a newer version of shpchpd\n" -#define msg_unable_to_save "Unable to store PCI hot plug add resource information. This system must be rebooted before adding any PCI devices.\n" #define msg_button_on "PCI slot #%d - powering on due to button press.\n" #define msg_button_off "PCI slot #%d - powering off due to button press.\n" #define msg_button_cancel "PCI slot #%d - action canceled due to button press.\n" -#define msg_button_ignore "PCI slot #%d - button press ignored. (action in progress...)\n" /* sysfs functions for the hotplug controller info */ extern void shpchp_create_ctrl_files (struct controller *ctrl); /* controller functions */ -extern int shpchprm_find_available_resources(struct controller *ctrl); extern int shpchp_event_start_thread(void); extern void shpchp_event_stop_thread(void); -extern struct pci_func *shpchp_slot_create(unsigned char busnumber); -extern struct pci_func *shpchp_slot_find(unsigned char bus, unsigned char device, unsigned char index); extern int shpchp_enable_slot(struct slot *slot); extern int shpchp_disable_slot(struct slot *slot); @@ -220,29 +166,20 @@ extern u8 shpchp_handle_switch_change(u8 hp_slot, void *inst_id); extern u8 shpchp_handle_presence_change(u8 hp_slot, void *inst_id); extern u8 shpchp_handle_power_fault(u8 hp_slot, void *inst_id); -/* resource functions */ -extern int shpchp_resource_sort_and_combine(struct pci_resource **head); - /* pci functions */ -extern int shpchp_set_irq(u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num); -/*extern int shpchp_get_bus_dev(struct controller *ctrl, u8 *bus_num, u8 *dev_num, struct slot *slot);*/ extern int shpchp_save_config(struct controller *ctrl, int busnumber, int num_ctlr_slots, int first_device_num); -extern int shpchp_save_used_resources(struct controller *ctrl, struct pci_func * func, int flag); -extern int shpchp_save_slot_config(struct controller *ctrl, struct pci_func * new_slot); -extern void shpchp_destroy_board_resources(struct pci_func * func); -extern int shpchp_return_board_resources(struct pci_func * func, struct resource_lists * resources); -extern void shpchp_destroy_resource_list(struct resource_lists * resources); -extern int shpchp_configure_device(struct controller* ctrl, struct pci_func* func); -extern int shpchp_unconfigure_device(struct pci_func* func); +extern int shpchp_configure_device(struct slot *p_slot); +extern int shpchp_unconfigure_device(struct slot *p_slot); +extern void get_hp_hw_control_from_firmware(struct pci_dev *dev); +extern void get_hp_params_from_firmware(struct pci_dev *dev, + struct hotplug_params *hpp); +extern int shpchprm_get_physical_slot_number(struct controller *ctrl, + u32 *sun, u8 busnum, u8 devnum); +extern void shpchp_remove_ctrl_files(struct controller *ctrl); /* Global variables */ extern struct controller *shpchp_ctrl_list; -extern struct pci_func *shpchp_slot_list[256]; - -/* These are added to support AMD shpc */ -extern u8 shpchp_nic_irq; -extern u8 shpchp_disk_irq; struct ctrl_reg { volatile u32 base_offset; @@ -298,7 +235,7 @@ enum ctrl_offsets { SLOT11 = offsetof(struct ctrl_reg, slot11), SLOT12 = offsetof(struct ctrl_reg, slot12), }; -typedef u8(*php_intr_callback_t) (unsigned int change_id, void *instance_id); +typedef u8(*php_intr_callback_t) (u8 hp_slot, void *instance_id); struct php_ctlr_state_s { struct php_ctlr_state_s *pnext; struct pci_dev *pci_dev; @@ -359,12 +296,9 @@ static inline struct slot *shpchp_find_slot (struct controller *ctrl, u8 device) p_slot = ctrl->slot; - dbg("p_slot = %p\n", p_slot); - while (p_slot && (p_slot->device != device)) { tmp_slot = p_slot; p_slot = p_slot->next; - dbg("In while loop, p_slot = %p\n", p_slot); } if (p_slot == NULL) { err("ERROR: shpchp_find_slot device=0x%x\n", device); @@ -379,8 +313,6 @@ static inline int wait_for_ctrl_irq (struct controller *ctrl) DECLARE_WAITQUEUE(wait, current); int retval = 0; - dbg("%s : start\n",__FUNCTION__); - add_wait_queue(&ctrl->queue, &wait); if (!shpchp_poll_mode) { @@ -394,19 +326,9 @@ static inline int wait_for_ctrl_irq (struct controller *ctrl) if (signal_pending(current)) retval = -EINTR; - dbg("%s : end\n", __FUNCTION__); return retval; } -/* Puts node back in the resource list pointed to by head */ -static inline void return_resource(struct pci_resource **head, struct pci_resource *node) -{ - if (!node || !head) - return; - node->next = *head; - *head = node; -} - #define SLOT_NAME_SIZE 10 static inline void make_slot_name(char *buffer, int buffer_size, struct slot *slot) @@ -420,11 +342,7 @@ enum php_ctlr_type { ACPI }; -int shpc_init( struct controller *ctrl, struct pci_dev *pdev, - php_intr_callback_t attention_button_callback, - php_intr_callback_t switch_change_callback, - php_intr_callback_t presence_change_callback, - php_intr_callback_t power_fault_callback); +int shpc_init( struct controller *ctrl, struct pci_dev *pdev); int shpc_get_ctlr_slot_config( struct controller *ctrl, int *num_ctlr_slots, @@ -437,8 +355,6 @@ struct hpc_ops { int (*power_on_slot ) (struct slot *slot); int (*slot_enable ) (struct slot *slot); int (*slot_disable ) (struct slot *slot); - int (*enable_all_slots) (struct slot *slot); - int (*pwr_on_all_slots) (struct slot *slot); int (*set_bus_speed_mode) (struct slot *slot, enum pci_bus_speed speed); int (*get_power_status) (struct slot *slot, u8 *status); int (*get_attention_status) (struct slot *slot, u8 *status); diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c index 6f7d8a29957a..63628e01dd43 100644 --- a/drivers/pci/hotplug/shpchp_core.c +++ b/drivers/pci/hotplug/shpchp_core.c @@ -27,26 +27,18 @@ * */ -#include <linux/config.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/kernel.h> #include <linux/types.h> -#include <linux/proc_fs.h> -#include <linux/slab.h> -#include <linux/workqueue.h> #include <linux/pci.h> -#include <linux/init.h> -#include <asm/uaccess.h> #include "shpchp.h" -#include "shpchprm.h" /* Global variables */ int shpchp_debug; int shpchp_poll_mode; int shpchp_poll_time; struct controller *shpchp_ctrl_list; /* = NULL */ -struct pci_func *shpchp_slot_list[256]; #define DRIVER_VERSION "0.4" #define DRIVER_AUTHOR "Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>, Dely Sy <dely.l.sy@intel.com>" @@ -113,8 +105,6 @@ static int init_slots(struct controller *ctrl) u32 slot_number, sun; int result = -ENOMEM; - dbg("%s\n",__FUNCTION__); - number_of_slots = ctrl->num_slots; slot_device = ctrl->slot_device_offset; slot_number = ctrl->first_slot; @@ -352,6 +342,17 @@ static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_sp return 0; } +static int is_shpc_capable(struct pci_dev *dev) +{ + if ((dev->vendor == PCI_VENDOR_ID_AMD) || (dev->device == + PCI_DEVICE_ID_AMD_GOLAM_7450)) + return 1; + if (pci_find_capability(dev, PCI_CAP_ID_SHPC)) + return 1; + + return 0; +} + static int shpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { int rc; @@ -360,6 +361,9 @@ static int shpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) int first_device_num; /* first PCI device number supported by this SHPC */ int num_ctlr_slots; /* number of slots supported by this SHPC */ + if (!is_shpc_capable(pdev)) + return -ENODEV; + ctrl = (struct controller *) kmalloc(sizeof(struct controller), GFP_KERNEL); if (!ctrl) { err("%s : out of memory\n", __FUNCTION__); @@ -367,19 +371,12 @@ static int shpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) } memset(ctrl, 0, sizeof(struct controller)); - dbg("DRV_thread pid = %d\n", current->pid); - - rc = shpc_init(ctrl, pdev, - (php_intr_callback_t) shpchp_handle_attention_button, - (php_intr_callback_t) shpchp_handle_switch_change, - (php_intr_callback_t) shpchp_handle_presence_change, - (php_intr_callback_t) shpchp_handle_power_fault); + rc = shpc_init(ctrl, pdev); if (rc) { dbg("%s: controller initialization failed\n", SHPC_MODULE_NAME); goto err_out_free_ctrl; } - dbg("%s: controller initialization success\n", __FUNCTION__); ctrl->pci_dev = pdev; /* pci_dev of the P2P bridge */ pci_set_drvdata(pdev, ctrl); @@ -411,23 +408,8 @@ static int shpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) first_device_num = ctrl->slot_device_offset; num_ctlr_slots = ctrl->num_slots; - /* Store PCI Config Space for all devices on this bus */ - rc = shpchp_save_config(ctrl, ctrl->slot_bus, num_ctlr_slots, first_device_num); - if (rc) { - err("%s: unable to save PCI configuration data, error %d\n", __FUNCTION__, rc); - goto err_out_free_ctrl_bus; - } - - /* Get IO, memory, and IRQ resources for new devices */ - rc = shpchprm_find_available_resources(ctrl); - ctrl->add_support = !rc; + ctrl->add_support = 1; - if (rc) { - dbg("shpchprm_find_available_resources = %#x\n", rc); - err("unable to locate PCI configuration resources for hot plug add.\n"); - goto err_out_free_ctrl_bus; - } - /* Setup the slot information structures */ rc = init_slots(ctrl); if (rc) { @@ -477,7 +459,6 @@ err_out_none: static int shpc_start_thread(void) { - int loop; int retval = 0; dbg("Initialize + Start the notification/polling mechanism \n"); @@ -488,48 +469,21 @@ static int shpc_start_thread(void) return retval; } - dbg("Initialize slot lists\n"); - /* One slot list for each bus in the system */ - for (loop = 0; loop < 256; loop++) { - shpchp_slot_list[loop] = NULL; - } - return retval; } -static inline void __exit -free_shpchp_res(struct pci_resource *res) -{ - struct pci_resource *tres; - - while (res) { - tres = res; - res = res->next; - kfree(tres); - } -} - static void __exit unload_shpchpd(void) { - struct pci_func *next; - struct pci_func *TempSlot; - int loop; struct controller *ctrl; struct controller *tctrl; ctrl = shpchp_ctrl_list; while (ctrl) { + shpchp_remove_ctrl_files(ctrl); cleanup_slots(ctrl); - free_shpchp_res(ctrl->io_head); - free_shpchp_res(ctrl->mem_head); - free_shpchp_res(ctrl->p_mem_head); - free_shpchp_res(ctrl->bus_head); - kfree (ctrl->pci_bus); - - dbg("%s: calling release_ctlr\n", __FUNCTION__); ctrl->hpc_ops->release_ctlr(ctrl); tctrl = ctrl; @@ -538,20 +492,6 @@ static void __exit unload_shpchpd(void) kfree(tctrl); } - for (loop = 0; loop < 256; loop++) { - next = shpchp_slot_list[loop]; - while (next != NULL) { - free_shpchp_res(next->io_head); - free_shpchp_res(next->mem_head); - free_shpchp_res(next->p_mem_head); - free_shpchp_res(next->bus_head); - - TempSlot = next; - next = next->next; - kfree(TempSlot); - } - } - /* Stop the notification mechanism */ shpchp_event_stop_thread(); @@ -596,20 +536,14 @@ static int __init shpcd_init(void) if (retval) goto error_hpc_init; - retval = shpchprm_init(PCI); - if (!retval) { - retval = pci_register_driver(&shpc_driver); - dbg("%s: pci_register_driver = %d\n", __FUNCTION__, retval); - info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); - } + retval = pci_register_driver(&shpc_driver); + dbg("%s: pci_register_driver = %d\n", __FUNCTION__, retval); + info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); error_hpc_init: if (retval) { - shpchprm_cleanup(); shpchp_event_stop_thread(); - } else - shpchprm_print_pirt(); - + } return retval; } @@ -618,9 +552,6 @@ static void __exit shpcd_cleanup(void) dbg("unload_shpchpd()\n"); unload_shpchpd(); - shpchprm_cleanup(); - - dbg("pci_unregister_driver\n"); pci_unregister_driver(&shpc_driver); info(DRIVER_DESC " version: " DRIVER_VERSION " unloaded\n"); diff --git a/drivers/pci/hotplug/shpchp_ctrl.c b/drivers/pci/hotplug/shpchp_ctrl.c index 91c9903e621f..58619359ad08 100644 --- a/drivers/pci/hotplug/shpchp_ctrl.c +++ b/drivers/pci/hotplug/shpchp_ctrl.c @@ -27,24 +27,14 @@ * */ -#include <linux/config.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/types.h> -#include <linux/slab.h> -#include <linux/workqueue.h> -#include <linux/interrupt.h> -#include <linux/delay.h> -#include <linux/wait.h> #include <linux/smp_lock.h> #include <linux/pci.h> +#include "../pci.h" #include "shpchp.h" -#include "shpchprm.h" -static u32 configure_new_device(struct controller *ctrl, struct pci_func *func, - u8 behind_bridge, struct resource_lists *resources, u8 bridge_bus, u8 bridge_dev); -static int configure_new_function( struct controller *ctrl, struct pci_func *func, - u8 behind_bridge, struct resource_lists *resources, u8 bridge_bus, u8 bridge_dev); static void interrupt_event_handler(struct controller *ctrl); static struct semaphore event_semaphore; /* mutex for process loop (up if something to process) */ @@ -52,28 +42,22 @@ static struct semaphore event_exit; /* guard ensure thread has exited before ca static int event_finished; static unsigned long pushbutton_pending; /* = 0 */ -u8 shpchp_disk_irq; -u8 shpchp_nic_irq; - u8 shpchp_handle_attention_button(u8 hp_slot, void *inst_id) { struct controller *ctrl = (struct controller *) inst_id; struct slot *p_slot; u8 rc = 0; u8 getstatus; - struct pci_func *func; struct event_info *taskInfo; /* Attention Button Change */ dbg("shpchp: Attention button interrupt received.\n"); - func = shpchp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0); - /* This is the structure that tells the worker thread what to do */ taskInfo = &(ctrl->event_queue[ctrl->next_event]); p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); - p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save)); + p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save)); p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); ctrl->next_event = (ctrl->next_event + 1) % 10; @@ -118,14 +102,11 @@ u8 shpchp_handle_switch_change(u8 hp_slot, void *inst_id) struct slot *p_slot; u8 rc = 0; u8 getstatus; - struct pci_func *func; struct event_info *taskInfo; /* Switch Change */ dbg("shpchp: Switch interrupt received.\n"); - func = shpchp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0); - /* This is the structure that tells the worker thread * what to do */ @@ -135,19 +116,18 @@ u8 shpchp_handle_switch_change(u8 hp_slot, void *inst_id) rc++; p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); - p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save)); + p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save)); p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); dbg("%s: Card present %x Power status %x\n", __FUNCTION__, - func->presence_save, func->pwr_save); + p_slot->presence_save, p_slot->pwr_save); if (getstatus) { /* * Switch opened */ info("Latch open on Slot(%d)\n", ctrl->first_slot + hp_slot); - func->switch_save = 0; taskInfo->event_type = INT_SWITCH_OPEN; - if (func->pwr_save && func->presence_save) { + if (p_slot->pwr_save && p_slot->presence_save) { taskInfo->event_type = INT_POWER_FAULT; err("Surprise Removal of card\n"); } @@ -156,7 +136,6 @@ u8 shpchp_handle_switch_change(u8 hp_slot, void *inst_id) * Switch closed */ info("Latch close on Slot(%d)\n", ctrl->first_slot + hp_slot); - func->switch_save = 0x10; taskInfo->event_type = INT_SWITCH_CLOSE; } @@ -172,14 +151,11 @@ u8 shpchp_handle_presence_change(u8 hp_slot, void *inst_id) struct slot *p_slot; u8 rc = 0; /*u8 temp_byte;*/ - struct pci_func *func; struct event_info *taskInfo; /* Presence Change */ dbg("shpchp: Presence/Notify input change.\n"); - func = shpchp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0); - /* This is the structure that tells the worker thread * what to do */ @@ -193,8 +169,8 @@ u8 shpchp_handle_presence_change(u8 hp_slot, void *inst_id) /* * Save the presence state */ - p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save)); - if (func->presence_save) { + p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save)); + if (p_slot->presence_save) { /* * Card Present */ @@ -219,14 +195,11 @@ u8 shpchp_handle_power_fault(u8 hp_slot, void *inst_id) struct controller *ctrl = (struct controller *) inst_id; struct slot *p_slot; u8 rc = 0; - struct pci_func *func; struct event_info *taskInfo; /* Power fault */ dbg("shpchp: Power fault interrupt received.\n"); - func = shpchp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0); - /* This is the structure that tells the worker thread * what to do */ @@ -242,7 +215,7 @@ u8 shpchp_handle_power_fault(u8 hp_slot, void *inst_id) * Power fault Cleared */ info("Power fault cleared on Slot(%d)\n", ctrl->first_slot + hp_slot); - func->status = 0x00; + p_slot->status = 0x00; taskInfo->event_type = INT_POWER_FAULT_CLEAR; } else { /* @@ -251,7 +224,7 @@ u8 shpchp_handle_power_fault(u8 hp_slot, void *inst_id) info("Power fault on Slot(%d)\n", ctrl->first_slot + hp_slot); taskInfo->event_type = INT_POWER_FAULT; /* set power fault status for this board */ - func->status = 0xFF; + p_slot->status = 0xFF; info("power fault bit %x set\n", hp_slot); } if (rc) @@ -260,799 +233,13 @@ u8 shpchp_handle_power_fault(u8 hp_slot, void *inst_id) return rc; } - -/* - * sort_by_size - * - * Sorts nodes on the list by their length. - * Smallest first. - * - */ -static int sort_by_size(struct pci_resource **head) -{ - struct pci_resource *current_res; - struct pci_resource *next_res; - int out_of_order = 1; - - if (!(*head)) - return(1); - - if (!((*head)->next)) - return(0); - - while (out_of_order) { - out_of_order = 0; - - /* Special case for swapping list head */ - if (((*head)->next) && - ((*head)->length > (*head)->next->length)) { - out_of_order++; - current_res = *head; - *head = (*head)->next; - current_res->next = (*head)->next; - (*head)->next = current_res; - } - - current_res = *head; - - while (current_res->next && current_res->next->next) { - if (current_res->next->length > current_res->next->next->length) { - out_of_order++; - next_res = current_res->next; - current_res->next = current_res->next->next; - current_res = current_res->next; - next_res->next = current_res->next; - current_res->next = next_res; - } else - current_res = current_res->next; - } - } /* End of out_of_order loop */ - - return(0); -} - - -/* - * sort_by_max_size - * - * Sorts nodes on the list by their length. - * Largest first. - * - */ -static int sort_by_max_size(struct pci_resource **head) -{ - struct pci_resource *current_res; - struct pci_resource *next_res; - int out_of_order = 1; - - if (!(*head)) - return(1); - - if (!((*head)->next)) - return(0); - - while (out_of_order) { - out_of_order = 0; - - /* Special case for swapping list head */ - if (((*head)->next) && - ((*head)->length < (*head)->next->length)) { - out_of_order++; - current_res = *head; - *head = (*head)->next; - current_res->next = (*head)->next; - (*head)->next = current_res; - } - - current_res = *head; - - while (current_res->next && current_res->next->next) { - if (current_res->next->length < current_res->next->next->length) { - out_of_order++; - next_res = current_res->next; - current_res->next = current_res->next->next; - current_res = current_res->next; - next_res->next = current_res->next; - current_res->next = next_res; - } else - current_res = current_res->next; - } - } /* End of out_of_order loop */ - - return(0); -} - - -/* - * do_pre_bridge_resource_split - * - * Returns zero or one node of resources that aren't in use - * - */ -static struct pci_resource *do_pre_bridge_resource_split (struct pci_resource **head, struct pci_resource **orig_head, u32 alignment) -{ - struct pci_resource *prevnode = NULL; - struct pci_resource *node; - struct pci_resource *split_node; - u32 rc; - u32 temp_dword; - dbg("do_pre_bridge_resource_split\n"); - - if (!(*head) || !(*orig_head)) - return(NULL); - - rc = shpchp_resource_sort_and_combine(head); - - if (rc) - return(NULL); - - if ((*head)->base != (*orig_head)->base) - return(NULL); - - if ((*head)->length == (*orig_head)->length) - return(NULL); - - - /* If we got here, there the bridge requires some of the resource, but - * we may be able to split some off of the front - */ - node = *head; - - if (node->length & (alignment -1)) { - /* This one isn't an aligned length, so we'll make a new entry - * and split it up. - */ - split_node = kmalloc(sizeof(*split_node), GFP_KERNEL); - - if (!split_node) - return(NULL); - - temp_dword = (node->length | (alignment-1)) + 1 - alignment; - - split_node->base = node->base; - split_node->length = temp_dword; - - node->length -= temp_dword; - node->base += split_node->length; - - /* Put it in the list */ - *head = split_node; - split_node->next = node; - } - - if (node->length < alignment) { - return(NULL); - } - - /* Now unlink it */ - if (*head == node) { - *head = node->next; - node->next = NULL; - } else { - prevnode = *head; - while (prevnode->next != node) - prevnode = prevnode->next; - - prevnode->next = node->next; - node->next = NULL; - } - - return(node); -} - - -/* - * do_bridge_resource_split - * - * Returns zero or one node of resources that aren't in use - * - */ -static struct pci_resource *do_bridge_resource_split (struct pci_resource **head, u32 alignment) -{ - struct pci_resource *prevnode = NULL; - struct pci_resource *node; - u32 rc; - u32 temp_dword; - - if (!(*head)) - return(NULL); - - rc = shpchp_resource_sort_and_combine(head); - - if (rc) - return(NULL); - - node = *head; - - while (node->next) { - prevnode = node; - node = node->next; - kfree(prevnode); - } - - if (node->length < alignment) { - kfree(node); - return(NULL); - } - - if (node->base & (alignment - 1)) { - /* Short circuit if adjusted size is too small */ - temp_dword = (node->base | (alignment-1)) + 1; - if ((node->length - (temp_dword - node->base)) < alignment) { - kfree(node); - return(NULL); - } - - node->length -= (temp_dword - node->base); - node->base = temp_dword; - } - - if (node->length & (alignment - 1)) { - /* There's stuff in use after this node */ - kfree(node); - return(NULL); - } - - return(node); -} - - -/* - * get_io_resource - * - * this function sorts the resource list by size and then - * returns the first node of "size" length that is not in the - * ISA aliasing window. If it finds a node larger than "size" - * it will split it up. - * - * size must be a power of two. - */ -static struct pci_resource *get_io_resource (struct pci_resource **head, u32 size) -{ - struct pci_resource *prevnode; - struct pci_resource *node; - struct pci_resource *split_node = NULL; - u32 temp_dword; - - if (!(*head)) - return(NULL); - - if ( shpchp_resource_sort_and_combine(head) ) - return(NULL); - - if ( sort_by_size(head) ) - return(NULL); - - for (node = *head; node; node = node->next) { - if (node->length < size) - continue; - - if (node->base & (size - 1)) { - /* This one isn't base aligned properly - so we'll make a new entry and split it up */ - temp_dword = (node->base | (size-1)) + 1; - - /*/ Short circuit if adjusted size is too small */ - if ((node->length - (temp_dword - node->base)) < size) - continue; - - split_node = kmalloc(sizeof(*split_node), GFP_KERNEL); - - if (!split_node) - return(NULL); - - split_node->base = node->base; - split_node->length = temp_dword - node->base; - node->base = temp_dword; - node->length -= split_node->length; - - /* Put it in the list */ - split_node->next = node->next; - node->next = split_node; - } /* End of non-aligned base */ - - /* Don't need to check if too small since we already did */ - if (node->length > size) { - /* This one is longer than we need - so we'll make a new entry and split it up */ - split_node = kmalloc(sizeof(*split_node), GFP_KERNEL); - - if (!split_node) - return(NULL); - - split_node->base = node->base + size; - split_node->length = node->length - size; - node->length = size; - - /* Put it in the list */ - split_node->next = node->next; - node->next = split_node; - } /* End of too big on top end */ - - /* For IO make sure it's not in the ISA aliasing space */ - if (node->base & 0x300L) - continue; - - /* If we got here, then it is the right size - Now take it out of the list */ - if (*head == node) { - *head = node->next; - } else { - prevnode = *head; - while (prevnode->next != node) - prevnode = prevnode->next; - - prevnode->next = node->next; - } - node->next = NULL; - /* Stop looping */ - break; - } - - return(node); -} - - -/* - * get_max_resource - * - * Gets the largest node that is at least "size" big from the - * list pointed to by head. It aligns the node on top and bottom - * to "size" alignment before returning it. - * J.I. modified to put max size limits of; 64M->32M->16M->8M->4M->1M - * This is needed to avoid allocating entire ACPI _CRS res to one child bridge/slot. - */ -static struct pci_resource *get_max_resource (struct pci_resource **head, u32 size) -{ - struct pci_resource *max; - struct pci_resource *temp; - struct pci_resource *split_node; - u32 temp_dword; - u32 max_size[] = { 0x4000000, 0x2000000, 0x1000000, 0x0800000, 0x0400000, 0x0200000, 0x0100000, 0x00 }; - int i; - - if (!(*head)) - return(NULL); - - if (shpchp_resource_sort_and_combine(head)) - return(NULL); - - if (sort_by_max_size(head)) - return(NULL); - - for (max = *head;max; max = max->next) { - - /* If not big enough we could probably just bail, - instead we'll continue to the next. */ - if (max->length < size) - continue; - - if (max->base & (size - 1)) { - /* This one isn't base aligned properly - so we'll make a new entry and split it up */ - temp_dword = (max->base | (size-1)) + 1; - - /* Short circuit if adjusted size is too small */ - if ((max->length - (temp_dword - max->base)) < size) - continue; - - split_node = kmalloc(sizeof(*split_node), GFP_KERNEL); - - if (!split_node) - return(NULL); - - split_node->base = max->base; - split_node->length = temp_dword - max->base; - max->base = temp_dword; - max->length -= split_node->length; - - /* Put it next in the list */ - split_node->next = max->next; - max->next = split_node; - } - - if ((max->base + max->length) & (size - 1)) { - /* This one isn't end aligned properly at the top - so we'll make a new entry and split it up */ - split_node = kmalloc(sizeof(*split_node), GFP_KERNEL); - - if (!split_node) - return(NULL); - temp_dword = ((max->base + max->length) & ~(size - 1)); - split_node->base = temp_dword; - split_node->length = max->length + max->base - - split_node->base; - max->length -= split_node->length; - - /* Put it in the list */ - split_node->next = max->next; - max->next = split_node; - } - - /* Make sure it didn't shrink too much when we aligned it */ - if (max->length < size) - continue; - - for ( i = 0; max_size[i] > size; i++) { - if (max->length > max_size[i]) { - split_node = kmalloc(sizeof(*split_node), - GFP_KERNEL); - if (!split_node) - break; /* return (NULL); */ - split_node->base = max->base + max_size[i]; - split_node->length = max->length - max_size[i]; - max->length = max_size[i]; - /* Put it next in the list */ - split_node->next = max->next; - max->next = split_node; - break; - } - } - - /* Now take it out of the list */ - temp = (struct pci_resource*) *head; - if (temp == max) { - *head = max->next; - } else { - while (temp && temp->next != max) { - temp = temp->next; - } - - temp->next = max->next; - } - - max->next = NULL; - return(max); - } - - /* If we get here, we couldn't find one */ - return(NULL); -} - - -/* - * get_resource - * - * this function sorts the resource list by size and then - * returns the first node of "size" length. If it finds a node - * larger than "size" it will split it up. - * - * size must be a power of two. - */ -static struct pci_resource *get_resource (struct pci_resource **head, u32 size) -{ - struct pci_resource *prevnode; - struct pci_resource *node; - struct pci_resource *split_node; - u32 temp_dword; - - if (!(*head)) - return(NULL); - - if ( shpchp_resource_sort_and_combine(head) ) - return(NULL); - - if ( sort_by_size(head) ) - return(NULL); - - for (node = *head; node; node = node->next) { - dbg("%s: req_size =0x%x node=%p, base=0x%x, length=0x%x\n", - __FUNCTION__, size, node, node->base, node->length); - if (node->length < size) - continue; - - if (node->base & (size - 1)) { - dbg("%s: not aligned\n", __FUNCTION__); - /* this one isn't base aligned properly - so we'll make a new entry and split it up */ - temp_dword = (node->base | (size-1)) + 1; - - /* Short circuit if adjusted size is too small */ - if ((node->length - (temp_dword - node->base)) < size) - continue; - - split_node = kmalloc(sizeof(*split_node), GFP_KERNEL); - - if (!split_node) - return(NULL); - - split_node->base = node->base; - split_node->length = temp_dword - node->base; - node->base = temp_dword; - node->length -= split_node->length; - - /* Put it in the list */ - split_node->next = node->next; - node->next = split_node; - } /* End of non-aligned base */ - - /* Don't need to check if too small since we already did */ - if (node->length > size) { - dbg("%s: too big\n", __FUNCTION__); - /* this one is longer than we need - so we'll make a new entry and split it up */ - split_node = kmalloc(sizeof(*split_node), GFP_KERNEL); - - if (!split_node) - return(NULL); - - split_node->base = node->base + size; - split_node->length = node->length - size; - node->length = size; - - /* Put it in the list */ - split_node->next = node->next; - node->next = split_node; - } /* End of too big on top end */ - - dbg("%s: got one!!!\n", __FUNCTION__); - /* If we got here, then it is the right size - Now take it out of the list */ - if (*head == node) { - *head = node->next; - } else { - prevnode = *head; - while (prevnode->next != node) - prevnode = prevnode->next; - - prevnode->next = node->next; - } - node->next = NULL; - /* Stop looping */ - break; - } - return(node); -} - - -/* - * shpchp_resource_sort_and_combine - * - * Sorts all of the nodes in the list in ascending order by - * their base addresses. Also does garbage collection by - * combining adjacent nodes. - * - * returns 0 if success - */ -int shpchp_resource_sort_and_combine(struct pci_resource **head) -{ - struct pci_resource *node1; - struct pci_resource *node2; - int out_of_order = 1; - - dbg("%s: head = %p, *head = %p\n", __FUNCTION__, head, *head); - - if (!(*head)) - return(1); - - dbg("*head->next = %p\n",(*head)->next); - - if (!(*head)->next) - return(0); /* only one item on the list, already sorted! */ - - dbg("*head->base = 0x%x\n",(*head)->base); - dbg("*head->next->base = 0x%x\n",(*head)->next->base); - while (out_of_order) { - out_of_order = 0; - - /* Special case for swapping list head */ - if (((*head)->next) && - ((*head)->base > (*head)->next->base)) { - node1 = *head; - (*head) = (*head)->next; - node1->next = (*head)->next; - (*head)->next = node1; - out_of_order++; - } - - node1 = (*head); - - while (node1->next && node1->next->next) { - if (node1->next->base > node1->next->next->base) { - out_of_order++; - node2 = node1->next; - node1->next = node1->next->next; - node1 = node1->next; - node2->next = node1->next; - node1->next = node2; - } else - node1 = node1->next; - } - } /* End of out_of_order loop */ - - node1 = *head; - - while (node1 && node1->next) { - if ((node1->base + node1->length) == node1->next->base) { - /* Combine */ - dbg("8..\n"); - node1->length += node1->next->length; - node2 = node1->next; - node1->next = node1->next->next; - kfree(node2); - } else - node1 = node1->next; - } - - return(0); -} - - -/** - * shpchp_slot_create - Creates a node and adds it to the proper bus. - * @busnumber - bus where new node is to be located - * - * Returns pointer to the new node or NULL if unsuccessful - */ -struct pci_func *shpchp_slot_create(u8 busnumber) -{ - struct pci_func *new_slot; - struct pci_func *next; - - new_slot = kmalloc(sizeof(*new_slot), GFP_KERNEL); - - if (new_slot == NULL) { - return(new_slot); - } - - memset(new_slot, 0, sizeof(struct pci_func)); - - new_slot->next = NULL; - new_slot->configured = 1; - - if (shpchp_slot_list[busnumber] == NULL) { - shpchp_slot_list[busnumber] = new_slot; - } else { - next = shpchp_slot_list[busnumber]; - while (next->next != NULL) - next = next->next; - next->next = new_slot; - } - return(new_slot); -} - - -/* - * slot_remove - Removes a node from the linked list of slots. - * @old_slot: slot to remove - * - * Returns 0 if successful, !0 otherwise. - */ -static int slot_remove(struct pci_func * old_slot) -{ - struct pci_func *next; - - if (old_slot == NULL) - return(1); - - next = shpchp_slot_list[old_slot->bus]; - - if (next == NULL) { - return(1); - } - - if (next == old_slot) { - shpchp_slot_list[old_slot->bus] = old_slot->next; - shpchp_destroy_board_resources(old_slot); - kfree(old_slot); - return(0); - } - - while ((next->next != old_slot) && (next->next != NULL)) { - next = next->next; - } - - if (next->next == old_slot) { - next->next = old_slot->next; - shpchp_destroy_board_resources(old_slot); - kfree(old_slot); - return(0); - } else - return(2); -} - - -/** - * bridge_slot_remove - Removes a node from the linked list of slots. - * @bridge: bridge to remove - * - * Returns 0 if successful, !0 otherwise. - */ -static int bridge_slot_remove(struct pci_func *bridge) -{ - u8 subordinateBus, secondaryBus; - u8 tempBus; - struct pci_func *next; - - if (bridge == NULL) - return(1); - - secondaryBus = (bridge->config_space[0x06] >> 8) & 0xFF; - subordinateBus = (bridge->config_space[0x06] >> 16) & 0xFF; - - for (tempBus = secondaryBus; tempBus <= subordinateBus; tempBus++) { - next = shpchp_slot_list[tempBus]; - - while (!slot_remove(next)) { - next = shpchp_slot_list[tempBus]; - } - } - - next = shpchp_slot_list[bridge->bus]; - - if (next == NULL) { - return(1); - } - - if (next == bridge) { - shpchp_slot_list[bridge->bus] = bridge->next; - kfree(bridge); - return(0); - } - - while ((next->next != bridge) && (next->next != NULL)) { - next = next->next; - } - - if (next->next == bridge) { - next->next = bridge->next; - kfree(bridge); - return(0); - } else - return(2); -} - - -/** - * shpchp_slot_find - Looks for a node by bus, and device, multiple functions accessed - * @bus: bus to find - * @device: device to find - * @index: is 0 for first function found, 1 for the second... - * - * Returns pointer to the node if successful, %NULL otherwise. - */ -struct pci_func *shpchp_slot_find(u8 bus, u8 device, u8 index) -{ - int found = -1; - struct pci_func *func; - - func = shpchp_slot_list[bus]; - - if ((func == NULL) || ((func->device == device) && (index == 0))) - return(func); - - if (func->device == device) - found++; - - while (func->next != NULL) { - func = func->next; - - if (func->device == device) - found++; - - if (found == index) - return(func); - } - - return(NULL); -} - -static int is_bridge(struct pci_func * func) -{ - /* Check the header type */ - if (((func->config_space[0x03] >> 16) & 0xFF) == 0x01) - return 1; - else - return 0; -} - - /* The following routines constitute the bulk of the hotplug controller logic */ -static u32 change_bus_speed(struct controller *ctrl, struct slot *p_slot, enum pci_bus_speed speed) +static int change_bus_speed(struct controller *ctrl, struct slot *p_slot, + enum pci_bus_speed speed) { - u32 rc = 0; + int rc = 0; dbg("%s: change to speed %d\n", __FUNCTION__, speed); down(&ctrl->crit_sect); @@ -1074,10 +261,11 @@ static u32 change_bus_speed(struct controller *ctrl, struct slot *p_slot, enum p return rc; } -static u32 fix_bus_speed(struct controller *ctrl, struct slot *pslot, u8 flag, -enum pci_bus_speed asp, enum pci_bus_speed bsp, enum pci_bus_speed msp) +static int fix_bus_speed(struct controller *ctrl, struct slot *pslot, + u8 flag, enum pci_bus_speed asp, enum pci_bus_speed bsp, + enum pci_bus_speed msp) { - u32 rc = 0; + int rc = 0; if (flag != 0) { /* Other slots on the same bus are occupied */ if ( asp < bsp ) { @@ -1116,23 +304,20 @@ enum pci_bus_speed asp, enum pci_bus_speed bsp, enum pci_bus_speed msp) * Configures board * */ -static u32 board_added(struct pci_func * func, struct controller * ctrl) +static int board_added(struct slot *p_slot) { u8 hp_slot; u8 slots_not_empty = 0; - int index; - u32 temp_register = 0xFFFFFFFF; - u32 retval, rc = 0; - struct pci_func *new_func = NULL; - struct slot *p_slot; - struct resource_lists res_lists; + int rc = 0; enum pci_bus_speed adapter_speed, bus_speed, max_bus_speed; u8 pi, mode; + struct controller *ctrl = p_slot->ctrl; - p_slot = shpchp_find_slot(ctrl, func->device); - hp_slot = func->device - ctrl->slot_device_offset; + hp_slot = p_slot->device - ctrl->slot_device_offset; - dbg("%s: func->device, slot_offset, hp_slot = %d, %d ,%d\n", __FUNCTION__, func->device, ctrl->slot_device_offset, hp_slot); + dbg("%s: p_slot->device, slot_offset, hp_slot = %d, %d ,%d\n", + __FUNCTION__, p_slot->device, + ctrl->slot_device_offset, hp_slot); /* Wait for exclusive access to hardware */ down(&ctrl->crit_sect); @@ -1320,143 +505,68 @@ static u32 board_added(struct pci_func * func, struct controller * ctrl) up(&ctrl->crit_sect); /* Wait for ~1 second */ - dbg("%s: before long_delay\n", __FUNCTION__); wait_for_ctrl_irq (ctrl); - dbg("%s: after long_delay\n", __FUNCTION__); - dbg("%s: func status = %x\n", __FUNCTION__, func->status); + dbg("%s: slot status = %x\n", __FUNCTION__, p_slot->status); /* Check for a power fault */ - if (func->status == 0xFF) { + if (p_slot->status == 0xFF) { /* power fault occurred, but it was benign */ - temp_register = 0xFFFFFFFF; - dbg("%s: temp register set to %x by power fault\n", __FUNCTION__, temp_register); + dbg("%s: power fault\n", __FUNCTION__); rc = POWER_FAILURE; - func->status = 0; - } else { - /* Get vendor/device ID u32 */ - rc = pci_bus_read_config_dword (ctrl->pci_dev->subordinate, PCI_DEVFN(func->device, func->function), - PCI_VENDOR_ID, &temp_register); - dbg("%s: pci_bus_read_config_dword returns %d\n", __FUNCTION__, rc); - dbg("%s: temp_register is %x\n", __FUNCTION__, temp_register); - - if (rc != 0) { - /* Something's wrong here */ - temp_register = 0xFFFFFFFF; - dbg("%s: temp register set to %x by error\n", __FUNCTION__, temp_register); - } - /* Preset return code. It will be changed later if things go okay. */ - rc = NO_ADAPTER_PRESENT; + p_slot->status = 0; + goto err_exit; } - /* All F's is an empty slot or an invalid board */ - if (temp_register != 0xFFFFFFFF) { /* Check for a board in the slot */ - res_lists.io_head = ctrl->io_head; - res_lists.mem_head = ctrl->mem_head; - res_lists.p_mem_head = ctrl->p_mem_head; - res_lists.bus_head = ctrl->bus_head; - res_lists.irqs = NULL; - - rc = configure_new_device(ctrl, func, 0, &res_lists, 0, 0); - dbg("%s: back from configure_new_device\n", __FUNCTION__); - - ctrl->io_head = res_lists.io_head; - ctrl->mem_head = res_lists.mem_head; - ctrl->p_mem_head = res_lists.p_mem_head; - ctrl->bus_head = res_lists.bus_head; - - shpchp_resource_sort_and_combine(&(ctrl->mem_head)); - shpchp_resource_sort_and_combine(&(ctrl->p_mem_head)); - shpchp_resource_sort_and_combine(&(ctrl->io_head)); - shpchp_resource_sort_and_combine(&(ctrl->bus_head)); - - if (rc) { - /* Wait for exclusive access to hardware */ - down(&ctrl->crit_sect); - - /* turn off slot, turn on Amber LED, turn off Green LED */ - retval = p_slot->hpc_ops->slot_disable(p_slot); - if (retval) { - err("%s: Issue of Slot Enable command failed\n", __FUNCTION__); - /* Done with exclusive hardware access */ - up(&ctrl->crit_sect); - return retval; - } - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); - - retval = p_slot->hpc_ops->check_cmd_status(ctrl); - if (retval) { - err("%s: Failed to disable slot, error code(%d)\n", __FUNCTION__, retval); - /* Done with exclusive hardware access */ - up(&ctrl->crit_sect); - return retval; - } - - /* Done with exclusive hardware access */ - up(&ctrl->crit_sect); + if (shpchp_configure_device(p_slot)) { + err("Cannot add device at 0x%x:0x%x\n", p_slot->bus, + p_slot->device); + goto err_exit; + } - return(rc); - } - shpchp_save_slot_config(ctrl, func); + p_slot->status = 0; + p_slot->is_a_board = 0x01; + p_slot->pwr_save = 1; - func->status = 0; - func->switch_save = 0x10; - func->is_a_board = 0x01; - func->pwr_save = 1; + /* Wait for exclusive access to hardware */ + down(&ctrl->crit_sect); - /* Next, we will instantiate the linux pci_dev structures - * (with appropriate driver notification, if already present) - */ - index = 0; - do { - new_func = shpchp_slot_find(ctrl->slot_bus, func->device, index++); - if (new_func && !new_func->pci_dev) { - dbg("%s:call pci_hp_configure_dev\n", __FUNCTION__); - shpchp_configure_device(ctrl, new_func); - } - } while (new_func); + p_slot->hpc_ops->green_led_on(p_slot); - /* Wait for exclusive access to hardware */ - down(&ctrl->crit_sect); + /* Wait for the command to complete */ + wait_for_ctrl_irq (ctrl); - p_slot->hpc_ops->green_led_on(p_slot); + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); + return 0; +err_exit: + /* Wait for exclusive access to hardware */ + down(&ctrl->crit_sect); + /* turn off slot, turn on Amber LED, turn off Green LED */ + rc = p_slot->hpc_ops->slot_disable(p_slot); + if (rc) { + err("%s: Issue of Slot Disable command failed\n", __FUNCTION__); /* Done with exclusive hardware access */ up(&ctrl->crit_sect); + return rc; + } + /* Wait for the command to complete */ + wait_for_ctrl_irq (ctrl); - } else { - /* Wait for exclusive access to hardware */ - down(&ctrl->crit_sect); - - /* turn off slot, turn on Amber LED, turn off Green LED */ - rc = p_slot->hpc_ops->slot_disable(p_slot); - if (rc) { - err("%s: Issue of Slot Disable command failed\n", __FUNCTION__); - /* Done with exclusive hardware access */ - up(&ctrl->crit_sect); - return rc; - } - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); - - rc = p_slot->hpc_ops->check_cmd_status(ctrl); - if (rc) { - err("%s: Failed to disable slot, error code(%d)\n", __FUNCTION__, rc); - /* Done with exclusive hardware access */ - up(&ctrl->crit_sect); - return rc; - } - + rc = p_slot->hpc_ops->check_cmd_status(ctrl); + if (rc) { + err("%s: Failed to disable slot, error code(%d)\n", __FUNCTION__, rc); /* Done with exclusive hardware access */ up(&ctrl->crit_sect); - - return(rc); + return rc; } - return 0; + + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + + return(rc); } @@ -1464,55 +574,23 @@ static u32 board_added(struct pci_func * func, struct controller * ctrl) * remove_board - Turns off slot and LED's * */ -static u32 remove_board(struct pci_func *func, struct controller *ctrl) +static int remove_board(struct slot *p_slot) { - int index; - u8 skip = 0; - u8 device; + struct controller *ctrl = p_slot->ctrl; u8 hp_slot; - u32 rc; - struct resource_lists res_lists; - struct pci_func *temp_func; - struct slot *p_slot; - - if (func == NULL) - return(1); + int rc; - if (shpchp_unconfigure_device(func)) + if (shpchp_unconfigure_device(p_slot)) return(1); - device = func->device; - - hp_slot = func->device - ctrl->slot_device_offset; + hp_slot = p_slot->device - ctrl->slot_device_offset; p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot); - if ((ctrl->add_support) && - !(func->bus_head || func->mem_head || func->p_mem_head || func->io_head)) { - /* Here we check to see if we've saved any of the board's - * resources already. If so, we'll skip the attempt to - * determine what's being used. - */ - index = 0; - - temp_func = func; - - while ((temp_func = shpchp_slot_find(temp_func->bus, temp_func->device, index++))) { - if (temp_func->bus_head || temp_func->mem_head - || temp_func->p_mem_head || temp_func->io_head) { - skip = 1; - break; - } - } - - if (!skip) - rc = shpchp_save_used_resources(ctrl, func, DISABLE_CARD); - } /* Change status to shutdown */ - if (func->is_a_board) - func->status = 0x01; - func->configured = 0; + if (p_slot->is_a_board) + p_slot->status = 0x01; /* Wait for exclusive access to hardware */ down(&ctrl->crit_sect); @@ -1549,55 +627,8 @@ static u32 remove_board(struct pci_func *func, struct controller *ctrl) /* Done with exclusive hardware access */ up(&ctrl->crit_sect); - if (ctrl->add_support) { - while (func) { - res_lists.io_head = ctrl->io_head; - res_lists.mem_head = ctrl->mem_head; - res_lists.p_mem_head = ctrl->p_mem_head; - res_lists.bus_head = ctrl->bus_head; - - dbg("Returning resources to ctlr lists for (B/D/F) = (%#x/%#x/%#x)\n", func->bus, - func->device, func->function); - - shpchp_return_board_resources(func, &res_lists); - - ctrl->io_head = res_lists.io_head; - ctrl->mem_head = res_lists.mem_head; - ctrl->p_mem_head = res_lists.p_mem_head; - ctrl->bus_head = res_lists.bus_head; - - shpchp_resource_sort_and_combine(&(ctrl->mem_head)); - shpchp_resource_sort_and_combine(&(ctrl->p_mem_head)); - shpchp_resource_sort_and_combine(&(ctrl->io_head)); - shpchp_resource_sort_and_combine(&(ctrl->bus_head)); - - if (is_bridge(func)) { - dbg("PCI Bridge Hot-Remove s:b:d:f(%02x:%02x:%02x:%02x)\n", ctrl->seg, func->bus, - func->device, func->function); - bridge_slot_remove(func); - } else - dbg("PCI Function Hot-Remove s:b:d:f(%02x:%02x:%02x:%02x)\n", ctrl->seg, func->bus, - func->device, func->function); - slot_remove(func); - - func = shpchp_slot_find(ctrl->slot_bus, device, 0); - } - - /* Setup slot structure with entry for empty slot */ - func = shpchp_slot_create(ctrl->slot_bus); - - if (func == NULL) { - return(1); - } - - func->bus = ctrl->slot_bus; - func->device = device; - func->function = 0; - func->configured = 0; - func->switch_save = 0x10; - func->pwr_save = 0; - func->is_a_board = 0; - } + p_slot->pwr_save = 0; + p_slot->is_a_board = 0; return 0; } @@ -1633,13 +664,11 @@ static void shpchp_pushbutton_thread (unsigned long slot) p_slot->hpc_ops->get_power_status(p_slot, &getstatus); if (getstatus) { p_slot->state = POWEROFF_STATE; - dbg("In power_down_board, b:d(%x:%x)\n", p_slot->bus, p_slot->device); shpchp_disable_slot(p_slot); p_slot->state = STATIC_STATE; } else { p_slot->state = POWERON_STATE; - dbg("In add_board, b:d(%x:%x)\n", p_slot->bus, p_slot->device); if (shpchp_enable_slot(p_slot)) { /* Wait for exclusive access to hardware */ @@ -1701,7 +730,6 @@ int shpchp_event_start_thread (void) err ("Can't start up our event thread\n"); return -1; } - dbg("Our event thread pid = %d\n", pid); return 0; } @@ -1709,9 +737,7 @@ int shpchp_event_start_thread (void) void shpchp_event_stop_thread (void) { event_finished = 1; - dbg("event_thread finish command given\n"); up(&event_semaphore); - dbg("wait for event_thread to exit\n"); down(&event_exit); } @@ -1739,12 +765,10 @@ static void interrupt_event_handler(struct controller *ctrl) { int loop = 0; int change = 1; - struct pci_func *func; u8 hp_slot; u8 getstatus; struct slot *p_slot; - dbg("%s:\n", __FUNCTION__); while (change) { change = 0; @@ -1754,12 +778,8 @@ static void interrupt_event_handler(struct controller *ctrl) ctrl->event_queue[loop].event_type); hp_slot = ctrl->event_queue[loop].hp_slot; - func = shpchp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0); - p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); - dbg("%s: hp_slot %d, func %p, p_slot %p\n", __FUNCTION__, hp_slot, func, p_slot); - if (ctrl->event_queue[loop].event_type == INT_BUTTON_CANCEL) { dbg("%s: button cancel\n", __FUNCTION__); del_timer(&p_slot->task_event); @@ -1880,13 +900,6 @@ int shpchp_enable_slot (struct slot *p_slot) { u8 getstatus = 0; int rc; - struct pci_func *func; - - func = shpchp_slot_find(p_slot->bus, p_slot->device, 0); - if (!func) { - dbg("%s: Error! slot NULL\n", __FUNCTION__); - return -ENODEV; - } /* Check to see if (latch closed, card present, power off) */ down(&p_slot->ctrl->crit_sect); @@ -1910,72 +923,34 @@ int shpchp_enable_slot (struct slot *p_slot) } up(&p_slot->ctrl->crit_sect); - slot_remove(func); - - func = shpchp_slot_create(p_slot->bus); - if (func == NULL) - return -ENOMEM; - - func->bus = p_slot->bus; - func->device = p_slot->device; - func->function = 0; - func->configured = 0; - func->is_a_board = 1; + p_slot->is_a_board = 1; /* We have to save the presence info for these slots */ - p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save)); - p_slot->hpc_ops->get_power_status(p_slot, &(func->pwr_save)); - dbg("%s: func->pwr_save %x\n", __FUNCTION__, func->pwr_save); + p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save)); + p_slot->hpc_ops->get_power_status(p_slot, &(p_slot->pwr_save)); + dbg("%s: p_slot->pwr_save %x\n", __FUNCTION__, p_slot->pwr_save); p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); - func->switch_save = !getstatus? 0x10:0; - rc = board_added(func, p_slot->ctrl); + rc = board_added(p_slot); if (rc) { - if (is_bridge(func)) - bridge_slot_remove(func); - else - slot_remove(func); - - /* Setup slot structure with entry for empty slot */ - func = shpchp_slot_create(p_slot->bus); - if (func == NULL) - return -ENOMEM; /* Out of memory */ - - func->bus = p_slot->bus; - func->device = p_slot->device; - func->function = 0; - func->configured = 0; - func->is_a_board = 1; - - /* We have to save the presence info for these slots */ - p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save)); + p_slot->hpc_ops->get_adapter_status(p_slot, + &(p_slot->presence_save)); p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); - func->switch_save = !getstatus? 0x10:0; } - if (p_slot) - update_slot_info(p_slot); - + update_slot_info(p_slot); return rc; } int shpchp_disable_slot (struct slot *p_slot) { - u8 class_code, header_type, BCR; - u8 index = 0; u8 getstatus = 0; - u32 rc = 0; int ret = 0; - unsigned int devfn; - struct pci_bus *pci_bus; - struct pci_func *func; if (!p_slot->ctrl) return -ENODEV; - pci_bus = p_slot->ctrl->pci_dev->subordinate; - /* Check to see if (latch closed, card present, power on) */ down(&p_slot->ctrl->crit_sect); @@ -1999,849 +974,8 @@ int shpchp_disable_slot (struct slot *p_slot) } up(&p_slot->ctrl->crit_sect); - func = shpchp_slot_find(p_slot->bus, p_slot->device, index++); - - /* Make sure there are no video controllers here - * for all func of p_slot - */ - while (func && !rc) { - pci_bus->number = func->bus; - devfn = PCI_DEVFN(func->device, func->function); - - /* Check the Class Code */ - rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &class_code); - if (rc) - return -ENODEV; - - if (class_code == PCI_BASE_CLASS_DISPLAY) { - /* Display/Video adapter (not supported) */ - rc = REMOVE_NOT_SUPPORTED; - } else { - /* See if it's a bridge */ - rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type); - if (rc) - return -ENODEV; - - /* If it's a bridge, check the VGA Enable bit */ - if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { - rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_BRIDGE_CONTROL, &BCR); - if (rc) - return -ENODEV; - - /* If the VGA Enable bit is set, remove isn't supported */ - if (BCR & PCI_BRIDGE_CTL_VGA) { - rc = REMOVE_NOT_SUPPORTED; - } - } - } - - func = shpchp_slot_find(p_slot->bus, p_slot->device, index++); - } - - func = shpchp_slot_find(p_slot->bus, p_slot->device, 0); - if ((func != NULL) && !rc) { - rc = remove_board(func, p_slot->ctrl); - } else if (!rc) - rc = -ENODEV; - - if (p_slot) - update_slot_info(p_slot); - - return rc; -} - - -/** - * configure_new_device - Configures the PCI header information of one board. - * - * @ctrl: pointer to controller structure - * @func: pointer to function structure - * @behind_bridge: 1 if this is a recursive call, 0 if not - * @resources: pointer to set of resource lists - * - * Returns 0 if success - * - */ -static u32 configure_new_device (struct controller * ctrl, struct pci_func * func, - u8 behind_bridge, struct resource_lists * resources, u8 bridge_bus, u8 bridge_dev) -{ - u8 temp_byte, function, max_functions, stop_it; - int rc; - u32 ID; - struct pci_func *new_slot; - struct pci_bus lpci_bus, *pci_bus; - int index; - - new_slot = func; - - dbg("%s\n", __FUNCTION__); - memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus)); - pci_bus = &lpci_bus; - pci_bus->number = func->bus; - - /* Check for Multi-function device */ - rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(func->device, func->function), 0x0E, &temp_byte); - if (rc) { - dbg("%s: rc = %d\n", __FUNCTION__, rc); - return rc; - } - - if (temp_byte & 0x80) /* Multi-function device */ - max_functions = 8; - else - max_functions = 1; - - function = 0; - - do { - rc = configure_new_function(ctrl, new_slot, behind_bridge, resources, bridge_bus, bridge_dev); - - if (rc) { - dbg("configure_new_function failed %d\n",rc); - index = 0; - - while (new_slot) { - new_slot = shpchp_slot_find(new_slot->bus, new_slot->device, index++); - - if (new_slot) - shpchp_return_board_resources(new_slot, resources); - } - - return(rc); - } - - function++; - - stop_it = 0; - - /* The following loop skips to the next present function - * and creates a board structure - */ - - while ((function < max_functions) && (!stop_it)) { - pci_bus_read_config_dword(pci_bus, PCI_DEVFN(func->device, function), 0x00, &ID); - - if (ID == 0xFFFFFFFF) { /* There's nothing there. */ - function++; - } else { /* There's something there */ - /* Setup slot structure. */ - new_slot = shpchp_slot_create(func->bus); - - if (new_slot == NULL) { - /* Out of memory */ - return(1); - } - - new_slot->bus = func->bus; - new_slot->device = func->device; - new_slot->function = function; - new_slot->is_a_board = 1; - new_slot->status = 0; - - stop_it++; - } - } - - } while (function < max_functions); - dbg("returning from configure_new_device\n"); - - return 0; -} - - -/* - * Configuration logic that involves the hotplug data structures and - * their bookkeeping - */ - - -/** - * configure_new_function - Configures the PCI header information of one device - * - * @ctrl: pointer to controller structure - * @func: pointer to function structure - * @behind_bridge: 1 if this is a recursive call, 0 if not - * @resources: pointer to set of resource lists - * - * Calls itself recursively for bridged devices. - * Returns 0 if success - * - */ -static int configure_new_function (struct controller * ctrl, struct pci_func * func, - u8 behind_bridge, struct resource_lists *resources, u8 bridge_bus, u8 bridge_dev) -{ - int cloop; - u8 temp_byte; - u8 device; - u8 class_code; - u16 temp_word; - u32 rc; - u32 temp_register; - u32 base; - u32 ID; - unsigned int devfn; - struct pci_resource *mem_node; - struct pci_resource *p_mem_node; - struct pci_resource *io_node; - struct pci_resource *bus_node; - struct pci_resource *hold_mem_node; - struct pci_resource *hold_p_mem_node; - struct pci_resource *hold_IO_node; - struct pci_resource *hold_bus_node; - struct irq_mapping irqs; - struct pci_func *new_slot; - struct pci_bus lpci_bus, *pci_bus; - struct resource_lists temp_resources; -#if defined(CONFIG_X86_64) - u8 IRQ=0; -#endif - - memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus)); - pci_bus = &lpci_bus; - pci_bus->number = func->bus; - devfn = PCI_DEVFN(func->device, func->function); - - /* Check for Bridge */ - rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &temp_byte); - if (rc) - return rc; - - if ((temp_byte & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { /* PCI-PCI Bridge */ - /* set Primary bus */ - dbg("set Primary bus = 0x%x\n", func->bus); - rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_PRIMARY_BUS, func->bus); - if (rc) - return rc; - - /* find range of busses to use */ - bus_node = get_max_resource(&resources->bus_head, 1L); - - /* If we don't have any busses to allocate, we can't continue */ - if (!bus_node) { - err("Got NO bus resource to use\n"); - return -ENOMEM; - } - dbg("Got ranges of buses to use: base:len=0x%x:%x\n", bus_node->base, bus_node->length); - - /* set Secondary bus */ - temp_byte = (u8)bus_node->base; - dbg("set Secondary bus = 0x%x\n", temp_byte); - rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_SECONDARY_BUS, temp_byte); - if (rc) - return rc; - - /* set subordinate bus */ - temp_byte = (u8)(bus_node->base + bus_node->length - 1); - dbg("set subordinate bus = 0x%x\n", temp_byte); - rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_SUBORDINATE_BUS, temp_byte); - if (rc) - return rc; - - /* Set HP parameters (Cache Line Size, Latency Timer) */ - rc = shpchprm_set_hpp(ctrl, func, PCI_HEADER_TYPE_BRIDGE); - if (rc) - return rc; - - /* Setup the IO, memory, and prefetchable windows */ - - io_node = get_max_resource(&(resources->io_head), 0x1000L); - if (io_node) { - dbg("io_node(base, len, next) (%x, %x, %p)\n", io_node->base, io_node->length, io_node->next); - } - - mem_node = get_max_resource(&(resources->mem_head), 0x100000L); - if (mem_node) { - dbg("mem_node(base, len, next) (%x, %x, %p)\n", mem_node->base, mem_node->length, mem_node->next); - } - - if (resources->p_mem_head) - p_mem_node = get_max_resource(&(resources->p_mem_head), 0x100000L); - else { - /* - * In some platform implementation, MEM and PMEM are not - * distinguished, and hence ACPI _CRS has only MEM entries - * for both MEM and PMEM. - */ - dbg("using MEM for PMEM\n"); - p_mem_node = get_max_resource(&(resources->mem_head), 0x100000L); - } - if (p_mem_node) { - dbg("p_mem_node(base, len, next) (%x, %x, %p)\n", p_mem_node->base, p_mem_node->length, p_mem_node->next); - } - - /* set up the IRQ info */ - if (!resources->irqs) { - irqs.barber_pole = 0; - irqs.interrupt[0] = 0; - irqs.interrupt[1] = 0; - irqs.interrupt[2] = 0; - irqs.interrupt[3] = 0; - irqs.valid_INT = 0; - } else { - irqs.barber_pole = resources->irqs->barber_pole; - irqs.interrupt[0] = resources->irqs->interrupt[0]; - irqs.interrupt[1] = resources->irqs->interrupt[1]; - irqs.interrupt[2] = resources->irqs->interrupt[2]; - irqs.interrupt[3] = resources->irqs->interrupt[3]; - irqs.valid_INT = resources->irqs->valid_INT; - } - - /* set up resource lists that are now aligned on top and bottom - * for anything behind the bridge. - */ - temp_resources.bus_head = bus_node; - temp_resources.io_head = io_node; - temp_resources.mem_head = mem_node; - temp_resources.p_mem_head = p_mem_node; - temp_resources.irqs = &irqs; - - /* Make copies of the nodes we are going to pass down so that - * if there is a problem,we can just use these to free resources - */ - hold_bus_node = kmalloc(sizeof(*hold_bus_node), GFP_KERNEL); - hold_IO_node = kmalloc(sizeof(*hold_IO_node), GFP_KERNEL); - hold_mem_node = kmalloc(sizeof(*hold_mem_node), GFP_KERNEL); - hold_p_mem_node = kmalloc(sizeof(*hold_p_mem_node), GFP_KERNEL); - - if (!hold_bus_node || !hold_IO_node || !hold_mem_node || !hold_p_mem_node) { - kfree(hold_bus_node); - kfree(hold_IO_node); - kfree(hold_mem_node); - kfree(hold_p_mem_node); - - return 1; - } - - memcpy(hold_bus_node, bus_node, sizeof(struct pci_resource)); - - bus_node->base += 1; - bus_node->length -= 1; - bus_node->next = NULL; - - /* If we have IO resources copy them and fill in the bridge's - * IO range registers - */ - if (io_node) { - memcpy(hold_IO_node, io_node, sizeof(struct pci_resource)); - io_node->next = NULL; - - /* set IO base and Limit registers */ - RES_CHECK(io_node->base, 8); - temp_byte = (u8)(io_node->base >> 8); - rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_IO_BASE, temp_byte); - - RES_CHECK(io_node->base + io_node->length - 1, 8); - temp_byte = (u8)((io_node->base + io_node->length - 1) >> 8); - rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_IO_LIMIT, temp_byte); - } else { - kfree(hold_IO_node); - hold_IO_node = NULL; - } - - /* If we have memory resources copy them and fill in the bridge's - * memory range registers. Otherwise, fill in the range - * registers with values that disable them. - */ - if (mem_node) { - memcpy(hold_mem_node, mem_node, sizeof(struct pci_resource)); - mem_node->next = NULL; - - /* set Mem base and Limit registers */ - RES_CHECK(mem_node->base, 16); - temp_word = (u32)(mem_node->base >> 16); - rc = pci_bus_write_config_word(pci_bus, devfn, PCI_MEMORY_BASE, temp_word); - - RES_CHECK(mem_node->base + mem_node->length - 1, 16); - temp_word = (u32)((mem_node->base + mem_node->length - 1) >> 16); - rc = pci_bus_write_config_word(pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word); - } else { - temp_word = 0xFFFF; - rc = pci_bus_write_config_word(pci_bus, devfn, PCI_MEMORY_BASE, temp_word); - - temp_word = 0x0000; - rc = pci_bus_write_config_word(pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word); - - kfree(hold_mem_node); - hold_mem_node = NULL; - } - - /* If we have prefetchable memory resources copy them and - * fill in the bridge's memory range registers. Otherwise, - * fill in the range registers with values that disable them. - */ - if (p_mem_node) { - memcpy(hold_p_mem_node, p_mem_node, sizeof(struct pci_resource)); - p_mem_node->next = NULL; - - /* set Pre Mem base and Limit registers */ - RES_CHECK(p_mem_node->base, 16); - temp_word = (u32)(p_mem_node->base >> 16); - rc = pci_bus_write_config_word(pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word); - - RES_CHECK(p_mem_node->base + p_mem_node->length - 1, 16); - temp_word = (u32)((p_mem_node->base + p_mem_node->length - 1) >> 16); - rc = pci_bus_write_config_word(pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word); - } else { - temp_word = 0xFFFF; - rc = pci_bus_write_config_word(pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word); - - temp_word = 0x0000; - rc = pci_bus_write_config_word(pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word); - - kfree(hold_p_mem_node); - hold_p_mem_node = NULL; - } - - /* Adjust this to compensate for extra adjustment in first loop */ - irqs.barber_pole--; - - rc = 0; - - /* Here we actually find the devices and configure them */ - for (device = 0; (device <= 0x1F) && !rc; device++) { - irqs.barber_pole = (irqs.barber_pole + 1) & 0x03; - - ID = 0xFFFFFFFF; - pci_bus->number = hold_bus_node->base; - pci_bus_read_config_dword(pci_bus, PCI_DEVFN(device, 0), - PCI_VENDOR_ID, &ID); - pci_bus->number = func->bus; - - if (ID != 0xFFFFFFFF) { /* device Present */ - /* Setup slot structure. */ - new_slot = shpchp_slot_create(hold_bus_node->base); - - if (new_slot == NULL) { - /* Out of memory */ - rc = -ENOMEM; - continue; - } - - new_slot->bus = hold_bus_node->base; - new_slot->device = device; - new_slot->function = 0; - new_slot->is_a_board = 1; - new_slot->status = 0; - - rc = configure_new_device(ctrl, new_slot, 1, &temp_resources, func->bus, func->device); - dbg("configure_new_device rc=0x%x\n",rc); - } /* End of IF (device in slot?) */ - } /* End of FOR loop */ - - if (rc) { - shpchp_destroy_resource_list(&temp_resources); - - return_resource(&(resources->bus_head), hold_bus_node); - return_resource(&(resources->io_head), hold_IO_node); - return_resource(&(resources->mem_head), hold_mem_node); - return_resource(&(resources->p_mem_head), hold_p_mem_node); - return(rc); - } - - /* save the interrupt routing information */ - if (resources->irqs) { - resources->irqs->interrupt[0] = irqs.interrupt[0]; - resources->irqs->interrupt[1] = irqs.interrupt[1]; - resources->irqs->interrupt[2] = irqs.interrupt[2]; - resources->irqs->interrupt[3] = irqs.interrupt[3]; - resources->irqs->valid_INT = irqs.valid_INT; - } else if (!behind_bridge) { - /* We need to hook up the interrupts here */ - for (cloop = 0; cloop < 4; cloop++) { - if (irqs.valid_INT & (0x01 << cloop)) { - rc = shpchp_set_irq(func->bus, func->device, - 0x0A + cloop, irqs.interrupt[cloop]); - if (rc) { - shpchp_destroy_resource_list (&temp_resources); - return_resource(&(resources->bus_head), hold_bus_node); - return_resource(&(resources->io_head), hold_IO_node); - return_resource(&(resources->mem_head), hold_mem_node); - return_resource(&(resources->p_mem_head), hold_p_mem_node); - return rc; - } - } - } /* end of for loop */ - } - - /* Return unused bus resources - * First use the temporary node to store information for the board - */ - if (hold_bus_node && bus_node && temp_resources.bus_head) { - hold_bus_node->length = bus_node->base - hold_bus_node->base; - - hold_bus_node->next = func->bus_head; - func->bus_head = hold_bus_node; - - temp_byte = (u8)(temp_resources.bus_head->base - 1); - - /* set subordinate bus */ - dbg("re-set subordinate bus = 0x%x\n", temp_byte); - rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_SUBORDINATE_BUS, temp_byte); - - if (temp_resources.bus_head->length == 0) { - kfree(temp_resources.bus_head); - temp_resources.bus_head = NULL; - } else { - dbg("return bus res of b:d(0x%x:%x) base:len(0x%x:%x)\n", - func->bus, func->device, temp_resources.bus_head->base, temp_resources.bus_head->length); - return_resource(&(resources->bus_head), temp_resources.bus_head); - } - } - - /* If we have IO space available and there is some left, - * return the unused portion - */ - if (hold_IO_node && temp_resources.io_head) { - io_node = do_pre_bridge_resource_split(&(temp_resources.io_head), - &hold_IO_node, 0x1000); - - /* Check if we were able to split something off */ - if (io_node) { - hold_IO_node->base = io_node->base + io_node->length; - - RES_CHECK(hold_IO_node->base, 8); - temp_byte = (u8)((hold_IO_node->base) >> 8); - rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_BASE, temp_byte); - - return_resource(&(resources->io_head), io_node); - } - - io_node = do_bridge_resource_split(&(temp_resources.io_head), 0x1000); - - /* Check if we were able to split something off */ - if (io_node) { - /* First use the temporary node to store information for the board */ - hold_IO_node->length = io_node->base - hold_IO_node->base; - - /* If we used any, add it to the board's list */ - if (hold_IO_node->length) { - hold_IO_node->next = func->io_head; - func->io_head = hold_IO_node; - - RES_CHECK(io_node->base - 1, 8); - temp_byte = (u8)((io_node->base - 1) >> 8); - rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_LIMIT, temp_byte); - - return_resource(&(resources->io_head), io_node); - } else { - /* it doesn't need any IO */ - temp_byte = 0x00; - rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_IO_LIMIT, temp_byte); - - return_resource(&(resources->io_head), io_node); - kfree(hold_IO_node); - } - } else { - /* it used most of the range */ - hold_IO_node->next = func->io_head; - func->io_head = hold_IO_node; - } - } else if (hold_IO_node) { - /* it used the whole range */ - hold_IO_node->next = func->io_head; - func->io_head = hold_IO_node; - } - - /* If we have memory space available and there is some left, - * return the unused portion - */ - if (hold_mem_node && temp_resources.mem_head) { - mem_node = do_pre_bridge_resource_split(&(temp_resources.mem_head), &hold_mem_node, 0x100000L); - - /* Check if we were able to split something off */ - if (mem_node) { - hold_mem_node->base = mem_node->base + mem_node->length; - - RES_CHECK(hold_mem_node->base, 16); - temp_word = (u32)((hold_mem_node->base) >> 16); - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_BASE, temp_word); - - return_resource(&(resources->mem_head), mem_node); - } - - mem_node = do_bridge_resource_split(&(temp_resources.mem_head), 0x100000L); - - /* Check if we were able to split something off */ - if (mem_node) { - /* First use the temporary node to store information for the board */ - hold_mem_node->length = mem_node->base - hold_mem_node->base; - - if (hold_mem_node->length) { - hold_mem_node->next = func->mem_head; - func->mem_head = hold_mem_node; - - /* configure end address */ - RES_CHECK(mem_node->base - 1, 16); - temp_word = (u32)((mem_node->base - 1) >> 16); - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word); - - /* Return unused resources to the pool */ - return_resource(&(resources->mem_head), mem_node); - } else { - /* it doesn't need any Mem */ - temp_word = 0x0000; - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word); - - return_resource(&(resources->mem_head), mem_node); - kfree(hold_mem_node); - } - } else { - /* it used most of the range */ - hold_mem_node->next = func->mem_head; - func->mem_head = hold_mem_node; - } - } else if (hold_mem_node) { - /* it used the whole range */ - hold_mem_node->next = func->mem_head; - func->mem_head = hold_mem_node; - } - - /* If we have prefetchable memory space available and there is some - * left at the end, return the unused portion - */ - if (hold_p_mem_node && temp_resources.p_mem_head) { - p_mem_node = do_pre_bridge_resource_split(&(temp_resources.p_mem_head), - &hold_p_mem_node, 0x100000L); - - /* Check if we were able to split something off */ - if (p_mem_node) { - hold_p_mem_node->base = p_mem_node->base + p_mem_node->length; - - RES_CHECK(hold_p_mem_node->base, 16); - temp_word = (u32)((hold_p_mem_node->base) >> 16); - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word); - - return_resource(&(resources->p_mem_head), p_mem_node); - } - - p_mem_node = do_bridge_resource_split(&(temp_resources.p_mem_head), 0x100000L); - - /* Check if we were able to split something off */ - if (p_mem_node) { - /* First use the temporary node to store information for the board */ - hold_p_mem_node->length = p_mem_node->base - hold_p_mem_node->base; - - /* If we used any, add it to the board's list */ - if (hold_p_mem_node->length) { - hold_p_mem_node->next = func->p_mem_head; - func->p_mem_head = hold_p_mem_node; - - RES_CHECK(p_mem_node->base - 1, 16); - temp_word = (u32)((p_mem_node->base - 1) >> 16); - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word); - - return_resource(&(resources->p_mem_head), p_mem_node); - } else { - /* it doesn't need any PMem */ - temp_word = 0x0000; - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word); - - return_resource(&(resources->p_mem_head), p_mem_node); - kfree(hold_p_mem_node); - } - } else { - /* it used the most of the range */ - hold_p_mem_node->next = func->p_mem_head; - func->p_mem_head = hold_p_mem_node; - } - } else if (hold_p_mem_node) { - /* it used the whole range */ - hold_p_mem_node->next = func->p_mem_head; - func->p_mem_head = hold_p_mem_node; - } - - /* We should be configuring an IRQ and the bridge's base address - * registers if it needs them. Although we have never seen such - * a device - */ - - shpchprm_enable_card(ctrl, func, PCI_HEADER_TYPE_BRIDGE); - - dbg("PCI Bridge Hot-Added s:b:d:f(%02x:%02x:%02x:%02x)\n", ctrl->seg, func->bus, func->device, func->function); - } else if ((temp_byte & 0x7F) == PCI_HEADER_TYPE_NORMAL) { - /* Standard device */ - u64 base64; - rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &class_code); - - if (class_code == PCI_BASE_CLASS_DISPLAY) - return (DEVICE_TYPE_NOT_SUPPORTED); - - /* Figure out IO and memory needs */ - for (cloop = PCI_BASE_ADDRESS_0; cloop <= PCI_BASE_ADDRESS_5; cloop += 4) { - temp_register = 0xFFFFFFFF; - - rc = pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register); - rc = pci_bus_read_config_dword(pci_bus, devfn, cloop, &temp_register); - dbg("Bar[%x]=0x%x on bus:dev:func(0x%x:%x:%x)\n", cloop, temp_register, func->bus, func->device, - func->function); - - if (!temp_register) - continue; - - base64 = 0L; - if (temp_register & PCI_BASE_ADDRESS_SPACE_IO) { - /* Map IO */ - - /* set base = amount of IO space */ - base = temp_register & 0xFFFFFFFC; - base = ~base + 1; - - dbg("NEED IO length(0x%x)\n", base); - io_node = get_io_resource(&(resources->io_head),(ulong)base); - - /* allocate the resource to the board */ - if (io_node) { - dbg("Got IO base=0x%x(length=0x%x)\n", io_node->base, io_node->length); - base = (u32)io_node->base; - io_node->next = func->io_head; - func->io_head = io_node; - } else { - err("Got NO IO resource(length=0x%x)\n", base); - return -ENOMEM; - } - } else { /* map MEM */ - int prefetchable = 1; - struct pci_resource **res_node = &func->p_mem_head; - char *res_type_str = "PMEM"; - u32 temp_register2; - - if (!(temp_register & PCI_BASE_ADDRESS_MEM_PREFETCH)) { - prefetchable = 0; - res_node = &func->mem_head; - res_type_str++; - } - - base = temp_register & 0xFFFFFFF0; - base = ~base + 1; - - switch (temp_register & PCI_BASE_ADDRESS_MEM_TYPE_MASK) { - case PCI_BASE_ADDRESS_MEM_TYPE_32: - dbg("NEED 32 %s bar=0x%x(length=0x%x)\n", res_type_str, temp_register, base); - - if (prefetchable && resources->p_mem_head) - mem_node=get_resource(&(resources->p_mem_head), (ulong)base); - else { - if (prefetchable) - dbg("using MEM for PMEM\n"); - mem_node=get_resource(&(resources->mem_head), (ulong)base); - } - - /* allocate the resource to the board */ - if (mem_node) { - base = (u32)mem_node->base; - mem_node->next = *res_node; - *res_node = mem_node; - dbg("Got 32 %s base=0x%x(length=0x%x)\n", res_type_str, mem_node->base, - mem_node->length); - } else { - err("Got NO 32 %s resource(length=0x%x)\n", res_type_str, base); - return -ENOMEM; - } - break; - case PCI_BASE_ADDRESS_MEM_TYPE_64: - rc = pci_bus_read_config_dword(pci_bus, devfn, cloop+4, &temp_register2); - dbg("NEED 64 %s bar=0x%x:%x(length=0x%x)\n", res_type_str, temp_register2, - temp_register, base); - - if (prefetchable && resources->p_mem_head) - mem_node = get_resource(&(resources->p_mem_head), (ulong)base); - else { - if (prefetchable) - dbg("using MEM for PMEM\n"); - mem_node = get_resource(&(resources->mem_head), (ulong)base); - } - - /* allocate the resource to the board */ - if (mem_node) { - base64 = mem_node->base; - mem_node->next = *res_node; - *res_node = mem_node; - dbg("Got 64 %s base=0x%x:%x(length=%x)\n", res_type_str, (u32)(base64 >> 32), - (u32)base64, mem_node->length); - } else { - err("Got NO 64 %s resource(length=0x%x)\n", res_type_str, base); - return -ENOMEM; - } - break; - default: - dbg("reserved BAR type=0x%x\n", temp_register); - break; - } - - } - - if (base64) { - rc = pci_bus_write_config_dword(pci_bus, devfn, cloop, (u32)base64); - cloop += 4; - base64 >>= 32; - - if (base64) { - dbg("%s: high dword of base64(0x%x) set to 0\n", __FUNCTION__, (u32)base64); - base64 = 0x0L; - } - - rc = pci_bus_write_config_dword(pci_bus, devfn, cloop, (u32)base64); - } else { - rc = pci_bus_write_config_dword(pci_bus, devfn, cloop, base); - } - } /* End of base register loop */ - -#if defined(CONFIG_X86_64) - /* Figure out which interrupt pin this function uses */ - rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_INTERRUPT_PIN, &temp_byte); - - /* If this function needs an interrupt and we are behind a bridge - and the pin is tied to something that's alread mapped, - set this one the same - */ - if (temp_byte && resources->irqs && - (resources->irqs->valid_INT & - (0x01 << ((temp_byte + resources->irqs->barber_pole - 1) & 0x03)))) { - /* We have to share with something already set up */ - IRQ = resources->irqs->interrupt[(temp_byte + resources->irqs->barber_pole - 1) & 0x03]; - } else { - /* Program IRQ based on card type */ - rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &class_code); - - if (class_code == PCI_BASE_CLASS_STORAGE) { - IRQ = shpchp_disk_irq; - } else { - IRQ = shpchp_nic_irq; - } - } - - /* IRQ Line */ - rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_INTERRUPT_LINE, IRQ); - - if (!behind_bridge) { - rc = shpchp_set_irq(func->bus, func->device, temp_byte + 0x09, IRQ); - if (rc) - return(1); - } else { - /* TBD - this code may also belong in the other clause of this If statement */ - resources->irqs->interrupt[(temp_byte + resources->irqs->barber_pole - 1) & 0x03] = IRQ; - resources->irqs->valid_INT |= 0x01 << (temp_byte + resources->irqs->barber_pole - 1) & 0x03; - } -#endif - /* Disable ROM base Address */ - rc = pci_bus_write_config_dword (pci_bus, devfn, PCI_ROM_ADDRESS, 0x00); - - /* Set HP parameters (Cache Line Size, Latency Timer) */ - rc = shpchprm_set_hpp(ctrl, func, PCI_HEADER_TYPE_NORMAL); - if (rc) - return rc; - - shpchprm_enable_card(ctrl, func, PCI_HEADER_TYPE_NORMAL); - - dbg("PCI function Hot-Added s:b:d:f(%02x:%02x:%02x:%02x)\n", ctrl->seg, func->bus, func->device, func->function); - } /* End of Not-A-Bridge else */ - else { - /* It's some strange type of PCI adapter (Cardbus?) */ - return(DEVICE_TYPE_NOT_SUPPORTED); - } - - func->configured = 1; - - return 0; + ret = remove_board(p_slot); + update_slot_info(p_slot); + return ret; } diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c index 8d98410bf1c0..40905a6c8094 100644 --- a/drivers/pci/hotplug/shpchp_hpc.c +++ b/drivers/pci/hotplug/shpchp_hpc.c @@ -27,17 +27,10 @@ * */ -#include <linux/config.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/types.h> -#include <linux/slab.h> -#include <linux/vmalloc.h> -#include <linux/interrupt.h> -#include <linux/spinlock.h> -#include <linux/delay.h> #include <linux/pci.h> -#include <asm/system.h> #include "shpchp.h" #ifdef DEBUG @@ -282,7 +275,7 @@ static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds) static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd) { - struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; u16 cmd_status; int retval = 0; u16 temp_word; @@ -320,7 +313,6 @@ static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd) * command. */ writew(temp_word, php_ctlr->creg + CMD); - dbg("%s: temp_word written %x\n", __FUNCTION__, temp_word); DBG_LEAVE_ROUTINE return retval; @@ -328,7 +320,7 @@ static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd) static int hpc_check_cmd_status(struct controller *ctrl) { - struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) ctrl->hpc_ctlr_handle; + struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle; u16 cmd_status; int retval = 0; @@ -368,7 +360,7 @@ static int hpc_check_cmd_status(struct controller *ctrl) static int hpc_get_attention_status(struct slot *slot, u8 *status) { - struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; u32 slot_reg; u16 slot_status; u8 atten_led_state; @@ -408,7 +400,7 @@ static int hpc_get_attention_status(struct slot *slot, u8 *status) static int hpc_get_power_status(struct slot * slot, u8 *status) { - struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; u32 slot_reg; u16 slot_status; u8 slot_state; @@ -450,7 +442,7 @@ static int hpc_get_power_status(struct slot * slot, u8 *status) static int hpc_get_latch_status(struct slot *slot, u8 *status) { - struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; u32 slot_reg; u16 slot_status; @@ -473,7 +465,7 @@ static int hpc_get_latch_status(struct slot *slot, u8 *status) static int hpc_get_adapter_status(struct slot *slot, u8 *status) { - struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; u32 slot_reg; u16 slot_status; u8 card_state; @@ -496,7 +488,7 @@ static int hpc_get_adapter_status(struct slot *slot, u8 *status) static int hpc_get_prog_int(struct slot *slot, u8 *prog_int) { - struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; DBG_ENTER_ROUTINE @@ -513,7 +505,7 @@ static int hpc_get_prog_int(struct slot *slot, u8 *prog_int) static int hpc_get_adapter_speed(struct slot *slot, enum pci_bus_speed *value) { - struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; u32 slot_reg; u16 slot_status, sec_bus_status; u8 m66_cap, pcix_cap, pi; @@ -594,7 +586,7 @@ static int hpc_get_adapter_speed(struct slot *slot, enum pci_bus_speed *value) static int hpc_get_mode1_ECC_cap(struct slot *slot, u8 *mode) { - struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; u16 sec_bus_status; u8 pi; int retval = 0; @@ -623,7 +615,7 @@ static int hpc_get_mode1_ECC_cap(struct slot *slot, u8 *mode) static int hpc_query_power_fault(struct slot * slot) { - struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; u32 slot_reg; u16 slot_status; u8 pwr_fault_state, status; @@ -647,7 +639,7 @@ static int hpc_query_power_fault(struct slot * slot) static int hpc_set_attention_status(struct slot *slot, u8 value) { - struct php_ctlr_state_s *php_ctlr =(struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; u8 slot_cmd = 0; int rc = 0; @@ -683,7 +675,7 @@ static int hpc_set_attention_status(struct slot *slot, u8 value) static void hpc_set_green_led_on(struct slot *slot) { - struct php_ctlr_state_s *php_ctlr =(struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; u8 slot_cmd; if (!slot->ctrl->hpc_ctlr_handle) { @@ -705,7 +697,7 @@ static void hpc_set_green_led_on(struct slot *slot) static void hpc_set_green_led_off(struct slot *slot) { - struct php_ctlr_state_s *php_ctlr =(struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; u8 slot_cmd; if (!slot->ctrl->hpc_ctlr_handle) { @@ -727,7 +719,7 @@ static void hpc_set_green_led_off(struct slot *slot) static void hpc_set_green_led_blink(struct slot *slot) { - struct php_ctlr_state_s *php_ctlr =(struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; u8 slot_cmd; if (!slot->ctrl->hpc_ctlr_handle) { @@ -754,7 +746,7 @@ int shpc_get_ctlr_slot_config(struct controller *ctrl, int *updown, /* physical_slot_num increament: 1 or -1 */ int *flags) { - struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) ctrl->hpc_ctlr_handle; + struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle; DBG_ENTER_ROUTINE @@ -776,7 +768,7 @@ int shpc_get_ctlr_slot_config(struct controller *ctrl, static void hpc_release_ctlr(struct controller *ctrl) { - struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) ctrl->hpc_ctlr_handle; + struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle; struct php_ctlr_state_s *p, *p_prev; DBG_ENTER_ROUTINE @@ -796,10 +788,8 @@ static void hpc_release_ctlr(struct controller *ctrl) } } if (php_ctlr->pci_dev) { - dbg("%s: before calling iounmap & release_mem_region\n", __FUNCTION__); iounmap(php_ctlr->creg); release_mem_region(pci_resource_start(php_ctlr->pci_dev, 0), pci_resource_len(php_ctlr->pci_dev, 0)); - dbg("%s: before calling iounmap & release_mem_region\n", __FUNCTION__); php_ctlr->pci_dev = NULL; } @@ -828,7 +818,7 @@ DBG_LEAVE_ROUTINE static int hpc_power_on_slot(struct slot * slot) { - struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; u8 slot_cmd; int retval = 0; @@ -859,7 +849,7 @@ static int hpc_power_on_slot(struct slot * slot) static int hpc_slot_enable(struct slot * slot) { - struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; u8 slot_cmd; int retval = 0; @@ -890,7 +880,7 @@ static int hpc_slot_enable(struct slot * slot) static int hpc_slot_disable(struct slot * slot) { - struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; u8 slot_cmd; int retval = 0; @@ -920,51 +910,12 @@ static int hpc_slot_disable(struct slot * slot) return retval; } -static int hpc_enable_all_slots( struct slot *slot ) -{ - int retval = 0; - - DBG_ENTER_ROUTINE - - if (!slot->ctrl->hpc_ctlr_handle) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } - - retval = shpc_write_cmd(slot, 0, SET_ENABLE_ALL); - if (retval) { - err("%s: Write command failed!\n", __FUNCTION__); - return -1; - } - - DBG_LEAVE_ROUTINE - - return retval; -} - -static int hpc_pwr_on_all_slots(struct slot *slot) -{ - int retval = 0; - - DBG_ENTER_ROUTINE - - retval = shpc_write_cmd(slot, 0, SET_PWR_ON_ALL); - - if (retval) { - err("%s: Write command failed!\n", __FUNCTION__); - return -1; - } - - DBG_LEAVE_ROUTINE - return retval; -} - static int hpc_set_bus_speed_mode(struct slot * slot, enum pci_bus_speed value) { u8 slot_cmd; u8 pi; int retval = 0; - struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; DBG_ENTER_ROUTINE @@ -1089,18 +1040,13 @@ static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs) if (!intr_loc) return IRQ_NONE; - dbg("%s: shpc_isr proceeds\n", __FUNCTION__); dbg("%s: intr_loc = %x\n",__FUNCTION__, intr_loc); if(!shpchp_poll_mode) { /* Mask Global Interrupt Mask - see implementation note on p. 139 */ /* of SHPC spec rev 1.0*/ temp_dword = readl(php_ctlr->creg + SERR_INTR_ENABLE); - dbg("%s: Before masking global interrupt, temp_dword = %x\n", - __FUNCTION__, temp_dword); temp_dword |= 0x00000001; - dbg("%s: After masking global interrupt, temp_dword = %x\n", - __FUNCTION__, temp_dword); writel(temp_dword, php_ctlr->creg + SERR_INTR_ENABLE); intr_loc2 = readl(php_ctlr->creg + INTR_LOC); @@ -1114,11 +1060,7 @@ static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs) * Detect bit in Controller SERR-INT register */ temp_dword = readl(php_ctlr->creg + SERR_INTR_ENABLE); - dbg("%s: Before clearing CCIP, temp_dword = %x\n", - __FUNCTION__, temp_dword); temp_dword &= 0xfffeffff; - dbg("%s: After clearing CCIP, temp_dword = %x\n", - __FUNCTION__, temp_dword); writel(temp_dword, php_ctlr->creg + SERR_INTR_ENABLE); wake_up_interruptible(&ctrl->queue); } @@ -1126,11 +1068,7 @@ static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs) if ((intr_loc = (intr_loc >> 1)) == 0) { /* Unmask Global Interrupt Mask */ temp_dword = readl(php_ctlr->creg + SERR_INTR_ENABLE); - dbg("%s: 1-Before unmasking global interrupt, temp_dword = %x\n", - __FUNCTION__, temp_dword); temp_dword &= 0xfffffffe; - dbg("%s: 1-After unmasking global interrupt, temp_dword = %x\n", - __FUNCTION__, temp_dword); writel(temp_dword, php_ctlr->creg + SERR_INTR_ENABLE); return IRQ_NONE; @@ -1140,11 +1078,9 @@ static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs) /* To find out which slot has interrupt pending */ if ((intr_loc >> hp_slot) & 0x01) { temp_dword = readl(php_ctlr->creg + SLOT1 + (4*hp_slot)); - dbg("%s: Slot %x with intr, temp_dword = %x\n", - __FUNCTION__, hp_slot, temp_dword); + dbg("%s: Slot %x with intr, slot register = %x\n", + __FUNCTION__, hp_slot, temp_dword); temp_byte = (temp_dword >> 16) & 0xFF; - dbg("%s: Slot with intr, temp_byte = %x\n", - __FUNCTION__, temp_byte); if ((php_ctlr->switch_change_callback) && (temp_byte & 0x08)) schedule_flag += php_ctlr->switch_change_callback( hp_slot, php_ctlr->callback_instance_id); @@ -1160,8 +1096,6 @@ static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs) /* Clear all slot events */ temp_dword = 0xe01f3fff; - dbg("%s: Clearing slot events, temp_dword = %x\n", - __FUNCTION__, temp_dword); writel(temp_dword, php_ctlr->creg + SLOT1 + (4*hp_slot)); intr_loc2 = readl(php_ctlr->creg + INTR_LOC); @@ -1171,11 +1105,7 @@ static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs) if (!shpchp_poll_mode) { /* Unmask Global Interrupt Mask */ temp_dword = readl(php_ctlr->creg + SERR_INTR_ENABLE); - dbg("%s: 2-Before unmasking global interrupt, temp_dword = %x\n", - __FUNCTION__, temp_dword); temp_dword &= 0xfffffffe; - dbg("%s: 2-After unmasking global interrupt, temp_dword = %x\n", - __FUNCTION__, temp_dword); writel(temp_dword, php_ctlr->creg + SERR_INTR_ENABLE); } @@ -1184,7 +1114,7 @@ static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs) static int hpc_get_max_bus_speed (struct slot *slot, enum pci_bus_speed *value) { - struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; enum pci_bus_speed bus_speed = PCI_SPEED_UNKNOWN; int retval = 0; u8 pi; @@ -1253,7 +1183,7 @@ static int hpc_get_max_bus_speed (struct slot *slot, enum pci_bus_speed *value) static int hpc_get_cur_bus_speed (struct slot *slot, enum pci_bus_speed *value) { - struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; enum pci_bus_speed bus_speed = PCI_SPEED_UNKNOWN; u16 sec_bus_status; int retval = 0; @@ -1367,8 +1297,6 @@ static struct hpc_ops shpchp_hpc_ops = { .power_on_slot = hpc_power_on_slot, .slot_enable = hpc_slot_enable, .slot_disable = hpc_slot_disable, - .enable_all_slots = hpc_enable_all_slots, - .pwr_on_all_slots = hpc_pwr_on_all_slots, .set_bus_speed_mode = hpc_set_bus_speed_mode, .set_attention_status = hpc_set_attention_status, .get_power_status = hpc_get_power_status, @@ -1391,12 +1319,7 @@ static struct hpc_ops shpchp_hpc_ops = { .check_cmd_status = hpc_check_cmd_status, }; -int shpc_init(struct controller * ctrl, - struct pci_dev * pdev, - php_intr_callback_t attention_button_callback, - php_intr_callback_t switch_change_callback, - php_intr_callback_t presence_change_callback, - php_intr_callback_t power_fault_callback) +int shpc_init(struct controller * ctrl, struct pci_dev * pdev) { struct php_ctlr_state_s *php_ctlr, *p; void *instance_id = ctrl; @@ -1405,7 +1328,6 @@ int shpc_init(struct controller * ctrl, static int first = 1; u32 shpc_cap_offset, shpc_base_offset; u32 tempdword, slot_reg; - u16 vendor_id, device_id; u8 i; DBG_ENTER_ROUTINE @@ -1422,21 +1344,8 @@ int shpc_init(struct controller * ctrl, php_ctlr->pci_dev = pdev; /* save pci_dev in context */ - rc = pci_read_config_word(pdev, PCI_VENDOR_ID, &vendor_id); - dbg("%s: Vendor ID: %x\n",__FUNCTION__, vendor_id); - if (rc) { - err("%s: unable to read PCI configuration data\n", __FUNCTION__); - goto abort_free_ctlr; - } - - rc = pci_read_config_word(pdev, PCI_DEVICE_ID, &device_id); - dbg("%s: Device ID: %x\n",__FUNCTION__, device_id); - if (rc) { - err("%s: unable to read PCI configuration data\n", __FUNCTION__); - goto abort_free_ctlr; - } - - if ((vendor_id == PCI_VENDOR_ID_AMD) || (device_id == PCI_DEVICE_ID_AMD_GOLAM_7450)) { + if ((pdev->vendor == PCI_VENDOR_ID_AMD) || (pdev->device == + PCI_DEVICE_ID_AMD_GOLAM_7450)) { shpc_base_offset = 0; /* amd shpc driver doesn't use this; assume 0 */ } else { if ((shpc_cap_offset = pci_find_capability(pdev, PCI_CAP_ID_SHPC)) == 0) { @@ -1469,7 +1378,8 @@ int shpc_init(struct controller * ctrl, err("%s : pci_read_config_dword failed\n", __FUNCTION__); goto abort_free_ctlr; } - dbg("%s: offset %d: tempdword %x\n", __FUNCTION__,i, tempdword); + dbg("%s: offset %d: value %x\n", __FUNCTION__,i, + tempdword); } } @@ -1478,13 +1388,6 @@ int shpc_init(struct controller * ctrl, first = 0; } - dbg("pdev = %p: b:d:f:irq=0x%x:%x:%x:%x\n", pdev, pdev->bus->number, PCI_SLOT(pdev->devfn), - PCI_FUNC(pdev->devfn), pdev->irq); - for ( rc = 0; rc < DEVICE_COUNT_RESOURCE; rc++) - if (pci_resource_len(pdev, rc) > 0) - dbg("pci resource[%d] start=0x%lx(len=0x%lx), shpc_base_offset %x\n", rc, - pci_resource_start(pdev, rc), pci_resource_len(pdev, rc), shpc_base_offset); - info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device, pdev->subsystem_vendor, pdev->subsystem_device); @@ -1504,7 +1407,6 @@ int shpc_init(struct controller * ctrl, goto abort_free_ctlr; } dbg("%s: php_ctlr->creg %p\n", __FUNCTION__, php_ctlr->creg); - dbg("%s: physical addr %p\n", __FUNCTION__, (void*)pci_resource_start(pdev, 0)); init_MUTEX(&ctrl->crit_sect); /* Setup wait queue */ @@ -1512,13 +1414,10 @@ int shpc_init(struct controller * ctrl, /* Find the IRQ */ php_ctlr->irq = pdev->irq; - dbg("HPC interrupt = %d\n", php_ctlr->irq); - - /* Save interrupt callback info */ - php_ctlr->attention_button_callback = attention_button_callback; - php_ctlr->switch_change_callback = switch_change_callback; - php_ctlr->presence_change_callback = presence_change_callback; - php_ctlr->power_fault_callback = power_fault_callback; + php_ctlr->attention_button_callback = shpchp_handle_attention_button, + php_ctlr->switch_change_callback = shpchp_handle_switch_change; + php_ctlr->presence_change_callback = shpchp_handle_presence_change; + php_ctlr->power_fault_callback = shpchp_handle_power_fault; php_ctlr->callback_instance_id = instance_id; /* Return PCI Controller Info */ @@ -1556,7 +1455,6 @@ int shpc_init(struct controller * ctrl, if (rc) { info("Can't get msi for the hotplug controller\n"); info("Use INTx for the hotplug controller\n"); - dbg("%s: rc = %x\n", __FUNCTION__, rc); } else php_ctlr->irq = pdev->irq; @@ -1566,9 +1464,11 @@ int shpc_init(struct controller * ctrl, err("Can't get irq %d for the hotplug controller\n", php_ctlr->irq); goto abort_free_ctlr; } - /* Execute OSHP method here */ } - dbg("%s: Before adding HPC to HPC list\n", __FUNCTION__); + dbg("%s: HPC at b:d:f:irq=0x%x:%x:%x:%x\n", __FUNCTION__, + pdev->bus->number, PCI_SLOT(pdev->devfn), + PCI_FUNC(pdev->devfn), pdev->irq); + get_hp_hw_control_from_firmware(pdev); /* Add this HPC instance into the HPC list */ spin_lock(&list_lock); @@ -1607,7 +1507,6 @@ int shpc_init(struct controller * ctrl, dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword); } - dbg("%s: Leaving shpc_init\n", __FUNCTION__); DBG_LEAVE_ROUTINE return 0; diff --git a/drivers/pci/hotplug/shpchp_pci.c b/drivers/pci/hotplug/shpchp_pci.c index d867099114ec..b8e95acea3b6 100644 --- a/drivers/pci/hotplug/shpchp_pci.c +++ b/drivers/pci/hotplug/shpchp_pci.c @@ -27,784 +27,151 @@ * */ -#include <linux/config.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/types.h> -#include <linux/slab.h> -#include <linux/workqueue.h> -#include <linux/proc_fs.h> #include <linux/pci.h> #include "../pci.h" #include "shpchp.h" -#ifndef CONFIG_IA64 -#include "../../../arch/i386/pci/pci.h" /* horrible hack showing how processor dependant we are... */ -#endif -int shpchp_configure_device (struct controller* ctrl, struct pci_func* func) +void program_fw_provided_values(struct pci_dev *dev) { - unsigned char bus; - struct pci_bus *child; - int num; - - if (func->pci_dev == NULL) - func->pci_dev = pci_find_slot(func->bus, PCI_DEVFN(func->device, func->function)); - - /* Still NULL ? Well then scan for it ! */ - if (func->pci_dev == NULL) { - num = pci_scan_slot(ctrl->pci_dev->subordinate, PCI_DEVFN(func->device, func->function)); - if (num) { - dbg("%s: subordiante %p number %x\n", __FUNCTION__, ctrl->pci_dev->subordinate, - ctrl->pci_dev->subordinate->number); - pci_bus_add_devices(ctrl->pci_dev->subordinate); - } - - func->pci_dev = pci_find_slot(func->bus, PCI_DEVFN(func->device, func->function)); - if (func->pci_dev == NULL) { - dbg("ERROR: pci_dev still null\n"); - return 0; + u16 pci_cmd, pci_bctl; + struct pci_dev *cdev; + struct hotplug_params hpp = {0x8, 0x40, 0, 0}; /* defaults */ + + /* Program hpp values for this device */ + if (!(dev->hdr_type == PCI_HEADER_TYPE_NORMAL || + (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE && + (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI))) + return; + + get_hp_params_from_firmware(dev, &hpp); + + pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, hpp.cache_line_size); + pci_write_config_byte(dev, PCI_LATENCY_TIMER, hpp.latency_timer); + pci_read_config_word(dev, PCI_COMMAND, &pci_cmd); + if (hpp.enable_serr) + pci_cmd |= PCI_COMMAND_SERR; + else + pci_cmd &= ~PCI_COMMAND_SERR; + if (hpp.enable_perr) + pci_cmd |= PCI_COMMAND_PARITY; + else + pci_cmd &= ~PCI_COMMAND_PARITY; + pci_write_config_word(dev, PCI_COMMAND, pci_cmd); + + /* Program bridge control value and child devices */ + if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { + pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, + hpp.latency_timer); + pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &pci_bctl); + if (hpp.enable_serr) + pci_bctl |= PCI_BRIDGE_CTL_SERR; + else + pci_bctl &= ~PCI_BRIDGE_CTL_SERR; + if (hpp.enable_perr) + pci_bctl |= PCI_BRIDGE_CTL_PARITY; + else + pci_bctl &= ~PCI_BRIDGE_CTL_PARITY; + pci_write_config_word(dev, PCI_BRIDGE_CONTROL, pci_bctl); + if (dev->subordinate) { + list_for_each_entry(cdev, &dev->subordinate->devices, + bus_list) + program_fw_provided_values(cdev); } } - - if (func->pci_dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { - pci_read_config_byte(func->pci_dev, PCI_SECONDARY_BUS, &bus); - child = pci_add_new_bus(func->pci_dev->bus, (func->pci_dev), bus); - pci_do_scan_bus(child); - - } - - return 0; } - -int shpchp_unconfigure_device(struct pci_func* func) +int shpchp_configure_device(struct slot *p_slot) { - int rc = 0; - int j; - - dbg("%s: bus/dev/func = %x/%x/%x\n", __FUNCTION__, func->bus, - func->device, func->function); - - for (j=0; j<8 ; j++) { - struct pci_dev* temp = pci_find_slot(func->bus, - (func->device << 3) | j); - if (temp) { - pci_remove_bus_device(temp); - } + struct pci_dev *dev; + struct pci_bus *parent = p_slot->ctrl->pci_dev->subordinate; + int num, fn; + + dev = pci_find_slot(p_slot->bus, PCI_DEVFN(p_slot->device, 0)); + if (dev) { + err("Device %s already exists at %x:%x, cannot hot-add\n", + pci_name(dev), p_slot->bus, p_slot->device); + return -EINVAL; } - return rc; -} - -/* - * shpchp_set_irq - * - * @bus_num: bus number of PCI device - * @dev_num: device number of PCI device - * @slot: pointer to u8 where slot number will be returned - */ -int shpchp_set_irq (u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num) -{ -#if defined(CONFIG_X86) && !defined(CONFIG_X86_IO_APIC) && !defined(CONFIG_X86_64) - int rc; - u16 temp_word; - struct pci_dev fakedev; - struct pci_bus fakebus; - fakedev.devfn = dev_num << 3; - fakedev.bus = &fakebus; - fakebus.number = bus_num; - dbg("%s: dev %d, bus %d, pin %d, num %d\n", - __FUNCTION__, dev_num, bus_num, int_pin, irq_num); - rc = pcibios_set_irq_routing(&fakedev, int_pin - 0x0a, irq_num); - dbg("%s: rc %d\n", __FUNCTION__, rc); - if (!rc) - return !rc; - - /* set the Edge Level Control Register (ELCR) */ - temp_word = inb(0x4d0); - temp_word |= inb(0x4d1) << 8; - - temp_word |= 0x01 << irq_num; - - /* This should only be for x86 as it sets the Edge Level Control Register */ - outb((u8) (temp_word & 0xFF), 0x4d0); - outb((u8) ((temp_word & 0xFF00) >> 8), 0x4d1); -#endif - return 0; -} - -/* More PCI configuration routines; this time centered around hotplug controller */ - - -/* - * shpchp_save_config - * - * Reads configuration for all slots in a PCI bus and saves info. - * - * Note: For non-hot plug busses, the slot # saved is the device # - * - * returns 0 if success - */ -int shpchp_save_config(struct controller *ctrl, int busnumber, int num_ctlr_slots, int first_device_num) -{ - int rc; - u8 class_code; - u8 header_type; - u32 ID; - u8 secondary_bus; - struct pci_func *new_slot; - int sub_bus; - int FirstSupported; - int LastSupported; - int max_functions; - int function; - u8 DevError; - int device = 0; - int cloop = 0; - int stop_it; - int index; - int is_hot_plug = num_ctlr_slots || first_device_num; - struct pci_bus lpci_bus, *pci_bus; - - dbg("%s: num_ctlr_slots = %d, first_device_num = %d\n", __FUNCTION__, - num_ctlr_slots, first_device_num); - - memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus)); - pci_bus = &lpci_bus; - - dbg("%s: num_ctlr_slots = %d, first_device_num = %d\n", __FUNCTION__, - num_ctlr_slots, first_device_num); - - /* Decide which slots are supported */ - if (is_hot_plug) { - /********************************* - * is_hot_plug is the slot mask - *********************************/ - FirstSupported = first_device_num; - LastSupported = FirstSupported + num_ctlr_slots - 1; - } else { - FirstSupported = 0; - LastSupported = 0x1F; + num = pci_scan_slot(parent, PCI_DEVFN(p_slot->device, 0)); + if (num == 0) { + err("No new device found\n"); + return -ENODEV; } - dbg("FirstSupported = %d, LastSupported = %d\n", FirstSupported, - LastSupported); - - /* Save PCI configuration space for all devices in supported slots */ - pci_bus->number = busnumber; - for (device = FirstSupported; device <= LastSupported; device++) { - ID = 0xFFFFFFFF; - rc = pci_bus_read_config_dword(pci_bus, PCI_DEVFN(device, 0), - PCI_VENDOR_ID, &ID); - - if (ID != 0xFFFFFFFF) { /* device in slot */ - rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(device, 0), - 0x0B, &class_code); - if (rc) - return rc; - - rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(device, 0), - PCI_HEADER_TYPE, &header_type); - if (rc) - return rc; - - dbg("class_code = %x, header_type = %x\n", class_code, header_type); - - /* If multi-function device, set max_functions to 8 */ - if (header_type & 0x80) - max_functions = 8; - else - max_functions = 1; - - function = 0; - - do { - DevError = 0; - - if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { /* P-P Bridge */ - /* Recurse the subordinate bus - * get the subordinate bus number - */ - rc = pci_bus_read_config_byte(pci_bus, - PCI_DEVFN(device, function), - PCI_SECONDARY_BUS, &secondary_bus); - if (rc) { - return rc; - } else { - sub_bus = (int) secondary_bus; - - /* Save secondary bus cfg spc with this recursive call. */ - rc = shpchp_save_config(ctrl, sub_bus, 0, 0); - if (rc) - return rc; - } - } - - index = 0; - new_slot = shpchp_slot_find(busnumber, device, index++); - - dbg("new_slot = %p\n", new_slot); - - while (new_slot && (new_slot->function != (u8) function)) { - new_slot = shpchp_slot_find(busnumber, device, index++); - dbg("new_slot = %p\n", new_slot); - } - if (!new_slot) { - /* Setup slot structure. */ - new_slot = shpchp_slot_create(busnumber); - dbg("new_slot = %p\n", new_slot); - - if (new_slot == NULL) - return(1); - } - - new_slot->bus = (u8) busnumber; - new_slot->device = (u8) device; - new_slot->function = (u8) function; - new_slot->is_a_board = 1; - new_slot->switch_save = 0x10; - new_slot->pwr_save = 1; - /* In case of unsupported board */ - new_slot->status = DevError; - new_slot->pci_dev = pci_find_slot(new_slot->bus, - (new_slot->device << 3) | new_slot->function); - dbg("new_slot->pci_dev = %p\n", new_slot->pci_dev); - - for (cloop = 0; cloop < 0x20; cloop++) { - rc = pci_bus_read_config_dword(pci_bus, - PCI_DEVFN(device, function), - cloop << 2, - (u32 *) &(new_slot->config_space [cloop])); - /* dbg("new_slot->config_space[%x] = %x\n", - cloop, new_slot->config_space[cloop]); */ - if (rc) - return rc; - } - - function++; - - stop_it = 0; - - /* this loop skips to the next present function - * reading in Class Code and Header type. - */ - - while ((function < max_functions)&&(!stop_it)) { - rc = pci_bus_read_config_dword(pci_bus, - PCI_DEVFN(device, function), - PCI_VENDOR_ID, &ID); - - if (ID == 0xFFFFFFFF) { /* nothing there. */ - function++; - dbg("Nothing there\n"); - } else { /* Something there */ - rc = pci_bus_read_config_byte(pci_bus, - PCI_DEVFN(device, function), - 0x0B, &class_code); - if (rc) - return rc; - - rc = pci_bus_read_config_byte(pci_bus, - PCI_DEVFN(device, function), - PCI_HEADER_TYPE, &header_type); - if (rc) - return rc; - - dbg("class_code = %x, header_type = %x\n", - class_code, header_type); - stop_it++; - } - } - - } while (function < max_functions); - /* End of IF (device in slot?) */ - } else if (is_hot_plug) { - /* Setup slot structure with entry for empty slot */ - new_slot = shpchp_slot_create(busnumber); - - if (new_slot == NULL) { - return(1); - } - dbg("new_slot = %p\n", new_slot); - - new_slot->bus = (u8) busnumber; - new_slot->device = (u8) device; - new_slot->function = 0; - new_slot->is_a_board = 0; - new_slot->presence_save = 0; - new_slot->switch_save = 0; + for (fn = 0; fn < 8; fn++) { + if (!(dev = pci_find_slot(p_slot->bus, + PCI_DEVFN(p_slot->device, fn)))) + continue; + if ((dev->class >> 16) == PCI_BASE_CLASS_DISPLAY) { + err("Cannot hot-add display device %s\n", + pci_name(dev)); + continue; } - } /* End of FOR loop */ - - return(0); -} - - -/* - * shpchp_save_slot_config - * - * Saves configuration info for all PCI devices in a given slot - * including subordinate busses. - * - * returns 0 if success - */ -int shpchp_save_slot_config(struct controller *ctrl, struct pci_func * new_slot) -{ - int rc; - u8 class_code; - u8 header_type; - u32 ID; - u8 secondary_bus; - int sub_bus; - int max_functions; - int function; - int cloop = 0; - int stop_it; - struct pci_bus lpci_bus, *pci_bus; - memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus)); - pci_bus = &lpci_bus; - pci_bus->number = new_slot->bus; - - ID = 0xFFFFFFFF; - - pci_bus_read_config_dword(pci_bus, PCI_DEVFN(new_slot->device, 0), - PCI_VENDOR_ID, &ID); - - if (ID != 0xFFFFFFFF) { /* device in slot */ - pci_bus_read_config_byte(pci_bus, PCI_DEVFN(new_slot->device, 0), - 0x0B, &class_code); - - pci_bus_read_config_byte(pci_bus, PCI_DEVFN(new_slot->device, 0), - PCI_HEADER_TYPE, &header_type); - - if (header_type & 0x80) /* Multi-function device */ - max_functions = 8; - else - max_functions = 1; - - function = 0; - - do { - if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { /* PCI-PCI Bridge */ - /* Recurse the subordinate bus */ - pci_bus_read_config_byte(pci_bus, - PCI_DEVFN(new_slot->device, function), - PCI_SECONDARY_BUS, &secondary_bus); - - sub_bus = (int) secondary_bus; - - /* Save the config headers for the secondary bus. */ - rc = shpchp_save_config(ctrl, sub_bus, 0, 0); - - if (rc) - return rc; - - } /* End of IF */ - - new_slot->status = 0; - - for (cloop = 0; cloop < 0x20; cloop++) { - pci_bus_read_config_dword(pci_bus, - PCI_DEVFN(new_slot->device, function), - cloop << 2, - (u32 *) &(new_slot->config_space [cloop])); + if ((dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) || + (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)) { + /* Find an unused bus number for the new bridge */ + struct pci_bus *child; + unsigned char busnr, start = parent->secondary; + unsigned char end = parent->subordinate; + for (busnr = start; busnr <= end; busnr++) { + if (!pci_find_bus(pci_domain_nr(parent), + busnr)) + break; } - - function++; - - stop_it = 0; - - /* this loop skips to the next present function - * reading in the Class Code and the Header type. - */ - - while ((function < max_functions) && (!stop_it)) { - pci_bus_read_config_dword(pci_bus, - PCI_DEVFN(new_slot->device, function), - PCI_VENDOR_ID, &ID); - - if (ID == 0xFFFFFFFF) { /* nothing there. */ - function++; - } else { /* Something there */ - pci_bus_read_config_byte(pci_bus, - PCI_DEVFN(new_slot->device, function), - 0x0B, &class_code); - - pci_bus_read_config_byte(pci_bus, - PCI_DEVFN(new_slot->device, function), - PCI_HEADER_TYPE, &header_type); - - stop_it++; - } + if (busnr >= end) { + err("No free bus for hot-added bridge\n"); + continue; } - - } while (function < max_functions); - } /* End of IF (device in slot?) */ - else { - return 2; + child = pci_add_new_bus(parent, dev, busnr); + if (!child) { + err("Cannot add new bus for %s\n", + pci_name(dev)); + continue; + } + child->subordinate = pci_do_scan_bus(child); + pci_bus_size_bridges(child); + } + program_fw_provided_values(dev); } + pci_bus_assign_resources(parent); + pci_bus_add_devices(parent); + pci_enable_bridges(parent); return 0; } - -/* - * shpchp_save_used_resources - * - * Stores used resource information for existing boards. this is - * for boards that were in the system when this driver was loaded. - * this function is for hot plug ADD - * - * returns 0 if success - * if disable == 1(DISABLE_CARD), - * it loops for all functions of the slot and disables them. - * else, it just get resources of the function and return. - */ -int shpchp_save_used_resources(struct controller *ctrl, struct pci_func *func, int disable) +int shpchp_unconfigure_device(struct slot *p_slot) { - u8 cloop; - u8 header_type; - u8 secondary_bus; - u8 temp_byte; - u16 command; - u16 save_command; - u16 w_base, w_length; - u32 temp_register; - u32 save_base; - u32 base, length; - u64 base64 = 0; - int index = 0; - unsigned int devfn; - struct pci_resource *mem_node = NULL; - struct pci_resource *p_mem_node = NULL; - struct pci_resource *t_mem_node; - struct pci_resource *io_node; - struct pci_resource *bus_node; - struct pci_bus lpci_bus, *pci_bus; - memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus)); - pci_bus = &lpci_bus; - - if (disable) - func = shpchp_slot_find(func->bus, func->device, index++); - - while ((func != NULL) && func->is_a_board) { - pci_bus->number = func->bus; - devfn = PCI_DEVFN(func->device, func->function); - - /* Save the command register */ - pci_bus_read_config_word(pci_bus, devfn, PCI_COMMAND, &save_command); + int rc = 0; + int j; + u8 bctl = 0; + + dbg("%s: bus/dev = %x/%x\n", __FUNCTION__, p_slot->bus, p_slot->device); - if (disable) { - /* disable card */ - command = 0x00; - pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command); + for (j=0; j<8 ; j++) { + struct pci_dev* temp = pci_find_slot(p_slot->bus, + (p_slot->device << 3) | j); + if (!temp) + continue; + if ((temp->class >> 16) == PCI_BASE_CLASS_DISPLAY) { + err("Cannot remove display device %s\n", + pci_name(temp)); + continue; } - - /* Check for Bridge */ - pci_bus_read_config_byte(pci_bus, devfn, PCI_HEADER_TYPE, &header_type); - - if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { /* PCI-PCI Bridge */ - dbg("Save_used_res of PCI bridge b:d=0x%x:%x, sc=0x%x\n", - func->bus, func->device, save_command); - if (disable) { - /* Clear Bridge Control Register */ - command = 0x00; - pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, command); + if (temp->hdr_type == PCI_HEADER_TYPE_BRIDGE) { + pci_read_config_byte(temp, PCI_BRIDGE_CONTROL, &bctl); + if (bctl & PCI_BRIDGE_CTL_VGA) { + err("Cannot remove display device %s\n", + pci_name(temp)); + continue; } - - pci_bus_read_config_byte(pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus); - pci_bus_read_config_byte(pci_bus, devfn, PCI_SUBORDINATE_BUS, &temp_byte); - - bus_node = kmalloc(sizeof(struct pci_resource), - GFP_KERNEL); - if (!bus_node) - return -ENOMEM; - - bus_node->base = (ulong)secondary_bus; - bus_node->length = (ulong)(temp_byte - secondary_bus + 1); - - bus_node->next = func->bus_head; - func->bus_head = bus_node; - - /* Save IO base and Limit registers */ - pci_bus_read_config_byte(pci_bus, devfn, PCI_IO_BASE, &temp_byte); - base = temp_byte; - pci_bus_read_config_byte(pci_bus, devfn, PCI_IO_LIMIT, &temp_byte); - length = temp_byte; - - if ((base <= length) && (!disable || (save_command & PCI_COMMAND_IO))) { - io_node = kmalloc(sizeof(struct pci_resource), - GFP_KERNEL); - if (!io_node) - return -ENOMEM; - - io_node->base = (ulong)(base & PCI_IO_RANGE_MASK) << 8; - io_node->length = (ulong)(length - base + 0x10) << 8; - - io_node->next = func->io_head; - func->io_head = io_node; - } - - /* Save memory base and Limit registers */ - pci_bus_read_config_word(pci_bus, devfn, PCI_MEMORY_BASE, &w_base); - pci_bus_read_config_word(pci_bus, devfn, PCI_MEMORY_LIMIT, &w_length); - - if ((w_base <= w_length) && (!disable || (save_command & PCI_COMMAND_MEMORY))) { - mem_node = kmalloc(sizeof(struct pci_resource), - GFP_KERNEL); - if (!mem_node) - return -ENOMEM; - - mem_node->base = (ulong)w_base << 16; - mem_node->length = (ulong)(w_length - w_base + 0x10) << 16; - - mem_node->next = func->mem_head; - func->mem_head = mem_node; - } - /* Save prefetchable memory base and Limit registers */ - pci_bus_read_config_word(pci_bus, devfn, PCI_PREF_MEMORY_BASE, &w_base); - pci_bus_read_config_word(pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, &w_length); - - if ((w_base <= w_length) && (!disable || (save_command & PCI_COMMAND_MEMORY))) { - p_mem_node = kmalloc(sizeof(struct pci_resource), - GFP_KERNEL); - if (!p_mem_node) - return -ENOMEM; - - p_mem_node->base = (ulong)w_base << 16; - p_mem_node->length = (ulong)(w_length - w_base + 0x10) << 16; - - p_mem_node->next = func->p_mem_head; - func->p_mem_head = p_mem_node; - } - } else if ((header_type & 0x7F) == PCI_HEADER_TYPE_NORMAL) { - dbg("Save_used_res of PCI adapter b:d=0x%x:%x, sc=0x%x\n", - func->bus, func->device, save_command); - - /* Figure out IO and memory base lengths */ - for (cloop = PCI_BASE_ADDRESS_0; cloop <= PCI_BASE_ADDRESS_5; cloop += 4) { - pci_bus_read_config_dword(pci_bus, devfn, cloop, &save_base); - - temp_register = 0xFFFFFFFF; - pci_bus_write_config_dword(pci_bus, devfn, cloop, temp_register); - pci_bus_read_config_dword(pci_bus, devfn, cloop, &temp_register); - - if (!disable) - pci_bus_write_config_dword(pci_bus, devfn, cloop, save_base); - - if (!temp_register) - continue; - - base = temp_register; - - if ((base & PCI_BASE_ADDRESS_SPACE_IO) && - (!disable || (save_command & PCI_COMMAND_IO))) { - /* IO base */ - /* set temp_register = amount of IO space requested */ - base = base & 0xFFFFFFFCL; - base = (~base) + 1; - - io_node = kmalloc(sizeof (struct pci_resource), - GFP_KERNEL); - if (!io_node) - return -ENOMEM; - - io_node->base = (ulong)save_base & PCI_BASE_ADDRESS_IO_MASK; - io_node->length = (ulong)base; - dbg("sur adapter: IO bar=0x%x(length=0x%x)\n", - io_node->base, io_node->length); - - io_node->next = func->io_head; - func->io_head = io_node; - } else { /* map Memory */ - int prefetchable = 1; - /* struct pci_resources **res_node; */ - char *res_type_str = "PMEM"; - u32 temp_register2; - - t_mem_node = kmalloc(sizeof (struct pci_resource), - GFP_KERNEL); - if (!t_mem_node) - return -ENOMEM; - - if (!(base & PCI_BASE_ADDRESS_MEM_PREFETCH) && - (!disable || (save_command & PCI_COMMAND_MEMORY))) { - prefetchable = 0; - mem_node = t_mem_node; - res_type_str++; - } else - p_mem_node = t_mem_node; - - base = base & 0xFFFFFFF0L; - base = (~base) + 1; - - switch (temp_register & PCI_BASE_ADDRESS_MEM_TYPE_MASK) { - case PCI_BASE_ADDRESS_MEM_TYPE_32: - if (prefetchable) { - p_mem_node->base = (ulong)save_base & PCI_BASE_ADDRESS_MEM_MASK; - p_mem_node->length = (ulong)base; - dbg("sur adapter: 32 %s bar=0x%x(length=0x%x)\n", - res_type_str, - p_mem_node->base, - p_mem_node->length); - - p_mem_node->next = func->p_mem_head; - func->p_mem_head = p_mem_node; - } else { - mem_node->base = (ulong)save_base & PCI_BASE_ADDRESS_MEM_MASK; - mem_node->length = (ulong)base; - dbg("sur adapter: 32 %s bar=0x%x(length=0x%x)\n", - res_type_str, - mem_node->base, - mem_node->length); - - mem_node->next = func->mem_head; - func->mem_head = mem_node; - } - break; - case PCI_BASE_ADDRESS_MEM_TYPE_64: - pci_bus_read_config_dword(pci_bus, devfn, cloop+4, &temp_register2); - base64 = temp_register2; - base64 = (base64 << 32) | save_base; - - if (temp_register2) { - dbg("sur adapter: 64 %s high dword of base64(0x%x:%x) masked to 0\n", - res_type_str, temp_register2, (u32)base64); - base64 &= 0x00000000FFFFFFFFL; - } - - if (prefetchable) { - p_mem_node->base = base64 & PCI_BASE_ADDRESS_MEM_MASK; - p_mem_node->length = base; - dbg("sur adapter: 64 %s base=0x%x(len=0x%x)\n", - res_type_str, - p_mem_node->base, - p_mem_node->length); - - p_mem_node->next = func->p_mem_head; - func->p_mem_head = p_mem_node; - } else { - mem_node->base = base64 & PCI_BASE_ADDRESS_MEM_MASK; - mem_node->length = base; - dbg("sur adapter: 64 %s base=0x%x(len=0x%x)\n", - res_type_str, - mem_node->base, - mem_node->length); - - mem_node->next = func->mem_head; - func->mem_head = mem_node; - } - cloop += 4; - break; - default: - dbg("asur: reserved BAR type=0x%x\n", - temp_register); - break; - } - } - } /* End of base register loop */ - } else { /* Some other unknown header type */ - dbg("Save_used_res of PCI unknown type b:d=0x%x:%x. skip.\n", - func->bus, func->device); } - - /* find the next device in this slot */ - if (!disable) - break; - func = shpchp_slot_find(func->bus, func->device, index++); + pci_remove_bus_device(temp); } - - return 0; -} - -/** - * kfree_resource_list: release memory of all list members - * @res: resource list to free - */ -static inline void -return_resource_list(struct pci_resource **func, struct pci_resource **res) -{ - struct pci_resource *node; - struct pci_resource *t_node; - - node = *func; - *func = NULL; - while (node) { - t_node = node->next; - return_resource(res, node); - node = t_node; - } -} - -/* - * shpchp_return_board_resources - * - * this routine returns all resources allocated to a board to - * the available pool. - * - * returns 0 if success - */ -int shpchp_return_board_resources(struct pci_func * func, - struct resource_lists * resources) -{ - int rc; - dbg("%s\n", __FUNCTION__); - - if (!func) - return 1; - - return_resource_list(&(func->io_head),&(resources->io_head)); - return_resource_list(&(func->mem_head),&(resources->mem_head)); - return_resource_list(&(func->p_mem_head),&(resources->p_mem_head)); - return_resource_list(&(func->bus_head),&(resources->bus_head)); - - rc = shpchp_resource_sort_and_combine(&(resources->mem_head)); - rc |= shpchp_resource_sort_and_combine(&(resources->p_mem_head)); - rc |= shpchp_resource_sort_and_combine(&(resources->io_head)); - rc |= shpchp_resource_sort_and_combine(&(resources->bus_head)); - return rc; } -/** - * kfree_resource_list: release memory of all list members - * @res: resource list to free - */ -static inline void -kfree_resource_list(struct pci_resource **r) -{ - struct pci_resource *res, *tres; - - res = *r; - *r = NULL; - - while (res) { - tres = res; - res = res->next; - kfree(tres); - } -} - -/** - * shpchp_destroy_resource_list: put node back in the resource list - * @resources: list to put nodes back - */ -void shpchp_destroy_resource_list(struct resource_lists *resources) -{ - kfree_resource_list(&(resources->io_head)); - kfree_resource_list(&(resources->mem_head)); - kfree_resource_list(&(resources->p_mem_head)); - kfree_resource_list(&(resources->bus_head)); -} - -/** - * shpchp_destroy_board_resources: put node back in the resource list - * @resources: list to put nodes back - */ -void shpchp_destroy_board_resources(struct pci_func * func) -{ - kfree_resource_list(&(func->io_head)); - kfree_resource_list(&(func->mem_head)); - kfree_resource_list(&(func->p_mem_head)); - kfree_resource_list(&(func->bus_head)); -} diff --git a/drivers/pci/hotplug/shpchp_sysfs.c b/drivers/pci/hotplug/shpchp_sysfs.c index c9445ebda5c7..f5cfbf2c047c 100644 --- a/drivers/pci/hotplug/shpchp_sysfs.c +++ b/drivers/pci/hotplug/shpchp_sysfs.c @@ -26,12 +26,9 @@ * */ -#include <linux/config.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/types.h> -#include <linux/proc_fs.h> -#include <linux/workqueue.h> #include <linux/pci.h> #include "shpchp.h" @@ -40,104 +37,60 @@ static ssize_t show_ctrl (struct device *dev, struct device_attribute *attr, char *buf) { - struct pci_dev *pci_dev; - struct controller *ctrl; + struct pci_dev *pdev; char * out = buf; - int index; - struct pci_resource *res; + int index, busnr; + struct resource *res; + struct pci_bus *bus; - pci_dev = container_of (dev, struct pci_dev, dev); - ctrl = pci_get_drvdata(pci_dev); + pdev = container_of (dev, struct pci_dev, dev); + bus = pdev->subordinate; out += sprintf(buf, "Free resources: memory\n"); - index = 11; - res = ctrl->mem_head; - while (res && index--) { - out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); - res = res->next; + for (index = 0; index < PCI_BUS_NUM_RESOURCES; index++) { + res = bus->resource[index]; + if (res && (res->flags & IORESOURCE_MEM) && + !(res->flags & IORESOURCE_PREFETCH)) { + out += sprintf(out, "start = %8.8lx, length = %8.8lx\n", + res->start, (res->end - res->start)); + } } out += sprintf(out, "Free resources: prefetchable memory\n"); - index = 11; - res = ctrl->p_mem_head; - while (res && index--) { - out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); - res = res->next; + for (index = 0; index < PCI_BUS_NUM_RESOURCES; index++) { + res = bus->resource[index]; + if (res && (res->flags & IORESOURCE_MEM) && + (res->flags & IORESOURCE_PREFETCH)) { + out += sprintf(out, "start = %8.8lx, length = %8.8lx\n", + res->start, (res->end - res->start)); + } } out += sprintf(out, "Free resources: IO\n"); - index = 11; - res = ctrl->io_head; - while (res && index--) { - out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); - res = res->next; + for (index = 0; index < PCI_BUS_NUM_RESOURCES; index++) { + res = bus->resource[index]; + if (res && (res->flags & IORESOURCE_IO)) { + out += sprintf(out, "start = %8.8lx, length = %8.8lx\n", + res->start, (res->end - res->start)); + } } out += sprintf(out, "Free resources: bus numbers\n"); - index = 11; - res = ctrl->bus_head; - while (res && index--) { - out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); - res = res->next; + for (busnr = bus->secondary; busnr <= bus->subordinate; busnr++) { + if (!pci_find_bus(pci_domain_nr(bus), busnr)) + break; } + if (busnr < bus->subordinate) + out += sprintf(out, "start = %8.8x, length = %8.8x\n", + busnr, (bus->subordinate - busnr)); return out - buf; } static DEVICE_ATTR (ctrl, S_IRUGO, show_ctrl, NULL); -static ssize_t show_dev (struct device *dev, struct device_attribute *attr, char *buf) +void shpchp_create_ctrl_files (struct controller *ctrl) { - struct pci_dev *pci_dev; - struct controller *ctrl; - char * out = buf; - int index; - struct pci_resource *res; - struct pci_func *new_slot; - struct slot *slot; - - pci_dev = container_of (dev, struct pci_dev, dev); - ctrl = pci_get_drvdata(pci_dev); - - slot=ctrl->slot; - - while (slot) { - new_slot = shpchp_slot_find(slot->bus, slot->device, 0); - if (!new_slot) - break; - out += sprintf(out, "assigned resources: memory\n"); - index = 11; - res = new_slot->mem_head; - while (res && index--) { - out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); - res = res->next; - } - out += sprintf(out, "assigned resources: prefetchable memory\n"); - index = 11; - res = new_slot->p_mem_head; - while (res && index--) { - out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); - res = res->next; - } - out += sprintf(out, "assigned resources: IO\n"); - index = 11; - res = new_slot->io_head; - while (res && index--) { - out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); - res = res->next; - } - out += sprintf(out, "assigned resources: bus numbers\n"); - index = 11; - res = new_slot->bus_head; - while (res && index--) { - out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); - res = res->next; - } - slot=slot->next; - } - - return out - buf; + device_create_file (&ctrl->pci_dev->dev, &dev_attr_ctrl); } -static DEVICE_ATTR (dev, S_IRUGO, show_dev, NULL); -void shpchp_create_ctrl_files (struct controller *ctrl) +void shpchp_remove_ctrl_files(struct controller *ctrl) { - device_create_file (&ctrl->pci_dev->dev, &dev_attr_ctrl); - device_create_file (&ctrl->pci_dev->dev, &dev_attr_dev); + device_remove_file(&ctrl->pci_dev->dev, &dev_attr_ctrl); } diff --git a/drivers/pci/hotplug/shpchprm.h b/drivers/pci/hotplug/shpchprm.h deleted file mode 100644 index 057b192ce589..000000000000 --- a/drivers/pci/hotplug/shpchprm.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * SHPCHPRM : SHPCHP Resource Manager for ACPI/non-ACPI platform - * - * Copyright (C) 1995,2001 Compaq Computer Corporation - * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (C) 2001 IBM Corp. - * Copyright (C) 2003-2004 Intel Corporation - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License 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, GOOD TITLE or - * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Send feedback to <greg@kroah.com>, <kristen.c.accardi@intel.com> - * - */ - -#ifndef _SHPCHPRM_H_ -#define _SHPCHPRM_H_ - -#ifdef CONFIG_HOTPLUG_PCI_SHPC_PHPRM_LEGACY -#include "shpchprm_legacy.h" -#else -#include "shpchprm_nonacpi.h" -#endif - -int shpchprm_init(enum php_ctlr_type ct); -void shpchprm_cleanup(void); -int shpchprm_print_pirt(void); -int shpchprm_find_available_resources(struct controller *ctrl); -int shpchprm_set_hpp(struct controller *ctrl, struct pci_func *func, u8 card_type); -void shpchprm_enable_card(struct controller *ctrl, struct pci_func *func, u8 card_type); -int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum); - -#ifdef DEBUG -#define RES_CHECK(this, bits) \ - { if (((this) & (bits - 1))) \ - printk("%s:%d ERR: potential res loss!\n", __FUNCTION__, __LINE__); } -#else -#define RES_CHECK(this, bits) -#endif - -#endif /* _SHPCHPRM_H_ */ diff --git a/drivers/pci/hotplug/shpchprm_acpi.c b/drivers/pci/hotplug/shpchprm_acpi.c index d37b31658edf..17145e52223a 100644 --- a/drivers/pci/hotplug/shpchprm_acpi.c +++ b/drivers/pci/hotplug/shpchprm_acpi.c @@ -24,91 +24,19 @@ * */ -#include <linux/config.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/types.h> #include <linux/pci.h> -#include <linux/init.h> -#include <linux/acpi.h> -#include <linux/efi.h> -#include <asm/uaccess.h> -#include <asm/system.h> -#ifdef CONFIG_IA64 -#include <asm/iosapic.h> -#endif #include <acpi/acpi.h> #include <acpi/acpi_bus.h> #include <acpi/actypes.h> #include "shpchp.h" -#include "shpchprm.h" - -#define PCI_MAX_BUS 0x100 -#define ACPI_STA_DEVICE_PRESENT 0x01 #define METHOD_NAME__SUN "_SUN" #define METHOD_NAME__HPP "_HPP" #define METHOD_NAME_OSHP "OSHP" -#define PHP_RES_BUS 0xA0 -#define PHP_RES_IO 0xA1 -#define PHP_RES_MEM 0xA2 -#define PHP_RES_PMEM 0xA3 - -#define BRIDGE_TYPE_P2P 0x00 -#define BRIDGE_TYPE_HOST 0x01 - -/* this should go to drivers/acpi/include/ */ -struct acpi__hpp { - u8 cache_line_size; - u8 latency_timer; - u8 enable_serr; - u8 enable_perr; -}; - -struct acpi_php_slot { - struct acpi_php_slot *next; - struct acpi_bridge *bridge; - acpi_handle handle; - int seg; - int bus; - int dev; - int fun; - u32 sun; - struct pci_resource *mem_head; - struct pci_resource *p_mem_head; - struct pci_resource *io_head; - struct pci_resource *bus_head; - void *slot_ops; /* _STA, _EJx, etc */ - struct slot *slot; -}; /* per func */ - -struct acpi_bridge { - struct acpi_bridge *parent; - struct acpi_bridge *next; - struct acpi_bridge *child; - acpi_handle handle; - int seg; - int pbus; /* pdev->bus->number */ - int pdevice; /* PCI_SLOT(pdev->devfn) */ - int pfunction; /* PCI_DEVFN(pdev->devfn) */ - int bus; /* pdev->subordinate->number */ - struct acpi__hpp *_hpp; - struct acpi_php_slot *slots; - struct pci_resource *tmem_head; /* total from crs */ - struct pci_resource *tp_mem_head; /* total from crs */ - struct pci_resource *tio_head; /* total from crs */ - struct pci_resource *tbus_head; /* total from crs */ - struct pci_resource *mem_head; /* available */ - struct pci_resource *p_mem_head; /* available */ - struct pci_resource *io_head; /* available */ - struct pci_resource *bus_head; /* available */ - int scanned; - int type; -}; - -static struct acpi_bridge *acpi_bridges_head; - static u8 * acpi_path_name( acpi_handle handle) { acpi_status status; @@ -124,82 +52,43 @@ static u8 * acpi_path_name( acpi_handle handle) return path_name; } -static void acpi_get__hpp ( struct acpi_bridge *ab); -static void acpi_run_oshp ( struct acpi_bridge *ab); - -static int acpi_add_slot_to_php_slots( - struct acpi_bridge *ab, - int bus_num, - acpi_handle handle, - u32 adr, - u32 sun - ) -{ - struct acpi_php_slot *aps; - static long samesun = -1; - - aps = (struct acpi_php_slot *) kmalloc (sizeof(struct acpi_php_slot), GFP_KERNEL); - if (!aps) { - err ("acpi_shpchprm: alloc for aps fail\n"); - return -1; - } - memset(aps, 0, sizeof(struct acpi_php_slot)); - - aps->handle = handle; - aps->bus = bus_num; - aps->dev = (adr >> 16) & 0xffff; - aps->fun = adr & 0xffff; - aps->sun = sun; - - aps->next = ab->slots; /* cling to the bridge */ - aps->bridge = ab; - ab->slots = aps; - - ab->scanned += 1; - if (!ab->_hpp) - acpi_get__hpp(ab); - - acpi_run_oshp(ab); - - if (sun != samesun) { - info("acpi_shpchprm: Slot sun(%x) at s:b:d:f=0x%02x:%02x:%02x:%02x\n", aps->sun, ab->seg, - aps->bus, aps->dev, aps->fun); - samesun = sun; - } - return 0; -} - -static void acpi_get__hpp ( struct acpi_bridge *ab) +static acpi_status +acpi_run_hpp(acpi_handle handle, struct hotplug_params *hpp) { acpi_status status; u8 nui[4]; struct acpi_buffer ret_buf = { 0, NULL}; union acpi_object *ext_obj, *package; - u8 *path_name = acpi_path_name(ab->handle); + u8 *path_name = acpi_path_name(handle); int i, len = 0; /* get _hpp */ - status = acpi_evaluate_object(ab->handle, METHOD_NAME__HPP, NULL, &ret_buf); + status = acpi_evaluate_object(handle, METHOD_NAME__HPP, NULL, &ret_buf); switch (status) { case AE_BUFFER_OVERFLOW: ret_buf.pointer = kmalloc (ret_buf.length, GFP_KERNEL); if (!ret_buf.pointer) { - err ("acpi_shpchprm:%s alloc for _HPP fail\n", path_name); - return; + err ("%s:%s alloc for _HPP fail\n", __FUNCTION__, + path_name); + return AE_NO_MEMORY; } - status = acpi_evaluate_object(ab->handle, METHOD_NAME__HPP, NULL, &ret_buf); + status = acpi_evaluate_object(handle, METHOD_NAME__HPP, + NULL, &ret_buf); if (ACPI_SUCCESS(status)) break; default: if (ACPI_FAILURE(status)) { - err("acpi_shpchprm:%s _HPP fail=0x%x\n", path_name, status); - return; + dbg("%s:%s _HPP fail=0x%x\n", __FUNCTION__, + path_name, status); + return status; } } ext_obj = (union acpi_object *) ret_buf.pointer; if (ext_obj->type != ACPI_TYPE_PACKAGE) { - err ("acpi_shpchprm:%s _HPP obj not a package\n", path_name); + err ("%s:%s _HPP obj not a package\n", __FUNCTION__, + path_name); + status = AE_ERROR; goto free_and_return; } @@ -212,1353 +101,41 @@ static void acpi_get__hpp ( struct acpi_bridge *ab) nui[i] = (u8)ext_obj->integer.value; break; default: - err ("acpi_shpchprm:%s _HPP obj type incorrect\n", path_name); + err ("%s:%s _HPP obj type incorrect\n", __FUNCTION__, + path_name); + status = AE_ERROR; goto free_and_return; } } - ab->_hpp = kmalloc (sizeof (struct acpi__hpp), GFP_KERNEL); - if (!ab->_hpp) { - err ("acpi_shpchprm:%s alloc for _HPP failed\n", path_name); - goto free_and_return; - } - memset(ab->_hpp, 0, sizeof(struct acpi__hpp)); + hpp->cache_line_size = nui[0]; + hpp->latency_timer = nui[1]; + hpp->enable_serr = nui[2]; + hpp->enable_perr = nui[3]; - ab->_hpp->cache_line_size = nui[0]; - ab->_hpp->latency_timer = nui[1]; - ab->_hpp->enable_serr = nui[2]; - ab->_hpp->enable_perr = nui[3]; - - dbg(" _HPP: cache_line_size=0x%x\n", ab->_hpp->cache_line_size); - dbg(" _HPP: latency timer =0x%x\n", ab->_hpp->latency_timer); - dbg(" _HPP: enable SERR =0x%x\n", ab->_hpp->enable_serr); - dbg(" _HPP: enable PERR =0x%x\n", ab->_hpp->enable_perr); + dbg(" _HPP: cache_line_size=0x%x\n", hpp->cache_line_size); + dbg(" _HPP: latency timer =0x%x\n", hpp->latency_timer); + dbg(" _HPP: enable SERR =0x%x\n", hpp->enable_serr); + dbg(" _HPP: enable PERR =0x%x\n", hpp->enable_perr); free_and_return: kfree(ret_buf.pointer); -} - -static void acpi_run_oshp ( struct acpi_bridge *ab) -{ - acpi_status status; - u8 *path_name = acpi_path_name(ab->handle); - - /* run OSHP */ - status = acpi_evaluate_object(ab->handle, METHOD_NAME_OSHP, NULL, NULL); - if (ACPI_FAILURE(status)) { - err("acpi_pciehprm:%s OSHP fails=0x%x\n", path_name, status); - } else - dbg("acpi_pciehprm:%s OSHP passes =0x%x\n", path_name, status); - return; -} - -static acpi_status acpi_evaluate_crs( - acpi_handle handle, - struct acpi_resource **retbuf - ) -{ - acpi_status status; - struct acpi_buffer crsbuf; - u8 *path_name = acpi_path_name(handle); - - crsbuf.length = 0; - crsbuf.pointer = NULL; - - status = acpi_get_current_resources (handle, &crsbuf); - - switch (status) { - case AE_BUFFER_OVERFLOW: - break; /* found */ - case AE_NOT_FOUND: - dbg("acpi_shpchprm:%s _CRS not found\n", path_name); - return status; - default: - err ("acpi_shpchprm:%s _CRS fail=0x%x\n", path_name, status); - return status; - } - - crsbuf.pointer = kmalloc (crsbuf.length, GFP_KERNEL); - if (!crsbuf.pointer) { - err ("acpi_shpchprm: alloc %ld bytes for %s _CRS fail\n", (ulong)crsbuf.length, path_name); - return AE_NO_MEMORY; - } - - status = acpi_get_current_resources (handle, &crsbuf); - if (ACPI_FAILURE(status)) { - err("acpi_shpchprm: %s _CRS fail=0x%x.\n", path_name, status); - kfree(crsbuf.pointer); - return status; - } - - *retbuf = crsbuf.pointer; - - return status; -} - -static void free_pci_resource ( struct pci_resource *aprh) -{ - struct pci_resource *res, *next; - - for (res = aprh; res; res = next) { - next = res->next; - kfree(res); - } -} - -static void print_pci_resource ( struct pci_resource *aprh) -{ - struct pci_resource *res; - - for (res = aprh; res; res = res->next) - dbg(" base= 0x%x length= 0x%x\n", res->base, res->length); -} - -static void print_slot_resources( struct acpi_php_slot *aps) -{ - if (aps->bus_head) { - dbg(" BUS Resources:\n"); - print_pci_resource (aps->bus_head); - } - - if (aps->io_head) { - dbg(" IO Resources:\n"); - print_pci_resource (aps->io_head); - } - - if (aps->mem_head) { - dbg(" MEM Resources:\n"); - print_pci_resource (aps->mem_head); - } - - if (aps->p_mem_head) { - dbg(" PMEM Resources:\n"); - print_pci_resource (aps->p_mem_head); - } -} - -static void print_pci_resources( struct acpi_bridge *ab) -{ - if (ab->tbus_head) { - dbg(" Total BUS Resources:\n"); - print_pci_resource (ab->tbus_head); - } - if (ab->bus_head) { - dbg(" BUS Resources:\n"); - print_pci_resource (ab->bus_head); - } - - if (ab->tio_head) { - dbg(" Total IO Resources:\n"); - print_pci_resource (ab->tio_head); - } - if (ab->io_head) { - dbg(" IO Resources:\n"); - print_pci_resource (ab->io_head); - } - - if (ab->tmem_head) { - dbg(" Total MEM Resources:\n"); - print_pci_resource (ab->tmem_head); - } - if (ab->mem_head) { - dbg(" MEM Resources:\n"); - print_pci_resource (ab->mem_head); - } - - if (ab->tp_mem_head) { - dbg(" Total PMEM Resources:\n"); - print_pci_resource (ab->tp_mem_head); - } - if (ab->p_mem_head) { - dbg(" PMEM Resources:\n"); - print_pci_resource (ab->p_mem_head); - } - if (ab->_hpp) { - dbg(" _HPP: cache_line_size=0x%x\n", ab->_hpp->cache_line_size); - dbg(" _HPP: latency timer =0x%x\n", ab->_hpp->latency_timer); - dbg(" _HPP: enable SERR =0x%x\n", ab->_hpp->enable_serr); - dbg(" _HPP: enable PERR =0x%x\n", ab->_hpp->enable_perr); - } -} - -static int shpchprm_delete_resource( - struct pci_resource **aprh, - ulong base, - ulong size) -{ - struct pci_resource *res; - struct pci_resource *prevnode; - struct pci_resource *split_node; - ulong tbase; - - shpchp_resource_sort_and_combine(aprh); - - for (res = *aprh; res; res = res->next) { - if (res->base > base) - continue; - - if ((res->base + res->length) < (base + size)) - continue; - - if (res->base < base) { - tbase = base; - - if ((res->length - (tbase - res->base)) < size) - continue; - - split_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - if (!split_node) - return -ENOMEM; - - split_node->base = res->base; - split_node->length = tbase - res->base; - res->base = tbase; - res->length -= split_node->length; - - split_node->next = res->next; - res->next = split_node; - } - - if (res->length >= size) { - split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - if (!split_node) - return -ENOMEM; - - split_node->base = res->base + size; - split_node->length = res->length - size; - res->length = size; - - split_node->next = res->next; - res->next = split_node; - } - - if (*aprh == res) { - *aprh = res->next; - } else { - prevnode = *aprh; - while (prevnode->next != res) - prevnode = prevnode->next; - - prevnode->next = res->next; - } - res->next = NULL; - kfree(res); - break; - } - - return 0; -} - -static int shpchprm_delete_resources( - struct pci_resource **aprh, - struct pci_resource *this - ) -{ - struct pci_resource *res; - - for (res = this; res; res = res->next) - shpchprm_delete_resource(aprh, res->base, res->length); - - return 0; -} - -static int shpchprm_add_resource( - struct pci_resource **aprh, - ulong base, - ulong size) -{ - struct pci_resource *res; - - for (res = *aprh; res; res = res->next) { - if ((res->base + res->length) == base) { - res->length += size; - size = 0L; - break; - } - if (res->next == *aprh) - break; - } - - if (size) { - res = kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - if (!res) { - err ("acpi_shpchprm: alloc for res fail\n"); - return -ENOMEM; - } - memset(res, 0, sizeof (struct pci_resource)); - - res->base = base; - res->length = size; - res->next = *aprh; - *aprh = res; - } - - return 0; -} - -static int shpchprm_add_resources( - struct pci_resource **aprh, - struct pci_resource *this - ) -{ - struct pci_resource *res; - int rc = 0; - - for (res = this; res && !rc; res = res->next) - rc = shpchprm_add_resource(aprh, res->base, res->length); - - return rc; -} - -static void acpi_parse_io ( - struct acpi_bridge *ab, - union acpi_resource_data *data - ) -{ - struct acpi_resource_io *dataio; - dataio = (struct acpi_resource_io *) data; - - dbg("Io Resource\n"); - dbg(" %d bit decode\n", ACPI_DECODE_16 == dataio->io_decode ? 16:10); - dbg(" Range minimum base: %08X\n", dataio->min_base_address); - dbg(" Range maximum base: %08X\n", dataio->max_base_address); - dbg(" Alignment: %08X\n", dataio->alignment); - dbg(" Range Length: %08X\n", dataio->range_length); -} - -static void acpi_parse_fixed_io ( - struct acpi_bridge *ab, - union acpi_resource_data *data - ) -{ - struct acpi_resource_fixed_io *datafio; - datafio = (struct acpi_resource_fixed_io *) data; - - dbg("Fixed Io Resource\n"); - dbg(" Range base address: %08X", datafio->base_address); - dbg(" Range length: %08X", datafio->range_length); -} - -static void acpi_parse_address16_32 ( - struct acpi_bridge *ab, - union acpi_resource_data *data, - acpi_resource_type id - ) -{ - /* - * acpi_resource_address16 == acpi_resource_address32 - * acpi_resource_address16 *data16 = (acpi_resource_address16 *) data; - */ - struct acpi_resource_address32 *data32 = (struct acpi_resource_address32 *) data; - struct pci_resource **aprh, **tprh; - - if (id == ACPI_RSTYPE_ADDRESS16) - dbg("acpi_shpchprm:16-Bit Address Space Resource\n"); - else - dbg("acpi_shpchprm:32-Bit Address Space Resource\n"); - - switch (data32->resource_type) { - case ACPI_MEMORY_RANGE: - dbg(" Resource Type: Memory Range\n"); - aprh = &ab->mem_head; - tprh = &ab->tmem_head; - - switch (data32->attribute.memory.cache_attribute) { - case ACPI_NON_CACHEABLE_MEMORY: - dbg(" Type Specific: Noncacheable memory\n"); - break; - case ACPI_CACHABLE_MEMORY: - dbg(" Type Specific: Cacheable memory\n"); - break; - case ACPI_WRITE_COMBINING_MEMORY: - dbg(" Type Specific: Write-combining memory\n"); - break; - case ACPI_PREFETCHABLE_MEMORY: - aprh = &ab->p_mem_head; - dbg(" Type Specific: Prefetchable memory\n"); - break; - default: - dbg(" Type Specific: Invalid cache attribute\n"); - break; - } - - dbg(" Type Specific: Read%s\n", ACPI_READ_WRITE_MEMORY == data32->attribute.memory.read_write_attribute ? "/Write":" Only"); - break; - - case ACPI_IO_RANGE: - dbg(" Resource Type: I/O Range\n"); - aprh = &ab->io_head; - tprh = &ab->tio_head; - - switch (data32->attribute.io.range_attribute) { - case ACPI_NON_ISA_ONLY_RANGES: - dbg(" Type Specific: Non-ISA Io Addresses\n"); - break; - case ACPI_ISA_ONLY_RANGES: - dbg(" Type Specific: ISA Io Addresses\n"); - break; - case ACPI_ENTIRE_RANGE: - dbg(" Type Specific: ISA and non-ISA Io Addresses\n"); - break; - default: - dbg(" Type Specific: Invalid range attribute\n"); - break; - } - break; - - case ACPI_BUS_NUMBER_RANGE: - dbg(" Resource Type: Bus Number Range(fixed)\n"); - /* fixup to be compatible with the rest of php driver */ - data32->min_address_range++; - data32->address_length--; - aprh = &ab->bus_head; - tprh = &ab->tbus_head; - break; - default: - dbg(" Resource Type: Invalid resource type. Exiting.\n"); - return; - } - - dbg(" Resource %s\n", ACPI_CONSUMER == data32->producer_consumer ? "Consumer":"Producer"); - dbg(" %s decode\n", ACPI_SUB_DECODE == data32->decode ? "Subtractive":"Positive"); - dbg(" Min address is %s fixed\n", ACPI_ADDRESS_FIXED == data32->min_address_fixed ? "":"not"); - dbg(" Max address is %s fixed\n", ACPI_ADDRESS_FIXED == data32->max_address_fixed ? "":"not"); - dbg(" Granularity: %08X\n", data32->granularity); - dbg(" Address range min: %08X\n", data32->min_address_range); - dbg(" Address range max: %08X\n", data32->max_address_range); - dbg(" Address translation offset: %08X\n", data32->address_translation_offset); - dbg(" Address Length: %08X\n", data32->address_length); - - if (0xFF != data32->resource_source.index) { - dbg(" Resource Source Index: %X\n", data32->resource_source.index); - /* dbg(" Resource Source: %s\n", data32->resource_source.string_ptr); */ - } - - shpchprm_add_resource(aprh, data32->min_address_range, data32->address_length); -} - -static acpi_status acpi_parse_crs( - struct acpi_bridge *ab, - struct acpi_resource *crsbuf - ) -{ - acpi_status status = AE_OK; - struct acpi_resource *resource = crsbuf; - u8 count = 0; - u8 done = 0; - - while (!done) { - dbg("acpi_shpchprm: PCI bus 0x%x Resource structure %x.\n", ab->bus, count++); - switch (resource->id) { - case ACPI_RSTYPE_IRQ: - dbg("Irq -------- Resource\n"); - break; - case ACPI_RSTYPE_DMA: - dbg("DMA -------- Resource\n"); - break; - case ACPI_RSTYPE_START_DPF: - dbg("Start DPF -------- Resource\n"); - break; - case ACPI_RSTYPE_END_DPF: - dbg("End DPF -------- Resource\n"); - break; - case ACPI_RSTYPE_IO: - acpi_parse_io (ab, &resource->data); - break; - case ACPI_RSTYPE_FIXED_IO: - acpi_parse_fixed_io (ab, &resource->data); - break; - case ACPI_RSTYPE_VENDOR: - dbg("Vendor -------- Resource\n"); - break; - case ACPI_RSTYPE_END_TAG: - dbg("End_tag -------- Resource\n"); - done = 1; - break; - case ACPI_RSTYPE_MEM24: - dbg("Mem24 -------- Resource\n"); - break; - case ACPI_RSTYPE_MEM32: - dbg("Mem32 -------- Resource\n"); - break; - case ACPI_RSTYPE_FIXED_MEM32: - dbg("Fixed Mem32 -------- Resource\n"); - break; - case ACPI_RSTYPE_ADDRESS16: - acpi_parse_address16_32(ab, &resource->data, ACPI_RSTYPE_ADDRESS16); - break; - case ACPI_RSTYPE_ADDRESS32: - acpi_parse_address16_32(ab, &resource->data, ACPI_RSTYPE_ADDRESS32); - break; - case ACPI_RSTYPE_ADDRESS64: - info("Address64 -------- Resource unparsed\n"); - break; - case ACPI_RSTYPE_EXT_IRQ: - dbg("Ext Irq -------- Resource\n"); - break; - default: - dbg("Invalid -------- resource type 0x%x\n", resource->id); - break; - } - - resource = (struct acpi_resource *) ((char *)resource + resource->length); - } - return status; } -static acpi_status acpi_get_crs( struct acpi_bridge *ab) +static void acpi_run_oshp(acpi_handle handle) { acpi_status status; - struct acpi_resource *crsbuf; - - status = acpi_evaluate_crs(ab->handle, &crsbuf); - if (ACPI_SUCCESS(status)) { - status = acpi_parse_crs(ab, crsbuf); - kfree(crsbuf); - - shpchp_resource_sort_and_combine(&ab->bus_head); - shpchp_resource_sort_and_combine(&ab->io_head); - shpchp_resource_sort_and_combine(&ab->mem_head); - shpchp_resource_sort_and_combine(&ab->p_mem_head); - - shpchprm_add_resources (&ab->tbus_head, ab->bus_head); - shpchprm_add_resources (&ab->tio_head, ab->io_head); - shpchprm_add_resources (&ab->tmem_head, ab->mem_head); - shpchprm_add_resources (&ab->tp_mem_head, ab->p_mem_head); - } - - return status; -} - -/* find acpi_bridge downword from ab. */ -static struct acpi_bridge * -find_acpi_bridge_by_bus( - struct acpi_bridge *ab, - int seg, - int bus /* pdev->subordinate->number */ - ) -{ - struct acpi_bridge *lab = NULL; - - if (!ab) - return NULL; - - if ((ab->bus == bus) && (ab->seg == seg)) - return ab; - - if (ab->child) - lab = find_acpi_bridge_by_bus(ab->child, seg, bus); - - if (!lab) - if (ab->next) - lab = find_acpi_bridge_by_bus(ab->next, seg, bus); - - return lab; -} - -/* - * Build a device tree of ACPI PCI Bridges - */ -static void shpchprm_acpi_register_a_bridge ( - struct acpi_bridge **head, - struct acpi_bridge *pab, /* parent bridge to which child bridge is added */ - struct acpi_bridge *cab /* child bridge to add */ - ) -{ - struct acpi_bridge *lpab; - struct acpi_bridge *lcab; - - lpab = find_acpi_bridge_by_bus(*head, pab->seg, pab->bus); - if (!lpab) { - if (!(pab->type & BRIDGE_TYPE_HOST)) - warn("PCI parent bridge s:b(%x:%x) not in list.\n", pab->seg, pab->bus); - pab->next = *head; - *head = pab; - lpab = pab; - } - - if ((cab->type & BRIDGE_TYPE_HOST) && (pab == cab)) - return; - - lcab = find_acpi_bridge_by_bus(*head, cab->seg, cab->bus); - if (lcab) { - if ((pab->bus != lcab->parent->bus) || (lcab->bus != cab->bus)) - err("PCI child bridge s:b(%x:%x) in list with diff parent.\n", cab->seg, cab->bus); - return; - } else - lcab = cab; - - lcab->parent = lpab; - lcab->next = lpab->child; - lpab->child = lcab; -} - -static acpi_status shpchprm_acpi_build_php_slots_callback( - acpi_handle handle, - u32 Level, - void *context, - void **retval - ) -{ - ulong bus_num; - ulong seg_num; - ulong sun, adr; - ulong padr = 0; - acpi_handle phandle = NULL; - struct acpi_bridge *pab = (struct acpi_bridge *)context; - struct acpi_bridge *lab; - acpi_status status; u8 *path_name = acpi_path_name(handle); - /* get _SUN */ - status = acpi_evaluate_integer(handle, METHOD_NAME__SUN, NULL, &sun); - switch(status) { - case AE_NOT_FOUND: - return AE_OK; - default: - if (ACPI_FAILURE(status)) { - err("acpi_shpchprm:%s _SUN fail=0x%x\n", path_name, status); - return status; - } - } - - /* get _ADR. _ADR must exist if _SUN exists */ - status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr); - if (ACPI_FAILURE(status)) { - err("acpi_shpchprm:%s _ADR fail=0x%x\n", path_name, status); - return status; - } - - dbg("acpi_shpchprm:%s sun=0x%08x adr=0x%08x\n", path_name, (u32)sun, (u32)adr); - - status = acpi_get_parent(handle, &phandle); + /* run OSHP */ + status = acpi_evaluate_object(handle, METHOD_NAME_OSHP, NULL, NULL); if (ACPI_FAILURE(status)) { - err("acpi_shpchprm:%s get_parent fail=0x%x\n", path_name, status); - return (status); - } - - bus_num = pab->bus; - seg_num = pab->seg; - - if (pab->bus == bus_num) { - lab = pab; + err("%s:%s OSHP fails=0x%x\n", __FUNCTION__, path_name, + status); } else { - dbg("WARN: pab is not parent\n"); - lab = find_acpi_bridge_by_bus(pab, seg_num, bus_num); - if (!lab) { - dbg("acpi_shpchprm: alloc new P2P bridge(%x) for sun(%08x)\n", (u32)bus_num, (u32)sun); - lab = (struct acpi_bridge *)kmalloc(sizeof(struct acpi_bridge), GFP_KERNEL); - if (!lab) { - err("acpi_shpchprm: alloc for ab fail\n"); - return AE_NO_MEMORY; - } - memset(lab, 0, sizeof(struct acpi_bridge)); - - lab->handle = phandle; - lab->pbus = pab->bus; - lab->pdevice = (int)(padr >> 16) & 0xffff; - lab->pfunction = (int)(padr & 0xffff); - lab->bus = (int)bus_num; - lab->scanned = 0; - lab->type = BRIDGE_TYPE_P2P; - - shpchprm_acpi_register_a_bridge (&acpi_bridges_head, pab, lab); - } else - dbg("acpi_shpchprm: found P2P bridge(%x) for sun(%08x)\n", (u32)bus_num, (u32)sun); + dbg("%s:%s OSHP passes\n", __FUNCTION__, path_name); } - - acpi_add_slot_to_php_slots(lab, (int)bus_num, handle, (u32)adr, (u32)sun); - return (status); -} - -static int shpchprm_acpi_build_php_slots( - struct acpi_bridge *ab, - u32 depth - ) -{ - acpi_status status; - u8 *path_name = acpi_path_name(ab->handle); - - /* Walk down this pci bridge to get _SUNs if any behind P2P */ - status = acpi_walk_namespace ( ACPI_TYPE_DEVICE, - ab->handle, - depth, - shpchprm_acpi_build_php_slots_callback, - ab, - NULL ); - if (ACPI_FAILURE(status)) { - dbg("acpi_shpchprm:%s walk for _SUN on pci bridge seg:bus(%x:%x) fail=0x%x\n", path_name, ab->seg, ab->bus, status); - return -1; - } - - return 0; -} - -static void build_a_bridge( - struct acpi_bridge *pab, - struct acpi_bridge *ab - ) -{ - u8 *path_name = acpi_path_name(ab->handle); - - shpchprm_acpi_register_a_bridge (&acpi_bridges_head, pab, ab); - - switch (ab->type) { - case BRIDGE_TYPE_HOST: - dbg("acpi_shpchprm: Registered PCI HOST Bridge(%02x) on s:b:d:f(%02x:%02x:%02x:%02x) [%s]\n", - ab->bus, ab->seg, ab->pbus, ab->pdevice, ab->pfunction, path_name); - break; - case BRIDGE_TYPE_P2P: - dbg("acpi_shpchprm: Registered PCI P2P Bridge(%02x-%02x) on s:b:d:f(%02x:%02x:%02x:%02x) [%s]\n", - ab->pbus, ab->bus, ab->seg, ab->pbus, ab->pdevice, ab->pfunction, path_name); - break; - }; - - /* build any immediate PHP slots under this pci bridge */ - shpchprm_acpi_build_php_slots(ab, 1); -} - -static struct acpi_bridge * add_p2p_bridge( - acpi_handle handle, - struct acpi_bridge *pab, /* parent */ - ulong adr - ) -{ - struct acpi_bridge *ab; - struct pci_dev *pdev; - ulong devnum, funcnum; - u8 *path_name = acpi_path_name(handle); - - ab = (struct acpi_bridge *) kmalloc (sizeof(struct acpi_bridge), GFP_KERNEL); - if (!ab) { - err("acpi_shpchprm: alloc for ab fail\n"); - return NULL; - } - memset(ab, 0, sizeof(struct acpi_bridge)); - - devnum = (adr >> 16) & 0xffff; - funcnum = adr & 0xffff; - - pdev = pci_find_slot(pab->bus, PCI_DEVFN(devnum, funcnum)); - if (!pdev || !pdev->subordinate) { - err("acpi_shpchprm:%s is not a P2P Bridge\n", path_name); - kfree(ab); - return NULL; - } - - ab->handle = handle; - ab->seg = pab->seg; - ab->pbus = pab->bus; /* or pdev->bus->number */ - ab->pdevice = devnum; /* or PCI_SLOT(pdev->devfn) */ - ab->pfunction = funcnum; /* or PCI_FUNC(pdev->devfn) */ - ab->bus = pdev->subordinate->number; - ab->scanned = 0; - ab->type = BRIDGE_TYPE_P2P; - - dbg("acpi_shpchprm: P2P(%x-%x) on pci=b:d:f(%x:%x:%x) acpi=b:d:f(%x:%x:%x) [%s]\n", - pab->bus, ab->bus, pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), - pab->bus, (u32)devnum, (u32)funcnum, path_name); - - build_a_bridge(pab, ab); - - return ab; -} - -static acpi_status scan_p2p_bridge( - acpi_handle handle, - u32 Level, - void *context, - void **retval - ) -{ - struct acpi_bridge *pab = (struct acpi_bridge *)context; - struct acpi_bridge *ab; - acpi_status status; - ulong adr = 0; - u8 *path_name = acpi_path_name(handle); - ulong devnum, funcnum; - struct pci_dev *pdev; - - /* get device, function */ - status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr); - if (ACPI_FAILURE(status)) { - if (status != AE_NOT_FOUND) - err("acpi_shpchprm:%s _ADR fail=0x%x\n", path_name, status); - return AE_OK; - } - - devnum = (adr >> 16) & 0xffff; - funcnum = adr & 0xffff; - - pdev = pci_find_slot(pab->bus, PCI_DEVFN(devnum, funcnum)); - if (!pdev) - return AE_OK; - if (!pdev->subordinate) - return AE_OK; - - ab = add_p2p_bridge(handle, pab, adr); - if (ab) { - status = acpi_walk_namespace ( ACPI_TYPE_DEVICE, - handle, - (u32)1, - scan_p2p_bridge, - ab, - NULL); - if (ACPI_FAILURE(status)) - dbg("acpi_shpchprm:%s find_p2p fail=0x%x\n", path_name, status); - } - - return AE_OK; -} - -static struct acpi_bridge * add_host_bridge( - acpi_handle handle, - ulong segnum, - ulong busnum - ) -{ - ulong adr = 0; - acpi_status status; - struct acpi_bridge *ab; - u8 *path_name = acpi_path_name(handle); - - /* get device, function: host br adr is always 0000 though. */ - status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr); - if (ACPI_FAILURE(status)) { - err("acpi_shpchprm:%s _ADR fail=0x%x\n", path_name, status); - return NULL; - } - dbg("acpi_shpchprm: ROOT PCI seg(0x%x)bus(0x%x)dev(0x%x)func(0x%x) [%s]\n", (u32)segnum, (u32)busnum, - (u32)(adr >> 16) & 0xffff, (u32)adr & 0xffff, path_name); - - ab = (struct acpi_bridge *) kmalloc (sizeof(struct acpi_bridge), GFP_KERNEL); - if (!ab) { - err("acpi_shpchprm: alloc for ab fail\n"); - return NULL; - } - memset(ab, 0, sizeof(struct acpi_bridge)); - - ab->handle = handle; - ab->seg = (int)segnum; - ab->bus = ab->pbus = (int)busnum; - ab->pdevice = (int)(adr >> 16) & 0xffff; - ab->pfunction = (int)(adr & 0xffff); - ab->scanned = 0; - ab->type = BRIDGE_TYPE_HOST; - - /* get root pci bridge's current resources */ - status = acpi_get_crs(ab); - if (ACPI_FAILURE(status)) { - err("acpi_shpchprm:%s evaluate _CRS fail=0x%x\n", path_name, status); - kfree(ab); - return NULL; - } - build_a_bridge(ab, ab); - - return ab; -} - -static acpi_status acpi_scan_from_root_pci_callback ( - acpi_handle handle, - u32 Level, - void *context, - void **retval - ) -{ - ulong segnum = 0; - ulong busnum = 0; - acpi_status status; - struct acpi_bridge *ab; - u8 *path_name = acpi_path_name(handle); - - /* get bus number of this pci root bridge */ - status = acpi_evaluate_integer(handle, METHOD_NAME__SEG, NULL, &segnum); - if (ACPI_FAILURE(status)) { - if (status != AE_NOT_FOUND) { - err("acpi_shpchprm:%s evaluate _SEG fail=0x%x\n", path_name, status); - return status; - } - segnum = 0; - } - - /* get bus number of this pci root bridge */ - status = acpi_evaluate_integer(handle, METHOD_NAME__BBN, NULL, &busnum); - if (ACPI_FAILURE(status)) { - err("acpi_shpchprm:%s evaluate _BBN fail=0x%x\n", path_name, status); - return (status); - } - - ab = add_host_bridge(handle, segnum, busnum); - if (ab) { - status = acpi_walk_namespace ( ACPI_TYPE_DEVICE, - handle, - 1, - scan_p2p_bridge, - ab, - NULL); - if (ACPI_FAILURE(status)) - dbg("acpi_shpchprm:%s find_p2p fail=0x%x\n", path_name, status); - } - - return AE_OK; -} - -static int shpchprm_acpi_scan_pci (void) -{ - acpi_status status; - - /* - * TBD: traverse LDM device tree with the help of - * unified ACPI augmented for php device population. - */ - status = acpi_get_devices ( PCI_ROOT_HID_STRING, - acpi_scan_from_root_pci_callback, - NULL, - NULL ); - if (ACPI_FAILURE(status)) { - err("acpi_shpchprm:get_device PCI ROOT HID fail=0x%x\n", status); - return -1; - } - - return 0; -} - -int shpchprm_init(enum php_ctlr_type ctlr_type) -{ - int rc; - - if (ctlr_type != PCI) - return -ENODEV; - - dbg("shpchprm ACPI init <enter>\n"); - acpi_bridges_head = NULL; - - /* construct PCI bus:device tree of acpi_handles */ - rc = shpchprm_acpi_scan_pci(); - if (rc) - return rc; - - dbg("shpchprm ACPI init %s\n", (rc)?"fail":"success"); - return rc; -} - -static void free_a_slot(struct acpi_php_slot *aps) -{ - dbg(" free a php func of slot(0x%02x) on PCI b:d:f=0x%02x:%02x:%02x\n", aps->sun, aps->bus, aps->dev, aps->fun); - - free_pci_resource (aps->io_head); - free_pci_resource (aps->bus_head); - free_pci_resource (aps->mem_head); - free_pci_resource (aps->p_mem_head); - - kfree(aps); -} - -static void free_a_bridge( struct acpi_bridge *ab) -{ - struct acpi_php_slot *aps, *next; - - switch (ab->type) { - case BRIDGE_TYPE_HOST: - dbg("Free ACPI PCI HOST Bridge(%x) [%s] on s:b:d:f(%x:%x:%x:%x)\n", - ab->bus, acpi_path_name(ab->handle), ab->seg, ab->pbus, ab->pdevice, ab->pfunction); - break; - case BRIDGE_TYPE_P2P: - dbg("Free ACPI PCI P2P Bridge(%x-%x) [%s] on s:b:d:f(%x:%x:%x:%x)\n", - ab->pbus, ab->bus, acpi_path_name(ab->handle), ab->seg, ab->pbus, ab->pdevice, ab->pfunction); - break; - }; - - /* free slots first */ - for (aps = ab->slots; aps; aps = next) { - next = aps->next; - free_a_slot(aps); - } - - free_pci_resource (ab->io_head); - free_pci_resource (ab->tio_head); - free_pci_resource (ab->bus_head); - free_pci_resource (ab->tbus_head); - free_pci_resource (ab->mem_head); - free_pci_resource (ab->tmem_head); - free_pci_resource (ab->p_mem_head); - free_pci_resource (ab->tp_mem_head); - - kfree(ab); -} - -static void shpchprm_free_bridges ( struct acpi_bridge *ab) -{ - if (!ab) - return; - - if (ab->child) - shpchprm_free_bridges (ab->child); - - if (ab->next) - shpchprm_free_bridges (ab->next); - - free_a_bridge(ab); -} - -void shpchprm_cleanup(void) -{ - shpchprm_free_bridges (acpi_bridges_head); -} - -static int get_number_of_slots ( - struct acpi_bridge *ab, - int selfonly - ) -{ - struct acpi_php_slot *aps; - int prev_slot = -1; - int slot_num = 0; - - for ( aps = ab->slots; aps; aps = aps->next) - if (aps->dev != prev_slot) { - prev_slot = aps->dev; - slot_num++; - } - - if (ab->child) - slot_num += get_number_of_slots (ab->child, 0); - - if (selfonly) - return slot_num; - - if (ab->next) - slot_num += get_number_of_slots (ab->next, 0); - - return slot_num; -} - -static int print_acpi_resources (struct acpi_bridge *ab) -{ - struct acpi_php_slot *aps; - int i; - - switch (ab->type) { - case BRIDGE_TYPE_HOST: - dbg("PCI HOST Bridge (%x) [%s]\n", ab->bus, acpi_path_name(ab->handle)); - break; - case BRIDGE_TYPE_P2P: - dbg("PCI P2P Bridge (%x-%x) [%s]\n", ab->pbus, ab->bus, acpi_path_name(ab->handle)); - break; - }; - - print_pci_resources (ab); - - for ( i = -1, aps = ab->slots; aps; aps = aps->next) { - if (aps->dev == i) - continue; - dbg(" Slot sun(%x) s:b:d:f(%02x:%02x:%02x:%02x)\n", aps->sun, aps->seg, aps->bus, aps->dev, aps->fun); - print_slot_resources(aps); - i = aps->dev; - } - - if (ab->child) - print_acpi_resources (ab->child); - - if (ab->next) - print_acpi_resources (ab->next); - - return 0; -} - -int shpchprm_print_pirt(void) -{ - dbg("SHPCHPRM ACPI Slots\n"); - if (acpi_bridges_head) - print_acpi_resources (acpi_bridges_head); - return 0; -} - -static struct acpi_php_slot * get_acpi_slot ( - struct acpi_bridge *ab, - u32 sun - ) -{ - struct acpi_php_slot *aps = NULL; - - for ( aps = ab->slots; aps; aps = aps->next) - if (aps->sun == sun) - return aps; - - if (!aps && ab->child) { - aps = (struct acpi_php_slot *)get_acpi_slot (ab->child, sun); - if (aps) - return aps; - } - - if (!aps && ab->next) { - aps = (struct acpi_php_slot *)get_acpi_slot (ab->next, sun); - if (aps) - return aps; - } - - return aps; - -} - -#if 0 -static void * shpchprm_get_slot(struct slot *slot) -{ - struct acpi_bridge *ab = acpi_bridges_head; - struct acpi_php_slot *aps = get_acpi_slot (ab, slot->number); - - aps->slot = slot; - - dbg("Got acpi slot sun(%x): s:b:d:f(%x:%x:%x:%x)\n", aps->sun, aps->seg, aps->bus, aps->dev, aps->fun); - - return (void *)aps; -} -#endif - -static void shpchprm_dump_func_res( struct pci_func *fun) -{ - struct pci_func *func = fun; - - if (func->bus_head) { - dbg(": BUS Resources:\n"); - print_pci_resource (func->bus_head); - } - if (func->io_head) { - dbg(": IO Resources:\n"); - print_pci_resource (func->io_head); - } - if (func->mem_head) { - dbg(": MEM Resources:\n"); - print_pci_resource (func->mem_head); - } - if (func->p_mem_head) { - dbg(": PMEM Resources:\n"); - print_pci_resource (func->p_mem_head); - } -} - -static void shpchprm_dump_ctrl_res( struct controller *ctlr) -{ - struct controller *ctrl = ctlr; - - if (ctrl->bus_head) { - dbg(": BUS Resources:\n"); - print_pci_resource (ctrl->bus_head); - } - if (ctrl->io_head) { - dbg(": IO Resources:\n"); - print_pci_resource (ctrl->io_head); - } - if (ctrl->mem_head) { - dbg(": MEM Resources:\n"); - print_pci_resource (ctrl->mem_head); - } - if (ctrl->p_mem_head) { - dbg(": PMEM Resources:\n"); - print_pci_resource (ctrl->p_mem_head); - } -} - -static int shpchprm_get_used_resources ( - struct controller *ctrl, - struct pci_func *func - ) -{ - return shpchp_save_used_resources (ctrl, func, !DISABLE_CARD); -} - -static int configure_existing_function( - struct controller *ctrl, - struct pci_func *func - ) -{ - int rc; - - /* see how much resources the func has used. */ - rc = shpchprm_get_used_resources (ctrl, func); - - if (!rc) { - /* subtract the resources used by the func from ctrl resources */ - rc = shpchprm_delete_resources (&ctrl->bus_head, func->bus_head); - rc |= shpchprm_delete_resources (&ctrl->io_head, func->io_head); - rc |= shpchprm_delete_resources (&ctrl->mem_head, func->mem_head); - rc |= shpchprm_delete_resources (&ctrl->p_mem_head, func->p_mem_head); - if (rc) - warn("aCEF: cannot del used resources\n"); - } else - err("aCEF: cannot get used resources\n"); - - return rc; -} - -static int bind_pci_resources_to_slots ( struct controller *ctrl) -{ - struct pci_func *func, new_func; - int busn = ctrl->slot_bus; - int devn, funn; - u32 vid; - - for (devn = 0; devn < 32; devn++) { - for (funn = 0; funn < 8; funn++) { - /* - if (devn == ctrl->device && funn == ctrl->function) - continue; - */ - /* find out if this entry is for an occupied slot */ - vid = 0xFFFFFFFF; - pci_bus_read_config_dword(ctrl->pci_dev->subordinate, PCI_DEVFN(devn, funn), PCI_VENDOR_ID, &vid); - - if (vid != 0xFFFFFFFF) { - func = shpchp_slot_find(busn, devn, funn); - if (!func) { - memset(&new_func, 0, sizeof(struct pci_func)); - new_func.bus = busn; - new_func.device = devn; - new_func.function = funn; - new_func.is_a_board = 1; - configure_existing_function(ctrl, &new_func); - shpchprm_dump_func_res(&new_func); - } else { - configure_existing_function(ctrl, func); - shpchprm_dump_func_res(func); - } - dbg("aCCF:existing PCI 0x%x Func ResourceDump\n", ctrl->bus); - } - } - } - - return 0; -} - -static int bind_pci_resources( - struct controller *ctrl, - struct acpi_bridge *ab - ) -{ - int status = 0; - - if (ab->bus_head) { - dbg("bapr: BUS Resources add on PCI 0x%x\n", ab->bus); - status = shpchprm_add_resources (&ctrl->bus_head, ab->bus_head); - if (shpchprm_delete_resources (&ab->bus_head, ctrl->bus_head)) - warn("bapr: cannot sub BUS Resource on PCI 0x%x\n", ab->bus); - if (status) { - err("bapr: BUS Resource add on PCI 0x%x: fail=0x%x\n", ab->bus, status); - return status; - } - } else - info("bapr: No BUS Resource on PCI 0x%x.\n", ab->bus); - - if (ab->io_head) { - dbg("bapr: IO Resources add on PCI 0x%x\n", ab->bus); - status = shpchprm_add_resources (&ctrl->io_head, ab->io_head); - if (shpchprm_delete_resources (&ab->io_head, ctrl->io_head)) - warn("bapr: cannot sub IO Resource on PCI 0x%x\n", ab->bus); - if (status) { - err("bapr: IO Resource add on PCI 0x%x: fail=0x%x\n", ab->bus, status); - return status; - } - } else - info("bapr: No IO Resource on PCI 0x%x.\n", ab->bus); - - if (ab->mem_head) { - dbg("bapr: MEM Resources add on PCI 0x%x\n", ab->bus); - status = shpchprm_add_resources (&ctrl->mem_head, ab->mem_head); - if (shpchprm_delete_resources (&ab->mem_head, ctrl->mem_head)) - warn("bapr: cannot sub MEM Resource on PCI 0x%x\n", ab->bus); - if (status) { - err("bapr: MEM Resource add on PCI 0x%x: fail=0x%x\n", ab->bus, status); - return status; - } - } else - info("bapr: No MEM Resource on PCI 0x%x.\n", ab->bus); - - if (ab->p_mem_head) { - dbg("bapr: PMEM Resources add on PCI 0x%x\n", ab->bus); - status = shpchprm_add_resources (&ctrl->p_mem_head, ab->p_mem_head); - if (shpchprm_delete_resources (&ab->p_mem_head, ctrl->p_mem_head)) - warn("bapr: cannot sub PMEM Resource on PCI 0x%x\n", ab->bus); - if (status) { - err("bapr: PMEM Resource add on PCI 0x%x: fail=0x%x\n", ab->bus, status); - return status; - } - } else - info("bapr: No PMEM Resource on PCI 0x%x.\n", ab->bus); - - return status; -} - -static int no_pci_resources( struct acpi_bridge *ab) -{ - return !(ab->p_mem_head || ab->mem_head || ab->io_head || ab->bus_head); -} - -static int find_pci_bridge_resources ( - struct controller *ctrl, - struct acpi_bridge *ab - ) -{ - int rc = 0; - struct pci_func func; - - memset(&func, 0, sizeof(struct pci_func)); - - func.bus = ab->pbus; - func.device = ab->pdevice; - func.function = ab->pfunction; - func.is_a_board = 1; - - /* Get used resources for this PCI bridge */ - rc = shpchp_save_used_resources (ctrl, &func, !DISABLE_CARD); - - ab->io_head = func.io_head; - ab->mem_head = func.mem_head; - ab->p_mem_head = func.p_mem_head; - ab->bus_head = func.bus_head; - if (ab->bus_head) - shpchprm_delete_resource(&ab->bus_head, ctrl->bus, 1); - - return rc; -} - -static int get_pci_resources_from_bridge( - struct controller *ctrl, - struct acpi_bridge *ab - ) -{ - int rc = 0; - - dbg("grfb: Get Resources for PCI 0x%x from actual PCI bridge 0x%x.\n", ctrl->bus, ab->bus); - - rc = find_pci_bridge_resources (ctrl, ab); - - shpchp_resource_sort_and_combine(&ab->bus_head); - shpchp_resource_sort_and_combine(&ab->io_head); - shpchp_resource_sort_and_combine(&ab->mem_head); - shpchp_resource_sort_and_combine(&ab->p_mem_head); - - shpchprm_add_resources (&ab->tbus_head, ab->bus_head); - shpchprm_add_resources (&ab->tio_head, ab->io_head); - shpchprm_add_resources (&ab->tmem_head, ab->mem_head); - shpchprm_add_resources (&ab->tp_mem_head, ab->p_mem_head); - - return rc; -} - -static int get_pci_resources( - struct controller *ctrl, - struct acpi_bridge *ab - ) -{ - int rc = 0; - - if (no_pci_resources(ab)) { - dbg("spbr:PCI 0x%x has no resources. Get parent resources.\n", ab->bus); - rc = get_pci_resources_from_bridge(ctrl, ab); - } - - return rc; } int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum) @@ -1570,144 +147,40 @@ int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busn return 0; } -/* - * Get resources for this ctrl. - * 1. get total resources from ACPI _CRS or bridge (this ctrl) - * 2. find used resources of existing adapters - * 3. subtract used resources from total resources - */ -int shpchprm_find_available_resources( struct controller *ctrl) +void get_hp_hw_control_from_firmware(struct pci_dev *dev) { - int rc = 0; - struct acpi_bridge *ab; - - ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl->seg, ctrl->pci_dev->subordinate->number); - if (!ab) { - err("pfar:cannot locate acpi bridge of PCI 0x%x.\n", ctrl->pci_dev->subordinate->number); - return -1; - } - if (no_pci_resources(ab)) { - rc = get_pci_resources(ctrl, ab); - if (rc) { - err("pfar:cannot get pci resources of PCI 0x%x.\n",ctrl->pci_dev->subordinate->number); - return -1; - } - } - - rc = bind_pci_resources(ctrl, ab); - dbg("pfar:pre-Bind PCI 0x%x Ctrl Resource Dump\n", ctrl->pci_dev->subordinate->number); - shpchprm_dump_ctrl_res(ctrl); - - bind_pci_resources_to_slots (ctrl); - - dbg("pfar:post-Bind PCI 0x%x Ctrl Resource Dump\n", ctrl->pci_dev->subordinate->number); - shpchprm_dump_ctrl_res(ctrl); - - return rc; -} - -int shpchprm_set_hpp( - struct controller *ctrl, - struct pci_func *func, - u8 card_type - ) -{ - struct acpi_bridge *ab; - struct pci_bus lpci_bus, *pci_bus; - int rc = 0; - unsigned int devfn; - u8 cls= 0x08; /* default cache line size */ - u8 lt = 0x40; /* default latency timer */ - u8 ep = 0; - u8 es = 0; - - memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus)); - pci_bus = &lpci_bus; - pci_bus->number = func->bus; - devfn = PCI_DEVFN(func->device, func->function); - - ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl->seg, ctrl->slot_bus); - - if (ab) { - if (ab->_hpp) { - lt = (u8)ab->_hpp->latency_timer; - cls = (u8)ab->_hpp->cache_line_size; - ep = (u8)ab->_hpp->enable_perr; - es = (u8)ab->_hpp->enable_serr; - } else - dbg("_hpp: no _hpp for B/D/F=%#x/%#x/%#x. use default value\n", func->bus, func->device, func->function); - } else - dbg("_hpp: no acpi bridge for B/D/F = %#x/%#x/%#x. use default value\n", func->bus, func->device, func->function); - - - if (card_type == PCI_HEADER_TYPE_BRIDGE) { - /* set subordinate Latency Timer */ - rc |= pci_bus_write_config_byte(pci_bus, devfn, PCI_SEC_LATENCY_TIMER, lt); - } - - /* set base Latency Timer */ - rc |= pci_bus_write_config_byte(pci_bus, devfn, PCI_LATENCY_TIMER, lt); - dbg(" set latency timer =0x%02x: %x\n", lt, rc); - - rc |= pci_bus_write_config_byte(pci_bus, devfn, PCI_CACHE_LINE_SIZE, cls); - dbg(" set cache_line_size=0x%02x: %x\n", cls, rc); - - return rc; + /* + * OSHP is an optional ACPI firmware control method. If present, + * we need to run it to inform BIOS that we will control SHPC + * hardware from now on. + */ + acpi_handle handle = DEVICE_ACPI_HANDLE(&(dev->dev)); + if (!handle) + return; + acpi_run_oshp(handle); } -void shpchprm_enable_card( - struct controller *ctrl, - struct pci_func *func, - u8 card_type) +void get_hp_params_from_firmware(struct pci_dev *dev, + struct hotplug_params *hpp) { - u16 command, cmd, bcommand, bcmd; - struct pci_bus lpci_bus, *pci_bus; - struct acpi_bridge *ab; - unsigned int devfn; - int rc; - - memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus)); - pci_bus = &lpci_bus; - pci_bus->number = func->bus; - devfn = PCI_DEVFN(func->device, func->function); - - rc = pci_bus_read_config_word(pci_bus, devfn, PCI_COMMAND, &command); - - if (card_type == PCI_HEADER_TYPE_BRIDGE) { - rc = pci_bus_read_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, &bcommand); - } + acpi_status status = AE_NOT_FOUND; + struct pci_dev *pdev = dev; - cmd = command = command | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE - | PCI_COMMAND_IO | PCI_COMMAND_MEMORY; - bcmd = bcommand = bcommand | PCI_BRIDGE_CTL_NO_ISA; - - ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl->seg, ctrl->slot_bus); - if (ab) { - if (ab->_hpp) { - if (ab->_hpp->enable_perr) { - command |= PCI_COMMAND_PARITY; - bcommand |= PCI_BRIDGE_CTL_PARITY; - } else { - command &= ~PCI_COMMAND_PARITY; - bcommand &= ~PCI_BRIDGE_CTL_PARITY; - } - if (ab->_hpp->enable_serr) { - command |= PCI_COMMAND_SERR; - bcommand |= PCI_BRIDGE_CTL_SERR; - } else { - command &= ~PCI_COMMAND_SERR; - bcommand &= ~PCI_BRIDGE_CTL_SERR; - } - } else - dbg("no _hpp for B/D/F = %#x/%#x/%#x.\n", func->bus, func->device, func->function); - } else - dbg("no acpi bridge for B/D/F = %#x/%#x/%#x.\n", func->bus, func->device, func->function); - - if (command != cmd) { - rc = pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command); - } - if ((card_type == PCI_HEADER_TYPE_BRIDGE) && (bcommand != bcmd)) { - rc = pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, bcommand); + /* + * _HPP settings apply to all child buses, until another _HPP is + * encountered. If we don't find an _HPP for the input pci dev, + * look for it in the parent device scope since that would apply to + * this pci dev. If we don't find any _HPP, use hardcoded defaults + */ + while (pdev && (ACPI_FAILURE(status))) { + acpi_handle handle = DEVICE_ACPI_HANDLE(&(pdev->dev)); + if (!handle) + break; + status = acpi_run_hpp(handle, hpp); + if (!(pdev->bus->parent)) + break; + /* Check if a parent object supports _HPP */ + pdev = pdev->bus->parent->self; } } diff --git a/drivers/pci/hotplug/shpchprm_legacy.c b/drivers/pci/hotplug/shpchprm_legacy.c index ba6c549c9b9d..ed6c1254bf6f 100644 --- a/drivers/pci/hotplug/shpchprm_legacy.c +++ b/drivers/pci/hotplug/shpchprm_legacy.c @@ -27,33 +27,11 @@ * */ -#include <linux/config.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/types.h> #include <linux/pci.h> -#include <linux/init.h> -#include <asm/uaccess.h> -#ifdef CONFIG_IA64 -#include <asm/iosapic.h> -#endif #include "shpchp.h" -#include "shpchprm.h" -#include "shpchprm_legacy.h" - -static void __iomem *shpchp_rom_start; -static u16 unused_IRQ; - -void shpchprm_cleanup(void) -{ - if (shpchp_rom_start) - iounmap(shpchp_rom_start); -} - -int shpchprm_print_pirt(void) -{ - return 0; -} int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum) { @@ -63,377 +41,14 @@ int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busn return 0; } -/* Find the Hot Plug Resource Table in the specified region of memory */ -static void __iomem *detect_HRT_floating_pointer(void __iomem *begin, void __iomem *end) +void get_hp_params_from_firmware(struct pci_dev *dev, + struct hotplug_params *hpp) { - void __iomem *fp; - void __iomem *endp; - u8 temp1, temp2, temp3, temp4; - int status = 0; - - endp = (end - sizeof(struct hrt) + 1); - - for (fp = begin; fp <= endp; fp += 16) { - temp1 = readb(fp + SIG0); - temp2 = readb(fp + SIG1); - temp3 = readb(fp + SIG2); - temp4 = readb(fp + SIG3); - if (temp1 == '$' && temp2 == 'H' && temp3 == 'R' && temp4 == 'T') { - status = 1; - break; - } - } - - if (!status) - fp = NULL; - - dbg("Discovered Hotplug Resource Table at %p\n", fp); - return fp; + return; } -/* - * shpchprm_find_available_resources - * - * Finds available memory, IO, and IRQ resources for programming - * devices which may be added to the system - * this function is for hot plug ADD! - * - * returns 0 if success - */ -int shpchprm_find_available_resources(struct controller *ctrl) +void get_hp_hw_control_from_firmware(struct pci_dev *dev) { - u8 populated_slot; - u8 bridged_slot; - void __iomem *one_slot; - struct pci_func *func = NULL; - int i = 10, index = 0; - u32 temp_dword, rc; - ulong temp_ulong; - struct pci_resource *mem_node; - struct pci_resource *p_mem_node; - struct pci_resource *io_node; - struct pci_resource *bus_node; - void __iomem *rom_resource_table; - struct pci_bus lpci_bus, *pci_bus; - u8 cfgspc_irq, temp; - - memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus)); - pci_bus = &lpci_bus; - rom_resource_table = detect_HRT_floating_pointer(shpchp_rom_start, shpchp_rom_start + 0xffff); - dbg("rom_resource_table = %p\n", rom_resource_table); - if (rom_resource_table == NULL) - return -ENODEV; - - /* Sum all resources and setup resource maps */ - unused_IRQ = readl(rom_resource_table + UNUSED_IRQ); - dbg("unused_IRQ = %x\n", unused_IRQ); - - temp = 0; - while (unused_IRQ) { - if (unused_IRQ & 1) { - shpchp_disk_irq = temp; - break; - } - unused_IRQ = unused_IRQ >> 1; - temp++; - } - - dbg("shpchp_disk_irq= %d\n", shpchp_disk_irq); - unused_IRQ = unused_IRQ >> 1; - temp++; - - while (unused_IRQ) { - if (unused_IRQ & 1) { - shpchp_nic_irq = temp; - break; - } - unused_IRQ = unused_IRQ >> 1; - temp++; - } - - dbg("shpchp_nic_irq= %d\n", shpchp_nic_irq); - unused_IRQ = readl(rom_resource_table + PCIIRQ); - - temp = 0; - - pci_read_config_byte(ctrl->pci_dev, PCI_INTERRUPT_LINE, &cfgspc_irq); - - if (!shpchp_nic_irq) { - shpchp_nic_irq = cfgspc_irq; - } - - if (!shpchp_disk_irq) { - shpchp_disk_irq = cfgspc_irq; - } - - dbg("shpchp_disk_irq, shpchp_nic_irq= %d, %d\n", shpchp_disk_irq, shpchp_nic_irq); - - one_slot = rom_resource_table + sizeof(struct hrt); - - i = readb(rom_resource_table + NUMBER_OF_ENTRIES); - dbg("number_of_entries = %d\n", i); - - if (!readb(one_slot + SECONDARY_BUS)) - return (1); - - dbg("dev|IO base|length|MEMbase|length|PM base|length|PB SB MB\n"); - - while (i && readb(one_slot + SECONDARY_BUS)) { - u8 dev_func = readb(one_slot + DEV_FUNC); - u8 primary_bus = readb(one_slot + PRIMARY_BUS); - u8 secondary_bus = readb(one_slot + SECONDARY_BUS); - u8 max_bus = readb(one_slot + MAX_BUS); - u16 io_base = readw(one_slot + IO_BASE); - u16 io_length = readw(one_slot + IO_LENGTH); - u16 mem_base = readw(one_slot + MEM_BASE); - u16 mem_length = readw(one_slot + MEM_LENGTH); - u16 pre_mem_base = readw(one_slot + PRE_MEM_BASE); - u16 pre_mem_length = readw(one_slot + PRE_MEM_LENGTH); - - dbg("%2.2x | %4.4x | %4.4x | %4.4x | %4.4x | %4.4x | %4.4x |%2.2x %2.2x %2.2x\n", - dev_func, io_base, io_length, mem_base, mem_length, pre_mem_base, pre_mem_length, - primary_bus, secondary_bus, max_bus); - - /* If this entry isn't for our controller's bus, ignore it */ - if (primary_bus != ctrl->slot_bus) { - i--; - one_slot += sizeof(struct slot_rt); - continue; - } - /* find out if this entry is for an occupied slot */ - temp_dword = 0xFFFFFFFF; - pci_bus->number = primary_bus; - pci_bus_read_config_dword(pci_bus, dev_func, PCI_VENDOR_ID, &temp_dword); - - dbg("temp_D_word = %x\n", temp_dword); - - if (temp_dword != 0xFFFFFFFF) { - index = 0; - func = shpchp_slot_find(primary_bus, dev_func >> 3, 0); - - while (func && (func->function != (dev_func & 0x07))) { - dbg("func = %p b:d:f(%x:%x:%x)\n", func, primary_bus, dev_func >> 3, index); - func = shpchp_slot_find(primary_bus, dev_func >> 3, index++); - } - - /* If we can't find a match, skip this table entry */ - if (!func) { - i--; - one_slot += sizeof(struct slot_rt); - continue; - } - /* this may not work and shouldn't be used */ - if (secondary_bus != primary_bus) - bridged_slot = 1; - else - bridged_slot = 0; - - populated_slot = 1; - } else { - populated_slot = 0; - bridged_slot = 0; - } - dbg("slot populated =%s \n", populated_slot?"yes":"no"); - - /* If we've got a valid IO base, use it */ - - temp_ulong = io_base + io_length; - - if ((io_base) && (temp_ulong <= 0x10000)) { - io_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - if (!io_node) - return -ENOMEM; - - io_node->base = (ulong)io_base; - io_node->length = (ulong)io_length; - dbg("found io_node(base, length) = %x, %x\n", io_node->base, io_node->length); - - if (!populated_slot) { - io_node->next = ctrl->io_head; - ctrl->io_head = io_node; - } else { - io_node->next = func->io_head; - func->io_head = io_node; - } - } - - /* If we've got a valid memory base, use it */ - temp_ulong = mem_base + mem_length; - if ((mem_base) && (temp_ulong <= 0x10000)) { - mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - if (!mem_node) - return -ENOMEM; - - mem_node->base = (ulong)mem_base << 16; - mem_node->length = (ulong)(mem_length << 16); - dbg("found mem_node(base, length) = %x, %x\n", mem_node->base, mem_node->length); - - if (!populated_slot) { - mem_node->next = ctrl->mem_head; - ctrl->mem_head = mem_node; - } else { - mem_node->next = func->mem_head; - func->mem_head = mem_node; - } - } - - /* - * If we've got a valid prefetchable memory base, and - * the base + length isn't greater than 0xFFFF - */ - temp_ulong = pre_mem_base + pre_mem_length; - if ((pre_mem_base) && (temp_ulong <= 0x10000)) { - p_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - if (!p_mem_node) - return -ENOMEM; - - p_mem_node->base = (ulong)pre_mem_base << 16; - p_mem_node->length = (ulong)pre_mem_length << 16; - dbg("found p_mem_node(base, length) = %x, %x\n", p_mem_node->base, p_mem_node->length); - - if (!populated_slot) { - p_mem_node->next = ctrl->p_mem_head; - ctrl->p_mem_head = p_mem_node; - } else { - p_mem_node->next = func->p_mem_head; - func->p_mem_head = p_mem_node; - } - } - - /* - * If we've got a valid bus number, use it - * The second condition is to ignore bus numbers on - * populated slots that don't have PCI-PCI bridges - */ - if (secondary_bus && (secondary_bus != primary_bus)) { - bus_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - if (!bus_node) - return -ENOMEM; - - bus_node->base = (ulong)secondary_bus; - bus_node->length = (ulong)(max_bus - secondary_bus + 1); - dbg("found bus_node(base, length) = %x, %x\n", bus_node->base, bus_node->length); - - if (!populated_slot) { - bus_node->next = ctrl->bus_head; - ctrl->bus_head = bus_node; - } else { - bus_node->next = func->bus_head; - func->bus_head = bus_node; - } - } - - i--; - one_slot += sizeof(struct slot_rt); - } - - /* If all of the following fail, we don't have any resources for hot plug add */ - rc = 1; - rc &= shpchp_resource_sort_and_combine(&(ctrl->mem_head)); - rc &= shpchp_resource_sort_and_combine(&(ctrl->p_mem_head)); - rc &= shpchp_resource_sort_and_combine(&(ctrl->io_head)); - rc &= shpchp_resource_sort_and_combine(&(ctrl->bus_head)); - - return (rc); + return; } -int shpchprm_set_hpp( - struct controller *ctrl, - struct pci_func *func, - u8 card_type) -{ - u32 rc; - u8 temp_byte; - struct pci_bus lpci_bus, *pci_bus; - unsigned int devfn; - memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus)); - pci_bus = &lpci_bus; - pci_bus->number = func->bus; - devfn = PCI_DEVFN(func->device, func->function); - - temp_byte = 0x40; /* hard coded value for LT */ - if (card_type == PCI_HEADER_TYPE_BRIDGE) { - /* set subordinate Latency Timer */ - rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_SEC_LATENCY_TIMER, temp_byte); - if (rc) { - dbg("%s: set secondary LT error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func->bus, - func->device, func->function); - return rc; - } - } - - /* set base Latency Timer */ - rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_LATENCY_TIMER, temp_byte); - if (rc) { - dbg("%s: set LT error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func->bus, func->device, func->function); - return rc; - } - - /* set Cache Line size */ - temp_byte = 0x08; /* hard coded value for CLS */ - rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_CACHE_LINE_SIZE, temp_byte); - if (rc) { - dbg("%s: set CLS error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func->bus, func->device, func->function); - } - - /* set enable_perr */ - /* set enable_serr */ - - return rc; -} - -void shpchprm_enable_card( - struct controller *ctrl, - struct pci_func *func, - u8 card_type) -{ - u16 command, bcommand; - struct pci_bus lpci_bus, *pci_bus; - unsigned int devfn; - int rc; - - memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus)); - pci_bus = &lpci_bus; - pci_bus->number = func->bus; - devfn = PCI_DEVFN(func->device, func->function); - - rc = pci_bus_read_config_word(pci_bus, devfn, PCI_COMMAND, &command); - command |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR - | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE - | PCI_COMMAND_IO | PCI_COMMAND_MEMORY; - rc = pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command); - - if (card_type == PCI_HEADER_TYPE_BRIDGE) { - rc = pci_bus_read_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, &bcommand); - bcommand |= PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR - | PCI_BRIDGE_CTL_NO_ISA; - rc = pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, bcommand); - } -} - -static int legacy_shpchprm_init_pci(void) -{ - shpchp_rom_start = ioremap(ROM_PHY_ADDR, ROM_PHY_LEN); - if (!shpchp_rom_start) { - err("Could not ioremap memory region for ROM\n"); - return -EIO; - } - - return 0; -} - -int shpchprm_init(enum php_ctlr_type ctrl_type) -{ - int retval; - - switch (ctrl_type) { - case PCI: - retval = legacy_shpchprm_init_pci(); - break; - default: - retval = -ENODEV; - break; - } - - return retval; -} diff --git a/drivers/pci/hotplug/shpchprm_legacy.h b/drivers/pci/hotplug/shpchprm_legacy.h deleted file mode 100644 index 21bda74ddfa5..000000000000 --- a/drivers/pci/hotplug/shpchprm_legacy.h +++ /dev/null @@ -1,113 +0,0 @@ -/* - * SHPCHPRM Legacy: PHP Resource Manager for Non-ACPI/Legacy platform using HRT - * - * Copyright (C) 1995,2001 Compaq Computer Corporation - * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (C) 2001 IBM Corp. - * Copyright (C) 2003-2004 Intel Corporation - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License 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, GOOD TITLE or - * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Send feedback to <greg@kroah.com>, <kristen.c.accardi@intel.com> - * - */ - -#ifndef _SHPCHPRM_LEGACY_H_ -#define _SHPCHPRM_LEGACY_H_ - -#define ROM_PHY_ADDR 0x0F0000 -#define ROM_PHY_LEN 0x00FFFF - -struct slot_rt { - u8 dev_func; - u8 primary_bus; - u8 secondary_bus; - u8 max_bus; - u16 io_base; - u16 io_length; - u16 mem_base; - u16 mem_length; - u16 pre_mem_base; - u16 pre_mem_length; -} __attribute__ ((packed)); - -/* offsets to the hotplug slot resource table registers based on the above structure layout */ -enum slot_rt_offsets { - DEV_FUNC = offsetof(struct slot_rt, dev_func), - PRIMARY_BUS = offsetof(struct slot_rt, primary_bus), - SECONDARY_BUS = offsetof(struct slot_rt, secondary_bus), - MAX_BUS = offsetof(struct slot_rt, max_bus), - IO_BASE = offsetof(struct slot_rt, io_base), - IO_LENGTH = offsetof(struct slot_rt, io_length), - MEM_BASE = offsetof(struct slot_rt, mem_base), - MEM_LENGTH = offsetof(struct slot_rt, mem_length), - PRE_MEM_BASE = offsetof(struct slot_rt, pre_mem_base), - PRE_MEM_LENGTH = offsetof(struct slot_rt, pre_mem_length), -}; - -struct hrt { - char sig0; - char sig1; - char sig2; - char sig3; - u16 unused_IRQ; - u16 PCIIRQ; - u8 number_of_entries; - u8 revision; - u16 reserved1; - u32 reserved2; -} __attribute__ ((packed)); - -/* offsets to the hotplug resource table registers based on the above structure layout */ -enum hrt_offsets { - SIG0 = offsetof(struct hrt, sig0), - SIG1 = offsetof(struct hrt, sig1), - SIG2 = offsetof(struct hrt, sig2), - SIG3 = offsetof(struct hrt, sig3), - UNUSED_IRQ = offsetof(struct hrt, unused_IRQ), - PCIIRQ = offsetof(struct hrt, PCIIRQ), - NUMBER_OF_ENTRIES = offsetof(struct hrt, number_of_entries), - REVISION = offsetof(struct hrt, revision), - HRT_RESERVED1 = offsetof(struct hrt, reserved1), - HRT_RESERVED2 = offsetof(struct hrt, reserved2), -}; - -struct irq_info { - u8 bus, devfn; /* bus, device and function */ - struct { - u8 link; /* IRQ line ID, chipset dependent, 0=not routed */ - u16 bitmap; /* Available IRQs */ - } __attribute__ ((packed)) irq[4]; - u8 slot; /* slot number, 0=onboard */ - u8 rfu; -} __attribute__ ((packed)); - -struct irq_routing_table { - u32 signature; /* PIRQ_SIGNATURE should be here */ - u16 version; /* PIRQ_VERSION */ - u16 size; /* Table size in bytes */ - u8 rtr_bus, rtr_devfn; /* Where the interrupt router lies */ - u16 exclusive_irqs; /* IRQs devoted exclusively to PCI usage */ - u16 rtr_vendor, rtr_device; /* Vendor and device ID of interrupt router */ - u32 miniport_data; /* Crap */ - u8 rfu[11]; - u8 checksum; /* Modulo 256 checksum must give zero */ - struct irq_info slots[0]; -} __attribute__ ((packed)); - -#endif /* _SHPCHPRM_LEGACY_H_ */ diff --git a/drivers/pci/hotplug/shpchprm_nonacpi.c b/drivers/pci/hotplug/shpchprm_nonacpi.c index 5f75ef7f3df2..c6b40998eeb3 100644 --- a/drivers/pci/hotplug/shpchprm_nonacpi.c +++ b/drivers/pci/hotplug/shpchprm_nonacpi.c @@ -32,24 +32,9 @@ #include <linux/kernel.h> #include <linux/types.h> #include <linux/pci.h> -#include <linux/init.h> -#include <asm/uaccess.h> -#ifdef CONFIG_IA64 -#include <asm/iosapic.h> -#endif -#include "shpchp.h" -#include "shpchprm.h" -#include "shpchprm_nonacpi.h" +#include <linux/slab.h> -void shpchprm_cleanup(void) -{ - return; -} - -int shpchprm_print_pirt(void) -{ - return 0; -} +#include "shpchp.h" int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum) { @@ -60,375 +45,13 @@ int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busn return 0; } -static void print_pci_resource ( struct pci_resource *aprh) -{ - struct pci_resource *res; - - for (res = aprh; res; res = res->next) - dbg(" base= 0x%x length= 0x%x\n", res->base, res->length); -} - - -static void phprm_dump_func_res( struct pci_func *fun) -{ - struct pci_func *func = fun; - - if (func->bus_head) { - dbg(": BUS Resources:\n"); - print_pci_resource (func->bus_head); - } - if (func->io_head) { - dbg(": IO Resources:\n"); - print_pci_resource (func->io_head); - } - if (func->mem_head) { - dbg(": MEM Resources:\n"); - print_pci_resource (func->mem_head); - } - if (func->p_mem_head) { - dbg(": PMEM Resources:\n"); - print_pci_resource (func->p_mem_head); - } -} - -static int phprm_get_used_resources ( - struct controller *ctrl, - struct pci_func *func - ) -{ - return shpchp_save_used_resources (ctrl, func, !DISABLE_CARD); -} - -static int phprm_delete_resource( - struct pci_resource **aprh, - ulong base, - ulong size) -{ - struct pci_resource *res; - struct pci_resource *prevnode; - struct pci_resource *split_node; - ulong tbase; - - shpchp_resource_sort_and_combine(aprh); - - for (res = *aprh; res; res = res->next) { - if (res->base > base) - continue; - - if ((res->base + res->length) < (base + size)) - continue; - - if (res->base < base) { - tbase = base; - - if ((res->length - (tbase - res->base)) < size) - continue; - - split_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - if (!split_node) - return -ENOMEM; - - split_node->base = res->base; - split_node->length = tbase - res->base; - res->base = tbase; - res->length -= split_node->length; - - split_node->next = res->next; - res->next = split_node; - } - - if (res->length >= size) { - split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - if (!split_node) - return -ENOMEM; - - split_node->base = res->base + size; - split_node->length = res->length - size; - res->length = size; - - split_node->next = res->next; - res->next = split_node; - } - - if (*aprh == res) { - *aprh = res->next; - } else { - prevnode = *aprh; - while (prevnode->next != res) - prevnode = prevnode->next; - - prevnode->next = res->next; - } - res->next = NULL; - kfree(res); - break; - } - - return 0; -} - - -static int phprm_delete_resources( - struct pci_resource **aprh, - struct pci_resource *this - ) -{ - struct pci_resource *res; - - for (res = this; res; res = res->next) - phprm_delete_resource(aprh, res->base, res->length); - - return 0; -} - - -static int configure_existing_function( - struct controller *ctrl, - struct pci_func *func - ) -{ - int rc; - - /* see how much resources the func has used. */ - rc = phprm_get_used_resources (ctrl, func); - - if (!rc) { - /* subtract the resources used by the func from ctrl resources */ - rc = phprm_delete_resources (&ctrl->bus_head, func->bus_head); - rc |= phprm_delete_resources (&ctrl->io_head, func->io_head); - rc |= phprm_delete_resources (&ctrl->mem_head, func->mem_head); - rc |= phprm_delete_resources (&ctrl->p_mem_head, func->p_mem_head); - if (rc) - warn("aCEF: cannot del used resources\n"); - } else - err("aCEF: cannot get used resources\n"); - - return rc; -} - -static int bind_pci_resources_to_slots ( struct controller *ctrl) -{ - struct pci_func *func, new_func; - int busn = ctrl->slot_bus; - int devn, funn; - u32 vid; - - for (devn = 0; devn < 32; devn++) { - for (funn = 0; funn < 8; funn++) { - /* - if (devn == ctrl->device && funn == ctrl->function) - continue; - */ - /* find out if this entry is for an occupied slot */ - vid = 0xFFFFFFFF; - - pci_bus_read_config_dword(ctrl->pci_dev->subordinate, PCI_DEVFN(devn, funn), PCI_VENDOR_ID, &vid); - - if (vid != 0xFFFFFFFF) { - func = shpchp_slot_find(busn, devn, funn); - if (!func) { - memset(&new_func, 0, sizeof(struct pci_func)); - new_func.bus = busn; - new_func.device = devn; - new_func.function = funn; - new_func.is_a_board = 1; - configure_existing_function(ctrl, &new_func); - phprm_dump_func_res(&new_func); - } else { - configure_existing_function(ctrl, func); - phprm_dump_func_res(func); - } - dbg("aCCF:existing PCI 0x%x Func ResourceDump\n", ctrl->bus); - } - } - } - - return 0; -} - -static void phprm_dump_ctrl_res( struct controller *ctlr) -{ - struct controller *ctrl = ctlr; - - if (ctrl->bus_head) { - dbg(": BUS Resources:\n"); - print_pci_resource (ctrl->bus_head); - } - if (ctrl->io_head) { - dbg(": IO Resources:\n"); - print_pci_resource (ctrl->io_head); - } - if (ctrl->mem_head) { - dbg(": MEM Resources:\n"); - print_pci_resource (ctrl->mem_head); - } - if (ctrl->p_mem_head) { - dbg(": PMEM Resources:\n"); - print_pci_resource (ctrl->p_mem_head); - } -} - -/* - * phprm_find_available_resources - * - * Finds available memory, IO, and IRQ resources for programming - * devices which may be added to the system - * this function is for hot plug ADD! - * - * returns 0 if success - */ -int shpchprm_find_available_resources(struct controller *ctrl) -{ - struct pci_func func; - u32 rc; - - memset(&func, 0, sizeof(struct pci_func)); - - func.bus = ctrl->bus; - func.device = ctrl->device; - func.function = ctrl->function; - func.is_a_board = 1; - - /* Get resources for this PCI bridge */ - rc = shpchp_save_used_resources (ctrl, &func, !DISABLE_CARD); - dbg("%s: shpchp_save_used_resources rc = %d\n", __FUNCTION__, rc); - - if (func.mem_head) - func.mem_head->next = ctrl->mem_head; - ctrl->mem_head = func.mem_head; - - if (func.p_mem_head) - func.p_mem_head->next = ctrl->p_mem_head; - ctrl->p_mem_head = func.p_mem_head; - - if (func.io_head) - func.io_head->next = ctrl->io_head; - ctrl->io_head = func.io_head; - - if(func.bus_head) - func.bus_head->next = ctrl->bus_head; - ctrl->bus_head = func.bus_head; - if (ctrl->bus_head) - phprm_delete_resource(&ctrl->bus_head, ctrl->pci_dev->subordinate->number, 1); - - dbg("%s:pre-Bind PCI 0x%x Ctrl Resource Dump\n", __FUNCTION__, ctrl->bus); - phprm_dump_ctrl_res(ctrl); - bind_pci_resources_to_slots (ctrl); - - dbg("%s:post-Bind PCI 0x%x Ctrl Resource Dump\n", __FUNCTION__, ctrl->bus); - phprm_dump_ctrl_res(ctrl); - - - /* If all of the following fail, we don't have any resources for hot plug add */ - rc = 1; - rc &= shpchp_resource_sort_and_combine(&(ctrl->mem_head)); - rc &= shpchp_resource_sort_and_combine(&(ctrl->p_mem_head)); - rc &= shpchp_resource_sort_and_combine(&(ctrl->io_head)); - rc &= shpchp_resource_sort_and_combine(&(ctrl->bus_head)); - - return (rc); -} - -int shpchprm_set_hpp( - struct controller *ctrl, - struct pci_func *func, - u8 card_type) +void get_hp_params_from_firmware(struct pci_dev *dev, + struct hotplug_params *hpp) { - u32 rc; - u8 temp_byte; - struct pci_bus lpci_bus, *pci_bus; - unsigned int devfn; - memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus)); - pci_bus = &lpci_bus; - pci_bus->number = func->bus; - devfn = PCI_DEVFN(func->device, func->function); - - temp_byte = 0x40; /* hard coded value for LT */ - if (card_type == PCI_HEADER_TYPE_BRIDGE) { - /* set subordinate Latency Timer */ - rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_SEC_LATENCY_TIMER, temp_byte); - - if (rc) { - dbg("%s: set secondary LT error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func->bus, - func->device, func->function); - return rc; - } - } - - /* set base Latency Timer */ - rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_LATENCY_TIMER, temp_byte); - - if (rc) { - dbg("%s: set LT error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func->bus, func->device, func->function); - return rc; - } - - /* set Cache Line size */ - temp_byte = 0x08; /* hard coded value for CLS */ - - rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_CACHE_LINE_SIZE, temp_byte); - - if (rc) { - dbg("%s: set CLS error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func->bus, func->device, func->function); - } - - /* set enable_perr */ - /* set enable_serr */ - - return rc; -} - -void shpchprm_enable_card( - struct controller *ctrl, - struct pci_func *func, - u8 card_type) -{ - u16 command, bcommand; - struct pci_bus lpci_bus, *pci_bus; - unsigned int devfn; - int rc; - - memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus)); - pci_bus = &lpci_bus; - pci_bus->number = func->bus; - devfn = PCI_DEVFN(func->device, func->function); - - rc = pci_bus_read_config_word(pci_bus, devfn, PCI_COMMAND, &command); - - command |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR - | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE - | PCI_COMMAND_IO | PCI_COMMAND_MEMORY; - - rc = pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command); - - if (card_type == PCI_HEADER_TYPE_BRIDGE) { - - rc = pci_bus_read_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, &bcommand); - - bcommand |= PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR - | PCI_BRIDGE_CTL_NO_ISA; - - rc = pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, bcommand); - } -} - -static int legacy_shpchprm_init_pci(void) -{ - return 0; + return; } -int shpchprm_init(enum php_ctlr_type ctrl_type) +void get_hp_hw_control_from_firmware(struct pci_dev *dev) { - int retval; - - switch (ctrl_type) { - case PCI: - retval = legacy_shpchprm_init_pci(); - break; - default: - retval = -ENODEV; - break; - } - - return retval; + return; } diff --git a/drivers/pci/hotplug/shpchprm_nonacpi.h b/drivers/pci/hotplug/shpchprm_nonacpi.h deleted file mode 100644 index cddaaa5ee1b3..000000000000 --- a/drivers/pci/hotplug/shpchprm_nonacpi.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * SHPCHPRM NONACPI: PHP Resource Manager for Non-ACPI/Legacy platform - * - * Copyright (C) 1995,2001 Compaq Computer Corporation - * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (C) 2001 IBM Corp. - * Copyright (C) 2003-2004 Intel Corporation - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License 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, GOOD TITLE or - * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Send feedback to <greg@kroah.com>, <kristen.c.accardi@intel.com> - * - */ - -#ifndef _SHPCHPRM_NONACPI_H_ -#define _SHPCHPRM_NONACPI_H_ - -struct irq_info { - u8 bus, devfn; /* bus, device and function */ - struct { - u8 link; /* IRQ line ID, chipset dependent, 0=not routed */ - u16 bitmap; /* Available IRQs */ - } __attribute__ ((packed)) irq[4]; - u8 slot; /* slot number, 0=onboard */ - u8 rfu; -} __attribute__ ((packed)); - -struct irq_routing_table { - u32 signature; /* PIRQ_SIGNATURE should be here */ - u16 version; /* PIRQ_VERSION */ - u16 size; /* Table size in bytes */ - u8 rtr_bus, rtr_devfn; /* Where the interrupt router lies */ - u16 exclusive_irqs; /* IRQs devoted exclusively to PCI usage */ - u16 rtr_vendor, rtr_device; /* Vendor and device ID of interrupt router */ - u32 miniport_data; /* Crap */ - u8 rfu[11]; - u8 checksum; /* Modulo 256 checksum must give zero */ - struct irq_info slots[0]; -} __attribute__ ((packed)); - -#endif /* _SHPCHPRM_NONACPI_H_ */ diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index ee8677bda950..a2033552423c 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -575,6 +575,8 @@ static int msi_capability_init(struct pci_dev *dev) /** * msix_capability_init - configure device's MSI-X capability * @dev: pointer to the pci_dev data structure of MSI-X device function + * @entries: pointer to an array of struct msix_entry entries + * @nvec: number of @entries * * Setup the MSI-X capability structure of device function with a * single MSI-X vector. A return of zero indicates the successful setup of diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 0d0d533894e0..ae986e590b48 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -8,6 +8,8 @@ #include <linux/init.h> #include <linux/device.h> #include <linux/mempolicy.h> +#include <linux/string.h> +#include <linux/slab.h> #include "pci.h" /* @@ -26,7 +28,10 @@ struct pci_dynid { #ifdef CONFIG_HOTPLUG /** - * store_new_id + * store_new_id - add a new PCI device ID to this driver and re-probe devices + * @driver: target device driver + * @buf: buffer for scanning device ID data + * @count: input size * * Adds a new dynamic pci device ID to this driver, * and causes the driver to probe for all devices again. @@ -194,8 +199,10 @@ static int pci_call_probe(struct pci_driver *drv, struct pci_dev *dev, /** * __pci_device_probe() + * @drv: driver to call to check if it wants the PCI device + * @pci_dev: PCI device being probed * - * returns 0 on success, else error. + * returns 0 on success, else error. * side-effect: pci_dev->driver is set to drv when drv claims pci_dev. */ static int @@ -377,6 +384,10 @@ int pci_register_driver(struct pci_driver *drv) * the pci shutdown function, this test can go away. */ if (!drv->driver.shutdown) drv->driver.shutdown = pci_device_shutdown; + else + printk(KERN_WARNING "Warning: PCI driver %s has a struct " + "device_driver shutdown method, please update!\n", + drv->name); drv->driver.owner = drv->owner; drv->driver.kobj.ktype = &pci_driver_kobj_type; @@ -436,11 +447,11 @@ pci_dev_driver(const struct pci_dev *dev) /** * pci_bus_match - Tell if a PCI device structure has a matching PCI device id structure - * @ids: array of PCI device id structures to search in * @dev: the PCI device structure to match against + * @drv: the device driver to search for matching PCI device id structures * * Used by a driver to check whether a PCI device present in the - * system is in its list of supported devices.Returns the matching + * system is in its list of supported devices. Returns the matching * pci_device_id structure or %NULL if there is no match. */ static int pci_bus_match(struct device *dev, struct device_driver *drv) diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 2898830c496f..965a5934623a 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -130,7 +130,7 @@ pci_read_config(struct kobject *kobj, char *buf, loff_t off, size_t count) if ((off & 1) && size) { u8 val; - pci_read_config_byte(dev, off, &val); + pci_user_read_config_byte(dev, off, &val); data[off - init_off] = val; off++; size--; @@ -138,7 +138,7 @@ pci_read_config(struct kobject *kobj, char *buf, loff_t off, size_t count) if ((off & 3) && size > 2) { u16 val; - pci_read_config_word(dev, off, &val); + pci_user_read_config_word(dev, off, &val); data[off - init_off] = val & 0xff; data[off - init_off + 1] = (val >> 8) & 0xff; off += 2; @@ -147,7 +147,7 @@ pci_read_config(struct kobject *kobj, char *buf, loff_t off, size_t count) while (size > 3) { u32 val; - pci_read_config_dword(dev, off, &val); + pci_user_read_config_dword(dev, off, &val); data[off - init_off] = val & 0xff; data[off - init_off + 1] = (val >> 8) & 0xff; data[off - init_off + 2] = (val >> 16) & 0xff; @@ -158,7 +158,7 @@ pci_read_config(struct kobject *kobj, char *buf, loff_t off, size_t count) if (size >= 2) { u16 val; - pci_read_config_word(dev, off, &val); + pci_user_read_config_word(dev, off, &val); data[off - init_off] = val & 0xff; data[off - init_off + 1] = (val >> 8) & 0xff; off += 2; @@ -167,7 +167,7 @@ pci_read_config(struct kobject *kobj, char *buf, loff_t off, size_t count) if (size > 0) { u8 val; - pci_read_config_byte(dev, off, &val); + pci_user_read_config_byte(dev, off, &val); data[off - init_off] = val; off++; --size; @@ -192,7 +192,7 @@ pci_write_config(struct kobject *kobj, char *buf, loff_t off, size_t count) } if ((off & 1) && size) { - pci_write_config_byte(dev, off, data[off - init_off]); + pci_user_write_config_byte(dev, off, data[off - init_off]); off++; size--; } @@ -200,7 +200,7 @@ pci_write_config(struct kobject *kobj, char *buf, loff_t off, size_t count) if ((off & 3) && size > 2) { u16 val = data[off - init_off]; val |= (u16) data[off - init_off + 1] << 8; - pci_write_config_word(dev, off, val); + pci_user_write_config_word(dev, off, val); off += 2; size -= 2; } @@ -210,7 +210,7 @@ pci_write_config(struct kobject *kobj, char *buf, loff_t off, size_t count) val |= (u32) data[off - init_off + 1] << 8; val |= (u32) data[off - init_off + 2] << 16; val |= (u32) data[off - init_off + 3] << 24; - pci_write_config_dword(dev, off, val); + pci_user_write_config_dword(dev, off, val); off += 4; size -= 4; } @@ -218,13 +218,13 @@ pci_write_config(struct kobject *kobj, char *buf, loff_t off, size_t count) if (size >= 2) { u16 val = data[off - init_off]; val |= (u16) data[off - init_off + 1] << 8; - pci_write_config_word(dev, off, val); + pci_user_write_config_word(dev, off, val); off += 2; size -= 2; } if (size) { - pci_write_config_byte(dev, off, data[off - init_off]); + pci_user_write_config_byte(dev, off, data[off - init_off]); off++; --size; } diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 259d247b7551..e74d75843047 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -15,6 +15,7 @@ #include <linux/pci.h> #include <linux/module.h> #include <linux/spinlock.h> +#include <linux/string.h> #include <asm/dma.h> /* isa_dma_bridge_buggy */ #include "pci.h" @@ -252,6 +253,8 @@ pci_restore_bars(struct pci_dev *dev) pci_update_resource(dev, &dev->resource[i], i); } +int (*platform_pci_set_power_state)(struct pci_dev *dev, pci_power_t t); + /** * pci_set_power_state - Set the power state of a PCI device * @dev: PCI device to be suspended @@ -266,7 +269,6 @@ pci_restore_bars(struct pci_dev *dev) * -EIO if device does not support PCI PM. * 0 if we can successfully change the power state. */ -int (*platform_pci_set_power_state)(struct pci_dev *dev, pci_power_t t); int pci_set_power_state(struct pci_dev *dev, pci_power_t state) { @@ -314,19 +316,19 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state) * sets PowerState to 0. */ switch (dev->current_state) { + case PCI_D0: + case PCI_D1: + case PCI_D2: + pmcsr &= ~PCI_PM_CTRL_STATE_MASK; + pmcsr |= state; + break; case PCI_UNKNOWN: /* Boot-up */ if ((pmcsr & PCI_PM_CTRL_STATE_MASK) == PCI_D3hot && !(pmcsr & PCI_PM_CTRL_NO_SOFT_RESET)) need_restore = 1; /* Fall-through: force to D0 */ - case PCI_D3hot: - case PCI_D3cold: - case PCI_POWER_ERROR: - pmcsr = 0; - break; default: - pmcsr &= ~PCI_PM_CTRL_STATE_MASK; - pmcsr |= state; + pmcsr = 0; break; } @@ -808,8 +810,8 @@ pci_clear_mwi(struct pci_dev *dev) /** * pci_intx - enables/disables PCI INTx for device dev - * @dev: the PCI device to operate on - * @enable: boolean + * @pdev: the PCI device to operate on + * @enable: boolean: whether to enable or disable PCI INTx * * Enables/disables PCI INTx for device dev */ diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index d3f3dd42240d..6527b36c9a61 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -15,6 +15,13 @@ extern int pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res, extern int (*platform_pci_choose_state)(struct pci_dev *dev, pm_message_t state); extern int (*platform_pci_set_power_state)(struct pci_dev *dev, pci_power_t state); +extern int pci_user_read_config_byte(struct pci_dev *dev, int where, u8 *val); +extern int pci_user_read_config_word(struct pci_dev *dev, int where, u16 *val); +extern int pci_user_read_config_dword(struct pci_dev *dev, int where, u32 *val); +extern int pci_user_write_config_byte(struct pci_dev *dev, int where, u8 val); +extern int pci_user_write_config_word(struct pci_dev *dev, int where, u16 val); +extern int pci_user_write_config_dword(struct pci_dev *dev, int where, u32 val); + /* PCI /proc functions */ #ifdef CONFIG_PROC_FS extern int pci_proc_attach_device(struct pci_dev *dev); diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c index 393e0cee91a9..467a4ceccf10 100644 --- a/drivers/pci/pcie/portdrv_core.c +++ b/drivers/pci/pcie/portdrv_core.c @@ -11,6 +11,8 @@ #include <linux/kernel.h> #include <linux/errno.h> #include <linux/pm.h> +#include <linux/string.h> +#include <linux/slab.h> #include <linux/pcieport_if.h> #include "portdrv.h" @@ -61,7 +63,7 @@ static int pcie_port_remove_service(struct device *dev) static void pcie_port_shutdown_service(struct device *dev) {} -static int pcie_port_suspend_service(struct device *dev, pm_message_t state, u32 level) +static int pcie_port_suspend_service(struct device *dev, pm_message_t state) { struct pcie_device *pciedev; struct pcie_port_service_driver *driver; @@ -76,7 +78,7 @@ static int pcie_port_suspend_service(struct device *dev, pm_message_t state, u32 return 0; } -static int pcie_port_resume_service(struct device *dev, u32 level) +static int pcie_port_resume_service(struct device *dev) { struct pcie_device *pciedev; struct pcie_port_service_driver *driver; diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c index 3c565ce7f77b..02260141dc81 100644 --- a/drivers/pci/pcie/portdrv_pci.c +++ b/drivers/pci/pcie/portdrv_pci.c @@ -12,6 +12,7 @@ #include <linux/errno.h> #include <linux/pm.h> #include <linux/init.h> +#include <linux/slab.h> #include <linux/pcieport_if.h> #include "portdrv.h" diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 005786416bb5..fce2cb2112d8 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -669,6 +669,7 @@ static void pci_release_dev(struct device *dev) /** * pci_cfg_space_size - get the configuration space size of the PCI device. + * @dev: PCI device * * Regular PCI devices have 256 bytes, but PCI-X 2 and PCI Express devices * have 4096 bytes. Even if the device is capable, that doesn't mean we can diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c index 9613f666c110..9eb465727fce 100644 --- a/drivers/pci/proc.c +++ b/drivers/pci/proc.c @@ -80,7 +80,7 @@ proc_bus_pci_read(struct file *file, char __user *buf, size_t nbytes, loff_t *pp if ((pos & 1) && cnt) { unsigned char val; - pci_read_config_byte(dev, pos, &val); + pci_user_read_config_byte(dev, pos, &val); __put_user(val, buf); buf++; pos++; @@ -89,7 +89,7 @@ proc_bus_pci_read(struct file *file, char __user *buf, size_t nbytes, loff_t *pp if ((pos & 3) && cnt > 2) { unsigned short val; - pci_read_config_word(dev, pos, &val); + pci_user_read_config_word(dev, pos, &val); __put_user(cpu_to_le16(val), (unsigned short __user *) buf); buf += 2; pos += 2; @@ -98,7 +98,7 @@ proc_bus_pci_read(struct file *file, char __user *buf, size_t nbytes, loff_t *pp while (cnt >= 4) { unsigned int val; - pci_read_config_dword(dev, pos, &val); + pci_user_read_config_dword(dev, pos, &val); __put_user(cpu_to_le32(val), (unsigned int __user *) buf); buf += 4; pos += 4; @@ -107,7 +107,7 @@ proc_bus_pci_read(struct file *file, char __user *buf, size_t nbytes, loff_t *pp if (cnt >= 2) { unsigned short val; - pci_read_config_word(dev, pos, &val); + pci_user_read_config_word(dev, pos, &val); __put_user(cpu_to_le16(val), (unsigned short __user *) buf); buf += 2; pos += 2; @@ -116,7 +116,7 @@ proc_bus_pci_read(struct file *file, char __user *buf, size_t nbytes, loff_t *pp if (cnt) { unsigned char val; - pci_read_config_byte(dev, pos, &val); + pci_user_read_config_byte(dev, pos, &val); __put_user(val, buf); buf++; pos++; @@ -151,7 +151,7 @@ proc_bus_pci_write(struct file *file, const char __user *buf, size_t nbytes, lof if ((pos & 1) && cnt) { unsigned char val; __get_user(val, buf); - pci_write_config_byte(dev, pos, val); + pci_user_write_config_byte(dev, pos, val); buf++; pos++; cnt--; @@ -160,7 +160,7 @@ proc_bus_pci_write(struct file *file, const char __user *buf, size_t nbytes, lof if ((pos & 3) && cnt > 2) { unsigned short val; __get_user(val, (unsigned short __user *) buf); - pci_write_config_word(dev, pos, le16_to_cpu(val)); + pci_user_write_config_word(dev, pos, le16_to_cpu(val)); buf += 2; pos += 2; cnt -= 2; @@ -169,7 +169,7 @@ proc_bus_pci_write(struct file *file, const char __user *buf, size_t nbytes, lof while (cnt >= 4) { unsigned int val; __get_user(val, (unsigned int __user *) buf); - pci_write_config_dword(dev, pos, le32_to_cpu(val)); + pci_user_write_config_dword(dev, pos, le32_to_cpu(val)); buf += 4; pos += 4; cnt -= 4; @@ -178,7 +178,7 @@ proc_bus_pci_write(struct file *file, const char __user *buf, size_t nbytes, lof if (cnt >= 2) { unsigned short val; __get_user(val, (unsigned short __user *) buf); - pci_write_config_word(dev, pos, le16_to_cpu(val)); + pci_user_write_config_word(dev, pos, le16_to_cpu(val)); buf += 2; pos += 2; cnt -= 2; @@ -187,7 +187,7 @@ proc_bus_pci_write(struct file *file, const char __user *buf, size_t nbytes, lof if (cnt) { unsigned char val; __get_user(val, buf); - pci_write_config_byte(dev, pos, val); + pci_user_write_config_byte(dev, pos, val); buf++; pos++; cnt--; @@ -484,10 +484,10 @@ static int show_dev_config(struct seq_file *m, void *v) drv = pci_dev_driver(dev); - pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); - pci_read_config_byte (dev, PCI_LATENCY_TIMER, &latency); - pci_read_config_byte (dev, PCI_MIN_GNT, &min_gnt); - pci_read_config_byte (dev, PCI_MAX_LAT, &max_lat); + pci_user_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); + pci_user_read_config_byte (dev, PCI_LATENCY_TIMER, &latency); + pci_user_read_config_byte (dev, PCI_MIN_GNT, &min_gnt); + pci_user_read_config_byte (dev, PCI_MAX_LAT, &max_lat); seq_printf(m, " Bus %2d, device %3d, function %2d:\n", dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); seq_printf(m, " Class %04x", class_rev >> 16); diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 7992bc8cc6a4..5627ce1d2b32 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -7,6 +7,9 @@ * * Copyright (c) 1999 Martin Mares <mj@ucw.cz> * + * Init/reset quirks for USB host controllers should be in the + * USB quirks file, where their drivers can access reuse it. + * * The bridge optimization stuff has been removed. If you really * have a silly BIOS which is unable to set your host bridge right, * use the PowerTweak utility (see http://powertweak.sourceforge.net). @@ -353,7 +356,7 @@ static void piix4_mem_quirk(struct pci_dev *dev, const char *name, unsigned int /* * PIIX4 ACPI: Two IO regions pointed to by longwords at * 0x40 (64 bytes of ACPI registers) - * 0x90 (32 bytes of SMB registers) + * 0x90 (16 bytes of SMB registers) * and a few strange programmable PIIX4 device resources. */ static void __devinit quirk_piix4_acpi(struct pci_dev *dev) @@ -363,7 +366,7 @@ static void __devinit quirk_piix4_acpi(struct pci_dev *dev) pci_read_config_dword(dev, 0x40, ®ion); quirk_io_region(dev, region, 64, PCI_BRIDGE_RESOURCES, "PIIX4 ACPI"); pci_read_config_dword(dev, 0x90, ®ion); - quirk_io_region(dev, region, 32, PCI_BRIDGE_RESOURCES+1, "PIIX4 SMB"); + quirk_io_region(dev, region, 16, PCI_BRIDGE_RESOURCES+1, "PIIX4 SMB"); /* Device resource A has enables for some of the other ones */ pci_read_config_dword(dev, 0x5c, &res_a); @@ -414,6 +417,18 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, quirk_ich4_lpc_acpi ); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_1, quirk_ich4_lpc_acpi ); +static void __devinit quirk_ich6_lpc_acpi(struct pci_dev *dev) +{ + u32 region; + + pci_read_config_dword(dev, 0x40, ®ion); + quirk_io_region(dev, region, 128, PCI_BRIDGE_RESOURCES, "ICH6 ACPI/GPIO/TCO"); + + pci_read_config_dword(dev, 0x48, ®ion); + quirk_io_region(dev, region, 64, PCI_BRIDGE_RESOURCES+1, "ICH6 GPIO"); +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, quirk_ich6_lpc_acpi ); + /* * VIA ACPI: One IO region pointed to by longword at * 0x48 or 0x20 (256 bytes of ACPI registers) @@ -633,28 +648,6 @@ static void quirk_via_irq(struct pci_dev *dev) DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_ANY_ID, quirk_via_irq); /* - * PIIX3 USB: We have to disable USB interrupts that are - * hardwired to PIRQD# and may be shared with an - * external device. - * - * Legacy Support Register (LEGSUP): - * bit13: USB PIRQ Enable (USBPIRQDEN), - * bit4: Trap/SMI On IRQ Enable (USBSMIEN). - * - * We mask out all r/wc bits, too. - */ -static void __devinit quirk_piix3_usb(struct pci_dev *dev) -{ - u16 legsup; - - pci_read_config_word(dev, 0xc0, &legsup); - legsup &= 0x50ef; - pci_write_config_word(dev, 0xc0, legsup); -} -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_2, quirk_piix3_usb ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_2, quirk_piix3_usb ); - -/* * VIA VT82C598 has its device ID settable and many BIOSes * set it to the ID of VT82C597 for backward compatibility. * We need to switch it off to be able to recognize the real @@ -922,6 +915,12 @@ static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev) case 0x186a: /* M6Ne notebook */ asus_hides_smbus = 1; } + if (dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB) { + switch (dev->subsystem_device) { + case 0x1882: /* M6V notebook */ + asus_hides_smbus = 1; + } + } } else if (unlikely(dev->subsystem_vendor == PCI_VENDOR_ID_HP)) { if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB) switch(dev->subsystem_device) { @@ -932,6 +931,7 @@ static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev) if (dev->device == PCI_DEVICE_ID_INTEL_82865_HB) switch (dev->subsystem_device) { case 0x12bc: /* HP D330L */ + case 0x12bd: /* HP D530 */ asus_hides_smbus = 1; } } else if (unlikely(dev->subsystem_vendor == PCI_VENDOR_ID_TOSHIBA)) { @@ -966,6 +966,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82865_HB, asus DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_7205_0, asus_hides_smbus_hostbridge ); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82855PM_HB, asus_hides_smbus_hostbridge ); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82855GM_HB, asus_hides_smbus_hostbridge ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82915GM_HB, asus_hides_smbus_hostbridge ); static void __init asus_hides_smbus_lpc(struct pci_dev *dev) { @@ -990,6 +991,23 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, as DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, asus_hides_smbus_lpc ); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, asus_hides_smbus_lpc ); +static void __init asus_hides_smbus_lpc_ich6(struct pci_dev *dev) +{ + u32 val, rcba; + void __iomem *base; + + if (likely(!asus_hides_smbus)) + return; + pci_read_config_dword(dev, 0xF0, &rcba); + base = ioremap_nocache(rcba & 0xFFFFC000, 0x4000); /* use bits 31:14, 16 kB aligned */ + if (base == NULL) return; + val=readl(base + 0x3418); /* read the Function Disable register, dword mode only */ + writel(val & 0xFFFFFFF7, base + 0x3418); /* enable the SMBus device */ + iounmap(base); + printk(KERN_INFO "PCI: Enabled ICH6/i801 SMBus device\n"); +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, asus_hides_smbus_lpc_ich6 ); + /* * SiS 96x south bridge: BIOS typically hides SMBus device... */ @@ -1002,234 +1020,6 @@ static void __init quirk_sis_96x_smbus(struct pci_dev *dev) pci_read_config_byte(dev, 0x77, &val); } - -#define UHCI_USBLEGSUP 0xc0 /* legacy support */ -#define UHCI_USBCMD 0 /* command register */ -#define UHCI_USBSTS 2 /* status register */ -#define UHCI_USBINTR 4 /* interrupt register */ -#define UHCI_USBLEGSUP_DEFAULT 0x2000 /* only PIRQ enable set */ -#define UHCI_USBCMD_RUN (1 << 0) /* RUN/STOP bit */ -#define UHCI_USBCMD_GRESET (1 << 2) /* Global reset */ -#define UHCI_USBCMD_CONFIGURE (1 << 6) /* config semaphore */ -#define UHCI_USBSTS_HALTED (1 << 5) /* HCHalted bit */ - -#define OHCI_CONTROL 0x04 -#define OHCI_CMDSTATUS 0x08 -#define OHCI_INTRSTATUS 0x0c -#define OHCI_INTRENABLE 0x10 -#define OHCI_INTRDISABLE 0x14 -#define OHCI_OCR (1 << 3) /* ownership change request */ -#define OHCI_CTRL_IR (1 << 8) /* interrupt routing */ -#define OHCI_INTR_OC (1 << 30) /* ownership change */ - -#define EHCI_HCC_PARAMS 0x08 /* extended capabilities */ -#define EHCI_USBCMD 0 /* command register */ -#define EHCI_USBCMD_RUN (1 << 0) /* RUN/STOP bit */ -#define EHCI_USBSTS 4 /* status register */ -#define EHCI_USBSTS_HALTED (1 << 12) /* HCHalted bit */ -#define EHCI_USBINTR 8 /* interrupt register */ -#define EHCI_USBLEGSUP 0 /* legacy support register */ -#define EHCI_USBLEGSUP_BIOS (1 << 16) /* BIOS semaphore */ -#define EHCI_USBLEGSUP_OS (1 << 24) /* OS semaphore */ -#define EHCI_USBLEGCTLSTS 4 /* legacy control/status */ -#define EHCI_USBLEGCTLSTS_SOOE (1 << 13) /* SMI on ownership change */ - -int usb_early_handoff __devinitdata = 0; -static int __init usb_handoff_early(char *str) -{ - usb_early_handoff = 1; - return 0; -} -__setup("usb-handoff", usb_handoff_early); - -static void __devinit quirk_usb_handoff_uhci(struct pci_dev *pdev) -{ - unsigned long base = 0; - int wait_time, delta; - u16 val, sts; - int i; - - for (i = 0; i < PCI_ROM_RESOURCE; i++) - if ((pci_resource_flags(pdev, i) & IORESOURCE_IO)) { - base = pci_resource_start(pdev, i); - break; - } - - if (!base) - return; - - /* - * stop controller - */ - sts = inw(base + UHCI_USBSTS); - val = inw(base + UHCI_USBCMD); - val &= ~(u16)(UHCI_USBCMD_RUN | UHCI_USBCMD_CONFIGURE); - outw(val, base + UHCI_USBCMD); - - /* - * wait while it stops if it was running - */ - if ((sts & UHCI_USBSTS_HALTED) == 0) - { - wait_time = 1000; - delta = 100; - - do { - outw(0x1f, base + UHCI_USBSTS); - udelay(delta); - wait_time -= delta; - val = inw(base + UHCI_USBSTS); - if (val & UHCI_USBSTS_HALTED) - break; - } while (wait_time > 0); - } - - /* - * disable interrupts & legacy support - */ - outw(0, base + UHCI_USBINTR); - outw(0x1f, base + UHCI_USBSTS); - pci_read_config_word(pdev, UHCI_USBLEGSUP, &val); - if (val & 0xbf) - pci_write_config_word(pdev, UHCI_USBLEGSUP, UHCI_USBLEGSUP_DEFAULT); - -} - -static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev) -{ - void __iomem *base; - int wait_time; - - base = ioremap_nocache(pci_resource_start(pdev, 0), - pci_resource_len(pdev, 0)); - if (base == NULL) return; - - if (readl(base + OHCI_CONTROL) & OHCI_CTRL_IR) { - wait_time = 500; /* 0.5 seconds */ - writel(OHCI_INTR_OC, base + OHCI_INTRENABLE); - writel(OHCI_OCR, base + OHCI_CMDSTATUS); - while (wait_time > 0 && - readl(base + OHCI_CONTROL) & OHCI_CTRL_IR) { - wait_time -= 10; - msleep(10); - } - } - - /* - * disable interrupts - */ - writel(~(u32)0, base + OHCI_INTRDISABLE); - writel(~(u32)0, base + OHCI_INTRSTATUS); - - iounmap(base); -} - -static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev) -{ - int wait_time, delta; - void __iomem *base, *op_reg_base; - u32 hcc_params, val, temp; - u8 cap_length; - - base = ioremap_nocache(pci_resource_start(pdev, 0), - pci_resource_len(pdev, 0)); - if (base == NULL) return; - - cap_length = readb(base); - op_reg_base = base + cap_length; - hcc_params = readl(base + EHCI_HCC_PARAMS); - hcc_params = (hcc_params >> 8) & 0xff; - if (hcc_params) { - pci_read_config_dword(pdev, - hcc_params + EHCI_USBLEGSUP, - &val); - if (((val & 0xff) == 1) && (val & EHCI_USBLEGSUP_BIOS)) { - /* - * Ok, BIOS is in smm mode, try to hand off... - */ - pci_read_config_dword(pdev, - hcc_params + EHCI_USBLEGCTLSTS, - &temp); - pci_write_config_dword(pdev, - hcc_params + EHCI_USBLEGCTLSTS, - temp | EHCI_USBLEGCTLSTS_SOOE); - val |= EHCI_USBLEGSUP_OS; - pci_write_config_dword(pdev, - hcc_params + EHCI_USBLEGSUP, - val); - - wait_time = 500; - do { - msleep(10); - wait_time -= 10; - pci_read_config_dword(pdev, - hcc_params + EHCI_USBLEGSUP, - &val); - } while (wait_time && (val & EHCI_USBLEGSUP_BIOS)); - if (!wait_time) { - /* - * well, possibly buggy BIOS... - */ - printk(KERN_WARNING "EHCI early BIOS handoff " - "failed (BIOS bug ?)\n"); - pci_write_config_dword(pdev, - hcc_params + EHCI_USBLEGSUP, - EHCI_USBLEGSUP_OS); - pci_write_config_dword(pdev, - hcc_params + EHCI_USBLEGCTLSTS, - 0); - } - } - } - - /* - * halt EHCI & disable its interrupts in any case - */ - val = readl(op_reg_base + EHCI_USBSTS); - if ((val & EHCI_USBSTS_HALTED) == 0) { - val = readl(op_reg_base + EHCI_USBCMD); - val &= ~EHCI_USBCMD_RUN; - writel(val, op_reg_base + EHCI_USBCMD); - - wait_time = 2000; - delta = 100; - do { - writel(0x3f, op_reg_base + EHCI_USBSTS); - udelay(delta); - wait_time -= delta; - val = readl(op_reg_base + EHCI_USBSTS); - if ((val == ~(u32)0) || (val & EHCI_USBSTS_HALTED)) { - break; - } - } while (wait_time > 0); - } - writel(0, op_reg_base + EHCI_USBINTR); - writel(0x3f, op_reg_base + EHCI_USBSTS); - - iounmap(base); - - return; -} - - - -static void __devinit quirk_usb_early_handoff(struct pci_dev *pdev) -{ - if (!usb_early_handoff) - return; - - if (pdev->class == ((PCI_CLASS_SERIAL_USB << 8) | 0x00)) { /* UHCI */ - quirk_usb_handoff_uhci(pdev); - } else if (pdev->class == ((PCI_CLASS_SERIAL_USB << 8) | 0x10)) { /* OHCI */ - quirk_usb_handoff_ohci(pdev); - } else if (pdev->class == ((PCI_CLASS_SERIAL_USB << 8) | 0x20)) { /* EHCI */ - quirk_usb_disable_ehci(pdev); - } - - return; -} -DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, quirk_usb_early_handoff); - /* * ... This is further complicated by the fact that some SiS96x south * bridges pretend to be 85C503/5513 instead. In that case see if we diff --git a/drivers/pci/rom.c b/drivers/pci/rom.c index 49bd21702314..598a115cd00e 100644 --- a/drivers/pci/rom.c +++ b/drivers/pci/rom.c @@ -9,6 +9,7 @@ #include <linux/config.h> #include <linux/kernel.h> #include <linux/pci.h> +#include <linux/slab.h> #include "pci.h" diff --git a/drivers/pci/syscall.c b/drivers/pci/syscall.c index c071790cc983..87fafc08cb9d 100644 --- a/drivers/pci/syscall.c +++ b/drivers/pci/syscall.c @@ -13,7 +13,7 @@ #include <linux/smp_lock.h> #include <linux/syscalls.h> #include <asm/uaccess.h> - +#include "pci.h" asmlinkage long sys_pciconfig_read(unsigned long bus, unsigned long dfn, @@ -38,13 +38,13 @@ sys_pciconfig_read(unsigned long bus, unsigned long dfn, lock_kernel(); switch (len) { case 1: - cfg_ret = pci_read_config_byte(dev, off, &byte); + cfg_ret = pci_user_read_config_byte(dev, off, &byte); break; case 2: - cfg_ret = pci_read_config_word(dev, off, &word); + cfg_ret = pci_user_read_config_word(dev, off, &word); break; case 4: - cfg_ret = pci_read_config_dword(dev, off, &dword); + cfg_ret = pci_user_read_config_dword(dev, off, &dword); break; default: err = -EINVAL; @@ -112,7 +112,7 @@ sys_pciconfig_write(unsigned long bus, unsigned long dfn, err = get_user(byte, (u8 __user *)buf); if (err) break; - err = pci_write_config_byte(dev, off, byte); + err = pci_user_write_config_byte(dev, off, byte); if (err != PCIBIOS_SUCCESSFUL) err = -EIO; break; @@ -121,7 +121,7 @@ sys_pciconfig_write(unsigned long bus, unsigned long dfn, err = get_user(word, (u16 __user *)buf); if (err) break; - err = pci_write_config_word(dev, off, word); + err = pci_user_write_config_word(dev, off, word); if (err != PCIBIOS_SUCCESSFUL) err = -EIO; break; @@ -130,7 +130,7 @@ sys_pciconfig_write(unsigned long bus, unsigned long dfn, err = get_user(dword, (u32 __user *)buf); if (err) break; - err = pci_write_config_dword(dev, off, dword); + err = pci_user_write_config_dword(dev, off, dword); if (err != PCIBIOS_SUCCESSFUL) err = -EIO; break; diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile index cb4861d9cb80..fe37541abbfe 100644 --- a/drivers/pcmcia/Makefile +++ b/drivers/pcmcia/Makefile @@ -43,9 +43,11 @@ pxa2xx_core-y += soc_common.o pxa2xx_base.o au1x00_ss-y += au1000_generic.o au1x00_ss-$(CONFIG_MIPS_PB1000) += au1000_pb1x00.o au1x00_ss-$(CONFIG_MIPS_PB1100) += au1000_pb1x00.o +au1x00_ss-$(CONFIG_MIPS_PB1200) += au1000_db1x00.o au1x00_ss-$(CONFIG_MIPS_PB1500) += au1000_pb1x00.o au1x00_ss-$(CONFIG_MIPS_DB1000) += au1000_db1x00.o au1x00_ss-$(CONFIG_MIPS_DB1100) += au1000_db1x00.o +au1x00_ss-$(CONFIG_MIPS_DB1200) += au1000_db1x00.o au1x00_ss-$(CONFIG_MIPS_DB1500) += au1000_db1x00.o au1x00_ss-$(CONFIG_MIPS_DB1550) += au1000_db1x00.o au1x00_ss-$(CONFIG_MIPS_XXS1500) += au1000_xxs1500.o @@ -58,6 +60,7 @@ sa1111_cs-$(CONFIG_SA1100_JORNADA720) += sa1100_jornada720.o sa1100_cs-y += sa1100_generic.o sa1100_cs-$(CONFIG_SA1100_ASSABET) += sa1100_assabet.o sa1100_cs-$(CONFIG_SA1100_CERF) += sa1100_cerf.o +sa1100_cs-$(CONFIG_SA1100_COLLIE) += pxa2xx_sharpsl.o sa1100_cs-$(CONFIG_SA1100_H3600) += sa1100_h3600.o sa1100_cs-$(CONFIG_SA1100_SHANNON) += sa1100_shannon.o sa1100_cs-$(CONFIG_SA1100_SIMPAD) += sa1100_simpad.o diff --git a/drivers/pcmcia/au1000_db1x00.c b/drivers/pcmcia/au1000_db1x00.c index 42cf8bfbcc98..24cfee1a412c 100644 --- a/drivers/pcmcia/au1000_db1x00.c +++ b/drivers/pcmcia/au1000_db1x00.c @@ -40,7 +40,15 @@ #include <asm/irq.h> #include <asm/signal.h> #include <asm/mach-au1x00/au1000.h> -#include <asm/mach-db1x00/db1x00.h> + +#if defined(CONFIG_MIPS_DB1200) + #include <db1200.h> +#elif defined(CONFIG_MIPS_PB1200) + #include <pb1200.h> +#else + #include <asm/mach-db1x00/db1x00.h> + static BCSR * const bcsr = (BCSR *)BCSR_KSEG1_ADDR; +#endif #include "au1000_generic.h" @@ -50,7 +58,6 @@ #define debug(x,args...) #endif -static BCSR * const bcsr = (BCSR *)BCSR_KSEG1_ADDR; struct au1000_pcmcia_socket au1000_pcmcia_socket[PCMCIA_NUM_SOCKS]; extern int au1x00_pcmcia_socket_probe(struct device *, struct pcmcia_low_level *, int, int); @@ -59,6 +66,8 @@ static int db1x00_pcmcia_hw_init(struct au1000_pcmcia_socket *skt) { #ifdef CONFIG_MIPS_DB1550 skt->irq = skt->nr ? AU1000_GPIO_5 : AU1000_GPIO_3; +#elif defined(CONFIG_MIPS_DB1200) || defined(CONFIG_MIPS_PB1200) + skt->irq = skt->nr ? BOARD_PC1_INT : BOARD_PC0_INT; #else skt->irq = skt->nr ? AU1000_GPIO_5 : AU1000_GPIO_2; #endif @@ -85,11 +94,19 @@ db1x00_pcmcia_socket_state(struct au1000_pcmcia_socket *skt, struct pcmcia_state switch (skt->nr) { case 0: vs = bcsr->status & 0x3; +#if defined(CONFIG_MIPS_DB1200) || defined(CONFIG_MIPS_PB1200) + inserted = BOARD_CARD_INSERTED(0); +#else inserted = !(bcsr->status & (1<<4)); +#endif break; case 1: vs = (bcsr->status & 0xC)>>2; +#if defined(CONFIG_MIPS_DB1200) || defined(CONFIG_MIPS_PB1200) + inserted = BOARD_CARD_INSERTED(1); +#else inserted = !(bcsr->status & (1<<5)); +#endif break; default:/* should never happen */ return; diff --git a/drivers/pcmcia/au1000_generic.c b/drivers/pcmcia/au1000_generic.c index 470ef756252e..ba48cef3a9dc 100644 --- a/drivers/pcmcia/au1000_generic.c +++ b/drivers/pcmcia/au1000_generic.c @@ -490,7 +490,7 @@ int au1x00_drv_pcmcia_remove(struct device *dev) flush_scheduled_work(); skt->ops->hw_shutdown(skt); au1x00_pcmcia_config_skt(skt, &dead_socket); - iounmap(skt->virt_io); + iounmap(skt->virt_io + (u32)mips_io_port_base); skt->virt_io = NULL; } @@ -519,36 +519,15 @@ static int au1x00_drv_pcmcia_probe(struct device *dev) } -static int au1x00_drv_pcmcia_suspend(struct device *dev, pm_message_t state, u32 level) -{ - int ret = 0; - if (level == SUSPEND_SAVE_STATE) - ret = pcmcia_socket_dev_suspend(dev, state); - return ret; -} - -static int au1x00_drv_pcmcia_resume(struct device *dev, u32 level) -{ - int ret = 0; - if (level == RESUME_RESTORE_STATE) - ret = pcmcia_socket_dev_resume(dev); - return ret; -} - - static struct device_driver au1x00_pcmcia_driver = { .probe = au1x00_drv_pcmcia_probe, .remove = au1x00_drv_pcmcia_remove, .name = "au1x00-pcmcia", .bus = &platform_bus_type, - .suspend = au1x00_drv_pcmcia_suspend, - .resume = au1x00_drv_pcmcia_resume + .suspend = pcmcia_socket_dev_suspend, + .resume = pcmcia_socket_dev_resume, }; -static struct platform_device au1x00_device = { - .name = "au1x00-pcmcia", - .id = 0, -}; /* au1x00_pcmcia_init() * @@ -562,7 +541,6 @@ static int __init au1x00_pcmcia_init(void) int error = 0; if ((error = driver_register(&au1x00_pcmcia_driver))) return error; - platform_device_register(&au1x00_device); return error; } @@ -573,7 +551,6 @@ static int __init au1x00_pcmcia_init(void) static void __exit au1x00_pcmcia_exit(void) { driver_unregister(&au1x00_pcmcia_driver); - platform_device_unregister(&au1x00_device); } module_init(au1x00_pcmcia_init); diff --git a/drivers/pcmcia/au1000_generic.h b/drivers/pcmcia/au1000_generic.h index d5122b1ea94b..b0e7908392a7 100644 --- a/drivers/pcmcia/au1000_generic.h +++ b/drivers/pcmcia/au1000_generic.h @@ -44,13 +44,13 @@ /* pcmcia socket 1 needs external glue logic so the memory map * differs from board to board. */ -#if defined(CONFIG_MIPS_PB1000) || defined(CONFIG_MIPS_PB1100) || defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1550) +#if defined(CONFIG_MIPS_PB1000) || defined(CONFIG_MIPS_PB1100) || defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1550) || defined(CONFIG_MIPS_PB1200) #define AU1X_SOCK1_IO 0xF08000000 #define AU1X_SOCK1_PHYS_ATTR 0xF48000000 #define AU1X_SOCK1_PHYS_MEM 0xF88000000 #define AU1X_SOCK1_PSEUDO_PHYS_ATTR 0xF4800000 #define AU1X_SOCK1_PSEUDO_PHYS_MEM 0xF8800000 -#elif defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100) || defined(CONFIG_MIPS_DB1500) || defined(CONFIG_MIPS_DB1550) +#elif defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100) || defined(CONFIG_MIPS_DB1500) || defined(CONFIG_MIPS_DB1550) || defined(CONFIG_MIPS_DB1200) #define AU1X_SOCK1_IO 0xF04000000 #define AU1X_SOCK1_PHYS_ATTR 0xF44000000 #define AU1X_SOCK1_PHYS_MEM 0xF84000000 diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index 080608c7381a..39d096b52926 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -1157,7 +1157,8 @@ static struct pcmcia_callback pcmcia_bus_callback = { .requery = pcmcia_bus_rescan, }; -static int __devinit pcmcia_bus_add_socket(struct class_device *class_dev) +static int __devinit pcmcia_bus_add_socket(struct class_device *class_dev, + struct class_interface *class_intf) { struct pcmcia_socket *socket = class_get_devdata(class_dev); int ret; @@ -1192,7 +1193,8 @@ static int __devinit pcmcia_bus_add_socket(struct class_device *class_dev) return 0; } -static void pcmcia_bus_remove_socket(struct class_device *class_dev) +static void pcmcia_bus_remove_socket(struct class_device *class_dev, + struct class_interface *class_intf) { struct pcmcia_socket *socket = class_get_devdata(class_dev); diff --git a/drivers/pcmcia/hd64465_ss.c b/drivers/pcmcia/hd64465_ss.c index 316f8bcc878b..b57a0b98b4d6 100644 --- a/drivers/pcmcia/hd64465_ss.c +++ b/drivers/pcmcia/hd64465_ss.c @@ -844,27 +844,11 @@ static void hs_exit_socket(hs_socket_t *sp) local_irq_restore(flags); } -static int hd64465_suspend(struct device *dev, pm_message_t state, u32 level) -{ - int ret = 0; - if (level == SUSPEND_SAVE_STATE) - ret = pcmcia_socket_dev_suspend(dev, state); - return ret; -} - -static int hd64465_resume(struct device *dev, u32 level) -{ - int ret = 0; - if (level == RESUME_RESTORE_STATE) - ret = pcmcia_socket_dev_resume(dev); - return ret; -} - static struct device_driver hd64465_driver = { .name = "hd64465-pcmcia", .bus = &platform_bus_type, - .suspend = hd64465_suspend, - .resume = hd64465_resume, + .suspend = pcmcia_socket_dev_suspend, + .resume = pcmcia_socket_dev_resume, }; static struct platform_device hd64465_device = { diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c index a713015e8228..4a41f67d185d 100644 --- a/drivers/pcmcia/i82365.c +++ b/drivers/pcmcia/i82365.c @@ -1332,27 +1332,11 @@ static struct pccard_operations pcic_operations = { /*====================================================================*/ -static int i82365_suspend(struct device *dev, pm_message_t state, u32 level) -{ - int ret = 0; - if (level == SUSPEND_SAVE_STATE) - ret = pcmcia_socket_dev_suspend(dev, state); - return ret; -} - -static int i82365_resume(struct device *dev, u32 level) -{ - int ret = 0; - if (level == RESUME_RESTORE_STATE) - ret = pcmcia_socket_dev_resume(dev); - return ret; -} - static struct device_driver i82365_driver = { .name = "i82365", .bus = &platform_bus_type, - .suspend = i82365_suspend, - .resume = i82365_resume, + .suspend = pcmcia_socket_dev_suspend, + .resume = pcmcia_socket_dev_resume, }; static struct platform_device i82365_device = { diff --git a/drivers/pcmcia/m32r_cfc.c b/drivers/pcmcia/m32r_cfc.c index 65f3ee3d4d3c..c6ed70ea4812 100644 --- a/drivers/pcmcia/m32r_cfc.c +++ b/drivers/pcmcia/m32r_cfc.c @@ -731,28 +731,11 @@ static struct pccard_operations pcc_operations = { /*====================================================================*/ -static int m32r_pcc_suspend(struct device *dev, pm_message_t state, u32 level) -{ - int ret = 0; - if (level == SUSPEND_SAVE_STATE) - ret = pcmcia_socket_dev_suspend(dev, state); - return ret; -} - -static int m32r_pcc_resume(struct device *dev, u32 level) -{ - int ret = 0; - if (level == RESUME_RESTORE_STATE) - ret = pcmcia_socket_dev_resume(dev); - return ret; -} - - static struct device_driver pcc_driver = { .name = "cfc", .bus = &platform_bus_type, - .suspend = m32r_pcc_suspend, - .resume = m32r_pcc_resume, + .suspend = pcmcia_socket_dev_suspend, + .resume = pcmcia_socket_dev_resume, }; static struct platform_device pcc_device = { diff --git a/drivers/pcmcia/m32r_pcc.c b/drivers/pcmcia/m32r_pcc.c index 7b14d7efd68c..3397ff28de6a 100644 --- a/drivers/pcmcia/m32r_pcc.c +++ b/drivers/pcmcia/m32r_pcc.c @@ -695,28 +695,11 @@ static struct pccard_operations pcc_operations = { /*====================================================================*/ -static int m32r_pcc_suspend(struct device *dev, pm_message_t state, u32 level) -{ - int ret = 0; - if (level == SUSPEND_SAVE_STATE) - ret = pcmcia_socket_dev_suspend(dev, state); - return ret; -} - -static int m32r_pcc_resume(struct device *dev, u32 level) -{ - int ret = 0; - if (level == RESUME_RESTORE_STATE) - ret = pcmcia_socket_dev_resume(dev); - return ret; -} - - static struct device_driver pcc_driver = { .name = "pcc", .bus = &platform_bus_type, - .suspend = m32r_pcc_suspend, - .resume = m32r_pcc_resume, + .suspend = pcmcia_socket_dev_suspend, + .resume = pcmcia_socket_dev_resume, }; static struct platform_device pcc_device = { diff --git a/drivers/pcmcia/omap_cf.c b/drivers/pcmcia/omap_cf.c index 94be9e51654e..2558c3cc91ec 100644 --- a/drivers/pcmcia/omap_cf.c +++ b/drivers/pcmcia/omap_cf.c @@ -329,27 +329,13 @@ static int __devexit omap_cf_remove(struct device *dev) return 0; } -static int omap_cf_suspend(struct device *dev, pm_message_t mesg, u32 level) -{ - if (level != SUSPEND_SAVE_STATE) - return 0; - return pcmcia_socket_dev_suspend(dev, mesg); -} - -static int omap_cf_resume(struct device *dev, u32 level) -{ - if (level != RESUME_RESTORE_STATE) - return 0; - return pcmcia_socket_dev_resume(dev); -} - static struct device_driver omap_cf_driver = { .name = (char *) driver_name, .bus = &platform_bus_type, .probe = omap_cf_probe, .remove = __devexit_p(omap_cf_remove), - .suspend = omap_cf_suspend, - .resume = omap_cf_resume, + .suspend = pcmcia_socket_dev_suspend, + .resume = pcmcia_socket_dev_resume, }; static int __init omap_cf_init(void) diff --git a/drivers/pcmcia/pxa2xx_base.c b/drivers/pcmcia/pxa2xx_base.c index 325c992f7d8f..c2a12d53f6c7 100644 --- a/drivers/pcmcia/pxa2xx_base.c +++ b/drivers/pcmcia/pxa2xx_base.c @@ -205,32 +205,20 @@ int pxa2xx_drv_pcmcia_probe(struct device *dev) } EXPORT_SYMBOL(pxa2xx_drv_pcmcia_probe); -static int pxa2xx_drv_pcmcia_suspend(struct device *dev, pm_message_t state, u32 level) +static int pxa2xx_drv_pcmcia_resume(struct device *dev) { - int ret = 0; - if (level == SUSPEND_SAVE_STATE) - ret = pcmcia_socket_dev_suspend(dev, state); - return ret; -} + struct pcmcia_low_level *ops = dev->platform_data; + int nr = ops ? ops->nr : 0; -static int pxa2xx_drv_pcmcia_resume(struct device *dev, u32 level) -{ - int ret = 0; - if (level == RESUME_RESTORE_STATE) - { - struct pcmcia_low_level *ops = dev->platform_data; - int nr = ops ? ops->nr : 0; - - MECR = nr > 1 ? MECR_CIT | MECR_NOS : (nr > 0 ? MECR_CIT : 0); - ret = pcmcia_socket_dev_resume(dev); - } - return ret; + MECR = nr > 1 ? MECR_CIT | MECR_NOS : (nr > 0 ? MECR_CIT : 0); + + return pcmcia_socket_dev_resume(dev); } static struct device_driver pxa2xx_pcmcia_driver = { .probe = pxa2xx_drv_pcmcia_probe, .remove = soc_common_drv_pcmcia_remove, - .suspend = pxa2xx_drv_pcmcia_suspend, + .suspend = pcmcia_socket_dev_suspend, .resume = pxa2xx_drv_pcmcia_resume, .name = "pxa2xx-pcmcia", .bus = &platform_bus_type, diff --git a/drivers/pcmcia/pxa2xx_sharpsl.c b/drivers/pcmcia/pxa2xx_sharpsl.c index a1178a600e3c..bd924336a49f 100644 --- a/drivers/pcmcia/pxa2xx_sharpsl.c +++ b/drivers/pcmcia/pxa2xx_sharpsl.c @@ -18,10 +18,15 @@ #include <linux/interrupt.h> #include <linux/device.h> +#include <asm/mach-types.h> #include <asm/hardware.h> #include <asm/irq.h> #include <asm/hardware/scoop.h> -#include <asm/arch/pxa-regs.h> +#ifdef CONFIG_SA1100_COLLIE +#include <asm/arch-sa1100/collie.h> +#else +#include <asm/arch-pxa/pxa-regs.h> +#endif #include "soc_common.h" @@ -38,6 +43,7 @@ static int sharpsl_pcmcia_hw_init(struct soc_pcmcia_socket *skt) { int ret; +#ifndef CONFIG_SA1100_COLLIE /* * Setup default state of GPIO outputs * before we enable them as outputs. @@ -60,6 +66,7 @@ static int sharpsl_pcmcia_hw_init(struct soc_pcmcia_socket *skt) pxa_gpio_mode(GPIO55_nPREG_MD); pxa_gpio_mode(GPIO56_nPWAIT_MD); pxa_gpio_mode(GPIO57_nIOIS16_MD); +#endif /* Register interrupts */ if (scoop_devs[skt->nr].cd_irq >= 0) { @@ -213,12 +220,20 @@ static void sharpsl_pcmcia_socket_init(struct soc_pcmcia_socket *skt) write_scoop_reg(scoop_devs[skt->nr].dev, SCOOP_IMR, 0x00C0); write_scoop_reg(scoop_devs[skt->nr].dev, SCOOP_MCR, 0x0101); scoop_devs[skt->nr].keep_vs = NO_KEEP_VS; + + if (machine_is_collie()) + /* We need to disable SS_OUTPUT_ENA here. */ + write_scoop_reg(scoop_devs[skt->nr].dev, SCOOP_CPR, read_scoop_reg(scoop_devs[skt->nr].dev, SCOOP_CPR) & ~0x0080); } static void sharpsl_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt) { /* CF_BUS_OFF */ sharpsl_pcmcia_init_reset(&scoop_devs[skt->nr]); + + if (machine_is_collie()) + /* We need to disable SS_OUTPUT_ENA here. */ + write_scoop_reg(scoop_devs[skt->nr].dev, SCOOP_CPR, read_scoop_reg(scoop_devs[skt->nr].dev, SCOOP_CPR) & ~0x0080); } static struct pcmcia_low_level sharpsl_pcmcia_ops = { @@ -235,6 +250,19 @@ static struct pcmcia_low_level sharpsl_pcmcia_ops = { static struct platform_device *sharpsl_pcmcia_device; +#ifdef CONFIG_SA1100_COLLIE +int __init pcmcia_collie_init(struct device *dev) +{ + int ret = -ENODEV; + + if (machine_is_collie()) + ret = sa11xx_drv_pcmcia_probe(dev, &sharpsl_pcmcia_ops, 0, 1); + + return ret; +} + +#else + static int __init sharpsl_pcmcia_init(void) { int ret; @@ -269,6 +297,7 @@ static void __exit sharpsl_pcmcia_exit(void) fs_initcall(sharpsl_pcmcia_init); module_exit(sharpsl_pcmcia_exit); +#endif MODULE_DESCRIPTION("Sharp SL Series PCMCIA Support"); MODULE_LICENSE("GPL"); diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c index f9a5c70284b5..00960a379b9c 100644 --- a/drivers/pcmcia/rsrc_nonstatic.c +++ b/drivers/pcmcia/rsrc_nonstatic.c @@ -779,7 +779,7 @@ static int nonstatic_autoadd_resources(struct pcmcia_socket *s) if (!s->cb_dev || !s->cb_dev->bus) return -ENODEV; -#if defined(CONFIG_X86) || defined(CONFIG_X86_64) +#if defined(CONFIG_X86) /* If this is the root bus, the risk of hitting * some strange system devices which aren't protected * by either ACPI resource tables or properly requested @@ -994,7 +994,8 @@ static struct class_device_attribute *pccard_rsrc_attributes[] = { NULL, }; -static int __devinit pccard_sysfs_add_rsrc(struct class_device *class_dev) +static int __devinit pccard_sysfs_add_rsrc(struct class_device *class_dev, + struct class_interface *class_intf) { struct pcmcia_socket *s = class_get_devdata(class_dev); struct class_device_attribute **attr; @@ -1011,7 +1012,8 @@ static int __devinit pccard_sysfs_add_rsrc(struct class_device *class_dev) return ret; } -static void __devexit pccard_sysfs_remove_rsrc(struct class_device *class_dev) +static void __devexit pccard_sysfs_remove_rsrc(struct class_device *class_dev, + struct class_interface *class_intf) { struct pcmcia_socket *s = class_get_devdata(class_dev); struct class_device_attribute **attr; diff --git a/drivers/pcmcia/sa1100_generic.c b/drivers/pcmcia/sa1100_generic.c index d4ed508b38be..acf60ffc8a12 100644 --- a/drivers/pcmcia/sa1100_generic.c +++ b/drivers/pcmcia/sa1100_generic.c @@ -38,8 +38,12 @@ #include <pcmcia/cs.h> #include <pcmcia/ss.h> +#include <asm/hardware/scoop.h> + #include "sa1100_generic.h" +int __init pcmcia_collie_init(struct device *dev); + static int (*sa11x0_pcmcia_hw_init[])(struct device *dev) = { #ifdef CONFIG_SA1100_ASSABET pcmcia_assabet_init, @@ -56,6 +60,9 @@ static int (*sa11x0_pcmcia_hw_init[])(struct device *dev) = { #ifdef CONFIG_SA1100_SIMPAD pcmcia_simpad_init, #endif +#ifdef CONFIG_SA1100_COLLIE + pcmcia_collie_init, +#endif }; static int sa11x0_drv_pcmcia_probe(struct device *dev) @@ -74,29 +81,13 @@ static int sa11x0_drv_pcmcia_probe(struct device *dev) return ret; } -static int sa11x0_drv_pcmcia_suspend(struct device *dev, pm_message_t state, u32 level) -{ - int ret = 0; - if (level == SUSPEND_SAVE_STATE) - ret = pcmcia_socket_dev_suspend(dev, state); - return ret; -} - -static int sa11x0_drv_pcmcia_resume(struct device *dev, u32 level) -{ - int ret = 0; - if (level == RESUME_RESTORE_STATE) - ret = pcmcia_socket_dev_resume(dev); - return ret; -} - static struct device_driver sa11x0_pcmcia_driver = { .probe = sa11x0_drv_pcmcia_probe, .remove = soc_common_drv_pcmcia_remove, .name = "sa11x0-pcmcia", .bus = &platform_bus_type, - .suspend = sa11x0_drv_pcmcia_suspend, - .resume = sa11x0_drv_pcmcia_resume, + .suspend = pcmcia_socket_dev_suspend, + .resume = pcmcia_socket_dev_resume, }; /* sa11x0_pcmcia_init() diff --git a/drivers/pcmcia/sa1111_generic.c b/drivers/pcmcia/sa1111_generic.c index bb90a1448a53..81ded52c8959 100644 --- a/drivers/pcmcia/sa1111_generic.c +++ b/drivers/pcmcia/sa1111_generic.c @@ -122,7 +122,7 @@ void sa1111_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt) static int pcmcia_probe(struct sa1111_dev *dev) { - char *base; + void __iomem *base; if (!request_mem_region(dev->res.start, 512, SA1111_DRIVER_NAME(dev))) diff --git a/drivers/pcmcia/socket_sysfs.c b/drivers/pcmcia/socket_sysfs.c index 1040a6c1a8a4..4a3150a7854c 100644 --- a/drivers/pcmcia/socket_sysfs.c +++ b/drivers/pcmcia/socket_sysfs.c @@ -341,7 +341,8 @@ static struct bin_attribute pccard_cis_attr = { .write = pccard_store_cis, }; -static int __devinit pccard_sysfs_add_socket(struct class_device *class_dev) +static int __devinit pccard_sysfs_add_socket(struct class_device *class_dev, + struct class_interface *class_intf) { struct class_device_attribute **attr; int ret = 0; @@ -357,7 +358,8 @@ static int __devinit pccard_sysfs_add_socket(struct class_device *class_dev) return ret; } -static void __devexit pccard_sysfs_remove_socket(struct class_device *class_dev) +static void __devexit pccard_sysfs_remove_socket(struct class_device *class_dev, + struct class_interface *class_intf) { struct class_device_attribute **attr; diff --git a/drivers/pcmcia/tcic.c b/drivers/pcmcia/tcic.c index d5a61eae6119..f158b67f6610 100644 --- a/drivers/pcmcia/tcic.c +++ b/drivers/pcmcia/tcic.c @@ -372,27 +372,11 @@ static int __init get_tcic_id(void) /*====================================================================*/ -static int tcic_drv_suspend(struct device *dev, pm_message_t state, u32 level) -{ - int ret = 0; - if (level == SUSPEND_SAVE_STATE) - ret = pcmcia_socket_dev_suspend(dev, state); - return ret; -} - -static int tcic_drv_resume(struct device *dev, u32 level) -{ - int ret = 0; - if (level == RESUME_RESTORE_STATE) - ret = pcmcia_socket_dev_resume(dev); - return ret; -} - static struct device_driver tcic_driver = { .name = "tcic-pcmcia", .bus = &platform_bus_type, - .suspend = tcic_drv_suspend, - .resume = tcic_drv_resume, + .suspend = pcmcia_socket_dev_suspend, + .resume = pcmcia_socket_dev_resume, }; static struct platform_device tcic_device = { diff --git a/drivers/pcmcia/vrc4171_card.c b/drivers/pcmcia/vrc4171_card.c index 17bb2da6752b..3d2dca675e02 100644 --- a/drivers/pcmcia/vrc4171_card.c +++ b/drivers/pcmcia/vrc4171_card.c @@ -774,31 +774,11 @@ static int __devinit vrc4171_card_setup(char *options) __setup("vrc4171_card=", vrc4171_card_setup); -static int vrc4171_card_suspend(struct device *dev, pm_message_t state, u32 level) -{ - int retval = 0; - - if (level == SUSPEND_SAVE_STATE) - retval = pcmcia_socket_dev_suspend(dev, state); - - return retval; -} - -static int vrc4171_card_resume(struct device *dev, u32 level) -{ - int retval = 0; - - if (level == RESUME_RESTORE_STATE) - retval = pcmcia_socket_dev_resume(dev); - - return retval; -} - static struct device_driver vrc4171_card_driver = { .name = vrc4171_card_name, .bus = &platform_bus_type, - .suspend = vrc4171_card_suspend, - .resume = vrc4171_card_resume, + .suspend = pcmcia_socket_dev_suspend, + .resume = pcmcia_socket_dev_resume, }; static int __devinit vrc4171_card_init(void) diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c index db9f952f9e3c..ec6ab65f0872 100644 --- a/drivers/pcmcia/yenta_socket.c +++ b/drivers/pcmcia/yenta_socket.c @@ -151,6 +151,40 @@ static void exca_writew(struct yenta_socket *socket, unsigned reg, u16 val) readb(socket->base + 0x800 + reg + 1); } +static ssize_t show_yenta_registers(struct device *yentadev, struct device_attribute *attr, char *buf) +{ + struct pci_dev *dev = to_pci_dev(yentadev); + struct yenta_socket *socket = pci_get_drvdata(dev); + int offset = 0, i; + + offset = snprintf(buf, PAGE_SIZE, "CB registers:"); + for (i = 0; i < 0x24; i += 4) { + unsigned val; + if (!(i & 15)) + offset += snprintf(buf + offset, PAGE_SIZE - offset, "\n%02x:", i); + val = cb_readl(socket, i); + offset += snprintf(buf + offset, PAGE_SIZE - offset, " %08x", val); + } + + offset += snprintf(buf + offset, PAGE_SIZE - offset, "\n\nExCA registers:"); + for (i = 0; i < 0x45; i++) { + unsigned char val; + if (!(i & 7)) { + if (i & 8) { + memcpy(buf + offset, " -", 2); + offset += 2; + } else + offset += snprintf(buf + offset, PAGE_SIZE - offset, "\n%02x:", i); + } + val = exca_readb(socket, i); + offset += snprintf(buf + offset, PAGE_SIZE - offset, " %02x", val); + } + buf[offset++] = '\n'; + return offset; +} + +static DEVICE_ATTR(yenta_registers, S_IRUSR, show_yenta_registers, NULL); + /* * Ugh, mixed-mode cardbus and 16-bit pccard state: things depend * on what kind of card is inserted.. @@ -765,6 +799,9 @@ static void yenta_close(struct pci_dev *dev) { struct yenta_socket *sock = pci_get_drvdata(dev); + /* Remove the register attributes */ + device_remove_file(&dev->dev, &dev_attr_yenta_registers); + /* we don't want a dying socket registered */ pcmcia_unregister_socket(&sock->socket); @@ -1138,8 +1175,11 @@ static int __devinit yenta_probe (struct pci_dev *dev, const struct pci_device_i /* Register it with the pcmcia layer.. */ ret = pcmcia_register_socket(&socket->socket); - if (ret == 0) + if (ret == 0) { + /* Add the yenta register attributes */ + device_create_file(&dev->dev, &dev_attr_yenta_registers); goto out; + } unmap: iounmap(socket->base); diff --git a/drivers/pnp/manager.c b/drivers/pnp/manager.c index 94442ffd4aed..cbb2749db178 100644 --- a/drivers/pnp/manager.c +++ b/drivers/pnp/manager.c @@ -12,6 +12,8 @@ #include <linux/init.h> #include <linux/kernel.h> #include <linux/pnp.h> +#include <linux/slab.h> +#include <linux/bitmap.h> #include "base.h" DECLARE_MUTEX(pnp_res_mutex); diff --git a/drivers/pnp/pnpbios/rsparser.c b/drivers/pnp/pnpbios/rsparser.c index b0ca65b68645..5e38cd7335f7 100644 --- a/drivers/pnp/pnpbios/rsparser.c +++ b/drivers/pnp/pnpbios/rsparser.c @@ -7,6 +7,8 @@ #include <linux/ctype.h> #include <linux/pnp.h> #include <linux/pnpbios.h> +#include <linux/string.h> +#include <linux/slab.h> #ifdef CONFIG_PCI #include <linux/pci.h> diff --git a/drivers/s390/char/con3270.c b/drivers/s390/char/con3270.c index fc7a213e591f..c570a9f6ce9c 100644 --- a/drivers/s390/char/con3270.c +++ b/drivers/s390/char/con3270.c @@ -213,6 +213,9 @@ con3270_update(struct con3270 *cp) struct string *s, *n; int rc; + if (cp->view.dev) + raw3270_activate_view(&cp->view); + wrq = xchg(&cp->write, 0); if (!wrq) { con3270_set_timer(cp, 1); @@ -489,8 +492,6 @@ con3270_write(struct console *co, const char *str, unsigned int count) unsigned char c; cp = condev; - if (cp->view.dev) - raw3270_activate_view(&cp->view); spin_lock_irqsave(&cp->view.lock, flags); while (count-- > 0) { c = *str++; @@ -620,7 +621,7 @@ con3270_init(void) (void (*)(unsigned long)) con3270_read_tasklet, (unsigned long) condev->read); - raw3270_add_view(&condev->view, &con3270_fn, 0); + raw3270_add_view(&condev->view, &con3270_fn, 1); INIT_LIST_HEAD(&condev->freemem); for (i = 0; i < CON3270_STRING_PAGES; i++) { diff --git a/drivers/s390/char/fs3270.c b/drivers/s390/char/fs3270.c index 60afcdcf91c2..735a7fcdeff5 100644 --- a/drivers/s390/char/fs3270.c +++ b/drivers/s390/char/fs3270.c @@ -33,8 +33,11 @@ struct fs3270 { int read_command; /* ccw command to use for reads. */ int write_command; /* ccw command to use for writes. */ int attention; /* Got attention. */ - struct raw3270_request *clear; /* single clear request. */ - wait_queue_head_t attn_wait; /* Attention wait queue. */ + int active; /* Fullscreen view is active. */ + struct raw3270_request *init; /* single init request. */ + wait_queue_head_t wait; /* Init & attention wait queue. */ + struct idal_buffer *rdbuf; /* full-screen-deactivate buffer */ + size_t rdbuf_size; /* size of data returned by RDBUF */ }; static void @@ -43,58 +46,172 @@ fs3270_wake_up(struct raw3270_request *rq, void *data) wake_up((wait_queue_head_t *) data); } +static inline int +fs3270_working(struct fs3270 *fp) +{ + /* + * The fullscreen view is in working order if the view + * has been activated AND the initial request is finished. + */ + return fp->active && raw3270_request_final(fp->init); +} + static int fs3270_do_io(struct raw3270_view *view, struct raw3270_request *rq) { - wait_queue_head_t wq; + struct fs3270 *fp; int rc; - init_waitqueue_head(&wq); + fp = (struct fs3270 *) view; rq->callback = fs3270_wake_up; - rq->callback_data = &wq; - rc = raw3270_start(view, rq); - if (rc) - return rc; - /* Started sucessfully. Now wait for completion. */ - wait_event(wq, raw3270_request_final(rq)); - return rq->rc; + rq->callback_data = &fp->wait; + + do { + if (!fs3270_working(fp)) { + /* Fullscreen view isn't ready yet. */ + rc = wait_event_interruptible(fp->wait, + fs3270_working(fp)); + if (rc != 0) + break; + } + rc = raw3270_start(view, rq); + if (rc == 0) { + /* Started sucessfully. Now wait for completion. */ + wait_event(fp->wait, raw3270_request_final(rq)); + } + } while (rc == -EACCES); + return rc; } +/* + * Switch to the fullscreen view. + */ static void fs3270_reset_callback(struct raw3270_request *rq, void *data) { + struct fs3270 *fp; + + fp = (struct fs3270 *) rq->view; raw3270_request_reset(rq); + wake_up(&fp->wait); +} + +static void +fs3270_restore_callback(struct raw3270_request *rq, void *data) +{ + struct fs3270 *fp; + + fp = (struct fs3270 *) rq->view; + if (rq->rc != 0 || rq->rescnt != 0) { + if (fp->fs_pid) + kill_proc(fp->fs_pid, SIGHUP, 1); + } + fp->rdbuf_size = 0; + raw3270_request_reset(rq); + wake_up(&fp->wait); } -/* - * Switch to the fullscreen view. - */ static int fs3270_activate(struct raw3270_view *view) { struct fs3270 *fp; + char *cp; + int rc; fp = (struct fs3270 *) view; - raw3270_request_set_cmd(fp->clear, TC_EWRITEA); - fp->clear->callback = fs3270_reset_callback; - return raw3270_start(view, fp->clear); + + /* If an old init command is still running just return. */ + if (!raw3270_request_final(fp->init)) + return 0; + + if (fp->rdbuf_size == 0) { + /* No saved buffer. Just clear the screen. */ + raw3270_request_set_cmd(fp->init, TC_EWRITEA); + fp->init->callback = fs3270_reset_callback; + } else { + /* Restore fullscreen buffer saved by fs3270_deactivate. */ + raw3270_request_set_cmd(fp->init, TC_EWRITEA); + raw3270_request_set_idal(fp->init, fp->rdbuf); + fp->init->ccw.count = fp->rdbuf_size; + cp = fp->rdbuf->data[0]; + cp[0] = TW_KR; + cp[1] = TO_SBA; + cp[2] = cp[6]; + cp[3] = cp[7]; + cp[4] = TO_IC; + cp[5] = TO_SBA; + cp[6] = 0x40; + cp[7] = 0x40; + fp->init->rescnt = 0; + fp->init->callback = fs3270_restore_callback; + } + rc = fp->init->rc = raw3270_start_locked(view, fp->init); + if (rc) + fp->init->callback(fp->init, NULL); + else + fp->active = 1; + return rc; } /* * Shutdown fullscreen view. */ static void +fs3270_save_callback(struct raw3270_request *rq, void *data) +{ + struct fs3270 *fp; + + fp = (struct fs3270 *) rq->view; + + /* Correct idal buffer element 0 address. */ + fp->rdbuf->data[0] -= 5; + fp->rdbuf->size += 5; + + /* + * If the rdbuf command failed or the idal buffer is + * to small for the amount of data returned by the + * rdbuf command, then we have no choice but to send + * a SIGHUP to the application. + */ + if (rq->rc != 0 || rq->rescnt == 0) { + if (fp->fs_pid) + kill_proc(fp->fs_pid, SIGHUP, 1); + fp->rdbuf_size = 0; + } else + fp->rdbuf_size = fp->rdbuf->size - rq->rescnt; + raw3270_request_reset(rq); + wake_up(&fp->wait); +} + +static void fs3270_deactivate(struct raw3270_view *view) { - // FIXME: is this a good idea? The user program using fullscreen 3270 - // will die just because a console message appeared. On the other - // hand the fullscreen device is unoperational now. struct fs3270 *fp; fp = (struct fs3270 *) view; - if (fp->fs_pid != 0) - kill_proc(fp->fs_pid, SIGHUP, 1); - fp->fs_pid = 0; + fp->active = 0; + + /* If an old init command is still running just return. */ + if (!raw3270_request_final(fp->init)) + return; + + /* Prepare read-buffer request. */ + raw3270_request_set_cmd(fp->init, TC_RDBUF); + /* + * Hackish: skip first 5 bytes of the idal buffer to make + * room for the TW_KR/TO_SBA/<address>/<address>/TO_IC sequence + * in the activation command. + */ + fp->rdbuf->data[0] += 5; + fp->rdbuf->size -= 5; + raw3270_request_set_idal(fp->init, fp->rdbuf); + fp->init->rescnt = 0; + fp->init->callback = fs3270_save_callback; + + /* Start I/O to read in the 3270 buffer. */ + fp->init->rc = raw3270_start_locked(view, fp->init); + if (fp->init->rc) + fp->init->callback(fp->init, NULL); } static int @@ -103,7 +220,7 @@ fs3270_irq(struct fs3270 *fp, struct raw3270_request *rq, struct irb *irb) /* Handle ATTN. Set indication and wake waiters for attention. */ if (irb->scsw.dstat & DEV_STAT_ATTENTION) { fp->attention = 1; - wake_up(&fp->attn_wait); + wake_up(&fp->wait); } if (rq) { @@ -125,7 +242,7 @@ fs3270_read(struct file *filp, char *data, size_t count, loff_t *off) struct fs3270 *fp; struct raw3270_request *rq; struct idal_buffer *ib; - int rc; + ssize_t rc; if (count == 0 || count > 65535) return -EINVAL; @@ -133,7 +250,7 @@ fs3270_read(struct file *filp, char *data, size_t count, loff_t *off) if (!fp) return -ENODEV; ib = idal_buffer_alloc(count, 0); - if (!ib) + if (IS_ERR(ib)) return -ENOMEM; rq = raw3270_request_alloc(0); if (!IS_ERR(rq)) { @@ -141,10 +258,19 @@ fs3270_read(struct file *filp, char *data, size_t count, loff_t *off) fp->read_command = 6; raw3270_request_set_cmd(rq, fp->read_command ? : 2); raw3270_request_set_idal(rq, ib); - wait_event(fp->attn_wait, fp->attention); - rc = fs3270_do_io(&fp->view, rq); - if (rc == 0 && idal_buffer_to_user(ib, data, count)) - rc = -EFAULT; + rc = wait_event_interruptible(fp->wait, fp->attention); + fp->attention = 0; + if (rc == 0) { + rc = fs3270_do_io(&fp->view, rq); + if (rc == 0) { + count -= rq->rescnt; + if (idal_buffer_to_user(ib, data, count) != 0) + rc = -EFAULT; + else + rc = count; + + } + } raw3270_request_free(rq); } else rc = PTR_ERR(rq); @@ -162,13 +288,13 @@ fs3270_write(struct file *filp, const char *data, size_t count, loff_t *off) struct raw3270_request *rq; struct idal_buffer *ib; int write_command; - int rc; + ssize_t rc; fp = filp->private_data; if (!fp) return -ENODEV; ib = idal_buffer_alloc(count, 0); - if (!ib) + if (IS_ERR(ib)) return -ENOMEM; rq = raw3270_request_alloc(0); if (!IS_ERR(rq)) { @@ -179,6 +305,8 @@ fs3270_write(struct file *filp, const char *data, size_t count, loff_t *off) raw3270_request_set_cmd(rq, write_command); raw3270_request_set_idal(rq, ib); rc = fs3270_do_io(&fp->view, rq); + if (rc == 0) + rc = count - rq->rescnt; } else rc = -EFAULT; raw3270_request_free(rq); @@ -232,7 +360,7 @@ fs3270_ioctl(struct inode *inode, struct file *filp, } /* - * Allocate tty3270 structure. + * Allocate fs3270 structure. */ static struct fs3270 * fs3270_alloc_view(void) @@ -243,8 +371,8 @@ fs3270_alloc_view(void) if (!fp) return ERR_PTR(-ENOMEM); memset(fp, 0, sizeof(struct fs3270)); - fp->clear = raw3270_request_alloc(0); - if (!IS_ERR(fp->clear)) { + fp->init = raw3270_request_alloc(0); + if (IS_ERR(fp->init)) { kfree(fp); return ERR_PTR(-ENOMEM); } @@ -252,12 +380,17 @@ fs3270_alloc_view(void) } /* - * Free tty3270 structure. + * Free fs3270 structure. */ static void fs3270_free_view(struct raw3270_view *view) { - raw3270_request_free(((struct fs3270 *) view)->clear); + struct fs3270 *fp; + + fp = (struct fs3270 *) view; + if (fp->rdbuf) + idal_buffer_free(fp->rdbuf); + raw3270_request_free(((struct fs3270 *) view)->init); kfree(view); } @@ -285,11 +418,20 @@ static int fs3270_open(struct inode *inode, struct file *filp) { struct fs3270 *fp; + struct idal_buffer *ib; int minor, rc; if (imajor(filp->f_dentry->d_inode) != IBM_FS3270_MAJOR) return -ENODEV; minor = iminor(filp->f_dentry->d_inode); + /* Check for minor 0 multiplexer. */ + if (minor == 0) { + if (!current->signal->tty) + return -ENODEV; + if (current->signal->tty->driver->major != IBM_TTY3270_MAJOR) + return -ENODEV; + minor = current->signal->tty->index + RAW3270_FIRSTMINOR; + } /* Check if some other program is already using fullscreen mode. */ fp = (struct fs3270 *) raw3270_find_view(&fs3270_fn, minor); if (!IS_ERR(fp)) { @@ -301,7 +443,7 @@ fs3270_open(struct inode *inode, struct file *filp) if (IS_ERR(fp)) return PTR_ERR(fp); - init_waitqueue_head(&fp->attn_wait); + init_waitqueue_head(&fp->wait); fp->fs_pid = current->pid; rc = raw3270_add_view(&fp->view, &fs3270_fn, minor); if (rc) { @@ -309,8 +451,18 @@ fs3270_open(struct inode *inode, struct file *filp) return rc; } + /* Allocate idal-buffer. */ + ib = idal_buffer_alloc(2*fp->view.rows*fp->view.cols + 5, 0); + if (IS_ERR(ib)) { + raw3270_put_view(&fp->view); + raw3270_del_view(&fp->view); + return PTR_ERR(fp); + } + fp->rdbuf = ib; + rc = raw3270_activate_view(&fp->view); if (rc) { + raw3270_put_view(&fp->view); raw3270_del_view(&fp->view); return rc; } @@ -329,8 +481,12 @@ fs3270_close(struct inode *inode, struct file *filp) fp = filp->private_data; filp->private_data = 0; - if (fp) + if (fp) { + fp->fs_pid = 0; + raw3270_reset(&fp->view); + raw3270_put_view(&fp->view); raw3270_del_view(&fp->view); + } return 0; } diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c index 328d9cbc56a3..d66946443dfc 100644 --- a/drivers/s390/char/raw3270.c +++ b/drivers/s390/char/raw3270.c @@ -25,6 +25,12 @@ #include "raw3270.h" +#include <linux/major.h> +#include <linux/kdev_t.h> +#include <linux/device.h> + +struct class *class3270; + /* The main 3270 data structure. */ struct raw3270 { struct list_head list; @@ -41,6 +47,8 @@ struct raw3270 { struct timer_list timer; /* Device timer. */ unsigned char *ascebc; /* ascii -> ebcdic table */ + struct class_device *clttydev; /* 3270-class tty device ptr */ + struct class_device *cltubdev; /* 3270-class tub device ptr */ }; /* raw3270->flags */ @@ -317,6 +325,22 @@ raw3270_start(struct raw3270_view *view, struct raw3270_request *rq) } int +raw3270_start_locked(struct raw3270_view *view, struct raw3270_request *rq) +{ + struct raw3270 *rp; + int rc; + + rp = view->dev; + if (!rp || rp->view != view) + rc = -EACCES; + else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags)) + rc = -ENODEV; + else + rc = __raw3270_start(rp, view, rq); + return rc; +} + +int raw3270_start_irq(struct raw3270_view *view, struct raw3270_request *rq) { struct raw3270 *rp; @@ -744,6 +768,22 @@ raw3270_reset_device(struct raw3270 *rp) return rc; } +int +raw3270_reset(struct raw3270_view *view) +{ + struct raw3270 *rp; + int rc; + + rp = view->dev; + if (!rp || rp->view != view) + rc = -EACCES; + else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags)) + rc = -ENODEV; + else + rc = raw3270_reset_device(view->dev); + return rc; +} + /* * Setup new 3270 device. */ @@ -774,11 +814,12 @@ raw3270_setup_device(struct ccw_device *cdev, struct raw3270 *rp, char *ascebc) /* * Add device to list and find the smallest unused minor - * number for it. + * number for it. Note: there is no device with minor 0, + * see special case for fs3270.c:fs3270_open(). */ down(&raw3270_sem); /* Keep the list sorted. */ - minor = 0; + minor = RAW3270_FIRSTMINOR; rp->minor = -1; list_for_each(l, &raw3270_devices) { tmp = list_entry(l, struct raw3270, list); @@ -789,7 +830,7 @@ raw3270_setup_device(struct ccw_device *cdev, struct raw3270 *rp, char *ascebc) } minor++; } - if (rp->minor == -1 && minor < RAW3270_MAXDEVS) { + if (rp->minor == -1 && minor < RAW3270_MAXDEVS + RAW3270_FIRSTMINOR) { rp->minor = minor; list_add_tail(&rp->list, &raw3270_devices); } @@ -941,11 +982,12 @@ raw3270_deactivate_view(struct raw3270_view *view) list_add_tail(&view->list, &rp->view_list); /* Try to activate another view. */ if (test_bit(RAW3270_FLAGS_READY, &rp->flags)) { - list_for_each_entry(view, &rp->view_list, list) - if (view->fn->activate(view) == 0) { - rp->view = view; + list_for_each_entry(view, &rp->view_list, list) { + rp->view = view; + if (view->fn->activate(view) == 0) break; - } + rp->view = 0; + } } } spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags); @@ -961,6 +1003,8 @@ raw3270_add_view(struct raw3270_view *view, struct raw3270_fn *fn, int minor) struct raw3270 *rp; int rc; + if (minor <= 0) + return -ENODEV; down(&raw3270_sem); rc = -ENODEV; list_for_each_entry(rp, &raw3270_devices, list) { @@ -976,7 +1020,7 @@ raw3270_add_view(struct raw3270_view *view, struct raw3270_fn *fn, int minor) view->cols = rp->cols; view->ascebc = rp->ascebc; spin_lock_init(&view->lock); - list_add_tail(&view->list, &rp->view_list); + list_add(&view->list, &rp->view_list); rc = 0; } spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags); @@ -1039,7 +1083,7 @@ raw3270_del_view(struct raw3270_view *view) if (!rp->view && test_bit(RAW3270_FLAGS_READY, &rp->flags)) { /* Try to activate another view. */ list_for_each_entry(nv, &rp->view_list, list) { - if (nv->fn->activate(view) == 0) { + if (nv->fn->activate(nv) == 0) { rp->view = nv; break; } @@ -1063,6 +1107,12 @@ raw3270_delete_device(struct raw3270 *rp) /* Remove from device chain. */ down(&raw3270_sem); + if (rp->clttydev) + class_device_destroy(class3270, + MKDEV(IBM_TTY3270_MAJOR, rp->minor)); + if (rp->cltubdev) + class_device_destroy(class3270, + MKDEV(IBM_FS3270_MAJOR, rp->minor)); list_del_init(&rp->list); up(&raw3270_sem); @@ -1129,6 +1179,16 @@ raw3270_create_attributes(struct raw3270 *rp) { //FIXME: check return code sysfs_create_group(&rp->cdev->dev.kobj, &raw3270_attr_group); + rp->clttydev = + class_device_create(class3270, + MKDEV(IBM_TTY3270_MAJOR, rp->minor), + &rp->cdev->dev, "tty%s", + rp->cdev->dev.bus_id); + rp->cltubdev = + class_device_create(class3270, + MKDEV(IBM_FS3270_MAJOR, rp->minor), + &rp->cdev->dev, "tub%s", + rp->cdev->dev.bus_id); } /* @@ -1189,13 +1249,13 @@ raw3270_set_online (struct ccw_device *cdev) return PTR_ERR(rp); rc = raw3270_reset_device(rp); if (rc) - return rc; + goto failure; rc = raw3270_size_device(rp); if (rc) - return rc; + goto failure; rc = raw3270_reset_device(rp); if (rc) - return rc; + goto failure; raw3270_create_attributes(rp); set_bit(RAW3270_FLAGS_READY, &rp->flags); down(&raw3270_sem); @@ -1203,6 +1263,10 @@ raw3270_set_online (struct ccw_device *cdev) np->notifier(rp->minor, 1); up(&raw3270_sem); return 0; + +failure: + raw3270_delete_device(rp); + return rc; } /* @@ -1217,6 +1281,14 @@ raw3270_remove (struct ccw_device *cdev) struct raw3270_notifier *np; rp = cdev->dev.driver_data; + /* + * _remove is the opposite of _probe; it's probe that + * should set up rp. raw3270_remove gets entered for + * devices even if they haven't been varied online. + * Thus, rp may validly be NULL here. + */ + if (rp == NULL) + return; clear_bit(RAW3270_FLAGS_READY, &rp->flags); sysfs_remove_group(&cdev->dev.kobj, &raw3270_attr_group); @@ -1301,6 +1373,7 @@ raw3270_init(void) if (rc == 0) { /* Create attributes for early (= console) device. */ down(&raw3270_sem); + class3270 = class_create(THIS_MODULE, "3270"); list_for_each_entry(rp, &raw3270_devices, list) { get_device(&rp->cdev->dev); raw3270_create_attributes(rp); @@ -1314,6 +1387,7 @@ static void raw3270_exit(void) { ccw_driver_unregister(&raw3270_ccw_driver); + class_destroy(class3270); } MODULE_LICENSE("GPL"); @@ -1335,7 +1409,9 @@ EXPORT_SYMBOL(raw3270_find_view); EXPORT_SYMBOL(raw3270_activate_view); EXPORT_SYMBOL(raw3270_deactivate_view); EXPORT_SYMBOL(raw3270_start); +EXPORT_SYMBOL(raw3270_start_locked); EXPORT_SYMBOL(raw3270_start_irq); +EXPORT_SYMBOL(raw3270_reset); EXPORT_SYMBOL(raw3270_register_notifier); EXPORT_SYMBOL(raw3270_unregister_notifier); EXPORT_SYMBOL(raw3270_wait_queue); diff --git a/drivers/s390/char/raw3270.h b/drivers/s390/char/raw3270.h index ed5d4eb9f623..b635bf8e7775 100644 --- a/drivers/s390/char/raw3270.h +++ b/drivers/s390/char/raw3270.h @@ -21,6 +21,7 @@ /* Local Channel Commands */ #define TC_WRITE 0x01 /* Write */ +#define TC_RDBUF 0x02 /* Read Buffer */ #define TC_EWRITE 0x05 /* Erase write */ #define TC_READMOD 0x06 /* Read modified */ #define TC_EWRITEA 0x0d /* Erase write alternate */ @@ -76,7 +77,8 @@ #define TW_KR 0xc2 /* Keyboard restore */ #define TW_PLUSALARM 0x04 /* Add this bit for alarm */ -#define RAW3270_MAXDEVS 256 +#define RAW3270_FIRSTMINOR 1 /* First minor number */ +#define RAW3270_MAXDEVS 255 /* Max number of 3270 devices */ /* For TUBGETMOD and TUBSETMOD. Should include. */ struct raw3270_iocb { @@ -166,7 +168,10 @@ void raw3270_del_view(struct raw3270_view *); void raw3270_deactivate_view(struct raw3270_view *); struct raw3270_view *raw3270_find_view(struct raw3270_fn *, int); int raw3270_start(struct raw3270_view *, struct raw3270_request *); +int raw3270_start_locked(struct raw3270_view *, struct raw3270_request *); int raw3270_start_irq(struct raw3270_view *, struct raw3270_request *); +int raw3270_reset(struct raw3270_view *); +struct raw3270_view *raw3270_view(struct raw3270_view *); /* Reference count inliner for view structures. */ static inline void diff --git a/drivers/s390/char/tape_class.c b/drivers/s390/char/tape_class.c index ed0cb1f15b4c..fcaee447d6fe 100644 --- a/drivers/s390/char/tape_class.c +++ b/drivers/s390/char/tape_class.c @@ -72,6 +72,7 @@ struct tape_class_device *register_tape_dev( tcd->class_device = class_device_create( tape_class, + NULL, tcd->char_device->dev, device, "%s", tcd->device_name diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c index 7db5ebce7f0f..4b9069370388 100644 --- a/drivers/s390/char/tty3270.c +++ b/drivers/s390/char/tty3270.c @@ -653,18 +653,12 @@ tty3270_activate(struct raw3270_view *view) tp->update_flags = TTY_UPDATE_ALL; tty3270_set_timer(tp, 1); spin_unlock_irqrestore(&tp->view.lock, flags); - start_tty(tp->tty); return 0; } static void tty3270_deactivate(struct raw3270_view *view) { - struct tty3270 *tp; - - tp = (struct tty3270 *) view; - if (tp && tp->tty) - stop_tty(tp->tty); } static int @@ -716,13 +710,13 @@ tty3270_alloc_view(void) tp->freemem_pages[pages], PAGE_SIZE); } tp->write = raw3270_request_alloc(TTY3270_OUTPUT_BUFFER_SIZE); - if (!tp->write) + if (IS_ERR(tp->write)) goto out_pages; tp->read = raw3270_request_alloc(0); - if (!tp->read) + if (IS_ERR(tp->read)) goto out_write; tp->kreset = raw3270_request_alloc(1); - if (!tp->kreset) + if (IS_ERR(tp->kreset)) goto out_read; tp->kbd = kbd_alloc(); if (!tp->kbd) @@ -845,7 +839,8 @@ tty3270_del_views(void) int i; for (i = 0; i < tty3270_max_index; i++) { - tp = (struct tty3270 *) raw3270_find_view(&tty3270_fn, i); + tp = (struct tty3270 *) + raw3270_find_view(&tty3270_fn, i + RAW3270_FIRSTMINOR); if (!IS_ERR(tp)) raw3270_del_view(&tp->view); } @@ -871,7 +866,9 @@ tty3270_open(struct tty_struct *tty, struct file * filp) if (tty->count > 1) return 0; /* Check if the tty3270 is already there. */ - tp = (struct tty3270 *) raw3270_find_view(&tty3270_fn, tty->index); + tp = (struct tty3270 *) + raw3270_find_view(&tty3270_fn, + tty->index + RAW3270_FIRSTMINOR); if (!IS_ERR(tp)) { tty->driver_data = tp; tty->winsize.ws_row = tp->view.rows - 2; @@ -903,7 +900,8 @@ tty3270_open(struct tty_struct *tty, struct file * filp) (void (*)(unsigned long)) tty3270_read_tasklet, (unsigned long) tp->read); - rc = raw3270_add_view(&tp->view, &tty3270_fn, tty->index); + rc = raw3270_add_view(&tp->view, &tty3270_fn, + tty->index + RAW3270_FIRSTMINOR); if (rc) { tty3270_free_view(tp); return rc; @@ -911,8 +909,8 @@ tty3270_open(struct tty_struct *tty, struct file * filp) rc = tty3270_alloc_screen(tp); if (rc) { - raw3270_del_view(&tp->view); raw3270_put_view(&tp->view); + raw3270_del_view(&tp->view); return rc; } @@ -1780,7 +1778,7 @@ tty3270_init(void) struct tty_driver *driver; int ret; - driver = alloc_tty_driver(256); + driver = alloc_tty_driver(RAW3270_MAXDEVS); if (!driver) return -ENOMEM; @@ -1794,6 +1792,7 @@ tty3270_init(void) driver->driver_name = "ttyTUB"; driver->name = "ttyTUB"; driver->major = IBM_TTY3270_MAJOR; + driver->minor_start = RAW3270_FIRSTMINOR; driver->type = TTY_DRIVER_TYPE_SYSTEM; driver->subtype = SYSTEM_TYPE_TTY; driver->init_termios = tty_std_termios; diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c index 491f00c032e8..b2d75de144c6 100644 --- a/drivers/s390/char/vmlogrdr.c +++ b/drivers/s390/char/vmlogrdr.c @@ -788,6 +788,7 @@ vmlogrdr_register_device(struct vmlogrdr_priv_t *priv) { } priv->class_device = class_device_create( vmlogrdr_class, + NULL, MKDEV(vmlogrdr_major, priv->minor_num), dev, "%s", dev->bus_id ); diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c index 8cc4f1a940dc..c05b069c2996 100644 --- a/drivers/s390/cio/cmf.c +++ b/drivers/s390/cio/cmf.c @@ -30,10 +30,13 @@ #include <linux/list.h> #include <linux/module.h> #include <linux/moduleparam.h> +#include <linux/slab.h> +#include <linux/timex.h> /* get_clock() */ #include <asm/ccwdev.h> #include <asm/cio.h> #include <asm/cmb.h> +#include <asm/div64.h> #include "cio.h" #include "css.h" diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 9adc11e8b8bc..811c9d150637 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -22,6 +22,7 @@ #include <asm/ccwdev.h> #include <asm/cio.h> +#include <asm/param.h> /* HZ */ #include "cio.h" #include "css.h" @@ -252,6 +253,23 @@ cutype_show (struct device *dev, struct device_attribute *attr, char *buf) } static ssize_t +modalias_show (struct device *dev, struct device_attribute *attr, char *buf) +{ + struct ccw_device *cdev = to_ccwdev(dev); + struct ccw_device_id *id = &(cdev->id); + int ret; + + ret = sprintf(buf, "ccw:t%04Xm%02x", + id->cu_type, id->cu_model); + if (id->dev_type != 0) + ret += sprintf(buf + ret, "dt%04Xdm%02X\n", + id->dev_type, id->dev_model); + else + ret += sprintf(buf + ret, "dtdm\n"); + return ret; +} + +static ssize_t online_show (struct device *dev, struct device_attribute *attr, char *buf) { struct ccw_device *cdev = to_ccwdev(dev); @@ -448,6 +466,7 @@ static DEVICE_ATTR(chpids, 0444, chpids_show, NULL); static DEVICE_ATTR(pimpampom, 0444, pimpampom_show, NULL); static DEVICE_ATTR(devtype, 0444, devtype_show, NULL); static DEVICE_ATTR(cutype, 0444, cutype_show, NULL); +static DEVICE_ATTR(modalias, 0444, modalias_show, NULL); static DEVICE_ATTR(online, 0644, online_show, online_store); extern struct device_attribute dev_attr_cmb_enable; static DEVICE_ATTR(availability, 0444, available_show, NULL); @@ -471,6 +490,7 @@ subchannel_add_files (struct device *dev) static struct attribute * ccwdev_attrs[] = { &dev_attr_devtype.attr, &dev_attr_cutype.attr, + &dev_attr_modalias.attr, &dev_attr_online.attr, &dev_attr_cmb_enable.attr, &dev_attr_availability.attr, diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index fbe4202a3f6f..c1c89f4fd4e3 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c @@ -11,6 +11,8 @@ #include <linux/module.h> #include <linux/config.h> #include <linux/init.h> +#include <linux/jiffies.h> +#include <linux/string.h> #include <asm/ccwdev.h> #include <asm/cio.h> diff --git a/drivers/s390/net/fsm.c b/drivers/s390/net/fsm.c index fa09440d82e5..38f50b7129a2 100644 --- a/drivers/s390/net/fsm.c +++ b/drivers/s390/net/fsm.c @@ -16,7 +16,7 @@ MODULE_LICENSE("GPL"); fsm_instance * init_fsm(char *name, const char **state_names, const char **event_names, int nr_states, - int nr_events, const fsm_node *tmpl, int tmpl_len, int order) + int nr_events, const fsm_node *tmpl, int tmpl_len, gfp_t order) { int i; fsm_instance *this; diff --git a/drivers/s390/net/fsm.h b/drivers/s390/net/fsm.h index f9a011001eb6..1b8a7e7c34f3 100644 --- a/drivers/s390/net/fsm.h +++ b/drivers/s390/net/fsm.h @@ -110,7 +110,7 @@ extern fsm_instance * init_fsm(char *name, const char **state_names, const char **event_names, int nr_states, int nr_events, const fsm_node *tmpl, - int tmpl_len, int order); + int tmpl_len, gfp_t order); /** * Releases an FSM diff --git a/drivers/s390/net/qeth.h b/drivers/s390/net/qeth.h index 9963479ba89f..38a2441564d7 100644 --- a/drivers/s390/net/qeth.h +++ b/drivers/s390/net/qeth.h @@ -275,6 +275,10 @@ qeth_is_ipa_enabled(struct qeth_ipa_info *ipa, enum qeth_ipa_funcs func) QETH_IDX_FUNC_LEVEL_IQD_ENA_IPAT, \ QETH_IDX_FUNC_LEVEL_IQD_DIS_IPAT, \ QETH_MAX_QUEUES,0x103}, \ + {0x1731,0x06,0x1732,0x06,QETH_CARD_TYPE_OSN,0, \ + QETH_IDX_FUNC_LEVEL_OSAE_ENA_IPAT, \ + QETH_IDX_FUNC_LEVEL_OSAE_DIS_IPAT, \ + QETH_MAX_QUEUES,0}, \ {0,0,0,0,0,0,0,0,0}} #define QETH_REAL_CARD 1 @@ -363,10 +367,22 @@ struct qeth_hdr_layer2 { __u8 reserved2[16]; } __attribute__ ((packed)); +struct qeth_hdr_osn { + __u8 id; + __u8 reserved; + __u16 seq_no; + __u16 reserved2; + __u16 control_flags; + __u16 pdu_length; + __u8 reserved3[18]; + __u32 ccid; +} __attribute__ ((packed)); + struct qeth_hdr { union { struct qeth_hdr_layer2 l2; struct qeth_hdr_layer3 l3; + struct qeth_hdr_osn osn; } hdr; } __attribute__ ((packed)); @@ -413,6 +429,7 @@ enum qeth_header_ids { QETH_HEADER_TYPE_LAYER3 = 0x01, QETH_HEADER_TYPE_LAYER2 = 0x02, QETH_HEADER_TYPE_TSO = 0x03, + QETH_HEADER_TYPE_OSN = 0x04, }; /* flags for qeth_hdr.ext_flags */ #define QETH_HDR_EXT_VLAN_FRAME 0x01 @@ -582,7 +599,6 @@ enum qeth_card_states { * Protocol versions */ enum qeth_prot_versions { - QETH_PROT_SNA = 0x0001, QETH_PROT_IPV4 = 0x0004, QETH_PROT_IPV6 = 0x0006, }; @@ -761,6 +777,11 @@ enum qeth_threads { QETH_RECOVER_THREAD = 2, }; +struct qeth_osn_info { + int (*assist_cb)(struct net_device *dev, void *data); + int (*data_cb)(struct sk_buff *skb); +}; + struct qeth_card { struct list_head list; enum qeth_card_states state; @@ -803,6 +824,7 @@ struct qeth_card { int use_hard_stop; int (*orig_hard_header)(struct sk_buff *,struct net_device *, unsigned short,void *,void *,unsigned); + struct qeth_osn_info osn_info; }; struct qeth_card_list_struct { @@ -916,10 +938,12 @@ qeth_get_hlen(__u8 link_type) static inline unsigned short qeth_get_netdev_flags(struct qeth_card *card) { - if (card->options.layer2) + if (card->options.layer2 && + (card->info.type == QETH_CARD_TYPE_OSAE)) return 0; switch (card->info.type) { case QETH_CARD_TYPE_IQD: + case QETH_CARD_TYPE_OSN: return IFF_NOARP; #ifdef CONFIG_QETH_IPV6 default: @@ -956,9 +980,10 @@ static inline int qeth_get_max_mtu_for_card(int cardtype) { switch (cardtype) { + case QETH_CARD_TYPE_UNKNOWN: - return 61440; case QETH_CARD_TYPE_OSAE: + case QETH_CARD_TYPE_OSN: return 61440; case QETH_CARD_TYPE_IQD: return 57344; @@ -1004,6 +1029,7 @@ qeth_mtu_is_valid(struct qeth_card * card, int mtu) case QETH_CARD_TYPE_IQD: return ((mtu >= 576) && (mtu <= card->info.max_mtu + 4096 - 32)); + case QETH_CARD_TYPE_OSN: case QETH_CARD_TYPE_UNKNOWN: default: return 1; @@ -1015,6 +1041,7 @@ qeth_get_arphdr_type(int cardtype, int linktype) { switch (cardtype) { case QETH_CARD_TYPE_OSAE: + case QETH_CARD_TYPE_OSN: switch (linktype) { case QETH_LINK_TYPE_LANE_TR: case QETH_LINK_TYPE_HSTR: @@ -1182,4 +1209,16 @@ qeth_fill_header(struct qeth_card *, struct qeth_hdr *, extern void qeth_flush_buffers(struct qeth_qdio_out_q *, int, int, int); +extern int +qeth_osn_assist(struct net_device *, void *, int); + +extern int +qeth_osn_register(unsigned char *read_dev_no, + struct net_device **, + int (*assist_cb)(struct net_device *, void *), + int (*data_cb)(struct sk_buff *)); + +extern void +qeth_osn_deregister(struct net_device *); + #endif /* __QETH_H__ */ diff --git a/drivers/s390/net/qeth_fs.h b/drivers/s390/net/qeth_fs.h index 5c9a51ce91b6..c0b4c8d82c45 100644 --- a/drivers/s390/net/qeth_fs.h +++ b/drivers/s390/net/qeth_fs.h @@ -12,7 +12,7 @@ #ifndef __QETH_FS_H__ #define __QETH_FS_H__ -#define VERSION_QETH_FS_H "$Revision: 1.9 $" +#define VERSION_QETH_FS_H "$Revision: 1.10 $" extern const char *VERSION_QETH_PROC_C; extern const char *VERSION_QETH_SYS_C; @@ -43,6 +43,12 @@ extern void qeth_remove_device_attributes(struct device *dev); extern int +qeth_create_device_attributes_osn(struct device *dev); + +extern void +qeth_remove_device_attributes_osn(struct device *dev); + +extern int qeth_create_driver_attributes(void); extern void @@ -108,6 +114,8 @@ qeth_get_cardname(struct qeth_card *card) return " OSD Express"; case QETH_CARD_TYPE_IQD: return " HiperSockets"; + case QETH_CARD_TYPE_OSN: + return " OSN QDIO"; default: return " unknown"; } @@ -153,6 +161,8 @@ qeth_get_cardname_short(struct qeth_card *card) } case QETH_CARD_TYPE_IQD: return "HiperSockets"; + case QETH_CARD_TYPE_OSN: + return "OSN"; default: return "unknown"; } diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c index bd28e2438d7f..692003c9f896 100644 --- a/drivers/s390/net/qeth_main.c +++ b/drivers/s390/net/qeth_main.c @@ -196,7 +196,6 @@ qeth_notifier_register(struct task_struct *p, int signum) { struct qeth_notify_list_struct *n_entry; - /*check first if entry already exists*/ spin_lock(&qeth_notify_lock); list_for_each_entry(n_entry, &qeth_notify_list, list) { @@ -1024,7 +1023,10 @@ qeth_set_intial_options(struct qeth_card *card) card->options.fake_broadcast = 0; card->options.add_hhlen = DEFAULT_ADD_HHLEN; card->options.fake_ll = 0; - card->options.layer2 = 0; + if (card->info.type == QETH_CARD_TYPE_OSN) + card->options.layer2 = 1; + else + card->options.layer2 = 0; } /** @@ -1113,19 +1115,20 @@ qeth_determine_card_type(struct qeth_card *card) QETH_DBF_TEXT(setup, 2, "detcdtyp"); + card->qdio.do_prio_queueing = QETH_PRIOQ_DEFAULT; + card->qdio.default_out_queue = QETH_DEFAULT_QUEUE; while (known_devices[i][4]) { if ((CARD_RDEV(card)->id.dev_type == known_devices[i][2]) && (CARD_RDEV(card)->id.dev_model == known_devices[i][3])) { card->info.type = known_devices[i][4]; + card->qdio.no_out_queues = known_devices[i][8]; + card->info.is_multicast_different = known_devices[i][9]; if (is_1920_device(card)) { PRINT_INFO("Priority Queueing not able " "due to hardware limitations!\n"); card->qdio.no_out_queues = 1; card->qdio.default_out_queue = 0; - } else { - card->qdio.no_out_queues = known_devices[i][8]; - } - card->info.is_multicast_different = known_devices[i][9]; + } return 0; } i++; @@ -1149,6 +1152,8 @@ qeth_probe_device(struct ccwgroup_device *gdev) if (!get_device(dev)) return -ENODEV; + QETH_DBF_TEXT_(setup, 2, "%s", gdev->dev.bus_id); + card = qeth_alloc_card(); if (!card) { put_device(dev); @@ -1158,28 +1163,27 @@ qeth_probe_device(struct ccwgroup_device *gdev) card->read.ccwdev = gdev->cdev[0]; card->write.ccwdev = gdev->cdev[1]; card->data.ccwdev = gdev->cdev[2]; - - if ((rc = qeth_setup_card(card))){ - QETH_DBF_TEXT_(setup, 2, "2err%d", rc); - put_device(dev); - qeth_free_card(card); - return rc; - } gdev->dev.driver_data = card; card->gdev = gdev; gdev->cdev[0]->handler = qeth_irq; gdev->cdev[1]->handler = qeth_irq; gdev->cdev[2]->handler = qeth_irq; - rc = qeth_create_device_attributes(dev); - if (rc) { + if ((rc = qeth_determine_card_type(card))){ + PRINT_WARN("%s: not a valid card type\n", __func__); + QETH_DBF_TEXT_(setup, 2, "3err%d", rc); + put_device(dev); + qeth_free_card(card); + return rc; + } + if ((rc = qeth_setup_card(card))){ + QETH_DBF_TEXT_(setup, 2, "2err%d", rc); put_device(dev); qeth_free_card(card); return rc; } - if ((rc = qeth_determine_card_type(card))){ - PRINT_WARN("%s: not a valid card type\n", __func__); - QETH_DBF_TEXT_(setup, 2, "3err%d", rc); + rc = qeth_create_device_attributes(dev); + if (rc) { put_device(dev); qeth_free_card(card); return rc; @@ -1660,6 +1664,8 @@ qeth_check_ipa_data(struct qeth_card *card, struct qeth_cmd_buffer *iob) netif_carrier_on(card->dev); qeth_schedule_recovery(card); return NULL; + case IPA_CMD_MODCCID: + return cmd; case IPA_CMD_REGISTER_LOCAL_ADDR: QETH_DBF_TEXT(trace,3, "irla"); break; @@ -1721,6 +1727,14 @@ qeth_send_control_data_cb(struct qeth_channel *channel, cmd = qeth_check_ipa_data(card, iob); if ((cmd == NULL) && (card->state != CARD_STATE_DOWN)) goto out; + /*in case of OSN : check if cmd is set */ + if (card->info.type == QETH_CARD_TYPE_OSN && + cmd && + cmd->hdr.command != IPA_CMD_STARTLAN && + card->osn_info.assist_cb != NULL) { + card->osn_info.assist_cb(card->dev, cmd); + goto out; + } spin_lock_irqsave(&card->lock, flags); list_for_each_entry_safe(reply, r, &card->cmd_waiter_list, list) { @@ -1737,8 +1751,7 @@ qeth_send_control_data_cb(struct qeth_channel *channel, keep_reply = reply->callback(card, reply, (unsigned long)cmd); - } - else + } else keep_reply = reply->callback(card, reply, (unsigned long)iob); @@ -1768,6 +1781,24 @@ out: qeth_release_buffer(channel,iob); } +static inline void +qeth_prepare_control_data(struct qeth_card *card, int len, +struct qeth_cmd_buffer *iob) +{ + qeth_setup_ccw(&card->write,iob->data,len); + iob->callback = qeth_release_buffer; + + memcpy(QETH_TRANSPORT_HEADER_SEQ_NO(iob->data), + &card->seqno.trans_hdr, QETH_SEQ_NO_LENGTH); + card->seqno.trans_hdr++; + memcpy(QETH_PDU_HEADER_SEQ_NO(iob->data), + &card->seqno.pdu_hdr, QETH_SEQ_NO_LENGTH); + card->seqno.pdu_hdr++; + memcpy(QETH_PDU_HEADER_ACK_SEQ_NO(iob->data), + &card->seqno.pdu_hdr_ack, QETH_SEQ_NO_LENGTH); + QETH_DBF_HEX(control, 2, iob->data, QETH_DBF_CONTROL_LEN); +} + static int qeth_send_control_data(struct qeth_card *card, int len, struct qeth_cmd_buffer *iob, @@ -1778,24 +1809,11 @@ qeth_send_control_data(struct qeth_card *card, int len, { int rc; unsigned long flags; - struct qeth_reply *reply; + struct qeth_reply *reply = NULL; struct timer_list timer; QETH_DBF_TEXT(trace, 2, "sendctl"); - qeth_setup_ccw(&card->write,iob->data,len); - - memcpy(QETH_TRANSPORT_HEADER_SEQ_NO(iob->data), - &card->seqno.trans_hdr, QETH_SEQ_NO_LENGTH); - card->seqno.trans_hdr++; - - memcpy(QETH_PDU_HEADER_SEQ_NO(iob->data), - &card->seqno.pdu_hdr, QETH_SEQ_NO_LENGTH); - card->seqno.pdu_hdr++; - memcpy(QETH_PDU_HEADER_ACK_SEQ_NO(iob->data), - &card->seqno.pdu_hdr_ack, QETH_SEQ_NO_LENGTH); - iob->callback = qeth_release_buffer; - reply = qeth_alloc_reply(card); if (!reply) { PRINT_WARN("Could no alloc qeth_reply!\n"); @@ -1810,10 +1828,6 @@ qeth_send_control_data(struct qeth_card *card, int len, init_timer(&timer); timer.function = qeth_cmd_timeout; timer.data = (unsigned long) reply; - if (IS_IPA(iob->data)) - timer.expires = jiffies + QETH_IPA_TIMEOUT; - else - timer.expires = jiffies + QETH_TIMEOUT; init_waitqueue_head(&reply->wait_q); spin_lock_irqsave(&card->lock, flags); list_add_tail(&reply->list, &card->cmd_waiter_list); @@ -1821,6 +1835,11 @@ qeth_send_control_data(struct qeth_card *card, int len, QETH_DBF_HEX(control, 2, iob->data, QETH_DBF_CONTROL_LEN); wait_event(card->wait_q, atomic_compare_and_swap(0,1,&card->write.irq_pending) == 0); + qeth_prepare_control_data(card, len, iob); + if (IS_IPA(iob->data)) + timer.expires = jiffies + QETH_IPA_TIMEOUT; + else + timer.expires = jiffies + QETH_TIMEOUT; QETH_DBF_TEXT(trace, 6, "noirqpnd"); spin_lock_irqsave(get_ccwdev_lock(card->write.ccwdev), flags); rc = ccw_device_start(card->write.ccwdev, &card->write.ccw, @@ -1848,6 +1867,62 @@ qeth_send_control_data(struct qeth_card *card, int len, } static int +qeth_osn_send_control_data(struct qeth_card *card, int len, + struct qeth_cmd_buffer *iob) +{ + unsigned long flags; + int rc = 0; + + QETH_DBF_TEXT(trace, 5, "osndctrd"); + + wait_event(card->wait_q, + atomic_compare_and_swap(0,1,&card->write.irq_pending) == 0); + qeth_prepare_control_data(card, len, iob); + QETH_DBF_TEXT(trace, 6, "osnoirqp"); + spin_lock_irqsave(get_ccwdev_lock(card->write.ccwdev), flags); + rc = ccw_device_start(card->write.ccwdev, &card->write.ccw, + (addr_t) iob, 0, 0); + spin_unlock_irqrestore(get_ccwdev_lock(card->write.ccwdev), flags); + if (rc){ + PRINT_WARN("qeth_osn_send_control_data: " + "ccw_device_start rc = %i\n", rc); + QETH_DBF_TEXT_(trace, 2, " err%d", rc); + qeth_release_buffer(iob->channel, iob); + atomic_set(&card->write.irq_pending, 0); + wake_up(&card->wait_q); + } + return rc; +} + +static inline void +qeth_prepare_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob, + char prot_type) +{ + memcpy(iob->data, IPA_PDU_HEADER, IPA_PDU_HEADER_SIZE); + memcpy(QETH_IPA_CMD_PROT_TYPE(iob->data),&prot_type,1); + memcpy(QETH_IPA_CMD_DEST_ADDR(iob->data), + &card->token.ulp_connection_r, QETH_MPC_TOKEN_LENGTH); +} + +static int +qeth_osn_send_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob, + int data_len) +{ + u16 s1, s2; + +QETH_DBF_TEXT(trace,4,"osndipa"); + + qeth_prepare_ipa_cmd(card, iob, QETH_PROT_OSN2); + s1 = (u16)(IPA_PDU_HEADER_SIZE + data_len); + s2 = (u16)data_len; + memcpy(QETH_IPA_PDU_LEN_TOTAL(iob->data), &s1, 2); + memcpy(QETH_IPA_PDU_LEN_PDU1(iob->data), &s2, 2); + memcpy(QETH_IPA_PDU_LEN_PDU2(iob->data), &s2, 2); + memcpy(QETH_IPA_PDU_LEN_PDU3(iob->data), &s2, 2); + return qeth_osn_send_control_data(card, s1, iob); +} + +static int qeth_send_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob, int (*reply_cb) (struct qeth_card *,struct qeth_reply*, unsigned long), @@ -1858,17 +1933,14 @@ qeth_send_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob, QETH_DBF_TEXT(trace,4,"sendipa"); - memcpy(iob->data, IPA_PDU_HEADER, IPA_PDU_HEADER_SIZE); - if (card->options.layer2) - prot_type = QETH_PROT_LAYER2; + if (card->info.type == QETH_CARD_TYPE_OSN) + prot_type = QETH_PROT_OSN2; + else + prot_type = QETH_PROT_LAYER2; else prot_type = QETH_PROT_TCPIP; - - memcpy(QETH_IPA_CMD_PROT_TYPE(iob->data),&prot_type,1); - memcpy(QETH_IPA_CMD_DEST_ADDR(iob->data), - &card->token.ulp_connection_r, QETH_MPC_TOKEN_LENGTH); - + qeth_prepare_ipa_cmd(card,iob,prot_type); rc = qeth_send_control_data(card, IPA_CMD_LENGTH, iob, reply_cb, reply_param); return rc; @@ -2010,7 +2082,10 @@ qeth_ulp_enable(struct qeth_card *card) *(QETH_ULP_ENABLE_LINKNUM(iob->data)) = (__u8) card->info.portno; if (card->options.layer2) - prot_type = QETH_PROT_LAYER2; + if (card->info.type == QETH_CARD_TYPE_OSN) + prot_type = QETH_PROT_OSN2; + else + prot_type = QETH_PROT_LAYER2; else prot_type = QETH_PROT_TCPIP; @@ -2100,15 +2175,21 @@ qeth_check_for_inbound_error(struct qeth_qdio_buffer *buf, } static inline struct sk_buff * -qeth_get_skb(unsigned int length) +qeth_get_skb(unsigned int length, struct qeth_hdr *hdr) { struct sk_buff* skb; + int add_len; + + add_len = 0; + if (hdr->hdr.osn.id == QETH_HEADER_TYPE_OSN) + add_len = sizeof(struct qeth_hdr); #ifdef CONFIG_QETH_VLAN - if ((skb = dev_alloc_skb(length + VLAN_HLEN))) - skb_reserve(skb, VLAN_HLEN); -#else - skb = dev_alloc_skb(length); + else + add_len = VLAN_HLEN; #endif + skb = dev_alloc_skb(length + add_len); + if (skb && add_len) + skb_reserve(skb, add_len); return skb; } @@ -2138,7 +2219,10 @@ qeth_get_next_skb(struct qeth_card *card, struct qdio_buffer *buffer, offset += sizeof(struct qeth_hdr); if (card->options.layer2) - skb_len = (*hdr)->hdr.l2.pkt_length; + if (card->info.type == QETH_CARD_TYPE_OSN) + skb_len = (*hdr)->hdr.osn.pdu_length; + else + skb_len = (*hdr)->hdr.l2.pkt_length; else skb_len = (*hdr)->hdr.l3.length; @@ -2146,15 +2230,15 @@ qeth_get_next_skb(struct qeth_card *card, struct qdio_buffer *buffer, return NULL; if (card->options.fake_ll){ if(card->dev->type == ARPHRD_IEEE802_TR){ - if (!(skb = qeth_get_skb(skb_len+QETH_FAKE_LL_LEN_TR))) + if (!(skb = qeth_get_skb(skb_len+QETH_FAKE_LL_LEN_TR, *hdr))) goto no_mem; skb_reserve(skb,QETH_FAKE_LL_LEN_TR); } else { - if (!(skb = qeth_get_skb(skb_len+QETH_FAKE_LL_LEN_ETH))) + if (!(skb = qeth_get_skb(skb_len+QETH_FAKE_LL_LEN_ETH, *hdr))) goto no_mem; skb_reserve(skb,QETH_FAKE_LL_LEN_ETH); } - } else if (!(skb = qeth_get_skb(skb_len))) + } else if (!(skb = qeth_get_skb(skb_len, *hdr))) goto no_mem; data_ptr = element->addr + offset; while (skb_len) { @@ -2453,8 +2537,12 @@ qeth_process_inbound_buffer(struct qeth_card *card, skb->dev = card->dev; if (hdr->hdr.l2.id == QETH_HEADER_TYPE_LAYER2) vlan_tag = qeth_layer2_rebuild_skb(card, skb, hdr); - else + else if (hdr->hdr.l3.id == QETH_HEADER_TYPE_LAYER3) qeth_rebuild_skb(card, skb, hdr); + else { /*in case of OSN*/ + skb_push(skb, sizeof(struct qeth_hdr)); + memcpy(skb->data, hdr, sizeof(struct qeth_hdr)); + } /* is device UP ? */ if (!(card->dev->flags & IFF_UP)){ dev_kfree_skb_any(skb); @@ -2465,7 +2553,10 @@ qeth_process_inbound_buffer(struct qeth_card *card, vlan_hwaccel_rx(skb, card->vlangrp, vlan_tag); else #endif - rxrc = netif_rx(skb); + if (card->info.type == QETH_CARD_TYPE_OSN) + rxrc = card->osn_info.data_cb(skb); + else + rxrc = netif_rx(skb); card->dev->last_rx = jiffies; card->stats.rx_packets++; card->stats.rx_bytes += skb->len; @@ -3150,8 +3241,6 @@ qeth_init_qdio_info(struct qeth_card *card) INIT_LIST_HEAD(&card->qdio.in_buf_pool.entry_list); INIT_LIST_HEAD(&card->qdio.init_pool.entry_list); /* outbound */ - card->qdio.do_prio_queueing = QETH_PRIOQ_DEFAULT; - card->qdio.default_out_queue = QETH_DEFAULT_QUEUE; } static int @@ -3466,7 +3555,7 @@ qeth_mpc_initialize(struct qeth_card *card) return 0; out_qdio: - qeth_qdio_clear_card(card, card->info.type==QETH_CARD_TYPE_OSAE); + qeth_qdio_clear_card(card, card->info.type!=QETH_CARD_TYPE_IQD); return rc; } @@ -3491,6 +3580,9 @@ qeth_get_netdevice(enum qeth_card_types type, enum qeth_link_types linktype) case QETH_CARD_TYPE_IQD: dev = alloc_netdev(0, "hsi%d", ether_setup); break; + case QETH_CARD_TYPE_OSN: + dev = alloc_netdev(0, "osn%d", ether_setup); + break; default: dev = alloc_etherdev(0); } @@ -3655,7 +3747,8 @@ qeth_open(struct net_device *dev) if (card->state != CARD_STATE_SOFTSETUP) return -ENODEV; - if ( (card->options.layer2) && + if ( (card->info.type != QETH_CARD_TYPE_OSN) && + (card->options.layer2) && (!card->info.layer2_mac_registered)) { QETH_DBF_TEXT(trace,4,"nomacadr"); return -EPERM; @@ -3693,6 +3786,9 @@ qeth_get_cast_type(struct qeth_card *card, struct sk_buff *skb) { int cast_type = RTN_UNSPEC; + if (card->info.type == QETH_CARD_TYPE_OSN) + return cast_type; + if (skb->dst && skb->dst->neighbour){ cast_type = skb->dst->neighbour->type; if ((cast_type == RTN_BROADCAST) || @@ -3782,13 +3878,16 @@ static inline int qeth_prepare_skb(struct qeth_card *card, struct sk_buff **skb, struct qeth_hdr **hdr, int ipv) { - int rc; + int rc = 0; #ifdef CONFIG_QETH_VLAN u16 *tag; #endif QETH_DBF_TEXT(trace, 6, "prepskb"); - + if (card->info.type == QETH_CARD_TYPE_OSN) { + *hdr = (struct qeth_hdr *)(*skb)->data; + return rc; + } rc = qeth_realloc_headroom(card, skb, sizeof(struct qeth_hdr)); if (rc) return rc; @@ -4291,8 +4390,14 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb) } } } + if ((card->info.type == QETH_CARD_TYPE_OSN) && + (skb->protocol == htons(ETH_P_IPV6))) { + dev_kfree_skb_any(skb); + return 0; + } cast_type = qeth_get_cast_type(card, skb); - if ((cast_type == RTN_BROADCAST) && (card->info.broadcast_capable == 0)){ + if ((cast_type == RTN_BROADCAST) && + (card->info.broadcast_capable == 0)){ card->stats.tx_dropped++; card->stats.tx_errors++; dev_kfree_skb_any(skb); @@ -4320,7 +4425,8 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb) QETH_DBF_TEXT_(trace, 4, "pskbe%d", rc); return rc; } - qeth_fill_header(card, hdr, skb, ipv, cast_type); + if (card->info.type != QETH_CARD_TYPE_OSN) + qeth_fill_header(card, hdr, skb, ipv, cast_type); } if (large_send == QETH_LARGE_SEND_EDDP) { @@ -4381,6 +4487,7 @@ qeth_mdio_read(struct net_device *dev, int phy_id, int regnum) case MII_BMCR: /* Basic mode control register */ rc = BMCR_FULLDPLX; if ((card->info.link_type != QETH_LINK_TYPE_GBIT_ETH)&& + (card->info.link_type != QETH_LINK_TYPE_OSN) && (card->info.link_type != QETH_LINK_TYPE_10GBIT_ETH)) rc |= BMCR_SPEED100; break; @@ -5004,6 +5111,9 @@ qeth_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) (card->state != CARD_STATE_SOFTSETUP)) return -ENODEV; + if (card->info.type == QETH_CARD_TYPE_OSN) + return -EPERM; + switch (cmd){ case SIOC_QETH_ARP_SET_NO_ENTRIES: if ( !capable(CAP_NET_ADMIN) || @@ -5329,6 +5439,9 @@ qeth_set_multicast_list(struct net_device *dev) { struct qeth_card *card = (struct qeth_card *) dev->priv; + if (card->info.type == QETH_CARD_TYPE_OSN) + return ; + QETH_DBF_TEXT(trace,3,"setmulti"); qeth_delete_mc_addresses(card); qeth_add_multicast_ipv4(card); @@ -5370,6 +5483,94 @@ qeth_get_addr_buffer(enum qeth_prot_versions prot) return addr; } +int +qeth_osn_assist(struct net_device *dev, + void *data, + int data_len) +{ + struct qeth_cmd_buffer *iob; + struct qeth_card *card; + int rc; + + QETH_DBF_TEXT(trace, 2, "osnsdmc"); + if (!dev) + return -ENODEV; + card = (struct qeth_card *)dev->priv; + if (!card) + return -ENODEV; + if ((card->state != CARD_STATE_UP) && + (card->state != CARD_STATE_SOFTSETUP)) + return -ENODEV; + iob = qeth_wait_for_buffer(&card->write); + memcpy(iob->data+IPA_PDU_HEADER_SIZE, data, data_len); + rc = qeth_osn_send_ipa_cmd(card, iob, data_len); + return rc; +} + +static struct net_device * +qeth_netdev_by_devno(unsigned char *read_dev_no) +{ + struct qeth_card *card; + struct net_device *ndev; + unsigned char *readno; + __u16 temp_dev_no, card_dev_no; + char *endp; + unsigned long flags; + + ndev = NULL; + memcpy(&temp_dev_no, read_dev_no, 2); + read_lock_irqsave(&qeth_card_list.rwlock, flags); + list_for_each_entry(card, &qeth_card_list.list, list) { + readno = CARD_RDEV_ID(card); + readno += (strlen(readno) - 4); + card_dev_no = simple_strtoul(readno, &endp, 16); + if (card_dev_no == temp_dev_no) { + ndev = card->dev; + break; + } + } + read_unlock_irqrestore(&qeth_card_list.rwlock, flags); + return ndev; +} + +int +qeth_osn_register(unsigned char *read_dev_no, + struct net_device **dev, + int (*assist_cb)(struct net_device *, void *), + int (*data_cb)(struct sk_buff *)) +{ + struct qeth_card * card; + + QETH_DBF_TEXT(trace, 2, "osnreg"); + *dev = qeth_netdev_by_devno(read_dev_no); + if (*dev == NULL) + return -ENODEV; + card = (struct qeth_card *)(*dev)->priv; + if (!card) + return -ENODEV; + if ((assist_cb == NULL) || (data_cb == NULL)) + return -EINVAL; + card->osn_info.assist_cb = assist_cb; + card->osn_info.data_cb = data_cb; + return 0; +} + +void +qeth_osn_deregister(struct net_device * dev) +{ + struct qeth_card *card; + + QETH_DBF_TEXT(trace, 2, "osndereg"); + if (!dev) + return; + card = (struct qeth_card *)dev->priv; + if (!card) + return; + card->osn_info.assist_cb = NULL; + card->osn_info.data_cb = NULL; + return; +} + static void qeth_delete_mc_addresses(struct qeth_card *card) { @@ -5700,6 +5901,12 @@ qeth_layer2_set_mac_address(struct net_device *dev, void *p) QETH_DBF_TEXT(trace, 3, "setmcLY3"); return -EOPNOTSUPP; } + if (card->info.type == QETH_CARD_TYPE_OSN) { + PRINT_WARN("Setting MAC address on %s is not supported.\n", + dev->name); + QETH_DBF_TEXT(trace, 3, "setmcOSN"); + return -EOPNOTSUPP; + } QETH_DBF_TEXT_(trace, 3, "%s", CARD_BUS_ID(card)); QETH_DBF_HEX(trace, 3, addr->sa_data, OSA_ADDR_LEN); rc = qeth_layer2_send_delmac(card, &card->dev->dev_addr[0]); @@ -6076,9 +6283,8 @@ qeth_netdev_init(struct net_device *dev) qeth_get_hlen(card->info.link_type) + card->options.add_hhlen; dev->addr_len = OSA_ADDR_LEN; dev->mtu = card->info.initial_mtu; - - SET_ETHTOOL_OPS(dev, &qeth_ethtool_ops); - + if (card->info.type != QETH_CARD_TYPE_OSN) + SET_ETHTOOL_OPS(dev, &qeth_ethtool_ops); SET_MODULE_OWNER(dev); return 0; } @@ -6095,6 +6301,7 @@ qeth_init_func_level(struct qeth_card *card) QETH_IDX_FUNC_LEVEL_OSAE_ENA_IPAT; } else { if (card->info.type == QETH_CARD_TYPE_IQD) + /*FIXME:why do we have same values for dis and ena for osae??? */ card->info.func_level = QETH_IDX_FUNC_LEVEL_IQD_DIS_IPAT; else @@ -6124,7 +6331,7 @@ retry: ccw_device_set_online(CARD_WDEV(card)); ccw_device_set_online(CARD_DDEV(card)); } - rc = qeth_qdio_clear_card(card,card->info.type==QETH_CARD_TYPE_OSAE); + rc = qeth_qdio_clear_card(card,card->info.type!=QETH_CARD_TYPE_IQD); if (rc == -ERESTARTSYS) { QETH_DBF_TEXT(setup, 2, "break1"); return rc; @@ -6176,8 +6383,8 @@ retry: card->dev = qeth_get_netdevice(card->info.type, card->info.link_type); if (!card->dev){ - qeth_qdio_clear_card(card, card->info.type == - QETH_CARD_TYPE_OSAE); + qeth_qdio_clear_card(card, card->info.type != + QETH_CARD_TYPE_IQD); rc = -ENODEV; QETH_DBF_TEXT_(setup, 2, "6err%d", rc); goto out; @@ -7084,6 +7291,8 @@ qeth_softsetup_card(struct qeth_card *card) return rc; } else card->lan_online = 1; + if (card->info.type==QETH_CARD_TYPE_OSN) + goto out; if (card->options.layer2) { card->dev->features |= NETIF_F_HW_VLAN_FILTER | @@ -7255,7 +7464,8 @@ qeth_stop_card(struct qeth_card *card, int recovery_mode) if (card->read.state == CH_STATE_UP && card->write.state == CH_STATE_UP && (card->state == CARD_STATE_UP)) { - if(recovery_mode) { + if (recovery_mode && + card->info.type != QETH_CARD_TYPE_OSN) { qeth_stop(card->dev); } else { rtnl_lock(); @@ -7437,7 +7647,8 @@ qeth_start_again(struct qeth_card *card, int recovery_mode) { QETH_DBF_TEXT(setup ,2, "startag"); - if(recovery_mode) { + if (recovery_mode && + card->info.type != QETH_CARD_TYPE_OSN) { qeth_open(card->dev); } else { rtnl_lock(); @@ -7469,33 +7680,36 @@ qeth_start_again(struct qeth_card *card, int recovery_mode) static void qeth_make_parameters_consistent(struct qeth_card *card) { - if (card->options.layer2) { - if (card->info.type == QETH_CARD_TYPE_IQD) { - PRINT_ERR("Device %s does not support " \ - "layer 2 functionality. " \ - "Ignoring layer2 option.\n",CARD_BUS_ID(card)); - } - IGNORE_PARAM_NEQ(route4.type, NO_ROUTER, NO_ROUTER, - "Routing options are"); + if (card->options.layer2 == 0) + return; + if (card->info.type == QETH_CARD_TYPE_OSN) + return; + if (card->info.type == QETH_CARD_TYPE_IQD) { + PRINT_ERR("Device %s does not support layer 2 functionality." \ + " Ignoring layer2 option.\n",CARD_BUS_ID(card)); + card->options.layer2 = 0; + return; + } + IGNORE_PARAM_NEQ(route4.type, NO_ROUTER, NO_ROUTER, + "Routing options are"); #ifdef CONFIG_QETH_IPV6 - IGNORE_PARAM_NEQ(route6.type, NO_ROUTER, NO_ROUTER, - "Routing options are"); + IGNORE_PARAM_NEQ(route6.type, NO_ROUTER, NO_ROUTER, + "Routing options are"); #endif - IGNORE_PARAM_EQ(checksum_type, HW_CHECKSUMMING, - QETH_CHECKSUM_DEFAULT, - "Checksumming options are"); - IGNORE_PARAM_NEQ(broadcast_mode, QETH_TR_BROADCAST_ALLRINGS, - QETH_TR_BROADCAST_ALLRINGS, - "Broadcast mode options are"); - IGNORE_PARAM_NEQ(macaddr_mode, QETH_TR_MACADDR_NONCANONICAL, - QETH_TR_MACADDR_NONCANONICAL, - "Canonical MAC addr options are"); - IGNORE_PARAM_NEQ(fake_broadcast, 0, 0, - "Broadcast faking options are"); - IGNORE_PARAM_NEQ(add_hhlen, DEFAULT_ADD_HHLEN, - DEFAULT_ADD_HHLEN,"Option add_hhlen is"); - IGNORE_PARAM_NEQ(fake_ll, 0, 0,"Option fake_ll is"); - } + IGNORE_PARAM_EQ(checksum_type, HW_CHECKSUMMING, + QETH_CHECKSUM_DEFAULT, + "Checksumming options are"); + IGNORE_PARAM_NEQ(broadcast_mode, QETH_TR_BROADCAST_ALLRINGS, + QETH_TR_BROADCAST_ALLRINGS, + "Broadcast mode options are"); + IGNORE_PARAM_NEQ(macaddr_mode, QETH_TR_MACADDR_NONCANONICAL, + QETH_TR_MACADDR_NONCANONICAL, + "Canonical MAC addr options are"); + IGNORE_PARAM_NEQ(fake_broadcast, 0, 0, + "Broadcast faking options are"); + IGNORE_PARAM_NEQ(add_hhlen, DEFAULT_ADD_HHLEN, + DEFAULT_ADD_HHLEN,"Option add_hhlen is"); + IGNORE_PARAM_NEQ(fake_ll, 0, 0,"Option fake_ll is"); } @@ -7525,8 +7739,7 @@ __qeth_set_online(struct ccwgroup_device *gdev, int recovery_mode) return -EIO; } - if (card->options.layer2) - qeth_make_parameters_consistent(card); + qeth_make_parameters_consistent(card); if ((rc = qeth_hardsetup_card(card))){ QETH_DBF_TEXT_(setup, 2, "2err%d", rc); @@ -7585,6 +7798,7 @@ qeth_set_online(struct ccwgroup_device *gdev) static struct ccw_device_id qeth_ids[] = { {CCW_DEVICE(0x1731, 0x01), driver_info:QETH_CARD_TYPE_OSAE}, {CCW_DEVICE(0x1731, 0x05), driver_info:QETH_CARD_TYPE_IQD}, + {CCW_DEVICE(0x1731, 0x06), driver_info:QETH_CARD_TYPE_OSN}, {}, }; MODULE_DEVICE_TABLE(ccw, qeth_ids); @@ -8329,6 +8543,9 @@ again: printk("qeth: removed\n"); } +EXPORT_SYMBOL(qeth_osn_register); +EXPORT_SYMBOL(qeth_osn_deregister); +EXPORT_SYMBOL(qeth_osn_assist); module_init(qeth_init); module_exit(qeth_exit); MODULE_AUTHOR("Frank Pavlic <pavlic@de.ibm.com>"); diff --git a/drivers/s390/net/qeth_mpc.c b/drivers/s390/net/qeth_mpc.c index f685ecc7da99..30e053d3cac2 100644 --- a/drivers/s390/net/qeth_mpc.c +++ b/drivers/s390/net/qeth_mpc.c @@ -11,7 +11,7 @@ #include <asm/cio.h> #include "qeth_mpc.h" -const char *VERSION_QETH_MPC_C = "$Revision: 1.11 $"; +const char *VERSION_QETH_MPC_C = "$Revision: 1.12 $"; unsigned char IDX_ACTIVATE_READ[]={ 0x00,0x00,0x80,0x00, 0x00,0x00,0x00,0x00, @@ -138,7 +138,9 @@ unsigned char IPA_PDU_HEADER[]={ sizeof(struct qeth_ipa_cmd)%256, 0x00, sizeof(struct qeth_ipa_cmd)/256, - sizeof(struct qeth_ipa_cmd),0x05, 0x77,0x77,0x77,0x77, + sizeof(struct qeth_ipa_cmd)%256, + 0x05, + 0x77,0x77,0x77,0x77, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x01,0x00, sizeof(struct qeth_ipa_cmd)/256, diff --git a/drivers/s390/net/qeth_mpc.h b/drivers/s390/net/qeth_mpc.h index 3d916b5c5d09..7edc5f1fc0d2 100644 --- a/drivers/s390/net/qeth_mpc.h +++ b/drivers/s390/net/qeth_mpc.h @@ -46,13 +46,16 @@ extern unsigned char IPA_PDU_HEADER[]; /* IP Assist related definitions */ /*****************************************************************************/ #define IPA_CMD_INITIATOR_HOST 0x00 -#define IPA_CMD_INITIATOR_HYDRA 0x01 +#define IPA_CMD_INITIATOR_OSA 0x01 +#define IPA_CMD_INITIATOR_HOST_REPLY 0x80 +#define IPA_CMD_INITIATOR_OSA_REPLY 0x81 #define IPA_CMD_PRIM_VERSION_NO 0x01 enum qeth_card_types { QETH_CARD_TYPE_UNKNOWN = 0, QETH_CARD_TYPE_OSAE = 10, QETH_CARD_TYPE_IQD = 1234, + QETH_CARD_TYPE_OSN = 11, }; #define QETH_MPC_DIFINFO_LEN_INDICATES_LINK_TYPE 0x18 @@ -61,6 +64,7 @@ enum qeth_link_types { QETH_LINK_TYPE_FAST_ETH = 0x01, QETH_LINK_TYPE_HSTR = 0x02, QETH_LINK_TYPE_GBIT_ETH = 0x03, + QETH_LINK_TYPE_OSN = 0x04, QETH_LINK_TYPE_10GBIT_ETH = 0x10, QETH_LINK_TYPE_LANE_ETH100 = 0x81, QETH_LINK_TYPE_LANE_TR = 0x82, @@ -111,6 +115,9 @@ enum qeth_ipa_cmds { IPA_CMD_DELGMAC = 0x24, IPA_CMD_SETVLAN = 0x25, IPA_CMD_DELVLAN = 0x26, + IPA_CMD_SETCCID = 0x41, + IPA_CMD_DELCCID = 0x42, + IPA_CMD_MODCCID = 0x43, IPA_CMD_SETIP = 0xb1, IPA_CMD_DELIP = 0xb7, IPA_CMD_QIPASSIST = 0xb2, @@ -437,8 +444,9 @@ enum qeth_ipa_arp_return_codes { #define QETH_ARP_DATA_SIZE 3968 #define QETH_ARP_CMD_LEN (QETH_ARP_DATA_SIZE + 8) /* Helper functions */ -#define IS_IPA_REPLY(cmd) (cmd->hdr.initiator == IPA_CMD_INITIATOR_HOST) - +#define IS_IPA_REPLY(cmd) ((cmd->hdr.initiator == IPA_CMD_INITIATOR_HOST) || \ + (cmd->hdr.initiator == IPA_CMD_INITIATOR_OSA_REPLY)) + /*****************************************************************************/ /* END OF IP Assist related definitions */ /*****************************************************************************/ @@ -483,6 +491,7 @@ extern unsigned char ULP_ENABLE[]; /* Layer 2 defintions */ #define QETH_PROT_LAYER2 0x08 #define QETH_PROT_TCPIP 0x03 +#define QETH_PROT_OSN2 0x0a #define QETH_ULP_ENABLE_PROT_TYPE(buffer) (buffer+0x50) #define QETH_IPA_CMD_PROT_TYPE(buffer) (buffer+0x19) diff --git a/drivers/s390/net/qeth_sys.c b/drivers/s390/net/qeth_sys.c index dda105b73063..f91a02db5743 100644 --- a/drivers/s390/net/qeth_sys.c +++ b/drivers/s390/net/qeth_sys.c @@ -1,6 +1,6 @@ /* * - * linux/drivers/s390/net/qeth_sys.c ($Revision: 1.54 $) + * linux/drivers/s390/net/qeth_sys.c ($Revision: 1.55 $) * * Linux on zSeries OSA Express and HiperSockets support * This file contains code related to sysfs. @@ -20,7 +20,7 @@ #include "qeth_mpc.h" #include "qeth_fs.h" -const char *VERSION_QETH_SYS_C = "$Revision: 1.54 $"; +const char *VERSION_QETH_SYS_C = "$Revision: 1.55 $"; /*****************************************************************************/ /* */ @@ -937,6 +937,19 @@ static struct attribute_group qeth_device_attr_group = { .attrs = (struct attribute **)qeth_device_attrs, }; +static struct device_attribute * qeth_osn_device_attrs[] = { + &dev_attr_state, + &dev_attr_chpid, + &dev_attr_if_name, + &dev_attr_card_type, + &dev_attr_buffer_count, + &dev_attr_recover, + NULL, +}; + +static struct attribute_group qeth_osn_device_attr_group = { + .attrs = (struct attribute **)qeth_osn_device_attrs, +}; #define QETH_DEVICE_ATTR(_id,_name,_mode,_show,_store) \ struct device_attribute dev_attr_##_id = { \ @@ -1667,7 +1680,12 @@ int qeth_create_device_attributes(struct device *dev) { int ret; + struct qeth_card *card = dev->driver_data; + if (card->info.type == QETH_CARD_TYPE_OSN) + return sysfs_create_group(&dev->kobj, + &qeth_osn_device_attr_group); + if ((ret = sysfs_create_group(&dev->kobj, &qeth_device_attr_group))) return ret; if ((ret = sysfs_create_group(&dev->kobj, &qeth_device_ipato_group))){ @@ -1693,6 +1711,12 @@ qeth_create_device_attributes(struct device *dev) void qeth_remove_device_attributes(struct device *dev) { + struct qeth_card *card = dev->driver_data; + + if (card->info.type == QETH_CARD_TYPE_OSN) + return sysfs_remove_group(&dev->kobj, + &qeth_osn_device_attr_group); + sysfs_remove_group(&dev->kobj, &qeth_device_attr_group); sysfs_remove_group(&dev->kobj, &qeth_device_ipato_group); sysfs_remove_group(&dev->kobj, &qeth_device_vipa_group); diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 3ee9b8b33be0..9c9f162bd6ed 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -489,11 +489,11 @@ config SCSI_SATA_NV If unsure, say N. -config SCSI_SATA_PROMISE - tristate "Promise SATA TX2/TX4 support" +config SCSI_PDC_ADMA + tristate "Pacific Digital ADMA support" depends on SCSI_SATA && PCI help - This option enables support for Promise Serial ATA TX2/TX4. + This option enables support for Pacific Digital ADMA controllers If unsure, say N. @@ -505,6 +505,14 @@ config SCSI_SATA_QSTOR If unsure, say N. +config SCSI_SATA_PROMISE + tristate "Promise SATA TX2/TX4 support" + depends on SCSI_SATA && PCI + help + This option enables support for Promise Serial ATA TX2/TX4. + + If unsure, say N. + config SCSI_SATA_SX4 tristate "Promise SATA SX4 support" depends on SCSI_SATA && PCI && EXPERIMENTAL @@ -521,6 +529,14 @@ config SCSI_SATA_SIL If unsure, say N. +config SCSI_SATA_SIL24 + tristate "Silicon Image 3124/3132 SATA support" + depends on SCSI_SATA && PCI && EXPERIMENTAL + help + This option enables support for Silicon Image 3124/3132 Serial ATA. + + If unsure, say N. + config SCSI_SATA_SIS tristate "SiS 964/180 SATA support" depends on SCSI_SATA && PCI && EXPERIMENTAL diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index 48529d180ca8..2d4439826c08 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -130,6 +130,7 @@ obj-$(CONFIG_SCSI_ATA_PIIX) += libata.o ata_piix.o obj-$(CONFIG_SCSI_SATA_PROMISE) += libata.o sata_promise.o obj-$(CONFIG_SCSI_SATA_QSTOR) += libata.o sata_qstor.o obj-$(CONFIG_SCSI_SATA_SIL) += libata.o sata_sil.o +obj-$(CONFIG_SCSI_SATA_SIL24) += libata.o sata_sil24.o obj-$(CONFIG_SCSI_SATA_VIA) += libata.o sata_via.o obj-$(CONFIG_SCSI_SATA_VITESSE) += libata.o sata_vsc.o obj-$(CONFIG_SCSI_SATA_SIS) += libata.o sata_sis.o @@ -137,6 +138,7 @@ obj-$(CONFIG_SCSI_SATA_SX4) += libata.o sata_sx4.o obj-$(CONFIG_SCSI_SATA_NV) += libata.o sata_nv.o obj-$(CONFIG_SCSI_SATA_ULI) += libata.o sata_uli.o obj-$(CONFIG_SCSI_SATA_MV) += libata.o sata_mv.o +obj-$(CONFIG_SCSI_PDC_ADMA) += libata.o pdc_adma.o obj-$(CONFIG_ARM) += arm/ diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c index c2c8fa828e24..e2a5657d5fdb 100644 --- a/drivers/scsi/ahci.c +++ b/drivers/scsi/ahci.c @@ -41,6 +41,7 @@ #include <linux/interrupt.h> #include <linux/sched.h> #include <linux/dma-mapping.h> +#include <linux/device.h> #include "scsi.h" #include <scsi/scsi_host.h> #include <linux/libata.h> @@ -192,7 +193,6 @@ static void ahci_port_stop(struct ata_port *ap); static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf); static void ahci_qc_prep(struct ata_queued_cmd *qc); static u8 ahci_check_status(struct ata_port *ap); -static u8 ahci_check_err(struct ata_port *ap); static inline int ahci_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc); static void ahci_remove_one (struct pci_dev *pdev); @@ -216,12 +216,11 @@ static Scsi_Host_Template ahci_sht = { .ordered_flush = 1, }; -static struct ata_port_operations ahci_ops = { +static const struct ata_port_operations ahci_ops = { .port_disable = ata_port_disable, .check_status = ahci_check_status, .check_altstatus = ahci_check_status, - .check_err = ahci_check_err, .dev_select = ata_noop_dev_select, .tf_read = ahci_tf_read, @@ -407,7 +406,7 @@ static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg_in) return 0xffffffffU; } - return readl((void *) ap->ioaddr.scr_addr + (sc_reg * 4)); + return readl((void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4)); } @@ -425,7 +424,7 @@ static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg_in, return; } - writel(val, (void *) ap->ioaddr.scr_addr + (sc_reg * 4)); + writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4)); } static void ahci_phy_reset(struct ata_port *ap) @@ -453,18 +452,11 @@ static void ahci_phy_reset(struct ata_port *ap) static u8 ahci_check_status(struct ata_port *ap) { - void *mmio = (void *) ap->ioaddr.cmd_addr; + void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr; return readl(mmio + PORT_TFDATA) & 0xFF; } -static u8 ahci_check_err(struct ata_port *ap) -{ - void *mmio = (void *) ap->ioaddr.cmd_addr; - - return (readl(mmio + PORT_TFDATA) >> 8) & 0xFF; -} - static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf) { struct ahci_port_priv *pp = ap->private_data; @@ -609,7 +601,7 @@ static void ahci_eng_timeout(struct ata_port *ap) * not being called from the SCSI EH. */ qc->scsidone = scsi_finish_command; - ata_qc_complete(qc, ATA_ERR); + ata_qc_complete(qc, AC_ERR_OTHER); } spin_unlock_irqrestore(&host_set->lock, flags); @@ -638,7 +630,7 @@ static inline int ahci_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc) if (status & PORT_IRQ_FATAL) { ahci_intr_error(ap, status); if (qc) - ata_qc_complete(qc, ATA_ERR); + ata_qc_complete(qc, AC_ERR_OTHER); } return 1; @@ -672,17 +664,35 @@ static irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs * for (i = 0; i < host_set->n_ports; i++) { struct ata_port *ap; - u32 tmp; - VPRINTK("port %u\n", i); + if (!(irq_stat & (1 << i))) + continue; + ap = host_set->ports[i]; - tmp = irq_stat & (1 << i); - if (tmp && ap) { + if (ap) { struct ata_queued_cmd *qc; qc = ata_qc_from_tag(ap, ap->active_tag); - if (ahci_host_intr(ap, qc)) - irq_ack |= (1 << i); + if (!ahci_host_intr(ap, qc)) + if (ata_ratelimit()) { + struct pci_dev *pdev = + to_pci_dev(ap->host_set->dev); + dev_printk(KERN_WARNING, &pdev->dev, + "unhandled interrupt on port %u\n", + i); + } + + VPRINTK("port %u\n", i); + } else { + VPRINTK("port %u (no irq)\n", i); + if (ata_ratelimit()) { + struct pci_dev *pdev = + to_pci_dev(ap->host_set->dev); + dev_printk(KERN_WARNING, &pdev->dev, + "interrupt on disabled port %u\n", i); + } } + + irq_ack |= (1 << i); } if (irq_ack) { @@ -750,8 +760,8 @@ static int ahci_host_init(struct ata_probe_ent *probe_ent) tmp = readl(mmio + HOST_CTL); if (tmp & HOST_RESET) { - printk(KERN_ERR DRV_NAME "(%s): controller reset failed (0x%x)\n", - pci_name(pdev), tmp); + dev_printk(KERN_ERR, &pdev->dev, + "controller reset failed (0x%x)\n", tmp); return -EIO; } @@ -779,22 +789,22 @@ static int ahci_host_init(struct ata_probe_ent *probe_ent) if (rc) { rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); if (rc) { - printk(KERN_ERR DRV_NAME "(%s): 64-bit DMA enable failed\n", - pci_name(pdev)); + dev_printk(KERN_ERR, &pdev->dev, + "64-bit DMA enable failed\n"); return rc; } } } else { rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK); if (rc) { - printk(KERN_ERR DRV_NAME "(%s): 32-bit DMA enable failed\n", - pci_name(pdev)); + dev_printk(KERN_ERR, &pdev->dev, + "32-bit DMA enable failed\n"); return rc; } rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); if (rc) { - printk(KERN_ERR DRV_NAME "(%s): 32-bit consistent DMA enable failed\n", - pci_name(pdev)); + dev_printk(KERN_ERR, &pdev->dev, + "32-bit consistent DMA enable failed\n"); return rc; } } @@ -897,10 +907,10 @@ static void ahci_print_info(struct ata_probe_ent *probe_ent) else scc_s = "unknown"; - printk(KERN_INFO DRV_NAME "(%s) AHCI %02x%02x.%02x%02x " + dev_printk(KERN_INFO, &pdev->dev, + "AHCI %02x%02x.%02x%02x " "%u slots %u ports %s Gbps 0x%x impl %s mode\n" , - pci_name(pdev), (vers >> 24) & 0xff, (vers >> 16) & 0xff, @@ -913,11 +923,11 @@ static void ahci_print_info(struct ata_probe_ent *probe_ent) impl, scc_s); - printk(KERN_INFO DRV_NAME "(%s) flags: " + dev_printk(KERN_INFO, &pdev->dev, + "flags: " "%s%s%s%s%s%s" "%s%s%s%s%s%s%s\n" , - pci_name(pdev), cap & (1 << 31) ? "64bit " : "", cap & (1 << 30) ? "ncq " : "", @@ -950,7 +960,7 @@ static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) VPRINTK("ENTER\n"); if (!printed_version++) - printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); + dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); rc = pci_enable_device(pdev); if (rc) diff --git a/drivers/scsi/arm/scsi.h b/drivers/scsi/arm/scsi.h index 48e1c4d9738b..19937640e2e7 100644 --- a/drivers/scsi/arm/scsi.h +++ b/drivers/scsi/arm/scsi.h @@ -10,6 +10,8 @@ * Commonly used scsi driver functions. */ +#include <linux/scatterlist.h> + #define BELT_AND_BRACES /* @@ -22,9 +24,7 @@ static inline int copy_SCp_to_sg(struct scatterlist *sg, Scsi_Pointer *SCp, int BUG_ON(bufs + 1 > max); - sg->page = virt_to_page(SCp->ptr); - sg->offset = offset_in_page(SCp->ptr); - sg->length = SCp->this_residual; + sg_set_buf(sg, SCp->ptr, SCp->this_residual); if (bufs) memcpy(sg + 1, SCp->buffer + 1, diff --git a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c index d71cef767cec..7f8aa1b552ce 100644 --- a/drivers/scsi/ata_piix.c +++ b/drivers/scsi/ata_piix.c @@ -45,6 +45,7 @@ #include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> +#include <linux/device.h> #include "scsi.h" #include <scsi/scsi_host.h> #include <linux/libata.h> @@ -147,7 +148,7 @@ static Scsi_Host_Template piix_sht = { .ordered_flush = 1, }; -static struct ata_port_operations piix_pata_ops = { +static const struct ata_port_operations piix_pata_ops = { .port_disable = ata_port_disable, .set_piomode = piix_set_piomode, .set_dmamode = piix_set_dmamode, @@ -177,7 +178,7 @@ static struct ata_port_operations piix_pata_ops = { .host_stop = ata_host_stop, }; -static struct ata_port_operations piix_sata_ops = { +static const struct ata_port_operations piix_sata_ops = { .port_disable = ata_port_disable, .tf_load = ata_tf_load, @@ -621,18 +622,19 @@ static int piix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { static int printed_version; struct ata_port_info *port_info[2]; - unsigned int combined = 0, n_ports = 1; + unsigned int combined = 0; unsigned int pata_chan = 0, sata_chan = 0; if (!printed_version++) - printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); + dev_printk(KERN_DEBUG, &pdev->dev, + "version " DRV_VERSION "\n"); /* no hotplugging support (FIXME) */ if (!in_module_init) return -ENODEV; port_info[0] = &piix_port_info[ent->driver_data]; - port_info[1] = NULL; + port_info[1] = &piix_port_info[ent->driver_data]; if (port_info[0]->host_flags & PIIX_FLAG_AHCI) { u8 tmp; @@ -670,12 +672,13 @@ static int piix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) port_info[sata_chan] = &piix_port_info[ent->driver_data]; port_info[sata_chan]->host_flags |= ATA_FLAG_SLAVE_POSS; port_info[pata_chan] = &piix_port_info[ich5_pata]; - n_ports++; - printk(KERN_WARNING DRV_NAME ": combined mode detected\n"); + dev_printk(KERN_WARNING, &pdev->dev, + "combined mode detected (p=%u, s=%u)\n", + pata_chan, sata_chan); } - return ata_pci_init_one(pdev, port_info, n_ports); + return ata_pci_init_one(pdev, port_info, 2); } static int __init piix_init(void) diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c index da6e51c7fe69..540147cb51ce 100644 --- a/drivers/scsi/ch.c +++ b/drivers/scsi/ch.c @@ -936,7 +936,7 @@ static int ch_probe(struct device *dev) if (init) ch_init_elem(ch); - class_device_create(ch_sysfs_class, + class_device_create(ch_sysfs_class, NULL, MKDEV(SCSI_CHANGER_MAJOR,ch->minor), dev, "s%s", ch->name); diff --git a/drivers/scsi/dec_esp.c b/drivers/scsi/dec_esp.c index 315f95a0d6c0..4f39890b44ac 100644 --- a/drivers/scsi/dec_esp.c +++ b/drivers/scsi/dec_esp.c @@ -228,7 +228,7 @@ static int dec_esp_detect(Scsi_Host_Template * tpnt) mem_start = get_tc_base_addr(slot); /* Store base addr into esp struct */ - esp->slot = PHYSADDR(mem_start); + esp->slot = CPHYSADDR(mem_start); esp->dregs = 0; esp->eregs = (struct ESP_regs *) (mem_start + DEC_SCSI_SREG); diff --git a/drivers/scsi/eata.c b/drivers/scsi/eata.c index c10e45b94b62..3d13fdee4fc2 100644 --- a/drivers/scsi/eata.c +++ b/drivers/scsi/eata.c @@ -1357,7 +1357,7 @@ static int port_detect(unsigned long port_base, unsigned int j, for (i = 0; i < shost->can_queue; i++) { size_t sz = shost->sg_tablesize *sizeof(struct sg_list); - unsigned int gfp_mask = (shost->unchecked_isa_dma ? GFP_DMA : 0) | GFP_ATOMIC; + gfp_t gfp_mask = (shost->unchecked_isa_dma ? GFP_DMA : 0) | GFP_ATOMIC; ha->cp[i].sglist = kmalloc(sz, gfp_mask); if (!ha->cp[i].sglist) { printk diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 02fe371b0ab8..f24d84538fd5 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -287,7 +287,8 @@ static void scsi_host_dev_release(struct device *dev) struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize) { struct Scsi_Host *shost; - int gfp_mask = GFP_KERNEL, rval; + gfp_t gfp_mask = GFP_KERNEL; + int rval; if (sht->unchecked_isa_dma && privsize) gfp_mask |= __GFP_DMA; diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c index 3d62c9bcbff7..00d6a6657ebc 100644 --- a/drivers/scsi/ide-scsi.c +++ b/drivers/scsi/ide-scsi.c @@ -180,19 +180,12 @@ static void idescsi_input_buffers (ide_drive_t *drive, idescsi_pc_t *pc, unsigne return; } count = min(pc->sg->length - pc->b_count, bcount); - if (PageHighMem(pc->sg->page)) { - unsigned long flags; - - local_irq_save(flags); - buf = kmap_atomic(pc->sg->page, KM_IRQ0) + pc->sg->offset; - drive->hwif->atapi_input_bytes(drive, buf + pc->b_count, count); - kunmap_atomic(buf - pc->sg->offset, KM_IRQ0); - local_irq_restore(flags); - } else { - buf = page_address(pc->sg->page) + pc->sg->offset; - drive->hwif->atapi_input_bytes(drive, buf + pc->b_count, count); - } - bcount -= count; pc->b_count += count; + buf = kmap_atomic(pc->sg->page, KM_IRQ0); + drive->hwif->atapi_input_bytes(drive, + buf + pc->b_count + pc->sg->offset, count); + kunmap_atomic(buf, KM_IRQ0); + bcount -= count; + pc->b_count += count; if (pc->b_count == pc->sg->length) { pc->sg++; pc->b_count = 0; @@ -212,19 +205,12 @@ static void idescsi_output_buffers (ide_drive_t *drive, idescsi_pc_t *pc, unsign return; } count = min(pc->sg->length - pc->b_count, bcount); - if (PageHighMem(pc->sg->page)) { - unsigned long flags; - - local_irq_save(flags); - buf = kmap_atomic(pc->sg->page, KM_IRQ0) + pc->sg->offset; - drive->hwif->atapi_output_bytes(drive, buf + pc->b_count, count); - kunmap_atomic(buf - pc->sg->offset, KM_IRQ0); - local_irq_restore(flags); - } else { - buf = page_address(pc->sg->page) + pc->sg->offset; - drive->hwif->atapi_output_bytes(drive, buf + pc->b_count, count); - } - bcount -= count; pc->b_count += count; + buf = kmap_atomic(pc->sg->page, KM_IRQ0); + drive->hwif->atapi_output_bytes(drive, + buf + pc->b_count + pc->sg->offset, count); + kunmap_atomic(buf, KM_IRQ0); + bcount -= count; + pc->b_count += count; if (pc->b_count == pc->sg->length) { pc->sg++; pc->b_count = 0; diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index babd48363402..e0039dfae8e5 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -4944,6 +4944,7 @@ static int ipr_reset_restore_cfg_space(struct ipr_cmnd *ipr_cmd) int rc; ENTER; + pci_unblock_user_cfg_access(ioa_cfg->pdev); rc = pci_restore_state(ioa_cfg->pdev); if (rc != PCIBIOS_SUCCESSFUL) { @@ -4998,6 +4999,7 @@ static int ipr_reset_start_bist(struct ipr_cmnd *ipr_cmd) int rc; ENTER; + pci_block_user_cfg_access(ioa_cfg->pdev); rc = pci_write_config_byte(ioa_cfg->pdev, PCI_BIST, PCI_BIST_START); if (rc != PCIBIOS_SUCCESSFUL) { diff --git a/drivers/scsi/lasi700.c b/drivers/scsi/lasi700.c index 4cbb6187cc44..459a4daebece 100644 --- a/drivers/scsi/lasi700.c +++ b/drivers/scsi/lasi700.c @@ -98,7 +98,7 @@ MODULE_DEVICE_TABLE(parisc, lasi700_ids); static int __init lasi700_probe(struct parisc_device *dev) { - unsigned long base = dev->hpa + LASI_SCSI_CORE_OFFSET; + unsigned long base = dev->hpa.start + LASI_SCSI_CORE_OFFSET; struct NCR_700_Host_Parameters *hostdata; struct Scsi_Host *host; @@ -125,8 +125,6 @@ lasi700_probe(struct parisc_device *dev) hostdata->dmode_extra = DMODE_FC2; } - NCR_700_set_mem_mapped(hostdata); - host = NCR_700_detect(&lasi700_template, hostdata, &dev->dev); if (!host) goto out_kfree; @@ -168,7 +166,7 @@ lasi700_driver_remove(struct parisc_device *dev) } static struct parisc_driver lasi700_driver = { - .name = "Lasi SCSI", + .name = "lasi_scsi", .id_table = lasi700_ids, .probe = lasi700_probe, .remove = __devexit_p(lasi700_driver_remove), diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index e5b01997117a..8be7dc0b47b8 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -48,6 +48,8 @@ #include <linux/completion.h> #include <linux/suspend.h> #include <linux/workqueue.h> +#include <linux/jiffies.h> +#include <linux/scatterlist.h> #include <scsi/scsi.h> #include "scsi.h" #include "scsi_priv.h" @@ -62,14 +64,15 @@ static unsigned int ata_busy_sleep (struct ata_port *ap, unsigned long tmout_pat, unsigned long tmout); +static void ata_dev_reread_id(struct ata_port *ap, struct ata_device *dev); +static void ata_dev_init_params(struct ata_port *ap, struct ata_device *dev); static void ata_set_mode(struct ata_port *ap); static void ata_dev_set_xfermode(struct ata_port *ap, struct ata_device *dev); -static unsigned int ata_get_mode_mask(struct ata_port *ap, int shift); +static unsigned int ata_get_mode_mask(const struct ata_port *ap, int shift); static int fgb(u32 bitmap); -static int ata_choose_xfer_mode(struct ata_port *ap, +static int ata_choose_xfer_mode(const struct ata_port *ap, u8 *xfer_mode_out, unsigned int *xfer_shift_out); -static int ata_qc_complete_noop(struct ata_queued_cmd *qc, u8 drv_stat); static void __ata_qc_complete(struct ata_queued_cmd *qc); static unsigned int ata_unique_id = 1; @@ -85,7 +88,7 @@ MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_VERSION); /** - * ata_tf_load - send taskfile registers to host controller + * ata_tf_load_pio - send taskfile registers to host controller * @ap: Port to which output is sent * @tf: ATA taskfile register set * @@ -95,7 +98,7 @@ MODULE_VERSION(DRV_VERSION); * Inherited from caller. */ -static void ata_tf_load_pio(struct ata_port *ap, struct ata_taskfile *tf) +static void ata_tf_load_pio(struct ata_port *ap, const struct ata_taskfile *tf) { struct ata_ioports *ioaddr = &ap->ioaddr; unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; @@ -153,7 +156,7 @@ static void ata_tf_load_pio(struct ata_port *ap, struct ata_taskfile *tf) * Inherited from caller. */ -static void ata_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf) +static void ata_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf) { struct ata_ioports *ioaddr = &ap->ioaddr; unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; @@ -222,7 +225,7 @@ static void ata_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf) * LOCKING: * Inherited from caller. */ -void ata_tf_load(struct ata_port *ap, struct ata_taskfile *tf) +void ata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf) { if (ap->flags & ATA_FLAG_MMIO) ata_tf_load_mmio(ap, tf); @@ -242,7 +245,7 @@ void ata_tf_load(struct ata_port *ap, struct ata_taskfile *tf) * spin_lock_irqsave(host_set lock) */ -static void ata_exec_command_pio(struct ata_port *ap, struct ata_taskfile *tf) +static void ata_exec_command_pio(struct ata_port *ap, const struct ata_taskfile *tf) { DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command); @@ -263,7 +266,7 @@ static void ata_exec_command_pio(struct ata_port *ap, struct ata_taskfile *tf) * spin_lock_irqsave(host_set lock) */ -static void ata_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf) +static void ata_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf) { DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command); @@ -283,7 +286,7 @@ static void ata_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf) * LOCKING: * spin_lock_irqsave(host_set lock) */ -void ata_exec_command(struct ata_port *ap, struct ata_taskfile *tf) +void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf) { if (ap->flags & ATA_FLAG_MMIO) ata_exec_command_mmio(ap, tf); @@ -303,7 +306,7 @@ void ata_exec_command(struct ata_port *ap, struct ata_taskfile *tf) * Obtains host_set lock. */ -static inline void ata_exec(struct ata_port *ap, struct ata_taskfile *tf) +static inline void ata_exec(struct ata_port *ap, const struct ata_taskfile *tf) { unsigned long flags; @@ -326,7 +329,7 @@ static inline void ata_exec(struct ata_port *ap, struct ata_taskfile *tf) * Obtains host_set lock. */ -static void ata_tf_to_host(struct ata_port *ap, struct ata_taskfile *tf) +static void ata_tf_to_host(struct ata_port *ap, const struct ata_taskfile *tf) { ap->ops->tf_load(ap, tf); @@ -346,7 +349,7 @@ static void ata_tf_to_host(struct ata_port *ap, struct ata_taskfile *tf) * spin_lock_irqsave(host_set lock) */ -void ata_tf_to_host_nolock(struct ata_port *ap, struct ata_taskfile *tf) +void ata_tf_to_host_nolock(struct ata_port *ap, const struct ata_taskfile *tf) { ap->ops->tf_load(ap, tf); ap->ops->exec_command(ap, tf); @@ -368,6 +371,8 @@ static void ata_tf_read_pio(struct ata_port *ap, struct ata_taskfile *tf) { struct ata_ioports *ioaddr = &ap->ioaddr; + tf->command = ata_check_status(ap); + tf->feature = inb(ioaddr->error_addr); tf->nsect = inb(ioaddr->nsect_addr); tf->lbal = inb(ioaddr->lbal_addr); tf->lbam = inb(ioaddr->lbam_addr); @@ -400,6 +405,8 @@ static void ata_tf_read_mmio(struct ata_port *ap, struct ata_taskfile *tf) { struct ata_ioports *ioaddr = &ap->ioaddr; + tf->command = ata_check_status(ap); + tf->feature = readb((void __iomem *)ioaddr->error_addr); tf->nsect = readb((void __iomem *)ioaddr->nsect_addr); tf->lbal = readb((void __iomem *)ioaddr->lbal_addr); tf->lbam = readb((void __iomem *)ioaddr->lbam_addr); @@ -520,30 +527,6 @@ u8 ata_altstatus(struct ata_port *ap) /** - * ata_chk_err - Read device error reg - * @ap: port where the device is - * - * Reads ATA taskfile error register for - * currently-selected device and return its value. - * - * Note: may NOT be used as the check_err() entry in - * ata_port_operations. - * - * LOCKING: - * Inherited from caller. - */ -u8 ata_chk_err(struct ata_port *ap) -{ - if (ap->ops->check_err) - return ap->ops->check_err(ap); - - if (ap->flags & ATA_FLAG_MMIO) { - return readb((void __iomem *) ap->ioaddr.error_addr); - } - return inb(ap->ioaddr.error_addr); -} - -/** * ata_tf_to_fis - Convert ATA taskfile to SATA FIS structure * @tf: Taskfile to convert * @fis: Buffer into which data will output @@ -556,7 +539,7 @@ u8 ata_chk_err(struct ata_port *ap) * Inherited from caller. */ -void ata_tf_to_fis(struct ata_taskfile *tf, u8 *fis, u8 pmp) +void ata_tf_to_fis(const struct ata_taskfile *tf, u8 *fis, u8 pmp) { fis[0] = 0x27; /* Register - Host to Device FIS */ fis[1] = (pmp & 0xf) | (1 << 7); /* Port multiplier number, @@ -597,7 +580,7 @@ void ata_tf_to_fis(struct ata_taskfile *tf, u8 *fis, u8 pmp) * Inherited from caller. */ -void ata_tf_from_fis(u8 *fis, struct ata_taskfile *tf) +void ata_tf_from_fis(const u8 *fis, struct ata_taskfile *tf) { tf->command = fis[2]; /* status */ tf->feature = fis[3]; /* error */ @@ -615,79 +598,53 @@ void ata_tf_from_fis(u8 *fis, struct ata_taskfile *tf) tf->hob_nsect = fis[13]; } -/** - * ata_prot_to_cmd - determine which read/write opcodes to use - * @protocol: ATA_PROT_xxx taskfile protocol - * @lba48: true is lba48 is present - * - * Given necessary input, determine which read/write commands - * to use to transfer data. - * - * LOCKING: - * None. - */ -static int ata_prot_to_cmd(int protocol, int lba48) -{ - int rcmd = 0, wcmd = 0; - - switch (protocol) { - case ATA_PROT_PIO: - if (lba48) { - rcmd = ATA_CMD_PIO_READ_EXT; - wcmd = ATA_CMD_PIO_WRITE_EXT; - } else { - rcmd = ATA_CMD_PIO_READ; - wcmd = ATA_CMD_PIO_WRITE; - } - break; - - case ATA_PROT_DMA: - if (lba48) { - rcmd = ATA_CMD_READ_EXT; - wcmd = ATA_CMD_WRITE_EXT; - } else { - rcmd = ATA_CMD_READ; - wcmd = ATA_CMD_WRITE; - } - break; - - default: - return -1; - } - - return rcmd | (wcmd << 8); -} +static const u8 ata_rw_cmds[] = { + /* pio multi */ + ATA_CMD_READ_MULTI, + ATA_CMD_WRITE_MULTI, + ATA_CMD_READ_MULTI_EXT, + ATA_CMD_WRITE_MULTI_EXT, + /* pio */ + ATA_CMD_PIO_READ, + ATA_CMD_PIO_WRITE, + ATA_CMD_PIO_READ_EXT, + ATA_CMD_PIO_WRITE_EXT, + /* dma */ + ATA_CMD_READ, + ATA_CMD_WRITE, + ATA_CMD_READ_EXT, + ATA_CMD_WRITE_EXT +}; /** - * ata_dev_set_protocol - set taskfile protocol and r/w commands - * @dev: device to examine and configure + * ata_rwcmd_protocol - set taskfile r/w commands and protocol + * @qc: command to examine and configure * - * Examine the device configuration, after we have - * read the identify-device page and configured the - * data transfer mode. Set internal state related to - * the ATA taskfile protocol (pio, pio mult, dma, etc.) - * and calculate the proper read/write commands to use. + * Examine the device configuration and tf->flags to calculate + * the proper read/write commands and protocol to use. * * LOCKING: * caller. */ -static void ata_dev_set_protocol(struct ata_device *dev) +void ata_rwcmd_protocol(struct ata_queued_cmd *qc) { - int pio = (dev->flags & ATA_DFLAG_PIO); - int lba48 = (dev->flags & ATA_DFLAG_LBA48); - int proto, cmd; + struct ata_taskfile *tf = &qc->tf; + struct ata_device *dev = qc->dev; - if (pio) - proto = dev->xfer_protocol = ATA_PROT_PIO; - else - proto = dev->xfer_protocol = ATA_PROT_DMA; + int index, lba48, write; + + lba48 = (tf->flags & ATA_TFLAG_LBA48) ? 2 : 0; + write = (tf->flags & ATA_TFLAG_WRITE) ? 1 : 0; - cmd = ata_prot_to_cmd(proto, lba48); - if (cmd < 0) - BUG(); + if (dev->flags & ATA_DFLAG_PIO) { + tf->protocol = ATA_PROT_PIO; + index = dev->multi_count ? 0 : 4; + } else { + tf->protocol = ATA_PROT_DMA; + index = 8; + } - dev->read_cmd = cmd & 0xff; - dev->write_cmd = (cmd >> 8) & 0xff; + tf->command = ata_rw_cmds[index + lba48 + write]; } static const char * xfer_mode_str[] = { @@ -869,7 +826,7 @@ static unsigned int ata_devchk(struct ata_port *ap, * the event of failure. */ -unsigned int ata_dev_classify(struct ata_taskfile *tf) +unsigned int ata_dev_classify(const struct ata_taskfile *tf) { /* Apple's open source Darwin code hints that some devices only * put a proper signature into the LBA mid/high registers, @@ -921,8 +878,8 @@ static u8 ata_dev_try_classify(struct ata_port *ap, unsigned int device) memset(&tf, 0, sizeof(tf)); - err = ata_chk_err(ap); ap->ops->tf_read(ap, &tf); + err = tf.feature; dev->class = ATA_DEV_NONE; @@ -961,7 +918,7 @@ static u8 ata_dev_try_classify(struct ata_port *ap, unsigned int device) * caller. */ -void ata_dev_id_string(u16 *id, unsigned char *s, +void ata_dev_id_string(const u16 *id, unsigned char *s, unsigned int ofs, unsigned int len) { unsigned int c; @@ -1078,7 +1035,7 @@ void ata_dev_select(struct ata_port *ap, unsigned int device, * caller. */ -static inline void ata_dump_id(struct ata_device *dev) +static inline void ata_dump_id(const struct ata_device *dev) { DPRINTK("49==0x%04x " "53==0x%04x " @@ -1106,6 +1063,31 @@ static inline void ata_dump_id(struct ata_device *dev) dev->id[93]); } +/* + * Compute the PIO modes available for this device. This is not as + * trivial as it seems if we must consider early devices correctly. + * + * FIXME: pre IDE drive timing (do we care ?). + */ + +static unsigned int ata_pio_modes(const struct ata_device *adev) +{ + u16 modes; + + /* Usual case. Word 53 indicates word 88 is valid */ + if (adev->id[ATA_ID_FIELD_VALID] & (1 << 2)) { + modes = adev->id[ATA_ID_PIO_MODES] & 0x03; + modes <<= 3; + modes |= 0x7; + return modes; + } + + /* If word 88 isn't valid then Word 51 holds the PIO timing number + for the maximum. Turn it into a mask and return it */ + modes = (2 << (adev->id[ATA_ID_OLD_PIO_MODES] & 0xFF)) - 1 ; + return modes; +} + /** * ata_dev_identify - obtain IDENTIFY x DEVICE page * @ap: port on which device we wish to probe resides @@ -1131,10 +1113,9 @@ static inline void ata_dump_id(struct ata_device *dev) static void ata_dev_identify(struct ata_port *ap, unsigned int device) { struct ata_device *dev = &ap->device[device]; - unsigned int i; + unsigned int major_version; u16 tmp; unsigned long xfer_modes; - u8 status; unsigned int using_edd; DECLARE_COMPLETION(wait); struct ata_queued_cmd *qc; @@ -1188,8 +1169,11 @@ retry: else wait_for_completion(&wait); - status = ata_chk_status(ap); - if (status & ATA_ERR) { + spin_lock_irqsave(&ap->host_set->lock, flags); + ap->ops->tf_read(ap, &qc->tf); + spin_unlock_irqrestore(&ap->host_set->lock, flags); + + if (qc->tf.command & ATA_ERR) { /* * arg! EDD works for all test cases, but seems to return * the ATA signature for some ATAPI devices. Until the @@ -1202,7 +1186,7 @@ retry: * to have this problem. */ if ((using_edd) && (qc->tf.command == ATA_CMD_ID_ATA)) { - u8 err = ata_chk_err(ap); + u8 err = qc->tf.feature; if (err & ATA_ABORTED) { dev->class = ATA_DEV_ATAPI; qc->cursg = 0; @@ -1229,9 +1213,9 @@ retry: * common ATA, ATAPI feature tests */ - /* we require LBA and DMA support (bits 8 & 9 of word 49) */ - if (!ata_id_has_dma(dev->id) || !ata_id_has_lba(dev->id)) { - printk(KERN_DEBUG "ata%u: no dma/lba\n", ap->id); + /* we require DMA support (bits 8 of word 49) */ + if (!ata_id_has_dma(dev->id)) { + printk(KERN_DEBUG "ata%u: no dma\n", ap->id); goto err_out_nosup; } @@ -1239,10 +1223,8 @@ retry: xfer_modes = dev->id[ATA_ID_UDMA_MODES]; if (!xfer_modes) xfer_modes = (dev->id[ATA_ID_MWDMA_MODES]) << ATA_SHIFT_MWDMA; - if (!xfer_modes) { - xfer_modes = (dev->id[ATA_ID_PIO_MODES]) << (ATA_SHIFT_PIO + 3); - xfer_modes |= (0x7 << ATA_SHIFT_PIO); - } + if (!xfer_modes) + xfer_modes = ata_pio_modes(dev); ata_dump_id(dev); @@ -1251,32 +1233,75 @@ retry: if (!ata_id_is_ata(dev->id)) /* sanity check */ goto err_out_nosup; + /* get major version */ tmp = dev->id[ATA_ID_MAJOR_VER]; - for (i = 14; i >= 1; i--) - if (tmp & (1 << i)) + for (major_version = 14; major_version >= 1; major_version--) + if (tmp & (1 << major_version)) break; - /* we require at least ATA-3 */ - if (i < 3) { - printk(KERN_DEBUG "ata%u: no ATA-3\n", ap->id); - goto err_out_nosup; + /* + * The exact sequence expected by certain pre-ATA4 drives is: + * SRST RESET + * IDENTIFY + * INITIALIZE DEVICE PARAMETERS + * anything else.. + * Some drives were very specific about that exact sequence. + */ + if (major_version < 4 || (!ata_id_has_lba(dev->id))) { + ata_dev_init_params(ap, dev); + + /* current CHS translation info (id[53-58]) might be + * changed. reread the identify device info. + */ + ata_dev_reread_id(ap, dev); } - if (ata_id_has_lba48(dev->id)) { - dev->flags |= ATA_DFLAG_LBA48; - dev->n_sectors = ata_id_u64(dev->id, 100); - } else { - dev->n_sectors = ata_id_u32(dev->id, 60); + if (ata_id_has_lba(dev->id)) { + dev->flags |= ATA_DFLAG_LBA; + + if (ata_id_has_lba48(dev->id)) { + dev->flags |= ATA_DFLAG_LBA48; + dev->n_sectors = ata_id_u64(dev->id, 100); + } else { + dev->n_sectors = ata_id_u32(dev->id, 60); + } + + /* print device info to dmesg */ + printk(KERN_INFO "ata%u: dev %u ATA-%d, max %s, %Lu sectors:%s\n", + ap->id, device, + major_version, + ata_mode_string(xfer_modes), + (unsigned long long)dev->n_sectors, + dev->flags & ATA_DFLAG_LBA48 ? " LBA48" : " LBA"); + } else { + /* CHS */ + + /* Default translation */ + dev->cylinders = dev->id[1]; + dev->heads = dev->id[3]; + dev->sectors = dev->id[6]; + dev->n_sectors = dev->cylinders * dev->heads * dev->sectors; + + if (ata_id_current_chs_valid(dev->id)) { + /* Current CHS translation is valid. */ + dev->cylinders = dev->id[54]; + dev->heads = dev->id[55]; + dev->sectors = dev->id[56]; + + dev->n_sectors = ata_id_u32(dev->id, 57); + } + + /* print device info to dmesg */ + printk(KERN_INFO "ata%u: dev %u ATA-%d, max %s, %Lu sectors: CHS %d/%d/%d\n", + ap->id, device, + major_version, + ata_mode_string(xfer_modes), + (unsigned long long)dev->n_sectors, + (int)dev->cylinders, (int)dev->heads, (int)dev->sectors); + } ap->host->max_cmd_len = 16; - - /* print device info to dmesg */ - printk(KERN_INFO "ata%u: dev %u ATA, max %s, %Lu sectors:%s\n", - ap->id, device, - ata_mode_string(xfer_modes), - (unsigned long long)dev->n_sectors, - dev->flags & ATA_DFLAG_LBA48 ? " lba48" : ""); } /* ATAPI-specific feature tests */ @@ -1310,7 +1335,7 @@ err_out: } -static inline u8 ata_dev_knobble(struct ata_port *ap) +static inline u8 ata_dev_knobble(const struct ata_port *ap) { return ((ap->cbl == ATA_CBL_SATA) && (!ata_id_is_sata(ap->device->id))); } @@ -1496,7 +1521,153 @@ void ata_port_disable(struct ata_port *ap) ap->flags |= ATA_FLAG_PORT_DISABLED; } -static struct { +/* + * This mode timing computation functionality is ported over from + * drivers/ide/ide-timing.h and was originally written by Vojtech Pavlik + */ +/* + * PIO 0-5, MWDMA 0-2 and UDMA 0-6 timings (in nanoseconds). + * These were taken from ATA/ATAPI-6 standard, rev 0a, except + * for PIO 5, which is a nonstandard extension and UDMA6, which + * is currently supported only by Maxtor drives. + */ + +static const struct ata_timing ata_timing[] = { + + { XFER_UDMA_6, 0, 0, 0, 0, 0, 0, 0, 15 }, + { XFER_UDMA_5, 0, 0, 0, 0, 0, 0, 0, 20 }, + { XFER_UDMA_4, 0, 0, 0, 0, 0, 0, 0, 30 }, + { XFER_UDMA_3, 0, 0, 0, 0, 0, 0, 0, 45 }, + + { XFER_UDMA_2, 0, 0, 0, 0, 0, 0, 0, 60 }, + { XFER_UDMA_1, 0, 0, 0, 0, 0, 0, 0, 80 }, + { XFER_UDMA_0, 0, 0, 0, 0, 0, 0, 0, 120 }, + +/* { XFER_UDMA_SLOW, 0, 0, 0, 0, 0, 0, 0, 150 }, */ + + { XFER_MW_DMA_2, 25, 0, 0, 0, 70, 25, 120, 0 }, + { XFER_MW_DMA_1, 45, 0, 0, 0, 80, 50, 150, 0 }, + { XFER_MW_DMA_0, 60, 0, 0, 0, 215, 215, 480, 0 }, + + { XFER_SW_DMA_2, 60, 0, 0, 0, 120, 120, 240, 0 }, + { XFER_SW_DMA_1, 90, 0, 0, 0, 240, 240, 480, 0 }, + { XFER_SW_DMA_0, 120, 0, 0, 0, 480, 480, 960, 0 }, + +/* { XFER_PIO_5, 20, 50, 30, 100, 50, 30, 100, 0 }, */ + { XFER_PIO_4, 25, 70, 25, 120, 70, 25, 120, 0 }, + { XFER_PIO_3, 30, 80, 70, 180, 80, 70, 180, 0 }, + + { XFER_PIO_2, 30, 290, 40, 330, 100, 90, 240, 0 }, + { XFER_PIO_1, 50, 290, 93, 383, 125, 100, 383, 0 }, + { XFER_PIO_0, 70, 290, 240, 600, 165, 150, 600, 0 }, + +/* { XFER_PIO_SLOW, 120, 290, 240, 960, 290, 240, 960, 0 }, */ + + { 0xFF } +}; + +#define ENOUGH(v,unit) (((v)-1)/(unit)+1) +#define EZ(v,unit) ((v)?ENOUGH(v,unit):0) + +static void ata_timing_quantize(const struct ata_timing *t, struct ata_timing *q, int T, int UT) +{ + q->setup = EZ(t->setup * 1000, T); + q->act8b = EZ(t->act8b * 1000, T); + q->rec8b = EZ(t->rec8b * 1000, T); + q->cyc8b = EZ(t->cyc8b * 1000, T); + q->active = EZ(t->active * 1000, T); + q->recover = EZ(t->recover * 1000, T); + q->cycle = EZ(t->cycle * 1000, T); + q->udma = EZ(t->udma * 1000, UT); +} + +void ata_timing_merge(const struct ata_timing *a, const struct ata_timing *b, + struct ata_timing *m, unsigned int what) +{ + if (what & ATA_TIMING_SETUP ) m->setup = max(a->setup, b->setup); + if (what & ATA_TIMING_ACT8B ) m->act8b = max(a->act8b, b->act8b); + if (what & ATA_TIMING_REC8B ) m->rec8b = max(a->rec8b, b->rec8b); + if (what & ATA_TIMING_CYC8B ) m->cyc8b = max(a->cyc8b, b->cyc8b); + if (what & ATA_TIMING_ACTIVE ) m->active = max(a->active, b->active); + if (what & ATA_TIMING_RECOVER) m->recover = max(a->recover, b->recover); + if (what & ATA_TIMING_CYCLE ) m->cycle = max(a->cycle, b->cycle); + if (what & ATA_TIMING_UDMA ) m->udma = max(a->udma, b->udma); +} + +static const struct ata_timing* ata_timing_find_mode(unsigned short speed) +{ + const struct ata_timing *t; + + for (t = ata_timing; t->mode != speed; t++) + if (t->mode == 0xFF) + return NULL; + return t; +} + +int ata_timing_compute(struct ata_device *adev, unsigned short speed, + struct ata_timing *t, int T, int UT) +{ + const struct ata_timing *s; + struct ata_timing p; + + /* + * Find the mode. + */ + + if (!(s = ata_timing_find_mode(speed))) + return -EINVAL; + + /* + * If the drive is an EIDE drive, it can tell us it needs extended + * PIO/MW_DMA cycle timing. + */ + + if (adev->id[ATA_ID_FIELD_VALID] & 2) { /* EIDE drive */ + memset(&p, 0, sizeof(p)); + if(speed >= XFER_PIO_0 && speed <= XFER_SW_DMA_0) { + if (speed <= XFER_PIO_2) p.cycle = p.cyc8b = adev->id[ATA_ID_EIDE_PIO]; + else p.cycle = p.cyc8b = adev->id[ATA_ID_EIDE_PIO_IORDY]; + } else if(speed >= XFER_MW_DMA_0 && speed <= XFER_MW_DMA_2) { + p.cycle = adev->id[ATA_ID_EIDE_DMA_MIN]; + } + ata_timing_merge(&p, t, t, ATA_TIMING_CYCLE | ATA_TIMING_CYC8B); + } + + /* + * Convert the timing to bus clock counts. + */ + + ata_timing_quantize(s, t, T, UT); + + /* + * Even in DMA/UDMA modes we still use PIO access for IDENTIFY, S.M.A.R.T + * and some other commands. We have to ensure that the DMA cycle timing is + * slower/equal than the fastest PIO timing. + */ + + if (speed > XFER_PIO_4) { + ata_timing_compute(adev, adev->pio_mode, &p, T, UT); + ata_timing_merge(&p, t, t, ATA_TIMING_ALL); + } + + /* + * Lenghten active & recovery time so that cycle time is correct. + */ + + if (t->act8b + t->rec8b < t->cyc8b) { + t->act8b += (t->cyc8b - (t->act8b + t->rec8b)) / 2; + t->rec8b = t->cyc8b - t->act8b; + } + + if (t->active + t->recover < t->cycle) { + t->active += (t->cycle - (t->active + t->recover)) / 2; + t->recover = t->cycle - t->active; + } + + return 0; +} + +static const struct { unsigned int shift; u8 base; } xfer_mode_classes[] = { @@ -1603,7 +1774,7 @@ static void ata_host_set_dma(struct ata_port *ap, u8 xfer_mode, */ static void ata_set_mode(struct ata_port *ap) { - unsigned int i, xfer_shift; + unsigned int xfer_shift; u8 xfer_mode; int rc; @@ -1632,11 +1803,6 @@ static void ata_set_mode(struct ata_port *ap) if (ap->ops->post_set_mode) ap->ops->post_set_mode(ap); - for (i = 0; i < 2; i++) { - struct ata_device *dev = &ap->device[i]; - ata_dev_set_protocol(dev); - } - return; err_out: @@ -1910,7 +2076,8 @@ err_out: DPRINTK("EXIT\n"); } -static void ata_pr_blacklisted(struct ata_port *ap, struct ata_device *dev) +static void ata_pr_blacklisted(const struct ata_port *ap, + const struct ata_device *dev) { printk(KERN_WARNING "ata%u: dev %u is on DMA blacklist, disabling DMA\n", ap->id, dev->devno); @@ -1948,7 +2115,7 @@ static const char * ata_dma_blacklist [] = { "_NEC DV5800A", }; -static int ata_dma_blacklisted(struct ata_port *ap, struct ata_device *dev) +static int ata_dma_blacklisted(const struct ata_device *dev) { unsigned char model_num[40]; char *s; @@ -1973,9 +2140,9 @@ static int ata_dma_blacklisted(struct ata_port *ap, struct ata_device *dev) return 0; } -static unsigned int ata_get_mode_mask(struct ata_port *ap, int shift) +static unsigned int ata_get_mode_mask(const struct ata_port *ap, int shift) { - struct ata_device *master, *slave; + const struct ata_device *master, *slave; unsigned int mask; master = &ap->device[0]; @@ -1987,14 +2154,14 @@ static unsigned int ata_get_mode_mask(struct ata_port *ap, int shift) mask = ap->udma_mask; if (ata_dev_present(master)) { mask &= (master->id[ATA_ID_UDMA_MODES] & 0xff); - if (ata_dma_blacklisted(ap, master)) { + if (ata_dma_blacklisted(master)) { mask = 0; ata_pr_blacklisted(ap, master); } } if (ata_dev_present(slave)) { mask &= (slave->id[ATA_ID_UDMA_MODES] & 0xff); - if (ata_dma_blacklisted(ap, slave)) { + if (ata_dma_blacklisted(slave)) { mask = 0; ata_pr_blacklisted(ap, slave); } @@ -2004,14 +2171,14 @@ static unsigned int ata_get_mode_mask(struct ata_port *ap, int shift) mask = ap->mwdma_mask; if (ata_dev_present(master)) { mask &= (master->id[ATA_ID_MWDMA_MODES] & 0x07); - if (ata_dma_blacklisted(ap, master)) { + if (ata_dma_blacklisted(master)) { mask = 0; ata_pr_blacklisted(ap, master); } } if (ata_dev_present(slave)) { mask &= (slave->id[ATA_ID_MWDMA_MODES] & 0x07); - if (ata_dma_blacklisted(ap, slave)) { + if (ata_dma_blacklisted(slave)) { mask = 0; ata_pr_blacklisted(ap, slave); } @@ -2075,7 +2242,7 @@ static int fgb(u32 bitmap) * Zero on success, negative on error. */ -static int ata_choose_xfer_mode(struct ata_port *ap, +static int ata_choose_xfer_mode(const struct ata_port *ap, u8 *xfer_mode_out, unsigned int *xfer_shift_out) { @@ -2144,6 +2311,110 @@ static void ata_dev_set_xfermode(struct ata_port *ap, struct ata_device *dev) } /** + * ata_dev_reread_id - Reread the device identify device info + * @ap: port where the device is + * @dev: device to reread the identify device info + * + * LOCKING: + */ + +static void ata_dev_reread_id(struct ata_port *ap, struct ata_device *dev) +{ + DECLARE_COMPLETION(wait); + struct ata_queued_cmd *qc; + unsigned long flags; + int rc; + + qc = ata_qc_new_init(ap, dev); + BUG_ON(qc == NULL); + + ata_sg_init_one(qc, dev->id, sizeof(dev->id)); + qc->dma_dir = DMA_FROM_DEVICE; + + if (dev->class == ATA_DEV_ATA) { + qc->tf.command = ATA_CMD_ID_ATA; + DPRINTK("do ATA identify\n"); + } else { + qc->tf.command = ATA_CMD_ID_ATAPI; + DPRINTK("do ATAPI identify\n"); + } + + qc->tf.flags |= ATA_TFLAG_DEVICE; + qc->tf.protocol = ATA_PROT_PIO; + qc->nsect = 1; + + qc->waiting = &wait; + qc->complete_fn = ata_qc_complete_noop; + + spin_lock_irqsave(&ap->host_set->lock, flags); + rc = ata_qc_issue(qc); + spin_unlock_irqrestore(&ap->host_set->lock, flags); + + if (rc) + goto err_out; + + wait_for_completion(&wait); + + swap_buf_le16(dev->id, ATA_ID_WORDS); + + ata_dump_id(dev); + + DPRINTK("EXIT\n"); + + return; +err_out: + ata_port_disable(ap); +} + +/** + * ata_dev_init_params - Issue INIT DEV PARAMS command + * @ap: Port associated with device @dev + * @dev: Device to which command will be sent + * + * LOCKING: + */ + +static void ata_dev_init_params(struct ata_port *ap, struct ata_device *dev) +{ + DECLARE_COMPLETION(wait); + struct ata_queued_cmd *qc; + int rc; + unsigned long flags; + u16 sectors = dev->id[6]; + u16 heads = dev->id[3]; + + /* Number of sectors per track 1-255. Number of heads 1-16 */ + if (sectors < 1 || sectors > 255 || heads < 1 || heads > 16) + return; + + /* set up init dev params taskfile */ + DPRINTK("init dev params \n"); + + qc = ata_qc_new_init(ap, dev); + BUG_ON(qc == NULL); + + qc->tf.command = ATA_CMD_INIT_DEV_PARAMS; + qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + qc->tf.protocol = ATA_PROT_NODATA; + qc->tf.nsect = sectors; + qc->tf.device |= (heads - 1) & 0x0f; /* max head = num. of heads - 1 */ + + qc->waiting = &wait; + qc->complete_fn = ata_qc_complete_noop; + + spin_lock_irqsave(&ap->host_set->lock, flags); + rc = ata_qc_issue(qc); + spin_unlock_irqrestore(&ap->host_set->lock, flags); + + if (rc) + ata_port_disable(ap); + else + wait_for_completion(&wait); + + DPRINTK("EXIT\n"); +} + +/** * ata_sg_clean - Unmap DMA memory associated with command * @qc: Command containing DMA memory to be released * @@ -2284,19 +2555,12 @@ void ata_qc_prep(struct ata_queued_cmd *qc) void ata_sg_init_one(struct ata_queued_cmd *qc, void *buf, unsigned int buflen) { - struct scatterlist *sg; - qc->flags |= ATA_QCFLAG_SINGLE; - memset(&qc->sgent, 0, sizeof(qc->sgent)); qc->sg = &qc->sgent; qc->n_elem = 1; qc->buf_virt = buf; - - sg = qc->sg; - sg->page = virt_to_page(buf); - sg->offset = (unsigned long) buf & ~PAGE_MASK; - sg->length = buflen; + sg_init_one(qc->sg, buf, buflen); } /** @@ -2399,7 +2663,7 @@ static int ata_sg_setup(struct ata_queued_cmd *qc) * None. (grabs host lock) */ -void ata_poll_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) +void ata_poll_qc_complete(struct ata_queued_cmd *qc, unsigned int err_mask) { struct ata_port *ap = qc->ap; unsigned long flags; @@ -2407,38 +2671,38 @@ void ata_poll_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) spin_lock_irqsave(&ap->host_set->lock, flags); ap->flags &= ~ATA_FLAG_NOINTR; ata_irq_on(ap); - ata_qc_complete(qc, drv_stat); + ata_qc_complete(qc, err_mask); spin_unlock_irqrestore(&ap->host_set->lock, flags); } /** * ata_pio_poll - - * @ap: + * @ap: the target ata_port * * LOCKING: * None. (executing in kernel thread context) * * RETURNS: - * + * timeout value to use */ static unsigned long ata_pio_poll(struct ata_port *ap) { u8 status; - unsigned int poll_state = PIO_ST_UNKNOWN; - unsigned int reg_state = PIO_ST_UNKNOWN; - const unsigned int tmout_state = PIO_ST_TMOUT; - - switch (ap->pio_task_state) { - case PIO_ST: - case PIO_ST_POLL: - poll_state = PIO_ST_POLL; - reg_state = PIO_ST; + unsigned int poll_state = HSM_ST_UNKNOWN; + unsigned int reg_state = HSM_ST_UNKNOWN; + const unsigned int tmout_state = HSM_ST_TMOUT; + + switch (ap->hsm_task_state) { + case HSM_ST: + case HSM_ST_POLL: + poll_state = HSM_ST_POLL; + reg_state = HSM_ST; break; - case PIO_ST_LAST: - case PIO_ST_LAST_POLL: - poll_state = PIO_ST_LAST_POLL; - reg_state = PIO_ST_LAST; + case HSM_ST_LAST: + case HSM_ST_LAST_POLL: + poll_state = HSM_ST_LAST_POLL; + reg_state = HSM_ST_LAST; break; default: BUG(); @@ -2448,20 +2712,20 @@ static unsigned long ata_pio_poll(struct ata_port *ap) status = ata_chk_status(ap); if (status & ATA_BUSY) { if (time_after(jiffies, ap->pio_task_timeout)) { - ap->pio_task_state = tmout_state; + ap->hsm_task_state = tmout_state; return 0; } - ap->pio_task_state = poll_state; + ap->hsm_task_state = poll_state; return ATA_SHORT_PAUSE; } - ap->pio_task_state = reg_state; + ap->hsm_task_state = reg_state; return 0; } /** - * ata_pio_complete - - * @ap: + * ata_pio_complete - check if drive is busy or idle + * @ap: the target ata_port * * LOCKING: * None. (executing in kernel thread context) @@ -2480,14 +2744,14 @@ static int ata_pio_complete (struct ata_port *ap) * we enter, BSY will be cleared in a chk-status or two. If not, * the drive is probably seeking or something. Snooze for a couple * msecs, then chk-status again. If still busy, fall back to - * PIO_ST_POLL state. + * HSM_ST_POLL state. */ drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 10); if (drv_stat & (ATA_BUSY | ATA_DRQ)) { msleep(2); drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 10); if (drv_stat & (ATA_BUSY | ATA_DRQ)) { - ap->pio_task_state = PIO_ST_LAST_POLL; + ap->hsm_task_state = HSM_ST_LAST_POLL; ap->pio_task_timeout = jiffies + ATA_TMOUT_PIO; return 0; } @@ -2495,16 +2759,16 @@ static int ata_pio_complete (struct ata_port *ap) drv_stat = ata_wait_idle(ap); if (!ata_ok(drv_stat)) { - ap->pio_task_state = PIO_ST_ERR; + ap->hsm_task_state = HSM_ST_ERR; return 0; } qc = ata_qc_from_tag(ap, ap->active_tag); assert(qc != NULL); - ap->pio_task_state = PIO_ST_IDLE; + ap->hsm_task_state = HSM_ST_IDLE; - ata_poll_qc_complete(qc, drv_stat); + ata_poll_qc_complete(qc, 0); /* another command may start at this point */ @@ -2513,7 +2777,7 @@ static int ata_pio_complete (struct ata_port *ap) /** - * swap_buf_le16 - + * swap_buf_le16 - swap halves of 16-words in place * @buf: Buffer to swap * @buf_words: Number of 16-bit words in buffer. * @@ -2522,6 +2786,7 @@ static int ata_pio_complete (struct ata_port *ap) * vice-versa. * * LOCKING: + * Inherited from caller. */ void swap_buf_le16(u16 *buf, unsigned int buf_words) { @@ -2544,7 +2809,6 @@ void swap_buf_le16(u16 *buf, unsigned int buf_words) * * LOCKING: * Inherited from caller. - * */ static void ata_mmio_data_xfer(struct ata_port *ap, unsigned char *buf, @@ -2590,7 +2854,6 @@ static void ata_mmio_data_xfer(struct ata_port *ap, unsigned char *buf, * * LOCKING: * Inherited from caller. - * */ static void ata_pio_data_xfer(struct ata_port *ap, unsigned char *buf, @@ -2630,7 +2893,6 @@ static void ata_pio_data_xfer(struct ata_port *ap, unsigned char *buf, * * LOCKING: * Inherited from caller. - * */ static void ata_data_xfer(struct ata_port *ap, unsigned char *buf, @@ -2662,7 +2924,7 @@ static void ata_pio_sector(struct ata_queued_cmd *qc) unsigned char *buf; if (qc->cursect == (qc->nsect - 1)) - ap->pio_task_state = PIO_ST_LAST; + ap->hsm_task_state = HSM_ST_LAST; page = sg[qc->cursg].page; offset = sg[qc->cursg].offset + qc->cursg_ofs * ATA_SECT_SIZE; @@ -2712,7 +2974,7 @@ static void __atapi_pio_bytes(struct ata_queued_cmd *qc, unsigned int bytes) unsigned int offset, count; if (qc->curbytes + bytes >= qc->nbytes) - ap->pio_task_state = PIO_ST_LAST; + ap->hsm_task_state = HSM_ST_LAST; next_sg: if (unlikely(qc->cursg >= qc->n_elem)) { @@ -2734,7 +2996,7 @@ next_sg: for (i = 0; i < words; i++) ata_data_xfer(ap, (unsigned char*)pad_buf, 2, do_write); - ap->pio_task_state = PIO_ST_LAST; + ap->hsm_task_state = HSM_ST_LAST; return; } @@ -2783,7 +3045,6 @@ next_sg: * * LOCKING: * Inherited from caller. - * */ static void atapi_pio_bytes(struct ata_queued_cmd *qc) @@ -2815,12 +3076,12 @@ static void atapi_pio_bytes(struct ata_queued_cmd *qc) err_out: printk(KERN_INFO "ata%u: dev %u: ATAPI check failed\n", ap->id, dev->devno); - ap->pio_task_state = PIO_ST_ERR; + ap->hsm_task_state = HSM_ST_ERR; } /** - * ata_pio_sector - - * @ap: + * ata_pio_block - start PIO on a block + * @ap: the target ata_port * * LOCKING: * None. (executing in kernel thread context) @@ -2832,19 +3093,19 @@ static void ata_pio_block(struct ata_port *ap) u8 status; /* - * This is purely hueristic. This is a fast path. + * This is purely heuristic. This is a fast path. * Sometimes when we enter, BSY will be cleared in * a chk-status or two. If not, the drive is probably seeking * or something. Snooze for a couple msecs, then * chk-status again. If still busy, fall back to - * PIO_ST_POLL state. + * HSM_ST_POLL state. */ status = ata_busy_wait(ap, ATA_BUSY, 5); if (status & ATA_BUSY) { msleep(2); status = ata_busy_wait(ap, ATA_BUSY, 10); if (status & ATA_BUSY) { - ap->pio_task_state = PIO_ST_POLL; + ap->hsm_task_state = HSM_ST_POLL; ap->pio_task_timeout = jiffies + ATA_TMOUT_PIO; return; } @@ -2856,7 +3117,7 @@ static void ata_pio_block(struct ata_port *ap) if (is_atapi_taskfile(&qc->tf)) { /* no more data to transfer or unsupported ATAPI command */ if ((status & ATA_DRQ) == 0) { - ap->pio_task_state = PIO_ST_LAST; + ap->hsm_task_state = HSM_ST_LAST; return; } @@ -2864,7 +3125,7 @@ static void ata_pio_block(struct ata_port *ap) } else { /* handle BSY=0, DRQ=0 as error */ if ((status & ATA_DRQ) == 0) { - ap->pio_task_state = PIO_ST_ERR; + ap->hsm_task_state = HSM_ST_ERR; return; } @@ -2875,18 +3136,15 @@ static void ata_pio_block(struct ata_port *ap) static void ata_pio_error(struct ata_port *ap) { struct ata_queued_cmd *qc; - u8 drv_stat; + + printk(KERN_WARNING "ata%u: PIO error\n", ap->id); qc = ata_qc_from_tag(ap, ap->active_tag); assert(qc != NULL); - drv_stat = ata_chk_status(ap); - printk(KERN_WARNING "ata%u: PIO error, drv_stat 0x%x\n", - ap->id, drv_stat); - - ap->pio_task_state = PIO_ST_IDLE; + ap->hsm_task_state = HSM_ST_IDLE; - ata_poll_qc_complete(qc, drv_stat | ATA_ERR); + ata_poll_qc_complete(qc, AC_ERR_ATA_BUS); } static void ata_pio_task(void *_data) @@ -2899,25 +3157,25 @@ fsm_start: timeout = 0; qc_completed = 0; - switch (ap->pio_task_state) { - case PIO_ST_IDLE: + switch (ap->hsm_task_state) { + case HSM_ST_IDLE: return; - case PIO_ST: + case HSM_ST: ata_pio_block(ap); break; - case PIO_ST_LAST: + case HSM_ST_LAST: qc_completed = ata_pio_complete(ap); break; - case PIO_ST_POLL: - case PIO_ST_LAST_POLL: + case HSM_ST_POLL: + case HSM_ST_LAST_POLL: timeout = ata_pio_poll(ap); break; - case PIO_ST_TMOUT: - case PIO_ST_ERR: + case HSM_ST_TMOUT: + case HSM_ST_ERR: ata_pio_error(ap); return; } @@ -2928,52 +3186,6 @@ fsm_start: goto fsm_start; } -static void atapi_request_sense(struct ata_port *ap, struct ata_device *dev, - struct scsi_cmnd *cmd) -{ - DECLARE_COMPLETION(wait); - struct ata_queued_cmd *qc; - unsigned long flags; - int rc; - - DPRINTK("ATAPI request sense\n"); - - qc = ata_qc_new_init(ap, dev); - BUG_ON(qc == NULL); - - /* FIXME: is this needed? */ - memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer)); - - ata_sg_init_one(qc, cmd->sense_buffer, sizeof(cmd->sense_buffer)); - qc->dma_dir = DMA_FROM_DEVICE; - - memset(&qc->cdb, 0, ap->cdb_len); - qc->cdb[0] = REQUEST_SENSE; - qc->cdb[4] = SCSI_SENSE_BUFFERSIZE; - - qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; - qc->tf.command = ATA_CMD_PACKET; - - qc->tf.protocol = ATA_PROT_ATAPI; - qc->tf.lbam = (8 * 1024) & 0xff; - qc->tf.lbah = (8 * 1024) >> 8; - qc->nbytes = SCSI_SENSE_BUFFERSIZE; - - qc->waiting = &wait; - qc->complete_fn = ata_qc_complete_noop; - - spin_lock_irqsave(&ap->host_set->lock, flags); - rc = ata_qc_issue(qc); - spin_unlock_irqrestore(&ap->host_set->lock, flags); - - if (rc) - ata_port_disable(ap); - else - wait_for_completion(&wait); - - DPRINTK("EXIT\n"); -} - /** * ata_qc_timeout - Handle timeout of queued command * @qc: Command that timed out @@ -3055,7 +3267,7 @@ static void ata_qc_timeout(struct ata_queued_cmd *qc) ap->id, qc->tf.command, drv_stat, host_stat); /* complete taskfile transaction */ - ata_qc_complete(qc, drv_stat); + ata_qc_complete(qc, ac_err_mask(drv_stat)); break; } @@ -3091,14 +3303,14 @@ void ata_eng_timeout(struct ata_port *ap) DPRINTK("ENTER\n"); qc = ata_qc_from_tag(ap, ap->active_tag); - if (!qc) { + if (qc) + ata_qc_timeout(qc); + else { printk(KERN_ERR "ata%u: BUG: timeout without command\n", ap->id); goto out; } - ata_qc_timeout(qc); - out: DPRINTK("EXIT\n"); } @@ -3155,15 +3367,12 @@ struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap, qc->nbytes = qc->curbytes = 0; ata_tf_init(ap, &qc->tf, dev->devno); - - if (dev->flags & ATA_DFLAG_LBA48) - qc->tf.flags |= ATA_TFLAG_LBA48; } return qc; } -static int ata_qc_complete_noop(struct ata_queued_cmd *qc, u8 drv_stat) +int ata_qc_complete_noop(struct ata_queued_cmd *qc, unsigned int err_mask) { return 0; } @@ -3201,7 +3410,6 @@ static void __ata_qc_complete(struct ata_queued_cmd *qc) * * LOCKING: * spin_lock_irqsave(host_set lock) - * */ void ata_qc_free(struct ata_queued_cmd *qc) { @@ -3221,10 +3429,9 @@ void ata_qc_free(struct ata_queued_cmd *qc) * * LOCKING: * spin_lock_irqsave(host_set lock) - * */ -void ata_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) +void ata_qc_complete(struct ata_queued_cmd *qc, unsigned int err_mask) { int rc; @@ -3241,7 +3448,7 @@ void ata_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) qc->flags &= ~ATA_QCFLAG_ACTIVE; /* call completion callback */ - rc = qc->complete_fn(qc, drv_stat); + rc = qc->complete_fn(qc, err_mask); /* if callback indicates not to complete command (non-zero), * return immediately @@ -3360,7 +3567,7 @@ int ata_qc_issue_prot(struct ata_queued_cmd *qc) case ATA_PROT_PIO: /* load tf registers, initiate polling pio */ ata_qc_set_polling(qc); ata_tf_to_host_nolock(ap, &qc->tf); - ap->pio_task_state = PIO_ST; + ap->hsm_task_state = HSM_ST; queue_work(ata_wq, &ap->pio_task); break; @@ -3586,7 +3793,7 @@ u8 ata_bmdma_status(struct ata_port *ap) void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr; host_stat = readb(mmio + ATA_DMA_STATUS); } else - host_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); + host_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); return host_stat; } @@ -3679,7 +3886,7 @@ inline unsigned int ata_host_intr (struct ata_port *ap, ap->ops->irq_clear(ap); /* complete taskfile transaction */ - ata_qc_complete(qc, status); + ata_qc_complete(qc, ac_err_mask(status)); break; default: @@ -3715,7 +3922,6 @@ idle_irq: * * RETURNS: * IRQ_NONE or IRQ_HANDLED. - * */ irqreturn_t ata_interrupt (int irq, void *dev_instance, struct pt_regs *regs) @@ -3775,7 +3981,7 @@ static void atapi_packet_task(void *_data) /* sleep-wait for BSY to clear */ DPRINTK("busy wait\n"); if (ata_busy_sleep(ap, ATA_TMOUT_CDB_QUICK, ATA_TMOUT_CDB)) - goto err_out; + goto err_out_status; /* make sure DRQ is set */ status = ata_chk_status(ap); @@ -3806,14 +4012,16 @@ static void atapi_packet_task(void *_data) ata_data_xfer(ap, qc->cdb, ap->cdb_len, 1); /* PIO commands are handled by polling */ - ap->pio_task_state = PIO_ST; + ap->hsm_task_state = HSM_ST; queue_work(ata_wq, &ap->pio_task); } return; +err_out_status: + status = ata_chk_status(ap); err_out: - ata_poll_qc_complete(qc, ATA_ERR); + ata_poll_qc_complete(qc, __ac_err_mask(status)); } @@ -3827,6 +4035,7 @@ err_out: * May be used as the port_start() entry in ata_port_operations. * * LOCKING: + * Inherited from caller. */ int ata_port_start (struct ata_port *ap) @@ -3852,6 +4061,7 @@ int ata_port_start (struct ata_port *ap) * May be used as the port_stop() entry in ata_port_operations. * * LOCKING: + * Inherited from caller. */ void ata_port_stop (struct ata_port *ap) @@ -3874,6 +4084,7 @@ void ata_host_stop (struct ata_host_set *host_set) * @do_unregister: 1 if we fully unregister, 0 to just stop the port * * LOCKING: + * Inherited from caller. */ static void ata_host_remove(struct ata_port *ap, unsigned int do_unregister) @@ -3901,12 +4112,11 @@ static void ata_host_remove(struct ata_port *ap, unsigned int do_unregister) * * LOCKING: * Inherited from caller. - * */ static void ata_host_init(struct ata_port *ap, struct Scsi_Host *host, struct ata_host_set *host_set, - struct ata_probe_ent *ent, unsigned int port_no) + const struct ata_probe_ent *ent, unsigned int port_no) { unsigned int i; @@ -3962,10 +4172,9 @@ static void ata_host_init(struct ata_port *ap, struct Scsi_Host *host, * * RETURNS: * New ata_port on success, for NULL on error. - * */ -static struct ata_port * ata_host_add(struct ata_probe_ent *ent, +static struct ata_port * ata_host_add(const struct ata_probe_ent *ent, struct ata_host_set *host_set, unsigned int port_no) { @@ -4010,10 +4219,9 @@ err_out: * * RETURNS: * Number of ports registered. Zero on error (no ports registered). - * */ -int ata_device_add(struct ata_probe_ent *ent) +int ata_device_add(const struct ata_probe_ent *ent) { unsigned int count = 0, i; struct device *dev = ent->dev; @@ -4021,11 +4229,10 @@ int ata_device_add(struct ata_probe_ent *ent) DPRINTK("ENTER\n"); /* alloc a container for our list of ATA ports (buses) */ - host_set = kmalloc(sizeof(struct ata_host_set) + + host_set = kzalloc(sizeof(struct ata_host_set) + (ent->n_ports * sizeof(void *)), GFP_KERNEL); if (!host_set) return 0; - memset(host_set, 0, sizeof(struct ata_host_set) + (ent->n_ports * sizeof(void *))); spin_lock_init(&host_set->lock); host_set->dev = dev; @@ -4065,10 +4272,8 @@ int ata_device_add(struct ata_probe_ent *ent) count++; } - if (!count) { - kfree(host_set); - return 0; - } + if (!count) + goto err_free_ret; /* obtain irq, that is shared between channels */ if (request_irq(ent->irq, ent->port_ops->irq_handler, ent->irq_flags, @@ -4113,7 +4318,7 @@ int ata_device_add(struct ata_probe_ent *ent) for (i = 0; i < count; i++) { struct ata_port *ap = host_set->ports[i]; - scsi_scan_host(ap->host); + ata_scsi_scan_host(ap); } dev_set_drvdata(dev, host_set); @@ -4126,6 +4331,7 @@ err_out: ata_host_remove(host_set->ports[i], 1); scsi_host_put(host_set->ports[i]->host); } +err_free_ret: kfree(host_set); VPRINTK("EXIT, returning 0\n"); return 0; @@ -4142,7 +4348,6 @@ err_out: * Inherited from calling layer (may sleep). */ - void ata_host_set_remove(struct ata_host_set *host_set) { struct ata_port *ap; @@ -4232,19 +4437,17 @@ void ata_std_ports(struct ata_ioports *ioaddr) } static struct ata_probe_ent * -ata_probe_ent_alloc(struct device *dev, struct ata_port_info *port) +ata_probe_ent_alloc(struct device *dev, const struct ata_port_info *port) { struct ata_probe_ent *probe_ent; - probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL); + probe_ent = kzalloc(sizeof(*probe_ent), GFP_KERNEL); if (!probe_ent) { printk(KERN_ERR DRV_NAME "(%s): out of memory\n", kobject_name(&(dev->kobj))); return NULL; } - memset(probe_ent, 0, sizeof(*probe_ent)); - INIT_LIST_HEAD(&probe_ent->node); probe_ent->dev = dev; @@ -4273,85 +4476,86 @@ void ata_pci_host_stop (struct ata_host_set *host_set) * ata_pci_init_native_mode - Initialize native-mode driver * @pdev: pci device to be initialized * @port: array[2] of pointers to port info structures. + * @ports: bitmap of ports present * * Utility function which allocates and initializes an * ata_probe_ent structure for a standard dual-port * PIO-based IDE controller. The returned ata_probe_ent * structure can be passed to ata_device_add(). The returned * ata_probe_ent structure should then be freed with kfree(). + * + * The caller need only pass the address of the primary port, the + * secondary will be deduced automatically. If the device has non + * standard secondary port mappings this function can be called twice, + * once for each interface. */ struct ata_probe_ent * -ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port) +ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int ports) { struct ata_probe_ent *probe_ent = ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[0]); + int p = 0; + if (!probe_ent) return NULL; - probe_ent->n_ports = 2; probe_ent->irq = pdev->irq; probe_ent->irq_flags = SA_SHIRQ; - probe_ent->port[0].cmd_addr = pci_resource_start(pdev, 0); - probe_ent->port[0].altstatus_addr = - probe_ent->port[0].ctl_addr = - pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS; - probe_ent->port[0].bmdma_addr = pci_resource_start(pdev, 4); - - probe_ent->port[1].cmd_addr = pci_resource_start(pdev, 2); - probe_ent->port[1].altstatus_addr = - probe_ent->port[1].ctl_addr = - pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS; - probe_ent->port[1].bmdma_addr = pci_resource_start(pdev, 4) + 8; + if (ports & ATA_PORT_PRIMARY) { + probe_ent->port[p].cmd_addr = pci_resource_start(pdev, 0); + probe_ent->port[p].altstatus_addr = + probe_ent->port[p].ctl_addr = + pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS; + probe_ent->port[p].bmdma_addr = pci_resource_start(pdev, 4); + ata_std_ports(&probe_ent->port[p]); + p++; + } - ata_std_ports(&probe_ent->port[0]); - ata_std_ports(&probe_ent->port[1]); + if (ports & ATA_PORT_SECONDARY) { + probe_ent->port[p].cmd_addr = pci_resource_start(pdev, 2); + probe_ent->port[p].altstatus_addr = + probe_ent->port[p].ctl_addr = + pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS; + probe_ent->port[p].bmdma_addr = pci_resource_start(pdev, 4) + 8; + ata_std_ports(&probe_ent->port[p]); + p++; + } + probe_ent->n_ports = p; return probe_ent; } -static struct ata_probe_ent * -ata_pci_init_legacy_mode(struct pci_dev *pdev, struct ata_port_info **port, - struct ata_probe_ent **ppe2) +static struct ata_probe_ent *ata_pci_init_legacy_port(struct pci_dev *pdev, struct ata_port_info *port, int port_num) { - struct ata_probe_ent *probe_ent, *probe_ent2; + struct ata_probe_ent *probe_ent; - probe_ent = ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[0]); + probe_ent = ata_probe_ent_alloc(pci_dev_to_dev(pdev), port); if (!probe_ent) return NULL; - probe_ent2 = ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[1]); - if (!probe_ent2) { - kfree(probe_ent); - return NULL; - } - - probe_ent->n_ports = 1; - probe_ent->irq = 14; - probe_ent->hard_port_no = 0; probe_ent->legacy_mode = 1; - - probe_ent2->n_ports = 1; - probe_ent2->irq = 15; - - probe_ent2->hard_port_no = 1; - probe_ent2->legacy_mode = 1; - - probe_ent->port[0].cmd_addr = 0x1f0; - probe_ent->port[0].altstatus_addr = - probe_ent->port[0].ctl_addr = 0x3f6; - probe_ent->port[0].bmdma_addr = pci_resource_start(pdev, 4); - - probe_ent2->port[0].cmd_addr = 0x170; - probe_ent2->port[0].altstatus_addr = - probe_ent2->port[0].ctl_addr = 0x376; - probe_ent2->port[0].bmdma_addr = pci_resource_start(pdev, 4)+8; - + probe_ent->n_ports = 1; + probe_ent->hard_port_no = port_num; + + switch(port_num) + { + case 0: + probe_ent->irq = 14; + probe_ent->port[0].cmd_addr = 0x1f0; + probe_ent->port[0].altstatus_addr = + probe_ent->port[0].ctl_addr = 0x3f6; + break; + case 1: + probe_ent->irq = 15; + probe_ent->port[0].cmd_addr = 0x170; + probe_ent->port[0].altstatus_addr = + probe_ent->port[0].ctl_addr = 0x376; + break; + } + probe_ent->port[0].bmdma_addr = pci_resource_start(pdev, 4) + 8 * port_num; ata_std_ports(&probe_ent->port[0]); - ata_std_ports(&probe_ent2->port[0]); - - *ppe2 = probe_ent2; return probe_ent; } @@ -4374,13 +4578,12 @@ ata_pci_init_legacy_mode(struct pci_dev *pdev, struct ata_port_info **port, * * RETURNS: * Zero on success, negative on errno-based value on error. - * */ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info, unsigned int n_ports) { - struct ata_probe_ent *probe_ent, *probe_ent2 = NULL; + struct ata_probe_ent *probe_ent = NULL, *probe_ent2 = NULL; struct ata_port_info *port[2]; u8 tmp8, mask; unsigned int legacy_mode = 0; @@ -4397,7 +4600,7 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info, if ((port[0]->host_flags & ATA_FLAG_NO_LEGACY) == 0 && (pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) { - /* TODO: support transitioning to native mode? */ + /* TODO: What if one channel is in native mode ... */ pci_read_config_byte(pdev, PCI_CLASS_PROG, &tmp8); mask = (1 << 2) | (1 << 0); if ((tmp8 & mask) != mask) @@ -4405,11 +4608,20 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info, } /* FIXME... */ - if ((!legacy_mode) && (n_ports > 1)) { - printk(KERN_ERR "ata: BUG: native mode, n_ports > 1\n"); - return -EINVAL; + if ((!legacy_mode) && (n_ports > 2)) { + printk(KERN_ERR "ata: BUG: native mode, n_ports > 2\n"); + n_ports = 2; + /* For now */ } + /* FIXME: Really for ATA it isn't safe because the device may be + multi-purpose and we want to leave it alone if it was already + enabled. Secondly for shared use as Arjan says we want refcounting + + Checking dev->is_enabled is insufficient as this is not set at + boot for the primary video which is BIOS enabled + */ + rc = pci_enable_device(pdev); if (rc) return rc; @@ -4420,6 +4632,7 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info, goto err_out; } + /* FIXME: Should use platform specific mappers for legacy port ranges */ if (legacy_mode) { if (!request_region(0x1f0, 8, "libata")) { struct resource *conflict, res; @@ -4464,10 +4677,17 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info, goto err_out_regions; if (legacy_mode) { - probe_ent = ata_pci_init_legacy_mode(pdev, port, &probe_ent2); - } else - probe_ent = ata_pci_init_native_mode(pdev, port); - if (!probe_ent) { + if (legacy_mode & (1 << 0)) + probe_ent = ata_pci_init_legacy_port(pdev, port[0], 0); + if (legacy_mode & (1 << 1)) + probe_ent2 = ata_pci_init_legacy_port(pdev, port[1], 1); + } else { + if (n_ports == 2) + probe_ent = ata_pci_init_native_mode(pdev, port, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY); + else + probe_ent = ata_pci_init_native_mode(pdev, port, ATA_PORT_PRIMARY); + } + if (!probe_ent && !probe_ent2) { rc = -ENOMEM; goto err_out_regions; } @@ -4505,7 +4725,7 @@ err_out: * @pdev: PCI device that was removed * * PCI layer indicates to libata via this hook that - * hot-unplug or module unload event has occured. + * hot-unplug or module unload event has occurred. * Handle this by unregistering all objects associated * with this PCI device. Free those objects. Then finally * release PCI resources and disable device. @@ -4526,7 +4746,7 @@ void ata_pci_remove_one (struct pci_dev *pdev) } /* move to PCI subsystem */ -int pci_test_config_bits(struct pci_dev *pdev, struct pci_bits *bits) +int pci_test_config_bits(struct pci_dev *pdev, const struct pci_bits *bits) { unsigned long tmp = 0; @@ -4579,6 +4799,27 @@ static void __exit ata_exit(void) module_init(ata_init); module_exit(ata_exit); +static unsigned long ratelimit_time; +static spinlock_t ata_ratelimit_lock = SPIN_LOCK_UNLOCKED; + +int ata_ratelimit(void) +{ + int rc; + unsigned long flags; + + spin_lock_irqsave(&ata_ratelimit_lock, flags); + + if (time_after(jiffies, ratelimit_time)) { + rc = 1; + ratelimit_time = jiffies + (HZ/5); + } else + rc = 0; + + spin_unlock_irqrestore(&ata_ratelimit_lock, flags); + + return rc; +} + /* * libata is essentially a library of internal helper functions for * low-level ATA host controller drivers. As such, the API/ABI is @@ -4603,7 +4844,6 @@ EXPORT_SYMBOL_GPL(ata_tf_to_fis); EXPORT_SYMBOL_GPL(ata_tf_from_fis); EXPORT_SYMBOL_GPL(ata_check_status); EXPORT_SYMBOL_GPL(ata_altstatus); -EXPORT_SYMBOL_GPL(ata_chk_err); EXPORT_SYMBOL_GPL(ata_exec_command); EXPORT_SYMBOL_GPL(ata_port_start); EXPORT_SYMBOL_GPL(ata_port_stop); @@ -4620,6 +4860,7 @@ EXPORT_SYMBOL_GPL(sata_phy_reset); EXPORT_SYMBOL_GPL(__sata_phy_reset); EXPORT_SYMBOL_GPL(ata_bus_reset); EXPORT_SYMBOL_GPL(ata_port_disable); +EXPORT_SYMBOL_GPL(ata_ratelimit); EXPORT_SYMBOL_GPL(ata_scsi_ioctl); EXPORT_SYMBOL_GPL(ata_scsi_queuecmd); EXPORT_SYMBOL_GPL(ata_scsi_error); @@ -4631,6 +4872,9 @@ EXPORT_SYMBOL_GPL(ata_dev_id_string); EXPORT_SYMBOL_GPL(ata_dev_config); EXPORT_SYMBOL_GPL(ata_scsi_simulate); +EXPORT_SYMBOL_GPL(ata_timing_compute); +EXPORT_SYMBOL_GPL(ata_timing_merge); + #ifdef CONFIG_PCI EXPORT_SYMBOL_GPL(pci_test_config_bits); EXPORT_SYMBOL_GPL(ata_pci_host_stop); diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index 104fd9a63e73..1e3792f86fcf 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -40,14 +40,64 @@ #include "scsi.h" #include <scsi/scsi_host.h> #include <linux/libata.h> +#include <linux/hdreg.h> #include <asm/uaccess.h> #include "libata.h" -typedef unsigned int (*ata_xlat_func_t)(struct ata_queued_cmd *qc, u8 *scsicmd); -static struct ata_device * -ata_scsi_find_dev(struct ata_port *ap, struct scsi_device *scsidev); +#define SECTOR_SIZE 512 +typedef unsigned int (*ata_xlat_func_t)(struct ata_queued_cmd *qc, const u8 *scsicmd); +static struct ata_device * +ata_scsi_find_dev(struct ata_port *ap, const struct scsi_device *scsidev); + +#define RW_RECOVERY_MPAGE 0x1 +#define RW_RECOVERY_MPAGE_LEN 12 +#define CACHE_MPAGE 0x8 +#define CACHE_MPAGE_LEN 20 +#define CONTROL_MPAGE 0xa +#define CONTROL_MPAGE_LEN 12 +#define ALL_MPAGES 0x3f +#define ALL_SUB_MPAGES 0xff + + +static const u8 def_rw_recovery_mpage[] = { + RW_RECOVERY_MPAGE, + RW_RECOVERY_MPAGE_LEN - 2, + (1 << 7) | /* AWRE, sat-r06 say it shall be 0 */ + (1 << 6), /* ARRE (auto read reallocation) */ + 0, /* read retry count */ + 0, 0, 0, 0, + 0, /* write retry count */ + 0, 0, 0 +}; + +static const u8 def_cache_mpage[CACHE_MPAGE_LEN] = { + CACHE_MPAGE, + CACHE_MPAGE_LEN - 2, + 0, /* contains WCE, needs to be 0 for logic */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, /* contains DRA, needs to be 0 for logic */ + 0, 0, 0, 0, 0, 0, 0 +}; + +static const u8 def_control_mpage[CONTROL_MPAGE_LEN] = { + CONTROL_MPAGE, + CONTROL_MPAGE_LEN - 2, + 2, /* DSENSE=0, GLTSD=1 */ + 0, /* [QAM+QERR may be 1, see 05-359r1] */ + 0, 0, 0, 0, 0xff, 0xff, + 0, 30 /* extended self test time, see 05-359r1 */ +}; + + +static void ata_scsi_invalid_field(struct scsi_cmnd *cmd, + void (*done)(struct scsi_cmnd *)) +{ + ata_scsi_set_sense(cmd, ILLEGAL_REQUEST, 0x24, 0x0); + /* "Invalid field in cbd" */ + done(cmd); +} /** * ata_std_bios_param - generic bios head/sector/cylinder calculator used by sd. @@ -78,6 +128,150 @@ int ata_std_bios_param(struct scsi_device *sdev, struct block_device *bdev, return 0; } +/** + * ata_cmd_ioctl - Handler for HDIO_DRIVE_CMD ioctl + * @dev: Device to whom we are issuing command + * @arg: User provided data for issuing command + * + * LOCKING: + * Defined by the SCSI layer. We don't really care. + * + * RETURNS: + * Zero on success, negative errno on error. + */ + +int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg) +{ + int rc = 0; + u8 scsi_cmd[MAX_COMMAND_SIZE]; + u8 args[4], *argbuf = NULL; + int argsize = 0; + struct scsi_request *sreq; + + if (NULL == (void *)arg) + return -EINVAL; + + if (copy_from_user(args, arg, sizeof(args))) + return -EFAULT; + + sreq = scsi_allocate_request(scsidev, GFP_KERNEL); + if (!sreq) + return -EINTR; + + memset(scsi_cmd, 0, sizeof(scsi_cmd)); + + if (args[3]) { + argsize = SECTOR_SIZE * args[3]; + argbuf = kmalloc(argsize, GFP_KERNEL); + if (argbuf == NULL) { + rc = -ENOMEM; + goto error; + } + + scsi_cmd[1] = (4 << 1); /* PIO Data-in */ + scsi_cmd[2] = 0x0e; /* no off.line or cc, read from dev, + block count in sector count field */ + sreq->sr_data_direction = DMA_FROM_DEVICE; + } else { + scsi_cmd[1] = (3 << 1); /* Non-data */ + /* scsi_cmd[2] is already 0 -- no off.line, cc, or data xfer */ + sreq->sr_data_direction = DMA_NONE; + } + + scsi_cmd[0] = ATA_16; + + scsi_cmd[4] = args[2]; + if (args[0] == WIN_SMART) { /* hack -- ide driver does this too... */ + scsi_cmd[6] = args[3]; + scsi_cmd[8] = args[1]; + scsi_cmd[10] = 0x4f; + scsi_cmd[12] = 0xc2; + } else { + scsi_cmd[6] = args[1]; + } + scsi_cmd[14] = args[0]; + + /* Good values for timeout and retries? Values below + from scsi_ioctl_send_command() for default case... */ + scsi_wait_req(sreq, scsi_cmd, argbuf, argsize, (10*HZ), 5); + + if (sreq->sr_result) { + rc = -EIO; + goto error; + } + + /* Need code to retrieve data from check condition? */ + + if ((argbuf) + && copy_to_user((void *)(arg + sizeof(args)), argbuf, argsize)) + rc = -EFAULT; +error: + scsi_release_request(sreq); + + if (argbuf) + kfree(argbuf); + + return rc; +} + +/** + * ata_task_ioctl - Handler for HDIO_DRIVE_TASK ioctl + * @dev: Device to whom we are issuing command + * @arg: User provided data for issuing command + * + * LOCKING: + * Defined by the SCSI layer. We don't really care. + * + * RETURNS: + * Zero on success, negative errno on error. + */ +int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg) +{ + int rc = 0; + u8 scsi_cmd[MAX_COMMAND_SIZE]; + u8 args[7]; + struct scsi_request *sreq; + + if (NULL == (void *)arg) + return -EINVAL; + + if (copy_from_user(args, arg, sizeof(args))) + return -EFAULT; + + memset(scsi_cmd, 0, sizeof(scsi_cmd)); + scsi_cmd[0] = ATA_16; + scsi_cmd[1] = (3 << 1); /* Non-data */ + /* scsi_cmd[2] is already 0 -- no off.line, cc, or data xfer */ + scsi_cmd[4] = args[1]; + scsi_cmd[6] = args[2]; + scsi_cmd[8] = args[3]; + scsi_cmd[10] = args[4]; + scsi_cmd[12] = args[5]; + scsi_cmd[14] = args[0]; + + sreq = scsi_allocate_request(scsidev, GFP_KERNEL); + if (!sreq) { + rc = -EINTR; + goto error; + } + + sreq->sr_data_direction = DMA_NONE; + /* Good values for timeout and retries? Values below + from scsi_ioctl_send_command() for default case... */ + scsi_wait_req(sreq, scsi_cmd, NULL, 0, (10*HZ), 5); + + if (sreq->sr_result) { + rc = -EIO; + goto error; + } + + /* Need code to retrieve data from check condition? */ + +error: + scsi_release_request(sreq); + return rc; +} + int ata_scsi_ioctl(struct scsi_device *scsidev, int cmd, void __user *arg) { struct ata_port *ap; @@ -107,6 +301,16 @@ int ata_scsi_ioctl(struct scsi_device *scsidev, int cmd, void __user *arg) return -EINVAL; return 0; + case HDIO_DRIVE_CMD: + if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) + return -EACCES; + return ata_cmd_ioctl(scsidev, arg); + + case HDIO_DRIVE_TASK: + if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) + return -EACCES; + return ata_task_ioctl(scsidev, arg); + default: rc = -ENOTTY; break; @@ -165,24 +369,70 @@ struct ata_queued_cmd *ata_scsi_qc_new(struct ata_port *ap, } /** + * ata_dump_status - user friendly display of error info + * @id: id of the port in question + * @tf: ptr to filled out taskfile + * + * Decode and dump the ATA error/status registers for the user so + * that they have some idea what really happened at the non + * make-believe layer. + * + * LOCKING: + * inherited from caller + */ +void ata_dump_status(unsigned id, struct ata_taskfile *tf) +{ + u8 stat = tf->command, err = tf->feature; + + printk(KERN_WARNING "ata%u: status=0x%02x { ", id, stat); + if (stat & ATA_BUSY) { + printk("Busy }\n"); /* Data is not valid in this case */ + } else { + if (stat & 0x40) printk("DriveReady "); + if (stat & 0x20) printk("DeviceFault "); + if (stat & 0x10) printk("SeekComplete "); + if (stat & 0x08) printk("DataRequest "); + if (stat & 0x04) printk("CorrectedError "); + if (stat & 0x02) printk("Index "); + if (stat & 0x01) printk("Error "); + printk("}\n"); + + if (err) { + printk(KERN_WARNING "ata%u: error=0x%02x { ", id, err); + if (err & 0x04) printk("DriveStatusError "); + if (err & 0x80) { + if (err & 0x04) printk("BadCRC "); + else printk("Sector "); + } + if (err & 0x40) printk("UncorrectableError "); + if (err & 0x10) printk("SectorIdNotFound "); + if (err & 0x02) printk("TrackZeroNotFound "); + if (err & 0x01) printk("AddrMarkNotFound "); + printk("}\n"); + } + } +} + +/** * ata_to_sense_error - convert ATA error to SCSI error - * @qc: Command that we are erroring out * @drv_stat: value contained in ATA status register + * @drv_err: value contained in ATA error register + * @sk: the sense key we'll fill out + * @asc: the additional sense code we'll fill out + * @ascq: the additional sense code qualifier we'll fill out * - * Converts an ATA error into a SCSI error. While we are at it - * we decode and dump the ATA error for the user so that they - * have some idea what really happened at the non make-believe - * layer. + * Converts an ATA error into a SCSI error. Fill out pointers to + * SK, ASC, and ASCQ bytes for later use in fixed or descriptor + * format sense blocks. * * LOCKING: * spin_lock_irqsave(host_set lock) */ - -void ata_to_sense_error(struct ata_queued_cmd *qc, u8 drv_stat) +void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk, u8 *asc, + u8 *ascq) { - struct scsi_cmnd *cmd = qc->scsicmd; - u8 err = 0; - unsigned char *sb = cmd->sense_buffer; + int i; + /* Based on the 3ware driver translation table */ static unsigned char sense_table[][4] = { /* BBD|ECC|ID|MAR */ @@ -223,105 +473,192 @@ void ata_to_sense_error(struct ata_queued_cmd *qc, u8 drv_stat) {0x04, RECOVERED_ERROR, 0x11, 0x00}, // Recovered ECC error Medium error, recovered {0xFF, 0xFF, 0xFF, 0xFF}, // END mark }; - int i = 0; - - cmd->result = SAM_STAT_CHECK_CONDITION; /* * Is this an error we can process/parse */ + if (drv_stat & ATA_BUSY) { + drv_err = 0; /* Ignore the err bits, they're invalid */ + } + + if (drv_err) { + /* Look for drv_err */ + for (i = 0; sense_table[i][0] != 0xFF; i++) { + /* Look for best matches first */ + if ((sense_table[i][0] & drv_err) == + sense_table[i][0]) { + *sk = sense_table[i][1]; + *asc = sense_table[i][2]; + *ascq = sense_table[i][3]; + goto translate_done; + } + } + /* No immediate match */ + printk(KERN_WARNING "ata%u: no sense translation for " + "error 0x%02x\n", id, drv_err); + } + + /* Fall back to interpreting status bits */ + for (i = 0; stat_table[i][0] != 0xFF; i++) { + if (stat_table[i][0] & drv_stat) { + *sk = stat_table[i][1]; + *asc = stat_table[i][2]; + *ascq = stat_table[i][3]; + goto translate_done; + } + } + /* No error? Undecoded? */ + printk(KERN_WARNING "ata%u: no sense translation for status: 0x%02x\n", + id, drv_stat); + + /* For our last chance pick, use medium read error because + * it's much more common than an ATA drive telling you a write + * has failed. + */ + *sk = MEDIUM_ERROR; + *asc = 0x11; /* "unrecovered read error" */ + *ascq = 0x04; /* "auto-reallocation failed" */ + + translate_done: + printk(KERN_ERR "ata%u: translated ATA stat/err 0x%02x/%02x to " + "SCSI SK/ASC/ASCQ 0x%x/%02x/%02x\n", id, drv_stat, drv_err, + *sk, *asc, *ascq); + return; +} + +/* + * ata_gen_ata_desc_sense - Generate check condition sense block. + * @qc: Command that completed. + * + * This function is specific to the ATA descriptor format sense + * block specified for the ATA pass through commands. Regardless + * of whether the command errored or not, return a sense + * block. Copy all controller registers into the sense + * block. Clear sense key, ASC & ASCQ if there is no error. + * + * LOCKING: + * spin_lock_irqsave(host_set lock) + */ +void ata_gen_ata_desc_sense(struct ata_queued_cmd *qc) +{ + struct scsi_cmnd *cmd = qc->scsicmd; + struct ata_taskfile *tf = &qc->tf; + unsigned char *sb = cmd->sense_buffer; + unsigned char *desc = sb + 8; - if(drv_stat & ATA_ERR) - /* Read the err bits */ - err = ata_chk_err(qc->ap); + memset(sb, 0, SCSI_SENSE_BUFFERSIZE); - /* Display the ATA level error info */ + cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; - printk(KERN_WARNING "ata%u: status=0x%02x { ", qc->ap->id, drv_stat); - if(drv_stat & 0x80) - { - printk("Busy "); - err = 0; /* Data is not valid in this case */ + /* + * Read the controller registers. + */ + assert(NULL != qc->ap->ops->tf_read); + qc->ap->ops->tf_read(qc->ap, tf); + + /* + * Use ata_to_sense_error() to map status register bits + * onto sense key, asc & ascq. + */ + if (tf->command & (ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ)) { + ata_to_sense_error(qc->ap->id, tf->command, tf->feature, + &sb[1], &sb[2], &sb[3]); + sb[1] &= 0x0f; } - else { - if(drv_stat & 0x40) printk("DriveReady "); - if(drv_stat & 0x20) printk("DeviceFault "); - if(drv_stat & 0x10) printk("SeekComplete "); - if(drv_stat & 0x08) printk("DataRequest "); - if(drv_stat & 0x04) printk("CorrectedError "); - if(drv_stat & 0x02) printk("Index "); - if(drv_stat & 0x01) printk("Error "); + + /* + * Sense data is current and format is descriptor. + */ + sb[0] = 0x72; + + desc[0] = 0x09; + + /* + * Set length of additional sense data. + * Since we only populate descriptor 0, the total + * length is the same (fixed) length as descriptor 0. + */ + desc[1] = sb[7] = 14; + + /* + * Copy registers into sense buffer. + */ + desc[2] = 0x00; + desc[3] = tf->feature; /* == error reg */ + desc[5] = tf->nsect; + desc[7] = tf->lbal; + desc[9] = tf->lbam; + desc[11] = tf->lbah; + desc[12] = tf->device; + desc[13] = tf->command; /* == status reg */ + + /* + * Fill in Extend bit, and the high order bytes + * if applicable. + */ + if (tf->flags & ATA_TFLAG_LBA48) { + desc[2] |= 0x01; + desc[4] = tf->hob_nsect; + desc[6] = tf->hob_lbal; + desc[8] = tf->hob_lbam; + desc[10] = tf->hob_lbah; } - printk("}\n"); - - if(err) - { - printk(KERN_WARNING "ata%u: error=0x%02x { ", qc->ap->id, err); - if(err & 0x04) printk("DriveStatusError "); - if(err & 0x80) - { - if(err & 0x04) - printk("BadCRC "); - else - printk("Sector "); - } - if(err & 0x40) printk("UncorrectableError "); - if(err & 0x10) printk("SectorIdNotFound "); - if(err & 0x02) printk("TrackZeroNotFound "); - if(err & 0x01) printk("AddrMarkNotFound "); - printk("}\n"); +} - /* Should we dump sector info here too ?? */ +/** + * ata_gen_fixed_sense - generate a SCSI fixed sense block + * @qc: Command that we are erroring out + * + * Leverage ata_to_sense_error() to give us the codes. Fit our + * LBA in here if there's room. + * + * LOCKING: + * inherited from caller + */ +void ata_gen_fixed_sense(struct ata_queued_cmd *qc) +{ + struct scsi_cmnd *cmd = qc->scsicmd; + struct ata_taskfile *tf = &qc->tf; + unsigned char *sb = cmd->sense_buffer; + + memset(sb, 0, SCSI_SENSE_BUFFERSIZE); + + cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; + + /* + * Read the controller registers. + */ + assert(NULL != qc->ap->ops->tf_read); + qc->ap->ops->tf_read(qc->ap, tf); + + /* + * Use ata_to_sense_error() to map status register bits + * onto sense key, asc & ascq. + */ + if (tf->command & (ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ)) { + ata_to_sense_error(qc->ap->id, tf->command, tf->feature, + &sb[2], &sb[12], &sb[13]); + sb[2] &= 0x0f; } + sb[0] = 0x70; + sb[7] = 0x0a; - /* Look for err */ - while(sense_table[i][0] != 0xFF) - { - /* Look for best matches first */ - if((sense_table[i][0] & err) == sense_table[i][0]) - { - sb[0] = 0x70; - sb[2] = sense_table[i][1]; - sb[7] = 0x0a; - sb[12] = sense_table[i][2]; - sb[13] = sense_table[i][3]; - return; - } - i++; + if (tf->flags & ATA_TFLAG_LBA48) { + /* TODO: find solution for LBA48 descriptors */ } - /* No immediate match */ - if(err) - printk(KERN_DEBUG "ata%u: no sense translation for 0x%02x\n", qc->ap->id, err); - i = 0; - /* Fall back to interpreting status bits */ - while(stat_table[i][0] != 0xFF) - { - if(stat_table[i][0] & drv_stat) - { - sb[0] = 0x70; - sb[2] = stat_table[i][1]; - sb[7] = 0x0a; - sb[12] = stat_table[i][2]; - sb[13] = stat_table[i][3]; - return; - } - i++; + else if (tf->flags & ATA_TFLAG_LBA) { + /* A small (28b) LBA will fit in the 32b info field */ + sb[0] |= 0x80; /* set valid bit */ + sb[3] = tf->device & 0x0f; + sb[4] = tf->lbah; + sb[5] = tf->lbam; + sb[6] = tf->lbal; } - /* No error ?? */ - printk(KERN_ERR "ata%u: called with no error (%02X)!\n", qc->ap->id, drv_stat); - /* additional-sense-code[-qualifier] */ - sb[0] = 0x70; - sb[2] = MEDIUM_ERROR; - sb[7] = 0x0A; - if (cmd->sc_data_direction == DMA_FROM_DEVICE) { - sb[12] = 0x11; /* "unrecovered read error" */ - sb[13] = 0x04; - } else { - sb[12] = 0x0C; /* "write error - */ - sb[13] = 0x02; /* auto-reallocation failed" */ + else { + /* TODO: C/H/S */ } } @@ -420,7 +757,7 @@ int ata_scsi_error(struct Scsi_Host *host) */ static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc, - u8 *scsicmd) + const u8 *scsicmd) { struct ata_taskfile *tf = &qc->tf; @@ -430,15 +767,26 @@ static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc, ; /* ignore IMMED bit, violates sat-r05 */ } if (scsicmd[4] & 0x2) - return 1; /* LOEJ bit set not supported */ + goto invalid_fld; /* LOEJ bit set not supported */ if (((scsicmd[4] >> 4) & 0xf) != 0) - return 1; /* power conditions not supported */ + goto invalid_fld; /* power conditions not supported */ if (scsicmd[4] & 0x1) { tf->nsect = 1; /* 1 sector, lba=0 */ - tf->lbah = 0x0; - tf->lbam = 0x0; - tf->lbal = 0x0; - tf->device |= ATA_LBA; + + if (qc->dev->flags & ATA_DFLAG_LBA) { + qc->tf.flags |= ATA_TFLAG_LBA; + + tf->lbah = 0x0; + tf->lbam = 0x0; + tf->lbal = 0x0; + tf->device |= ATA_LBA; + } else { + /* CHS */ + tf->lbal = 0x1; /* sect */ + tf->lbam = 0x0; /* cyl low */ + tf->lbah = 0x0; /* cyl high */ + } + tf->command = ATA_CMD_VERIFY; /* READ VERIFY */ } else { tf->nsect = 0; /* time period value (0 implies now) */ @@ -453,6 +801,11 @@ static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc, */ return 0; + +invalid_fld: + ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x24, 0x0); + /* "Invalid field in cbd" */ + return 1; } @@ -471,14 +824,14 @@ static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc, * Zero on success, non-zero on error. */ -static unsigned int ata_scsi_flush_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) +static unsigned int ata_scsi_flush_xlat(struct ata_queued_cmd *qc, const u8 *scsicmd) { struct ata_taskfile *tf = &qc->tf; tf->flags |= ATA_TFLAG_DEVICE; tf->protocol = ATA_PROT_NODATA; - if ((tf->flags & ATA_TFLAG_LBA48) && + if ((qc->dev->flags & ATA_DFLAG_LBA48) && (ata_id_has_flush_ext(qc->dev->id))) tf->command = ATA_CMD_FLUSH_EXT; else @@ -488,6 +841,99 @@ static unsigned int ata_scsi_flush_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) } /** + * scsi_6_lba_len - Get LBA and transfer length + * @scsicmd: SCSI command to translate + * + * Calculate LBA and transfer length for 6-byte commands. + * + * RETURNS: + * @plba: the LBA + * @plen: the transfer length + */ + +static void scsi_6_lba_len(const u8 *scsicmd, u64 *plba, u32 *plen) +{ + u64 lba = 0; + u32 len = 0; + + VPRINTK("six-byte command\n"); + + lba |= ((u64)scsicmd[2]) << 8; + lba |= ((u64)scsicmd[3]); + + len |= ((u32)scsicmd[4]); + + *plba = lba; + *plen = len; +} + +/** + * scsi_10_lba_len - Get LBA and transfer length + * @scsicmd: SCSI command to translate + * + * Calculate LBA and transfer length for 10-byte commands. + * + * RETURNS: + * @plba: the LBA + * @plen: the transfer length + */ + +static void scsi_10_lba_len(const u8 *scsicmd, u64 *plba, u32 *plen) +{ + u64 lba = 0; + u32 len = 0; + + VPRINTK("ten-byte command\n"); + + lba |= ((u64)scsicmd[2]) << 24; + lba |= ((u64)scsicmd[3]) << 16; + lba |= ((u64)scsicmd[4]) << 8; + lba |= ((u64)scsicmd[5]); + + len |= ((u32)scsicmd[7]) << 8; + len |= ((u32)scsicmd[8]); + + *plba = lba; + *plen = len; +} + +/** + * scsi_16_lba_len - Get LBA and transfer length + * @scsicmd: SCSI command to translate + * + * Calculate LBA and transfer length for 16-byte commands. + * + * RETURNS: + * @plba: the LBA + * @plen: the transfer length + */ + +static void scsi_16_lba_len(const u8 *scsicmd, u64 *plba, u32 *plen) +{ + u64 lba = 0; + u32 len = 0; + + VPRINTK("sixteen-byte command\n"); + + lba |= ((u64)scsicmd[2]) << 56; + lba |= ((u64)scsicmd[3]) << 48; + lba |= ((u64)scsicmd[4]) << 40; + lba |= ((u64)scsicmd[5]) << 32; + lba |= ((u64)scsicmd[6]) << 24; + lba |= ((u64)scsicmd[7]) << 16; + lba |= ((u64)scsicmd[8]) << 8; + lba |= ((u64)scsicmd[9]); + + len |= ((u32)scsicmd[10]) << 24; + len |= ((u32)scsicmd[11]) << 16; + len |= ((u32)scsicmd[12]) << 8; + len |= ((u32)scsicmd[13]); + + *plba = lba; + *plen = len; +} + +/** * ata_scsi_verify_xlat - Translate SCSI VERIFY command into an ATA one * @qc: Storage for translated ATA taskfile * @scsicmd: SCSI command to translate @@ -501,82 +947,110 @@ static unsigned int ata_scsi_flush_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) * Zero on success, non-zero on error. */ -static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) +static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc, const u8 *scsicmd) { struct ata_taskfile *tf = &qc->tf; - unsigned int lba48 = tf->flags & ATA_TFLAG_LBA48; + struct ata_device *dev = qc->dev; u64 dev_sectors = qc->dev->n_sectors; - u64 sect = 0; - u32 n_sect = 0; + u64 block; + u32 n_block; tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; tf->protocol = ATA_PROT_NODATA; - tf->device |= ATA_LBA; - if (scsicmd[0] == VERIFY) { - sect |= ((u64)scsicmd[2]) << 24; - sect |= ((u64)scsicmd[3]) << 16; - sect |= ((u64)scsicmd[4]) << 8; - sect |= ((u64)scsicmd[5]); + if (scsicmd[0] == VERIFY) + scsi_10_lba_len(scsicmd, &block, &n_block); + else if (scsicmd[0] == VERIFY_16) + scsi_16_lba_len(scsicmd, &block, &n_block); + else + goto invalid_fld; - n_sect |= ((u32)scsicmd[7]) << 8; - n_sect |= ((u32)scsicmd[8]); - } + if (!n_block) + goto nothing_to_do; + if (block >= dev_sectors) + goto out_of_range; + if ((block + n_block) > dev_sectors) + goto out_of_range; - else if (scsicmd[0] == VERIFY_16) { - sect |= ((u64)scsicmd[2]) << 56; - sect |= ((u64)scsicmd[3]) << 48; - sect |= ((u64)scsicmd[4]) << 40; - sect |= ((u64)scsicmd[5]) << 32; - sect |= ((u64)scsicmd[6]) << 24; - sect |= ((u64)scsicmd[7]) << 16; - sect |= ((u64)scsicmd[8]) << 8; - sect |= ((u64)scsicmd[9]); - - n_sect |= ((u32)scsicmd[10]) << 24; - n_sect |= ((u32)scsicmd[11]) << 16; - n_sect |= ((u32)scsicmd[12]) << 8; - n_sect |= ((u32)scsicmd[13]); - } + if (dev->flags & ATA_DFLAG_LBA) { + tf->flags |= ATA_TFLAG_LBA; - else - return 1; + if (dev->flags & ATA_DFLAG_LBA48) { + if (n_block > (64 * 1024)) + goto invalid_fld; - if (!n_sect) - return 1; - if (sect >= dev_sectors) - return 1; - if ((sect + n_sect) > dev_sectors) - return 1; - if (lba48) { - if (n_sect > (64 * 1024)) - return 1; - } else { - if (n_sect > 256) - return 1; - } + /* use LBA48 */ + tf->flags |= ATA_TFLAG_LBA48; + tf->command = ATA_CMD_VERIFY_EXT; - if (lba48) { - tf->command = ATA_CMD_VERIFY_EXT; + tf->hob_nsect = (n_block >> 8) & 0xff; + + tf->hob_lbah = (block >> 40) & 0xff; + tf->hob_lbam = (block >> 32) & 0xff; + tf->hob_lbal = (block >> 24) & 0xff; + } else { + if (n_block > 256) + goto invalid_fld; + + /* use LBA28 */ + tf->command = ATA_CMD_VERIFY; + + tf->device |= (block >> 24) & 0xf; + } - tf->hob_nsect = (n_sect >> 8) & 0xff; + tf->nsect = n_block & 0xff; - tf->hob_lbah = (sect >> 40) & 0xff; - tf->hob_lbam = (sect >> 32) & 0xff; - tf->hob_lbal = (sect >> 24) & 0xff; + tf->lbah = (block >> 16) & 0xff; + tf->lbam = (block >> 8) & 0xff; + tf->lbal = block & 0xff; + + tf->device |= ATA_LBA; } else { + /* CHS */ + u32 sect, head, cyl, track; + + if (n_block > 256) + goto invalid_fld; + + /* Convert LBA to CHS */ + track = (u32)block / dev->sectors; + cyl = track / dev->heads; + head = track % dev->heads; + sect = (u32)block % dev->sectors + 1; + + DPRINTK("block %u track %u cyl %u head %u sect %u\n", + (u32)block, track, cyl, head, sect); + + /* Check whether the converted CHS can fit. + Cylinder: 0-65535 + Head: 0-15 + Sector: 1-255*/ + if ((cyl >> 16) || (head >> 4) || (sect >> 8) || (!sect)) + goto out_of_range; + tf->command = ATA_CMD_VERIFY; - - tf->device |= (sect >> 24) & 0xf; + tf->nsect = n_block & 0xff; /* Sector count 0 means 256 sectors */ + tf->lbal = sect; + tf->lbam = cyl; + tf->lbah = cyl >> 8; + tf->device |= head; } - tf->nsect = n_sect & 0xff; + return 0; - tf->lbah = (sect >> 16) & 0xff; - tf->lbam = (sect >> 8) & 0xff; - tf->lbal = sect & 0xff; +invalid_fld: + ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x24, 0x0); + /* "Invalid field in cbd" */ + return 1; - return 0; +out_of_range: + ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x21, 0x0); + /* "Logical Block Address out of range" */ + return 1; + +nothing_to_do: + qc->scsicmd->result = SAM_STAT_GOOD; + return 1; } /** @@ -599,117 +1073,175 @@ static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) * Zero on success, non-zero on error. */ -static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) +static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, const u8 *scsicmd) { struct ata_taskfile *tf = &qc->tf; - unsigned int lba48 = tf->flags & ATA_TFLAG_LBA48; + struct ata_device *dev = qc->dev; + u64 block; + u32 n_block; tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; - tf->protocol = qc->dev->xfer_protocol; - tf->device |= ATA_LBA; - if (scsicmd[0] == READ_10 || scsicmd[0] == READ_6 || - scsicmd[0] == READ_16) { - tf->command = qc->dev->read_cmd; - } else { - tf->command = qc->dev->write_cmd; + if (scsicmd[0] == WRITE_10 || scsicmd[0] == WRITE_6 || + scsicmd[0] == WRITE_16) tf->flags |= ATA_TFLAG_WRITE; - } - if (scsicmd[0] == READ_10 || scsicmd[0] == WRITE_10) { - if (lba48) { - tf->hob_nsect = scsicmd[7]; - tf->hob_lbal = scsicmd[2]; + /* Calculate the SCSI LBA and transfer length. */ + switch (scsicmd[0]) { + case READ_10: + case WRITE_10: + scsi_10_lba_len(scsicmd, &block, &n_block); + break; + case READ_6: + case WRITE_6: + scsi_6_lba_len(scsicmd, &block, &n_block); - qc->nsect = ((unsigned int)scsicmd[7] << 8) | - scsicmd[8]; - } else { - /* if we don't support LBA48 addressing, the request - * -may- be too large. */ - if ((scsicmd[2] & 0xf0) || scsicmd[7]) - return 1; + /* for 6-byte r/w commands, transfer length 0 + * means 256 blocks of data, not 0 block. + */ + if (!n_block) + n_block = 256; + break; + case READ_16: + case WRITE_16: + scsi_16_lba_len(scsicmd, &block, &n_block); + break; + default: + DPRINTK("no-byte command\n"); + goto invalid_fld; + } - /* stores LBA27:24 in lower 4 bits of device reg */ - tf->device |= scsicmd[2]; + /* Check and compose ATA command */ + if (!n_block) + /* For 10-byte and 16-byte SCSI R/W commands, transfer + * length 0 means transfer 0 block of data. + * However, for ATA R/W commands, sector count 0 means + * 256 or 65536 sectors, not 0 sectors as in SCSI. + */ + goto nothing_to_do; - qc->nsect = scsicmd[8]; - } + if (dev->flags & ATA_DFLAG_LBA) { + tf->flags |= ATA_TFLAG_LBA; - tf->nsect = scsicmd[8]; - tf->lbal = scsicmd[5]; - tf->lbam = scsicmd[4]; - tf->lbah = scsicmd[3]; + if (dev->flags & ATA_DFLAG_LBA48) { + /* The request -may- be too large for LBA48. */ + if ((block >> 48) || (n_block > 65536)) + goto out_of_range; - VPRINTK("ten-byte command\n"); - if (qc->nsect == 0) /* we don't support length==0 cmds */ - return 1; - return 0; - } + /* use LBA48 */ + tf->flags |= ATA_TFLAG_LBA48; - if (scsicmd[0] == READ_6 || scsicmd[0] == WRITE_6) { - qc->nsect = tf->nsect = scsicmd[4]; - if (!qc->nsect) { - qc->nsect = 256; - if (lba48) - tf->hob_nsect = 1; - } + tf->hob_nsect = (n_block >> 8) & 0xff; - tf->lbal = scsicmd[3]; - tf->lbam = scsicmd[2]; - tf->lbah = scsicmd[1] & 0x1f; /* mask out reserved bits */ + tf->hob_lbah = (block >> 40) & 0xff; + tf->hob_lbam = (block >> 32) & 0xff; + tf->hob_lbal = (block >> 24) & 0xff; + } else { + /* use LBA28 */ - VPRINTK("six-byte command\n"); - return 0; - } + /* The request -may- be too large for LBA28. */ + if ((block >> 28) || (n_block > 256)) + goto out_of_range; - if (scsicmd[0] == READ_16 || scsicmd[0] == WRITE_16) { - /* rule out impossible LBAs and sector counts */ - if (scsicmd[2] || scsicmd[3] || scsicmd[10] || scsicmd[11]) - return 1; + tf->device |= (block >> 24) & 0xf; + } - if (lba48) { - tf->hob_nsect = scsicmd[12]; - tf->hob_lbal = scsicmd[6]; - tf->hob_lbam = scsicmd[5]; - tf->hob_lbah = scsicmd[4]; + ata_rwcmd_protocol(qc); - qc->nsect = ((unsigned int)scsicmd[12] << 8) | - scsicmd[13]; - } else { - /* once again, filter out impossible non-zero values */ - if (scsicmd[4] || scsicmd[5] || scsicmd[12] || - (scsicmd[6] & 0xf0)) - return 1; + qc->nsect = n_block; + tf->nsect = n_block & 0xff; - /* stores LBA27:24 in lower 4 bits of device reg */ - tf->device |= scsicmd[6]; + tf->lbah = (block >> 16) & 0xff; + tf->lbam = (block >> 8) & 0xff; + tf->lbal = block & 0xff; - qc->nsect = scsicmd[13]; - } + tf->device |= ATA_LBA; + } else { + /* CHS */ + u32 sect, head, cyl, track; + + /* The request -may- be too large for CHS addressing. */ + if ((block >> 28) || (n_block > 256)) + goto out_of_range; + + ata_rwcmd_protocol(qc); + + /* Convert LBA to CHS */ + track = (u32)block / dev->sectors; + cyl = track / dev->heads; + head = track % dev->heads; + sect = (u32)block % dev->sectors + 1; + + DPRINTK("block %u track %u cyl %u head %u sect %u\n", + (u32)block, track, cyl, head, sect); + + /* Check whether the converted CHS can fit. + Cylinder: 0-65535 + Head: 0-15 + Sector: 1-255*/ + if ((cyl >> 16) || (head >> 4) || (sect >> 8) || (!sect)) + goto out_of_range; + + qc->nsect = n_block; + tf->nsect = n_block & 0xff; /* Sector count 0 means 256 sectors */ + tf->lbal = sect; + tf->lbam = cyl; + tf->lbah = cyl >> 8; + tf->device |= head; + } - tf->nsect = scsicmd[13]; - tf->lbal = scsicmd[9]; - tf->lbam = scsicmd[8]; - tf->lbah = scsicmd[7]; + return 0; - VPRINTK("sixteen-byte command\n"); - if (qc->nsect == 0) /* we don't support length==0 cmds */ - return 1; - return 0; - } +invalid_fld: + ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x24, 0x0); + /* "Invalid field in cbd" */ + return 1; - DPRINTK("no-byte command\n"); +out_of_range: + ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x21, 0x0); + /* "Logical Block Address out of range" */ + return 1; + +nothing_to_do: + qc->scsicmd->result = SAM_STAT_GOOD; return 1; } -static int ata_scsi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) +static int ata_scsi_qc_complete(struct ata_queued_cmd *qc, + unsigned int err_mask) { struct scsi_cmnd *cmd = qc->scsicmd; + u8 *cdb = cmd->cmnd; + int need_sense = (err_mask != 0); + + /* For ATA pass thru (SAT) commands, generate a sense block if + * user mandated it or if there's an error. Note that if we + * generate because the user forced us to, a check condition + * is generated and the ATA register values are returned + * whether the command completed successfully or not. If there + * was no error, SK, ASC and ASCQ will all be zero. + */ + if (((cdb[0] == ATA_16) || (cdb[0] == ATA_12)) && + ((cdb[2] & 0x20) || need_sense)) { + ata_gen_ata_desc_sense(qc); + } else { + if (!need_sense) { + cmd->result = SAM_STAT_GOOD; + } else { + /* TODO: decide which descriptor format to use + * for 48b LBA devices and call that here + * instead of the fixed desc, which is only + * good for smaller LBA (and maybe CHS?) + * devices. + */ + ata_gen_fixed_sense(qc); + } + } - if (unlikely(drv_stat & (ATA_ERR | ATA_BUSY | ATA_DRQ))) - ata_to_sense_error(qc, drv_stat); - else - cmd->result = SAM_STAT_GOOD; + if (need_sense) { + /* The ata_gen_..._sense routines fill in tf */ + ata_dump_status(qc->ap->id, &qc->tf); + } qc->scsidone(cmd); @@ -731,6 +1263,12 @@ static int ata_scsi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) * This function sets up an ata_queued_cmd structure for the * SCSI command, and sends that ata_queued_cmd to the hardware. * + * The xlat_func argument (actor) returns 0 if ready to execute + * ATA command, else 1 to finish translation. If 1 is returned + * then cmd->result (and possibly cmd->sense_buffer) are assumed + * to be set reflecting an error condition or clean (early) + * termination. + * * LOCKING: * spin_lock_irqsave(host_set lock) */ @@ -747,7 +1285,7 @@ static void ata_scsi_translate(struct ata_port *ap, struct ata_device *dev, qc = ata_scsi_qc_new(ap, dev, cmd, done); if (!qc) - return; + goto err_mem; /* data is present; dma-map it */ if (cmd->sc_data_direction == DMA_FROM_DEVICE || @@ -755,7 +1293,7 @@ static void ata_scsi_translate(struct ata_port *ap, struct ata_device *dev, if (unlikely(cmd->request_bufflen < 1)) { printk(KERN_WARNING "ata%u(%u): WARNING: zero len r/w req\n", ap->id, dev->devno); - goto err_out; + goto err_did; } if (cmd->use_sg) @@ -770,19 +1308,28 @@ static void ata_scsi_translate(struct ata_port *ap, struct ata_device *dev, qc->complete_fn = ata_scsi_qc_complete; if (xlat_func(qc, scsicmd)) - goto err_out; + goto early_finish; /* select device, send command to hardware */ if (ata_qc_issue(qc)) - goto err_out; + goto err_did; VPRINTK("EXIT\n"); return; -err_out: +early_finish: + ata_qc_free(qc); + done(cmd); + DPRINTK("EXIT - early finish (good or error)\n"); + return; + +err_did: ata_qc_free(qc); - ata_bad_cdb(cmd, done); - DPRINTK("EXIT - badcmd\n"); +err_mem: + cmd->result = (DID_ERROR << 16); + done(cmd); + DPRINTK("EXIT - internal\n"); + return; } /** @@ -849,7 +1396,8 @@ static inline void ata_scsi_rbuf_put(struct scsi_cmnd *cmd, u8 *buf) * Mapping the response buffer, calling the command's handler, * and handling the handler's return value. This return value * indicates whether the handler wishes the SCSI command to be - * completed successfully, or not. + * completed successfully (0), or not (in which case cmd->result + * and sense buffer are assumed to be set). * * LOCKING: * spin_lock_irqsave(host_set lock) @@ -868,12 +1416,9 @@ void ata_scsi_rbuf_fill(struct ata_scsi_args *args, rc = actor(args, rbuf, buflen); ata_scsi_rbuf_put(cmd, rbuf); - if (rc) - ata_bad_cdb(cmd, args->done); - else { + if (rc == 0) cmd->result = SAM_STAT_GOOD; - args->done(cmd); - } + args->done(cmd); } /** @@ -1087,13 +1632,9 @@ static void ata_msense_push(u8 **ptr_io, const u8 *last, static unsigned int ata_msense_caching(u16 *id, u8 **ptr_io, const u8 *last) { - u8 page[] = { - 0x8, /* page code */ - 0x12, /* page length */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 zeroes */ - 0, 0, 0, 0, 0, 0, 0, 0 /* 8 zeroes */ - }; + u8 page[CACHE_MPAGE_LEN]; + memcpy(page, def_cache_mpage, sizeof(page)); if (ata_id_wcache_enabled(id)) page[2] |= (1 << 2); /* write cache enable */ if (!ata_id_rahead_enabled(id)) @@ -1117,15 +1658,9 @@ static unsigned int ata_msense_caching(u16 *id, u8 **ptr_io, static unsigned int ata_msense_ctl_mode(u8 **ptr_io, const u8 *last) { - const u8 page[] = {0xa, 0xa, 6, 0, 0, 0, 0, 0, 0xff, 0xff, 0, 30}; - - /* byte 2: set the descriptor format sense data bit (bit 2) - * since we need to support returning this format for SAT - * commands and any SCSI commands against a 48b LBA device. - */ - - ata_msense_push(ptr_io, last, page, sizeof(page)); - return sizeof(page); + ata_msense_push(ptr_io, last, def_control_mpage, + sizeof(def_control_mpage)); + return sizeof(def_control_mpage); } /** @@ -1142,15 +1677,10 @@ static unsigned int ata_msense_ctl_mode(u8 **ptr_io, const u8 *last) static unsigned int ata_msense_rw_recovery(u8 **ptr_io, const u8 *last) { - const u8 page[] = { - 0x1, /* page code */ - 0xa, /* page length */ - (1 << 7) | (1 << 6), /* note auto r/w reallocation */ - 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 9 zeroes */ - }; - ata_msense_push(ptr_io, last, page, sizeof(page)); - return sizeof(page); + ata_msense_push(ptr_io, last, def_rw_recovery_mpage, + sizeof(def_rw_recovery_mpage)); + return sizeof(def_rw_recovery_mpage); } /** @@ -1159,7 +1689,9 @@ static unsigned int ata_msense_rw_recovery(u8 **ptr_io, const u8 *last) * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. * @buflen: Response buffer length. * - * Simulate MODE SENSE commands. + * Simulate MODE SENSE commands. Assume this is invoked for direct + * access devices (e.g. disks) only. There should be no block + * descriptor for other device types. * * LOCKING: * spin_lock_irqsave(host_set lock) @@ -1169,61 +1701,115 @@ unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf, unsigned int buflen) { u8 *scsicmd = args->cmd->cmnd, *p, *last; - unsigned int page_control, six_byte, output_len; + const u8 sat_blk_desc[] = { + 0, 0, 0, 0, /* number of blocks: sat unspecified */ + 0, + 0, 0x2, 0x0 /* block length: 512 bytes */ + }; + u8 pg, spg; + unsigned int ebd, page_control, six_byte, output_len, alloc_len, minlen; VPRINTK("ENTER\n"); six_byte = (scsicmd[0] == MODE_SENSE); - - /* we only support saved and current values (which we treat - * in the same manner) + ebd = !(scsicmd[1] & 0x8); /* dbd bit inverted == edb */ + /* + * LLBA bit in msense(10) ignored (compliant) */ + page_control = scsicmd[2] >> 6; - if ((page_control != 0) && (page_control != 3)) - return 1; + switch (page_control) { + case 0: /* current */ + break; /* supported */ + case 3: /* saved */ + goto saving_not_supp; + case 1: /* changeable */ + case 2: /* defaults */ + default: + goto invalid_fld; + } - if (six_byte) - output_len = 4; - else - output_len = 8; + if (six_byte) { + output_len = 4 + (ebd ? 8 : 0); + alloc_len = scsicmd[4]; + } else { + output_len = 8 + (ebd ? 8 : 0); + alloc_len = (scsicmd[7] << 8) + scsicmd[8]; + } + minlen = (alloc_len < buflen) ? alloc_len : buflen; p = rbuf + output_len; - last = rbuf + buflen - 1; + last = rbuf + minlen - 1; - switch(scsicmd[2] & 0x3f) { - case 0x01: /* r/w error recovery */ + pg = scsicmd[2] & 0x3f; + spg = scsicmd[3]; + /* + * No mode subpages supported (yet) but asking for _all_ + * subpages may be valid + */ + if (spg && (spg != ALL_SUB_MPAGES)) + goto invalid_fld; + + switch(pg) { + case RW_RECOVERY_MPAGE: output_len += ata_msense_rw_recovery(&p, last); break; - case 0x08: /* caching */ + case CACHE_MPAGE: output_len += ata_msense_caching(args->id, &p, last); break; - case 0x0a: { /* control mode */ + case CONTROL_MPAGE: { output_len += ata_msense_ctl_mode(&p, last); break; } - case 0x3f: /* all pages */ + case ALL_MPAGES: output_len += ata_msense_rw_recovery(&p, last); output_len += ata_msense_caching(args->id, &p, last); output_len += ata_msense_ctl_mode(&p, last); break; default: /* invalid page code */ - return 1; + goto invalid_fld; } + if (minlen < 1) + return 0; if (six_byte) { output_len--; rbuf[0] = output_len; + if (ebd) { + if (minlen > 3) + rbuf[3] = sizeof(sat_blk_desc); + if (minlen > 11) + memcpy(rbuf + 4, sat_blk_desc, + sizeof(sat_blk_desc)); + } } else { output_len -= 2; rbuf[0] = output_len >> 8; - rbuf[1] = output_len; + if (minlen > 1) + rbuf[1] = output_len; + if (ebd) { + if (minlen > 7) + rbuf[7] = sizeof(sat_blk_desc); + if (minlen > 15) + memcpy(rbuf + 8, sat_blk_desc, + sizeof(sat_blk_desc)); + } } - return 0; + +invalid_fld: + ata_scsi_set_sense(args->cmd, ILLEGAL_REQUEST, 0x24, 0x0); + /* "Invalid field in cbd" */ + return 1; + +saving_not_supp: + ata_scsi_set_sense(args->cmd, ILLEGAL_REQUEST, 0x39, 0x0); + /* "Saving parameters not supported" */ + return 1; } /** @@ -1246,10 +1832,20 @@ unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf, VPRINTK("ENTER\n"); - if (ata_id_has_lba48(args->id)) - n_sectors = ata_id_u64(args->id, 100); - else - n_sectors = ata_id_u32(args->id, 60); + if (ata_id_has_lba(args->id)) { + if (ata_id_has_lba48(args->id)) + n_sectors = ata_id_u64(args->id, 100); + else + n_sectors = ata_id_u32(args->id, 60); + } else { + /* CHS default translation */ + n_sectors = args->id[1] * args->id[3] * args->id[6]; + + if (ata_id_current_chs_valid(args->id)) + /* CHS current translation */ + n_sectors = ata_id_u32(args->id, 57); + } + n_sectors--; /* ATA TotalUserSectors - 1 */ if (args->cmd->cmnd[0] == READ_CAPACITY) { @@ -1313,6 +1909,34 @@ unsigned int ata_scsiop_report_luns(struct ata_scsi_args *args, u8 *rbuf, } /** + * ata_scsi_set_sense - Set SCSI sense data and status + * @cmd: SCSI request to be handled + * @sk: SCSI-defined sense key + * @asc: SCSI-defined additional sense code + * @ascq: SCSI-defined additional sense code qualifier + * + * Helper function that builds a valid fixed format, current + * response code and the given sense key (sk), additional sense + * code (asc) and additional sense code qualifier (ascq) with + * a SCSI command status of %SAM_STAT_CHECK_CONDITION and + * DRIVER_SENSE set in the upper bits of scsi_cmnd::result . + * + * LOCKING: + * Not required + */ + +void ata_scsi_set_sense(struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq) +{ + cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; + + cmd->sense_buffer[0] = 0x70; /* fixed format, current */ + cmd->sense_buffer[2] = sk; + cmd->sense_buffer[7] = 18 - 8; /* additional sense length */ + cmd->sense_buffer[12] = asc; + cmd->sense_buffer[13] = ascq; +} + +/** * ata_scsi_badcmd - End a SCSI request with an error * @cmd: SCSI request to be handled * @done: SCSI command completion function @@ -1330,30 +1954,89 @@ unsigned int ata_scsiop_report_luns(struct ata_scsi_args *args, u8 *rbuf, void ata_scsi_badcmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *), u8 asc, u8 ascq) { DPRINTK("ENTER\n"); - cmd->result = SAM_STAT_CHECK_CONDITION; - - cmd->sense_buffer[0] = 0x70; - cmd->sense_buffer[2] = ILLEGAL_REQUEST; - cmd->sense_buffer[7] = 14 - 8; /* addnl. sense len. FIXME: correct? */ - cmd->sense_buffer[12] = asc; - cmd->sense_buffer[13] = ascq; + ata_scsi_set_sense(cmd, ILLEGAL_REQUEST, asc, ascq); done(cmd); } -static int atapi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) +void atapi_request_sense(struct ata_port *ap, struct ata_device *dev, + struct scsi_cmnd *cmd) +{ + DECLARE_COMPLETION(wait); + struct ata_queued_cmd *qc; + unsigned long flags; + int rc; + + DPRINTK("ATAPI request sense\n"); + + qc = ata_qc_new_init(ap, dev); + BUG_ON(qc == NULL); + + /* FIXME: is this needed? */ + memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer)); + + ata_sg_init_one(qc, cmd->sense_buffer, sizeof(cmd->sense_buffer)); + qc->dma_dir = DMA_FROM_DEVICE; + + memset(&qc->cdb, 0, ap->cdb_len); + qc->cdb[0] = REQUEST_SENSE; + qc->cdb[4] = SCSI_SENSE_BUFFERSIZE; + + qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + qc->tf.command = ATA_CMD_PACKET; + + qc->tf.protocol = ATA_PROT_ATAPI; + qc->tf.lbam = (8 * 1024) & 0xff; + qc->tf.lbah = (8 * 1024) >> 8; + qc->nbytes = SCSI_SENSE_BUFFERSIZE; + + qc->waiting = &wait; + qc->complete_fn = ata_qc_complete_noop; + + spin_lock_irqsave(&ap->host_set->lock, flags); + rc = ata_qc_issue(qc); + spin_unlock_irqrestore(&ap->host_set->lock, flags); + + if (rc) + ata_port_disable(ap); + else + wait_for_completion(&wait); + + DPRINTK("EXIT\n"); +} + +static int atapi_qc_complete(struct ata_queued_cmd *qc, unsigned int err_mask) { struct scsi_cmnd *cmd = qc->scsicmd; - if (unlikely(drv_stat & (ATA_ERR | ATA_BUSY | ATA_DRQ))) { + VPRINTK("ENTER, err_mask 0x%X\n", err_mask); + + if (unlikely(err_mask & AC_ERR_DEV)) { DPRINTK("request check condition\n"); + /* FIXME: command completion with check condition + * but no sense causes the error handler to run, + * which then issues REQUEST SENSE, fills in the sense + * buffer, and completes the command (for the second + * time). We need to issue REQUEST SENSE some other + * way, to avoid completing the command twice. + */ cmd->result = SAM_STAT_CHECK_CONDITION; qc->scsidone(cmd); return 1; - } else { + } + + else if (unlikely(err_mask)) + /* FIXME: not quite right; we don't want the + * translation of taskfile registers into + * a sense descriptors, since that's only + * correct for ATA, not ATAPI + */ + ata_gen_ata_desc_sense(qc); + + else { u8 *scsicmd = cmd->cmnd; if (scsicmd[0] == INQUIRY) { @@ -1361,15 +2044,30 @@ static int atapi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) unsigned int buflen; buflen = ata_scsi_rbuf_get(cmd, &buf); - buf[2] = 0x5; - buf[3] = (buf[3] & 0xf0) | 2; + + /* ATAPI devices typically report zero for their SCSI version, + * and sometimes deviate from the spec WRT response data + * format. If SCSI version is reported as zero like normal, + * then we make the following fixups: 1) Fake MMC-5 version, + * to indicate to the Linux scsi midlayer this is a modern + * device. 2) Ensure response data format / ATAPI information + * are always correct. + */ + /* FIXME: do we ever override EVPD pages and the like, with + * this code? + */ + if (buf[2] == 0) { + buf[2] = 0x5; + buf[3] = 0x32; + } + ata_scsi_rbuf_put(cmd, buf); } + cmd->result = SAM_STAT_GOOD; } qc->scsidone(cmd); - return 0; } /** @@ -1384,7 +2082,7 @@ static int atapi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) * Zero on success, non-zero on failure. */ -static unsigned int atapi_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) +static unsigned int atapi_xlat(struct ata_queued_cmd *qc, const u8 *scsicmd) { struct scsi_cmnd *cmd = qc->scsicmd; struct ata_device *dev = qc->dev; @@ -1453,7 +2151,7 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) */ static struct ata_device * -ata_scsi_find_dev(struct ata_port *ap, struct scsi_device *scsidev) +ata_scsi_find_dev(struct ata_port *ap, const struct scsi_device *scsidev) { struct ata_device *dev; @@ -1478,6 +2176,143 @@ ata_scsi_find_dev(struct ata_port *ap, struct scsi_device *scsidev) return dev; } +/* + * ata_scsi_map_proto - Map pass-thru protocol value to taskfile value. + * @byte1: Byte 1 from pass-thru CDB. + * + * RETURNS: + * ATA_PROT_UNKNOWN if mapping failed/unimplemented, protocol otherwise. + */ +static u8 +ata_scsi_map_proto(u8 byte1) +{ + switch((byte1 & 0x1e) >> 1) { + case 3: /* Non-data */ + return ATA_PROT_NODATA; + + case 6: /* DMA */ + return ATA_PROT_DMA; + + case 4: /* PIO Data-in */ + case 5: /* PIO Data-out */ + if (byte1 & 0xe0) { + return ATA_PROT_PIO_MULT; + } + return ATA_PROT_PIO; + + case 10: /* Device Reset */ + case 0: /* Hard Reset */ + case 1: /* SRST */ + case 2: /* Bus Idle */ + case 7: /* Packet */ + case 8: /* DMA Queued */ + case 9: /* Device Diagnostic */ + case 11: /* UDMA Data-in */ + case 12: /* UDMA Data-Out */ + case 13: /* FPDMA */ + default: /* Reserved */ + break; + } + + return ATA_PROT_UNKNOWN; +} + +/** + * ata_scsi_pass_thru - convert ATA pass-thru CDB to taskfile + * @qc: command structure to be initialized + * @cmd: SCSI command to convert + * + * Handles either 12 or 16-byte versions of the CDB. + * + * RETURNS: + * Zero on success, non-zero on failure. + */ +static unsigned int +ata_scsi_pass_thru(struct ata_queued_cmd *qc, const u8 *scsicmd) +{ + struct ata_taskfile *tf = &(qc->tf); + struct scsi_cmnd *cmd = qc->scsicmd; + + if ((tf->protocol = ata_scsi_map_proto(scsicmd[1])) == ATA_PROT_UNKNOWN) + return 1; + + /* + * 12 and 16 byte CDBs use different offsets to + * provide the various register values. + */ + if (scsicmd[0] == ATA_16) { + /* + * 16-byte CDB - may contain extended commands. + * + * If that is the case, copy the upper byte register values. + */ + if (scsicmd[1] & 0x01) { + tf->hob_feature = scsicmd[3]; + tf->hob_nsect = scsicmd[5]; + tf->hob_lbal = scsicmd[7]; + tf->hob_lbam = scsicmd[9]; + tf->hob_lbah = scsicmd[11]; + tf->flags |= ATA_TFLAG_LBA48; + } else + tf->flags &= ~ATA_TFLAG_LBA48; + + /* + * Always copy low byte, device and command registers. + */ + tf->feature = scsicmd[4]; + tf->nsect = scsicmd[6]; + tf->lbal = scsicmd[8]; + tf->lbam = scsicmd[10]; + tf->lbah = scsicmd[12]; + tf->device = scsicmd[13]; + tf->command = scsicmd[14]; + } else { + /* + * 12-byte CDB - incapable of extended commands. + */ + tf->flags &= ~ATA_TFLAG_LBA48; + + tf->feature = scsicmd[3]; + tf->nsect = scsicmd[4]; + tf->lbal = scsicmd[5]; + tf->lbam = scsicmd[6]; + tf->lbah = scsicmd[7]; + tf->device = scsicmd[8]; + tf->command = scsicmd[9]; + } + + /* + * Filter SET_FEATURES - XFER MODE command -- otherwise, + * SET_FEATURES - XFER MODE must be preceded/succeeded + * by an update to hardware-specific registers for each + * controller (i.e. the reason for ->set_piomode(), + * ->set_dmamode(), and ->post_set_mode() hooks). + */ + if ((tf->command == ATA_CMD_SET_FEATURES) + && (tf->feature == SETFEATURES_XFER)) + return 1; + + /* + * Set flags so that all registers will be written, + * and pass on write indication (used for PIO/DMA + * setup.) + */ + tf->flags |= (ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE); + + if (cmd->sc_data_direction == DMA_TO_DEVICE) + tf->flags |= ATA_TFLAG_WRITE; + + /* + * Set transfer length. + * + * TODO: find out if we need to do more here to + * cover scatter/gather case. + */ + qc->nsect = cmd->bufflen / ATA_SECT_SIZE; + + return 0; +} + /** * ata_get_xlat_func - check if SCSI to ATA translation is possible * @dev: ATA device @@ -1510,6 +2345,11 @@ static inline ata_xlat_func_t ata_get_xlat_func(struct ata_device *dev, u8 cmd) case VERIFY: case VERIFY_16: return ata_scsi_verify_xlat; + + case ATA_12: + case ATA_16: + return ata_scsi_pass_thru; + case START_STOP: return ata_scsi_start_stop_xlat; } @@ -1610,7 +2450,7 @@ void ata_scsi_simulate(u16 *id, void (*done)(struct scsi_cmnd *)) { struct ata_scsi_args args; - u8 *scsicmd = cmd->cmnd; + const u8 *scsicmd = cmd->cmnd; args.id = id; args.cmd = cmd; @@ -1630,7 +2470,7 @@ void ata_scsi_simulate(u16 *id, case INQUIRY: if (scsicmd[1] & 2) /* is CmdDt set? */ - ata_bad_cdb(cmd, done); + ata_scsi_invalid_field(cmd, done); else if ((scsicmd[1] & 1) == 0) /* is EVPD clear? */ ata_scsi_rbuf_fill(&args, ata_scsiop_inq_std); else if (scsicmd[2] == 0x00) @@ -1640,7 +2480,7 @@ void ata_scsi_simulate(u16 *id, else if (scsicmd[2] == 0x83) ata_scsi_rbuf_fill(&args, ata_scsiop_inq_83); else - ata_bad_cdb(cmd, done); + ata_scsi_invalid_field(cmd, done); break; case MODE_SENSE: @@ -1650,7 +2490,7 @@ void ata_scsi_simulate(u16 *id, case MODE_SELECT: /* unconditionally return */ case MODE_SELECT_10: /* bad-field-in-cdb */ - ata_bad_cdb(cmd, done); + ata_scsi_invalid_field(cmd, done); break; case READ_CAPACITY: @@ -1661,20 +2501,38 @@ void ata_scsi_simulate(u16 *id, if ((scsicmd[1] & 0x1f) == SAI_READ_CAPACITY_16) ata_scsi_rbuf_fill(&args, ata_scsiop_read_cap); else - ata_bad_cdb(cmd, done); + ata_scsi_invalid_field(cmd, done); break; case REPORT_LUNS: ata_scsi_rbuf_fill(&args, ata_scsiop_report_luns); break; - /* mandantory commands we haven't implemented yet */ + /* mandatory commands we haven't implemented yet */ case REQUEST_SENSE: /* all other commands */ default: - ata_bad_scsiop(cmd, done); + ata_scsi_set_sense(cmd, ILLEGAL_REQUEST, 0x20, 0x0); + /* "Invalid command operation code" */ + done(cmd); break; } } +void ata_scsi_scan_host(struct ata_port *ap) +{ + struct ata_device *dev; + unsigned int i; + + if (ap->flags & ATA_FLAG_PORT_DISABLED) + return; + + for (i = 0; i < ATA_MAX_DEVICES; i++) { + dev = &ap->device[i]; + + if (ata_dev_present(dev)) + scsi_scan_target(&ap->host->shost_gendev, 0, i, 0, 0); + } +} + diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h index d608b3a0f6fe..10ecd9e15e4f 100644 --- a/drivers/scsi/libata.h +++ b/drivers/scsi/libata.h @@ -39,19 +39,25 @@ struct ata_scsi_args { /* libata-core.c */ extern int atapi_enabled; +extern int ata_qc_complete_noop(struct ata_queued_cmd *qc, unsigned int err_mask); extern struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap, struct ata_device *dev); +extern void ata_rwcmd_protocol(struct ata_queued_cmd *qc); extern void ata_qc_free(struct ata_queued_cmd *qc); extern int ata_qc_issue(struct ata_queued_cmd *qc); extern int ata_check_atapi_dma(struct ata_queued_cmd *qc); extern void ata_dev_select(struct ata_port *ap, unsigned int device, unsigned int wait, unsigned int can_sleep); -extern void ata_tf_to_host_nolock(struct ata_port *ap, struct ata_taskfile *tf); +extern void ata_tf_to_host_nolock(struct ata_port *ap, const struct ata_taskfile *tf); extern void swap_buf_le16(u16 *buf, unsigned int buf_words); +extern int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg); +extern int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg); /* libata-scsi.c */ -extern void ata_to_sense_error(struct ata_queued_cmd *qc, u8 drv_stat); +extern void atapi_request_sense(struct ata_port *ap, struct ata_device *dev, + struct scsi_cmnd *cmd); +extern void ata_scsi_scan_host(struct ata_port *ap); extern int ata_scsi_error(struct Scsi_Host *host); extern unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf, unsigned int buflen); @@ -76,18 +82,10 @@ extern unsigned int ata_scsiop_report_luns(struct ata_scsi_args *args, u8 *rbuf, extern void ata_scsi_badcmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *), u8 asc, u8 ascq); +extern void ata_scsi_set_sense(struct scsi_cmnd *cmd, + u8 sk, u8 asc, u8 ascq); extern void ata_scsi_rbuf_fill(struct ata_scsi_args *args, unsigned int (*actor) (struct ata_scsi_args *args, u8 *rbuf, unsigned int buflen)); -static inline void ata_bad_scsiop(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) -{ - ata_scsi_badcmd(cmd, done, 0x20, 0x00); -} - -static inline void ata_bad_cdb(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) -{ - ata_scsi_badcmd(cmd, done, 0x24, 0x00); -} - #endif /* __LIBATA_H__ */ diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c index 0aba13ceaacf..352df47bcaca 100644 --- a/drivers/scsi/lpfc/lpfc_mem.c +++ b/drivers/scsi/lpfc/lpfc_mem.c @@ -39,7 +39,7 @@ #define LPFC_MEM_POOL_SIZE 64 /* max elem in non-DMA safety pool */ static void * -lpfc_pool_kmalloc(unsigned int gfp_flags, void *data) +lpfc_pool_kmalloc(gfp_t gfp_flags, void *data) { return kmalloc((unsigned long)data, gfp_flags); } diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c index d47be8e0ea3a..c9e743ba09ec 100644 --- a/drivers/scsi/megaraid/megaraid_mbox.c +++ b/drivers/scsi/megaraid/megaraid_mbox.c @@ -76,7 +76,7 @@ static void megaraid_exit(void); static int megaraid_probe_one(struct pci_dev*, const struct pci_device_id *); static void megaraid_detach_one(struct pci_dev *); -static void megaraid_mbox_shutdown(struct device *); +static void megaraid_mbox_shutdown(struct pci_dev *); static int megaraid_io_attach(adapter_t *); static void megaraid_io_detach(adapter_t *); @@ -369,9 +369,7 @@ static struct pci_driver megaraid_pci_driver_g = { .id_table = pci_id_table_g, .probe = megaraid_probe_one, .remove = __devexit_p(megaraid_detach_one), - .driver = { - .shutdown = megaraid_mbox_shutdown, - } + .shutdown = megaraid_mbox_shutdown, }; @@ -673,9 +671,9 @@ megaraid_detach_one(struct pci_dev *pdev) * Shutdown notification, perform flush cache */ static void -megaraid_mbox_shutdown(struct device *device) +megaraid_mbox_shutdown(struct pci_dev *pdev) { - adapter_t *adapter = pci_get_drvdata(to_pci_dev(device)); + adapter_t *adapter = pci_get_drvdata(pdev); static int counter; if (!adapter) { diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c index b235556b7b65..bdccf73cf9fe 100644 --- a/drivers/scsi/mesh.c +++ b/drivers/scsi/mesh.c @@ -730,7 +730,7 @@ static void start_phase(struct mesh_state *ms) * issue a SEQ_MSGOUT to get the mesh to drop ACK. */ if ((in_8(&mr->bus_status0) & BS0_ATN) == 0) { - dlog(ms, "bus0 was %.2x explictly asserting ATN", mr->bus_status0); + dlog(ms, "bus0 was %.2x explicitly asserting ATN", mr->bus_status0); out_8(&mr->bus_status0, BS0_ATN); /* explicit ATN */ mesh_flush_io(mr); udelay(1); diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c index 3f2f2464fa63..172839fce0eb 100644 --- a/drivers/scsi/osst.c +++ b/drivers/scsi/osst.c @@ -5146,7 +5146,8 @@ static long osst_compat_ioctl(struct file * file, unsigned int cmd_in, unsigned /* Try to allocate a new tape buffer skeleton. Caller must not hold os_scsi_tapes_lock */ static struct osst_buffer * new_tape_buffer( int from_initialization, int need_dma, int max_sg ) { - int i, priority; + int i; + gfp_t priority; struct osst_buffer *tb; if (from_initialization) @@ -5178,7 +5179,8 @@ static struct osst_buffer * new_tape_buffer( int from_initialization, int need_d /* Try to allocate a temporary (while a user has the device open) enlarged tape buffer */ static int enlarge_buffer(struct osst_buffer *STbuffer, int need_dma) { - int segs, nbr, max_segs, b_size, priority, order, got; + int segs, nbr, max_segs, b_size, order, got; + gfp_t priority; if (STbuffer->buffer_size >= OS_FRAME_SIZE) return 1; @@ -5627,7 +5629,7 @@ static void osst_sysfs_add(dev_t dev, struct device *device, struct osst_tape * if (!osst_sysfs_valid) return; - osst_class_member = class_device_create(osst_sysfs_class, dev, device, "%s", name); + osst_class_member = class_device_create(osst_sysfs_class, NULL, dev, device, "%s", name); if (IS_ERR(osst_class_member)) { printk(KERN_WARNING "osst :W: Unable to add sysfs class member %s\n", name); return; diff --git a/drivers/scsi/pdc_adma.c b/drivers/scsi/pdc_adma.c new file mode 100644 index 000000000000..665017eda8a6 --- /dev/null +++ b/drivers/scsi/pdc_adma.c @@ -0,0 +1,741 @@ +/* + * pdc_adma.c - Pacific Digital Corporation ADMA + * + * Maintained by: Mark Lord <mlord@pobox.com> + * + * Copyright 2005 Mark Lord + * + * 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, 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; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * libata documentation is available via 'make {ps|pdf}docs', + * as Documentation/DocBook/libata.* + * + * + * Supports ATA disks in single-packet ADMA mode. + * Uses PIO for everything else. + * + * TODO: Use ADMA transfers for ATAPI devices, when possible. + * This requires careful attention to a number of quirks of the chip. + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/blkdev.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/sched.h> +#include <linux/device.h> +#include "scsi.h" +#include <scsi/scsi_host.h> +#include <asm/io.h> +#include <linux/libata.h> + +#define DRV_NAME "pdc_adma" +#define DRV_VERSION "0.03" + +/* macro to calculate base address for ATA regs */ +#define ADMA_ATA_REGS(base,port_no) ((base) + ((port_no) * 0x40)) + +/* macro to calculate base address for ADMA regs */ +#define ADMA_REGS(base,port_no) ((base) + 0x80 + ((port_no) * 0x20)) + +enum { + ADMA_PORTS = 2, + ADMA_CPB_BYTES = 40, + ADMA_PRD_BYTES = LIBATA_MAX_PRD * 16, + ADMA_PKT_BYTES = ADMA_CPB_BYTES + ADMA_PRD_BYTES, + + ADMA_DMA_BOUNDARY = 0xffffffff, + + /* global register offsets */ + ADMA_MODE_LOCK = 0x00c7, + + /* per-channel register offsets */ + ADMA_CONTROL = 0x0000, /* ADMA control */ + ADMA_STATUS = 0x0002, /* ADMA status */ + ADMA_CPB_COUNT = 0x0004, /* CPB count */ + ADMA_CPB_CURRENT = 0x000c, /* current CPB address */ + ADMA_CPB_NEXT = 0x000c, /* next CPB address */ + ADMA_CPB_LOOKUP = 0x0010, /* CPB lookup table */ + ADMA_FIFO_IN = 0x0014, /* input FIFO threshold */ + ADMA_FIFO_OUT = 0x0016, /* output FIFO threshold */ + + /* ADMA_CONTROL register bits */ + aNIEN = (1 << 8), /* irq mask: 1==masked */ + aGO = (1 << 7), /* packet trigger ("Go!") */ + aRSTADM = (1 << 5), /* ADMA logic reset */ + aPIOMD4 = 0x0003, /* PIO mode 4 */ + + /* ADMA_STATUS register bits */ + aPSD = (1 << 6), + aUIRQ = (1 << 4), + aPERR = (1 << 0), + + /* CPB bits */ + cDONE = (1 << 0), + cVLD = (1 << 0), + cDAT = (1 << 2), + cIEN = (1 << 3), + + /* PRD bits */ + pORD = (1 << 4), + pDIRO = (1 << 5), + pEND = (1 << 7), + + /* ATA register flags */ + rIGN = (1 << 5), + rEND = (1 << 7), + + /* ATA register addresses */ + ADMA_REGS_CONTROL = 0x0e, + ADMA_REGS_SECTOR_COUNT = 0x12, + ADMA_REGS_LBA_LOW = 0x13, + ADMA_REGS_LBA_MID = 0x14, + ADMA_REGS_LBA_HIGH = 0x15, + ADMA_REGS_DEVICE = 0x16, + ADMA_REGS_COMMAND = 0x17, + + /* PCI device IDs */ + board_1841_idx = 0, /* ADMA 2-port controller */ +}; + +typedef enum { adma_state_idle, adma_state_pkt, adma_state_mmio } adma_state_t; + +struct adma_port_priv { + u8 *pkt; + dma_addr_t pkt_dma; + adma_state_t state; +}; + +static int adma_ata_init_one (struct pci_dev *pdev, + const struct pci_device_id *ent); +static irqreturn_t adma_intr (int irq, void *dev_instance, + struct pt_regs *regs); +static int adma_port_start(struct ata_port *ap); +static void adma_host_stop(struct ata_host_set *host_set); +static void adma_port_stop(struct ata_port *ap); +static void adma_phy_reset(struct ata_port *ap); +static void adma_qc_prep(struct ata_queued_cmd *qc); +static int adma_qc_issue(struct ata_queued_cmd *qc); +static int adma_check_atapi_dma(struct ata_queued_cmd *qc); +static void adma_bmdma_stop(struct ata_queued_cmd *qc); +static u8 adma_bmdma_status(struct ata_port *ap); +static void adma_irq_clear(struct ata_port *ap); +static void adma_eng_timeout(struct ata_port *ap); + +static Scsi_Host_Template adma_ata_sht = { + .module = THIS_MODULE, + .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, + .queuecommand = ata_scsi_queuecmd, + .eh_strategy_handler = ata_scsi_error, + .can_queue = ATA_DEF_QUEUE, + .this_id = ATA_SHT_THIS_ID, + .sg_tablesize = LIBATA_MAX_PRD, + .max_sectors = ATA_MAX_SECTORS, + .cmd_per_lun = ATA_SHT_CMD_PER_LUN, + .emulated = ATA_SHT_EMULATED, + .use_clustering = ENABLE_CLUSTERING, + .proc_name = DRV_NAME, + .dma_boundary = ADMA_DMA_BOUNDARY, + .slave_configure = ata_scsi_slave_config, + .bios_param = ata_std_bios_param, +}; + +static const struct ata_port_operations adma_ata_ops = { + .port_disable = ata_port_disable, + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .check_status = ata_check_status, + .check_atapi_dma = adma_check_atapi_dma, + .exec_command = ata_exec_command, + .dev_select = ata_std_dev_select, + .phy_reset = adma_phy_reset, + .qc_prep = adma_qc_prep, + .qc_issue = adma_qc_issue, + .eng_timeout = adma_eng_timeout, + .irq_handler = adma_intr, + .irq_clear = adma_irq_clear, + .port_start = adma_port_start, + .port_stop = adma_port_stop, + .host_stop = adma_host_stop, + .bmdma_stop = adma_bmdma_stop, + .bmdma_status = adma_bmdma_status, +}; + +static struct ata_port_info adma_port_info[] = { + /* board_1841_idx */ + { + .sht = &adma_ata_sht, + .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST | + ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO, + .pio_mask = 0x10, /* pio4 */ + .udma_mask = 0x1f, /* udma0-4 */ + .port_ops = &adma_ata_ops, + }, +}; + +static struct pci_device_id adma_ata_pci_tbl[] = { + { PCI_VENDOR_ID_PDC, 0x1841, PCI_ANY_ID, PCI_ANY_ID, 0, 0, + board_1841_idx }, + + { } /* terminate list */ +}; + +static struct pci_driver adma_ata_pci_driver = { + .name = DRV_NAME, + .id_table = adma_ata_pci_tbl, + .probe = adma_ata_init_one, + .remove = ata_pci_remove_one, +}; + +static int adma_check_atapi_dma(struct ata_queued_cmd *qc) +{ + return 1; /* ATAPI DMA not yet supported */ +} + +static void adma_bmdma_stop(struct ata_queued_cmd *qc) +{ + /* nothing */ +} + +static u8 adma_bmdma_status(struct ata_port *ap) +{ + return 0; +} + +static void adma_irq_clear(struct ata_port *ap) +{ + /* nothing */ +} + +static void adma_reset_engine(void __iomem *chan) +{ + /* reset ADMA to idle state */ + writew(aPIOMD4 | aNIEN | aRSTADM, chan + ADMA_CONTROL); + udelay(2); + writew(aPIOMD4, chan + ADMA_CONTROL); + udelay(2); +} + +static void adma_reinit_engine(struct ata_port *ap) +{ + struct adma_port_priv *pp = ap->private_data; + void __iomem *mmio_base = ap->host_set->mmio_base; + void __iomem *chan = ADMA_REGS(mmio_base, ap->port_no); + + /* mask/clear ATA interrupts */ + writeb(ATA_NIEN, (void __iomem *)ap->ioaddr.ctl_addr); + ata_check_status(ap); + + /* reset the ADMA engine */ + adma_reset_engine(chan); + + /* set in-FIFO threshold to 0x100 */ + writew(0x100, chan + ADMA_FIFO_IN); + + /* set CPB pointer */ + writel((u32)pp->pkt_dma, chan + ADMA_CPB_NEXT); + + /* set out-FIFO threshold to 0x100 */ + writew(0x100, chan + ADMA_FIFO_OUT); + + /* set CPB count */ + writew(1, chan + ADMA_CPB_COUNT); + + /* read/discard ADMA status */ + readb(chan + ADMA_STATUS); +} + +static inline void adma_enter_reg_mode(struct ata_port *ap) +{ + void __iomem *chan = ADMA_REGS(ap->host_set->mmio_base, ap->port_no); + + writew(aPIOMD4, chan + ADMA_CONTROL); + readb(chan + ADMA_STATUS); /* flush */ +} + +static void adma_phy_reset(struct ata_port *ap) +{ + struct adma_port_priv *pp = ap->private_data; + + pp->state = adma_state_idle; + adma_reinit_engine(ap); + ata_port_probe(ap); + ata_bus_reset(ap); +} + +static void adma_eng_timeout(struct ata_port *ap) +{ + struct adma_port_priv *pp = ap->private_data; + + if (pp->state != adma_state_idle) /* healthy paranoia */ + pp->state = adma_state_mmio; + adma_reinit_engine(ap); + ata_eng_timeout(ap); +} + +static int adma_fill_sg(struct ata_queued_cmd *qc) +{ + struct scatterlist *sg = qc->sg; + struct ata_port *ap = qc->ap; + struct adma_port_priv *pp = ap->private_data; + u8 *buf = pp->pkt; + int nelem, i = (2 + buf[3]) * 8; + u8 pFLAGS = pORD | ((qc->tf.flags & ATA_TFLAG_WRITE) ? pDIRO : 0); + + for (nelem = 0; nelem < qc->n_elem; nelem++,sg++) { + u32 addr; + u32 len; + + addr = (u32)sg_dma_address(sg); + *(__le32 *)(buf + i) = cpu_to_le32(addr); + i += 4; + + len = sg_dma_len(sg) >> 3; + *(__le32 *)(buf + i) = cpu_to_le32(len); + i += 4; + + if ((nelem + 1) == qc->n_elem) + pFLAGS |= pEND; + buf[i++] = pFLAGS; + buf[i++] = qc->dev->dma_mode & 0xf; + buf[i++] = 0; /* pPKLW */ + buf[i++] = 0; /* reserved */ + + *(__le32 *)(buf + i) + = (pFLAGS & pEND) ? 0 : cpu_to_le32(pp->pkt_dma + i + 4); + i += 4; + + VPRINTK("PRD[%u] = (0x%lX, 0x%X)\n", nelem, + (unsigned long)addr, len); + } + return i; +} + +static void adma_qc_prep(struct ata_queued_cmd *qc) +{ + struct adma_port_priv *pp = qc->ap->private_data; + u8 *buf = pp->pkt; + u32 pkt_dma = (u32)pp->pkt_dma; + int i = 0; + + VPRINTK("ENTER\n"); + + adma_enter_reg_mode(qc->ap); + if (qc->tf.protocol != ATA_PROT_DMA) { + ata_qc_prep(qc); + return; + } + + buf[i++] = 0; /* Response flags */ + buf[i++] = 0; /* reserved */ + buf[i++] = cVLD | cDAT | cIEN; + i++; /* cLEN, gets filled in below */ + + *(__le32 *)(buf+i) = cpu_to_le32(pkt_dma); /* cNCPB */ + i += 4; /* cNCPB */ + i += 4; /* cPRD, gets filled in below */ + + buf[i++] = 0; /* reserved */ + buf[i++] = 0; /* reserved */ + buf[i++] = 0; /* reserved */ + buf[i++] = 0; /* reserved */ + + /* ATA registers; must be a multiple of 4 */ + buf[i++] = qc->tf.device; + buf[i++] = ADMA_REGS_DEVICE; + if ((qc->tf.flags & ATA_TFLAG_LBA48)) { + buf[i++] = qc->tf.hob_nsect; + buf[i++] = ADMA_REGS_SECTOR_COUNT; + buf[i++] = qc->tf.hob_lbal; + buf[i++] = ADMA_REGS_LBA_LOW; + buf[i++] = qc->tf.hob_lbam; + buf[i++] = ADMA_REGS_LBA_MID; + buf[i++] = qc->tf.hob_lbah; + buf[i++] = ADMA_REGS_LBA_HIGH; + } + buf[i++] = qc->tf.nsect; + buf[i++] = ADMA_REGS_SECTOR_COUNT; + buf[i++] = qc->tf.lbal; + buf[i++] = ADMA_REGS_LBA_LOW; + buf[i++] = qc->tf.lbam; + buf[i++] = ADMA_REGS_LBA_MID; + buf[i++] = qc->tf.lbah; + buf[i++] = ADMA_REGS_LBA_HIGH; + buf[i++] = 0; + buf[i++] = ADMA_REGS_CONTROL; + buf[i++] = rIGN; + buf[i++] = 0; + buf[i++] = qc->tf.command; + buf[i++] = ADMA_REGS_COMMAND | rEND; + + buf[3] = (i >> 3) - 2; /* cLEN */ + *(__le32 *)(buf+8) = cpu_to_le32(pkt_dma + i); /* cPRD */ + + i = adma_fill_sg(qc); + wmb(); /* flush PRDs and pkt to memory */ +#if 0 + /* dump out CPB + PRDs for debug */ + { + int j, len = 0; + static char obuf[2048]; + for (j = 0; j < i; ++j) { + len += sprintf(obuf+len, "%02x ", buf[j]); + if ((j & 7) == 7) { + printk("%s\n", obuf); + len = 0; + } + } + if (len) + printk("%s\n", obuf); + } +#endif +} + +static inline void adma_packet_start(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + void __iomem *chan = ADMA_REGS(ap->host_set->mmio_base, ap->port_no); + + VPRINTK("ENTER, ap %p\n", ap); + + /* fire up the ADMA engine */ + writew(aPIOMD4 | aGO, chan + ADMA_CONTROL); +} + +static int adma_qc_issue(struct ata_queued_cmd *qc) +{ + struct adma_port_priv *pp = qc->ap->private_data; + + switch (qc->tf.protocol) { + case ATA_PROT_DMA: + pp->state = adma_state_pkt; + adma_packet_start(qc); + return 0; + + case ATA_PROT_ATAPI_DMA: + BUG(); + break; + + default: + break; + } + + pp->state = adma_state_mmio; + return ata_qc_issue_prot(qc); +} + +static inline unsigned int adma_intr_pkt(struct ata_host_set *host_set) +{ + unsigned int handled = 0, port_no; + u8 __iomem *mmio_base = host_set->mmio_base; + + for (port_no = 0; port_no < host_set->n_ports; ++port_no) { + struct ata_port *ap = host_set->ports[port_no]; + struct adma_port_priv *pp; + struct ata_queued_cmd *qc; + void __iomem *chan = ADMA_REGS(mmio_base, port_no); + u8 status = readb(chan + ADMA_STATUS); + + if (status == 0) + continue; + handled = 1; + adma_enter_reg_mode(ap); + if (ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR)) + continue; + pp = ap->private_data; + if (!pp || pp->state != adma_state_pkt) + continue; + qc = ata_qc_from_tag(ap, ap->active_tag); + if (qc && (!(qc->tf.ctl & ATA_NIEN))) { + unsigned int err_mask = 0; + + if ((status & (aPERR | aPSD | aUIRQ))) + err_mask = AC_ERR_OTHER; + else if (pp->pkt[0] != cDONE) + err_mask = AC_ERR_OTHER; + + ata_qc_complete(qc, err_mask); + } + } + return handled; +} + +static inline unsigned int adma_intr_mmio(struct ata_host_set *host_set) +{ + unsigned int handled = 0, port_no; + + for (port_no = 0; port_no < host_set->n_ports; ++port_no) { + struct ata_port *ap; + ap = host_set->ports[port_no]; + if (ap && (!(ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR)))) { + struct ata_queued_cmd *qc; + struct adma_port_priv *pp = ap->private_data; + if (!pp || pp->state != adma_state_mmio) + continue; + qc = ata_qc_from_tag(ap, ap->active_tag); + if (qc && (!(qc->tf.ctl & ATA_NIEN))) { + + /* check main status, clearing INTRQ */ + u8 status = ata_check_status(ap); + if ((status & ATA_BUSY)) + continue; + DPRINTK("ata%u: protocol %d (dev_stat 0x%X)\n", + ap->id, qc->tf.protocol, status); + + /* complete taskfile transaction */ + pp->state = adma_state_idle; + ata_qc_complete(qc, ac_err_mask(status)); + handled = 1; + } + } + } + return handled; +} + +static irqreturn_t adma_intr(int irq, void *dev_instance, struct pt_regs *regs) +{ + struct ata_host_set *host_set = dev_instance; + unsigned int handled = 0; + + VPRINTK("ENTER\n"); + + spin_lock(&host_set->lock); + handled = adma_intr_pkt(host_set) | adma_intr_mmio(host_set); + spin_unlock(&host_set->lock); + + VPRINTK("EXIT\n"); + + return IRQ_RETVAL(handled); +} + +static void adma_ata_setup_port(struct ata_ioports *port, unsigned long base) +{ + port->cmd_addr = + port->data_addr = base + 0x000; + port->error_addr = + port->feature_addr = base + 0x004; + port->nsect_addr = base + 0x008; + port->lbal_addr = base + 0x00c; + port->lbam_addr = base + 0x010; + port->lbah_addr = base + 0x014; + port->device_addr = base + 0x018; + port->status_addr = + port->command_addr = base + 0x01c; + port->altstatus_addr = + port->ctl_addr = base + 0x038; +} + +static int adma_port_start(struct ata_port *ap) +{ + struct device *dev = ap->host_set->dev; + struct adma_port_priv *pp; + int rc; + + rc = ata_port_start(ap); + if (rc) + return rc; + adma_enter_reg_mode(ap); + rc = -ENOMEM; + pp = kcalloc(1, sizeof(*pp), GFP_KERNEL); + if (!pp) + goto err_out; + pp->pkt = dma_alloc_coherent(dev, ADMA_PKT_BYTES, &pp->pkt_dma, + GFP_KERNEL); + if (!pp->pkt) + goto err_out_kfree; + /* paranoia? */ + if ((pp->pkt_dma & 7) != 0) { + printk("bad alignment for pp->pkt_dma: %08x\n", + (u32)pp->pkt_dma); + dma_free_coherent(dev, ADMA_PKT_BYTES, + pp->pkt, pp->pkt_dma); + goto err_out_kfree; + } + memset(pp->pkt, 0, ADMA_PKT_BYTES); + ap->private_data = pp; + adma_reinit_engine(ap); + return 0; + +err_out_kfree: + kfree(pp); +err_out: + ata_port_stop(ap); + return rc; +} + +static void adma_port_stop(struct ata_port *ap) +{ + struct device *dev = ap->host_set->dev; + struct adma_port_priv *pp = ap->private_data; + + adma_reset_engine(ADMA_REGS(ap->host_set->mmio_base, ap->port_no)); + if (pp != NULL) { + ap->private_data = NULL; + if (pp->pkt != NULL) + dma_free_coherent(dev, ADMA_PKT_BYTES, + pp->pkt, pp->pkt_dma); + kfree(pp); + } + ata_port_stop(ap); +} + +static void adma_host_stop(struct ata_host_set *host_set) +{ + unsigned int port_no; + + for (port_no = 0; port_no < ADMA_PORTS; ++port_no) + adma_reset_engine(ADMA_REGS(host_set->mmio_base, port_no)); + + ata_pci_host_stop(host_set); +} + +static void adma_host_init(unsigned int chip_id, + struct ata_probe_ent *probe_ent) +{ + unsigned int port_no; + void __iomem *mmio_base = probe_ent->mmio_base; + + /* enable/lock aGO operation */ + writeb(7, mmio_base + ADMA_MODE_LOCK); + + /* reset the ADMA logic */ + for (port_no = 0; port_no < ADMA_PORTS; ++port_no) + adma_reset_engine(ADMA_REGS(mmio_base, port_no)); +} + +static int adma_set_dma_masks(struct pci_dev *pdev, void __iomem *mmio_base) +{ + int rc; + + rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + if (rc) { + dev_printk(KERN_ERR, &pdev->dev, + "32-bit DMA enable failed\n"); + return rc; + } + rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); + if (rc) { + dev_printk(KERN_ERR, &pdev->dev, + "32-bit consistent DMA enable failed\n"); + return rc; + } + return 0; +} + +static int adma_ata_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + static int printed_version; + struct ata_probe_ent *probe_ent = NULL; + void __iomem *mmio_base; + unsigned int board_idx = (unsigned int) ent->driver_data; + int rc, port_no; + + if (!printed_version++) + dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); + + rc = pci_enable_device(pdev); + if (rc) + return rc; + + rc = pci_request_regions(pdev, DRV_NAME); + if (rc) + goto err_out; + + if ((pci_resource_flags(pdev, 4) & IORESOURCE_MEM) == 0) { + rc = -ENODEV; + goto err_out_regions; + } + + mmio_base = pci_iomap(pdev, 4, 0); + if (mmio_base == NULL) { + rc = -ENOMEM; + goto err_out_regions; + } + + rc = adma_set_dma_masks(pdev, mmio_base); + if (rc) + goto err_out_iounmap; + + probe_ent = kcalloc(1, sizeof(*probe_ent), GFP_KERNEL); + if (probe_ent == NULL) { + rc = -ENOMEM; + goto err_out_iounmap; + } + + probe_ent->dev = pci_dev_to_dev(pdev); + INIT_LIST_HEAD(&probe_ent->node); + + probe_ent->sht = adma_port_info[board_idx].sht; + probe_ent->host_flags = adma_port_info[board_idx].host_flags; + probe_ent->pio_mask = adma_port_info[board_idx].pio_mask; + probe_ent->mwdma_mask = adma_port_info[board_idx].mwdma_mask; + probe_ent->udma_mask = adma_port_info[board_idx].udma_mask; + probe_ent->port_ops = adma_port_info[board_idx].port_ops; + + probe_ent->irq = pdev->irq; + probe_ent->irq_flags = SA_SHIRQ; + probe_ent->mmio_base = mmio_base; + probe_ent->n_ports = ADMA_PORTS; + + for (port_no = 0; port_no < probe_ent->n_ports; ++port_no) { + adma_ata_setup_port(&probe_ent->port[port_no], + ADMA_ATA_REGS((unsigned long)mmio_base, port_no)); + } + + pci_set_master(pdev); + + /* initialize adapter */ + adma_host_init(board_idx, probe_ent); + + rc = ata_device_add(probe_ent); + kfree(probe_ent); + if (rc != ADMA_PORTS) + goto err_out_iounmap; + return 0; + +err_out_iounmap: + pci_iounmap(pdev, mmio_base); +err_out_regions: + pci_release_regions(pdev); +err_out: + pci_disable_device(pdev); + return rc; +} + +static int __init adma_ata_init(void) +{ + return pci_module_init(&adma_ata_pci_driver); +} + +static void __exit adma_ata_exit(void) +{ + pci_unregister_driver(&adma_ata_pci_driver); +} + +MODULE_AUTHOR("Mark Lord"); +MODULE_DESCRIPTION("Pacific Digital Corporation ADMA low-level driver"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, adma_ata_pci_tbl); +MODULE_VERSION(DRV_VERSION); + +module_init(adma_ata_init); +module_exit(adma_ata_exit); diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 1ed32e7b5472..e451941ad81d 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -52,7 +52,7 @@ extern int qla2x00_load_risc(struct scsi_qla_host *, uint32_t *); extern int qla24xx_load_risc_flash(scsi_qla_host_t *, uint32_t *); extern int qla24xx_load_risc_hotplug(scsi_qla_host_t *, uint32_t *); -extern fc_port_t *qla2x00_alloc_fcport(scsi_qla_host_t *, int); +extern fc_port_t *qla2x00_alloc_fcport(scsi_qla_host_t *, gfp_t); extern int qla2x00_loop_resync(scsi_qla_host_t *); @@ -277,7 +277,7 @@ extern int qla2x00_fdmi_register(scsi_qla_host_t *); /* * Global Function Prototypes in qla_rscn.c source file. */ -extern fc_port_t *qla2x00_alloc_rscn_fcport(scsi_qla_host_t *, int); +extern fc_port_t *qla2x00_alloc_rscn_fcport(scsi_qla_host_t *, gfp_t); extern int qla2x00_handle_port_rscn(scsi_qla_host_t *, uint32_t, fc_port_t *, int); extern void qla2x00_process_iodesc(scsi_qla_host_t *, struct mbx_entry *); diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 23d095d3817b..fbb6feee40cf 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -1685,7 +1685,7 @@ qla2x00_nvram_config(scsi_qla_host_t *ha) * Returns a pointer to the allocated fcport, or NULL, if none available. */ fc_port_t * -qla2x00_alloc_fcport(scsi_qla_host_t *ha, int flags) +qla2x00_alloc_fcport(scsi_qla_host_t *ha, gfp_t flags) { fc_port_t *fcport; diff --git a/drivers/scsi/qla2xxx/qla_rscn.c b/drivers/scsi/qla2xxx/qla_rscn.c index 1eba98828636..7534efcc8918 100644 --- a/drivers/scsi/qla2xxx/qla_rscn.c +++ b/drivers/scsi/qla2xxx/qla_rscn.c @@ -1066,7 +1066,7 @@ qla2x00_send_login_iocb_cb(scsi_qla_host_t *ha, struct io_descriptor *iodesc, * Returns a pointer to the allocated RSCN fcport, or NULL, if none available. */ fc_port_t * -qla2x00_alloc_rscn_fcport(scsi_qla_host_t *ha, int flags) +qla2x00_alloc_rscn_fcport(scsi_qla_host_t *ha, gfp_t flags) { fc_port_t *fcport; diff --git a/drivers/scsi/sata_mv.c b/drivers/scsi/sata_mv.c index ea76fe44585e..46dbdee79f77 100644 --- a/drivers/scsi/sata_mv.c +++ b/drivers/scsi/sata_mv.c @@ -29,13 +29,14 @@ #include <linux/interrupt.h> #include <linux/sched.h> #include <linux/dma-mapping.h> +#include <linux/device.h> #include "scsi.h" #include <scsi/scsi_host.h> #include <linux/libata.h> #include <asm/io.h> #define DRV_NAME "sata_mv" -#define DRV_VERSION "0.12" +#define DRV_VERSION "0.25" enum { /* BAR's are enumerated in terms of pci_resource_start() terms */ @@ -55,31 +56,61 @@ enum { MV_SATAHC_ARBTR_REG_SZ = MV_MINOR_REG_AREA_SZ, /* arbiter */ MV_PORT_REG_SZ = MV_MINOR_REG_AREA_SZ, - MV_Q_CT = 32, - MV_CRQB_SZ = 32, - MV_CRPB_SZ = 8, + MV_USE_Q_DEPTH = ATA_DEF_QUEUE, - MV_DMA_BOUNDARY = 0xffffffffU, - SATAHC_MASK = (~(MV_SATAHC_REG_SZ - 1)), + MV_MAX_Q_DEPTH = 32, + MV_MAX_Q_DEPTH_MASK = MV_MAX_Q_DEPTH - 1, + + /* CRQB needs alignment on a 1KB boundary. Size == 1KB + * CRPB needs alignment on a 256B boundary. Size == 256B + * SG count of 176 leads to MV_PORT_PRIV_DMA_SZ == 4KB + * ePRD (SG) entries need alignment on a 16B boundary. Size == 16B + */ + MV_CRQB_Q_SZ = (32 * MV_MAX_Q_DEPTH), + MV_CRPB_Q_SZ = (8 * MV_MAX_Q_DEPTH), + MV_MAX_SG_CT = 176, + MV_SG_TBL_SZ = (16 * MV_MAX_SG_CT), + MV_PORT_PRIV_DMA_SZ = (MV_CRQB_Q_SZ + MV_CRPB_Q_SZ + MV_SG_TBL_SZ), + + /* Our DMA boundary is determined by an ePRD being unable to handle + * anything larger than 64KB + */ + MV_DMA_BOUNDARY = 0xffffU, MV_PORTS_PER_HC = 4, /* == (port / MV_PORTS_PER_HC) to determine HC from 0-7 port */ MV_PORT_HC_SHIFT = 2, - /* == (port % MV_PORTS_PER_HC) to determine port from 0-7 port */ + /* == (port % MV_PORTS_PER_HC) to determine hard port from 0-7 port */ MV_PORT_MASK = 3, /* Host Flags */ MV_FLAG_DUAL_HC = (1 << 30), /* two SATA Host Controllers */ MV_FLAG_IRQ_COALESCE = (1 << 29), /* IRQ coalescing capability */ - MV_FLAG_BDMA = (1 << 28), /* Basic DMA */ + MV_FLAG_GLBL_SFT_RST = (1 << 28), /* Global Soft Reset support */ + MV_COMMON_FLAGS = (ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | + ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO), + MV_6XXX_FLAGS = (MV_FLAG_IRQ_COALESCE | + MV_FLAG_GLBL_SFT_RST), chip_504x = 0, chip_508x = 1, chip_604x = 2, chip_608x = 3, + CRQB_FLAG_READ = (1 << 0), + CRQB_TAG_SHIFT = 1, + CRQB_CMD_ADDR_SHIFT = 8, + CRQB_CMD_CS = (0x2 << 11), + CRQB_CMD_LAST = (1 << 15), + + CRPB_FLAG_STATUS_SHIFT = 8, + + EPRD_FLAG_END_OF_TBL = (1 << 31), + /* PCI interface registers */ + PCI_COMMAND_OFS = 0xc00, + PCI_MAIN_CMD_STS_OFS = 0xd30, STOP_PCI_MASTER = (1 << 2), PCI_MASTER_EMPTY = (1 << 3), @@ -111,20 +142,13 @@ enum { HC_CFG_OFS = 0, HC_IRQ_CAUSE_OFS = 0x14, - CRBP_DMA_DONE = (1 << 0), /* shift by port # */ + CRPB_DMA_DONE = (1 << 0), /* shift by port # */ HC_IRQ_COAL = (1 << 4), /* IRQ coalescing */ DEV_IRQ = (1 << 8), /* shift by port # */ /* Shadow block registers */ - SHD_PIO_DATA_OFS = 0x100, - SHD_FEA_ERR_OFS = 0x104, - SHD_SECT_CNT_OFS = 0x108, - SHD_LBA_L_OFS = 0x10C, - SHD_LBA_M_OFS = 0x110, - SHD_LBA_H_OFS = 0x114, - SHD_DEV_HD_OFS = 0x118, - SHD_CMD_STA_OFS = 0x11C, - SHD_CTL_AST_OFS = 0x120, + SHD_BLK_OFS = 0x100, + SHD_CTL_AST_OFS = 0x20, /* ofs from SHD_BLK_OFS */ /* SATA registers */ SATA_STATUS_OFS = 0x300, /* ctrl, err regs follow status */ @@ -132,6 +156,11 @@ enum { /* Port registers */ EDMA_CFG_OFS = 0, + EDMA_CFG_Q_DEPTH = 0, /* queueing disabled */ + EDMA_CFG_NCQ = (1 << 5), + EDMA_CFG_NCQ_GO_ON_ERR = (1 << 14), /* continue on error */ + EDMA_CFG_RD_BRST_EXT = (1 << 11), /* read burst 512B */ + EDMA_CFG_WR_BUFF_LEN = (1 << 13), /* write buffer 512B */ EDMA_ERR_IRQ_CAUSE_OFS = 0x8, EDMA_ERR_IRQ_MASK_OFS = 0xc, @@ -161,33 +190,84 @@ enum { EDMA_ERR_LNK_DATA_TX | EDMA_ERR_TRANS_PROTO), + EDMA_REQ_Q_BASE_HI_OFS = 0x10, + EDMA_REQ_Q_IN_PTR_OFS = 0x14, /* also contains BASE_LO */ + EDMA_REQ_Q_BASE_LO_MASK = 0xfffffc00U, + + EDMA_REQ_Q_OUT_PTR_OFS = 0x18, + EDMA_REQ_Q_PTR_SHIFT = 5, + + EDMA_RSP_Q_BASE_HI_OFS = 0x1c, + EDMA_RSP_Q_IN_PTR_OFS = 0x20, + EDMA_RSP_Q_OUT_PTR_OFS = 0x24, /* also contains BASE_LO */ + EDMA_RSP_Q_BASE_LO_MASK = 0xffffff00U, + EDMA_RSP_Q_PTR_SHIFT = 3, + EDMA_CMD_OFS = 0x28, EDMA_EN = (1 << 0), EDMA_DS = (1 << 1), ATA_RST = (1 << 2), - /* BDMA is 6xxx part only */ - BDMA_CMD_OFS = 0x224, - BDMA_START = (1 << 0), + /* Host private flags (hp_flags) */ + MV_HP_FLAG_MSI = (1 << 0), - MV_UNDEF = 0, + /* Port private flags (pp_flags) */ + MV_PP_FLAG_EDMA_EN = (1 << 0), + MV_PP_FLAG_EDMA_DS_ACT = (1 << 1), }; -struct mv_port_priv { +/* Command ReQuest Block: 32B */ +struct mv_crqb { + u32 sg_addr; + u32 sg_addr_hi; + u16 ctrl_flags; + u16 ata_cmd[11]; +}; +/* Command ResPonse Block: 8B */ +struct mv_crpb { + u16 id; + u16 flags; + u32 tmstmp; }; -struct mv_host_priv { +/* EDMA Physical Region Descriptor (ePRD); A.K.A. SG */ +struct mv_sg { + u32 addr; + u32 flags_size; + u32 addr_hi; + u32 reserved; +}; +struct mv_port_priv { + struct mv_crqb *crqb; + dma_addr_t crqb_dma; + struct mv_crpb *crpb; + dma_addr_t crpb_dma; + struct mv_sg *sg_tbl; + dma_addr_t sg_tbl_dma; + + unsigned req_producer; /* cp of req_in_ptr */ + unsigned rsp_consumer; /* cp of rsp_out_ptr */ + u32 pp_flags; +}; + +struct mv_host_priv { + u32 hp_flags; }; static void mv_irq_clear(struct ata_port *ap); static u32 mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in); static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val); static void mv_phy_reset(struct ata_port *ap); -static int mv_master_reset(void __iomem *mmio_base); +static void mv_host_stop(struct ata_host_set *host_set); +static int mv_port_start(struct ata_port *ap); +static void mv_port_stop(struct ata_port *ap); +static void mv_qc_prep(struct ata_queued_cmd *qc); +static int mv_qc_issue(struct ata_queued_cmd *qc); static irqreturn_t mv_interrupt(int irq, void *dev_instance, struct pt_regs *regs); +static void mv_eng_timeout(struct ata_port *ap); static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); static Scsi_Host_Template mv_sht = { @@ -196,13 +276,13 @@ static Scsi_Host_Template mv_sht = { .ioctl = ata_scsi_ioctl, .queuecommand = ata_scsi_queuecmd, .eh_strategy_handler = ata_scsi_error, - .can_queue = ATA_DEF_QUEUE, + .can_queue = MV_USE_Q_DEPTH, .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = MV_UNDEF, + .sg_tablesize = MV_MAX_SG_CT, .max_sectors = ATA_MAX_SECTORS, .cmd_per_lun = ATA_SHT_CMD_PER_LUN, .emulated = ATA_SHT_EMULATED, - .use_clustering = MV_UNDEF, + .use_clustering = ATA_SHT_USE_CLUSTERING, .proc_name = DRV_NAME, .dma_boundary = MV_DMA_BOUNDARY, .slave_configure = ata_scsi_slave_config, @@ -210,7 +290,7 @@ static Scsi_Host_Template mv_sht = { .ordered_flush = 1, }; -static struct ata_port_operations mv_ops = { +static const struct ata_port_operations mv_ops = { .port_disable = ata_port_disable, .tf_load = ata_tf_load, @@ -221,10 +301,10 @@ static struct ata_port_operations mv_ops = { .phy_reset = mv_phy_reset, - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, + .qc_prep = mv_qc_prep, + .qc_issue = mv_qc_issue, - .eng_timeout = ata_eng_timeout, + .eng_timeout = mv_eng_timeout, .irq_handler = mv_interrupt, .irq_clear = mv_irq_clear, @@ -232,46 +312,39 @@ static struct ata_port_operations mv_ops = { .scr_read = mv_scr_read, .scr_write = mv_scr_write, - .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop, + .port_start = mv_port_start, + .port_stop = mv_port_stop, + .host_stop = mv_host_stop, }; static struct ata_port_info mv_port_info[] = { { /* chip_504x */ .sht = &mv_sht, - .host_flags = (ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | - ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO), - .pio_mask = 0x1f, /* pio4-0 */ - .udma_mask = 0, /* 0x7f (udma6-0 disabled for now) */ + .host_flags = MV_COMMON_FLAGS, + .pio_mask = 0x1f, /* pio0-4 */ + .udma_mask = 0, /* 0x7f (udma0-6 disabled for now) */ .port_ops = &mv_ops, }, { /* chip_508x */ .sht = &mv_sht, - .host_flags = (ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | - ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO | - MV_FLAG_DUAL_HC), - .pio_mask = 0x1f, /* pio4-0 */ - .udma_mask = 0, /* 0x7f (udma6-0 disabled for now) */ + .host_flags = (MV_COMMON_FLAGS | MV_FLAG_DUAL_HC), + .pio_mask = 0x1f, /* pio0-4 */ + .udma_mask = 0, /* 0x7f (udma0-6 disabled for now) */ .port_ops = &mv_ops, }, { /* chip_604x */ .sht = &mv_sht, - .host_flags = (ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | - ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO | - MV_FLAG_IRQ_COALESCE | MV_FLAG_BDMA), - .pio_mask = 0x1f, /* pio4-0 */ - .udma_mask = 0, /* 0x7f (udma6-0 disabled for now) */ + .host_flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS), + .pio_mask = 0x1f, /* pio0-4 */ + .udma_mask = 0x7f, /* udma0-6 */ .port_ops = &mv_ops, }, { /* chip_608x */ .sht = &mv_sht, - .host_flags = (ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | - ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO | - MV_FLAG_IRQ_COALESCE | MV_FLAG_DUAL_HC | - MV_FLAG_BDMA), - .pio_mask = 0x1f, /* pio4-0 */ - .udma_mask = 0, /* 0x7f (udma6-0 disabled for now) */ + .host_flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS | + MV_FLAG_DUAL_HC), + .pio_mask = 0x1f, /* pio0-4 */ + .udma_mask = 0x7f, /* udma0-6 */ .port_ops = &mv_ops, }, }; @@ -306,12 +379,6 @@ static inline void writelfl(unsigned long data, void __iomem *addr) (void) readl(addr); /* flush to avoid PCI posted write */ } -static inline void __iomem *mv_port_addr_to_hc_base(void __iomem *port_mmio) -{ - return ((void __iomem *)((unsigned long)port_mmio & - (unsigned long)SATAHC_MASK)); -} - static inline void __iomem *mv_hc_base(void __iomem *base, unsigned int hc) { return (base + MV_SATAHC0_REG_BASE + (hc * MV_SATAHC_REG_SZ)); @@ -329,24 +396,150 @@ static inline void __iomem *mv_ap_base(struct ata_port *ap) return mv_port_base(ap->host_set->mmio_base, ap->port_no); } -static inline int mv_get_hc_count(unsigned long flags) +static inline int mv_get_hc_count(unsigned long hp_flags) { - return ((flags & MV_FLAG_DUAL_HC) ? 2 : 1); + return ((hp_flags & MV_FLAG_DUAL_HC) ? 2 : 1); } -static inline int mv_is_edma_active(struct ata_port *ap) +static void mv_irq_clear(struct ata_port *ap) +{ +} + +/** + * mv_start_dma - Enable eDMA engine + * @base: port base address + * @pp: port private data + * + * Verify the local cache of the eDMA state is accurate with an + * assert. + * + * LOCKING: + * Inherited from caller. + */ +static void mv_start_dma(void __iomem *base, struct mv_port_priv *pp) +{ + if (!(MV_PP_FLAG_EDMA_EN & pp->pp_flags)) { + writelfl(EDMA_EN, base + EDMA_CMD_OFS); + pp->pp_flags |= MV_PP_FLAG_EDMA_EN; + } + assert(EDMA_EN & readl(base + EDMA_CMD_OFS)); +} + +/** + * mv_stop_dma - Disable eDMA engine + * @ap: ATA channel to manipulate + * + * Verify the local cache of the eDMA state is accurate with an + * assert. + * + * LOCKING: + * Inherited from caller. + */ +static void mv_stop_dma(struct ata_port *ap) { void __iomem *port_mmio = mv_ap_base(ap); - return (EDMA_EN & readl(port_mmio + EDMA_CMD_OFS)); + struct mv_port_priv *pp = ap->private_data; + u32 reg; + int i; + + if (MV_PP_FLAG_EDMA_EN & pp->pp_flags) { + /* Disable EDMA if active. The disable bit auto clears. + */ + writelfl(EDMA_DS, port_mmio + EDMA_CMD_OFS); + pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN; + } else { + assert(!(EDMA_EN & readl(port_mmio + EDMA_CMD_OFS))); + } + + /* now properly wait for the eDMA to stop */ + for (i = 1000; i > 0; i--) { + reg = readl(port_mmio + EDMA_CMD_OFS); + if (!(EDMA_EN & reg)) { + break; + } + udelay(100); + } + + if (EDMA_EN & reg) { + printk(KERN_ERR "ata%u: Unable to stop eDMA\n", ap->id); + /* FIXME: Consider doing a reset here to recover */ + } } -static inline int mv_port_bdma_capable(struct ata_port *ap) +#ifdef ATA_DEBUG +static void mv_dump_mem(void __iomem *start, unsigned bytes) { - return (ap->flags & MV_FLAG_BDMA); + int b, w; + for (b = 0; b < bytes; ) { + DPRINTK("%p: ", start + b); + for (w = 0; b < bytes && w < 4; w++) { + printk("%08x ",readl(start + b)); + b += sizeof(u32); + } + printk("\n"); + } } +#endif -static void mv_irq_clear(struct ata_port *ap) +static void mv_dump_pci_cfg(struct pci_dev *pdev, unsigned bytes) +{ +#ifdef ATA_DEBUG + int b, w; + u32 dw; + for (b = 0; b < bytes; ) { + DPRINTK("%02x: ", b); + for (w = 0; b < bytes && w < 4; w++) { + (void) pci_read_config_dword(pdev,b,&dw); + printk("%08x ",dw); + b += sizeof(u32); + } + printk("\n"); + } +#endif +} +static void mv_dump_all_regs(void __iomem *mmio_base, int port, + struct pci_dev *pdev) { +#ifdef ATA_DEBUG + void __iomem *hc_base = mv_hc_base(mmio_base, + port >> MV_PORT_HC_SHIFT); + void __iomem *port_base; + int start_port, num_ports, p, start_hc, num_hcs, hc; + + if (0 > port) { + start_hc = start_port = 0; + num_ports = 8; /* shld be benign for 4 port devs */ + num_hcs = 2; + } else { + start_hc = port >> MV_PORT_HC_SHIFT; + start_port = port; + num_ports = num_hcs = 1; + } + DPRINTK("All registers for port(s) %u-%u:\n", start_port, + num_ports > 1 ? num_ports - 1 : start_port); + + if (NULL != pdev) { + DPRINTK("PCI config space regs:\n"); + mv_dump_pci_cfg(pdev, 0x68); + } + DPRINTK("PCI regs:\n"); + mv_dump_mem(mmio_base+0xc00, 0x3c); + mv_dump_mem(mmio_base+0xd00, 0x34); + mv_dump_mem(mmio_base+0xf00, 0x4); + mv_dump_mem(mmio_base+0x1d00, 0x6c); + for (hc = start_hc; hc < start_hc + num_hcs; hc++) { + hc_base = mv_hc_base(mmio_base, port >> MV_PORT_HC_SHIFT); + DPRINTK("HC regs (HC %i):\n", hc); + mv_dump_mem(hc_base, 0x1c); + } + for (p = start_port; p < start_port + num_ports; p++) { + port_base = mv_port_base(mmio_base, p); + DPRINTK("EDMA regs (port %i):\n",p); + mv_dump_mem(port_base, 0x54); + DPRINTK("SATA regs (port %i):\n",p); + mv_dump_mem(port_base+0x300, 0x60); + } +#endif } static unsigned int mv_scr_offset(unsigned int sc_reg_in) @@ -389,30 +582,37 @@ static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val) } } -static int mv_master_reset(void __iomem *mmio_base) +/** + * mv_global_soft_reset - Perform the 6xxx global soft reset + * @mmio_base: base address of the HBA + * + * This routine only applies to 6xxx parts. + * + * LOCKING: + * Inherited from caller. + */ +static int mv_global_soft_reset(void __iomem *mmio_base) { void __iomem *reg = mmio_base + PCI_MAIN_CMD_STS_OFS; int i, rc = 0; u32 t; - VPRINTK("ENTER\n"); - /* Following procedure defined in PCI "main command and status * register" table. */ t = readl(reg); writel(t | STOP_PCI_MASTER, reg); - for (i = 0; i < 100; i++) { - msleep(10); + for (i = 0; i < 1000; i++) { + udelay(1); t = readl(reg); if (PCI_MASTER_EMPTY & t) { break; } } if (!(PCI_MASTER_EMPTY & t)) { - printk(KERN_ERR DRV_NAME "PCI master won't flush\n"); - rc = 1; /* broken HW? */ + printk(KERN_ERR DRV_NAME ": PCI master won't flush\n"); + rc = 1; goto done; } @@ -425,39 +625,399 @@ static int mv_master_reset(void __iomem *mmio_base) } while (!(GLOB_SFT_RST & t) && (i-- > 0)); if (!(GLOB_SFT_RST & t)) { - printk(KERN_ERR DRV_NAME "can't set global reset\n"); - rc = 1; /* broken HW? */ + printk(KERN_ERR DRV_NAME ": can't set global reset\n"); + rc = 1; goto done; } - /* clear reset */ + /* clear reset and *reenable the PCI master* (not mentioned in spec) */ i = 5; do { - writel(t & ~GLOB_SFT_RST, reg); + writel(t & ~(GLOB_SFT_RST | STOP_PCI_MASTER), reg); t = readl(reg); udelay(1); } while ((GLOB_SFT_RST & t) && (i-- > 0)); if (GLOB_SFT_RST & t) { - printk(KERN_ERR DRV_NAME "can't clear global reset\n"); - rc = 1; /* broken HW? */ + printk(KERN_ERR DRV_NAME ": can't clear global reset\n"); + rc = 1; } - - done: - VPRINTK("EXIT, rc = %i\n", rc); +done: return rc; } -static void mv_err_intr(struct ata_port *ap) +/** + * mv_host_stop - Host specific cleanup/stop routine. + * @host_set: host data structure + * + * Disable ints, cleanup host memory, call general purpose + * host_stop. + * + * LOCKING: + * Inherited from caller. + */ +static void mv_host_stop(struct ata_host_set *host_set) { - void __iomem *port_mmio; - u32 edma_err_cause, serr = 0; + struct mv_host_priv *hpriv = host_set->private_data; + struct pci_dev *pdev = to_pci_dev(host_set->dev); + + if (hpriv->hp_flags & MV_HP_FLAG_MSI) { + pci_disable_msi(pdev); + } else { + pci_intx(pdev, 0); + } + kfree(hpriv); + ata_host_stop(host_set); +} + +/** + * mv_port_start - Port specific init/start routine. + * @ap: ATA channel to manipulate + * + * Allocate and point to DMA memory, init port private memory, + * zero indices. + * + * LOCKING: + * Inherited from caller. + */ +static int mv_port_start(struct ata_port *ap) +{ + struct device *dev = ap->host_set->dev; + struct mv_port_priv *pp; + void __iomem *port_mmio = mv_ap_base(ap); + void *mem; + dma_addr_t mem_dma; + + pp = kmalloc(sizeof(*pp), GFP_KERNEL); + if (!pp) { + return -ENOMEM; + } + memset(pp, 0, sizeof(*pp)); + + mem = dma_alloc_coherent(dev, MV_PORT_PRIV_DMA_SZ, &mem_dma, + GFP_KERNEL); + if (!mem) { + kfree(pp); + return -ENOMEM; + } + memset(mem, 0, MV_PORT_PRIV_DMA_SZ); + + /* First item in chunk of DMA memory: + * 32-slot command request table (CRQB), 32 bytes each in size + */ + pp->crqb = mem; + pp->crqb_dma = mem_dma; + mem += MV_CRQB_Q_SZ; + mem_dma += MV_CRQB_Q_SZ; + + /* Second item: + * 32-slot command response table (CRPB), 8 bytes each in size + */ + pp->crpb = mem; + pp->crpb_dma = mem_dma; + mem += MV_CRPB_Q_SZ; + mem_dma += MV_CRPB_Q_SZ; + + /* Third item: + * Table of scatter-gather descriptors (ePRD), 16 bytes each + */ + pp->sg_tbl = mem; + pp->sg_tbl_dma = mem_dma; + + writelfl(EDMA_CFG_Q_DEPTH | EDMA_CFG_RD_BRST_EXT | + EDMA_CFG_WR_BUFF_LEN, port_mmio + EDMA_CFG_OFS); - /* bug here b/c we got an err int on a port we don't know about, - * so there's no way to clear it + writel((pp->crqb_dma >> 16) >> 16, port_mmio + EDMA_REQ_Q_BASE_HI_OFS); + writelfl(pp->crqb_dma & EDMA_REQ_Q_BASE_LO_MASK, + port_mmio + EDMA_REQ_Q_IN_PTR_OFS); + + writelfl(0, port_mmio + EDMA_REQ_Q_OUT_PTR_OFS); + writelfl(0, port_mmio + EDMA_RSP_Q_IN_PTR_OFS); + + writel((pp->crpb_dma >> 16) >> 16, port_mmio + EDMA_RSP_Q_BASE_HI_OFS); + writelfl(pp->crpb_dma & EDMA_RSP_Q_BASE_LO_MASK, + port_mmio + EDMA_RSP_Q_OUT_PTR_OFS); + + pp->req_producer = pp->rsp_consumer = 0; + + /* Don't turn on EDMA here...do it before DMA commands only. Else + * we'll be unable to send non-data, PIO, etc due to restricted access + * to shadow regs. */ - BUG_ON(NULL == ap); - port_mmio = mv_ap_base(ap); + ap->private_data = pp; + return 0; +} + +/** + * mv_port_stop - Port specific cleanup/stop routine. + * @ap: ATA channel to manipulate + * + * Stop DMA, cleanup port memory. + * + * LOCKING: + * This routine uses the host_set lock to protect the DMA stop. + */ +static void mv_port_stop(struct ata_port *ap) +{ + struct device *dev = ap->host_set->dev; + struct mv_port_priv *pp = ap->private_data; + unsigned long flags; + + spin_lock_irqsave(&ap->host_set->lock, flags); + mv_stop_dma(ap); + spin_unlock_irqrestore(&ap->host_set->lock, flags); + + ap->private_data = NULL; + dma_free_coherent(dev, MV_PORT_PRIV_DMA_SZ, pp->crpb, pp->crpb_dma); + kfree(pp); +} + +/** + * mv_fill_sg - Fill out the Marvell ePRD (scatter gather) entries + * @qc: queued command whose SG list to source from + * + * Populate the SG list and mark the last entry. + * + * LOCKING: + * Inherited from caller. + */ +static void mv_fill_sg(struct ata_queued_cmd *qc) +{ + struct mv_port_priv *pp = qc->ap->private_data; + unsigned int i; + + for (i = 0; i < qc->n_elem; i++) { + u32 sg_len; + dma_addr_t addr; + + addr = sg_dma_address(&qc->sg[i]); + sg_len = sg_dma_len(&qc->sg[i]); + + pp->sg_tbl[i].addr = cpu_to_le32(addr & 0xffffffff); + pp->sg_tbl[i].addr_hi = cpu_to_le32((addr >> 16) >> 16); + assert(0 == (sg_len & ~MV_DMA_BOUNDARY)); + pp->sg_tbl[i].flags_size = cpu_to_le32(sg_len); + } + if (0 < qc->n_elem) { + pp->sg_tbl[qc->n_elem - 1].flags_size |= + cpu_to_le32(EPRD_FLAG_END_OF_TBL); + } +} + +static inline unsigned mv_inc_q_index(unsigned *index) +{ + *index = (*index + 1) & MV_MAX_Q_DEPTH_MASK; + return *index; +} + +static inline void mv_crqb_pack_cmd(u16 *cmdw, u8 data, u8 addr, unsigned last) +{ + *cmdw = data | (addr << CRQB_CMD_ADDR_SHIFT) | CRQB_CMD_CS | + (last ? CRQB_CMD_LAST : 0); +} + +/** + * mv_qc_prep - Host specific command preparation. + * @qc: queued command to prepare + * + * This routine simply redirects to the general purpose routine + * if command is not DMA. Else, it handles prep of the CRQB + * (command request block), does some sanity checking, and calls + * the SG load routine. + * + * LOCKING: + * Inherited from caller. + */ +static void mv_qc_prep(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct mv_port_priv *pp = ap->private_data; + u16 *cw; + struct ata_taskfile *tf; + u16 flags = 0; + + if (ATA_PROT_DMA != qc->tf.protocol) { + return; + } + + /* the req producer index should be the same as we remember it */ + assert(((readl(mv_ap_base(qc->ap) + EDMA_REQ_Q_IN_PTR_OFS) >> + EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) == + pp->req_producer); + + /* Fill in command request block + */ + if (!(qc->tf.flags & ATA_TFLAG_WRITE)) { + flags |= CRQB_FLAG_READ; + } + assert(MV_MAX_Q_DEPTH > qc->tag); + flags |= qc->tag << CRQB_TAG_SHIFT; + + pp->crqb[pp->req_producer].sg_addr = + cpu_to_le32(pp->sg_tbl_dma & 0xffffffff); + pp->crqb[pp->req_producer].sg_addr_hi = + cpu_to_le32((pp->sg_tbl_dma >> 16) >> 16); + pp->crqb[pp->req_producer].ctrl_flags = cpu_to_le16(flags); + + cw = &pp->crqb[pp->req_producer].ata_cmd[0]; + tf = &qc->tf; + + /* Sadly, the CRQB cannot accomodate all registers--there are + * only 11 bytes...so we must pick and choose required + * registers based on the command. So, we drop feature and + * hob_feature for [RW] DMA commands, but they are needed for + * NCQ. NCQ will drop hob_nsect. + */ + switch (tf->command) { + case ATA_CMD_READ: + case ATA_CMD_READ_EXT: + case ATA_CMD_WRITE: + case ATA_CMD_WRITE_EXT: + mv_crqb_pack_cmd(cw++, tf->hob_nsect, ATA_REG_NSECT, 0); + break; +#ifdef LIBATA_NCQ /* FIXME: remove this line when NCQ added */ + case ATA_CMD_FPDMA_READ: + case ATA_CMD_FPDMA_WRITE: + mv_crqb_pack_cmd(cw++, tf->hob_feature, ATA_REG_FEATURE, 0); + mv_crqb_pack_cmd(cw++, tf->feature, ATA_REG_FEATURE, 0); + break; +#endif /* FIXME: remove this line when NCQ added */ + default: + /* The only other commands EDMA supports in non-queued and + * non-NCQ mode are: [RW] STREAM DMA and W DMA FUA EXT, none + * of which are defined/used by Linux. If we get here, this + * driver needs work. + * + * FIXME: modify libata to give qc_prep a return value and + * return error here. + */ + BUG_ON(tf->command); + break; + } + mv_crqb_pack_cmd(cw++, tf->nsect, ATA_REG_NSECT, 0); + mv_crqb_pack_cmd(cw++, tf->hob_lbal, ATA_REG_LBAL, 0); + mv_crqb_pack_cmd(cw++, tf->lbal, ATA_REG_LBAL, 0); + mv_crqb_pack_cmd(cw++, tf->hob_lbam, ATA_REG_LBAM, 0); + mv_crqb_pack_cmd(cw++, tf->lbam, ATA_REG_LBAM, 0); + mv_crqb_pack_cmd(cw++, tf->hob_lbah, ATA_REG_LBAH, 0); + mv_crqb_pack_cmd(cw++, tf->lbah, ATA_REG_LBAH, 0); + mv_crqb_pack_cmd(cw++, tf->device, ATA_REG_DEVICE, 0); + mv_crqb_pack_cmd(cw++, tf->command, ATA_REG_CMD, 1); /* last */ + + if (!(qc->flags & ATA_QCFLAG_DMAMAP)) { + return; + } + mv_fill_sg(qc); +} + +/** + * mv_qc_issue - Initiate a command to the host + * @qc: queued command to start + * + * This routine simply redirects to the general purpose routine + * if command is not DMA. Else, it sanity checks our local + * caches of the request producer/consumer indices then enables + * DMA and bumps the request producer index. + * + * LOCKING: + * Inherited from caller. + */ +static int mv_qc_issue(struct ata_queued_cmd *qc) +{ + void __iomem *port_mmio = mv_ap_base(qc->ap); + struct mv_port_priv *pp = qc->ap->private_data; + u32 in_ptr; + + if (ATA_PROT_DMA != qc->tf.protocol) { + /* We're about to send a non-EDMA capable command to the + * port. Turn off EDMA so there won't be problems accessing + * shadow block, etc registers. + */ + mv_stop_dma(qc->ap); + return ata_qc_issue_prot(qc); + } + + in_ptr = readl(port_mmio + EDMA_REQ_Q_IN_PTR_OFS); + + /* the req producer index should be the same as we remember it */ + assert(((in_ptr >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) == + pp->req_producer); + /* until we do queuing, the queue should be empty at this point */ + assert(((in_ptr >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) == + ((readl(port_mmio + EDMA_REQ_Q_OUT_PTR_OFS) >> + EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK)); + + mv_inc_q_index(&pp->req_producer); /* now incr producer index */ + + mv_start_dma(port_mmio, pp); + + /* and write the request in pointer to kick the EDMA to life */ + in_ptr &= EDMA_REQ_Q_BASE_LO_MASK; + in_ptr |= pp->req_producer << EDMA_REQ_Q_PTR_SHIFT; + writelfl(in_ptr, port_mmio + EDMA_REQ_Q_IN_PTR_OFS); + + return 0; +} + +/** + * mv_get_crpb_status - get status from most recently completed cmd + * @ap: ATA channel to manipulate + * + * This routine is for use when the port is in DMA mode, when it + * will be using the CRPB (command response block) method of + * returning command completion information. We assert indices + * are good, grab status, and bump the response consumer index to + * prove that we're up to date. + * + * LOCKING: + * Inherited from caller. + */ +static u8 mv_get_crpb_status(struct ata_port *ap) +{ + void __iomem *port_mmio = mv_ap_base(ap); + struct mv_port_priv *pp = ap->private_data; + u32 out_ptr; + + out_ptr = readl(port_mmio + EDMA_RSP_Q_OUT_PTR_OFS); + + /* the response consumer index should be the same as we remember it */ + assert(((out_ptr >> EDMA_RSP_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) == + pp->rsp_consumer); + + /* increment our consumer index... */ + pp->rsp_consumer = mv_inc_q_index(&pp->rsp_consumer); + + /* and, until we do NCQ, there should only be 1 CRPB waiting */ + assert(((readl(port_mmio + EDMA_RSP_Q_IN_PTR_OFS) >> + EDMA_RSP_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) == + pp->rsp_consumer); + + /* write out our inc'd consumer index so EDMA knows we're caught up */ + out_ptr &= EDMA_RSP_Q_BASE_LO_MASK; + out_ptr |= pp->rsp_consumer << EDMA_RSP_Q_PTR_SHIFT; + writelfl(out_ptr, port_mmio + EDMA_RSP_Q_OUT_PTR_OFS); + + /* Return ATA status register for completed CRPB */ + return (pp->crpb[pp->rsp_consumer].flags >> CRPB_FLAG_STATUS_SHIFT); +} + +/** + * mv_err_intr - Handle error interrupts on the port + * @ap: ATA channel to manipulate + * + * In most cases, just clear the interrupt and move on. However, + * some cases require an eDMA reset, which is done right before + * the COMRESET in mv_phy_reset(). The SERR case requires a + * clear of pending errors in the SATA SERROR register. Finally, + * if the port disabled DMA, update our cached copy to match. + * + * LOCKING: + * Inherited from caller. + */ +static void mv_err_intr(struct ata_port *ap) +{ + void __iomem *port_mmio = mv_ap_base(ap); + u32 edma_err_cause, serr = 0; edma_err_cause = readl(port_mmio + EDMA_ERR_IRQ_CAUSE_OFS); @@ -465,8 +1025,12 @@ static void mv_err_intr(struct ata_port *ap) serr = scr_read(ap, SCR_ERROR); scr_write_flush(ap, SCR_ERROR, serr); } - DPRINTK("port %u error; EDMA err cause: 0x%08x SERR: 0x%08x\n", - ap->port_no, edma_err_cause, serr); + if (EDMA_ERR_SELF_DIS & edma_err_cause) { + struct mv_port_priv *pp = ap->private_data; + pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN; + } + DPRINTK(KERN_ERR "ata%u: port error; EDMA err cause: 0x%08x " + "SERR: 0x%08x\n", ap->id, edma_err_cause, serr); /* Clear EDMA now that SERR cleanup done */ writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS); @@ -477,7 +1041,21 @@ static void mv_err_intr(struct ata_port *ap) } } -/* Handle any outstanding interrupts in a single SATAHC +/** + * mv_host_intr - Handle all interrupts on the given host controller + * @host_set: host specific structure + * @relevant: port error bits relevant to this host controller + * @hc: which host controller we're to look at + * + * Read then write clear the HC interrupt status then walk each + * port connected to the HC and see if it needs servicing. Port + * success ints are reported in the HC interrupt status reg, the + * port error ints are reported in the higher level main + * interrupt status register and thus are passed in via the + * 'relevant' argument. + * + * LOCKING: + * Inherited from caller. */ static void mv_host_intr(struct ata_host_set *host_set, u32 relevant, unsigned int hc) @@ -487,8 +1065,9 @@ static void mv_host_intr(struct ata_host_set *host_set, u32 relevant, struct ata_port *ap; struct ata_queued_cmd *qc; u32 hc_irq_cause; - int shift, port, port0, hard_port; - u8 ata_status; + int shift, port, port0, hard_port, handled; + unsigned int err_mask; + u8 ata_status = 0; if (hc == 0) { port0 = 0; @@ -499,7 +1078,7 @@ static void mv_host_intr(struct ata_host_set *host_set, u32 relevant, /* we'll need the HC success int register in most cases */ hc_irq_cause = readl(hc_mmio + HC_IRQ_CAUSE_OFS); if (hc_irq_cause) { - writelfl(0, hc_mmio + HC_IRQ_CAUSE_OFS); + writelfl(~hc_irq_cause, hc_mmio + HC_IRQ_CAUSE_OFS); } VPRINTK("ENTER, hc%u relevant=0x%08x HC IRQ cause=0x%08x\n", @@ -508,54 +1087,70 @@ static void mv_host_intr(struct ata_host_set *host_set, u32 relevant, for (port = port0; port < port0 + MV_PORTS_PER_HC; port++) { ap = host_set->ports[port]; hard_port = port & MV_PORT_MASK; /* range 0-3 */ - ata_status = 0xffU; + handled = 0; /* ensure ata_status is set if handled++ */ - if (((CRBP_DMA_DONE | DEV_IRQ) << hard_port) & hc_irq_cause) { - BUG_ON(NULL == ap); - /* rcv'd new resp, basic DMA complete, or ATA IRQ */ - /* This is needed to clear the ATA INTRQ. - * FIXME: don't read the status reg in EDMA mode! + if ((CRPB_DMA_DONE << hard_port) & hc_irq_cause) { + /* new CRPB on the queue; just one at a time until NCQ + */ + ata_status = mv_get_crpb_status(ap); + handled++; + } else if ((DEV_IRQ << hard_port) & hc_irq_cause) { + /* received ATA IRQ; read the status reg to clear INTRQ */ ata_status = readb((void __iomem *) ap->ioaddr.status_addr); + handled++; } - shift = port * 2; + err_mask = ac_err_mask(ata_status); + + shift = port << 1; /* (port * 2) */ if (port >= MV_PORTS_PER_HC) { shift++; /* skip bit 8 in the HC Main IRQ reg */ } if ((PORT0_ERR << shift) & relevant) { mv_err_intr(ap); - /* FIXME: smart to OR in ATA_ERR? */ - ata_status = readb((void __iomem *) - ap->ioaddr.status_addr) | ATA_ERR; + err_mask |= AC_ERR_OTHER; + handled++; } - if (ap) { + if (handled && ap) { qc = ata_qc_from_tag(ap, ap->active_tag); if (NULL != qc) { VPRINTK("port %u IRQ found for qc, " "ata_status 0x%x\n", port,ata_status); - BUG_ON(0xffU == ata_status); /* mark qc status appropriately */ - ata_qc_complete(qc, ata_status); + ata_qc_complete(qc, err_mask); } } } VPRINTK("EXIT\n"); } +/** + * mv_interrupt - + * @irq: unused + * @dev_instance: private data; in this case the host structure + * @regs: unused + * + * Read the read only register to determine if any host + * controllers have pending interrupts. If so, call lower level + * routine to handle. Also check for PCI errors which are only + * reported here. + * + * LOCKING: + * This routine holds the host_set lock while processing pending + * interrupts. + */ static irqreturn_t mv_interrupt(int irq, void *dev_instance, struct pt_regs *regs) { struct ata_host_set *host_set = dev_instance; unsigned int hc, handled = 0, n_hcs; - void __iomem *mmio; + void __iomem *mmio = host_set->mmio_base; u32 irq_stat; - mmio = host_set->mmio_base; irq_stat = readl(mmio + HC_MAIN_IRQ_CAUSE_OFS); - n_hcs = mv_get_hc_count(host_set->ports[0]->flags); /* check the cases where we either have nothing pending or have read * a bogus register value which can indicate HW removal or PCI fault @@ -564,64 +1159,89 @@ static irqreturn_t mv_interrupt(int irq, void *dev_instance, return IRQ_NONE; } + n_hcs = mv_get_hc_count(host_set->ports[0]->flags); spin_lock(&host_set->lock); for (hc = 0; hc < n_hcs; hc++) { u32 relevant = irq_stat & (HC0_IRQ_PEND << (hc * HC_SHIFT)); if (relevant) { mv_host_intr(host_set, relevant, hc); - handled = 1; + handled++; } } if (PCI_ERR & irq_stat) { - /* FIXME: these are all masked by default, but still need - * to recover from them properly. - */ - } + printk(KERN_ERR DRV_NAME ": PCI ERROR; PCI IRQ cause=0x%08x\n", + readl(mmio + PCI_IRQ_CAUSE_OFS)); + DPRINTK("All regs @ PCI error\n"); + mv_dump_all_regs(mmio, -1, to_pci_dev(host_set->dev)); + + writelfl(0, mmio + PCI_IRQ_CAUSE_OFS); + handled++; + } spin_unlock(&host_set->lock); return IRQ_RETVAL(handled); } +/** + * mv_phy_reset - Perform eDMA reset followed by COMRESET + * @ap: ATA channel to manipulate + * + * Part of this is taken from __sata_phy_reset and modified to + * not sleep since this routine gets called from interrupt level. + * + * LOCKING: + * Inherited from caller. This is coded to safe to call at + * interrupt level, i.e. it does not sleep. + */ static void mv_phy_reset(struct ata_port *ap) { void __iomem *port_mmio = mv_ap_base(ap); struct ata_taskfile tf; struct ata_device *dev = &ap->device[0]; - u32 edma = 0, bdma; + unsigned long timeout; VPRINTK("ENTER, port %u, mmio 0x%p\n", ap->port_no, port_mmio); - edma = readl(port_mmio + EDMA_CMD_OFS); - if (EDMA_EN & edma) { - /* disable EDMA if active */ - edma &= ~EDMA_EN; - writelfl(edma | EDMA_DS, port_mmio + EDMA_CMD_OFS); - udelay(1); - } else if (mv_port_bdma_capable(ap) && - (bdma = readl(port_mmio + BDMA_CMD_OFS)) & BDMA_START) { - /* disable BDMA if active */ - writelfl(bdma & ~BDMA_START, port_mmio + BDMA_CMD_OFS); - } + mv_stop_dma(ap); - writelfl(edma | ATA_RST, port_mmio + EDMA_CMD_OFS); + writelfl(ATA_RST, port_mmio + EDMA_CMD_OFS); udelay(25); /* allow reset propagation */ /* Spec never mentions clearing the bit. Marvell's driver does * clear the bit, however. */ - writelfl(edma & ~ATA_RST, port_mmio + EDMA_CMD_OFS); + writelfl(0, port_mmio + EDMA_CMD_OFS); - VPRINTK("Done. Now calling __sata_phy_reset()\n"); + VPRINTK("S-regs after ATA_RST: SStat 0x%08x SErr 0x%08x " + "SCtrl 0x%08x\n", mv_scr_read(ap, SCR_STATUS), + mv_scr_read(ap, SCR_ERROR), mv_scr_read(ap, SCR_CONTROL)); /* proceed to init communications via the scr_control reg */ - __sata_phy_reset(ap); + scr_write_flush(ap, SCR_CONTROL, 0x301); + mdelay(1); + scr_write_flush(ap, SCR_CONTROL, 0x300); + timeout = jiffies + (HZ * 1); + do { + mdelay(10); + if ((scr_read(ap, SCR_STATUS) & 0xf) != 1) + break; + } while (time_before(jiffies, timeout)); + + VPRINTK("S-regs after PHY wake: SStat 0x%08x SErr 0x%08x " + "SCtrl 0x%08x\n", mv_scr_read(ap, SCR_STATUS), + mv_scr_read(ap, SCR_ERROR), mv_scr_read(ap, SCR_CONTROL)); - if (ap->flags & ATA_FLAG_PORT_DISABLED) { - VPRINTK("Port disabled pre-sig. Exiting.\n"); + if (sata_dev_present(ap)) { + ata_port_probe(ap); + } else { + printk(KERN_INFO "ata%u: no device found (phy stat %08x)\n", + ap->id, scr_read(ap, SCR_STATUS)); + ata_port_disable(ap); return; } + ap->cbl = ATA_CBL_SATA; tf.lbah = readb((void __iomem *) ap->ioaddr.lbah_addr); tf.lbam = readb((void __iomem *) ap->ioaddr.lbam_addr); @@ -636,37 +1256,118 @@ static void mv_phy_reset(struct ata_port *ap) VPRINTK("EXIT\n"); } -static void mv_port_init(struct ata_ioports *port, unsigned long base) +/** + * mv_eng_timeout - Routine called by libata when SCSI times out I/O + * @ap: ATA channel to manipulate + * + * Intent is to clear all pending error conditions, reset the + * chip/bus, fail the command, and move on. + * + * LOCKING: + * This routine holds the host_set lock while failing the command. + */ +static void mv_eng_timeout(struct ata_port *ap) +{ + struct ata_queued_cmd *qc; + unsigned long flags; + + printk(KERN_ERR "ata%u: Entering mv_eng_timeout\n",ap->id); + DPRINTK("All regs @ start of eng_timeout\n"); + mv_dump_all_regs(ap->host_set->mmio_base, ap->port_no, + to_pci_dev(ap->host_set->dev)); + + qc = ata_qc_from_tag(ap, ap->active_tag); + printk(KERN_ERR "mmio_base %p ap %p qc %p scsi_cmnd %p &cmnd %p\n", + ap->host_set->mmio_base, ap, qc, qc->scsicmd, + &qc->scsicmd->cmnd); + + mv_err_intr(ap); + mv_phy_reset(ap); + + if (!qc) { + printk(KERN_ERR "ata%u: BUG: timeout without command\n", + ap->id); + } else { + /* hack alert! We cannot use the supplied completion + * function from inside the ->eh_strategy_handler() thread. + * libata is the only user of ->eh_strategy_handler() in + * any kernel, so the default scsi_done() assumes it is + * not being called from the SCSI EH. + */ + spin_lock_irqsave(&ap->host_set->lock, flags); + qc->scsidone = scsi_finish_command; + ata_qc_complete(qc, AC_ERR_OTHER); + spin_unlock_irqrestore(&ap->host_set->lock, flags); + } +} + +/** + * mv_port_init - Perform some early initialization on a single port. + * @port: libata data structure storing shadow register addresses + * @port_mmio: base address of the port + * + * Initialize shadow register mmio addresses, clear outstanding + * interrupts on the port, and unmask interrupts for the future + * start of the port. + * + * LOCKING: + * Inherited from caller. + */ +static void mv_port_init(struct ata_ioports *port, void __iomem *port_mmio) { - /* PIO related setup */ - port->data_addr = base + SHD_PIO_DATA_OFS; - port->error_addr = port->feature_addr = base + SHD_FEA_ERR_OFS; - port->nsect_addr = base + SHD_SECT_CNT_OFS; - port->lbal_addr = base + SHD_LBA_L_OFS; - port->lbam_addr = base + SHD_LBA_M_OFS; - port->lbah_addr = base + SHD_LBA_H_OFS; - port->device_addr = base + SHD_DEV_HD_OFS; - port->status_addr = port->command_addr = base + SHD_CMD_STA_OFS; - port->altstatus_addr = port->ctl_addr = base + SHD_CTL_AST_OFS; - /* unused */ + unsigned long shd_base = (unsigned long) port_mmio + SHD_BLK_OFS; + unsigned serr_ofs; + + /* PIO related setup + */ + port->data_addr = shd_base + (sizeof(u32) * ATA_REG_DATA); + port->error_addr = + port->feature_addr = shd_base + (sizeof(u32) * ATA_REG_ERR); + port->nsect_addr = shd_base + (sizeof(u32) * ATA_REG_NSECT); + port->lbal_addr = shd_base + (sizeof(u32) * ATA_REG_LBAL); + port->lbam_addr = shd_base + (sizeof(u32) * ATA_REG_LBAM); + port->lbah_addr = shd_base + (sizeof(u32) * ATA_REG_LBAH); + port->device_addr = shd_base + (sizeof(u32) * ATA_REG_DEVICE); + port->status_addr = + port->command_addr = shd_base + (sizeof(u32) * ATA_REG_STATUS); + /* special case: control/altstatus doesn't have ATA_REG_ address */ + port->altstatus_addr = port->ctl_addr = shd_base + SHD_CTL_AST_OFS; + + /* unused: */ port->cmd_addr = port->bmdma_addr = port->scr_addr = 0; + /* Clear any currently outstanding port interrupt conditions */ + serr_ofs = mv_scr_offset(SCR_ERROR); + writelfl(readl(port_mmio + serr_ofs), port_mmio + serr_ofs); + writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS); + /* unmask all EDMA error interrupts */ - writel(~0, (void __iomem *)base + EDMA_ERR_IRQ_MASK_OFS); + writelfl(~0, port_mmio + EDMA_ERR_IRQ_MASK_OFS); VPRINTK("EDMA cfg=0x%08x EDMA IRQ err cause/mask=0x%08x/0x%08x\n", - readl((void __iomem *)base + EDMA_CFG_OFS), - readl((void __iomem *)base + EDMA_ERR_IRQ_CAUSE_OFS), - readl((void __iomem *)base + EDMA_ERR_IRQ_MASK_OFS)); + readl(port_mmio + EDMA_CFG_OFS), + readl(port_mmio + EDMA_ERR_IRQ_CAUSE_OFS), + readl(port_mmio + EDMA_ERR_IRQ_MASK_OFS)); } +/** + * mv_host_init - Perform some early initialization of the host. + * @probe_ent: early data struct representing the host + * + * If possible, do an early global reset of the host. Then do + * our port init and clear/unmask all/relevant host interrupts. + * + * LOCKING: + * Inherited from caller. + */ static int mv_host_init(struct ata_probe_ent *probe_ent) { int rc = 0, n_hc, port, hc; void __iomem *mmio = probe_ent->mmio_base; void __iomem *port_mmio; - if (mv_master_reset(probe_ent->mmio_base)) { + if ((MV_FLAG_GLBL_SFT_RST & probe_ent->host_flags) && + mv_global_soft_reset(probe_ent->mmio_base)) { rc = 1; goto done; } @@ -676,17 +1377,27 @@ static int mv_host_init(struct ata_probe_ent *probe_ent) for (port = 0; port < probe_ent->n_ports; port++) { port_mmio = mv_port_base(mmio, port); - mv_port_init(&probe_ent->port[port], (unsigned long)port_mmio); + mv_port_init(&probe_ent->port[port], port_mmio); } for (hc = 0; hc < n_hc; hc++) { - VPRINTK("HC%i: HC config=0x%08x HC IRQ cause=0x%08x\n", hc, - readl(mv_hc_base(mmio, hc) + HC_CFG_OFS), - readl(mv_hc_base(mmio, hc) + HC_IRQ_CAUSE_OFS)); + void __iomem *hc_mmio = mv_hc_base(mmio, hc); + + VPRINTK("HC%i: HC config=0x%08x HC IRQ cause " + "(before clear)=0x%08x\n", hc, + readl(hc_mmio + HC_CFG_OFS), + readl(hc_mmio + HC_IRQ_CAUSE_OFS)); + + /* Clear any currently outstanding hc interrupt conditions */ + writelfl(0, hc_mmio + HC_IRQ_CAUSE_OFS); } - writel(~HC_MAIN_MASKED_IRQS, mmio + HC_MAIN_IRQ_MASK_OFS); - writel(PCI_UNMASK_ALL_IRQS, mmio + PCI_IRQ_MASK_OFS); + /* Clear any currently outstanding host interrupt conditions */ + writelfl(0, mmio + PCI_IRQ_CAUSE_OFS); + + /* and unmask interrupt generation for host regs */ + writelfl(PCI_UNMASK_ALL_IRQS, mmio + PCI_IRQ_MASK_OFS); + writelfl(~HC_MAIN_MASKED_IRQS, mmio + HC_MAIN_IRQ_MASK_OFS); VPRINTK("HC MAIN IRQ cause/mask=0x%08x/0x%08x " "PCI int cause/mask=0x%08x/0x%08x\n", @@ -694,11 +1405,53 @@ static int mv_host_init(struct ata_probe_ent *probe_ent) readl(mmio + HC_MAIN_IRQ_MASK_OFS), readl(mmio + PCI_IRQ_CAUSE_OFS), readl(mmio + PCI_IRQ_MASK_OFS)); - - done: +done: return rc; } +/** + * mv_print_info - Dump key info to kernel log for perusal. + * @probe_ent: early data struct representing the host + * + * FIXME: complete this. + * + * LOCKING: + * Inherited from caller. + */ +static void mv_print_info(struct ata_probe_ent *probe_ent) +{ + struct pci_dev *pdev = to_pci_dev(probe_ent->dev); + struct mv_host_priv *hpriv = probe_ent->private_data; + u8 rev_id, scc; + const char *scc_s; + + /* Use this to determine the HW stepping of the chip so we know + * what errata to workaround + */ + pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id); + + pci_read_config_byte(pdev, PCI_CLASS_DEVICE, &scc); + if (scc == 0) + scc_s = "SCSI"; + else if (scc == 0x01) + scc_s = "RAID"; + else + scc_s = "unknown"; + + dev_printk(KERN_INFO, &pdev->dev, + "%u slots %u ports %s mode IRQ via %s\n", + (unsigned)MV_MAX_Q_DEPTH, probe_ent->n_ports, + scc_s, (MV_HP_FLAG_MSI & hpriv->hp_flags) ? "MSI" : "INTx"); +} + +/** + * mv_init_one - handle a positive probe of a Marvell host + * @pdev: PCI device found + * @ent: PCI device ID entry for the matched host + * + * LOCKING: + * Inherited from caller. + */ static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { static int printed_version = 0; @@ -706,15 +1459,10 @@ static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) struct mv_host_priv *hpriv; unsigned int board_idx = (unsigned int)ent->driver_data; void __iomem *mmio_base; - int pci_dev_busy = 0; - int rc; + int pci_dev_busy = 0, rc; - if (!printed_version++) { - printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); - } - - VPRINTK("ENTER for PCI Bus:Slot.Func=%u:%u.%u\n", pdev->bus->number, - PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); + if (!printed_version++) + dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n"); rc = pci_enable_device(pdev); if (rc) { @@ -727,8 +1475,6 @@ static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_out; } - pci_intx(pdev, 1); - probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL); if (probe_ent == NULL) { rc = -ENOMEM; @@ -739,8 +1485,7 @@ static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) probe_ent->dev = pci_dev_to_dev(pdev); INIT_LIST_HEAD(&probe_ent->node); - mmio_base = ioremap_nocache(pci_resource_start(pdev, MV_PRIMARY_BAR), - pci_resource_len(pdev, MV_PRIMARY_BAR)); + mmio_base = pci_iomap(pdev, MV_PRIMARY_BAR, 0); if (mmio_base == NULL) { rc = -ENOMEM; goto err_out_free_ent; @@ -769,37 +1514,40 @@ static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) { goto err_out_hpriv; } -/* mv_print_info(probe_ent); */ - { - int b, w; - u32 dw[4]; /* hold a line of 16b */ - VPRINTK("PCI config space:\n"); - for (b = 0; b < 0x40; ) { - for (w = 0; w < 4; w++) { - (void) pci_read_config_dword(pdev,b,&dw[w]); - b += sizeof(*dw); - } - VPRINTK("%08x %08x %08x %08x\n", - dw[0],dw[1],dw[2],dw[3]); - } + /* Enable interrupts */ + if (pci_enable_msi(pdev) == 0) { + hpriv->hp_flags |= MV_HP_FLAG_MSI; + } else { + pci_intx(pdev, 1); } - /* FIXME: check ata_device_add return value */ - ata_device_add(probe_ent); - kfree(probe_ent); + mv_dump_pci_cfg(pdev, 0x68); + mv_print_info(probe_ent); + + if (ata_device_add(probe_ent) == 0) { + rc = -ENODEV; /* No devices discovered */ + goto err_out_dev_add; + } + kfree(probe_ent); return 0; - err_out_hpriv: +err_out_dev_add: + if (MV_HP_FLAG_MSI & hpriv->hp_flags) { + pci_disable_msi(pdev); + } else { + pci_intx(pdev, 0); + } +err_out_hpriv: kfree(hpriv); - err_out_iounmap: - iounmap(mmio_base); - err_out_free_ent: +err_out_iounmap: + pci_iounmap(pdev, mmio_base); +err_out_free_ent: kfree(probe_ent); - err_out_regions: +err_out_regions: pci_release_regions(pdev); - err_out: +err_out: if (!pci_dev_busy) { pci_disable_device(pdev); } diff --git a/drivers/scsi/sata_nv.c b/drivers/scsi/sata_nv.c index cb832b03ec5e..d573888eda76 100644 --- a/drivers/scsi/sata_nv.c +++ b/drivers/scsi/sata_nv.c @@ -61,6 +61,7 @@ #include <linux/blkdev.h> #include <linux/delay.h> #include <linux/interrupt.h> +#include <linux/device.h> #include "scsi.h" #include <scsi/scsi_host.h> #include <linux/libata.h> @@ -238,7 +239,7 @@ static Scsi_Host_Template nv_sht = { .ordered_flush = 1, }; -static struct ata_port_operations nv_ops = { +static const struct ata_port_operations nv_ops = { .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, @@ -331,7 +332,7 @@ static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg) return 0xffffffffU; if (host->host_flags & NV_HOST_FLAGS_SCR_MMIO) - return readl((void*)ap->ioaddr.scr_addr + (sc_reg * 4)); + return readl((void __iomem *)ap->ioaddr.scr_addr + (sc_reg * 4)); else return inl(ap->ioaddr.scr_addr + (sc_reg * 4)); } @@ -345,7 +346,7 @@ static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) return; if (host->host_flags & NV_HOST_FLAGS_SCR_MMIO) - writel(val, (void*)ap->ioaddr.scr_addr + (sc_reg * 4)); + writel(val, (void __iomem *)ap->ioaddr.scr_addr + (sc_reg * 4)); else outl(val, ap->ioaddr.scr_addr + (sc_reg * 4)); } @@ -383,7 +384,7 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) return -ENODEV; if (!printed_version++) - printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); + dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); rc = pci_enable_device(pdev); if (rc) @@ -405,7 +406,7 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) rc = -ENOMEM; ppi = &nv_port_info; - probe_ent = ata_pci_init_native_mode(pdev, &ppi); + probe_ent = ata_pci_init_native_mode(pdev, &ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY); if (!probe_ent) goto err_out_regions; diff --git a/drivers/scsi/sata_promise.c b/drivers/scsi/sata_promise.c index 538ad727bd2e..b41c977d6fab 100644 --- a/drivers/scsi/sata_promise.c +++ b/drivers/scsi/sata_promise.c @@ -38,6 +38,7 @@ #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/sched.h> +#include <linux/device.h> #include "scsi.h" #include <scsi/scsi_host.h> #include <linux/libata.h> @@ -87,8 +88,8 @@ static void pdc_port_stop(struct ata_port *ap); static void pdc_pata_phy_reset(struct ata_port *ap); static void pdc_sata_phy_reset(struct ata_port *ap); static void pdc_qc_prep(struct ata_queued_cmd *qc); -static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf); -static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf); +static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf); +static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf); static void pdc_irq_clear(struct ata_port *ap); static int pdc_qc_issue_prot(struct ata_queued_cmd *qc); @@ -113,7 +114,7 @@ static Scsi_Host_Template pdc_ata_sht = { .ordered_flush = 1, }; -static struct ata_port_operations pdc_sata_ops = { +static const struct ata_port_operations pdc_sata_ops = { .port_disable = ata_port_disable, .tf_load = pdc_tf_load_mmio, .tf_read = ata_tf_read, @@ -136,7 +137,7 @@ static struct ata_port_operations pdc_sata_ops = { .host_stop = ata_pci_host_stop, }; -static struct ata_port_operations pdc_pata_ops = { +static const struct ata_port_operations pdc_pata_ops = { .port_disable = ata_port_disable, .tf_load = pdc_tf_load_mmio, .tf_read = ata_tf_read, @@ -195,6 +196,8 @@ static struct ata_port_info pdc_port_info[] = { static struct pci_device_id pdc_ata_pci_tbl[] = { { PCI_VENDOR_ID_PROMISE, 0x3371, PCI_ANY_ID, PCI_ANY_ID, 0, 0, board_2037x }, + { PCI_VENDOR_ID_PROMISE, 0x3570, PCI_ANY_ID, PCI_ANY_ID, 0, 0, + board_2037x }, { PCI_VENDOR_ID_PROMISE, 0x3571, PCI_ANY_ID, PCI_ANY_ID, 0, 0, board_2037x }, { PCI_VENDOR_ID_PROMISE, 0x3373, PCI_ANY_ID, PCI_ANY_ID, 0, 0, @@ -207,6 +210,8 @@ static struct pci_device_id pdc_ata_pci_tbl[] = { board_2037x }, { PCI_VENDOR_ID_PROMISE, 0x3d75, PCI_ANY_ID, PCI_ANY_ID, 0, 0, board_2037x }, + { PCI_VENDOR_ID_PROMISE, 0x3d73, PCI_ANY_ID, PCI_ANY_ID, 0, 0, + board_2037x }, { PCI_VENDOR_ID_PROMISE, 0x3318, PCI_ANY_ID, PCI_ANY_ID, 0, 0, board_20319 }, @@ -324,7 +329,7 @@ static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg) { if (sc_reg > SCR_CONTROL) return 0xffffffffU; - return readl((void *) ap->ioaddr.scr_addr + (sc_reg * 4)); + return readl((void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4)); } @@ -333,7 +338,7 @@ static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, { if (sc_reg > SCR_CONTROL) return; - writel(val, (void *) ap->ioaddr.scr_addr + (sc_reg * 4)); + writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4)); } static void pdc_qc_prep(struct ata_queued_cmd *qc) @@ -395,7 +400,8 @@ static void pdc_eng_timeout(struct ata_port *ap) case ATA_PROT_DMA: case ATA_PROT_NODATA: printk(KERN_ERR "ata%u: command timeout\n", ap->id); - ata_qc_complete(qc, ata_wait_idle(ap) | ATA_ERR); + drv_stat = ata_wait_idle(ap); + ata_qc_complete(qc, __ac_err_mask(drv_stat)); break; default: @@ -404,7 +410,7 @@ static void pdc_eng_timeout(struct ata_port *ap) printk(KERN_ERR "ata%u: unknown timeout, cmd 0x%x stat 0x%x\n", ap->id, qc->tf.command, drv_stat); - ata_qc_complete(qc, drv_stat); + ata_qc_complete(qc, ac_err_mask(drv_stat)); break; } @@ -416,33 +422,30 @@ out: static inline unsigned int pdc_host_intr( struct ata_port *ap, struct ata_queued_cmd *qc) { - u8 status; - unsigned int handled = 0, have_err = 0; + unsigned int handled = 0, err_mask = 0; u32 tmp; void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr + PDC_GLOBAL_CTL; tmp = readl(mmio); if (tmp & PDC_ERR_MASK) { - have_err = 1; + err_mask = AC_ERR_DEV; pdc_reset_port(ap); } switch (qc->tf.protocol) { case ATA_PROT_DMA: case ATA_PROT_NODATA: - status = ata_wait_idle(ap); - if (have_err) - status |= ATA_ERR; - ata_qc_complete(qc, status); + err_mask |= ac_err_mask(ata_wait_idle(ap)); + ata_qc_complete(qc, err_mask); handled = 1; break; default: - ap->stats.idle_irq++; - break; + ap->stats.idle_irq++; + break; } - return handled; + return handled; } static void pdc_irq_clear(struct ata_port *ap) @@ -523,8 +526,8 @@ static inline void pdc_packet_start(struct ata_queued_cmd *qc) pp->pkt[2] = seq; wmb(); /* flush PRD, pkt writes */ - writel(pp->pkt_dma, (void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); - readl((void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); /* flush */ + writel(pp->pkt_dma, (void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); + readl((void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); /* flush */ } static int pdc_qc_issue_prot(struct ata_queued_cmd *qc) @@ -546,7 +549,7 @@ static int pdc_qc_issue_prot(struct ata_queued_cmd *qc) return ata_qc_issue_prot(qc); } -static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf) +static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf) { WARN_ON (tf->protocol == ATA_PROT_DMA || tf->protocol == ATA_PROT_NODATA); @@ -554,7 +557,7 @@ static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf) } -static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf) +static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf) { WARN_ON (tf->protocol == ATA_PROT_DMA || tf->protocol == ATA_PROT_NODATA); @@ -631,7 +634,7 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e int rc; if (!printed_version++) - printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); + dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); /* * If this driver happens to only be useful on Apple's K2, then diff --git a/drivers/scsi/sata_qstor.c b/drivers/scsi/sata_qstor.c index ffcdeb68641c..9938dae782b6 100644 --- a/drivers/scsi/sata_qstor.c +++ b/drivers/scsi/sata_qstor.c @@ -35,6 +35,7 @@ #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/sched.h> +#include <linux/device.h> #include "scsi.h" #include <scsi/scsi_host.h> #include <asm/io.h> @@ -51,8 +52,6 @@ enum { QS_PRD_BYTES = QS_MAX_PRD * 16, QS_PKT_BYTES = QS_CPB_BYTES + QS_PRD_BYTES, - QS_DMA_BOUNDARY = ~0UL, - /* global register offsets */ QS_HCF_CNFG3 = 0x0003, /* host configuration offset */ QS_HID_HPHY = 0x0004, /* host physical interface info */ @@ -101,6 +100,10 @@ enum { board_2068_idx = 0, /* QStor 4-port SATA/RAID */ }; +enum { + QS_DMA_BOUNDARY = ~0UL +}; + typedef enum { qs_state_idle, qs_state_pkt, qs_state_mmio } qs_state_t; struct qs_port_priv { @@ -145,7 +148,7 @@ static Scsi_Host_Template qs_ata_sht = { .bios_param = ata_std_bios_param, }; -static struct ata_port_operations qs_ata_ops = { +static const struct ata_port_operations qs_ata_ops = { .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, @@ -398,11 +401,12 @@ static inline unsigned int qs_intr_pkt(struct ata_host_set *host_set) qc = ata_qc_from_tag(ap, ap->active_tag); if (qc && (!(qc->tf.ctl & ATA_NIEN))) { switch (sHST) { - case 0: /* sucessful CPB */ + case 0: /* successful CPB */ case 3: /* device error */ pp->state = qs_state_idle; qs_enter_reg_mode(qc->ap); - ata_qc_complete(qc, sDST); + ata_qc_complete(qc, + ac_err_mask(sDST)); break; default: break; @@ -431,7 +435,7 @@ static inline unsigned int qs_intr_mmio(struct ata_host_set *host_set) if (qc && (!(qc->tf.ctl & ATA_NIEN))) { /* check main status, clearing INTRQ */ - u8 status = ata_chk_status(ap); + u8 status = ata_check_status(ap); if ((status & ATA_BUSY)) continue; DPRINTK("ata%u: protocol %d (dev_stat 0x%X)\n", @@ -439,7 +443,7 @@ static inline unsigned int qs_intr_mmio(struct ata_host_set *host_set) /* complete taskfile transaction */ pp->state = qs_state_idle; - ata_qc_complete(qc, status); + ata_qc_complete(qc, ac_err_mask(status)); handled = 1; } } @@ -597,25 +601,22 @@ static int qs_set_dma_masks(struct pci_dev *pdev, void __iomem *mmio_base) if (rc) { rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); if (rc) { - printk(KERN_ERR DRV_NAME - "(%s): 64-bit DMA enable failed\n", - pci_name(pdev)); + dev_printk(KERN_ERR, &pdev->dev, + "64-bit DMA enable failed\n"); return rc; } } } else { rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK); if (rc) { - printk(KERN_ERR DRV_NAME - "(%s): 32-bit DMA enable failed\n", - pci_name(pdev)); + dev_printk(KERN_ERR, &pdev->dev, + "32-bit DMA enable failed\n"); return rc; } rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); if (rc) { - printk(KERN_ERR DRV_NAME - "(%s): 32-bit consistent DMA enable failed\n", - pci_name(pdev)); + dev_printk(KERN_ERR, &pdev->dev, + "32-bit consistent DMA enable failed\n"); return rc; } } @@ -632,7 +633,7 @@ static int qs_ata_init_one(struct pci_dev *pdev, int rc, port_no; if (!printed_version++) - printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); + dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); rc = pci_enable_device(pdev); if (rc) diff --git a/drivers/scsi/sata_sil.c b/drivers/scsi/sata_sil.c index ba98a175ee3a..435f7e0085ec 100644 --- a/drivers/scsi/sata_sil.c +++ b/drivers/scsi/sata_sil.c @@ -41,6 +41,7 @@ #include <linux/blkdev.h> #include <linux/delay.h> #include <linux/interrupt.h> +#include <linux/device.h> #include "scsi.h" #include <scsi/scsi_host.h> #include <linux/libata.h> @@ -150,7 +151,7 @@ static Scsi_Host_Template sil_sht = { .ordered_flush = 1, }; -static struct ata_port_operations sil_ops = { +static const struct ata_port_operations sil_ops = { .port_disable = ata_port_disable, .dev_config = sil_dev_config, .tf_load = ata_tf_load, @@ -289,7 +290,7 @@ static inline unsigned long sil_scr_addr(struct ata_port *ap, unsigned int sc_re static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg) { - void *mmio = (void *) sil_scr_addr(ap, sc_reg); + void __iomem *mmio = (void __iomem *) sil_scr_addr(ap, sc_reg); if (mmio) return readl(mmio); return 0xffffffffU; @@ -297,7 +298,7 @@ static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg) static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) { - void *mmio = (void *) sil_scr_addr(ap, sc_reg); + void *mmio = (void __iomem *) sil_scr_addr(ap, sc_reg); if (mmio) writel(val, mmio); } @@ -386,7 +387,7 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) u8 cls; if (!printed_version++) - printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); + dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); /* * If this driver happens to only be useful on Apple's K2, then @@ -463,8 +464,8 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) writeb(cls, mmio_base + SIL_FIFO_W3); } } else - printk(KERN_WARNING DRV_NAME "(%s): cache line size not set. Driver may not function\n", - pci_name(pdev)); + dev_printk(KERN_WARNING, &pdev->dev, + "cache line size not set. Driver may not function\n"); if (ent->driver_data == sil_3114) { irq_mask = SIL_MASK_4PORT; diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c new file mode 100644 index 000000000000..c66548025657 --- /dev/null +++ b/drivers/scsi/sata_sil24.c @@ -0,0 +1,871 @@ +/* + * sata_sil24.c - Driver for Silicon Image 3124/3132 SATA-2 controllers + * + * Copyright 2005 Tejun Heo + * + * Based on preview driver from Silicon Image. + * + * NOTE: No NCQ/ATAPI support yet. The preview driver didn't support + * NCQ nor ATAPI, and, unfortunately, I couldn't find out how to make + * those work. Enabling those shouldn't be difficult. Basic + * structure is all there (in libata-dev tree). If you have any + * information about this hardware, please contact me or linux-ide. + * Info is needed on... + * + * - How to issue tagged commands and turn on sactive on issue accordingly. + * - Where to put an ATAPI command and how to tell the device to send it. + * - How to enable/use 64bit. + * + * 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, 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. + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/blkdev.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/dma-mapping.h> +#include <linux/device.h> +#include <scsi/scsi_host.h> +#include "scsi.h" +#include <linux/libata.h> +#include <asm/io.h> + +#define DRV_NAME "sata_sil24" +#define DRV_VERSION "0.22" /* Silicon Image's preview driver was 0.10 */ + +/* + * Port request block (PRB) 32 bytes + */ +struct sil24_prb { + u16 ctrl; + u16 prot; + u32 rx_cnt; + u8 fis[6 * 4]; +}; + +/* + * Scatter gather entry (SGE) 16 bytes + */ +struct sil24_sge { + u64 addr; + u32 cnt; + u32 flags; +}; + +/* + * Port multiplier + */ +struct sil24_port_multiplier { + u32 diag; + u32 sactive; +}; + +enum { + /* + * Global controller registers (128 bytes @ BAR0) + */ + /* 32 bit regs */ + HOST_SLOT_STAT = 0x00, /* 32 bit slot stat * 4 */ + HOST_CTRL = 0x40, + HOST_IRQ_STAT = 0x44, + HOST_PHY_CFG = 0x48, + HOST_BIST_CTRL = 0x50, + HOST_BIST_PTRN = 0x54, + HOST_BIST_STAT = 0x58, + HOST_MEM_BIST_STAT = 0x5c, + HOST_FLASH_CMD = 0x70, + /* 8 bit regs */ + HOST_FLASH_DATA = 0x74, + HOST_TRANSITION_DETECT = 0x75, + HOST_GPIO_CTRL = 0x76, + HOST_I2C_ADDR = 0x78, /* 32 bit */ + HOST_I2C_DATA = 0x7c, + HOST_I2C_XFER_CNT = 0x7e, + HOST_I2C_CTRL = 0x7f, + + /* HOST_SLOT_STAT bits */ + HOST_SSTAT_ATTN = (1 << 31), + + /* + * Port registers + * (8192 bytes @ +0x0000, +0x2000, +0x4000 and +0x6000 @ BAR2) + */ + PORT_REGS_SIZE = 0x2000, + PORT_PRB = 0x0000, /* (32 bytes PRB + 16 bytes SGEs * 6) * 31 (3968 bytes) */ + + PORT_PM = 0x0f80, /* 8 bytes PM * 16 (128 bytes) */ + /* 32 bit regs */ + PORT_CTRL_STAT = 0x1000, /* write: ctrl-set, read: stat */ + PORT_CTRL_CLR = 0x1004, /* write: ctrl-clear */ + PORT_IRQ_STAT = 0x1008, /* high: status, low: interrupt */ + PORT_IRQ_ENABLE_SET = 0x1010, /* write: enable-set */ + PORT_IRQ_ENABLE_CLR = 0x1014, /* write: enable-clear */ + PORT_ACTIVATE_UPPER_ADDR= 0x101c, + PORT_EXEC_FIFO = 0x1020, /* command execution fifo */ + PORT_CMD_ERR = 0x1024, /* command error number */ + PORT_FIS_CFG = 0x1028, + PORT_FIFO_THRES = 0x102c, + /* 16 bit regs */ + PORT_DECODE_ERR_CNT = 0x1040, + PORT_DECODE_ERR_THRESH = 0x1042, + PORT_CRC_ERR_CNT = 0x1044, + PORT_CRC_ERR_THRESH = 0x1046, + PORT_HSHK_ERR_CNT = 0x1048, + PORT_HSHK_ERR_THRESH = 0x104a, + /* 32 bit regs */ + PORT_PHY_CFG = 0x1050, + PORT_SLOT_STAT = 0x1800, + PORT_CMD_ACTIVATE = 0x1c00, /* 64 bit cmd activate * 31 (248 bytes) */ + PORT_EXEC_DIAG = 0x1e00, /* 32bit exec diag * 16 (64 bytes, 0-10 used on 3124) */ + PORT_PSD_DIAG = 0x1e40, /* 32bit psd diag * 16 (64 bytes, 0-8 used on 3124) */ + PORT_SCONTROL = 0x1f00, + PORT_SSTATUS = 0x1f04, + PORT_SERROR = 0x1f08, + PORT_SACTIVE = 0x1f0c, + + /* PORT_CTRL_STAT bits */ + PORT_CS_PORT_RST = (1 << 0), /* port reset */ + PORT_CS_DEV_RST = (1 << 1), /* device reset */ + PORT_CS_INIT = (1 << 2), /* port initialize */ + PORT_CS_IRQ_WOC = (1 << 3), /* interrupt write one to clear */ + PORT_CS_RESUME = (1 << 6), /* port resume */ + PORT_CS_32BIT_ACTV = (1 << 10), /* 32-bit activation */ + PORT_CS_PM_EN = (1 << 13), /* port multiplier enable */ + PORT_CS_RDY = (1 << 31), /* port ready to accept commands */ + + /* PORT_IRQ_STAT/ENABLE_SET/CLR */ + /* bits[11:0] are masked */ + PORT_IRQ_COMPLETE = (1 << 0), /* command(s) completed */ + PORT_IRQ_ERROR = (1 << 1), /* command execution error */ + PORT_IRQ_PORTRDY_CHG = (1 << 2), /* port ready change */ + PORT_IRQ_PWR_CHG = (1 << 3), /* power management change */ + PORT_IRQ_PHYRDY_CHG = (1 << 4), /* PHY ready change */ + PORT_IRQ_COMWAKE = (1 << 5), /* COMWAKE received */ + PORT_IRQ_UNK_FIS = (1 << 6), /* Unknown FIS received */ + PORT_IRQ_SDB_FIS = (1 << 11), /* SDB FIS received */ + + /* bits[27:16] are unmasked (raw) */ + PORT_IRQ_RAW_SHIFT = 16, + PORT_IRQ_MASKED_MASK = 0x7ff, + PORT_IRQ_RAW_MASK = (0x7ff << PORT_IRQ_RAW_SHIFT), + + /* ENABLE_SET/CLR specific, intr steering - 2 bit field */ + PORT_IRQ_STEER_SHIFT = 30, + PORT_IRQ_STEER_MASK = (3 << PORT_IRQ_STEER_SHIFT), + + /* PORT_CMD_ERR constants */ + PORT_CERR_DEV = 1, /* Error bit in D2H Register FIS */ + PORT_CERR_SDB = 2, /* Error bit in SDB FIS */ + PORT_CERR_DATA = 3, /* Error in data FIS not detected by dev */ + PORT_CERR_SEND = 4, /* Initial cmd FIS transmission failure */ + PORT_CERR_INCONSISTENT = 5, /* Protocol mismatch */ + PORT_CERR_DIRECTION = 6, /* Data direction mismatch */ + PORT_CERR_UNDERRUN = 7, /* Ran out of SGEs while writing */ + PORT_CERR_OVERRUN = 8, /* Ran out of SGEs while reading */ + PORT_CERR_PKT_PROT = 11, /* DIR invalid in 1st PIO setup of ATAPI */ + PORT_CERR_SGT_BOUNDARY = 16, /* PLD ecode 00 - SGT not on qword boundary */ + PORT_CERR_SGT_TGTABRT = 17, /* PLD ecode 01 - target abort */ + PORT_CERR_SGT_MSTABRT = 18, /* PLD ecode 10 - master abort */ + PORT_CERR_SGT_PCIPERR = 19, /* PLD ecode 11 - PCI parity err while fetching SGT */ + PORT_CERR_CMD_BOUNDARY = 24, /* ctrl[15:13] 001 - PRB not on qword boundary */ + PORT_CERR_CMD_TGTABRT = 25, /* ctrl[15:13] 010 - target abort */ + PORT_CERR_CMD_MSTABRT = 26, /* ctrl[15:13] 100 - master abort */ + PORT_CERR_CMD_PCIPERR = 27, /* ctrl[15:13] 110 - PCI parity err while fetching PRB */ + PORT_CERR_XFR_UNDEF = 32, /* PSD ecode 00 - undefined */ + PORT_CERR_XFR_TGTABRT = 33, /* PSD ecode 01 - target abort */ + PORT_CERR_XFR_MSGABRT = 34, /* PSD ecode 10 - master abort */ + PORT_CERR_XFR_PCIPERR = 35, /* PSD ecode 11 - PCI prity err during transfer */ + PORT_CERR_SENDSERVICE = 36, /* FIS received while sending service */ + + /* + * Other constants + */ + SGE_TRM = (1 << 31), /* Last SGE in chain */ + PRB_SOFT_RST = (1 << 7), /* Soft reset request (ign BSY?) */ + + /* board id */ + BID_SIL3124 = 0, + BID_SIL3132 = 1, + BID_SIL3131 = 2, + + IRQ_STAT_4PORTS = 0xf, +}; + +struct sil24_cmd_block { + struct sil24_prb prb; + struct sil24_sge sge[LIBATA_MAX_PRD]; +}; + +/* + * ap->private_data + * + * The preview driver always returned 0 for status. We emulate it + * here from the previous interrupt. + */ +struct sil24_port_priv { + struct sil24_cmd_block *cmd_block; /* 32 cmd blocks */ + dma_addr_t cmd_block_dma; /* DMA base addr for them */ + struct ata_taskfile tf; /* Cached taskfile registers */ +}; + +/* ap->host_set->private_data */ +struct sil24_host_priv { + void __iomem *host_base; /* global controller control (128 bytes @BAR0) */ + void __iomem *port_base; /* port registers (4 * 8192 bytes @BAR2) */ +}; + +static u8 sil24_check_status(struct ata_port *ap); +static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg); +static void sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val); +static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf); +static void sil24_phy_reset(struct ata_port *ap); +static void sil24_qc_prep(struct ata_queued_cmd *qc); +static int sil24_qc_issue(struct ata_queued_cmd *qc); +static void sil24_irq_clear(struct ata_port *ap); +static void sil24_eng_timeout(struct ata_port *ap); +static irqreturn_t sil24_interrupt(int irq, void *dev_instance, struct pt_regs *regs); +static int sil24_port_start(struct ata_port *ap); +static void sil24_port_stop(struct ata_port *ap); +static void sil24_host_stop(struct ata_host_set *host_set); +static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); + +static struct pci_device_id sil24_pci_tbl[] = { + { 0x1095, 0x3124, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3124 }, + { 0x1095, 0x3132, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3132 }, + { 0x1095, 0x3131, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3131 }, + { 0x1095, 0x3531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3131 }, + { } /* terminate list */ +}; + +static struct pci_driver sil24_pci_driver = { + .name = DRV_NAME, + .id_table = sil24_pci_tbl, + .probe = sil24_init_one, + .remove = ata_pci_remove_one, /* safe? */ +}; + +static Scsi_Host_Template sil24_sht = { + .module = THIS_MODULE, + .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, + .queuecommand = ata_scsi_queuecmd, + .eh_strategy_handler = ata_scsi_error, + .can_queue = ATA_DEF_QUEUE, + .this_id = ATA_SHT_THIS_ID, + .sg_tablesize = LIBATA_MAX_PRD, + .max_sectors = ATA_MAX_SECTORS, + .cmd_per_lun = ATA_SHT_CMD_PER_LUN, + .emulated = ATA_SHT_EMULATED, + .use_clustering = ATA_SHT_USE_CLUSTERING, + .proc_name = DRV_NAME, + .dma_boundary = ATA_DMA_BOUNDARY, + .slave_configure = ata_scsi_slave_config, + .bios_param = ata_std_bios_param, + .ordered_flush = 1, /* NCQ not supported yet */ +}; + +static const struct ata_port_operations sil24_ops = { + .port_disable = ata_port_disable, + + .check_status = sil24_check_status, + .check_altstatus = sil24_check_status, + .dev_select = ata_noop_dev_select, + + .tf_read = sil24_tf_read, + + .phy_reset = sil24_phy_reset, + + .qc_prep = sil24_qc_prep, + .qc_issue = sil24_qc_issue, + + .eng_timeout = sil24_eng_timeout, + + .irq_handler = sil24_interrupt, + .irq_clear = sil24_irq_clear, + + .scr_read = sil24_scr_read, + .scr_write = sil24_scr_write, + + .port_start = sil24_port_start, + .port_stop = sil24_port_stop, + .host_stop = sil24_host_stop, +}; + +/* + * Use bits 30-31 of host_flags to encode available port numbers. + * Current maxium is 4. + */ +#define SIL24_NPORTS2FLAG(nports) ((((unsigned)(nports) - 1) & 0x3) << 30) +#define SIL24_FLAG2NPORTS(flag) ((((flag) >> 30) & 0x3) + 1) + +static struct ata_port_info sil24_port_info[] = { + /* sil_3124 */ + { + .sht = &sil24_sht, + .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | + ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO | + ATA_FLAG_PIO_DMA | SIL24_NPORTS2FLAG(4), + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ + .udma_mask = 0x3f, /* udma0-5 */ + .port_ops = &sil24_ops, + }, + /* sil_3132 */ + { + .sht = &sil24_sht, + .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | + ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO | + ATA_FLAG_PIO_DMA | SIL24_NPORTS2FLAG(2), + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ + .udma_mask = 0x3f, /* udma0-5 */ + .port_ops = &sil24_ops, + }, + /* sil_3131/sil_3531 */ + { + .sht = &sil24_sht, + .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | + ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO | + ATA_FLAG_PIO_DMA | SIL24_NPORTS2FLAG(1), + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ + .udma_mask = 0x3f, /* udma0-5 */ + .port_ops = &sil24_ops, + }, +}; + +static inline void sil24_update_tf(struct ata_port *ap) +{ + struct sil24_port_priv *pp = ap->private_data; + void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr; + struct sil24_prb __iomem *prb = port; + u8 fis[6 * 4]; + + memcpy_fromio(fis, prb->fis, 6 * 4); + ata_tf_from_fis(fis, &pp->tf); +} + +static u8 sil24_check_status(struct ata_port *ap) +{ + struct sil24_port_priv *pp = ap->private_data; + return pp->tf.command; +} + +static int sil24_scr_map[] = { + [SCR_CONTROL] = 0, + [SCR_STATUS] = 1, + [SCR_ERROR] = 2, + [SCR_ACTIVE] = 3, +}; + +static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg) +{ + void __iomem *scr_addr = (void __iomem *)ap->ioaddr.scr_addr; + if (sc_reg < ARRAY_SIZE(sil24_scr_map)) { + void __iomem *addr; + addr = scr_addr + sil24_scr_map[sc_reg] * 4; + return readl(scr_addr + sil24_scr_map[sc_reg] * 4); + } + return 0xffffffffU; +} + +static void sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val) +{ + void __iomem *scr_addr = (void __iomem *)ap->ioaddr.scr_addr; + if (sc_reg < ARRAY_SIZE(sil24_scr_map)) { + void __iomem *addr; + addr = scr_addr + sil24_scr_map[sc_reg] * 4; + writel(val, scr_addr + sil24_scr_map[sc_reg] * 4); + } +} + +static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf) +{ + struct sil24_port_priv *pp = ap->private_data; + *tf = pp->tf; +} + +static void sil24_phy_reset(struct ata_port *ap) +{ + __sata_phy_reset(ap); + /* + * No ATAPI yet. Just unconditionally indicate ATA device. + * If ATAPI device is attached, it will fail ATA_CMD_ID_ATA + * and libata core will ignore the device. + */ + if (!(ap->flags & ATA_FLAG_PORT_DISABLED)) + ap->device[0].class = ATA_DEV_ATA; +} + +static inline void sil24_fill_sg(struct ata_queued_cmd *qc, + struct sil24_cmd_block *cb) +{ + struct scatterlist *sg = qc->sg; + struct sil24_sge *sge = cb->sge; + unsigned i; + + for (i = 0; i < qc->n_elem; i++, sg++, sge++) { + sge->addr = cpu_to_le64(sg_dma_address(sg)); + sge->cnt = cpu_to_le32(sg_dma_len(sg)); + sge->flags = 0; + sge->flags = i < qc->n_elem - 1 ? 0 : cpu_to_le32(SGE_TRM); + } +} + +static void sil24_qc_prep(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct sil24_port_priv *pp = ap->private_data; + struct sil24_cmd_block *cb = pp->cmd_block + qc->tag; + struct sil24_prb *prb = &cb->prb; + + switch (qc->tf.protocol) { + case ATA_PROT_PIO: + case ATA_PROT_DMA: + case ATA_PROT_NODATA: + break; + default: + /* ATAPI isn't supported yet */ + BUG(); + } + + ata_tf_to_fis(&qc->tf, prb->fis, 0); + + if (qc->flags & ATA_QCFLAG_DMAMAP) + sil24_fill_sg(qc, cb); +} + +static int sil24_qc_issue(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr; + struct sil24_port_priv *pp = ap->private_data; + dma_addr_t paddr = pp->cmd_block_dma + qc->tag * sizeof(*pp->cmd_block); + + writel((u32)paddr, port + PORT_CMD_ACTIVATE); + return 0; +} + +static void sil24_irq_clear(struct ata_port *ap) +{ + /* unused */ +} + +static int __sil24_reset_controller(void __iomem *port) +{ + int cnt; + u32 tmp; + + /* Reset controller state. Is this correct? */ + writel(PORT_CS_DEV_RST, port + PORT_CTRL_STAT); + readl(port + PORT_CTRL_STAT); /* sync */ + + /* Max ~100ms */ + for (cnt = 0; cnt < 1000; cnt++) { + udelay(100); + tmp = readl(port + PORT_CTRL_STAT); + if (!(tmp & PORT_CS_DEV_RST)) + break; + } + + if (tmp & PORT_CS_DEV_RST) + return -1; + return 0; +} + +static void sil24_reset_controller(struct ata_port *ap) +{ + printk(KERN_NOTICE DRV_NAME + " ata%u: resetting controller...\n", ap->id); + if (__sil24_reset_controller((void __iomem *)ap->ioaddr.cmd_addr)) + printk(KERN_ERR DRV_NAME + " ata%u: failed to reset controller\n", ap->id); +} + +static void sil24_eng_timeout(struct ata_port *ap) +{ + struct ata_queued_cmd *qc; + + qc = ata_qc_from_tag(ap, ap->active_tag); + if (!qc) { + printk(KERN_ERR "ata%u: BUG: timeout without command\n", + ap->id); + return; + } + + /* + * hack alert! We cannot use the supplied completion + * function from inside the ->eh_strategy_handler() thread. + * libata is the only user of ->eh_strategy_handler() in + * any kernel, so the default scsi_done() assumes it is + * not being called from the SCSI EH. + */ + printk(KERN_ERR "ata%u: command timeout\n", ap->id); + qc->scsidone = scsi_finish_command; + ata_qc_complete(qc, AC_ERR_OTHER); + + sil24_reset_controller(ap); +} + +static void sil24_error_intr(struct ata_port *ap, u32 slot_stat) +{ + struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag); + struct sil24_port_priv *pp = ap->private_data; + void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr; + u32 irq_stat, cmd_err, sstatus, serror; + unsigned int err_mask; + + irq_stat = readl(port + PORT_IRQ_STAT); + writel(irq_stat, port + PORT_IRQ_STAT); /* clear irq */ + + if (!(irq_stat & PORT_IRQ_ERROR)) { + /* ignore non-completion, non-error irqs for now */ + printk(KERN_WARNING DRV_NAME + "ata%u: non-error exception irq (irq_stat %x)\n", + ap->id, irq_stat); + return; + } + + cmd_err = readl(port + PORT_CMD_ERR); + sstatus = readl(port + PORT_SSTATUS); + serror = readl(port + PORT_SERROR); + if (serror) + writel(serror, port + PORT_SERROR); + + printk(KERN_ERR DRV_NAME " ata%u: error interrupt on port%d\n" + " stat=0x%x irq=0x%x cmd_err=%d sstatus=0x%x serror=0x%x\n", + ap->id, ap->port_no, slot_stat, irq_stat, cmd_err, sstatus, serror); + + if (cmd_err == PORT_CERR_DEV || cmd_err == PORT_CERR_SDB) { + /* + * Device is reporting error, tf registers are valid. + */ + sil24_update_tf(ap); + err_mask = ac_err_mask(pp->tf.command); + } else { + /* + * Other errors. libata currently doesn't have any + * mechanism to report these errors. Just turn on + * ATA_ERR. + */ + err_mask = AC_ERR_OTHER; + } + + if (qc) + ata_qc_complete(qc, err_mask); + + sil24_reset_controller(ap); +} + +static inline void sil24_host_intr(struct ata_port *ap) +{ + struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag); + void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr; + u32 slot_stat; + + slot_stat = readl(port + PORT_SLOT_STAT); + if (!(slot_stat & HOST_SSTAT_ATTN)) { + struct sil24_port_priv *pp = ap->private_data; + /* + * !HOST_SSAT_ATTN guarantees successful completion, + * so reading back tf registers is unnecessary for + * most commands. TODO: read tf registers for + * commands which require these values on successful + * completion (EXECUTE DEVICE DIAGNOSTIC, CHECK POWER, + * DEVICE RESET and READ PORT MULTIPLIER (any more?). + */ + sil24_update_tf(ap); + + if (qc) + ata_qc_complete(qc, ac_err_mask(pp->tf.command)); + } else + sil24_error_intr(ap, slot_stat); +} + +static irqreturn_t sil24_interrupt(int irq, void *dev_instance, struct pt_regs *regs) +{ + struct ata_host_set *host_set = dev_instance; + struct sil24_host_priv *hpriv = host_set->private_data; + unsigned handled = 0; + u32 status; + int i; + + status = readl(hpriv->host_base + HOST_IRQ_STAT); + + if (status == 0xffffffff) { + printk(KERN_ERR DRV_NAME ": IRQ status == 0xffffffff, " + "PCI fault or device removal?\n"); + goto out; + } + + if (!(status & IRQ_STAT_4PORTS)) + goto out; + + spin_lock(&host_set->lock); + + for (i = 0; i < host_set->n_ports; i++) + if (status & (1 << i)) { + struct ata_port *ap = host_set->ports[i]; + if (ap && !(ap->flags & ATA_FLAG_PORT_DISABLED)) { + sil24_host_intr(host_set->ports[i]); + handled++; + } else + printk(KERN_ERR DRV_NAME + ": interrupt from disabled port %d\n", i); + } + + spin_unlock(&host_set->lock); + out: + return IRQ_RETVAL(handled); +} + +static int sil24_port_start(struct ata_port *ap) +{ + struct device *dev = ap->host_set->dev; + struct sil24_port_priv *pp; + struct sil24_cmd_block *cb; + size_t cb_size = sizeof(*cb); + dma_addr_t cb_dma; + + pp = kmalloc(sizeof(*pp), GFP_KERNEL); + if (!pp) + return -ENOMEM; + memset(pp, 0, sizeof(*pp)); + + pp->tf.command = ATA_DRDY; + + cb = dma_alloc_coherent(dev, cb_size, &cb_dma, GFP_KERNEL); + if (!cb) { + kfree(pp); + return -ENOMEM; + } + memset(cb, 0, cb_size); + + pp->cmd_block = cb; + pp->cmd_block_dma = cb_dma; + + ap->private_data = pp; + + return 0; +} + +static void sil24_port_stop(struct ata_port *ap) +{ + struct device *dev = ap->host_set->dev; + struct sil24_port_priv *pp = ap->private_data; + size_t cb_size = sizeof(*pp->cmd_block); + + dma_free_coherent(dev, cb_size, pp->cmd_block, pp->cmd_block_dma); + kfree(pp); +} + +static void sil24_host_stop(struct ata_host_set *host_set) +{ + struct sil24_host_priv *hpriv = host_set->private_data; + + iounmap(hpriv->host_base); + iounmap(hpriv->port_base); + kfree(hpriv); +} + +static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + static int printed_version = 0; + unsigned int board_id = (unsigned int)ent->driver_data; + struct ata_port_info *pinfo = &sil24_port_info[board_id]; + struct ata_probe_ent *probe_ent = NULL; + struct sil24_host_priv *hpriv = NULL; + void __iomem *host_base = NULL; + void __iomem *port_base = NULL; + int i, rc; + + if (!printed_version++) + dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); + + rc = pci_enable_device(pdev); + if (rc) + return rc; + + rc = pci_request_regions(pdev, DRV_NAME); + if (rc) + goto out_disable; + + rc = -ENOMEM; + /* ioremap mmio registers */ + host_base = ioremap(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + if (!host_base) + goto out_free; + port_base = ioremap(pci_resource_start(pdev, 2), + pci_resource_len(pdev, 2)); + if (!port_base) + goto out_free; + + /* allocate & init probe_ent and hpriv */ + probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL); + if (!probe_ent) + goto out_free; + + hpriv = kmalloc(sizeof(*hpriv), GFP_KERNEL); + if (!hpriv) + goto out_free; + + memset(probe_ent, 0, sizeof(*probe_ent)); + probe_ent->dev = pci_dev_to_dev(pdev); + INIT_LIST_HEAD(&probe_ent->node); + + probe_ent->sht = pinfo->sht; + probe_ent->host_flags = pinfo->host_flags; + probe_ent->pio_mask = pinfo->pio_mask; + probe_ent->udma_mask = pinfo->udma_mask; + probe_ent->port_ops = pinfo->port_ops; + probe_ent->n_ports = SIL24_FLAG2NPORTS(pinfo->host_flags); + + probe_ent->irq = pdev->irq; + probe_ent->irq_flags = SA_SHIRQ; + probe_ent->mmio_base = port_base; + probe_ent->private_data = hpriv; + + memset(hpriv, 0, sizeof(*hpriv)); + hpriv->host_base = host_base; + hpriv->port_base = port_base; + + /* + * Configure the device + */ + /* + * FIXME: This device is certainly 64-bit capable. We just + * don't know how to use it. After fixing 32bit activation in + * this function, enable 64bit masks here. + */ + rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + if (rc) { + dev_printk(KERN_ERR, &pdev->dev, + "32-bit DMA enable failed\n"); + goto out_free; + } + rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); + if (rc) { + dev_printk(KERN_ERR, &pdev->dev, + "32-bit consistent DMA enable failed\n"); + goto out_free; + } + + /* GPIO off */ + writel(0, host_base + HOST_FLASH_CMD); + + /* Mask interrupts during initialization */ + writel(0, host_base + HOST_CTRL); + + for (i = 0; i < probe_ent->n_ports; i++) { + void __iomem *port = port_base + i * PORT_REGS_SIZE; + unsigned long portu = (unsigned long)port; + u32 tmp; + int cnt; + + probe_ent->port[i].cmd_addr = portu + PORT_PRB; + probe_ent->port[i].scr_addr = portu + PORT_SCONTROL; + + ata_std_ports(&probe_ent->port[i]); + + /* Initial PHY setting */ + writel(0x20c, port + PORT_PHY_CFG); + + /* Clear port RST */ + tmp = readl(port + PORT_CTRL_STAT); + if (tmp & PORT_CS_PORT_RST) { + writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR); + readl(port + PORT_CTRL_STAT); /* sync */ + for (cnt = 0; cnt < 10; cnt++) { + msleep(10); + tmp = readl(port + PORT_CTRL_STAT); + if (!(tmp & PORT_CS_PORT_RST)) + break; + } + if (tmp & PORT_CS_PORT_RST) + dev_printk(KERN_ERR, &pdev->dev, + "failed to clear port RST\n"); + } + + /* Zero error counters. */ + writel(0x8000, port + PORT_DECODE_ERR_THRESH); + writel(0x8000, port + PORT_CRC_ERR_THRESH); + writel(0x8000, port + PORT_HSHK_ERR_THRESH); + writel(0x0000, port + PORT_DECODE_ERR_CNT); + writel(0x0000, port + PORT_CRC_ERR_CNT); + writel(0x0000, port + PORT_HSHK_ERR_CNT); + + /* FIXME: 32bit activation? */ + writel(0, port + PORT_ACTIVATE_UPPER_ADDR); + writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_STAT); + + /* Configure interrupts */ + writel(0xffff, port + PORT_IRQ_ENABLE_CLR); + writel(PORT_IRQ_COMPLETE | PORT_IRQ_ERROR | PORT_IRQ_SDB_FIS, + port + PORT_IRQ_ENABLE_SET); + + /* Clear interrupts */ + writel(0x0fff0fff, port + PORT_IRQ_STAT); + writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR); + + /* Clear port multiplier enable and resume bits */ + writel(PORT_CS_PM_EN | PORT_CS_RESUME, port + PORT_CTRL_CLR); + + /* Reset itself */ + if (__sil24_reset_controller(port)) + dev_printk(KERN_ERR, &pdev->dev, + "failed to reset controller\n"); + } + + /* Turn on interrupts */ + writel(IRQ_STAT_4PORTS, host_base + HOST_CTRL); + + pci_set_master(pdev); + + /* FIXME: check ata_device_add return value */ + ata_device_add(probe_ent); + + kfree(probe_ent); + return 0; + + out_free: + if (host_base) + iounmap(host_base); + if (port_base) + iounmap(port_base); + kfree(probe_ent); + kfree(hpriv); + pci_release_regions(pdev); + out_disable: + pci_disable_device(pdev); + return rc; +} + +static int __init sil24_init(void) +{ + return pci_module_init(&sil24_pci_driver); +} + +static void __exit sil24_exit(void) +{ + pci_unregister_driver(&sil24_pci_driver); +} + +MODULE_AUTHOR("Tejun Heo"); +MODULE_DESCRIPTION("Silicon Image 3124/3132 SATA low-level driver"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, sil24_pci_tbl); + +module_init(sil24_init); +module_exit(sil24_exit); diff --git a/drivers/scsi/sata_sis.c b/drivers/scsi/sata_sis.c index b227e51d12f4..42288be0e561 100644 --- a/drivers/scsi/sata_sis.c +++ b/drivers/scsi/sata_sis.c @@ -38,6 +38,7 @@ #include <linux/blkdev.h> #include <linux/delay.h> #include <linux/interrupt.h> +#include <linux/device.h> #include "scsi.h" #include <scsi/scsi_host.h> #include <linux/libata.h> @@ -102,7 +103,7 @@ static Scsi_Host_Template sis_sht = { .ordered_flush = 1, }; -static struct ata_port_operations sis_ops = { +static const struct ata_port_operations sis_ops = { .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, @@ -237,6 +238,7 @@ static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { + static int printed_version; struct ata_probe_ent *probe_ent = NULL; int rc; u32 genctl; @@ -245,6 +247,9 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) u8 pmr; u8 port2_start; + if (!printed_version++) + dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n"); + rc = pci_enable_device(pdev); if (rc) return rc; @@ -263,7 +268,7 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) goto err_out_regions; ppi = &sis_port_info; - probe_ent = ata_pci_init_native_mode(pdev, &ppi); + probe_ent = ata_pci_init_native_mode(pdev, &ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY); if (!probe_ent) { rc = -ENOMEM; goto err_out_regions; @@ -288,16 +293,18 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) pci_read_config_byte(pdev, SIS_PMR, &pmr); if (ent->device != 0x182) { if ((pmr & SIS_PMR_COMBINED) == 0) { - printk(KERN_INFO "sata_sis: Detected SiS 180/181 chipset in SATA mode\n"); + dev_printk(KERN_INFO, &pdev->dev, + "Detected SiS 180/181 chipset in SATA mode\n"); port2_start = 64; } else { - printk(KERN_INFO "sata_sis: Detected SiS 180/181 chipset in combined mode\n"); + dev_printk(KERN_INFO, &pdev->dev, + "Detected SiS 180/181 chipset in combined mode\n"); port2_start=0; } } else { - printk(KERN_INFO "sata_sis: Detected SiS 182 chipset\n"); + dev_printk(KERN_INFO, &pdev->dev, "Detected SiS 182 chipset\n"); port2_start = 0x20; } diff --git a/drivers/scsi/sata_svw.c b/drivers/scsi/sata_svw.c index d89d968bedac..db615ff794d8 100644 --- a/drivers/scsi/sata_svw.c +++ b/drivers/scsi/sata_svw.c @@ -44,6 +44,7 @@ #include <linux/blkdev.h> #include <linux/delay.h> #include <linux/interrupt.h> +#include <linux/device.h> #include "scsi.h" #include <scsi/scsi_host.h> #include <linux/libata.h> @@ -84,6 +85,8 @@ /* Port stride */ #define K2_SATA_PORT_OFFSET 0x100 +static u8 k2_stat_check_status(struct ata_port *ap); + static u32 k2_sata_scr_read (struct ata_port *ap, unsigned int sc_reg) { @@ -102,7 +105,7 @@ static void k2_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, } -static void k2_sata_tf_load(struct ata_port *ap, struct ata_taskfile *tf) +static void k2_sata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf) { struct ata_ioports *ioaddr = &ap->ioaddr; unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; @@ -136,16 +139,24 @@ static void k2_sata_tf_load(struct ata_port *ap, struct ata_taskfile *tf) static void k2_sata_tf_read(struct ata_port *ap, struct ata_taskfile *tf) { struct ata_ioports *ioaddr = &ap->ioaddr; - u16 nsect, lbal, lbam, lbah; + u16 nsect, lbal, lbam, lbah, feature; - nsect = tf->nsect = readw(ioaddr->nsect_addr); - lbal = tf->lbal = readw(ioaddr->lbal_addr); - lbam = tf->lbam = readw(ioaddr->lbam_addr); - lbah = tf->lbah = readw(ioaddr->lbah_addr); + tf->command = k2_stat_check_status(ap); tf->device = readw(ioaddr->device_addr); + feature = readw(ioaddr->error_addr); + nsect = readw(ioaddr->nsect_addr); + lbal = readw(ioaddr->lbal_addr); + lbam = readw(ioaddr->lbam_addr); + lbah = readw(ioaddr->lbah_addr); + + tf->feature = feature; + tf->nsect = nsect; + tf->lbal = lbal; + tf->lbam = lbam; + tf->lbah = lbah; if (tf->flags & ATA_TFLAG_LBA48) { - tf->hob_feature = readw(ioaddr->error_addr) >> 8; + tf->hob_feature = feature >> 8; tf->hob_nsect = nsect >> 8; tf->hob_lbal = lbal >> 8; tf->hob_lbam = lbam >> 8; @@ -297,7 +308,7 @@ static Scsi_Host_Template k2_sata_sht = { }; -static struct ata_port_operations k2_sata_ops = { +static const struct ata_port_operations k2_sata_ops = { .port_disable = ata_port_disable, .tf_load = k2_sata_tf_load, .tf_read = k2_sata_tf_read, @@ -352,7 +363,7 @@ static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *e int i; if (!printed_version++) - printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); + dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); /* * If this driver happens to only be useful on Apple's K2, then diff --git a/drivers/scsi/sata_sx4.c b/drivers/scsi/sata_sx4.c index 540a85191172..0ec21e09f5d8 100644 --- a/drivers/scsi/sata_sx4.c +++ b/drivers/scsi/sata_sx4.c @@ -38,6 +38,7 @@ #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/sched.h> +#include <linux/device.h> #include "scsi.h" #include <scsi/scsi_host.h> #include <linux/libata.h> @@ -137,7 +138,7 @@ struct pdc_port_priv { }; struct pdc_host_priv { - void *dimm_mmio; + void __iomem *dimm_mmio; unsigned int doing_hdma; unsigned int hdma_prod; @@ -157,8 +158,8 @@ static void pdc_20621_phy_reset (struct ata_port *ap); static int pdc_port_start(struct ata_port *ap); static void pdc_port_stop(struct ata_port *ap); static void pdc20621_qc_prep(struct ata_queued_cmd *qc); -static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf); -static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf); +static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf); +static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf); static void pdc20621_host_stop(struct ata_host_set *host_set); static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe); static int pdc20621_detect_dimm(struct ata_probe_ent *pe); @@ -196,7 +197,7 @@ static Scsi_Host_Template pdc_sata_sht = { .ordered_flush = 1, }; -static struct ata_port_operations pdc_20621_ops = { +static const struct ata_port_operations pdc_20621_ops = { .port_disable = ata_port_disable, .tf_load = pdc_tf_load_mmio, .tf_read = ata_tf_read, @@ -247,7 +248,7 @@ static void pdc20621_host_stop(struct ata_host_set *host_set) { struct pci_dev *pdev = to_pci_dev(host_set->dev); struct pdc_host_priv *hpriv = host_set->private_data; - void *dimm_mmio = hpriv->dimm_mmio; + void __iomem *dimm_mmio = hpriv->dimm_mmio; pci_iounmap(pdev, dimm_mmio); kfree(hpriv); @@ -669,8 +670,8 @@ static void pdc20621_packet_start(struct ata_queued_cmd *qc) readl(mmio + PDC_20621_SEQCTL + (seq * 4)); /* flush */ writel(port_ofs + PDC_DIMM_ATA_PKT, - (void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); - readl((void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); + (void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); + readl((void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); VPRINTK("submitted ofs 0x%x (%u), seq %u\n", port_ofs + PDC_DIMM_ATA_PKT, port_ofs + PDC_DIMM_ATA_PKT, @@ -718,7 +719,7 @@ static inline unsigned int pdc20621_host_intr( struct ata_port *ap, VPRINTK("ata%u: read hdma, 0x%x 0x%x\n", ap->id, readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT)); /* get drive status; clear intr; complete txn */ - ata_qc_complete(qc, ata_wait_idle(ap)); + ata_qc_complete(qc, ac_err_mask(ata_wait_idle(ap))); pdc20621_pop_hdma(qc); } @@ -747,8 +748,8 @@ static inline unsigned int pdc20621_host_intr( struct ata_port *ap, writel(0x00000001, mmio + PDC_20621_SEQCTL + (seq * 4)); readl(mmio + PDC_20621_SEQCTL + (seq * 4)); writel(port_ofs + PDC_DIMM_ATA_PKT, - (void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); - readl((void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); + (void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); + readl((void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); } /* step two - execute ATA command */ @@ -756,7 +757,7 @@ static inline unsigned int pdc20621_host_intr( struct ata_port *ap, VPRINTK("ata%u: write ata, 0x%x 0x%x\n", ap->id, readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT)); /* get drive status; clear intr; complete txn */ - ata_qc_complete(qc, ata_wait_idle(ap)); + ata_qc_complete(qc, ac_err_mask(ata_wait_idle(ap))); pdc20621_pop_hdma(qc); } handled = 1; @@ -766,7 +767,7 @@ static inline unsigned int pdc20621_host_intr( struct ata_port *ap, status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); DPRINTK("BUS_NODATA (drv_stat 0x%X)\n", status); - ata_qc_complete(qc, status); + ata_qc_complete(qc, ac_err_mask(status)); handled = 1; } else { @@ -881,7 +882,7 @@ static void pdc_eng_timeout(struct ata_port *ap) case ATA_PROT_DMA: case ATA_PROT_NODATA: printk(KERN_ERR "ata%u: command timeout\n", ap->id); - ata_qc_complete(qc, ata_wait_idle(ap) | ATA_ERR); + ata_qc_complete(qc, __ac_err_mask(ata_wait_idle(ap))); break; default: @@ -890,7 +891,7 @@ static void pdc_eng_timeout(struct ata_port *ap) printk(KERN_ERR "ata%u: unknown timeout, cmd 0x%x stat 0x%x\n", ap->id, qc->tf.command, drv_stat); - ata_qc_complete(qc, drv_stat); + ata_qc_complete(qc, ac_err_mask(drv_stat)); break; } @@ -899,7 +900,7 @@ out: DPRINTK("EXIT\n"); } -static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf) +static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf) { WARN_ON (tf->protocol == ATA_PROT_DMA || tf->protocol == ATA_PROT_NODATA); @@ -907,7 +908,7 @@ static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf) } -static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf) +static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf) { WARN_ON (tf->protocol == ATA_PROT_DMA || tf->protocol == ATA_PROT_NODATA); @@ -1014,7 +1015,7 @@ static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, void *psource, idx++; dist = ((long)(s32)(window_size - (offset + size))) >= 0 ? size : (long) (window_size - offset); - memcpy_toio((char *) (dimm_mmio + offset / 4), (char *) psource, dist); + memcpy_toio(dimm_mmio + offset / 4, psource, dist); writel(0x01, mmio + PDC_GENERAL_CTLR); readl(mmio + PDC_GENERAL_CTLR); @@ -1023,8 +1024,7 @@ static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, void *psource, for (; (long) size >= (long) window_size ;) { writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR); readl(mmio + PDC_DIMM_WINDOW_CTLR); - memcpy_toio((char *) (dimm_mmio), (char *) psource, - window_size / 4); + memcpy_toio(dimm_mmio, psource, window_size / 4); writel(0x01, mmio + PDC_GENERAL_CTLR); readl(mmio + PDC_GENERAL_CTLR); psource += window_size; @@ -1035,7 +1035,7 @@ static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, void *psource, if (size) { writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR); readl(mmio + PDC_DIMM_WINDOW_CTLR); - memcpy_toio((char *) (dimm_mmio), (char *) psource, size / 4); + memcpy_toio(dimm_mmio, psource, size / 4); writel(0x01, mmio + PDC_GENERAL_CTLR); readl(mmio + PDC_GENERAL_CTLR); } @@ -1386,7 +1386,7 @@ static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id * int rc; if (!printed_version++) - printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); + dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); /* * If this driver happens to only be useful on Apple's K2, then diff --git a/drivers/scsi/sata_uli.c b/drivers/scsi/sata_uli.c index 4c9fb8b71be1..a5e245c098e1 100644 --- a/drivers/scsi/sata_uli.c +++ b/drivers/scsi/sata_uli.c @@ -32,6 +32,7 @@ #include <linux/blkdev.h> #include <linux/delay.h> #include <linux/interrupt.h> +#include <linux/device.h> #include "scsi.h" #include <scsi/scsi_host.h> #include <linux/libata.h> @@ -90,7 +91,7 @@ static Scsi_Host_Template uli_sht = { .ordered_flush = 1, }; -static struct ata_port_operations uli_ops = { +static const struct ata_port_operations uli_ops = { .port_disable = ata_port_disable, .tf_load = ata_tf_load, @@ -178,12 +179,16 @@ static void uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { + static int printed_version; struct ata_probe_ent *probe_ent; struct ata_port_info *ppi; int rc; unsigned int board_idx = (unsigned int) ent->driver_data; int pci_dev_busy = 0; + if (!printed_version++) + dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n"); + rc = pci_enable_device(pdev); if (rc) return rc; @@ -202,7 +207,7 @@ static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) goto err_out_regions; ppi = &uli_port_info; - probe_ent = ata_pci_init_native_mode(pdev, &ppi); + probe_ent = ata_pci_init_native_mode(pdev, &ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY); if (!probe_ent) { rc = -ENOMEM; goto err_out_regions; diff --git a/drivers/scsi/sata_via.c b/drivers/scsi/sata_via.c index 128b996b07b7..b3ecdbe400e9 100644 --- a/drivers/scsi/sata_via.c +++ b/drivers/scsi/sata_via.c @@ -41,6 +41,7 @@ #include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> +#include <linux/device.h> #include "scsi.h" #include <scsi/scsi_host.h> #include <linux/libata.h> @@ -109,7 +110,7 @@ static Scsi_Host_Template svia_sht = { .ordered_flush = 1, }; -static struct ata_port_operations svia_sata_ops = { +static const struct ata_port_operations svia_sata_ops = { .port_disable = ata_port_disable, .tf_load = ata_tf_load, @@ -212,7 +213,7 @@ static struct ata_probe_ent *vt6420_init_probe_ent(struct pci_dev *pdev) struct ata_probe_ent *probe_ent; struct ata_port_info *ppi = &svia_port_info; - probe_ent = ata_pci_init_native_mode(pdev, &ppi); + probe_ent = ata_pci_init_native_mode(pdev, &ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY); if (!probe_ent) return NULL; @@ -259,15 +260,15 @@ static void svia_configure(struct pci_dev *pdev) u8 tmp8; pci_read_config_byte(pdev, PCI_INTERRUPT_LINE, &tmp8); - printk(KERN_INFO DRV_NAME "(%s): routed to hard irq line %d\n", - pci_name(pdev), + dev_printk(KERN_INFO, &pdev->dev, "routed to hard irq line %d\n", (int) (tmp8 & 0xf0) == 0xf0 ? 0 : tmp8 & 0x0f); /* make sure SATA channels are enabled */ pci_read_config_byte(pdev, SATA_CHAN_ENAB, &tmp8); if ((tmp8 & ALL_PORTS) != ALL_PORTS) { - printk(KERN_DEBUG DRV_NAME "(%s): enabling SATA channels (0x%x)\n", - pci_name(pdev), (int) tmp8); + dev_printk(KERN_DEBUG, &pdev->dev, + "enabling SATA channels (0x%x)\n", + (int) tmp8); tmp8 |= ALL_PORTS; pci_write_config_byte(pdev, SATA_CHAN_ENAB, tmp8); } @@ -275,8 +276,9 @@ static void svia_configure(struct pci_dev *pdev) /* make sure interrupts for each channel sent to us */ pci_read_config_byte(pdev, SATA_INT_GATE, &tmp8); if ((tmp8 & ALL_PORTS) != ALL_PORTS) { - printk(KERN_DEBUG DRV_NAME "(%s): enabling SATA channel interrupts (0x%x)\n", - pci_name(pdev), (int) tmp8); + dev_printk(KERN_DEBUG, &pdev->dev, + "enabling SATA channel interrupts (0x%x)\n", + (int) tmp8); tmp8 |= ALL_PORTS; pci_write_config_byte(pdev, SATA_INT_GATE, tmp8); } @@ -284,8 +286,9 @@ static void svia_configure(struct pci_dev *pdev) /* make sure native mode is enabled */ pci_read_config_byte(pdev, SATA_NATIVE_MODE, &tmp8); if ((tmp8 & NATIVE_MODE_ALL) != NATIVE_MODE_ALL) { - printk(KERN_DEBUG DRV_NAME "(%s): enabling SATA channel native mode (0x%x)\n", - pci_name(pdev), (int) tmp8); + dev_printk(KERN_DEBUG, &pdev->dev, + "enabling SATA channel native mode (0x%x)\n", + (int) tmp8); tmp8 |= NATIVE_MODE_ALL; pci_write_config_byte(pdev, SATA_NATIVE_MODE, tmp8); } @@ -303,7 +306,7 @@ static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) u8 tmp8; if (!printed_version++) - printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); + dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); rc = pci_enable_device(pdev); if (rc) @@ -318,8 +321,9 @@ static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) if (board_id == vt6420) { pci_read_config_byte(pdev, SATA_PATA_SHARING, &tmp8); if (tmp8 & SATA_2DEV) { - printk(KERN_ERR DRV_NAME "(%s): SATA master/slave not supported (0x%x)\n", - pci_name(pdev), (int) tmp8); + dev_printk(KERN_ERR, &pdev->dev, + "SATA master/slave not supported (0x%x)\n", + (int) tmp8); rc = -EIO; goto err_out_regions; } @@ -332,10 +336,11 @@ static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) for (i = 0; i < ARRAY_SIZE(svia_bar_sizes); i++) if ((pci_resource_start(pdev, i) == 0) || (pci_resource_len(pdev, i) < bar_sizes[i])) { - printk(KERN_ERR DRV_NAME "(%s): invalid PCI BAR %u (sz 0x%lx, val 0x%lx)\n", - pci_name(pdev), i, - pci_resource_start(pdev, i), - pci_resource_len(pdev, i)); + dev_printk(KERN_ERR, &pdev->dev, + "invalid PCI BAR %u (sz 0x%lx, val 0x%lx)\n", + i, + pci_resource_start(pdev, i), + pci_resource_len(pdev, i)); rc = -ENODEV; goto err_out_regions; } @@ -353,8 +358,7 @@ static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) probe_ent = vt6421_init_probe_ent(pdev); if (!probe_ent) { - printk(KERN_ERR DRV_NAME "(%s): out of memory\n", - pci_name(pdev)); + dev_printk(KERN_ERR, &pdev->dev, "out of memory\n"); rc = -ENOMEM; goto err_out_regions; } diff --git a/drivers/scsi/sata_vsc.c b/drivers/scsi/sata_vsc.c index cf94e0158a8d..bb84ba0c7e83 100644 --- a/drivers/scsi/sata_vsc.c +++ b/drivers/scsi/sata_vsc.c @@ -42,6 +42,7 @@ #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/dma-mapping.h> +#include <linux/device.h> #include "scsi.h" #include <scsi/scsi_host.h> #include <linux/libata.h> @@ -86,7 +87,7 @@ static u32 vsc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg) { if (sc_reg > SCR_CONTROL) return 0xffffffffU; - return readl((void *) ap->ioaddr.scr_addr + (sc_reg * 4)); + return readl((void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4)); } @@ -95,16 +96,16 @@ static void vsc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, { if (sc_reg > SCR_CONTROL) return; - writel(val, (void *) ap->ioaddr.scr_addr + (sc_reg * 4)); + writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4)); } static void vsc_intr_mask_update(struct ata_port *ap, u8 ctl) { - unsigned long mask_addr; + void __iomem *mask_addr; u8 mask; - mask_addr = (unsigned long) ap->host_set->mmio_base + + mask_addr = ap->host_set->mmio_base + VSC_SATA_INT_MASK_OFFSET + ap->port_no; mask = readb(mask_addr); if (ctl & ATA_NIEN) @@ -115,7 +116,7 @@ static void vsc_intr_mask_update(struct ata_port *ap, u8 ctl) } -static void vsc_sata_tf_load(struct ata_port *ap, struct ata_taskfile *tf) +static void vsc_sata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf) { struct ata_ioports *ioaddr = &ap->ioaddr; unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; @@ -153,16 +154,24 @@ static void vsc_sata_tf_load(struct ata_port *ap, struct ata_taskfile *tf) static void vsc_sata_tf_read(struct ata_port *ap, struct ata_taskfile *tf) { struct ata_ioports *ioaddr = &ap->ioaddr; - u16 nsect, lbal, lbam, lbah; + u16 nsect, lbal, lbam, lbah, feature; - nsect = tf->nsect = readw(ioaddr->nsect_addr); - lbal = tf->lbal = readw(ioaddr->lbal_addr); - lbam = tf->lbam = readw(ioaddr->lbam_addr); - lbah = tf->lbah = readw(ioaddr->lbah_addr); + tf->command = ata_check_status(ap); tf->device = readw(ioaddr->device_addr); + feature = readw(ioaddr->error_addr); + nsect = readw(ioaddr->nsect_addr); + lbal = readw(ioaddr->lbal_addr); + lbam = readw(ioaddr->lbam_addr); + lbah = readw(ioaddr->lbah_addr); + + tf->feature = feature; + tf->nsect = nsect; + tf->lbal = lbal; + tf->lbam = lbam; + tf->lbah = lbah; if (tf->flags & ATA_TFLAG_LBA48) { - tf->hob_feature = readb(ioaddr->error_addr); + tf->hob_feature = feature >> 8; tf->hob_nsect = nsect >> 8; tf->hob_lbal = lbal >> 8; tf->hob_lbam = lbam >> 8; @@ -231,7 +240,7 @@ static Scsi_Host_Template vsc_sata_sht = { }; -static struct ata_port_operations vsc_sata_ops = { +static const struct ata_port_operations vsc_sata_ops = { .port_disable = ata_port_disable, .tf_load = vsc_sata_tf_load, .tf_read = vsc_sata_tf_read, @@ -283,11 +292,11 @@ static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_d struct ata_probe_ent *probe_ent = NULL; unsigned long base; int pci_dev_busy = 0; - void *mmio_base; + void __iomem *mmio_base; int rc; if (!printed_version++) - printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); + dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); rc = pci_enable_device(pdev); if (rc) diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 1f0ebabf6d47..a5711d545d71 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -130,7 +130,7 @@ EXPORT_SYMBOL(scsi_device_types); * Returns: Pointer to request block. */ struct scsi_request *scsi_allocate_request(struct scsi_device *sdev, - int gfp_mask) + gfp_t gfp_mask) { const int offset = ALIGN(sizeof(struct scsi_request), 4); const int size = offset + sizeof(struct request); @@ -196,7 +196,7 @@ struct scsi_host_cmd_pool { unsigned int users; char *name; unsigned int slab_flags; - unsigned int gfp_mask; + gfp_t gfp_mask; }; static struct scsi_host_cmd_pool scsi_cmd_pool = { @@ -213,7 +213,7 @@ static struct scsi_host_cmd_pool scsi_cmd_dma_pool = { static DECLARE_MUTEX(host_cmd_pool_mutex); static struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *shost, - int gfp_mask) + gfp_t gfp_mask) { struct scsi_cmnd *cmd; @@ -245,7 +245,7 @@ static struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *shost, * * Returns: The allocated scsi command structure. */ -struct scsi_cmnd *scsi_get_command(struct scsi_device *dev, int gfp_mask) +struct scsi_cmnd *scsi_get_command(struct scsi_device *dev, gfp_t gfp_mask) { struct scsi_cmnd *cmd; diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c index de7f98cc38fe..6a3f6aae8a97 100644 --- a/drivers/scsi/scsi_ioctl.c +++ b/drivers/scsi/scsi_ioctl.c @@ -205,7 +205,8 @@ int scsi_ioctl_send_command(struct scsi_device *sdev, unsigned int inlen, outlen, cmdlen; unsigned int needed, buf_needed; int timeout, retries, result; - int data_direction, gfp_mask = GFP_KERNEL; + int data_direction; + gfp_t gfp_mask = GFP_KERNEL; if (!sic) return -EINVAL; diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 0074f28c37b2..3ff538809786 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -677,7 +677,7 @@ static struct scsi_cmnd *scsi_end_request(struct scsi_cmnd *cmd, int uptodate, return NULL; } -static struct scatterlist *scsi_alloc_sgtable(struct scsi_cmnd *cmd, int gfp_mask) +static struct scatterlist *scsi_alloc_sgtable(struct scsi_cmnd *cmd, gfp_t gfp_mask) { struct scsi_host_sg_pool *sgp; struct scatterlist *sgl; diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index 771e97ef136e..b856e140e65f 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -26,6 +26,7 @@ */ #include <linux/module.h> #include <linux/init.h> +#include <linux/sched.h> /* workqueue stuff, HZ */ #include <scsi/scsi_device.h> #include <scsi/scsi_host.h> #include <scsi/scsi_transport.h> diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 8bb8222ea589..d2caa35059d9 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -19,6 +19,9 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include <linux/module.h> +#include <linux/string.h> +#include <linux/slab.h> + #include <scsi/scsi.h> #include <scsi/scsi_host.h> #include <scsi/scsi_device.h> diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index ad94367df430..d86d5c26061d 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -49,6 +49,7 @@ static int sg_version_num = 30533; /* 2 digits for each component */ #include <linux/seq_file.h> #include <linux/blkdev.h> #include <linux/delay.h> +#include <linux/scatterlist.h> #include "scsi.h" #include <scsi/scsi_dbg.h> @@ -104,8 +105,8 @@ static int sg_allow_dio = SG_ALLOW_DIO_DEF; #define SG_DEV_ARR_LUMP 32 /* amount to over allocate sg_dev_arr by */ -static int sg_add(struct class_device *); -static void sg_remove(struct class_device *); +static int sg_add(struct class_device *, struct class_interface *); +static void sg_remove(struct class_device *, struct class_interface *); static Scsi_Request *dummy_cmdp; /* only used for sizeof */ @@ -1506,7 +1507,7 @@ static int sg_alloc(struct gendisk *disk, struct scsi_device *scsidp) } static int -sg_add(struct class_device *cl_dev) +sg_add(struct class_device *cl_dev, struct class_interface *cl_intf) { struct scsi_device *scsidp = to_scsi_device(cl_dev->dev); struct gendisk *disk; @@ -1550,7 +1551,7 @@ sg_add(struct class_device *cl_dev) if (sg_sysfs_valid) { struct class_device * sg_class_member; - sg_class_member = class_device_create(sg_sysfs_class, + sg_class_member = class_device_create(sg_sysfs_class, NULL, MKDEV(SCSI_GENERIC_MAJOR, k), cl_dev->dev, "%s", disk->disk_name); @@ -1582,7 +1583,7 @@ out: } static void -sg_remove(struct class_device *cl_dev) +sg_remove(struct class_device *cl_dev, struct class_interface *cl_intf) { struct scsi_device *scsidp = to_scsi_device(cl_dev->dev); Sg_device *sdp = NULL; @@ -1886,13 +1887,17 @@ st_unmap_user_pages(struct scatterlist *sgl, const unsigned int nr_pages, int i; for (i=0; i < nr_pages; i++) { - if (dirtied && !PageReserved(sgl[i].page)) - SetPageDirty(sgl[i].page); - /* unlock_page(sgl[i].page); */ + struct page *page = sgl[i].page; + + /* XXX: just for debug. Remove when PageReserved is removed */ + BUG_ON(PageReserved(page)); + if (dirtied) + SetPageDirty(page); + /* unlock_page(page); */ /* FIXME: cache flush missing for rw==READ * FIXME: call the correct reference counting function */ - page_cache_release(sgl[i].page); + page_cache_release(page); } return 0; @@ -1992,9 +1997,7 @@ sg_build_indirect(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size) if (!p) break; } - sclp->page = virt_to_page(p); - sclp->offset = offset_in_page(p); - sclp->length = ret_sz; + sg_set_buf(sclp, p, ret_sz); SCSI_LOG_TIMEOUT(5, printk("sg_build_build: k=%d, a=0x%p, len=%d\n", k, sg_scatg2virt(sclp), ret_sz)); @@ -2644,7 +2647,7 @@ static char * sg_page_malloc(int rqSz, int lowDma, int *retSzp) { char *resp = NULL; - int page_mask; + gfp_t page_mask; int order, a_size; int resSz = rqSz; diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index d001c046551b..da9766283bd7 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -3577,7 +3577,8 @@ static long st_compat_ioctl(struct file *file, unsigned int cmd, unsigned long a static struct st_buffer * new_tape_buffer(int from_initialization, int need_dma, int max_sg) { - int i, priority, got = 0, segs = 0; + int i, got = 0, segs = 0; + gfp_t priority; struct st_buffer *tb; if (from_initialization) @@ -3610,7 +3611,8 @@ static struct st_buffer * /* Try to allocate enough space in the tape buffer */ static int enlarge_buffer(struct st_buffer * STbuffer, int new_size, int need_dma) { - int segs, nbr, max_segs, b_size, priority, order, got; + int segs, nbr, max_segs, b_size, order, got; + gfp_t priority; if (new_size <= STbuffer->buffer_size) return 1; @@ -4375,7 +4377,7 @@ static void do_create_class_files(struct scsi_tape *STp, int dev_num, int mode) snprintf(name, 10, "%s%s%s", rew ? "n" : "", STp->disk->disk_name, st_formats[i]); st_class_member = - class_device_create(st_sysfs_class, + class_device_create(st_sysfs_class, NULL, MKDEV(SCSI_TAPE_MAJOR, TAPE_MINOR(dev_num, mode, rew)), &STp->device->sdev_gendev, "%s", name); @@ -4524,12 +4526,16 @@ static int sgl_unmap_user_pages(struct scatterlist *sgl, const unsigned int nr_p int i; for (i=0; i < nr_pages; i++) { - if (dirtied && !PageReserved(sgl[i].page)) - SetPageDirty(sgl[i].page); + struct page *page = sgl[i].page; + + /* XXX: just for debug. Remove when PageReserved is removed */ + BUG_ON(PageReserved(page)); + if (dirtied) + SetPageDirty(page); /* FIXME: cache flush missing for rw==READ * FIXME: call the correct reference counting function */ - page_cache_release(sgl[i].page); + page_cache_release(page); } return 0; diff --git a/drivers/scsi/sym53c8xx_2/sym_hipd.c b/drivers/scsi/sym53c8xx_2/sym_hipd.c index e753ba27dc59..a1a58e1d5ad3 100644 --- a/drivers/scsi/sym53c8xx_2/sym_hipd.c +++ b/drivers/scsi/sym53c8xx_2/sym_hipd.c @@ -37,6 +37,9 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include <linux/slab.h> + #include "sym_glue.h" #include "sym_nvram.h" diff --git a/drivers/scsi/sym53c8xx_2/sym_hipd.h b/drivers/scsi/sym53c8xx_2/sym_hipd.h index 3131a6bf7ab7..3a264a408216 100644 --- a/drivers/scsi/sym53c8xx_2/sym_hipd.h +++ b/drivers/scsi/sym53c8xx_2/sym_hipd.h @@ -37,6 +37,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include <linux/gfp.h> + #ifndef SYM_HIPD_H #define SYM_HIPD_H diff --git a/drivers/scsi/zalon.c b/drivers/scsi/zalon.c index 5a51051e31f0..b131432c677d 100644 --- a/drivers/scsi/zalon.c +++ b/drivers/scsi/zalon.c @@ -88,7 +88,7 @@ zalon_probe(struct parisc_device *dev) struct gsc_irq gsc_irq; u32 zalon_vers; int error = -ENODEV; - void __iomem *zalon = ioremap(dev->hpa, 4096); + void __iomem *zalon = ioremap(dev->hpa.start, 4096); void __iomem *io_port = zalon + GSC_SCSI_ZALON_OFFSET; static int unit = 0; struct Scsi_Host *host; @@ -127,7 +127,7 @@ zalon_probe(struct parisc_device *dev) device.chip = zalon720_chip; device.host_id = 7; device.dev = &dev->dev; - device.slot.base = dev->hpa + GSC_SCSI_ZALON_OFFSET; + device.slot.base = dev->hpa.start + GSC_SCSI_ZALON_OFFSET; device.slot.base_v = io_port; device.slot.irq = dev->irq; device.differential = 2; diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index 4d75cdfa0a0a..afb7ddf200e0 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -2358,13 +2358,10 @@ static int __devexit serial8250_remove(struct device *dev) return 0; } -static int serial8250_suspend(struct device *dev, pm_message_t state, u32 level) +static int serial8250_suspend(struct device *dev, pm_message_t state) { int i; - if (level != SUSPEND_DISABLE) - return 0; - for (i = 0; i < UART_NR; i++) { struct uart_8250_port *up = &serial8250_ports[i]; @@ -2375,13 +2372,10 @@ static int serial8250_suspend(struct device *dev, pm_message_t state, u32 level) return 0; } -static int serial8250_resume(struct device *dev, u32 level) +static int serial8250_resume(struct device *dev) { int i; - if (level != RESUME_ENABLE) - return 0; - for (i = 0; i < UART_NR; i++) { struct uart_8250_port *up = &serial8250_ports[i]; diff --git a/drivers/serial/8250_gsc.c b/drivers/serial/8250_gsc.c index 431aa5761a7a..8b4947933d9b 100644 --- a/drivers/serial/8250_gsc.c +++ b/drivers/serial/8250_gsc.c @@ -29,7 +29,6 @@ static int __init serial_init_chip(struct parisc_device *dev) { - static int serial_line_nr; struct uart_port port; unsigned long address; int err; @@ -42,12 +41,13 @@ serial_init_chip(struct parisc_device *dev) */ if (parisc_parent(dev)->id.hw_type != HPHW_IOA) { printk(KERN_INFO "Serial: device 0x%lx not configured.\n" - "Enable support for Wax, Lasi, Asp or Dino.\n", dev->hpa); + "Enable support for Wax, Lasi, Asp or Dino.\n", + dev->hpa.start); } return -ENODEV; } - address = dev->hpa; + address = dev->hpa.start; if (dev->id.sversion != 0x8d) { address += 0x800; } diff --git a/drivers/serial/amba-pl010.c b/drivers/serial/amba-pl010.c index 679e678c7e6a..ddd0307fece2 100644 --- a/drivers/serial/amba-pl010.c +++ b/drivers/serial/amba-pl010.c @@ -50,6 +50,7 @@ #include <asm/io.h> #include <asm/irq.h> +#include <asm/hardware.h> #include <asm/hardware/amba.h> #include <asm/hardware/amba_serial.h> diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c index 1ff629c74750..938d185841c9 100644 --- a/drivers/serial/amba-pl011.c +++ b/drivers/serial/amba-pl011.c @@ -50,6 +50,7 @@ #include <asm/io.h> #include <asm/irq.h> +#include <asm/sizes.h> #include <asm/hardware/amba.h> #include <asm/hardware/clock.h> #include <asm/hardware/amba_serial.h> diff --git a/drivers/serial/clps711x.c b/drivers/serial/clps711x.c index 87ef368384fb..6a67e8f585b3 100644 --- a/drivers/serial/clps711x.c +++ b/drivers/serial/clps711x.c @@ -408,7 +408,11 @@ static struct uart_port clps711x_ports[UART_NR] = { { .iobase = SYSCON1, .irq = IRQ_UTXINT1, /* IRQ_URXINT1, IRQ_UMSINT */ +#ifdef CONFIG_MP1000_90MHZ + .uartclk = 4515840, +#else .uartclk = 3686400, +#endif .fifosize = 16, .ops = &clps711x_pops, .line = 0, @@ -417,7 +421,11 @@ static struct uart_port clps711x_ports[UART_NR] = { { .iobase = SYSCON2, .irq = IRQ_UTXINT2, /* IRQ_URXINT2 */ +#ifdef CONFIG_MP1000_90MHZ + .uartclk = 4515840, +#else .uartclk = 3686400, +#endif .fifosize = 16, .ops = &clps711x_pops, .line = 1, @@ -551,6 +559,7 @@ console_initcall(clps711xuart_console_init); static struct uart_driver clps711x_reg = { .driver_name = "ttyCL", .dev_name = "ttyCL", + .devfs_name = "ttyCL", .major = SERIAL_CLPS711X_MAJOR, .minor = SERIAL_CLPS711X_MINOR, .nr = UART_NR, diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c index bdb4e454b8b0..5b3933b0c997 100644 --- a/drivers/serial/imx.c +++ b/drivers/serial/imx.c @@ -921,21 +921,21 @@ static struct uart_driver imx_reg = { .cons = IMX_CONSOLE, }; -static int serial_imx_suspend(struct device *_dev, pm_message_t state, u32 level) +static int serial_imx_suspend(struct device *_dev, pm_message_t state) { struct imx_port *sport = dev_get_drvdata(_dev); - if (sport && level == SUSPEND_DISABLE) + if (sport) uart_suspend_port(&imx_reg, &sport->port); return 0; } -static int serial_imx_resume(struct device *_dev, u32 level) +static int serial_imx_resume(struct device *_dev) { struct imx_port *sport = dev_get_drvdata(_dev); - if (sport && level == RESUME_ENABLE) + if (sport) uart_resume_port(&imx_reg, &sport->port); return 0; diff --git a/drivers/serial/ioc4_serial.c b/drivers/serial/ioc4_serial.c index f88fdd480685..771676abee60 100644 --- a/drivers/serial/ioc4_serial.c +++ b/drivers/serial/ioc4_serial.c @@ -308,6 +308,8 @@ struct ioc4_serial { typedef void ioc4_intr_func_f(void *, uint32_t); typedef ioc4_intr_func_f *ioc4_intr_func_t; +static unsigned int Num_of_ioc4_cards; + /* defining this will get you LOTS of great debug info */ //#define DEBUG_INTERRUPTS #define DPRINT_CONFIG(_x...) ; @@ -317,7 +319,8 @@ typedef ioc4_intr_func_f *ioc4_intr_func_t; #define WAKEUP_CHARS 256 /* number of characters we want to transmit to the lower level at a time */ -#define IOC4_MAX_CHARS 128 +#define IOC4_MAX_CHARS 256 +#define IOC4_FIFO_CHARS 255 /* Device name we're using */ #define DEVICE_NAME "ttyIOC" @@ -1038,6 +1041,7 @@ static int inline ioc4_attach_local(struct ioc4_driver_data *idd) return -ENOMEM; } memset(port, 0, sizeof(struct ioc4_port)); + spin_lock_init(&port->ip_lock); /* we need to remember the previous ones, to point back to * them farther down - setting up the ring buffers. @@ -1691,12 +1695,14 @@ ioc4_change_speed(struct uart_port *the_port, baud = 9600; if (!the_port->fifosize) - the_port->fifosize = IOC4_MAX_CHARS; + the_port->fifosize = IOC4_FIFO_CHARS; the_port->timeout = ((the_port->fifosize * HZ * bits) / (baud / 10)); the_port->timeout += HZ / 50; /* Add .02 seconds of slop */ the_port->ignore_status_mask = N_ALL_INPUT; + info->tty->low_latency = 1; + if (I_IGNPAR(info->tty)) the_port->ignore_status_mask &= ~(N_PARITY_ERROR | N_FRAMING_ERROR); @@ -1742,7 +1748,6 @@ ioc4_change_speed(struct uart_port *the_port, */ static inline int ic4_startup_local(struct uart_port *the_port) { - int retval = 0; struct ioc4_port *port; struct uart_info *info; @@ -1754,9 +1759,6 @@ static inline int ic4_startup_local(struct uart_port *the_port) return -1; info = the_port->info; - if (info->flags & UIF_INITIALIZED) { - return retval; - } if (info->tty) { set_bit(TTY_IO_ERROR, &info->tty->flags); @@ -1775,7 +1777,6 @@ static inline int ic4_startup_local(struct uart_port *the_port) /* set the speed of the serial port */ ioc4_change_speed(the_port, info->tty->termios, (struct termios *)0); - info->flags |= UIF_INITIALIZED; return 0; } @@ -1785,9 +1786,13 @@ static inline int ic4_startup_local(struct uart_port *the_port) */ static void ioc4_cb_output_lowat(struct ioc4_port *port) { + unsigned long pflags; + /* ip_lock is set on the call here */ if (port->ip_port) { + spin_lock_irqsave(&port->ip_port->lock, pflags); transmit_chars(port->ip_port); + spin_unlock_irqrestore(&port->ip_port->lock, pflags); } } @@ -2064,8 +2069,7 @@ static inline int do_read(struct uart_port *the_port, unsigned char *buf, * available data as long as it returns some. */ /* Re-arm the timer */ - writel(port->ip_rx_cons | IOC4_SRCIR_ARM, - &port->ip_serial_regs->srcir); + writel(port->ip_rx_cons | IOC4_SRCIR_ARM, &port->ip_serial_regs->srcir); prod_ptr = readl(&port->ip_serial_regs->srpir) & PROD_CONS_MASK; cons_ptr = port->ip_rx_cons; @@ -2299,6 +2303,7 @@ static inline int do_read(struct uart_port *the_port, unsigned char *buf, } return total; } + /** * receive_chars - upper level read. Called with ip_lock. * @the_port: port to read from @@ -2307,9 +2312,11 @@ static void receive_chars(struct uart_port *the_port) { struct tty_struct *tty; unsigned char ch[IOC4_MAX_CHARS]; - int read_count, request_count; + int read_count, request_count = IOC4_MAX_CHARS; struct uart_icount *icount; struct uart_info *info = the_port->info; + int flip = 0; + unsigned long pflags; /* Make sure all the pointers are "good" ones */ if (!info) @@ -2317,16 +2324,17 @@ static void receive_chars(struct uart_port *the_port) if (!info->tty) return; + spin_lock_irqsave(&the_port->lock, pflags); tty = info->tty; - request_count = TTY_FLIPBUF_SIZE - tty->flip.count - 1; + if (request_count > TTY_FLIPBUF_SIZE - tty->flip.count) + request_count = TTY_FLIPBUF_SIZE - tty->flip.count; if (request_count > 0) { - if (request_count > IOC4_MAX_CHARS - 2) - request_count = IOC4_MAX_CHARS - 2; icount = &the_port->icount; read_count = do_read(the_port, ch, request_count); if (read_count > 0) { + flip = 1; memcpy(tty->flip.char_buf_ptr, ch, read_count); memset(tty->flip.flag_buf_ptr, TTY_NORMAL, read_count); tty->flip.char_buf_ptr += read_count; @@ -2335,7 +2343,11 @@ static void receive_chars(struct uart_port *the_port) icount->rx += read_count; } } - tty_flip_buffer_push(tty); + + spin_unlock_irqrestore(&the_port->lock, pflags); + + if (flip) + tty_flip_buffer_push(tty); } /** @@ -2393,18 +2405,14 @@ static void ic4_shutdown(struct uart_port *the_port) info = the_port->info; - if (!(info->flags & UIF_INITIALIZED)) - return; - wake_up_interruptible(&info->delta_msr_wait); if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); - spin_lock_irqsave(&port->ip_lock, port_flags); + spin_lock_irqsave(&the_port->lock, port_flags); set_notification(port, N_ALL, 0); - info->flags &= ~UIF_INITIALIZED; - spin_unlock_irqrestore(&port->ip_lock, port_flags); + spin_unlock_irqrestore(&the_port->lock, port_flags); } /** @@ -2463,12 +2471,10 @@ static unsigned int ic4_get_mctrl(struct uart_port *the_port) static void ic4_start_tx(struct uart_port *the_port) { struct ioc4_port *port = get_ioc4_port(the_port); - unsigned long flags; if (port) { - spin_lock_irqsave(&port->ip_lock, flags); - transmit_chars(the_port); - spin_unlock_irqrestore(&port->ip_lock, flags); + set_notification(port, N_OUTPUT_LOWAT, 1); + enable_intrs(port, port->ip_hooks->intr_tx_mt); } } @@ -2510,9 +2516,9 @@ static int ic4_startup(struct uart_port *the_port) } /* Start up the serial port */ - spin_lock_irqsave(&port->ip_lock, port_flags); + spin_lock_irqsave(&the_port->lock, port_flags); retval = ic4_startup_local(the_port); - spin_unlock_irqrestore(&port->ip_lock, port_flags); + spin_unlock_irqrestore(&the_port->lock, port_flags); return retval; } @@ -2527,12 +2533,11 @@ static void ic4_set_termios(struct uart_port *the_port, struct termios *termios, struct termios *old_termios) { - struct ioc4_port *port = get_ioc4_port(the_port); unsigned long port_flags; - spin_lock_irqsave(&port->ip_lock, port_flags); + spin_lock_irqsave(&the_port->lock, port_flags); ioc4_change_speed(the_port, termios, old_termios); - spin_unlock_irqrestore(&port->ip_lock, port_flags); + spin_unlock_irqrestore(&the_port->lock, port_flags); } /** @@ -2607,24 +2612,25 @@ ioc4_serial_core_attach(struct pci_dev *pdev) __FUNCTION__, (void *)the_port, (void *)port)); - spin_lock_init(&the_port->lock); /* membase, iobase and mapbase just need to be non-0 */ the_port->membase = (unsigned char __iomem *)1; - the_port->line = the_port->iobase = ii; + the_port->iobase = (pdev->bus->number << 16) | ii; + the_port->line = (Num_of_ioc4_cards << 2) | ii; the_port->mapbase = 1; the_port->type = PORT_16550A; - the_port->fifosize = IOC4_MAX_CHARS; + the_port->fifosize = IOC4_FIFO_CHARS; the_port->ops = &ioc4_ops; the_port->irq = control->ic_irq; the_port->dev = &pdev->dev; + spin_lock_init(&the_port->lock); if (uart_add_one_port(&ioc4_uart, the_port) < 0) { printk(KERN_WARNING - "%s: unable to add port %d\n", - __FUNCTION__, the_port->line); + "%s: unable to add port %d bus %d\n", + __FUNCTION__, the_port->line, pdev->bus->number); } else { DPRINT_CONFIG( - ("IOC4 serial driver port %d irq = %d\n", - the_port->line, the_port->irq)); + ("IOC4 serial port %d irq = %d, bus %d\n", + the_port->line, the_port->irq, pdev->bus->number)); } /* all ports are rs232 for now */ ioc4_set_proto(port, PROTO_RS232); @@ -2734,6 +2740,8 @@ ioc4_serial_attach_one(struct ioc4_driver_data *idd) if ((ret = ioc4_serial_core_attach(idd->idd_pdev))) goto out4; + Num_of_ioc4_cards++; + return ret; /* error exits that give back resources */ diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c index 0585ab27ffde..8a79968f8ce1 100644 --- a/drivers/serial/mpc52xx_uart.c +++ b/drivers/serial/mpc52xx_uart.c @@ -781,22 +781,22 @@ mpc52xx_uart_remove(struct device *dev) #ifdef CONFIG_PM static int -mpc52xx_uart_suspend(struct device *dev, pm_message_t state, u32 level) +mpc52xx_uart_suspend(struct device *dev, pm_message_t state) { struct uart_port *port = (struct uart_port *) dev_get_drvdata(dev); - if (sport && level == SUSPEND_DISABLE) + if (sport) uart_suspend_port(&mpc52xx_uart_driver, port); return 0; } static int -mpc52xx_uart_resume(struct device *dev, u32 level) +mpc52xx_uart_resume(struct device *dev) { struct uart_port *port = (struct uart_port *) dev_get_drvdata(dev); - if (port && level == RESUME_ENABLE) + if (port) uart_resume_port(&mpc52xx_uart_driver, port); return 0; diff --git a/drivers/serial/mpsc.c b/drivers/serial/mpsc.c index efe79b1fd431..aec83f577ce6 100644 --- a/drivers/serial/mpsc.c +++ b/drivers/serial/mpsc.c @@ -1100,6 +1100,8 @@ mpsc_start_rx(struct mpsc_port_info *pi) { pr_debug("mpsc_start_rx[%d]: Starting...\n", pi->port.line); + /* Issue a Receive Abort to clear any receive errors */ + writel(MPSC_CHR_2_RA, pi->mpsc_base + MPSC_CHR_2); if (pi->rcv_data) { mpsc_enter_hunt(pi); mpsc_sdma_cmd(pi, SDMA_SDCM_ERD); diff --git a/drivers/serial/mux.c b/drivers/serial/mux.c index 189064607709..660bae5ba179 100644 --- a/drivers/serial/mux.c +++ b/drivers/serial/mux.c @@ -27,6 +27,7 @@ #include <linux/delay.h> /* for udelay */ #include <linux/device.h> #include <asm/io.h> +#include <asm/irq.h> #include <asm/parisc-device.h> #ifdef CONFIG_MAGIC_SYSRQ @@ -444,7 +445,7 @@ static int __init mux_probe(struct parisc_device *dev) unsigned long bytecnt; struct uart_port *port; - status = pdc_iodc_read(&bytecnt, dev->hpa, 0, iodc_data, 32); + status = pdc_iodc_read(&bytecnt, dev->hpa.start, 0, iodc_data, 32); if(status != PDC_OK) { printk(KERN_ERR "Serial mux: Unable to read IODC.\n"); return 1; @@ -469,16 +470,18 @@ static int __init mux_probe(struct parisc_device *dev) for(i = 0; i < ports; ++i, ++port_cnt) { port = &mux_ports[port_cnt]; port->iobase = 0; - port->mapbase = dev->hpa + MUX_OFFSET + (i * MUX_LINE_OFFSET); + port->mapbase = dev->hpa.start + MUX_OFFSET + + (i * MUX_LINE_OFFSET); port->membase = ioremap(port->mapbase, MUX_LINE_OFFSET); port->iotype = SERIAL_IO_MEM; port->type = PORT_MUX; - port->irq = SERIAL_IRQ_NONE; + port->irq = NO_IRQ; port->uartclk = 0; port->fifosize = MUX_FIFO_SIZE; port->ops = &mux_pops; port->flags = UPF_BOOT_AUTOCONF; port->line = port_cnt; + spin_lock_init(&port->lock); status = uart_add_one_port(&mux_driver, port); BUG_ON(status); } @@ -497,7 +500,7 @@ static struct parisc_device_id mux_tbl[] = { MODULE_DEVICE_TABLE(parisc, mux_tbl); static struct parisc_driver serial_mux_driver = { - .name = "Serial MUX", + .name = "serial_mux", .id_table = mux_tbl, .probe = mux_probe, }; diff --git a/drivers/serial/pxa.c b/drivers/serial/pxa.c index 90c2a86c421b..8cc4cedadd99 100644 --- a/drivers/serial/pxa.c +++ b/drivers/serial/pxa.c @@ -358,6 +358,9 @@ static int serial_pxa_startup(struct uart_port *port) unsigned long flags; int retval; + if (port->line == 3) /* HWUART */ + up->mcr |= UART_MCR_AFE; + else up->mcr = 0; /* @@ -481,8 +484,10 @@ serial_pxa_set_termios(struct uart_port *port, struct termios *termios, if ((up->port.uartclk / quot) < (2400 * 16)) fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR1; - else + else if ((up->port.uartclk / quot) < (230400 * 16)) fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR8; + else + fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR32; /* * Ok, we're now changing the port state. Do it with @@ -772,6 +777,20 @@ static struct uart_pxa_port serial_pxa_ports[] = { .ops = &serial_pxa_pops, .line = 2, }, + }, { /* HWUART */ + .name = "HWUART", + .cken = CKEN4_HWUART, + .port = { + .type = PORT_PXA, + .iotype = UPIO_MEM, + .membase = (void *)&HWUART, + .mapbase = __PREG(HWUART), + .irq = IRQ_HWUART, + .uartclk = 921600 * 16, + .fifosize = 64, + .ops = &serial_pxa_pops, + .line = 3, + }, } }; @@ -786,21 +805,21 @@ static struct uart_driver serial_pxa_reg = { .cons = PXA_CONSOLE, }; -static int serial_pxa_suspend(struct device *_dev, pm_message_t state, u32 level) +static int serial_pxa_suspend(struct device *_dev, pm_message_t state) { struct uart_pxa_port *sport = dev_get_drvdata(_dev); - if (sport && level == SUSPEND_DISABLE) + if (sport) uart_suspend_port(&serial_pxa_reg, &sport->port); return 0; } -static int serial_pxa_resume(struct device *_dev, u32 level) +static int serial_pxa_resume(struct device *_dev) { struct uart_pxa_port *sport = dev_get_drvdata(_dev); - if (sport && level == RESUME_ENABLE) + if (sport) uart_resume_port(&serial_pxa_reg, &sport->port); return 0; diff --git a/drivers/serial/s3c2410.c b/drivers/serial/s3c2410.c index 52692aa345ec..06a17dff1a73 100644 --- a/drivers/serial/s3c2410.c +++ b/drivers/serial/s3c2410.c @@ -1134,23 +1134,22 @@ static int s3c24xx_serial_remove(struct device *_dev) #ifdef CONFIG_PM -static int s3c24xx_serial_suspend(struct device *dev, pm_message_t state, - u32 level) +static int s3c24xx_serial_suspend(struct device *dev, pm_message_t state) { struct uart_port *port = s3c24xx_dev_to_port(dev); - if (port && level == SUSPEND_DISABLE) + if (port) uart_suspend_port(&s3c24xx_uart_drv, port); return 0; } -static int s3c24xx_serial_resume(struct device *dev, u32 level) +static int s3c24xx_serial_resume(struct device *dev) { struct uart_port *port = s3c24xx_dev_to_port(dev); struct s3c24xx_uart_port *ourport = to_ourport(port); - if (port && level == RESUME_ENABLE) { + if (port) { clk_enable(ourport->clk); s3c24xx_serial_resetport(port, s3c24xx_port_to_cfg(port)); clk_disable(ourport->clk); diff --git a/drivers/serial/sa1100.c b/drivers/serial/sa1100.c index dd8aed242357..c4a789e6af44 100644 --- a/drivers/serial/sa1100.c +++ b/drivers/serial/sa1100.c @@ -834,21 +834,21 @@ static struct uart_driver sa1100_reg = { .cons = SA1100_CONSOLE, }; -static int sa1100_serial_suspend(struct device *_dev, pm_message_t state, u32 level) +static int sa1100_serial_suspend(struct device *_dev, pm_message_t state) { struct sa1100_port *sport = dev_get_drvdata(_dev); - if (sport && level == SUSPEND_DISABLE) + if (sport) uart_suspend_port(&sa1100_reg, &sport->port); return 0; } -static int sa1100_serial_resume(struct device *_dev, u32 level) +static int sa1100_serial_resume(struct device *_dev) { struct sa1100_port *sport = dev_get_drvdata(_dev); - if (sport && level == RESUME_ENABLE) + if (sport) uart_resume_port(&sa1100_reg, &sport->port); return 0; diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c index 2d8622eef701..401d94a7fe2e 100644 --- a/drivers/serial/serial_core.c +++ b/drivers/serial/serial_core.c @@ -147,8 +147,7 @@ static int uart_startup(struct uart_state *state, int init_hw) * once we have successfully opened the port. Also set * up the tty->alt_speed kludge */ - if (info->tty) - set_bit(TTY_IO_ERROR, &info->tty->flags); + set_bit(TTY_IO_ERROR, &info->tty->flags); if (port->type == PORT_UNKNOWN) return 0; diff --git a/drivers/serial/vr41xx_siu.c b/drivers/serial/vr41xx_siu.c index 0c5d65a08f6e..2b623ab0e36e 100644 --- a/drivers/serial/vr41xx_siu.c +++ b/drivers/serial/vr41xx_siu.c @@ -976,14 +976,11 @@ static int siu_remove(struct device *dev) return 0; } -static int siu_suspend(struct device *dev, pm_message_t state, u32 level) +static int siu_suspend(struct device *dev, pm_message_t state) { struct uart_port *port; int i; - if (level != SUSPEND_DISABLE) - return 0; - for (i = 0; i < siu_uart_driver.nr; i++) { port = &siu_uart_ports[i]; if ((port->type == PORT_VR41XX_SIU || @@ -995,14 +992,11 @@ static int siu_suspend(struct device *dev, pm_message_t state, u32 level) return 0; } -static int siu_resume(struct device *dev, u32 level) +static int siu_resume(struct device *dev) { struct uart_port *port; int i; - if (level != RESUME_ENABLE) - return 0; - for (i = 0; i < siu_uart_driver.nr; i++) { port = &siu_uart_ports[i]; if ((port->type == PORT_VR41XX_SIU || diff --git a/drivers/sh/superhyway/superhyway.c b/drivers/sh/superhyway/superhyway.c index f056276b08a1..28757cb9d246 100644 --- a/drivers/sh/superhyway/superhyway.c +++ b/drivers/sh/superhyway/superhyway.c @@ -16,6 +16,8 @@ #include <linux/types.h> #include <linux/list.h> #include <linux/superhyway.h> +#include <linux/string.h> +#include <linux/slab.h> static int superhyway_devices; diff --git a/drivers/tc/tc.c b/drivers/tc/tc.c index a89ef4df80c3..a0e5af638e0e 100644 --- a/drivers/tc/tc.c +++ b/drivers/tc/tc.c @@ -8,33 +8,31 @@ * for more details. * * Copyright (c) Harald Koerfgen, 1998 - * Copyright (c) 2001, 2003 Maciej W. Rozycki + * Copyright (c) 2001, 2003, 2005 Maciej W. Rozycki */ -#include <linux/string.h> #include <linux/init.h> -#include <linux/ioport.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/string.h> +#include <linux/types.h> #include <asm/addrspace.h> +#include <asm/bug.h> #include <asm/errno.h> +#include <asm/io.h> +#include <asm/paccess.h> + #include <asm/dec/machtype.h> #include <asm/dec/prom.h> #include <asm/dec/tcinfo.h> #include <asm/dec/tcmodule.h> #include <asm/dec/interrupts.h> -#include <asm/paccess.h> -#include <asm/ptrace.h> - -#define TC_DEBUG MODULE_LICENSE("GPL"); slot_info tc_bus[MAX_SLOT]; static int num_tcslots; static tcinfo *info; -unsigned long system_base; - /* * Interface to the world. Read comment in include/asm-mips/tc.h. */ @@ -97,13 +95,16 @@ unsigned long get_tc_speed(void) static void __init tc_probe(unsigned long startaddr, unsigned long size, int slots) { + unsigned long slotaddr; int i, slot, err; long offset; - unsigned char pattern[4]; - unsigned char *module; + u8 pattern[4]; + volatile u8 *module; for (slot = 0; slot < slots; slot++) { - module = (char *)(startaddr + slot * size); + slotaddr = startaddr + slot * size; + module = ioremap_nocache(slotaddr, size); + BUG_ON(!module); offset = OLDCARD; @@ -112,8 +113,10 @@ static void __init tc_probe(unsigned long startaddr, unsigned long size, err |= get_dbe(pattern[1], module + OLDCARD + TC_PATTERN1); err |= get_dbe(pattern[2], module + OLDCARD + TC_PATTERN2); err |= get_dbe(pattern[3], module + OLDCARD + TC_PATTERN3); - if (err) + if (err) { + iounmap(module); continue; + } if (pattern[0] != 0x55 || pattern[1] != 0x00 || pattern[2] != 0xaa || pattern[3] != 0xff) { @@ -124,16 +127,20 @@ static void __init tc_probe(unsigned long startaddr, unsigned long size, err |= get_dbe(pattern[1], module + TC_PATTERN1); err |= get_dbe(pattern[2], module + TC_PATTERN2); err |= get_dbe(pattern[3], module + TC_PATTERN3); - if (err) + if (err) { + iounmap(module); continue; + } } if (pattern[0] != 0x55 || pattern[1] != 0x00 || - pattern[2] != 0xaa || pattern[3] != 0xff) + pattern[2] != 0xaa || pattern[3] != 0xff) { + iounmap(module); continue; + } - tc_bus[slot].base_addr = (unsigned long)module; - for(i = 0; i < 8; i++) { + tc_bus[slot].base_addr = slotaddr; + for (i = 0; i < 8; i++) { tc_bus[slot].firmware[i] = module[TC_FIRM_VER + offset + 4 * i]; tc_bus[slot].vendor[i] = @@ -171,13 +178,15 @@ static void __init tc_probe(unsigned long startaddr, unsigned long size, tc_bus[slot].interrupt = -1; break; } + + iounmap(module); } } /* * the main entry */ -void __init tc_init(void) +static int __init tc_init(void) { int tc_clock; int i; @@ -185,7 +194,7 @@ void __init tc_init(void) unsigned long slot_size; if (!TURBOCHANNEL) - return; + return 0; for (i = 0; i < MAX_SLOT; i++) { tc_bus[i].base_addr = 0; @@ -196,8 +205,8 @@ void __init tc_init(void) tc_bus[i].flags = FREE; } - info = (tcinfo *) rex_gettcinfo(); - slot0addr = (unsigned long)KSEG1ADDR(rex_slot_address(0)); + info = rex_gettcinfo(); + slot0addr = CPHYSADDR((long)rex_slot_address(0)); switch (mips_machtype) { case MACH_DS5000_200: @@ -216,37 +225,24 @@ void __init tc_init(void) tc_clock = 10000 / info->clk_period; - if (TURBOCHANNEL && info->slot_size && slot0addr) { - printk("TURBOchannel rev. %1d at %2d.%1d MHz ", info->revision, - tc_clock / 10, tc_clock % 10); - printk("(with%s parity)\n", info->parity ? "" : "out"); + if (info->slot_size && slot0addr) { + pr_info("TURBOchannel rev. %d at %d.%d MHz (with%s parity)\n", + info->revision, tc_clock / 10, tc_clock % 10, + info->parity ? "" : "out"); slot_size = info->slot_size << 20; tc_probe(slot0addr, slot_size, num_tcslots); - /* - * All TURBOchannel DECstations have the onboard devices - * where the (num_tcslots + 0 or 1 on DS5k/xx) Option Module - * would be. - */ - if(mips_machtype == MACH_DS5000_XX) - i = 1; - else - i = 0; - - system_base = slot0addr + slot_size * (num_tcslots + i); - -#ifdef TC_DEBUG - for (i = 0; i < num_tcslots; i++) - if (tc_bus[i].base_addr) { - printk(" slot %d: ", i); - printk("%s %s %s\n", tc_bus[i].vendor, - tc_bus[i].name, tc_bus[i].firmware); - } -#endif - ioport_resource.end = KSEG2 - 1; + for (i = 0; i < num_tcslots; i++) { + if (!tc_bus[i].base_addr) + continue; + pr_info(" slot %d: %s %s %s\n", i, tc_bus[i].vendor, + tc_bus[i].name, tc_bus[i].firmware); + } } + + return 0; } subsys_initcall(tc_init); @@ -257,4 +253,3 @@ EXPORT_SYMBOL(release_tc_card); EXPORT_SYMBOL(get_tc_base_addr); EXPORT_SYMBOL(get_tc_irq_nr); EXPORT_SYMBOL(get_tc_speed); -EXPORT_SYMBOL(system_base); diff --git a/drivers/tc/zs.c b/drivers/tc/zs.c index 6bed8713897e..c52af73a251b 100644 --- a/drivers/tc/zs.c +++ b/drivers/tc/zs.c @@ -65,14 +65,14 @@ #include <asm/system.h> #include <asm/uaccess.h> #include <asm/bootinfo.h> -#include <asm/dec/serial.h> -#ifdef CONFIG_MACH_DECSTATION #include <asm/dec/interrupts.h> +#include <asm/dec/ioasic_addrs.h> #include <asm/dec/machtype.h> +#include <asm/dec/serial.h> +#include <asm/dec/system.h> #include <asm/dec/tc.h> -#include <asm/dec/ioasic_addrs.h> -#endif + #ifdef CONFIG_KGDB #include <asm/kgdb.h> #endif @@ -192,18 +192,6 @@ static void probe_sccs(void); static void change_speed(struct dec_serial *info); static void rs_wait_until_sent(struct tty_struct *tty, int timeout); -/* - * tmp_buf is used as a temporary buffer by serial_write. We need to - * lock it in case the copy_from_user blocks while swapping in a page, - * and some other program tries to do a serial write at the same time. - * Since the lock will only come under contention when the system is - * swapping and available memory is low, it makes sense to share one - * buffer across all the serial ports, since it significantly saves - * memory if large numbers of serial ports are open. - */ -static unsigned char tmp_buf[4096]; /* This is cheating */ -static DECLARE_MUTEX(tmp_buf_sem); - static inline int serial_paranoia_check(struct dec_serial *info, char *name, const char *routine) { @@ -1628,30 +1616,22 @@ static void __init probe_sccs(void) return; } - /* - * When serial console is activated, tc_init has not been called yet - * and system_base is undefined. Unfortunately we have to hardcode - * system_base for this case :-(. HK - */ switch(mips_machtype) { #ifdef CONFIG_MACH_DECSTATION case MACH_DS5000_2X0: case MACH_DS5900: - system_base = KSEG1ADDR(0x1f800000); n_chips = 2; zs_parms = &ds_parms; zs_parms->irq0 = dec_interrupt[DEC_IRQ_SCC0]; zs_parms->irq1 = dec_interrupt[DEC_IRQ_SCC1]; break; case MACH_DS5000_1XX: - system_base = KSEG1ADDR(0x1c000000); n_chips = 2; zs_parms = &ds_parms; zs_parms->irq0 = dec_interrupt[DEC_IRQ_SCC0]; zs_parms->irq1 = dec_interrupt[DEC_IRQ_SCC1]; break; case MACH_DS5000_XX: - system_base = KSEG1ADDR(0x1c000000); n_chips = 1; zs_parms = &ds_parms; zs_parms->irq0 = dec_interrupt[DEC_IRQ_SCC0]; @@ -1673,10 +1653,10 @@ static void __init probe_sccs(void) * The sccs reside on the high byte of the 16 bit IOBUS */ zs_channels[n_channels].control = - (volatile unsigned char *)system_base + + (volatile void *)CKSEG1ADDR(dec_kn_slot_base + (0 == chip ? zs_parms->scc0 : zs_parms->scc1) + (0 == channel ? zs_parms->channel_a_offset : - zs_parms->channel_b_offset); + zs_parms->channel_b_offset)); zs_channels[n_channels].data = zs_channels[n_channels].control + 4; diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index df014c2a7c54..a50c2bc506f2 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_USB) += core/ obj-$(CONFIG_USB_MON) += mon/ +obj-$(CONFIG_PCI) += host/ obj-$(CONFIG_USB_EHCI_HCD) += host/ obj-$(CONFIG_USB_ISP116X_HCD) += host/ obj-$(CONFIG_USB_OHCI_HCD) += host/ @@ -17,7 +18,6 @@ obj-$(CONFIG_ETRAX_USB_HOST) += host/ obj-$(CONFIG_USB_ACM) += class/ obj-$(CONFIG_USB_AUDIO) += class/ -obj-$(CONFIG_USB_BLUETOOTH_TTY) += class/ obj-$(CONFIG_USB_MIDI) += class/ obj-$(CONFIG_USB_PRINTER) += class/ diff --git a/drivers/usb/class/Kconfig b/drivers/usb/class/Kconfig index 333e39bb105f..ef105a92a7bd 100644 --- a/drivers/usb/class/Kconfig +++ b/drivers/usb/class/Kconfig @@ -28,29 +28,6 @@ config USB_AUDIO To compile this driver as a module, choose M here: the module will be called audio. -comment "USB Bluetooth TTY can only be used with disabled Bluetooth subsystem" - depends on USB && BT - -config USB_BLUETOOTH_TTY - tristate "USB Bluetooth TTY support" - depends on USB && BT=n - ---help--- - This driver implements a nonstandard tty interface to a Bluetooth - device that can be used only by specialized Bluetooth HCI software. - - Say Y here if you want to use OpenBT Bluetooth stack (available - at <http://developer.axis.com/software>), or other TTY based - Bluetooth stacks, and want to connect a USB Bluetooth device - to your computer's USB port. - - Do *not* enable this driver if you want to use generic Linux - Bluetooth support. - - If in doubt, say N here. - - To compile this driver as a module, choose M here: the - module will be called bluetty. - config USB_MIDI tristate "USB MIDI support" depends on USB && SOUND && OBSOLETE_OSS_USB_DRIVER diff --git a/drivers/usb/class/Makefile b/drivers/usb/class/Makefile index 971e5497a3fd..229471247751 100644 --- a/drivers/usb/class/Makefile +++ b/drivers/usb/class/Makefile @@ -5,6 +5,5 @@ obj-$(CONFIG_USB_ACM) += cdc-acm.o obj-$(CONFIG_USB_AUDIO) += audio.o -obj-$(CONFIG_USB_BLUETOOTH_TTY) += bluetty.o obj-$(CONFIG_USB_MIDI) += usb-midi.o obj-$(CONFIG_USB_PRINTER) += usblp.o diff --git a/drivers/usb/class/bluetty.c b/drivers/usb/class/bluetty.c deleted file mode 100644 index 524023327c49..000000000000 --- a/drivers/usb/class/bluetty.c +++ /dev/null @@ -1,1279 +0,0 @@ -/* - * bluetty.c Version 0.13 - * - * Copyright (C) 2000, 2001 Greg Kroah-Hartman <greg@kroah.com> - * Copyright (C) 2000 Mark Douglas Corner <mcorner@umich.edu> - * - * USB Bluetooth TTY driver, based on the Bluetooth Spec version 1.0B - * - * (2001/11/30) Version 0.13 gkh - * - added locking patch from Masoodur Rahman <rmasoodu@in.ibm.com> - * - removed active variable, as open_count will do. - * - * (2001/07/09) Version 0.12 gkh - * - removed in_interrupt() call, as it doesn't make sense to do - * that anymore. - * - * (2001/06/05) Version 0.11 gkh - * - Fixed problem with read urb status saying that we have shutdown, - * and that we shouldn't resubmit the urb. Patch from unknown. - * - * (2001/05/28) Version 0.10 gkh - * - Fixed problem with using data from userspace in the bluetooth_write - * function as found by the CHECKER project. - * - Added a buffer to the write_urb_pool which reduces the number of - * buffers being created and destroyed for ever write. Also cleans - * up the logic a bit. - * - Added a buffer to the control_urb_pool which fixes a memory leak - * when the device is removed from the system. - * - * (2001/05/28) Version 0.9 gkh - * Fixed problem with bluetooth==NULL for bluetooth_read_bulk_callback - * which was found by both the CHECKER project and Mikko Rahkonen. - * - * (08/04/2001) gb - * Identify version on module load. - * - * (2001/03/10) Version 0.8 gkh - * Fixed problem with not unlinking interrupt urb on device close - * and resubmitting the read urb on error with bluetooth struct. - * Thanks to Narayan Mohanram <narayan@RovingNetworks.com> for the - * fixes. - * - * (11/29/2000) Version 0.7 gkh - * Fixed problem with overrunning the tty flip buffer. - * Removed unneeded NULL pointer initialization. - * - * (10/05/2000) Version 0.6 gkh - * Fixed bug with urb->dev not being set properly, now that the usb - * core needs it. - * Got a real major id number and name. - * - * (08/06/2000) Version 0.5 gkh - * Fixed problem of not resubmitting the bulk read urb if there is - * an error in the callback. Ericsson devices seem to need this. - * - * (07/11/2000) Version 0.4 gkh - * Fixed bug in disconnect for when we call tty_hangup - * Fixed bug in bluetooth_ctrl_msg where the bluetooth struct was not - * getting attached to the control urb properly. - * Fixed bug in bluetooth_write where we pay attention to the result - * of bluetooth_ctrl_msg. - * - * (08/03/2000) Version 0.3 gkh mdc - * Merged in Mark's changes to make the driver play nice with the Axis - * stack. - * Made the write bulk use an urb pool to enable larger transfers with - * fewer calls to the driver. - * Fixed off by one bug in acl pkt receive - * Made packet counters specific to each bluetooth device - * Added checks for zero length callbacks - * Added buffers for int and bulk packets. Had to do this otherwise - * packet types could intermingle. - * Made a control urb pool for the control messages. - * - * (07/11/2000) Version 0.2 gkh - * Fixed a small bug found by Nils Faerber in the usb_bluetooth_probe - * function. - * - * (07/09/2000) Version 0.1 gkh - * Initial release. Has support for sending ACL data (which is really just - * a HCI frame.) Raw HCI commands and HCI events are not supported. - * A ioctl will probably be needed for the HCI commands and events in the - * future. All isoch endpoints are ignored at this time also. - * This driver should work for all currently shipping USB Bluetooth - * devices at this time :) - * - */ - -/* - * 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 - */ - - -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/tty.h> -#include <linux/tty_driver.h> -#include <linux/tty_flip.h> -#include <linux/module.h> -#include <asm/uaccess.h> - -#define DEBUG -#include <linux/usb.h> - -/* - * Version Information - */ -#define DRIVER_VERSION "v0.13" -#define DRIVER_AUTHOR "Greg Kroah-Hartman, Mark Douglas Corner" -#define DRIVER_DESC "USB Bluetooth tty driver" - -/* define this if you have hardware that is not good */ -/*#define BTBUGGYHARDWARE */ - -/* Class, SubClass, and Protocol codes that describe a Bluetooth device */ -#define WIRELESS_CLASS_CODE 0xe0 -#define RF_SUBCLASS_CODE 0x01 -#define BLUETOOTH_PROGRAMMING_PROTOCOL_CODE 0x01 - - -#define BLUETOOTH_TTY_MAJOR 216 /* real device node major id */ -#define BLUETOOTH_TTY_MINORS 256 /* whole lotta bluetooth devices */ - -#define USB_BLUETOOTH_MAGIC 0x6d02 /* magic number for bluetooth struct */ - -#define BLUETOOTH_CONTROL_REQUEST_TYPE 0x20 - -/* Bluetooth packet types */ -#define CMD_PKT 0x01 -#define ACL_PKT 0x02 -#define SCO_PKT 0x03 -#define EVENT_PKT 0x04 -#define ERROR_PKT 0x05 -#define NEG_PKT 0x06 - -/* Message sizes */ -#define MAX_EVENT_SIZE 0xFF -#define EVENT_HDR_SIZE 3 /* 2 for the header + 1 for the type indicator */ -#define EVENT_BUFFER_SIZE (MAX_EVENT_SIZE + EVENT_HDR_SIZE) - -#define MAX_ACL_SIZE 0xFFFF -#define ACL_HDR_SIZE 5 /* 4 for the header + 1 for the type indicator */ -#define ACL_BUFFER_SIZE (MAX_ACL_SIZE + ACL_HDR_SIZE) - -/* parity check flag */ -#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) - -#define CHAR2INT16(c1,c0) (((u32)((c1) & 0xff) << 8) + (u32)((c0) & 0xff)) - -#define NUM_BULK_URBS 24 -#define NUM_CONTROL_URBS 16 - -struct usb_bluetooth { - int magic; - struct usb_device * dev; - struct tty_driver * tty_driver; /* the tty_driver for this device */ - struct tty_struct * tty; /* the corresponding tty for this port */ - - unsigned char minor; /* the starting minor number for this device */ - int throttle; /* throttled by tty layer */ - int open_count; - - __u8 control_out_bInterfaceNum; - struct urb * control_urb_pool[NUM_CONTROL_URBS]; - struct usb_ctrlrequest dr[NUM_CONTROL_URBS]; - - unsigned char * interrupt_in_buffer; - struct urb * interrupt_in_urb; - __u8 interrupt_in_endpointAddress; - __u8 interrupt_in_interval; - int interrupt_in_buffer_size; - - unsigned char * bulk_in_buffer; - struct urb * read_urb; - __u8 bulk_in_endpointAddress; - int bulk_in_buffer_size; - - int bulk_out_buffer_size; - __u8 bulk_out_endpointAddress; - - wait_queue_head_t write_wait; - - struct work_struct work; /* work queue entry for line discipline waking up */ - - unsigned int int_packet_pos; - unsigned char int_buffer[EVENT_BUFFER_SIZE]; - unsigned int bulk_packet_pos; - unsigned char bulk_buffer[ACL_BUFFER_SIZE]; /* 64k preallocated, fix? */ - struct semaphore lock; -}; - - -/* local function prototypes */ -static int bluetooth_open (struct tty_struct *tty, struct file *filp); -static void bluetooth_close (struct tty_struct *tty, struct file *filp); -static int bluetooth_write (struct tty_struct *tty, const unsigned char *buf, int count); -static int bluetooth_write_room (struct tty_struct *tty); -static int bluetooth_chars_in_buffer (struct tty_struct *tty); -static void bluetooth_throttle (struct tty_struct *tty); -static void bluetooth_unthrottle (struct tty_struct *tty); -static int bluetooth_ioctl (struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg); -static void bluetooth_set_termios (struct tty_struct *tty, struct termios *old); - -static void bluetooth_int_callback (struct urb *urb, struct pt_regs *regs); -static void bluetooth_ctrl_callback (struct urb *urb, struct pt_regs *regs); -static void bluetooth_read_bulk_callback (struct urb *urb, struct pt_regs *regs); -static void bluetooth_write_bulk_callback (struct urb *urb, struct pt_regs *regs); - -static int usb_bluetooth_probe (struct usb_interface *intf, - const struct usb_device_id *id); -static void usb_bluetooth_disconnect (struct usb_interface *intf); - - -static struct usb_device_id usb_bluetooth_ids [] = { - { USB_DEVICE_INFO(WIRELESS_CLASS_CODE, RF_SUBCLASS_CODE, BLUETOOTH_PROGRAMMING_PROTOCOL_CODE) }, - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE (usb, usb_bluetooth_ids); - -static struct usb_driver usb_bluetooth_driver = { - .owner = THIS_MODULE, - .name = "bluetty", - .probe = usb_bluetooth_probe, - .disconnect = usb_bluetooth_disconnect, - .id_table = usb_bluetooth_ids, -}; - -static struct tty_driver *bluetooth_tty_driver; -static struct usb_bluetooth *bluetooth_table[BLUETOOTH_TTY_MINORS]; - - -static inline int bluetooth_paranoia_check (struct usb_bluetooth *bluetooth, const char *function) -{ - if (!bluetooth) { - dbg("%s - bluetooth == NULL", function); - return -1; - } - if (bluetooth->magic != USB_BLUETOOTH_MAGIC) { - dbg("%s - bad magic number for bluetooth", function); - return -1; - } - - return 0; -} - - -static inline struct usb_bluetooth* get_usb_bluetooth (struct usb_bluetooth *bluetooth, const char *function) -{ - if (!bluetooth || - bluetooth_paranoia_check (bluetooth, function)) { - /* then say that we don't have a valid usb_bluetooth thing, which will - * end up generating -ENODEV return values */ - return NULL; - } - - return bluetooth; -} - - -static inline struct usb_bluetooth *get_bluetooth_by_index (int index) -{ - return bluetooth_table[index]; -} - - -static int bluetooth_ctrl_msg (struct usb_bluetooth *bluetooth, int request, int value, const unsigned char *buf, int len) -{ - struct urb *urb = NULL; - struct usb_ctrlrequest *dr = NULL; - int i; - int status; - - dbg ("%s", __FUNCTION__); - - /* try to find a free urb in our list */ - for (i = 0; i < NUM_CONTROL_URBS; ++i) { - if (bluetooth->control_urb_pool[i]->status != -EINPROGRESS) { - urb = bluetooth->control_urb_pool[i]; - dr = &bluetooth->dr[i]; - break; - } - } - if (urb == NULL) { - dbg ("%s - no free urbs", __FUNCTION__); - return -ENOMEM; - } - - /* keep increasing the urb transfer buffer to fit the size of the message */ - if (urb->transfer_buffer == NULL) { - urb->transfer_buffer = kmalloc (len, GFP_KERNEL); - if (urb->transfer_buffer == NULL) { - err ("%s - out of memory", __FUNCTION__); - return -ENOMEM; - } - } - if (urb->transfer_buffer_length < len) { - kfree(urb->transfer_buffer); - urb->transfer_buffer = kmalloc (len, GFP_KERNEL); - if (urb->transfer_buffer == NULL) { - err ("%s - out of memory", __FUNCTION__); - return -ENOMEM; - } - } - memcpy (urb->transfer_buffer, buf, len); - - dr->bRequestType= BLUETOOTH_CONTROL_REQUEST_TYPE; - dr->bRequest = request; - dr->wValue = cpu_to_le16((u16) value); - dr->wIndex = cpu_to_le16((u16) bluetooth->control_out_bInterfaceNum); - dr->wLength = cpu_to_le16((u16) len); - - usb_fill_control_urb (urb, bluetooth->dev, usb_sndctrlpipe(bluetooth->dev, 0), - (unsigned char*)dr, urb->transfer_buffer, len, bluetooth_ctrl_callback, bluetooth); - - /* send it down the pipe */ - status = usb_submit_urb(urb, GFP_KERNEL); - if (status) - dbg("%s - usb_submit_urb(control) failed with status = %d", __FUNCTION__, status); - - return status; -} - - - - - -/***************************************************************************** - * Driver tty interface functions - *****************************************************************************/ -static int bluetooth_open (struct tty_struct *tty, struct file * filp) -{ - struct usb_bluetooth *bluetooth; - int result; - - dbg("%s", __FUNCTION__); - - /* initialize the pointer incase something fails */ - tty->driver_data = NULL; - - /* get the bluetooth object associated with this tty pointer */ - bluetooth = get_bluetooth_by_index (tty->index); - - if (bluetooth_paranoia_check (bluetooth, __FUNCTION__)) { - return -ENODEV; - } - - down (&bluetooth->lock); - - ++bluetooth->open_count; - if (bluetooth->open_count == 1) { - /* set up our structure making the tty driver remember our object, and us it */ - tty->driver_data = bluetooth; - bluetooth->tty = tty; - - /* force low_latency on so that our tty_push actually forces the data through, - * otherwise it is scheduled, and with high data rates (like with OHCI) data - * can get lost. */ - bluetooth->tty->low_latency = 1; - - /* Reset the packet position counters */ - bluetooth->int_packet_pos = 0; - bluetooth->bulk_packet_pos = 0; - -#ifndef BTBUGGYHARDWARE - /* Start reading from the device */ - usb_fill_bulk_urb (bluetooth->read_urb, bluetooth->dev, - usb_rcvbulkpipe(bluetooth->dev, bluetooth->bulk_in_endpointAddress), - bluetooth->bulk_in_buffer, - bluetooth->bulk_in_buffer_size, - bluetooth_read_bulk_callback, bluetooth); - result = usb_submit_urb(bluetooth->read_urb, GFP_KERNEL); - if (result) - dbg("%s - usb_submit_urb(read bulk) failed with status %d", __FUNCTION__, result); -#endif - usb_fill_int_urb (bluetooth->interrupt_in_urb, bluetooth->dev, - usb_rcvintpipe(bluetooth->dev, bluetooth->interrupt_in_endpointAddress), - bluetooth->interrupt_in_buffer, - bluetooth->interrupt_in_buffer_size, - bluetooth_int_callback, bluetooth, - bluetooth->interrupt_in_interval); - result = usb_submit_urb(bluetooth->interrupt_in_urb, GFP_KERNEL); - if (result) - dbg("%s - usb_submit_urb(interrupt in) failed with status %d", __FUNCTION__, result); - } - - up(&bluetooth->lock); - - return 0; -} - - -static void bluetooth_close (struct tty_struct *tty, struct file * filp) -{ - struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__); - - if (!bluetooth) { - return; - } - - dbg("%s", __FUNCTION__); - - if (!bluetooth->open_count) { - dbg ("%s - device not opened", __FUNCTION__); - return; - } - - down (&bluetooth->lock); - - --bluetooth->open_count; - if (bluetooth->open_count <= 0) { - bluetooth->open_count = 0; - - /* shutdown any in-flight urbs that we know about */ - usb_kill_urb (bluetooth->read_urb); - usb_kill_urb (bluetooth->interrupt_in_urb); - } - up(&bluetooth->lock); -} - - -static int bluetooth_write (struct tty_struct * tty, const unsigned char *buf, int count) -{ - struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__); - struct urb *urb = NULL; - unsigned char *temp_buffer = NULL; - const unsigned char *current_buffer; - unsigned char *urb_buffer; - int i; - int retval = 0; - - if (!bluetooth) { - return -ENODEV; - } - - dbg("%s - %d byte(s)", __FUNCTION__, count); - - if (!bluetooth->open_count) { - dbg ("%s - device not opened", __FUNCTION__); - return -EINVAL; - } - - if (count == 0) { - dbg("%s - write request of 0 bytes", __FUNCTION__); - return 0; - } - if (count == 1) { - dbg("%s - write request only included type %d", __FUNCTION__, buf[0]); - return 1; - } - -#ifdef DEBUG - printk (KERN_DEBUG __FILE__ ": %s - length = %d, data = ", __FUNCTION__, count); - for (i = 0; i < count; ++i) { - printk ("%.2x ", buf[i]); - } - printk ("\n"); -#endif - - current_buffer = buf; - - switch (*current_buffer) { - /* First byte indicates the type of packet */ - case CMD_PKT: - /* dbg("%s- Send cmd_pkt len:%d", __FUNCTION__, count);*/ - - retval = bluetooth_ctrl_msg (bluetooth, 0x00, 0x00, ¤t_buffer[1], count-1); - if (retval) { - goto exit; - } - retval = count; - break; - - case ACL_PKT: - ++current_buffer; - --count; - - urb_buffer = kmalloc (count, GFP_ATOMIC); - if (!urb_buffer) { - dev_err(&bluetooth->dev->dev, "out of memory\n"); - retval = -ENOMEM; - goto exit; - } - - urb = usb_alloc_urb(0, GFP_ATOMIC); - if (!urb) { - dev_err(&bluetooth->dev->dev, "no more free urbs\n"); - kfree(urb_buffer); - retval = -ENOMEM; - goto exit; - } - memcpy (urb_buffer, current_buffer, count); - - /* build up our urb */ - usb_fill_bulk_urb(urb, bluetooth->dev, - usb_sndbulkpipe(bluetooth->dev, - bluetooth->bulk_out_endpointAddress), - urb_buffer, - count, - bluetooth_write_bulk_callback, - bluetooth); - - - /* send it down the pipe */ - retval = usb_submit_urb(urb, GFP_KERNEL); - if (retval) { - dbg("%s - usb_submit_urb(write bulk) failed with error = %d", __FUNCTION__, retval); - goto exit; - } - - /* we are done with this urb, so let the host driver - * really free it when it is finished with it */ - usb_free_urb (urb); - retval = count + 1; - break; - - default : - dbg("%s - unsupported (at this time) write type", __FUNCTION__); - retval = -EINVAL; - break; - } - -exit: - kfree(temp_buffer); - - return retval; -} - - -static int bluetooth_write_room (struct tty_struct *tty) -{ - dbg("%s", __FUNCTION__); - - /* - * We really can take anything the user throws at us - * but let's pick a nice big number to tell the tty - * layer that we have lots of free space - */ - return 2048; -} - - -static int bluetooth_chars_in_buffer (struct tty_struct *tty) -{ - dbg("%s", __FUNCTION__); - - /* - * We can't really account for how much data we - * have sent out, but hasn't made it through to the - * device, so just tell the tty layer that everything - * is flushed. - */ - return 0; -} - - -static void bluetooth_throttle (struct tty_struct * tty) -{ - struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__); - - if (!bluetooth) { - return; - } - - dbg("%s", __FUNCTION__); - - if (!bluetooth->open_count) { - dbg ("%s - device not open", __FUNCTION__); - return; - } - - dbg("%s unsupported (at this time)", __FUNCTION__); - - return; -} - - -static void bluetooth_unthrottle (struct tty_struct * tty) -{ - struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__); - - if (!bluetooth) { - return; - } - - dbg("%s", __FUNCTION__); - - if (!bluetooth->open_count) { - dbg ("%s - device not open", __FUNCTION__); - return; - } - - dbg("%s unsupported (at this time)", __FUNCTION__); -} - - -static int bluetooth_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg) -{ - struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__); - - if (!bluetooth) { - return -ENODEV; - } - - dbg("%s - cmd 0x%.4x", __FUNCTION__, cmd); - - if (!bluetooth->open_count) { - dbg ("%s - device not open", __FUNCTION__); - return -ENODEV; - } - - /* FIXME!!! */ - return -ENOIOCTLCMD; -} - - -static void bluetooth_set_termios (struct tty_struct *tty, struct termios * old) -{ - struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__); - - if (!bluetooth) { - return; - } - - dbg("%s", __FUNCTION__); - - if (!bluetooth->open_count) { - dbg ("%s - device not open", __FUNCTION__); - return; - } - - /* FIXME!!! */ - - return; -} - - -#ifdef BTBUGGYHARDWARE -void btusb_enable_bulk_read(struct tty_struct *tty){ - struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__); - int result; - - if (!bluetooth) { - return; - } - - dbg("%s", __FUNCTION__); - - if (!bluetooth->open_count) { - dbg ("%s - device not open", __FUNCTION__); - return; - } - - if (bluetooth->read_urb) { - usb_fill_bulk_urb(bluetooth->read_urb, bluetooth->dev, - usb_rcvbulkpipe(bluetooth->dev, bluetooth->bulk_in_endpointAddress), - bluetooth->bulk_in_buffer, bluetooth->bulk_in_buffer_size, - bluetooth_read_bulk_callback, bluetooth); - result = usb_submit_urb(bluetooth->read_urb, GFP_KERNEL); - if (result) - err ("%s - failed submitting read urb, error %d", __FUNCTION__, result); - } -} - -void btusb_disable_bulk_read(struct tty_struct *tty){ - struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__); - - if (!bluetooth) { - return; - } - - dbg("%s", __FUNCTION__); - - if (!bluetooth->open_count) { - dbg ("%s - device not open", __FUNCTION__); - return; - } - - if ((bluetooth->read_urb) && (bluetooth->read_urb->actual_length)) - usb_kill_urb(bluetooth->read_urb); -} -#endif - - -/***************************************************************************** - * urb callback functions - *****************************************************************************/ - - -static void bluetooth_int_callback (struct urb *urb, struct pt_regs *regs) -{ - struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)urb->context, __FUNCTION__); - unsigned char *data = urb->transfer_buffer; - unsigned int i; - unsigned int count = urb->actual_length; - unsigned int packet_size; - int status; - - dbg("%s", __FUNCTION__); - - if (!bluetooth) { - dbg("%s - bad bluetooth pointer, exiting", __FUNCTION__); - return; - } - - switch (urb->status) { - case 0: - /* success */ - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status); - return; - default: - dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status); - goto exit; - } - - if (!count) { - dbg("%s - zero length int", __FUNCTION__); - goto exit; - } - - -#ifdef DEBUG - if (count) { - printk (KERN_DEBUG __FILE__ ": %s- length = %d, data = ", __FUNCTION__, count); - for (i = 0; i < count; ++i) { - printk ("%.2x ", data[i]); - } - printk ("\n"); - } -#endif - -#ifdef BTBUGGYHARDWARE - if ((count >= 2) && (data[0] == 0xFF) && (data[1] == 0x00)) { - data += 2; - count -= 2; - } - if (count == 0) { - urb->actual_length = 0; - goto exit; - } -#endif - /* We add a packet type identifier to the beginning of each - HCI frame. This makes the data in the tty look like a - serial USB devices. Each HCI frame can be broken across - multiple URBs so we buffer them until we have a full hci - packet */ - - if (!bluetooth->int_packet_pos) { - bluetooth->int_buffer[0] = EVENT_PKT; - bluetooth->int_packet_pos++; - } - - if (bluetooth->int_packet_pos + count > EVENT_BUFFER_SIZE) { - err("%s - exceeded EVENT_BUFFER_SIZE", __FUNCTION__); - bluetooth->int_packet_pos = 0; - goto exit; - } - - memcpy (&bluetooth->int_buffer[bluetooth->int_packet_pos], - urb->transfer_buffer, count); - bluetooth->int_packet_pos += count; - urb->actual_length = 0; - - if (bluetooth->int_packet_pos >= EVENT_HDR_SIZE) - packet_size = bluetooth->int_buffer[2]; - else - goto exit; - - if (packet_size + EVENT_HDR_SIZE < bluetooth->int_packet_pos) { - err("%s - packet was too long", __FUNCTION__); - bluetooth->int_packet_pos = 0; - goto exit; - } - - if (packet_size + EVENT_HDR_SIZE == bluetooth->int_packet_pos) { - for (i = 0; i < bluetooth->int_packet_pos; ++i) { - /* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them */ - if (bluetooth->tty->flip.count >= TTY_FLIPBUF_SIZE) { - tty_flip_buffer_push(bluetooth->tty); - } - tty_insert_flip_char(bluetooth->tty, bluetooth->int_buffer[i], 0); - } - tty_flip_buffer_push(bluetooth->tty); - - bluetooth->int_packet_pos = 0; - } - -exit: - status = usb_submit_urb (urb, GFP_ATOMIC); - if (status) - err ("%s - usb_submit_urb failed with result %d", - __FUNCTION__, status); -} - - -static void bluetooth_ctrl_callback (struct urb *urb, struct pt_regs *regs) -{ - struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)urb->context, __FUNCTION__); - - dbg("%s", __FUNCTION__); - - if (!bluetooth) { - dbg("%s - bad bluetooth pointer, exiting", __FUNCTION__); - return; - } - - if (urb->status) { - dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status); - return; - } -} - - -static void bluetooth_read_bulk_callback (struct urb *urb, struct pt_regs *regs) -{ - struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)urb->context, __FUNCTION__); - unsigned char *data = urb->transfer_buffer; - unsigned int count = urb->actual_length; - unsigned int i; - unsigned int packet_size; - int result; - - - dbg("%s", __FUNCTION__); - - if (!bluetooth) { - dbg("%s - bad bluetooth pointer, exiting", __FUNCTION__); - return; - } - - if (urb->status) { - dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status); - if (urb->status == -ENOENT) { - dbg("%s - URB canceled, won't reschedule", __FUNCTION__); - return; - } - goto exit; - } - - if (!count) { - dbg("%s - zero length read bulk", __FUNCTION__); - goto exit; - } - -#ifdef DEBUG - if (count) { - printk (KERN_DEBUG __FILE__ ": %s- length = %d, data = ", __FUNCTION__, count); - for (i = 0; i < count; ++i) { - printk ("%.2x ", data[i]); - } - printk ("\n"); - } -#endif -#ifdef BTBUGGYHARDWARE - if ((count == 4) && (data[0] == 0x00) && (data[1] == 0x00) - && (data[2] == 0x00) && (data[3] == 0x00)) { - urb->actual_length = 0; - usb_fill_bulk_urb(bluetooth->read_urb, bluetooth->dev, - usb_rcvbulkpipe(bluetooth->dev, bluetooth->bulk_in_endpointAddress), - bluetooth->bulk_in_buffer, bluetooth->bulk_in_buffer_size, - bluetooth_read_bulk_callback, bluetooth); - result = usb_submit_urb(bluetooth->read_urb, GFP_KERNEL); - if (result) - err ("%s - failed resubmitting read urb, error %d", __FUNCTION__, result); - - return; - } -#endif - /* We add a packet type identifier to the beginning of each - HCI frame. This makes the data in the tty look like a - serial USB devices. Each HCI frame can be broken across - multiple URBs so we buffer them until we have a full hci - packet */ - - if (!bluetooth->bulk_packet_pos) { - bluetooth->bulk_buffer[0] = ACL_PKT; - bluetooth->bulk_packet_pos++; - } - - if (bluetooth->bulk_packet_pos + count > ACL_BUFFER_SIZE) { - err("%s - exceeded ACL_BUFFER_SIZE", __FUNCTION__); - bluetooth->bulk_packet_pos = 0; - goto exit; - } - - memcpy (&bluetooth->bulk_buffer[bluetooth->bulk_packet_pos], - urb->transfer_buffer, count); - bluetooth->bulk_packet_pos += count; - urb->actual_length = 0; - - if (bluetooth->bulk_packet_pos >= ACL_HDR_SIZE) { - packet_size = CHAR2INT16(bluetooth->bulk_buffer[4],bluetooth->bulk_buffer[3]); - } else { - goto exit; - } - - if (packet_size + ACL_HDR_SIZE < bluetooth->bulk_packet_pos) { - err("%s - packet was too long", __FUNCTION__); - bluetooth->bulk_packet_pos = 0; - goto exit; - } - - if (packet_size + ACL_HDR_SIZE == bluetooth->bulk_packet_pos) { - for (i = 0; i < bluetooth->bulk_packet_pos; ++i) { - /* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them. */ - if (bluetooth->tty->flip.count >= TTY_FLIPBUF_SIZE) { - tty_flip_buffer_push(bluetooth->tty); - } - tty_insert_flip_char(bluetooth->tty, bluetooth->bulk_buffer[i], 0); - } - tty_flip_buffer_push(bluetooth->tty); - bluetooth->bulk_packet_pos = 0; - } - -exit: - if (!bluetooth || !bluetooth->open_count) - return; - - usb_fill_bulk_urb(bluetooth->read_urb, bluetooth->dev, - usb_rcvbulkpipe(bluetooth->dev, bluetooth->bulk_in_endpointAddress), - bluetooth->bulk_in_buffer, bluetooth->bulk_in_buffer_size, - bluetooth_read_bulk_callback, bluetooth); - result = usb_submit_urb(bluetooth->read_urb, GFP_KERNEL); - if (result) - err ("%s - failed resubmitting read urb, error %d", __FUNCTION__, result); - - return; -} - - -static void bluetooth_write_bulk_callback (struct urb *urb, struct pt_regs *regs) -{ - struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)urb->context, __FUNCTION__); - - dbg("%s", __FUNCTION__); - - /* free up the transfer buffer, as usb_free_urb() does not do this */ - kfree(urb->transfer_buffer); - - if (!bluetooth) { - dbg("%s - bad bluetooth pointer, exiting", __FUNCTION__); - return; - } - - if (urb->status) { - dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status); - return; - } - - /* wake up our little function to let the tty layer know that something happened */ - schedule_work(&bluetooth->work); -} - - -static void bluetooth_softint(void *private) -{ - struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)private, __FUNCTION__); - - dbg("%s", __FUNCTION__); - - if (!bluetooth) - return; - - tty_wakeup(bluetooth->tty); -} - - -static int usb_bluetooth_probe (struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_device *dev = interface_to_usbdev (intf); - struct usb_bluetooth *bluetooth = NULL; - struct usb_host_interface *interface; - struct usb_endpoint_descriptor *endpoint; - struct usb_endpoint_descriptor *interrupt_in_endpoint[8]; - struct usb_endpoint_descriptor *bulk_in_endpoint[8]; - struct usb_endpoint_descriptor *bulk_out_endpoint[8]; - int control_out_endpoint; - - int minor; - int buffer_size; - int i; - int num_interrupt_in = 0; - int num_bulk_in = 0; - int num_bulk_out = 0; - - interface = intf->cur_altsetting; - control_out_endpoint = interface->desc.bInterfaceNumber; - - /* find the endpoints that we need */ - for (i = 0; i < interface->desc.bNumEndpoints; ++i) { - endpoint = &interface->endpoint[i].desc; - - if ((endpoint->bEndpointAddress & 0x80) && - ((endpoint->bmAttributes & 3) == 0x02)) { - /* we found a bulk in endpoint */ - dbg("found bulk in"); - bulk_in_endpoint[num_bulk_in] = endpoint; - ++num_bulk_in; - } - - if (((endpoint->bEndpointAddress & 0x80) == 0x00) && - ((endpoint->bmAttributes & 3) == 0x02)) { - /* we found a bulk out endpoint */ - dbg("found bulk out"); - bulk_out_endpoint[num_bulk_out] = endpoint; - ++num_bulk_out; - } - - if ((endpoint->bEndpointAddress & 0x80) && - ((endpoint->bmAttributes & 3) == 0x03)) { - /* we found a interrupt in endpoint */ - dbg("found interrupt in"); - interrupt_in_endpoint[num_interrupt_in] = endpoint; - ++num_interrupt_in; - } - } - - /* according to the spec, we can only have 1 bulk_in, 1 bulk_out, and 1 interrupt_in endpoints */ - if ((num_bulk_in != 1) || - (num_bulk_out != 1) || - (num_interrupt_in != 1)) { - dbg ("%s - improper number of endpoints. Bluetooth driver not bound.", __FUNCTION__); - return -EIO; - } - - info("USB Bluetooth converter detected"); - - for (minor = 0; minor < BLUETOOTH_TTY_MINORS && bluetooth_table[minor]; ++minor) - ; - if (bluetooth_table[minor]) { - err("No more free Bluetooth devices"); - return -ENODEV; - } - - if (!(bluetooth = kmalloc(sizeof(struct usb_bluetooth), GFP_KERNEL))) { - err("Out of memory"); - return -ENOMEM; - } - - memset(bluetooth, 0, sizeof(struct usb_bluetooth)); - - bluetooth->magic = USB_BLUETOOTH_MAGIC; - bluetooth->dev = dev; - bluetooth->minor = minor; - INIT_WORK(&bluetooth->work, bluetooth_softint, bluetooth); - init_MUTEX(&bluetooth->lock); - - /* record the interface number for the control out */ - bluetooth->control_out_bInterfaceNum = control_out_endpoint; - - /* create our control out urb pool */ - for (i = 0; i < NUM_CONTROL_URBS; ++i) { - struct urb *urb = usb_alloc_urb(0, GFP_KERNEL); - if (urb == NULL) { - err("No free urbs available"); - goto probe_error; - } - urb->transfer_buffer = NULL; - bluetooth->control_urb_pool[i] = urb; - } - - /* set up the endpoint information */ - endpoint = bulk_in_endpoint[0]; - bluetooth->read_urb = usb_alloc_urb (0, GFP_KERNEL); - if (!bluetooth->read_urb) { - err("No free urbs available"); - goto probe_error; - } - bluetooth->bulk_in_buffer_size = buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); - bluetooth->bulk_in_endpointAddress = endpoint->bEndpointAddress; - bluetooth->bulk_in_buffer = kmalloc (buffer_size, GFP_KERNEL); - if (!bluetooth->bulk_in_buffer) { - err("Couldn't allocate bulk_in_buffer"); - goto probe_error; - } - usb_fill_bulk_urb(bluetooth->read_urb, dev, usb_rcvbulkpipe(dev, endpoint->bEndpointAddress), - bluetooth->bulk_in_buffer, buffer_size, bluetooth_read_bulk_callback, bluetooth); - - endpoint = bulk_out_endpoint[0]; - bluetooth->bulk_out_endpointAddress = endpoint->bEndpointAddress; - bluetooth->bulk_out_buffer_size = le16_to_cpu(endpoint->wMaxPacketSize) * 2; - - endpoint = interrupt_in_endpoint[0]; - bluetooth->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!bluetooth->interrupt_in_urb) { - err("No free urbs available"); - goto probe_error; - } - bluetooth->interrupt_in_buffer_size = buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); - bluetooth->interrupt_in_endpointAddress = endpoint->bEndpointAddress; - bluetooth->interrupt_in_interval = endpoint->bInterval; - bluetooth->interrupt_in_buffer = kmalloc (buffer_size, GFP_KERNEL); - if (!bluetooth->interrupt_in_buffer) { - err("Couldn't allocate interrupt_in_buffer"); - goto probe_error; - } - usb_fill_int_urb(bluetooth->interrupt_in_urb, dev, usb_rcvintpipe(dev, endpoint->bEndpointAddress), - bluetooth->interrupt_in_buffer, buffer_size, bluetooth_int_callback, - bluetooth, endpoint->bInterval); - - /* initialize the devfs nodes for this device and let the user know what bluetooths we are bound to */ - tty_register_device (bluetooth_tty_driver, minor, &intf->dev); - info("Bluetooth converter now attached to ttyUB%d (or usb/ttub/%d for devfs)", minor, minor); - - bluetooth_table[minor] = bluetooth; - - /* success */ - usb_set_intfdata (intf, bluetooth); - return 0; - -probe_error: - if (bluetooth->read_urb) - usb_free_urb (bluetooth->read_urb); - if (bluetooth->bulk_in_buffer) - kfree (bluetooth->bulk_in_buffer); - if (bluetooth->interrupt_in_urb) - usb_free_urb (bluetooth->interrupt_in_urb); - if (bluetooth->interrupt_in_buffer) - kfree (bluetooth->interrupt_in_buffer); - for (i = 0; i < NUM_CONTROL_URBS; ++i) - if (bluetooth->control_urb_pool[i]) { - if (bluetooth->control_urb_pool[i]->transfer_buffer) - kfree (bluetooth->control_urb_pool[i]->transfer_buffer); - usb_free_urb (bluetooth->control_urb_pool[i]); - } - - bluetooth_table[minor] = NULL; - - /* free up any memory that we allocated */ - kfree (bluetooth); - return -EIO; -} - - -static void usb_bluetooth_disconnect(struct usb_interface *intf) -{ - struct usb_bluetooth *bluetooth = usb_get_intfdata (intf); - int i; - - usb_set_intfdata (intf, NULL); - if (bluetooth) { - if ((bluetooth->open_count) && (bluetooth->tty)) - tty_hangup(bluetooth->tty); - - bluetooth->open_count = 0; - - if (bluetooth->read_urb) { - usb_kill_urb (bluetooth->read_urb); - usb_free_urb (bluetooth->read_urb); - } - if (bluetooth->bulk_in_buffer) - kfree (bluetooth->bulk_in_buffer); - - if (bluetooth->interrupt_in_urb) { - usb_kill_urb (bluetooth->interrupt_in_urb); - usb_free_urb (bluetooth->interrupt_in_urb); - } - if (bluetooth->interrupt_in_buffer) - kfree (bluetooth->interrupt_in_buffer); - - tty_unregister_device (bluetooth_tty_driver, bluetooth->minor); - - for (i = 0; i < NUM_CONTROL_URBS; ++i) { - if (bluetooth->control_urb_pool[i]) { - usb_kill_urb (bluetooth->control_urb_pool[i]); - if (bluetooth->control_urb_pool[i]->transfer_buffer) - kfree (bluetooth->control_urb_pool[i]->transfer_buffer); - usb_free_urb (bluetooth->control_urb_pool[i]); - } - } - - info("Bluetooth converter now disconnected from ttyUB%d", bluetooth->minor); - - bluetooth_table[bluetooth->minor] = NULL; - - /* free up any memory that we allocated */ - kfree (bluetooth); - } else { - info("device disconnected"); - } -} - -static struct tty_operations bluetooth_ops = { - .open = bluetooth_open, - .close = bluetooth_close, - .write = bluetooth_write, - .write_room = bluetooth_write_room, - .ioctl = bluetooth_ioctl, - .set_termios = bluetooth_set_termios, - .throttle = bluetooth_throttle, - .unthrottle = bluetooth_unthrottle, - .chars_in_buffer = bluetooth_chars_in_buffer, -}; - -static int usb_bluetooth_init(void) -{ - int i; - int result; - - /* Initialize our global data */ - for (i = 0; i < BLUETOOTH_TTY_MINORS; ++i) { - bluetooth_table[i] = NULL; - } - - info ("USB Bluetooth support registered"); - - bluetooth_tty_driver = alloc_tty_driver(BLUETOOTH_TTY_MINORS); - if (!bluetooth_tty_driver) - return -ENOMEM; - - bluetooth_tty_driver->owner = THIS_MODULE; - bluetooth_tty_driver->driver_name = "usb-bluetooth"; - bluetooth_tty_driver->name = "ttyUB"; - bluetooth_tty_driver->devfs_name = "usb/ttub/"; - bluetooth_tty_driver->major = BLUETOOTH_TTY_MAJOR; - bluetooth_tty_driver->minor_start = 0; - bluetooth_tty_driver->type = TTY_DRIVER_TYPE_SERIAL; - bluetooth_tty_driver->subtype = SERIAL_TYPE_NORMAL; - bluetooth_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS; - bluetooth_tty_driver->init_termios = tty_std_termios; - bluetooth_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; - tty_set_operations(bluetooth_tty_driver, &bluetooth_ops); - if (tty_register_driver (bluetooth_tty_driver)) { - err("%s - failed to register tty driver", __FUNCTION__); - put_tty_driver(bluetooth_tty_driver); - return -1; - } - - /* register the USB driver */ - result = usb_register(&usb_bluetooth_driver); - if (result < 0) { - tty_unregister_driver(bluetooth_tty_driver); - put_tty_driver(bluetooth_tty_driver); - err("usb_register failed for the USB bluetooth driver. Error number %d", result); - return -1; - } - - info(DRIVER_DESC " " DRIVER_VERSION); - - return 0; -} - - -static void usb_bluetooth_exit(void) -{ - usb_deregister(&usb_bluetooth_driver); - tty_unregister_driver(bluetooth_tty_driver); - put_tty_driver(bluetooth_tty_driver); -} - - -module_init(usb_bluetooth_init); -module_exit(usb_bluetooth_exit); - -/* Module information */ -MODULE_AUTHOR( DRIVER_AUTHOR ); -MODULE_DESCRIPTION( DRIVER_DESC ); -MODULE_LICENSE("GPL"); - diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 16ecad30e29c..1b4751412970 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -827,11 +827,10 @@ skip_normal_probe: return -ENODEV; } - if (!(acm = kmalloc(sizeof(struct acm), GFP_KERNEL))) { - dev_dbg(&intf->dev, "out of memory (acm kmalloc)\n"); + if (!(acm = kzalloc(sizeof(struct acm), GFP_KERNEL))) { + dev_dbg(&intf->dev, "out of memory (acm kzalloc)\n"); goto alloc_fail; } - memset(acm, 0, sizeof(struct acm)); ctrlsize = le16_to_cpu(epctrl->wMaxPacketSize); readsize = le16_to_cpu(epread->wMaxPacketSize); diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index e195709c9c7f..357e75335f17 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -844,9 +844,8 @@ static struct file_operations usblp_fops = { }; static struct usb_class_driver usblp_class = { - .name = "usb/lp%d", + .name = "lp%d", .fops = &usblp_fops, - .mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, .minor_base = USBLP_MINOR_BASE, }; diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig index 1a9ff6184943..ff03184da403 100644 --- a/drivers/usb/core/Kconfig +++ b/drivers/usb/core/Kconfig @@ -61,14 +61,17 @@ config USB_DYNAMIC_MINORS If you are unsure about this, say N here. config USB_SUSPEND - bool "USB suspend/resume (EXPERIMENTAL)" + bool "USB selective suspend/resume and wakeup (EXPERIMENTAL)" depends on USB && PM && EXPERIMENTAL help If you say Y here, you can use driver calls or the sysfs "power/state" file to suspend or resume individual USB - peripherals. There are many related features, such as - remote wakeup and driver-specific suspend processing, that - may not yet work as expected. + peripherals. + + Also, USB "remote wakeup" signaling is supported, whereby some + USB devices (like keyboards and network adapters) can wake up + their parent hub. That wakeup cascades up the USB tree, and + could wake the system from states like suspend-to-RAM. If you are unsure about this, say N here. diff --git a/drivers/usb/core/Makefile b/drivers/usb/core/Makefile index d5503cf0bf74..dd1c4d2a0c31 100644 --- a/drivers/usb/core/Makefile +++ b/drivers/usb/core/Makefile @@ -3,7 +3,7 @@ # usbcore-objs := usb.o hub.o hcd.o urb.o message.o \ - config.o file.o buffer.o sysfs.o devio.o + config.o file.o buffer.o sysfs.o devio.o notify.o ifeq ($(CONFIG_PCI),y) usbcore-objs += hcd-pci.o diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c index fc15b4acc8af..57e800ac3cee 100644 --- a/drivers/usb/core/buffer.c +++ b/drivers/usb/core/buffer.c @@ -106,7 +106,7 @@ void hcd_buffer_destroy (struct usb_hcd *hcd) void *hcd_buffer_alloc ( struct usb_bus *bus, size_t size, - unsigned mem_flags, + gfp_t mem_flags, dma_addr_t *dma ) { diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index 99595e07b653..993019500cc3 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -112,8 +112,12 @@ void usb_release_interface_cache(struct kref *ref) struct usb_interface_cache *intfc = ref_to_usb_interface_cache(ref); int j; - for (j = 0; j < intfc->num_altsetting; j++) - kfree(intfc->altsetting[j].endpoint); + for (j = 0; j < intfc->num_altsetting; j++) { + struct usb_host_interface *alt = &intfc->altsetting[j]; + + kfree(alt->endpoint); + kfree(alt->string); + } kfree(intfc); } @@ -188,10 +192,9 @@ static int usb_parse_interface(struct device *ddev, int cfgno, } len = sizeof(struct usb_host_endpoint) * num_ep; - alt->endpoint = kmalloc(len, GFP_KERNEL); + alt->endpoint = kzalloc(len, GFP_KERNEL); if (!alt->endpoint) return -ENOMEM; - memset(alt->endpoint, 0, len); /* Parse all the endpoint descriptors */ n = 0; @@ -353,10 +356,9 @@ static int usb_parse_configuration(struct device *ddev, int cfgidx, } len = sizeof(*intfc) + sizeof(struct usb_host_interface) * j; - config->intf_cache[i] = intfc = kmalloc(len, GFP_KERNEL); + config->intf_cache[i] = intfc = kzalloc(len, GFP_KERNEL); if (!intfc) return -ENOMEM; - memset(intfc, 0, len); kref_init(&intfc->ref); } @@ -422,8 +424,6 @@ void usb_destroy_configuration(struct usb_device *dev) struct usb_host_config *cf = &dev->config[c]; kfree(cf->string); - cf->string = NULL; - for (i = 0; i < cf->desc.bNumInterfaces; i++) { if (cf->intf_cache[i]) kref_put(&cf->intf_cache[i]->ref, @@ -459,16 +459,14 @@ int usb_get_configuration(struct usb_device *dev) } length = ncfg * sizeof(struct usb_host_config); - dev->config = kmalloc(length, GFP_KERNEL); + dev->config = kzalloc(length, GFP_KERNEL); if (!dev->config) goto err2; - memset(dev->config, 0, length); length = ncfg * sizeof(char *); - dev->rawdescriptors = kmalloc(length, GFP_KERNEL); + dev->rawdescriptors = kzalloc(length, GFP_KERNEL); if (!dev->rawdescriptors) goto err2; - memset(dev->rawdescriptors, 0, length); buffer = kmalloc(USB_DT_CONFIG_SIZE, GFP_KERNEL); if (!buffer) diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 487ff672b104..942cd437dc48 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -46,6 +46,7 @@ #include <linux/usb.h> #include <linux/usbdevice_fs.h> #include <linux/cdev.h> +#include <linux/notifier.h> #include <asm/uaccess.h> #include <asm/byteorder.h> #include <linux/moduleparam.h> @@ -209,10 +210,10 @@ err: static struct async *alloc_async(unsigned int numisoframes) { unsigned int assize = sizeof(struct async) + numisoframes * sizeof(struct usb_iso_packet_descriptor); - struct async *as = kmalloc(assize, GFP_KERNEL); + struct async *as = kzalloc(assize, GFP_KERNEL); + if (!as) return NULL; - memset(as, 0, assize); as->urb = usb_alloc_urb(numisoframes, GFP_KERNEL); if (!as->urb) { kfree(as); @@ -279,6 +280,28 @@ static inline struct async *async_getpending(struct dev_state *ps, void __user * return NULL; } +static void snoop_urb(struct urb *urb, void __user *userurb) +{ + int j; + unsigned char *data = urb->transfer_buffer; + + if (!usbfs_snoop) + return; + + if (urb->pipe & USB_DIR_IN) + dev_info(&urb->dev->dev, "direction=IN\n"); + else + dev_info(&urb->dev->dev, "direction=OUT\n"); + dev_info(&urb->dev->dev, "userurb=%p\n", userurb); + dev_info(&urb->dev->dev, "transfer_buffer_length=%d\n", + urb->transfer_buffer_length); + dev_info(&urb->dev->dev, "actual_length=%d\n", urb->actual_length); + dev_info(&urb->dev->dev, "data: "); + for (j = 0; j < urb->transfer_buffer_length; ++j) + printk ("%02x ", data[j]); + printk("\n"); +} + static void async_completed(struct urb *urb, struct pt_regs *regs) { struct async *as = (struct async *)urb->context; @@ -296,7 +319,9 @@ static void async_completed(struct urb *urb, struct pt_regs *regs) kill_proc_info_as_uid(as->signr, &sinfo, as->pid, as->uid, as->euid); } - wake_up(&ps->wait); + snoop(&urb->dev->dev, "urb complete\n"); + snoop_urb(urb, as->userurb); + wake_up(&ps->wait); } static void destroy_async (struct dev_state *ps, struct list_head *list) @@ -493,6 +518,23 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, unsig return ret; } +static struct usb_device *usbdev_lookup_minor(int minor) +{ + struct class_device *class_dev; + struct usb_device *dev = NULL; + + down(&usb_device_class->sem); + list_for_each_entry(class_dev, &usb_device_class->children, node) { + if (class_dev->devt == MKDEV(USB_DEVICE_MAJOR, minor)) { + dev = class_dev->class_data; + break; + } + } + up(&usb_device_class->sem); + + return dev; +}; + /* * file operations */ @@ -601,7 +643,7 @@ static int proc_control(struct dev_state *ps, void __user *arg) if (usbfs_snoop) { dev_info(&dev->dev, "control read: data "); for (j = 0; j < i; ++j) - printk ("%02x ", (unsigned char)(tbuf)[j]); + printk("%02x ", (unsigned char)(tbuf)[j]); printk("\n"); } if (copy_to_user(ctrl.data, tbuf, i)) { @@ -624,7 +666,7 @@ static int proc_control(struct dev_state *ps, void __user *arg) if (usbfs_snoop) { dev_info(&dev->dev, "control write: data: "); for (j = 0; j < ctrl.wLength; ++j) - printk ("%02x ", (unsigned char)(tbuf)[j]); + printk("%02x ", (unsigned char)(tbuf)[j]); printk("\n"); } usb_unlock_device(dev); @@ -649,7 +691,7 @@ static int proc_bulk(struct dev_state *ps, void __user *arg) unsigned int tmo, len1, pipe; int len2; unsigned char *tbuf; - int i, ret; + int i, j, ret; if (copy_from_user(&bulk, arg, sizeof(bulk))) return -EFAULT; @@ -674,10 +716,18 @@ static int proc_bulk(struct dev_state *ps, void __user *arg) kfree(tbuf); return -EINVAL; } + snoop(&dev->dev, "bulk read: len=0x%02x timeout=%04d\n", + bulk.len, bulk.timeout); usb_unlock_device(dev); i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo); usb_lock_device(dev); if (!i && len2) { + if (usbfs_snoop) { + dev_info(&dev->dev, "bulk read: data "); + for (j = 0; j < len2; ++j) + printk("%02x ", (unsigned char)(tbuf)[j]); + printk("\n"); + } if (copy_to_user(bulk.data, tbuf, len2)) { kfree(tbuf); return -EFAULT; @@ -690,6 +740,14 @@ static int proc_bulk(struct dev_state *ps, void __user *arg) return -EFAULT; } } + snoop(&dev->dev, "bulk write: len=0x%02x timeout=%04d\n", + bulk.len, bulk.timeout); + if (usbfs_snoop) { + dev_info(&dev->dev, "bulk write: data: "); + for (j = 0; j < len1; ++j) + printk("%02x ", (unsigned char)(tbuf)[j]); + printk("\n"); + } usb_unlock_device(dev); i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo); usb_lock_device(dev); @@ -835,7 +893,6 @@ static int proc_setconfig(struct dev_state *ps, void __user *arg) return status; } - static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, struct usbdevfs_iso_packet_desc __user *iso_frame_desc, void __user *arg) @@ -896,6 +953,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, kfree(dr); return -EFAULT; } + snoop(&ps->dev->dev, "control urb\n"); break; case USBDEVFS_URB_TYPE_BULK: @@ -910,6 +968,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, return -EINVAL; if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length)) return -EFAULT; + snoop(&ps->dev->dev, "bulk urb\n"); break; case USBDEVFS_URB_TYPE_ISO: @@ -939,6 +998,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, return -EINVAL; } uurb->buffer_length = totlen; + snoop(&ps->dev->dev, "iso urb\n"); break; case USBDEVFS_URB_TYPE_INTERRUPT: @@ -954,6 +1014,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, return -EINVAL; if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length)) return -EFAULT; + snoop(&ps->dev->dev, "interrupt urb\n"); break; default: @@ -1003,6 +1064,8 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, return -EFAULT; } } + snoop(&as->urb->dev->dev, "submit urb\n"); + snoop_urb(as->urb, as->userurb); async_newpending(as); if ((ret = usb_submit_urb(as->urb, GFP_KERNEL))) { dev_printk(KERN_DEBUG, &ps->dev->dev, "usbfs: usb_submit_urb returned %d\n", ret); @@ -1238,23 +1301,20 @@ static int proc_releaseinterface(struct dev_state *ps, void __user *arg) return 0; } -static int proc_ioctl (struct dev_state *ps, void __user *arg) +static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl) { - struct usbdevfs_ioctl ctrl; int size; void *buf = NULL; int retval = 0; struct usb_interface *intf = NULL; struct usb_driver *driver = NULL; - /* get input parameters and alloc buffer */ - if (copy_from_user(&ctrl, arg, sizeof (ctrl))) - return -EFAULT; - if ((size = _IOC_SIZE (ctrl.ioctl_code)) > 0) { + /* alloc buffer */ + if ((size = _IOC_SIZE (ctl->ioctl_code)) > 0) { if ((buf = kmalloc (size, GFP_KERNEL)) == NULL) return -ENOMEM; - if ((_IOC_DIR(ctrl.ioctl_code) & _IOC_WRITE)) { - if (copy_from_user (buf, ctrl.data, size)) { + if ((_IOC_DIR(ctl->ioctl_code) & _IOC_WRITE)) { + if (copy_from_user (buf, ctl->data, size)) { kfree(buf); return -EFAULT; } @@ -1270,9 +1330,9 @@ static int proc_ioctl (struct dev_state *ps, void __user *arg) if (ps->dev->state != USB_STATE_CONFIGURED) retval = -EHOSTUNREACH; - else if (!(intf = usb_ifnum_to_if (ps->dev, ctrl.ifno))) + else if (!(intf = usb_ifnum_to_if (ps->dev, ctl->ifno))) retval = -EINVAL; - else switch (ctrl.ioctl_code) { + else switch (ctl->ioctl_code) { /* disconnect kernel driver from interface */ case USBDEVFS_DISCONNECT: @@ -1304,7 +1364,7 @@ static int proc_ioctl (struct dev_state *ps, void __user *arg) if (driver == NULL || driver->ioctl == NULL) { retval = -ENOTTY; } else { - retval = driver->ioctl (intf, ctrl.ioctl_code, buf); + retval = driver->ioctl (intf, ctl->ioctl_code, buf); if (retval == -ENOIOCTLCMD) retval = -ENOTTY; } @@ -1313,15 +1373,42 @@ static int proc_ioctl (struct dev_state *ps, void __user *arg) /* cleanup and return */ if (retval >= 0 - && (_IOC_DIR (ctrl.ioctl_code) & _IOC_READ) != 0 + && (_IOC_DIR (ctl->ioctl_code) & _IOC_READ) != 0 && size > 0 - && copy_to_user (ctrl.data, buf, size) != 0) + && copy_to_user (ctl->data, buf, size) != 0) retval = -EFAULT; kfree(buf); return retval; } +static int proc_ioctl_default(struct dev_state *ps, void __user *arg) +{ + struct usbdevfs_ioctl ctrl; + + if (copy_from_user(&ctrl, arg, sizeof (ctrl))) + return -EFAULT; + return proc_ioctl(ps, &ctrl); +} + +#ifdef CONFIG_COMPAT +static int proc_ioctl_compat(struct dev_state *ps, void __user *arg) +{ + struct usbdevfs_ioctl32 __user *uioc; + struct usbdevfs_ioctl ctrl; + u32 udata; + + uioc = compat_ptr(arg); + if (get_user(ctrl.ifno, &uioc->ifno) || + get_user(ctrl.ioctl_code, &uioc->ioctl_code) || + __get_user(udata, &uioc->data)) + return -EFAULT; + ctrl.data = compat_ptr(udata); + + return proc_ioctl(ps, &ctrl); +} +#endif + /* * NOTE: All requests here that have interface numbers as parameters * are assuming that somehow the configuration has been prevented from @@ -1422,6 +1509,10 @@ static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd ret = proc_reapurbnonblock_compat(ps, p); break; + case USBDEVFS_IOCTL32: + snoop(&dev->dev, "%s: IOCTL\n", __FUNCTION__); + ret = proc_ioctl_compat(ps, p); + break; #endif case USBDEVFS_DISCARDURB: @@ -1456,7 +1547,7 @@ static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd case USBDEVFS_IOCTL: snoop(&dev->dev, "%s: IOCTL\n", __FUNCTION__); - ret = proc_ioctl(ps, p); + ret = proc_ioctl_default(ps, p); break; } usb_unlock_device(dev); @@ -1488,39 +1579,40 @@ struct file_operations usbfs_device_file_operations = { .release = usbdev_release, }; -struct usb_device *usbdev_lookup_minor(int minor) -{ - struct class_device *class_dev; - struct usb_device *dev = NULL; - - down(&usb_device_class->sem); - list_for_each_entry(class_dev, &usb_device_class->children, node) { - if (class_dev->devt == MKDEV(USB_DEVICE_MAJOR, minor)) { - dev = class_dev->class_data; - break; - } - } - up(&usb_device_class->sem); - - return dev; -}; - -void usbdev_add(struct usb_device *dev) +static void usbdev_add(struct usb_device *dev) { int minor = ((dev->bus->busnum-1) * 128) + (dev->devnum-1); - dev->class_dev = class_device_create(usb_device_class, + dev->class_dev = class_device_create(usb_device_class, NULL, MKDEV(USB_DEVICE_MAJOR, minor), &dev->dev, "usbdev%d.%d", dev->bus->busnum, dev->devnum); dev->class_dev->class_data = dev; } -void usbdev_remove(struct usb_device *dev) +static void usbdev_remove(struct usb_device *dev) { class_device_unregister(dev->class_dev); } +static int usbdev_notify(struct notifier_block *self, unsigned long action, + void *dev) +{ + switch (action) { + case USB_DEVICE_ADD: + usbdev_add(dev); + break; + case USB_DEVICE_REMOVE: + usbdev_remove(dev); + break; + } + return NOTIFY_OK; +} + +static struct notifier_block usbdev_nb = { + .notifier_call = usbdev_notify, +}; + static struct cdev usb_device_cdev = { .kobj = {.name = "usb_device", }, .owner = THIS_MODULE, @@ -1540,24 +1632,32 @@ int __init usbdev_init(void) retval = cdev_add(&usb_device_cdev, USB_DEVICE_DEV, USB_DEVICE_MAX); if (retval) { err("unable to get usb_device major %d", USB_DEVICE_MAJOR); - unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX); - goto out; + goto error_cdev; } usb_device_class = class_create(THIS_MODULE, "usb_device"); if (IS_ERR(usb_device_class)) { err("unable to register usb_device class"); retval = PTR_ERR(usb_device_class); - usb_device_class = NULL; - cdev_del(&usb_device_cdev); - unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX); + goto error_class; } + usb_register_notify(&usbdev_nb); + out: return retval; + +error_class: + usb_device_class = NULL; + cdev_del(&usb_device_cdev); + +error_cdev: + unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX); + goto out; } void usbdev_cleanup(void) { + usb_unregister_notify(&usbdev_nb); class_destroy(usb_device_class); cdev_del(&usb_device_cdev); unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX); diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c index 65ca131cc44c..e695308095ae 100644 --- a/drivers/usb/core/file.c +++ b/drivers/usb/core/file.c @@ -17,7 +17,6 @@ #include <linux/config.h> #include <linux/module.h> -#include <linux/devfs_fs_kernel.h> #include <linux/spinlock.h> #include <linux/errno.h> @@ -88,8 +87,6 @@ int usb_major_init(void) goto out; } - devfs_mk_dir("usb"); - out: return error; } @@ -97,7 +94,6 @@ out: void usb_major_cleanup(void) { class_destroy(usb_class); - devfs_remove("usb"); unregister_chrdev(USB_MAJOR, "usb"); } @@ -112,8 +108,7 @@ void usb_major_cleanup(void) * enabled, the minor number will be based on the next available free minor, * starting at the class_driver->minor_base. * - * This function also creates the devfs file for the usb device, if devfs - * is enabled, and creates a usb class device in the sysfs tree. + * This function also creates a usb class device in the sysfs tree. * * usb_deregister_dev() must be called when the driver is done with * the minor numbers given out by this function. @@ -162,22 +157,20 @@ int usb_register_dev(struct usb_interface *intf, intf->minor = minor; - /* handle the devfs registration */ - snprintf(name, BUS_ID_SIZE, class_driver->name, minor - minor_base); - devfs_mk_cdev(MKDEV(USB_MAJOR, minor), class_driver->mode, name); - /* create a usb class device for this usb interface */ + snprintf(name, BUS_ID_SIZE, class_driver->name, minor - minor_base); temp = strrchr(name, '/'); if (temp && (temp[1] != 0x00)) ++temp; else temp = name; - intf->class_dev = class_device_create(usb_class, MKDEV(USB_MAJOR, minor), &intf->dev, "%s", temp); + intf->class_dev = class_device_create(usb_class, NULL, + MKDEV(USB_MAJOR, minor), + &intf->dev, "%s", temp); if (IS_ERR(intf->class_dev)) { spin_lock (&minor_lock); usb_minors[intf->minor] = NULL; spin_unlock (&minor_lock); - devfs_remove (name); retval = PTR_ERR(intf->class_dev); } exit: @@ -195,9 +188,8 @@ EXPORT_SYMBOL(usb_register_dev); * call to usb_register_dev() (usually when the device is disconnected * from the system.) * - * This function also cleans up the devfs file for the usb device, if devfs - * is enabled, and removes the usb class device from the sysfs tree. - * + * This function also removes the usb class device from the sysfs tree. + * * This should be called by all drivers that use the USB major number. */ void usb_deregister_dev(struct usb_interface *intf, @@ -220,7 +212,6 @@ void usb_deregister_dev(struct usb_interface *intf, spin_unlock (&minor_lock); snprintf(name, BUS_ID_SIZE, class_driver->name, intf->minor - minor_base); - devfs_remove (name); class_device_destroy(usb_class, MKDEV(USB_MAJOR, intf->minor)); intf->class_dev = NULL; intf->minor = -1; diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index 6385d1a99b60..84d9e69329bb 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -30,6 +30,8 @@ #include <asm/io.h> #include <asm/irq.h> #include <linux/usb.h> + +#include "usb.h" #include "hcd.h" @@ -197,6 +199,26 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message) hcd = pci_get_drvdata(dev); + /* Root hub suspend should have stopped all downstream traffic, + * and all bus master traffic. And done so for both the interface + * and the stub usb_device (which we check here). But maybe it + * didn't; writing sysfs power/state files ignores such rules... + * + * We must ignore the FREEZE vs SUSPEND distinction here, because + * otherwise the swsusp will save (and restore) garbage state. + */ + if (hcd->self.root_hub->dev.power.power_state.event == PM_EVENT_ON) + return -EBUSY; + + if (hcd->driver->suspend) { + retval = hcd->driver->suspend(hcd, message); + if (retval) { + dev_dbg (&dev->dev, "PCI pre-suspend fail, %d\n", + retval); + goto done; + } + } + /* FIXME until the generic PM interfaces change a lot more, this * can't use PCI D1 and D2 states. For example, the confusion * between messages and states will need to vanish, and messages @@ -215,31 +237,13 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message) */ has_pci_pm = pci_find_capability(dev, PCI_CAP_ID_PM); - switch (hcd->state) { - - /* entry if root hub wasn't yet suspended ... from sysfs, - * without autosuspend, or if USB_SUSPEND isn't configured. + /* Downstream ports from this root hub should already be quiesced, so + * there will be no DMA activity. Now we can shut down the upstream + * link (except maybe for PME# resume signaling) and enter some PCI + * low power state, if the hardware allows. */ - case HC_STATE_RUNNING: - hcd->state = HC_STATE_QUIESCING; - retval = hcd->driver->suspend (hcd, message); - if (retval) { - dev_dbg (hcd->self.controller, - "suspend fail, retval %d\n", - retval); - break; - } - hcd->state = HC_STATE_SUSPENDED; - /* FALLTHROUGH */ + if (hcd->state == HC_STATE_SUSPENDED) { - /* entry with CONFIG_USB_SUSPEND, or hcds that autosuspend: the - * controller and/or root hub will already have been suspended, - * but it won't be ready for a PCI resume call. - * - * FIXME only CONFIG_USB_SUSPEND guarantees hub_suspend() will - * have been called, otherwise root hub timers still run ... - */ - case HC_STATE_SUSPENDED: /* no DMA or IRQs except when HC is active */ if (dev->current_state == PCI_D0) { pci_save_state (dev); @@ -248,7 +252,7 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message) if (!has_pci_pm) { dev_dbg (hcd->self.controller, "--> PCI D0/legacy\n"); - break; + goto done; } /* NOTE: dev->current_state becomes nonzero only here, and @@ -259,28 +263,29 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message) retval = pci_set_power_state (dev, PCI_D3hot); if (retval == 0) { dev_dbg (hcd->self.controller, "--> PCI D3\n"); - retval = pci_enable_wake (dev, PCI_D3hot, hcd->remote_wakeup); - if (retval) - break; - retval = pci_enable_wake (dev, PCI_D3cold, hcd->remote_wakeup); - } else if (retval < 0) { + + /* Ignore these return values. We rely on pci code to + * reject requests the hardware can't implement, rather + * than coding the same thing. + */ + (void) pci_enable_wake (dev, PCI_D3hot, hcd->remote_wakeup); + (void) pci_enable_wake (dev, PCI_D3cold, hcd->remote_wakeup); + } else { dev_dbg (&dev->dev, "PCI D3 suspend fail, %d\n", retval); (void) usb_hcd_pci_resume (dev); - break; } - break; - default: + + } else { dev_dbg (hcd->self.controller, "hcd state %d; not suspended\n", hcd->state); WARN_ON(1); retval = -EINVAL; - break; } - /* update power_state **ONLY** to make sysfs happier */ +done: if (retval == 0) - dev->dev.power.power_state = message; + dev->dev.power.power_state = PMSG_SUSPEND; return retval; } EXPORT_SYMBOL (usb_hcd_pci_suspend); @@ -336,20 +341,9 @@ int usb_hcd_pci_resume (struct pci_dev *dev) dev->current_state); } #endif - retval = pci_enable_wake (dev, dev->current_state, 0); - if (retval) { - dev_err(hcd->self.controller, - "can't enable_wake to %d, %d!\n", - dev->current_state, retval); - return retval; - } - retval = pci_enable_wake (dev, PCI_D3cold, 0); - if (retval) { - dev_err(hcd->self.controller, - "can't enable_wake to %d, %d!\n", - PCI_D3cold, retval); - return retval; - } + /* yes, ignore these results too... */ + (void) pci_enable_wake (dev, dev->current_state, 0); + (void) pci_enable_wake (dev, PCI_D3cold, 0); } else { /* Same basic cases: clean (powered/not), dirty */ dev_dbg(hcd->self.controller, "PCI legacy resume\n"); @@ -371,17 +365,17 @@ int usb_hcd_pci_resume (struct pci_dev *dev) dev->dev.power.power_state = PMSG_ON; - hcd->state = HC_STATE_RESUMING; hcd->saw_irq = 0; - retval = hcd->driver->resume (hcd); - if (!HC_IS_RUNNING (hcd->state)) { - dev_dbg (hcd->self.controller, - "resume fail, retval %d\n", retval); - usb_hc_died (hcd); + if (hcd->driver->resume) { + retval = hcd->driver->resume(hcd); + if (retval) { + dev_err (hcd->self.controller, + "PCI post-resume error %d!\n", retval); + usb_hc_died (hcd); + } } - retval = pci_enable_device(dev); return retval; } EXPORT_SYMBOL (usb_hcd_pci_resume); diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 1017a97a418b..6c7ca5b08cd6 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -130,7 +130,7 @@ static const u8 usb2_rh_dev_descriptor [18] = { 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ 0x00, /* __u8 bDeviceSubClass; */ 0x01, /* __u8 bDeviceProtocol; [ usb 2.0 single TT ]*/ - 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */ + 0x40, /* __u8 bMaxPacketSize0; 64 Bytes */ 0x00, 0x00, /* __le16 idVendor; */ 0x00, 0x00, /* __le16 idProduct; */ @@ -153,7 +153,7 @@ static const u8 usb11_rh_dev_descriptor [18] = { 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ 0x00, /* __u8 bDeviceSubClass; */ 0x00, /* __u8 bDeviceProtocol; [ low/full speeds only ] */ - 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */ + 0x40, /* __u8 bMaxPacketSize0; 64 Bytes */ 0x00, 0x00, /* __le16 idVendor; */ 0x00, 0x00, /* __le16 idProduct; */ @@ -458,22 +458,18 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) default: /* non-generic request */ - if (HC_IS_SUSPENDED (hcd->state)) - status = -EAGAIN; - else { - switch (typeReq) { - case GetHubStatus: - case GetPortStatus: - len = 4; - break; - case GetHubDescriptor: - len = sizeof (struct usb_hub_descriptor); - break; - } - status = hcd->driver->hub_control (hcd, - typeReq, wValue, wIndex, - tbuf, wLength); + switch (typeReq) { + case GetHubStatus: + case GetPortStatus: + len = 4; + break; + case GetHubDescriptor: + len = sizeof (struct usb_hub_descriptor); + break; } + status = hcd->driver->hub_control (hcd, + typeReq, wValue, wIndex, + tbuf, wLength); break; error: /* "protocol stall" on error */ @@ -487,7 +483,7 @@ error: "CTRL: TypeReq=0x%x val=0x%x " "idx=0x%x len=%d ==> %d\n", typeReq, wValue, wIndex, - wLength, urb->status); + wLength, status); } } if (len) { @@ -748,10 +744,9 @@ struct usb_bus *usb_alloc_bus (struct usb_operations *op) { struct usb_bus *bus; - bus = kmalloc (sizeof *bus, GFP_KERNEL); + bus = kzalloc (sizeof *bus, GFP_KERNEL); if (!bus) return NULL; - memset(bus, 0, sizeof(struct usb_bus)); usb_bus_init (bus); bus->op = op; return bus; @@ -782,7 +777,8 @@ static int usb_register_bus(struct usb_bus *bus) return -E2BIG; } - bus->class_dev = class_device_create(usb_host_class, MKDEV(0,0), bus->controller, "usb_host%d", busnum); + bus->class_dev = class_device_create(usb_host_class, NULL, MKDEV(0,0), + bus->controller, "usb_host%d", busnum); if (IS_ERR(bus->class_dev)) { clear_bit(busnum, busmap.busmap); up(&usb_bus_list_lock); @@ -795,8 +791,7 @@ static int usb_register_bus(struct usb_bus *bus) list_add (&bus->bus_list, &usb_bus_list); up (&usb_bus_list_lock); - usbfs_add_bus (bus); - usbmon_notify_bus_add (bus); + usb_notify_add_bus(bus); dev_info (bus->controller, "new USB bus registered, assigned bus number %d\n", bus->busnum); return 0; @@ -823,8 +818,7 @@ static void usb_deregister_bus (struct usb_bus *bus) list_del (&bus->bus_list); up (&usb_bus_list_lock); - usbmon_notify_bus_remove (bus); - usbfs_remove_bus (bus); + usb_notify_remove_bus(bus); clear_bit (bus->busnum, busmap.busmap); @@ -1112,7 +1106,7 @@ static void urb_unlink (struct urb *urb) * expects usb_submit_urb() to have sanity checked and conditioned all * inputs in the urb */ -static int hcd_submit_urb (struct urb *urb, unsigned mem_flags) +static int hcd_submit_urb (struct urb *urb, gfp_t mem_flags) { int status; struct usb_hcd *hcd = urb->dev->bus->hcpriv; @@ -1142,10 +1136,20 @@ static int hcd_submit_urb (struct urb *urb, unsigned mem_flags) else switch (hcd->state) { case HC_STATE_RUNNING: case HC_STATE_RESUMING: +doit: usb_get_dev (urb->dev); list_add_tail (&urb->urb_list, &ep->urb_list); status = 0; break; + case HC_STATE_SUSPENDED: + /* HC upstream links (register access, wakeup signaling) can work + * even when the downstream links (and DMA etc) are quiesced; let + * usbcore talk to the root hub. + */ + if (hcd->self.controller->power.power_state.event == PM_EVENT_ON + && urb->dev->parent == NULL) + goto doit; + /* FALL THROUGH */ default: status = -ESHUTDOWN; break; @@ -1293,12 +1297,6 @@ static int hcd_unlink_urb (struct urb *urb, int status) goto done; } - /* running ~= hc unlink handshake works (irq, timer, etc) - * halted ~= no unlink handshake is needed - * suspended, resuming == should never happen - */ - WARN_ON (!HC_IS_RUNNING (hcd->state) && hcd->state != HC_STATE_HALT); - /* insist the urb is still queued */ list_for_each(tmp, &ep->urb_list) { if (tmp == &urb->urb_list) @@ -1430,28 +1428,92 @@ rescan: /*-------------------------------------------------------------------------*/ -#ifdef CONFIG_USB_SUSPEND +#ifdef CONFIG_PM -static int hcd_hub_suspend (struct usb_bus *bus) +int hcd_bus_suspend (struct usb_bus *bus) { struct usb_hcd *hcd; + int status; hcd = container_of (bus, struct usb_hcd, self); - if (hcd->driver->hub_suspend) - return hcd->driver->hub_suspend (hcd); - return 0; + if (!hcd->driver->bus_suspend) + return -ENOENT; + hcd->state = HC_STATE_QUIESCING; + status = hcd->driver->bus_suspend (hcd); + if (status == 0) + hcd->state = HC_STATE_SUSPENDED; + else + dev_dbg(&bus->root_hub->dev, "%s fail, err %d\n", + "suspend", status); + return status; } -static int hcd_hub_resume (struct usb_bus *bus) +int hcd_bus_resume (struct usb_bus *bus) { struct usb_hcd *hcd; + int status; hcd = container_of (bus, struct usb_hcd, self); - if (hcd->driver->hub_resume) - return hcd->driver->hub_resume (hcd); - return 0; + if (!hcd->driver->bus_resume) + return -ENOENT; + if (hcd->state == HC_STATE_RUNNING) + return 0; + hcd->state = HC_STATE_RESUMING; + status = hcd->driver->bus_resume (hcd); + if (status == 0) + hcd->state = HC_STATE_RUNNING; + else { + dev_dbg(&bus->root_hub->dev, "%s fail, err %d\n", + "resume", status); + usb_hc_died(hcd); + } + return status; } +/* + * usb_hcd_suspend_root_hub - HCD autosuspends downstream ports + * @hcd: host controller for this root hub + * + * This call arranges that usb_hcd_resume_root_hub() is safe to call later; + * that the HCD's root hub polling is deactivated; and that the root's hub + * driver is suspended. HCDs may call this to autosuspend when their root + * hub's downstream ports are all inactive: unpowered, disconnected, + * disabled, or suspended. + * + * The HCD will autoresume on device connect change detection (using SRP + * or a D+/D- pullup). The HCD also autoresumes on remote wakeup signaling + * from any ports that are suspended (if that is enabled). In most cases, + * overcurrent signaling (on powered ports) will also start autoresume. + * + * Always called with IRQs blocked. + */ +void usb_hcd_suspend_root_hub (struct usb_hcd *hcd) +{ + struct urb *urb; + + spin_lock (&hcd_root_hub_lock); + usb_suspend_root_hub (hcd->self.root_hub); + + /* force status urb to complete/unlink while suspended */ + if (hcd->status_urb) { + urb = hcd->status_urb; + urb->status = -ECONNRESET; + urb->hcpriv = NULL; + urb->actual_length = 0; + + del_timer (&hcd->rh_timer); + hcd->poll_pending = 0; + hcd->status_urb = NULL; + } else + urb = NULL; + spin_unlock (&hcd_root_hub_lock); + hcd->state = HC_STATE_SUSPENDED; + + if (urb) + usb_hcd_giveback_urb (hcd, urb, NULL); +} +EXPORT_SYMBOL_GPL(usb_hcd_suspend_root_hub); + /** * usb_hcd_resume_root_hub - called by HCD to resume its root hub * @hcd: host controller for this root hub @@ -1459,7 +1521,7 @@ static int hcd_hub_resume (struct usb_bus *bus) * The USB host controller calls this function when its root hub is * suspended (with the remote wakeup feature enabled) and a remote * wakeup request is received. It queues a request for khubd to - * resume the root hub. + * resume the root hub (that is, manage its downstream ports again). */ void usb_hcd_resume_root_hub (struct usb_hcd *hcd) { @@ -1470,13 +1532,9 @@ void usb_hcd_resume_root_hub (struct usb_hcd *hcd) usb_resume_root_hub (hcd->self.root_hub); spin_unlock_irqrestore (&hcd_root_hub_lock, flags); } +EXPORT_SYMBOL_GPL(usb_hcd_resume_root_hub); -#else -void usb_hcd_resume_root_hub (struct usb_hcd *hcd) -{ -} #endif -EXPORT_SYMBOL_GPL(usb_hcd_resume_root_hub); /*-------------------------------------------------------------------------*/ @@ -1529,10 +1587,6 @@ static struct usb_operations usb_hcd_operations = { .buffer_alloc = hcd_buffer_alloc, .buffer_free = hcd_buffer_free, .disable = hcd_endpoint_disable, -#ifdef CONFIG_USB_SUSPEND - .hub_suspend = hcd_hub_suspend, - .hub_resume = hcd_hub_resume, -#endif }; /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index ac451fa7e4d2..24a62a2ff86d 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -142,22 +142,18 @@ struct hcd_timeout { /* timeouts we allocate */ struct usb_operations { int (*get_frame_number) (struct usb_device *usb_dev); - int (*submit_urb) (struct urb *urb, unsigned mem_flags); + int (*submit_urb) (struct urb *urb, gfp_t mem_flags); int (*unlink_urb) (struct urb *urb, int status); /* allocate dma-consistent buffer for URB_DMA_NOMAPPING */ void *(*buffer_alloc)(struct usb_bus *bus, size_t size, - unsigned mem_flags, + gfp_t mem_flags, dma_addr_t *dma); void (*buffer_free)(struct usb_bus *bus, size_t size, void *addr, dma_addr_t dma); void (*disable)(struct usb_device *udev, struct usb_host_endpoint *ep); - - /* global suspend/resume of bus */ - int (*hub_suspend)(struct usb_bus *); - int (*hub_resume)(struct usb_bus *); }; /* each driver provides one of these, and hardware init support */ @@ -182,12 +178,12 @@ struct hc_driver { int (*start) (struct usb_hcd *hcd); /* NOTE: these suspend/resume calls relate to the HC as - * a whole, not just the root hub; they're for bus glue. + * a whole, not just the root hub; they're for PCI bus glue. */ - /* called after all devices were suspended */ + /* called after suspending the hub, before entering D3 etc */ int (*suspend) (struct usb_hcd *hcd, pm_message_t message); - /* called before any devices get resumed */ + /* called after entering D0 (etc), before resuming the hub */ int (*resume) (struct usb_hcd *hcd); /* cleanly make HCD stop writing memory and doing I/O */ @@ -200,7 +196,7 @@ struct hc_driver { int (*urb_enqueue) (struct usb_hcd *hcd, struct usb_host_endpoint *ep, struct urb *urb, - unsigned mem_flags); + gfp_t mem_flags); int (*urb_dequeue) (struct usb_hcd *hcd, struct urb *urb); /* hw synch, freeing endpoint resources that urb_dequeue can't */ @@ -212,8 +208,8 @@ struct hc_driver { int (*hub_control) (struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength); - int (*hub_suspend)(struct usb_hcd *); - int (*hub_resume)(struct usb_hcd *); + int (*bus_suspend)(struct usb_hcd *); + int (*bus_resume)(struct usb_hcd *); int (*start_port_reset)(struct usb_hcd *, unsigned port_num); void (*hub_irq_enable)(struct usb_hcd *); /* Needed only if port-change IRQs are level-triggered */ @@ -247,7 +243,7 @@ int hcd_buffer_create (struct usb_hcd *hcd); void hcd_buffer_destroy (struct usb_hcd *hcd); void *hcd_buffer_alloc (struct usb_bus *bus, size_t size, - unsigned mem_flags, dma_addr_t *dma); + gfp_t mem_flags, dma_addr_t *dma); void hcd_buffer_free (struct usb_bus *bus, size_t size, void *addr, dma_addr_t dma); @@ -355,8 +351,6 @@ extern long usb_calc_bus_time (int speed, int is_input, extern struct usb_bus *usb_alloc_bus (struct usb_operations *); -extern void usb_hcd_resume_root_hub (struct usb_hcd *hcd); - extern void usb_set_device_state(struct usb_device *udev, enum usb_device_state new_state); @@ -378,6 +372,33 @@ extern int usb_find_interface_driver (struct usb_device *dev, #define usb_endpoint_out(ep_dir) (!((ep_dir) & USB_DIR_IN)) +#ifdef CONFIG_PM +extern void usb_hcd_suspend_root_hub (struct usb_hcd *hcd); +extern void usb_hcd_resume_root_hub (struct usb_hcd *hcd); +extern int hcd_bus_suspend (struct usb_bus *bus); +extern int hcd_bus_resume (struct usb_bus *bus); +#else +static inline void usb_hcd_suspend_root_hub(struct usb_hcd *hcd) +{ + return; +} + +static inline void usb_hcd_resume_root_hub(struct usb_hcd *hcd) +{ + return; +} + +static inline int hcd_bus_suspend(struct usb_bus *bus) +{ + return 0; +} + +static inline int hcd_bus_resume (struct usb_bus *bus) +{ + return 0; +} +#endif /* CONFIG_PM */ + /* * USB device fs stuff */ @@ -388,23 +409,13 @@ extern int usb_find_interface_driver (struct usb_device *dev, * these are expected to be called from the USB core/hub thread * with the kernel lock held */ -extern void usbfs_add_bus(struct usb_bus *bus); -extern void usbfs_remove_bus(struct usb_bus *bus); -extern void usbfs_add_device(struct usb_device *dev); -extern void usbfs_remove_device(struct usb_device *dev); extern void usbfs_update_special (void); - extern int usbfs_init(void); extern void usbfs_cleanup(void); #else /* CONFIG_USB_DEVICEFS */ -static inline void usbfs_add_bus(struct usb_bus *bus) {} -static inline void usbfs_remove_bus(struct usb_bus *bus) {} -static inline void usbfs_add_device(struct usb_device *dev) {} -static inline void usbfs_remove_device(struct usb_device *dev) {} static inline void usbfs_update_special (void) {} - static inline int usbfs_init(void) { return 0; } static inline void usbfs_cleanup(void) { } @@ -419,8 +430,6 @@ struct usb_mon_operations { void (*urb_submit_error)(struct usb_bus *bus, struct urb *urb, int err); void (*urb_complete)(struct usb_bus *bus, struct urb *urb); /* void (*urb_unlink)(struct usb_bus *bus, struct urb *urb); */ - void (*bus_add)(struct usb_bus *bus); - void (*bus_remove)(struct usb_bus *bus); }; extern struct usb_mon_operations *mon_ops; @@ -443,18 +452,6 @@ static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb) if (bus->monitored) (*mon_ops->urb_complete)(bus, urb); } - -static inline void usbmon_notify_bus_add(struct usb_bus *bus) -{ - if (mon_ops) - (*mon_ops->bus_add)(bus); -} - -static inline void usbmon_notify_bus_remove(struct usb_bus *bus) -{ - if (mon_ops) - (*mon_ops->bus_remove)(bus); -} int usb_mon_register(struct usb_mon_operations *ops); void usb_mon_deregister(void); @@ -465,8 +462,6 @@ static inline void usbmon_urb_submit(struct usb_bus *bus, struct urb *urb) {} static inline void usbmon_urb_submit_error(struct usb_bus *bus, struct urb *urb, int error) {} static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb) {} -static inline void usbmon_notify_bus_add(struct usb_bus *bus) {} -static inline void usbmon_notify_bus_remove(struct usb_bus *bus) {} #endif /* CONFIG_USB_MON */ diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index a12cab5314e9..256d9f698715 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -436,9 +436,10 @@ static void hub_power_on(struct usb_hub *hub) { int port1; unsigned pgood_delay = hub->descriptor->bPwrOn2PwrGood * 2; + u16 wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics); /* if hub supports power switching, enable power on each port */ - if ((hub->descriptor->wHubCharacteristics & HUB_CHAR_LPSM) < 2) { + if ((wHubCharacteristics & HUB_CHAR_LPSM) < 2) { dev_dbg(hub->intfdev, "enabling power on all ports\n"); for (port1 = 1; port1 <= hub->descriptor->bNbrPorts; port1++) set_port_feature(hub->hdev, port1, @@ -449,10 +450,18 @@ static void hub_power_on(struct usb_hub *hub) msleep(max(pgood_delay, (unsigned) 100)); } -static void hub_quiesce(struct usb_hub *hub) +static inline void __hub_quiesce(struct usb_hub *hub) { - /* stop khubd and related activity */ + /* (nonblocking) khubd and related activity won't re-trigger */ hub->quiescing = 1; + hub->activating = 0; + hub->resume_root_hub = 0; +} + +static void hub_quiesce(struct usb_hub *hub) +{ + /* (blocking) stop khubd and related activity */ + __hub_quiesce(hub); usb_kill_urb(hub->urb); if (hub->has_indicators) cancel_delayed_work(&hub->leds); @@ -466,6 +475,7 @@ static void hub_activate(struct usb_hub *hub) hub->quiescing = 0; hub->activating = 1; + hub->resume_root_hub = 0; status = usb_submit_urb(hub->urb, GFP_NOIO); if (status < 0) dev_err(hub->intfdev, "activate --> %d\n", status); @@ -516,6 +526,7 @@ static int hub_configure(struct usb_hub *hub, struct usb_device *hdev = hub->hdev; struct device *hub_dev = hub->intfdev; u16 hubstatus, hubchange; + u16 wHubCharacteristics; unsigned int pipe; int maxp, ret; char *message; @@ -561,9 +572,9 @@ static int hub_configure(struct usb_hub *hub, dev_info (hub_dev, "%d port%s detected\n", hdev->maxchild, (hdev->maxchild == 1) ? "" : "s"); - le16_to_cpus(&hub->descriptor->wHubCharacteristics); + wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics); - if (hub->descriptor->wHubCharacteristics & HUB_CHAR_COMPOUND) { + if (wHubCharacteristics & HUB_CHAR_COMPOUND) { int i; char portstr [USB_MAXCHILDREN + 1]; @@ -576,7 +587,7 @@ static int hub_configure(struct usb_hub *hub, } else dev_dbg(hub_dev, "standalone hub\n"); - switch (hub->descriptor->wHubCharacteristics & HUB_CHAR_LPSM) { + switch (wHubCharacteristics & HUB_CHAR_LPSM) { case 0x00: dev_dbg(hub_dev, "ganged power switching\n"); break; @@ -589,7 +600,7 @@ static int hub_configure(struct usb_hub *hub, break; } - switch (hub->descriptor->wHubCharacteristics & HUB_CHAR_OCPM) { + switch (wHubCharacteristics & HUB_CHAR_OCPM) { case 0x00: dev_dbg(hub_dev, "global over-current protection\n"); break; @@ -629,7 +640,7 @@ static int hub_configure(struct usb_hub *hub, } /* Note 8 FS bit times == (8 bits / 12000000 bps) ~= 666ns */ - switch (hub->descriptor->wHubCharacteristics & HUB_CHAR_TTTT) { + switch (wHubCharacteristics & HUB_CHAR_TTTT) { case HUB_TTTT_8_BITS: if (hdev->descriptor.bDeviceProtocol != 0) { hub->tt.think_time = 666; @@ -659,7 +670,7 @@ static int hub_configure(struct usb_hub *hub, } /* probe() zeroes hub->indicator[] */ - if (hub->descriptor->wHubCharacteristics & HUB_CHAR_PORTIND) { + if (wHubCharacteristics & HUB_CHAR_PORTIND) { hub->has_indicators = 1; dev_dbg(hub_dev, "Port indicators are supported\n"); } @@ -704,7 +715,7 @@ static int hub_configure(struct usb_hub *hub, (hubstatus & HUB_STATUS_LOCAL_POWER) ? "lost (inactive)" : "good"); - if ((hub->descriptor->wHubCharacteristics & HUB_CHAR_OCPM) == 0) + if ((wHubCharacteristics & HUB_CHAR_OCPM) == 0) dev_dbg(hub_dev, "%sover-current condition exists\n", (hubstatus & HUB_STATUS_OVERCURRENT) ? "" : "no "); @@ -854,14 +865,12 @@ descriptor_error: /* We found a hub */ dev_info (&intf->dev, "USB hub found\n"); - hub = kmalloc(sizeof(*hub), GFP_KERNEL); + hub = kzalloc(sizeof(*hub), GFP_KERNEL); if (!hub) { dev_dbg (&intf->dev, "couldn't kmalloc hub struct\n"); return -ENOMEM; } - memset(hub, 0, sizeof(*hub)); - INIT_LIST_HEAD(&hub->event_list); hub->intfdev = &intf->dev; hub->hdev = hdev; @@ -1020,9 +1029,15 @@ void usb_set_device_state(struct usb_device *udev, spin_lock_irqsave(&device_state_lock, flags); if (udev->state == USB_STATE_NOTATTACHED) ; /* do nothing */ - else if (new_state != USB_STATE_NOTATTACHED) + else if (new_state != USB_STATE_NOTATTACHED) { udev->state = new_state; - else + if (new_state == USB_STATE_CONFIGURED) + device_init_wakeup(&udev->dev, + (udev->actconfig->desc.bmAttributes + & USB_CONFIG_ATT_WAKEUP)); + else if (new_state != USB_STATE_SUSPENDED) + device_init_wakeup(&udev->dev, 0); + } else recursively_mark_NOTATTACHED(udev); spin_unlock_irqrestore(&device_state_lock, flags); } @@ -1111,14 +1126,14 @@ void usb_disconnect(struct usb_device **pdev) */ usb_disable_device(udev, 0); + usb_notify_remove_device(udev); + /* Free the device number, remove the /proc/bus/usb entry and * the sysfs attributes, and delete the parent's children[] * (or root_hub) pointer. */ dev_dbg (&udev->dev, "unregistering device\n"); release_address(udev); - usbfs_remove_device(udev); - usbdev_remove(udev); usb_remove_sysfs_dev_files(udev); /* Avoid races with recursively_mark_NOTATTACHED() */ @@ -1189,21 +1204,6 @@ static inline void show_string(struct usb_device *udev, char *id, char *string) {} #endif -static void get_string(struct usb_device *udev, char **string, int index) -{ - char *buf; - - if (!index) - return; - buf = kmalloc(256, GFP_KERNEL); - if (!buf) - return; - if (usb_string(udev, index, buf, 256) > 0) - *string = buf; - else - kfree(buf); -} - #ifdef CONFIG_USB_OTG #include "otg_whitelist.h" @@ -1242,9 +1242,10 @@ int usb_new_device(struct usb_device *udev) } /* read the standard strings and cache them if present */ - get_string(udev, &udev->product, udev->descriptor.iProduct); - get_string(udev, &udev->manufacturer, udev->descriptor.iManufacturer); - get_string(udev, &udev->serial, udev->descriptor.iSerialNumber); + udev->product = usb_cache_string(udev, udev->descriptor.iProduct); + udev->manufacturer = usb_cache_string(udev, + udev->descriptor.iManufacturer); + udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber); /* Tell the world! */ dev_dbg(&udev->dev, "new device strings: Mfr=%d, Product=%d, " @@ -1316,11 +1317,9 @@ int usb_new_device(struct usb_device *udev) * (Includes HNP test device.) */ if (udev->bus->b_hnp_enable || udev->bus->is_b_host) { - static int __usb_suspend_device (struct usb_device *, - int port1, pm_message_t state); - err = __usb_suspend_device(udev, - udev->bus->otg_port, - PMSG_SUSPEND); + static int __usb_suspend_device(struct usb_device *, + int port1); + err = __usb_suspend_device(udev, udev->bus->otg_port); if (err < 0) dev_dbg(&udev->dev, "HNP fail, %d\n", err); } @@ -1356,10 +1355,8 @@ int usb_new_device(struct usb_device *udev) } /* USB device state == configured ... usable */ + usb_notify_add_device(udev); - /* add a /proc/bus/usb entry */ - usbdev_add(udev); - usbfs_add_device(udev); return 0; fail: @@ -1510,7 +1507,7 @@ static void hub_port_logical_disconnect(struct usb_hub *hub, int port1) /* FIXME let caller ask to power down the port: * - some devices won't enumerate without a VBUS power cycle * - SRP saves power that way - * - usb_suspend_device(dev, PMSG_SUSPEND) + * - ... new call, TBD ... * That's easy if this hub can switch power per-port, and * khubd reactivates the port later (timer, SRP, etc). * Powerdown must be optional, because of reset/DFU. @@ -1546,11 +1543,7 @@ static int hub_port_suspend(struct usb_hub *hub, int port1, * NOTE: OTG devices may issue remote wakeup (or SRP) even when * we don't explicitly enable it here. */ - if (udev->actconfig - // && FIXME (remote wakeup enabled on this bus) - // ... currently assuming it's always appropriate - && (udev->actconfig->desc.bmAttributes - & USB_CONFIG_ATT_WAKEUP) != 0) { + if (device_may_wakeup(&udev->dev)) { status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), USB_REQ_SET_FEATURE, USB_RECIP_DEVICE, USB_DEVICE_REMOTE_WAKEUP, 0, @@ -1596,11 +1589,14 @@ static int hub_port_suspend(struct usb_hub *hub, int port1, * Other than re-initializing the hub (plug/unplug, except for root hubs), * Linux (2.6) currently has NO mechanisms to initiate that: no khubd * timer, no SRP, no requests through sysfs. + * + * If CONFIG_USB_SUSPEND isn't enabled, devices only really suspend when + * the root hub for their bus goes into global suspend ... so we don't + * (falsely) update the device power state to say it suspended. */ -static int __usb_suspend_device (struct usb_device *udev, int port1, - pm_message_t state) +static int __usb_suspend_device (struct usb_device *udev, int port1) { - int status; + int status = 0; /* caller owns the udev device lock */ if (port1 < 0) @@ -1611,95 +1607,39 @@ static int __usb_suspend_device (struct usb_device *udev, int port1, return 0; } - /* suspend interface drivers; if this is a hub, it - * suspends the child devices - */ + /* all interfaces must already be suspended */ if (udev->actconfig) { int i; for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) { struct usb_interface *intf; - struct usb_driver *driver; intf = udev->actconfig->interface[i]; - if (state.event <= intf->dev.power.power_state.event) - continue; - if (!intf->dev.driver) - continue; - driver = to_usb_driver(intf->dev.driver); - - if (driver->suspend) { - status = driver->suspend(intf, state); - if (intf->dev.power.power_state.event != state.event - || status) - dev_err(&intf->dev, - "suspend %d fail, code %d\n", - state.event, status); - } - - /* only drivers with suspend() can ever resume(); - * and after power loss, even they won't. - * bus_rescan_devices() can rebind drivers later. - * - * FIXME the PM core self-deadlocks when unbinding - * drivers during suspend/resume ... everything grabs - * dpm_sem (not a spinlock, ugh). we want to unbind, - * since we know every driver's probe/disconnect works - * even for drivers that can't suspend. - */ - if (!driver->suspend || state.event > PM_EVENT_FREEZE) { -#if 1 - dev_warn(&intf->dev, "resume is unsafe!\n"); -#else - down_write(&usb_bus_type.rwsem); - device_release_driver(&intf->dev); - up_write(&usb_bus_type.rwsem); -#endif + if (is_active(intf)) { + dev_dbg(&intf->dev, "nyet suspended\n"); + return -EBUSY; } } } - /* - * FIXME this needs port power off call paths too, to help force - * USB into the "generic" PM model. At least for devices on - * ports that aren't using ganged switching (usually root hubs). - * - * NOTE: SRP-capable links should adopt more aggressive poweroff - * policies (when HNP doesn't apply) once we have mechanisms to - * turn power back on! (Likely not before 2.7...) + /* we only change a device's upstream USB link. + * root hubs have no upstream USB link. */ - if (state.event > PM_EVENT_FREEZE) { - dev_warn(&udev->dev, "no poweroff yet, suspending instead\n"); - } - - /* "global suspend" of the HC-to-USB interface (root hub), or - * "selective suspend" of just one hub-device link. - */ - if (!udev->parent) { - struct usb_bus *bus = udev->bus; - if (bus && bus->op->hub_suspend) { - status = bus->op->hub_suspend (bus); - if (status == 0) { - dev_dbg(&udev->dev, "usb suspend\n"); - usb_set_device_state(udev, - USB_STATE_SUSPENDED); - } - } else - status = -EOPNOTSUPP; - } else + if (udev->parent) status = hub_port_suspend(hdev_to_hub(udev->parent), port1, udev); if (status == 0) - udev->dev.power.power_state = state; + udev->dev.power.power_state = PMSG_SUSPEND; return status; } -/** +#endif + +/* * usb_suspend_device - suspend a usb device * @udev: device that's no longer in active use - * @state: PMSG_SUSPEND to suspend - * Context: must be able to sleep; device not locked + * Context: must be able to sleep; device not locked; pm locks held * * Suspends a USB device that isn't in active use, conserving power. * Devices may wake out of a suspend, if anything important happens, @@ -1707,37 +1647,50 @@ static int __usb_suspend_device (struct usb_device *udev, int port1, * suspend by the host, using usb_resume_device(). It's also routine * to disconnect devices while they are suspended. * + * This only affects the USB hardware for a device; its interfaces + * (and, for hubs, child devices) must already have been suspended. + * * Suspending OTG devices may trigger HNP, if that's been enabled * between a pair of dual-role devices. That will change roles, such * as from A-Host to A-Peripheral or from B-Host back to B-Peripheral. * * Returns 0 on success, else negative errno. */ -int usb_suspend_device(struct usb_device *udev, pm_message_t state) +int usb_suspend_device(struct usb_device *udev) { +#ifdef CONFIG_USB_SUSPEND int port1, status; port1 = locktree(udev); if (port1 < 0) return port1; - status = __usb_suspend_device(udev, port1, state); + status = __usb_suspend_device(udev, port1); usb_unlock_device(udev); return status; +#else + /* NOTE: udev->state unchanged, it's not lying ... */ + udev->dev.power.power_state = PMSG_SUSPEND; + return 0; +#endif } +EXPORT_SYMBOL_GPL(usb_suspend_device); /* + * If the USB "suspend" state is in use (rather than "global suspend"), + * many devices will be individually taken out of suspend state using + * special" resume" signaling. These routines kick in shortly after * hardware resume signaling is finished, either because of selective * resume (by host) or remote wakeup (by device) ... now see what changed * in the tree that's rooted at this device. */ -static int finish_port_resume(struct usb_device *udev) +static int finish_device_resume(struct usb_device *udev) { int status; u16 devstatus; /* caller owns the udev device lock */ - dev_dbg(&udev->dev, "usb resume\n"); + dev_dbg(&udev->dev, "finish resume\n"); /* usb ch9 identifies four variants of SUSPENDED, based on what * state the device resumes to. Linux currently won't see the @@ -1747,7 +1700,6 @@ static int finish_port_resume(struct usb_device *udev) usb_set_device_state(udev, udev->actconfig ? USB_STATE_CONFIGURED : USB_STATE_ADDRESS); - udev->dev.power.power_state = PMSG_ON; /* 10.5.4.5 says be sure devices in the tree are still there. * For now let's assume the device didn't go crazy on resume, @@ -1760,9 +1712,11 @@ static int finish_port_resume(struct usb_device *udev) status); else if (udev->actconfig) { unsigned i; + int (*resume)(struct device *); le16_to_cpus(&devstatus); - if (devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) { + if (devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP) + && udev->parent) { status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), USB_REQ_CLEAR_FEATURE, @@ -1778,33 +1732,11 @@ static int finish_port_resume(struct usb_device *udev) } /* resume interface drivers; if this is a hub, it - * resumes the child devices + * may have a child resume event to deal with soon */ - for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) { - struct usb_interface *intf; - struct usb_driver *driver; - - intf = udev->actconfig->interface[i]; - if (intf->dev.power.power_state.event == PM_EVENT_ON) - continue; - if (!intf->dev.driver) { - /* FIXME maybe force to alt 0 */ - continue; - } - driver = to_usb_driver(intf->dev.driver); - - /* bus_rescan_devices() may rebind drivers */ - if (!driver->resume) - continue; - - /* can we do better than just logging errors? */ - status = driver->resume(intf); - if (intf->dev.power.power_state.event != PM_EVENT_ON - || status) - dev_dbg(&intf->dev, - "resume fail, state %d code %d\n", - intf->dev.power.power_state.event, status); - } + resume = udev->dev.bus->resume; + for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) + (void) resume(&udev->actconfig->interface[i]->dev); status = 0; } else if (udev->devnum <= 0) { @@ -1814,6 +1746,8 @@ static int finish_port_resume(struct usb_device *udev) return status; } +#ifdef CONFIG_USB_SUSPEND + static int hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev) { @@ -1859,7 +1793,7 @@ hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev) /* TRSMRCY = 10 msec */ msleep(10); if (udev) - status = finish_port_resume(udev); + status = finish_device_resume(udev); } } if (status < 0) @@ -1868,12 +1802,12 @@ hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev) return status; } -static int hub_resume (struct usb_interface *intf); +#endif -/** +/* * usb_resume_device - re-activate a suspended usb device * @udev: device to re-activate - * Context: must be able to sleep; device not locked + * Context: must be able to sleep; device not locked; pm locks held * * This will re-activate the suspended device, increasing power usage * while letting drivers communicate again with its endpoints. @@ -1891,35 +1825,22 @@ int usb_resume_device(struct usb_device *udev) if (port1 < 0) return port1; - /* "global resume" of the HC-to-USB interface (root hub), or - * selective resume of one hub-to-device port - */ - if (!udev->parent) { - struct usb_bus *bus = udev->bus; - if (bus && bus->op->hub_resume) { - status = bus->op->hub_resume (bus); +#ifdef CONFIG_USB_SUSPEND + /* selective resume of one downstream hub-to-device port */ + if (udev->parent) { + if (udev->state == USB_STATE_SUSPENDED) { + // NOTE swsusp may bork us, device state being wrong... + // NOTE this fails if parent is also suspended... + status = hub_port_resume(hdev_to_hub(udev->parent), + port1, udev); } else - status = -EOPNOTSUPP; - if (status == 0) { - dev_dbg(&udev->dev, "usb resume\n"); - /* TRSMRCY = 10 msec */ - msleep(10); - usb_set_device_state (udev, USB_STATE_CONFIGURED); - udev->dev.power.power_state = PMSG_ON; - status = hub_resume (udev - ->actconfig->interface[0]); - } - } else if (udev->state == USB_STATE_SUSPENDED) { - // NOTE this fails if parent is also suspended... - status = hub_port_resume(hdev_to_hub(udev->parent), - port1, udev); - } else { - status = 0; - } - if (status < 0) { + status = 0; + } else +#endif + status = finish_device_resume(udev); + if (status < 0) dev_dbg(&udev->dev, "can't resume, status %d\n", status); - } usb_unlock_device(udev); @@ -1936,6 +1857,8 @@ static int remote_wakeup(struct usb_device *udev) { int status = 0; +#ifdef CONFIG_USB_SUSPEND + /* don't repeat RESUME sequence if this device * was already woken up by some other task */ @@ -1944,38 +1867,52 @@ static int remote_wakeup(struct usb_device *udev) dev_dbg(&udev->dev, "RESUME (wakeup)\n"); /* TRSMRCY = 10 msec */ msleep(10); - status = finish_port_resume(udev); + status = finish_device_resume(udev); } up(&udev->serialize); +#endif return status; } -static int hub_suspend(struct usb_interface *intf, pm_message_t state) +static int hub_suspend(struct usb_interface *intf, pm_message_t msg) { struct usb_hub *hub = usb_get_intfdata (intf); struct usb_device *hdev = hub->hdev; unsigned port1; - int status; - /* stop khubd and related activity */ - hub_quiesce(hub); - - /* then suspend every port */ + /* fail if children aren't already suspended */ for (port1 = 1; port1 <= hdev->maxchild; port1++) { struct usb_device *udev; udev = hdev->children [port1-1]; - if (!udev) - continue; - down(&udev->serialize); - status = __usb_suspend_device(udev, port1, state); - up(&udev->serialize); - if (status < 0) - dev_dbg(&intf->dev, "suspend port %d --> %d\n", - port1, status); + if (udev && (udev->dev.power.power_state.event + == PM_EVENT_ON +#ifdef CONFIG_USB_SUSPEND + || udev->state != USB_STATE_SUSPENDED +#endif + )) { + dev_dbg(&intf->dev, "port %d nyet suspended\n", port1); + return -EBUSY; + } } - intf->dev.power.power_state = state; + /* "global suspend" of the downstream HC-to-USB interface */ + if (!hdev->parent) { + struct usb_bus *bus = hdev->bus; + if (bus) { + int status = hcd_bus_suspend (bus); + + if (status != 0) { + dev_dbg(&hdev->dev, "'global' suspend %d\n", + status); + return status; + } + } else + return -EOPNOTSUPP; + } + + /* stop khubd and related activity */ + hub_quiesce(hub); return 0; } @@ -1983,11 +1920,35 @@ static int hub_resume(struct usb_interface *intf) { struct usb_device *hdev = interface_to_usbdev(intf); struct usb_hub *hub = usb_get_intfdata (intf); - unsigned port1; int status; - if (intf->dev.power.power_state.event == PM_EVENT_ON) - return 0; + /* "global resume" of the downstream HC-to-USB interface */ + if (!hdev->parent) { + struct usb_bus *bus = hdev->bus; + if (bus) { + status = hcd_bus_resume (bus); + if (status) { + dev_dbg(&intf->dev, "'global' resume %d\n", + status); + return status; + } + } else + return -EOPNOTSUPP; + if (status == 0) { + /* TRSMRCY = 10 msec */ + msleep(10); + } + } + + hub_activate(hub); + + /* REVISIT: this recursion probably shouldn't exist. Remove + * this code sometime, after retesting with different root and + * external hubs. + */ +#ifdef CONFIG_USB_SUSPEND + { + unsigned port1; for (port1 = 1; port1 <= hdev->maxchild; port1++) { struct usb_device *udev; @@ -2013,7 +1974,7 @@ static int hub_resume(struct usb_interface *intf) if (portstat & USB_PORT_STAT_SUSPEND) status = hub_port_resume(hub, port1, udev); else { - status = finish_port_resume(udev); + status = finish_device_resume(udev); if (status < 0) { dev_dbg(&intf->dev, "resume port %d --> %d\n", port1, status); @@ -2022,43 +1983,31 @@ static int hub_resume(struct usb_interface *intf) } up(&udev->serialize); } - intf->dev.power.power_state = PMSG_ON; - - hub->resume_root_hub = 0; - hub_activate(hub); + } +#endif return 0; } -void usb_resume_root_hub(struct usb_device *hdev) +void usb_suspend_root_hub(struct usb_device *hdev) { struct usb_hub *hub = hdev_to_hub(hdev); - hub->resume_root_hub = 1; - kick_khubd(hub); + /* This also makes any led blinker stop retriggering. We're called + * from irq, so the blinker might still be scheduled. Caller promises + * that the root hub status URB will be canceled. + */ + __hub_quiesce(hub); + mark_quiesced(to_usb_interface(hub->intfdev)); } -#else /* !CONFIG_USB_SUSPEND */ - -int usb_suspend_device(struct usb_device *udev, pm_message_t state) +void usb_resume_root_hub(struct usb_device *hdev) { - return 0; -} + struct usb_hub *hub = hdev_to_hub(hdev); -int usb_resume_device(struct usb_device *udev) -{ - return 0; + hub->resume_root_hub = 1; + kick_khubd(hub); } -#define hub_suspend NULL -#define hub_resume NULL -#define remote_wakeup(x) 0 - -#endif /* CONFIG_USB_SUSPEND */ - -EXPORT_SYMBOL(usb_suspend_device); -EXPORT_SYMBOL(usb_resume_device); - - /* USB 2.0 spec, 7.1.7.3 / fig 7-29: * @@ -2467,6 +2416,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, { struct usb_device *hdev = hub->hdev; struct device *hub_dev = hub->intfdev; + u16 wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics); int status, i; dev_dbg (hub_dev, @@ -2504,8 +2454,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, if (!(portstatus & USB_PORT_STAT_CONNECTION)) { /* maybe switch power back on (e.g. root hub was reset) */ - if ((hub->descriptor->wHubCharacteristics - & HUB_CHAR_LPSM) < 2 + if ((wHubCharacteristics & HUB_CHAR_LPSM) < 2 && !(portstatus & (1 << USB_PORT_FEAT_POWER))) set_port_feature(hdev, port1, USB_PORT_FEAT_POWER); @@ -2684,21 +2633,28 @@ static void hub_events(void) intf = to_usb_interface(hub->intfdev); hub_dev = &intf->dev; - dev_dbg(hub_dev, "state %d ports %d chg %04x evt %04x\n", + i = hub->resume_root_hub; + + dev_dbg(hub_dev, "state %d ports %d chg %04x evt %04x%s\n", hdev->state, hub->descriptor ? hub->descriptor->bNbrPorts : 0, /* NOTE: expects max 15 ports... */ (u16) hub->change_bits[0], - (u16) hub->event_bits[0]); + (u16) hub->event_bits[0], + i ? ", resume root" : ""); usb_get_intf(intf); - i = hub->resume_root_hub; spin_unlock_irq(&hub_event_lock); - /* Is this is a root hub wanting to be resumed? */ - if (i) - usb_resume_device(hdev); + /* Is this is a root hub wanting to reactivate the downstream + * ports? If so, be sure the interface resumes even if its + * stub "device" node was never suspended. + */ + if (i) { + dpm_runtime_resume(&hdev->dev); + dpm_runtime_resume(&intf->dev); + } /* Lock the device, then check to see if we were * disconnected while waiting for the lock to succeed. */ diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h index e7fa9b5a521e..bf23f8978024 100644 --- a/drivers/usb/core/hub.h +++ b/drivers/usb/core/hub.h @@ -131,7 +131,7 @@ struct usb_hub_descriptor { __u8 bDescLength; __u8 bDescriptorType; __u8 bNbrPorts; - __u16 wHubCharacteristics; + __le16 wHubCharacteristics; __u8 bPwrOn2PwrGood; __u8 bHubContrCurrent; /* add 1 bit for hub status change; round to bytes */ diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c index d07bba01995b..12f490fdee8f 100644 --- a/drivers/usb/core/inode.c +++ b/drivers/usb/core/inode.c @@ -39,6 +39,7 @@ #include <linux/usbdevice_fs.h> #include <linux/smp_lock.h> #include <linux/parser.h> +#include <linux/notifier.h> #include <asm/byteorder.h> #include "usb.h" #include "hcd.h" @@ -619,7 +620,7 @@ void usbfs_update_special (void) } } -void usbfs_add_bus(struct usb_bus *bus) +static void usbfs_add_bus(struct usb_bus *bus) { struct dentry *parent; char name[8]; @@ -642,12 +643,9 @@ void usbfs_add_bus(struct usb_bus *bus) err ("error creating usbfs bus entry"); return; } - - usbfs_update_special(); - usbfs_conn_disc_event(); } -void usbfs_remove_bus(struct usb_bus *bus) +static void usbfs_remove_bus(struct usb_bus *bus) { if (bus->usbfs_dentry) { fs_remove_file (bus->usbfs_dentry); @@ -659,12 +657,9 @@ void usbfs_remove_bus(struct usb_bus *bus) remove_special_files(); num_buses = 0; } - - usbfs_update_special(); - usbfs_conn_disc_event(); } -void usbfs_add_device(struct usb_device *dev) +static void usbfs_add_device(struct usb_device *dev) { char name[8]; int i; @@ -690,12 +685,9 @@ void usbfs_add_device(struct usb_device *dev) } if (dev->usbfs_dentry->d_inode) dev->usbfs_dentry->d_inode->i_size = i_size; - - usbfs_update_special(); - usbfs_conn_disc_event(); } -void usbfs_remove_device(struct usb_device *dev) +static void usbfs_remove_device(struct usb_device *dev) { struct dev_state *ds; struct siginfo sinfo; @@ -716,10 +708,33 @@ void usbfs_remove_device(struct usb_device *dev) kill_proc_info_as_uid(ds->discsignr, &sinfo, ds->disc_pid, ds->disc_uid, ds->disc_euid); } } +} + +static int usbfs_notify(struct notifier_block *self, unsigned long action, void *dev) +{ + switch (action) { + case USB_DEVICE_ADD: + usbfs_add_device(dev); + break; + case USB_DEVICE_REMOVE: + usbfs_remove_device(dev); + break; + case USB_BUS_ADD: + usbfs_add_bus(dev); + break; + case USB_BUS_REMOVE: + usbfs_remove_bus(dev); + } + usbfs_update_special(); usbfs_conn_disc_event(); + return NOTIFY_OK; } +static struct notifier_block usbfs_nb = { + .notifier_call = usbfs_notify, +}; + /* --------------------------------------------------------------------- */ static struct proc_dir_entry *usbdir = NULL; @@ -732,6 +747,8 @@ int __init usbfs_init(void) if (retval) return retval; + usb_register_notify(&usbfs_nb); + /* create mount point for usbfs */ usbdir = proc_mkdir("usb", proc_bus); @@ -740,6 +757,7 @@ int __init usbfs_init(void) void usbfs_cleanup(void) { + usb_unregister_notify(&usbfs_nb); unregister_filesystem(&usb_fs_type); if (usbdir) remove_proc_entry("usb", proc_bus); diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index f1fb67fe22a8..644a3d4f12aa 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -187,21 +187,37 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u * If a thread in your driver uses this call, make sure your disconnect() * method can wait for it to complete. Since you don't have a handle on * the URB used, you can't cancel the request. + * + * Because there is no usb_interrupt_msg() and no USBDEVFS_INTERRUPT + * ioctl, users are forced to abuse this routine by using it to submit + * URBs for interrupt endpoints. We will take the liberty of creating + * an interrupt URB (with the default interval) if the target is an + * interrupt endpoint. */ int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int *actual_length, int timeout) { struct urb *urb; + struct usb_host_endpoint *ep; - if (len < 0) + ep = (usb_pipein(pipe) ? usb_dev->ep_in : usb_dev->ep_out) + [usb_pipeendpoint(pipe)]; + if (!ep || len < 0) return -EINVAL; - urb=usb_alloc_urb(0, GFP_KERNEL); + urb = usb_alloc_urb(0, GFP_KERNEL); if (!urb) return -ENOMEM; - usb_fill_bulk_urb(urb, usb_dev, pipe, data, len, - usb_api_blocking_completion, NULL); + if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == + USB_ENDPOINT_XFER_INT) { + pipe = (pipe & ~(3 << 30)) | (PIPE_INTERRUPT << 30); + usb_fill_int_urb(urb, usb_dev, pipe, data, len, + usb_api_blocking_completion, NULL, + ep->desc.bInterval); + } else + usb_fill_bulk_urb(urb, usb_dev, pipe, data, len, + usb_api_blocking_completion, NULL); return usb_start_wait_urb(urb, timeout, actual_length); } @@ -321,7 +337,7 @@ int usb_sg_init ( struct scatterlist *sg, int nents, size_t length, - unsigned mem_flags + gfp_t mem_flags ) { int i; @@ -771,6 +787,31 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size) return err; } +/** + * usb_cache_string - read a string descriptor and cache it for later use + * @udev: the device whose string descriptor is being read + * @index: the descriptor index + * + * Returns a pointer to a kmalloc'ed buffer containing the descriptor string, + * or NULL if the index is 0 or the string could not be read. + */ +char *usb_cache_string(struct usb_device *udev, int index) +{ + char *buf; + char *smallbuf = NULL; + int len; + + if (index > 0 && (buf = kmalloc(256, GFP_KERNEL)) != NULL) { + if ((len = usb_string(udev, index, buf, 256)) > 0) { + if ((smallbuf = kmalloc(++len, GFP_KERNEL)) == NULL) + return buf; + memcpy(smallbuf, buf, len); + } + kfree(buf); + } + return smallbuf; +} + /* * usb_get_device_descriptor - (re)reads the device descriptor (usbcore) * @dev: the device whose device descriptor is being updated @@ -992,8 +1033,6 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0) dev_dbg (&dev->dev, "unregistering interface %s\n", interface->dev.bus_id); usb_remove_sysfs_intf_files(interface); - kfree(interface->cur_altsetting->string); - interface->cur_altsetting->string = NULL; device_del (&interface->dev); } @@ -1133,6 +1172,8 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) */ /* prevent submissions using previous endpoint settings */ + if (device_is_registered(&iface->dev)) + usb_remove_sysfs_intf_files(iface); usb_disable_interface(dev, iface); iface->cur_altsetting = alt; @@ -1168,6 +1209,8 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) * (Likewise, EP0 never "halts" on well designed devices.) */ usb_enable_interface(dev, iface); + if (device_is_registered(&iface->dev)) + usb_create_sysfs_intf_files(iface); return 0; } @@ -1217,10 +1260,8 @@ int usb_reset_configuration(struct usb_device *dev) USB_REQ_SET_CONFIGURATION, 0, config->desc.bConfigurationValue, 0, NULL, 0, USB_CTRL_SET_TIMEOUT); - if (retval < 0) { - usb_set_device_state(dev, USB_STATE_ADDRESS); + if (retval < 0) return retval; - } dev->toggle[0] = dev->toggle[1] = 0; @@ -1229,6 +1270,8 @@ int usb_reset_configuration(struct usb_device *dev) struct usb_interface *intf = config->interface[i]; struct usb_host_interface *alt; + if (device_is_registered(&intf->dev)) + usb_remove_sysfs_intf_files(intf); alt = usb_altnum_to_altsetting(intf, 0); /* No altsetting 0? We'll assume the first altsetting. @@ -1241,6 +1284,8 @@ int usb_reset_configuration(struct usb_device *dev) intf->cur_altsetting = alt; usb_enable_interface(dev, intf); + if (device_is_registered(&intf->dev)) + usb_create_sysfs_intf_files(intf); } return 0; } @@ -1328,7 +1373,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration) } for (; n < nintf; ++n) { - new_interfaces[n] = kmalloc( + new_interfaces[n] = kzalloc( sizeof(struct usb_interface), GFP_KERNEL); if (!new_interfaces[n]) { @@ -1369,7 +1414,6 @@ free_interfaces: struct usb_host_interface *alt; cp->interface[i] = intf = new_interfaces[i]; - memset(intf, 0, sizeof(*intf)); intfc = cp->intf_cache[i]; intf->altsetting = intfc->altsetting; intf->num_altsetting = intfc->num_altsetting; @@ -1393,6 +1437,7 @@ free_interfaces: intf->dev.dma_mask = dev->dev.dma_mask; intf->dev.release = release_interface; device_initialize (&intf->dev); + mark_quiesced(intf); sprintf (&intf->dev.bus_id[0], "%d-%s:%d.%d", dev->bus->busnum, dev->devpath, configuration, @@ -1400,12 +1445,9 @@ free_interfaces: } kfree(new_interfaces); - if ((cp->desc.iConfiguration) && - (cp->string == NULL)) { - cp->string = kmalloc(256, GFP_KERNEL); - if (cp->string) - usb_string(dev, cp->desc.iConfiguration, cp->string, 256); - } + if (cp->string == NULL) + cp->string = usb_cache_string(dev, + cp->desc.iConfiguration); /* Now that all the interfaces are set up, register them * to trigger binding of drivers to interfaces. probe() @@ -1415,13 +1457,12 @@ free_interfaces: */ for (i = 0; i < nintf; ++i) { struct usb_interface *intf = cp->interface[i]; - struct usb_interface_descriptor *desc; + struct usb_host_interface *alt = intf->cur_altsetting; - desc = &intf->altsetting [0].desc; dev_dbg (&dev->dev, "adding %s (config #%d, interface %d)\n", intf->dev.bus_id, configuration, - desc->bInterfaceNumber); + alt->desc.bInterfaceNumber); ret = device_add (&intf->dev); if (ret != 0) { dev_err(&dev->dev, @@ -1430,13 +1471,6 @@ free_interfaces: ret); continue; } - if ((intf->cur_altsetting->desc.iInterface) && - (intf->cur_altsetting->string == NULL)) { - intf->cur_altsetting->string = kmalloc(256, GFP_KERNEL); - if (intf->cur_altsetting->string) - usb_string(dev, intf->cur_altsetting->desc.iInterface, - intf->cur_altsetting->string, 256); - } usb_create_sysfs_intf_files (intf); } } diff --git a/drivers/usb/core/notify.c b/drivers/usb/core/notify.c new file mode 100644 index 000000000000..37da059eced7 --- /dev/null +++ b/drivers/usb/core/notify.c @@ -0,0 +1,120 @@ +/* + * All the USB notify logic + * + * (C) Copyright 2005 Greg Kroah-Hartman <gregkh@suse.de> + * + * notifier functions originally based on those in kernel/sys.c + * but fixed up to not be so broken. + * + */ + + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/notifier.h> +#ifdef CONFIG_USB_DEBUG + #define DEBUG +#else + #undef DEBUG +#endif +#include <linux/usb.h> + +#include "usb.h" + + +static struct notifier_block *usb_notifier_list; +static DECLARE_MUTEX(usb_notifier_lock); + +static void usb_notifier_chain_register(struct notifier_block **list, + struct notifier_block *n) +{ + down(&usb_notifier_lock); + while (*list) { + if (n->priority > (*list)->priority) + break; + list = &((*list)->next); + } + n->next = *list; + *list = n; + up(&usb_notifier_lock); +} + +static void usb_notifier_chain_unregister(struct notifier_block **nl, + struct notifier_block *n) +{ + down(&usb_notifier_lock); + while ((*nl)!=NULL) { + if ((*nl)==n) { + *nl = n->next; + goto exit; + } + nl=&((*nl)->next); + } +exit: + up(&usb_notifier_lock); +} + +static int usb_notifier_call_chain(struct notifier_block **n, + unsigned long val, void *v) +{ + int ret=NOTIFY_DONE; + struct notifier_block *nb = *n; + + down(&usb_notifier_lock); + while (nb) { + ret = nb->notifier_call(nb,val,v); + if (ret&NOTIFY_STOP_MASK) { + goto exit; + } + nb = nb->next; + } +exit: + up(&usb_notifier_lock); + return ret; +} + +/** + * usb_register_notify - register a notifier callback whenever a usb change happens + * @nb: pointer to the notifier block for the callback events. + * + * These changes are either USB devices or busses being added or removed. + */ +void usb_register_notify(struct notifier_block *nb) +{ + usb_notifier_chain_register(&usb_notifier_list, nb); +} +EXPORT_SYMBOL_GPL(usb_register_notify); + +/** + * usb_unregister_notify - unregister a notifier callback + * @nb: pointer to the notifier block for the callback events. + * + * usb_register_notifier() must have been previously called for this function + * to work properly. + */ +void usb_unregister_notify(struct notifier_block *nb) +{ + usb_notifier_chain_unregister(&usb_notifier_list, nb); +} +EXPORT_SYMBOL_GPL(usb_unregister_notify); + + +void usb_notify_add_device(struct usb_device *udev) +{ + usb_notifier_call_chain(&usb_notifier_list, USB_DEVICE_ADD, udev); +} + +void usb_notify_remove_device(struct usb_device *udev) +{ + usb_notifier_call_chain(&usb_notifier_list, USB_DEVICE_REMOVE, udev); +} + +void usb_notify_add_bus(struct usb_bus *ubus) +{ + usb_notifier_call_chain(&usb_notifier_list, USB_BUS_ADD, ubus); +} + +void usb_notify_remove_bus(struct usb_bus *ubus) +{ + usb_notifier_call_chain(&usb_notifier_list, USB_BUS_REMOVE, ubus); +} diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index 00297f113849..edd83e014452 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -22,9 +22,207 @@ #include "usb.h" +/* endpoint stuff */ +struct ep_object { + struct usb_endpoint_descriptor *desc; + struct usb_device *udev; + struct kobject kobj; +}; +#define to_ep_object(_kobj) \ + container_of(_kobj, struct ep_object, kobj) + +struct ep_attribute { + struct attribute attr; + ssize_t (*show)(struct usb_device *, + struct usb_endpoint_descriptor *, char *); +}; +#define to_ep_attribute(_attr) \ + container_of(_attr, struct ep_attribute, attr) + +#define EP_ATTR(_name) \ +struct ep_attribute ep_##_name = { \ + .attr = {.name = #_name, .owner = THIS_MODULE, \ + .mode = S_IRUGO}, \ + .show = show_ep_##_name} + +#define usb_ep_attr(field, format_string) \ +static ssize_t show_ep_##field(struct usb_device *udev, \ + struct usb_endpoint_descriptor *desc, \ + char *buf) \ +{ \ + return sprintf(buf, format_string, desc->field); \ +} \ +static EP_ATTR(field); + +usb_ep_attr(bLength, "%02x\n") +usb_ep_attr(bEndpointAddress, "%02x\n") +usb_ep_attr(bmAttributes, "%02x\n") +usb_ep_attr(bInterval, "%02x\n") + +static ssize_t show_ep_wMaxPacketSize(struct usb_device *udev, + struct usb_endpoint_descriptor *desc, char *buf) +{ + return sprintf(buf, "%04x\n", + le16_to_cpu(desc->wMaxPacketSize) & 0x07ff); +} +static EP_ATTR(wMaxPacketSize); + +static ssize_t show_ep_type(struct usb_device *udev, + struct usb_endpoint_descriptor *desc, char *buf) +{ + char *type = "unknown"; + + switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { + case USB_ENDPOINT_XFER_CONTROL: + type = "Control"; + break; + case USB_ENDPOINT_XFER_ISOC: + type = "Isoc"; + break; + case USB_ENDPOINT_XFER_BULK: + type = "Bulk"; + break; + case USB_ENDPOINT_XFER_INT: + type = "Interrupt"; + break; + } + return sprintf(buf, "%s\n", type); +} +static EP_ATTR(type); + +static ssize_t show_ep_interval(struct usb_device *udev, + struct usb_endpoint_descriptor *desc, char *buf) +{ + char unit; + unsigned interval = 0; + unsigned in; + + in = (desc->bEndpointAddress & USB_DIR_IN); + + switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { + case USB_ENDPOINT_XFER_CONTROL: + if (udev->speed == USB_SPEED_HIGH) /* uframes per NAK */ + interval = desc->bInterval; + break; + case USB_ENDPOINT_XFER_ISOC: + interval = 1 << (desc->bInterval - 1); + break; + case USB_ENDPOINT_XFER_BULK: + if (udev->speed == USB_SPEED_HIGH && !in) /* uframes per NAK */ + interval = desc->bInterval; + break; + case USB_ENDPOINT_XFER_INT: + if (udev->speed == USB_SPEED_HIGH) + interval = 1 << (desc->bInterval - 1); + else + interval = desc->bInterval; + break; + } + interval *= (udev->speed == USB_SPEED_HIGH) ? 125 : 1000; + if (interval % 1000) + unit = 'u'; + else { + unit = 'm'; + interval /= 1000; + } + + return sprintf(buf, "%d%cs\n", interval, unit); +} +static EP_ATTR(interval); + +static ssize_t show_ep_direction(struct usb_device *udev, + struct usb_endpoint_descriptor *desc, char *buf) +{ + char *direction; + + if ((desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == + USB_ENDPOINT_XFER_CONTROL) + direction = "both"; + else if (desc->bEndpointAddress & USB_DIR_IN) + direction = "in"; + else + direction = "out"; + return sprintf(buf, "%s\n", direction); +} +static EP_ATTR(direction); + +static struct attribute *ep_attrs[] = { + &ep_bLength.attr, + &ep_bEndpointAddress.attr, + &ep_bmAttributes.attr, + &ep_bInterval.attr, + &ep_wMaxPacketSize.attr, + &ep_type.attr, + &ep_interval.attr, + &ep_direction.attr, + NULL, +}; + +static void ep_object_release(struct kobject *kobj) +{ + kfree(to_ep_object(kobj)); +} + +static ssize_t ep_object_show(struct kobject *kobj, struct attribute *attr, + char *buf) +{ + struct ep_object *ep_obj = to_ep_object(kobj); + struct ep_attribute *ep_attr = to_ep_attribute(attr); + + return (ep_attr->show)(ep_obj->udev, ep_obj->desc, buf); +} + +static struct sysfs_ops ep_object_sysfs_ops = { + .show = ep_object_show, +}; + +static struct kobj_type ep_object_ktype = { + .release = ep_object_release, + .sysfs_ops = &ep_object_sysfs_ops, + .default_attrs = ep_attrs, +}; + +static void usb_create_ep_files(struct kobject *parent, + struct usb_host_endpoint *endpoint, + struct usb_device *udev) +{ + struct ep_object *ep_obj; + struct kobject *kobj; + + ep_obj = kzalloc(sizeof(struct ep_object), GFP_KERNEL); + if (!ep_obj) + return; + + ep_obj->desc = &endpoint->desc; + ep_obj->udev = udev; + + kobj = &ep_obj->kobj; + kobject_set_name(kobj, "ep_%02x", endpoint->desc.bEndpointAddress); + kobj->parent = parent; + kobj->ktype = &ep_object_ktype; + + /* Don't use kobject_register, because it generates a hotplug event */ + kobject_init(kobj); + if (kobject_add(kobj) == 0) + endpoint->kobj = kobj; + else + kobject_put(kobj); +} + +static void usb_remove_ep_files(struct usb_host_endpoint *endpoint) +{ + + if (endpoint->kobj) { + kobject_del(endpoint->kobj); + kobject_put(endpoint->kobj); + endpoint->kobj = NULL; + } +} + /* Active configuration fields */ #define usb_actconfig_show(field, multiplier, format_string) \ -static ssize_t show_##field (struct device *dev, struct device_attribute *attr, char *buf) \ +static ssize_t show_##field (struct device *dev, \ + struct device_attribute *attr, char *buf) \ { \ struct usb_device *udev; \ struct usb_host_config *actconfig; \ @@ -46,22 +244,17 @@ usb_actconfig_attr (bNumInterfaces, 1, "%2d\n") usb_actconfig_attr (bmAttributes, 1, "%2x\n") usb_actconfig_attr (bMaxPower, 2, "%3dmA\n") -static ssize_t show_configuration_string(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_configuration_string(struct device *dev, + struct device_attribute *attr, char *buf) { struct usb_device *udev; struct usb_host_config *actconfig; - int len; udev = to_usb_device (dev); actconfig = udev->actconfig; if ((!actconfig) || (!actconfig->string)) return 0; - len = sprintf(buf, actconfig->string, PAGE_SIZE); - if (len < 0) - return 0; - buf[len] = '\n'; - buf[len+1] = 0; - return len+1; + return sprintf(buf, "%s\n", actconfig->string); } static DEVICE_ATTR(configuration, S_IRUGO, show_configuration_string, NULL); @@ -69,7 +262,8 @@ static DEVICE_ATTR(configuration, S_IRUGO, show_configuration_string, NULL); usb_actconfig_show(bConfigurationValue, 1, "%u\n"); static ssize_t -set_bConfigurationValue (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +set_bConfigurationValue (struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct usb_device *udev = udev = to_usb_device (dev); int config, value; @@ -87,18 +281,13 @@ static DEVICE_ATTR(bConfigurationValue, S_IRUGO | S_IWUSR, /* String fields */ #define usb_string_attr(name) \ -static ssize_t show_##name(struct device *dev, struct device_attribute *attr, char *buf) \ +static ssize_t show_##name(struct device *dev, \ + struct device_attribute *attr, char *buf) \ { \ struct usb_device *udev; \ - int len; \ \ udev = to_usb_device (dev); \ - len = snprintf(buf, 256, "%s", udev->name); \ - if (len < 0) \ - return 0; \ - buf[len] = '\n'; \ - buf[len+1] = 0; \ - return len+1; \ + return sprintf(buf, "%s\n", udev->name); \ } \ static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL); @@ -167,7 +356,8 @@ static DEVICE_ATTR(maxchild, S_IRUGO, show_maxchild, NULL); /* Descriptor fields */ #define usb_descriptor_attr_le16(field, format_string) \ static ssize_t \ -show_##field (struct device *dev, struct device_attribute *attr, char *buf) \ +show_##field (struct device *dev, struct device_attribute *attr, \ + char *buf) \ { \ struct usb_device *udev; \ \ @@ -183,7 +373,8 @@ usb_descriptor_attr_le16(bcdDevice, "%04x\n") #define usb_descriptor_attr(field, format_string) \ static ssize_t \ -show_##field (struct device *dev, struct device_attribute *attr, char *buf) \ +show_##field (struct device *dev, struct device_attribute *attr, \ + char *buf) \ { \ struct usb_device *udev; \ \ @@ -236,19 +427,21 @@ void usb_create_sysfs_dev_files (struct usb_device *udev) if (udev->serial) device_create_file (dev, &dev_attr_serial); device_create_file (dev, &dev_attr_configuration); + usb_create_ep_files(&dev->kobj, &udev->ep0, udev); } void usb_remove_sysfs_dev_files (struct usb_device *udev) { struct device *dev = &udev->dev; + usb_remove_ep_files(&udev->ep0); sysfs_remove_group(&dev->kobj, &dev_attr_grp); - if (udev->descriptor.iManufacturer) + if (udev->manufacturer) device_remove_file(dev, &dev_attr_manufacturer); - if (udev->descriptor.iProduct) + if (udev->product) device_remove_file(dev, &dev_attr_product); - if (udev->descriptor.iSerialNumber) + if (udev->serial) device_remove_file(dev, &dev_attr_serial); device_remove_file (dev, &dev_attr_configuration); } @@ -256,11 +449,13 @@ void usb_remove_sysfs_dev_files (struct usb_device *udev) /* Interface fields */ #define usb_intf_attr(field, format_string) \ static ssize_t \ -show_##field (struct device *dev, struct device_attribute *attr, char *buf) \ +show_##field (struct device *dev, struct device_attribute *attr, \ + char *buf) \ { \ struct usb_interface *intf = to_usb_interface (dev); \ \ - return sprintf (buf, format_string, intf->cur_altsetting->desc.field); \ + return sprintf (buf, format_string, \ + intf->cur_altsetting->desc.field); \ } \ static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL); @@ -271,7 +466,8 @@ usb_intf_attr (bInterfaceClass, "%02x\n") usb_intf_attr (bInterfaceSubClass, "%02x\n") usb_intf_attr (bInterfaceProtocol, "%02x\n") -static ssize_t show_interface_string(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_interface_string(struct device *dev, + struct device_attribute *attr, char *buf) { struct usb_interface *intf; struct usb_device *udev; @@ -288,34 +484,28 @@ static ssize_t show_interface_string(struct device *dev, struct device_attribute } static DEVICE_ATTR(interface, S_IRUGO, show_interface_string, NULL); -static ssize_t show_modalias(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_modalias(struct device *dev, + struct device_attribute *attr, char *buf) { struct usb_interface *intf; struct usb_device *udev; - int len; + struct usb_host_interface *alt; intf = to_usb_interface(dev); udev = interface_to_usbdev(intf); - - len = sprintf(buf, "usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic", - le16_to_cpu(udev->descriptor.idVendor), - le16_to_cpu(udev->descriptor.idProduct), - le16_to_cpu(udev->descriptor.bcdDevice), - udev->descriptor.bDeviceClass, - udev->descriptor.bDeviceSubClass, - udev->descriptor.bDeviceProtocol); - buf += len; - - if (udev->descriptor.bDeviceClass == 0) { - struct usb_host_interface *alt = intf->cur_altsetting; - - return len + sprintf(buf, "%02Xisc%02Xip%02X\n", - alt->desc.bInterfaceClass, - alt->desc.bInterfaceSubClass, - alt->desc.bInterfaceProtocol); - } else { - return len + sprintf(buf, "*isc*ip*\n"); - } + alt = intf->cur_altsetting; + + return sprintf(buf, "usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02X" + "ic%02Xisc%02Xip%02X\n", + le16_to_cpu(udev->descriptor.idVendor), + le16_to_cpu(udev->descriptor.idProduct), + le16_to_cpu(udev->descriptor.bcdDevice), + udev->descriptor.bDeviceClass, + udev->descriptor.bDeviceSubClass, + udev->descriptor.bDeviceProtocol, + alt->desc.bInterfaceClass, + alt->desc.bInterfaceSubClass, + alt->desc.bInterfaceProtocol); } static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL); @@ -333,20 +523,47 @@ static struct attribute_group intf_attr_grp = { .attrs = intf_attrs, }; +static inline void usb_create_intf_ep_files(struct usb_interface *intf, + struct usb_device *udev) +{ + struct usb_host_interface *iface_desc; + int i; + + iface_desc = intf->cur_altsetting; + for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) + usb_create_ep_files(&intf->dev.kobj, &iface_desc->endpoint[i], + udev); +} + +static inline void usb_remove_intf_ep_files(struct usb_interface *intf) +{ + struct usb_host_interface *iface_desc; + int i; + + iface_desc = intf->cur_altsetting; + for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) + usb_remove_ep_files(&iface_desc->endpoint[i]); +} + void usb_create_sysfs_intf_files (struct usb_interface *intf) { + struct usb_device *udev = interface_to_usbdev(intf); + struct usb_host_interface *alt = intf->cur_altsetting; + sysfs_create_group(&intf->dev.kobj, &intf_attr_grp); - if (intf->cur_altsetting->string) + if (alt->string == NULL) + alt->string = usb_cache_string(udev, alt->desc.iInterface); + if (alt->string) device_create_file(&intf->dev, &dev_attr_interface); - + usb_create_intf_ep_files(intf, udev); } void usb_remove_sysfs_intf_files (struct usb_interface *intf) { + usb_remove_intf_ep_files(intf); sysfs_remove_group(&intf->dev.kobj, &intf_attr_grp); if (intf->cur_altsetting->string) device_remove_file(&intf->dev, &dev_attr_interface); - } diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index c846fefb7386..f2a1fed2a802 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -60,7 +60,7 @@ void usb_init_urb(struct urb *urb) * * The driver must call usb_free_urb() when it is finished with the urb. */ -struct urb *usb_alloc_urb(int iso_packets, unsigned mem_flags) +struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags) { struct urb *urb; @@ -224,7 +224,7 @@ struct urb * usb_get_urb(struct urb *urb) * GFP_NOIO, unless b) or c) apply * */ -int usb_submit_urb(struct urb *urb, unsigned mem_flags) +int usb_submit_urb(struct urb *urb, gfp_t mem_flags) { int pipe, temp, max; struct usb_device *dev; @@ -237,7 +237,8 @@ int usb_submit_urb(struct urb *urb, unsigned mem_flags) (dev->state < USB_STATE_DEFAULT) || (!dev->bus) || (dev->devnum <= 0)) return -ENODEV; - if (dev->state == USB_STATE_SUSPENDED) + if (dev->bus->controller->power.power_state.event != PM_EVENT_ON + || dev->state == USB_STATE_SUSPENDED) return -EHOSTUNREACH; if (!(op = dev->bus->op) || !op->submit_urb) return -ENODEV; diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 7d131509e419..0eefff7bcb3c 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -107,10 +107,19 @@ static int usb_probe_interface(struct device *dev) id = usb_match_id (intf, driver->id_table); if (id) { dev_dbg (dev, "%s - got id\n", __FUNCTION__); + + /* Interface "power state" doesn't correspond to any hardware + * state whatsoever. We use it to record when it's bound to + * a driver that may start I/0: it's not frozen/quiesced. + */ + mark_active(intf); intf->condition = USB_INTERFACE_BINDING; error = driver->probe (intf, id); - intf->condition = error ? USB_INTERFACE_UNBOUND : - USB_INTERFACE_BOUND; + if (error) { + mark_quiesced(intf); + intf->condition = USB_INTERFACE_UNBOUND; + } else + intf->condition = USB_INTERFACE_BOUND; } return error; @@ -136,6 +145,7 @@ static int usb_unbind_interface(struct device *dev) 0); usb_set_intfdata(intf, NULL); intf->condition = USB_INTERFACE_UNBOUND; + mark_quiesced(intf); return 0; } @@ -299,6 +309,7 @@ int usb_driver_claim_interface(struct usb_driver *driver, dev->driver = &driver->driver; usb_set_intfdata(iface, priv); iface->condition = USB_INTERFACE_BOUND; + mark_active(iface); /* if interface was already added, bind now; else let * the future device_add() bind it, bypassing probe() @@ -345,6 +356,7 @@ void usb_driver_release_interface(struct usb_driver *driver, dev->driver = NULL; usb_set_intfdata(iface, NULL); iface->condition = USB_INTERFACE_UNBOUND; + mark_quiesced(iface); } /** @@ -557,6 +569,7 @@ static int usb_hotplug (struct device *dev, char **envp, int num_envp, { struct usb_interface *intf; struct usb_device *usb_dev; + struct usb_host_interface *alt; int i = 0; int length = 0; @@ -573,7 +586,8 @@ static int usb_hotplug (struct device *dev, char **envp, int num_envp, intf = to_usb_interface(dev); usb_dev = interface_to_usbdev (intf); - + alt = intf->cur_altsetting; + if (usb_dev->devnum < 0) { pr_debug ("usb %s: already deleted?\n", dev->bus_id); return -ENODEV; @@ -615,46 +629,27 @@ static int usb_hotplug (struct device *dev, char **envp, int num_envp, usb_dev->descriptor.bDeviceProtocol)) return -ENOMEM; - if (usb_dev->descriptor.bDeviceClass == 0) { - struct usb_host_interface *alt = intf->cur_altsetting; + if (add_hotplug_env_var(envp, num_envp, &i, + buffer, buffer_size, &length, + "INTERFACE=%d/%d/%d", + alt->desc.bInterfaceClass, + alt->desc.bInterfaceSubClass, + alt->desc.bInterfaceProtocol)) + return -ENOMEM; - /* 2.4 only exposed interface zero. in 2.5, hotplug - * agents are called for all interfaces, and can use - * $DEVPATH/bInterfaceNumber if necessary. - */ - if (add_hotplug_env_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "INTERFACE=%d/%d/%d", - alt->desc.bInterfaceClass, - alt->desc.bInterfaceSubClass, - alt->desc.bInterfaceProtocol)) - return -ENOMEM; - - if (add_hotplug_env_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "MODALIAS=usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X", - le16_to_cpu(usb_dev->descriptor.idVendor), - le16_to_cpu(usb_dev->descriptor.idProduct), - le16_to_cpu(usb_dev->descriptor.bcdDevice), - usb_dev->descriptor.bDeviceClass, - usb_dev->descriptor.bDeviceSubClass, - usb_dev->descriptor.bDeviceProtocol, - alt->desc.bInterfaceClass, - alt->desc.bInterfaceSubClass, - alt->desc.bInterfaceProtocol)) - return -ENOMEM; - } else { - if (add_hotplug_env_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "MODALIAS=usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic*isc*ip*", - le16_to_cpu(usb_dev->descriptor.idVendor), - le16_to_cpu(usb_dev->descriptor.idProduct), - le16_to_cpu(usb_dev->descriptor.bcdDevice), - usb_dev->descriptor.bDeviceClass, - usb_dev->descriptor.bDeviceSubClass, - usb_dev->descriptor.bDeviceProtocol)) - return -ENOMEM; - } + if (add_hotplug_env_var(envp, num_envp, &i, + buffer, buffer_size, &length, + "MODALIAS=usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X", + le16_to_cpu(usb_dev->descriptor.idVendor), + le16_to_cpu(usb_dev->descriptor.idProduct), + le16_to_cpu(usb_dev->descriptor.bcdDevice), + usb_dev->descriptor.bDeviceClass, + usb_dev->descriptor.bDeviceSubClass, + usb_dev->descriptor.bDeviceProtocol, + alt->desc.bInterfaceClass, + alt->desc.bInterfaceSubClass, + alt->desc.bInterfaceProtocol)) + return -ENOMEM; envp[i] = NULL; @@ -709,12 +704,10 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1) { struct usb_device *dev; - dev = kmalloc(sizeof(*dev), GFP_KERNEL); + dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) return NULL; - memset(dev, 0, sizeof(*dev)); - bus = usb_bus_get(bus); if (!bus) { kfree(dev); @@ -1147,7 +1140,7 @@ int __usb_get_extra_descriptor(char *buffer, unsigned size, void *usb_buffer_alloc ( struct usb_device *dev, size_t size, - unsigned mem_flags, + gfp_t mem_flags, dma_addr_t *dma ) { @@ -1402,13 +1395,30 @@ void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe, usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } +static int verify_suspended(struct device *dev, void *unused) +{ + return (dev->power.power_state.event == PM_EVENT_ON) ? -EBUSY : 0; +} + static int usb_generic_suspend(struct device *dev, pm_message_t message) { - struct usb_interface *intf; - struct usb_driver *driver; + struct usb_interface *intf; + struct usb_driver *driver; + int status; - if (dev->driver == &usb_generic_driver) - return usb_suspend_device (to_usb_device(dev), message); + /* USB devices enter SUSPEND state through their hubs, but can be + * marked for FREEZE as soon as their children are already idled. + * But those semantics are useless, so we equate the two (sigh). + */ + if (dev->driver == &usb_generic_driver) { + if (dev->power.power_state.event == message.event) + return 0; + /* we need to rule out bogus requests through sysfs */ + status = device_for_each_child(dev, NULL, verify_suspended); + if (status) + return status; + return usb_suspend_device (to_usb_device(dev)); + } if ((dev->driver == NULL) || (dev->driver_data == &usb_generic_driver_data)) @@ -1417,23 +1427,44 @@ static int usb_generic_suspend(struct device *dev, pm_message_t message) intf = to_usb_interface(dev); driver = to_usb_driver(dev->driver); - /* there's only one USB suspend state */ - if (intf->dev.power.power_state.event) + /* with no hardware, USB interfaces only use FREEZE and ON states */ + if (!is_active(intf)) return 0; - if (driver->suspend) - return driver->suspend(intf, message); - return 0; + if (driver->suspend && driver->resume) { + status = driver->suspend(intf, message); + if (status) + dev_err(dev, "%s error %d\n", "suspend", status); + else + mark_quiesced(intf); + } else { + // FIXME else if there's no suspend method, disconnect... + dev_warn(dev, "no %s?\n", "suspend"); + status = 0; + } + return status; } static int usb_generic_resume(struct device *dev) { - struct usb_interface *intf; - struct usb_driver *driver; + struct usb_interface *intf; + struct usb_driver *driver; + struct usb_device *udev; + int status; - /* devices resume through their hub */ - if (dev->driver == &usb_generic_driver) + if (dev->power.power_state.event == PM_EVENT_ON) + return 0; + + /* mark things as "on" immediately, no matter what errors crop up */ + dev->power.power_state.event = PM_EVENT_ON; + + /* devices resume through their hubs */ + if (dev->driver == &usb_generic_driver) { + udev = to_usb_device(dev); + if (udev->state == USB_STATE_NOTATTACHED) + return 0; return usb_resume_device (to_usb_device(dev)); + } if ((dev->driver == NULL) || (dev->driver_data == &usb_generic_driver_data)) @@ -1442,8 +1473,22 @@ static int usb_generic_resume(struct device *dev) intf = to_usb_interface(dev); driver = to_usb_driver(dev->driver); - if (driver->resume) - return driver->resume(intf); + udev = interface_to_usbdev(intf); + if (udev->state == USB_STATE_NOTATTACHED) + return 0; + + /* if driver was suspended, it has a resume method; + * however, sysfs can wrongly mark things as suspended + * (on the "no suspend method" FIXME path above) + */ + if (driver->resume) { + status = driver->resume(intf); + if (status) { + dev_err(dev, "%s error %d\n", "resume", status); + mark_quiesced(intf); + } + } else + dev_warn(dev, "no %s?\n", "resume"); return 0; } diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index e6504f3370ad..1c4a68499dce 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -13,12 +13,14 @@ extern void usb_disable_device (struct usb_device *dev, int skip_ep0); extern int usb_get_device_descriptor(struct usb_device *dev, unsigned int size); +extern char *usb_cache_string(struct usb_device *udev, int index); extern int usb_set_configuration(struct usb_device *dev, int configuration); extern void usb_lock_all_devices(void); extern void usb_unlock_all_devices(void); extern void usb_kick_khubd(struct usb_device *dev); +extern void usb_suspend_root_hub(struct usb_device *hdev); extern void usb_resume_root_hub(struct usb_device *dev); extern int usb_hub_init(void); @@ -28,6 +30,28 @@ extern void usb_major_cleanup(void); extern int usb_host_init(void); extern void usb_host_cleanup(void); +extern int usb_suspend_device(struct usb_device *dev); +extern int usb_resume_device(struct usb_device *dev); + + +/* Interfaces and their "power state" are owned by usbcore */ + +static inline void mark_active(struct usb_interface *f) +{ + f->dev.power.power_state.event = PM_EVENT_ON; +} + +static inline void mark_quiesced(struct usb_interface *f) +{ + f->dev.power.power_state.event = PM_EVENT_FREEZE; +} + +static inline int is_active(struct usb_interface *f) +{ + return f->dev.power.power_state.event == PM_EVENT_ON; +} + + /* for labeling diagnostics */ extern const char *usbcore_name; @@ -39,9 +63,6 @@ extern void usbfs_conn_disc_event(void); extern int usbdev_init(void); extern void usbdev_cleanup(void); -extern void usbdev_add(struct usb_device *dev); -extern void usbdev_remove(struct usb_device *dev); -extern struct usb_device *usbdev_lookup_minor(int minor); struct dev_state { struct list_head list; /* state list */ @@ -58,3 +79,9 @@ struct dev_state { unsigned long ifclaimed; }; +/* internal notify stuff */ +extern void usb_notify_add_device(struct usb_device *udev); +extern void usb_notify_remove_device(struct usb_device *udev); +extern void usb_notify_add_bus(struct usb_bus *ubus); +extern void usb_notify_remove_bus(struct usb_bus *ubus); + diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 583db7c38cf1..02106bebd5c1 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -470,7 +470,7 @@ static int dummy_disable (struct usb_ep *_ep) } static struct usb_request * -dummy_alloc_request (struct usb_ep *_ep, unsigned mem_flags) +dummy_alloc_request (struct usb_ep *_ep, gfp_t mem_flags) { struct dummy_ep *ep; struct dummy_request *req; @@ -507,7 +507,7 @@ dummy_alloc_buffer ( struct usb_ep *_ep, unsigned bytes, dma_addr_t *dma, - unsigned mem_flags + gfp_t mem_flags ) { char *retval; struct dummy_ep *ep; @@ -541,7 +541,7 @@ fifo_complete (struct usb_ep *ep, struct usb_request *req) static int dummy_queue (struct usb_ep *_ep, struct usb_request *_req, - unsigned mem_flags) + gfp_t mem_flags) { struct dummy_ep *ep; struct dummy_request *req; @@ -935,14 +935,10 @@ static int dummy_udc_remove (struct device *dev) return 0; } -static int dummy_udc_suspend (struct device *dev, pm_message_t state, - u32 level) +static int dummy_udc_suspend (struct device *dev, pm_message_t state) { struct dummy *dum = dev_get_drvdata(dev); - if (level != SUSPEND_DISABLE) - return 0; - dev_dbg (dev, "%s\n", __FUNCTION__); spin_lock_irq (&dum->lock); dum->udc_suspended = 1; @@ -954,13 +950,10 @@ static int dummy_udc_suspend (struct device *dev, pm_message_t state, return 0; } -static int dummy_udc_resume (struct device *dev, u32 level) +static int dummy_udc_resume (struct device *dev) { struct dummy *dum = dev_get_drvdata(dev); - if (level != RESUME_ENABLE) - return 0; - dev_dbg (dev, "%s\n", __FUNCTION__); spin_lock_irq (&dum->lock); dum->udc_suspended = 0; @@ -974,6 +967,7 @@ static int dummy_udc_resume (struct device *dev, u32 level) static struct device_driver dummy_udc_driver = { .name = (char *) gadget_name, + .owner = THIS_MODULE, .bus = &platform_bus_type, .probe = dummy_udc_probe, .remove = dummy_udc_remove, @@ -999,7 +993,7 @@ static int dummy_urb_enqueue ( struct usb_hcd *hcd, struct usb_host_endpoint *ep, struct urb *urb, - unsigned mem_flags + gfp_t mem_flags ) { struct dummy *dum; struct urbp *urbp; @@ -1758,7 +1752,7 @@ static int dummy_hub_control ( return retval; } -static int dummy_hub_suspend (struct usb_hcd *hcd) +static int dummy_bus_suspend (struct usb_hcd *hcd) { struct dummy *dum = hcd_to_dummy (hcd); @@ -1769,7 +1763,7 @@ static int dummy_hub_suspend (struct usb_hcd *hcd) return 0; } -static int dummy_hub_resume (struct usb_hcd *hcd) +static int dummy_bus_resume (struct usb_hcd *hcd) { struct dummy *dum = hcd_to_dummy (hcd); @@ -1901,8 +1895,8 @@ static const struct hc_driver dummy_hcd = { .hub_status_data = dummy_hub_status, .hub_control = dummy_hub_control, - .hub_suspend = dummy_hub_suspend, - .hub_resume = dummy_hub_resume, + .bus_suspend = dummy_bus_suspend, + .bus_resume = dummy_bus_resume, }; static int dummy_hcd_probe (struct device *dev) @@ -1936,52 +1930,32 @@ static int dummy_hcd_remove (struct device *dev) return 0; } -static int dummy_hcd_suspend (struct device *dev, pm_message_t state, - u32 level) +static int dummy_hcd_suspend (struct device *dev, pm_message_t state) { struct usb_hcd *hcd; - if (level != SUSPEND_DISABLE) - return 0; - dev_dbg (dev, "%s\n", __FUNCTION__); hcd = dev_get_drvdata (dev); -#ifndef CONFIG_USB_SUSPEND - /* Otherwise this would never happen */ - usb_lock_device (hcd->self.root_hub); - dummy_hub_suspend (hcd); - usb_unlock_device (hcd->self.root_hub); -#endif - hcd->state = HC_STATE_SUSPENDED; return 0; } -static int dummy_hcd_resume (struct device *dev, u32 level) +static int dummy_hcd_resume (struct device *dev) { struct usb_hcd *hcd; - if (level != RESUME_ENABLE) - return 0; - dev_dbg (dev, "%s\n", __FUNCTION__); hcd = dev_get_drvdata (dev); hcd->state = HC_STATE_RUNNING; -#ifndef CONFIG_USB_SUSPEND - /* Otherwise this would never happen */ - usb_lock_device (hcd->self.root_hub); - dummy_hub_resume (hcd); - usb_unlock_device (hcd->self.root_hub); -#endif - usb_hcd_poll_rh_status (hcd); return 0; } static struct device_driver dummy_hcd_driver = { .name = (char *) driver_name, + .owner = THIS_MODULE, .bus = &platform_bus_type, .probe = dummy_hcd_probe, .remove = dummy_hcd_remove, diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 49459e33e952..8f402f85e1ca 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -945,11 +945,11 @@ config_buf (enum usb_device_speed speed, /*-------------------------------------------------------------------------*/ -static void eth_start (struct eth_dev *dev, unsigned gfp_flags); -static int alloc_requests (struct eth_dev *dev, unsigned n, unsigned gfp_flags); +static void eth_start (struct eth_dev *dev, gfp_t gfp_flags); +static int alloc_requests (struct eth_dev *dev, unsigned n, gfp_t gfp_flags); static int -set_ether_config (struct eth_dev *dev, unsigned gfp_flags) +set_ether_config (struct eth_dev *dev, gfp_t gfp_flags) { int result = 0; struct usb_gadget *gadget = dev->gadget; @@ -1081,7 +1081,7 @@ static void eth_reset_config (struct eth_dev *dev) * that returns config descriptors, and altsetting code. */ static int -eth_set_config (struct eth_dev *dev, unsigned number, unsigned gfp_flags) +eth_set_config (struct eth_dev *dev, unsigned number, gfp_t gfp_flags) { int result = 0; struct usb_gadget *gadget = dev->gadget; @@ -1598,7 +1598,7 @@ static void defer_kevent (struct eth_dev *dev, int flag) static void rx_complete (struct usb_ep *ep, struct usb_request *req); static int -rx_submit (struct eth_dev *dev, struct usb_request *req, unsigned gfp_flags) +rx_submit (struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags) { struct sk_buff *skb; int retval = -ENOMEM; @@ -1724,7 +1724,7 @@ clean: } static int prealloc (struct list_head *list, struct usb_ep *ep, - unsigned n, unsigned gfp_flags) + unsigned n, gfp_t gfp_flags) { unsigned i; struct usb_request *req; @@ -1763,7 +1763,7 @@ extra: return 0; } -static int alloc_requests (struct eth_dev *dev, unsigned n, unsigned gfp_flags) +static int alloc_requests (struct eth_dev *dev, unsigned n, gfp_t gfp_flags) { int status; @@ -1779,7 +1779,7 @@ fail: return status; } -static void rx_fill (struct eth_dev *dev, unsigned gfp_flags) +static void rx_fill (struct eth_dev *dev, gfp_t gfp_flags) { struct usb_request *req; unsigned long flags; @@ -1962,7 +1962,7 @@ drop: * normally just one notification will be queued. */ -static struct usb_request *eth_req_alloc (struct usb_ep *, unsigned, unsigned); +static struct usb_request *eth_req_alloc (struct usb_ep *, unsigned, gfp_t); static void eth_req_free (struct usb_ep *ep, struct usb_request *req); static void @@ -2024,7 +2024,7 @@ static int rndis_control_ack (struct net_device *net) #endif /* RNDIS */ -static void eth_start (struct eth_dev *dev, unsigned gfp_flags) +static void eth_start (struct eth_dev *dev, gfp_t gfp_flags) { DEBUG (dev, "%s\n", __FUNCTION__); @@ -2092,7 +2092,7 @@ static int eth_stop (struct net_device *net) /*-------------------------------------------------------------------------*/ static struct usb_request * -eth_req_alloc (struct usb_ep *ep, unsigned size, unsigned gfp_flags) +eth_req_alloc (struct usb_ep *ep, unsigned size, gfp_t gfp_flags) { struct usb_request *req; @@ -2533,6 +2533,7 @@ static struct usb_gadget_driver eth_driver = { .driver = { .name = (char *) shortname, + .owner = THIS_MODULE, // .shutdown = ... // .suspend = ... // .resume = ... diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index a41d9d4baee3..ea09aaa3cab6 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -224,6 +224,7 @@ #include <linux/fs.h> #include <linux/init.h> #include <linux/kernel.h> +#include <linux/kthread.h> #include <linux/limits.h> #include <linux/list.h> #include <linux/module.h> @@ -669,7 +670,6 @@ struct fsg_dev { wait_queue_head_t thread_wqh; int thread_wakeup_needed; struct completion thread_notifier; - int thread_pid; struct task_struct *thread_task; sigset_t thread_signal_mask; @@ -1084,7 +1084,6 @@ static void wakeup_thread(struct fsg_dev *fsg) static void raise_exception(struct fsg_dev *fsg, enum fsg_state new_state) { unsigned long flags; - struct task_struct *thread_task; /* Do nothing if a higher-priority exception is already in progress. * If a lower-or-equal priority exception is in progress, preempt it @@ -1093,9 +1092,9 @@ static void raise_exception(struct fsg_dev *fsg, enum fsg_state new_state) if (fsg->state <= new_state) { fsg->exception_req_tag = fsg->ep0_req_tag; fsg->state = new_state; - thread_task = fsg->thread_task; - if (thread_task) - send_sig_info(SIGUSR1, SEND_SIG_FORCED, thread_task); + if (fsg->thread_task) + send_sig_info(SIGUSR1, SEND_SIG_FORCED, + fsg->thread_task); } spin_unlock_irqrestore(&fsg->lock, flags); } @@ -3383,11 +3382,6 @@ static int fsg_main_thread(void *fsg_) { struct fsg_dev *fsg = (struct fsg_dev *) fsg_; - fsg->thread_task = current; - - /* Release all our userspace resources */ - daemonize("file-storage-gadget"); - /* Allow the thread to be killed by a signal, but set the signal mask * to block everything but INT, TERM, KILL, and USR1. */ siginitsetinv(&fsg->thread_signal_mask, sigmask(SIGINT) | @@ -3400,9 +3394,6 @@ static int fsg_main_thread(void *fsg_) * that expects a __user pointer and it will work okay. */ set_fs(get_ds()); - /* Wait for the gadget registration to finish up */ - wait_for_completion(&fsg->thread_notifier); - /* The main loop */ while (fsg->state != FSG_STATE_TERMINATED) { if (exception_in_progress(fsg) || signal_pending(current)) { @@ -3440,8 +3431,9 @@ static int fsg_main_thread(void *fsg_) spin_unlock_irq(&fsg->lock); } + spin_lock_irq(&fsg->lock); fsg->thread_task = NULL; - flush_signals(current); + spin_unlock_irq(&fsg->lock); /* In case we are exiting because of a signal, unregister the * gadget driver and close the backing file. */ @@ -3831,12 +3823,11 @@ static int __init fsg_bind(struct usb_gadget *gadget) /* Create the LUNs, open their backing files, and register the * LUN devices in sysfs. */ - fsg->luns = kmalloc(i * sizeof(struct lun), GFP_KERNEL); + fsg->luns = kzalloc(i * sizeof(struct lun), GFP_KERNEL); if (!fsg->luns) { rc = -ENOMEM; goto out; } - memset(fsg->luns, 0, i * sizeof(struct lun)); fsg->nluns = i; for (i = 0; i < fsg->nluns; ++i) { @@ -3959,10 +3950,12 @@ static int __init fsg_bind(struct usb_gadget *gadget) sprintf(&serial[i], "%02X", c); } - if ((rc = kernel_thread(fsg_main_thread, fsg, (CLONE_VM | CLONE_FS | - CLONE_FILES))) < 0) + fsg->thread_task = kthread_create(fsg_main_thread, fsg, + "file-storage-gadget"); + if (IS_ERR(fsg->thread_task)) { + rc = PTR_ERR(fsg->thread_task); goto out; - fsg->thread_pid = rc; + } INFO(fsg, DRIVER_DESC ", version: " DRIVER_VERSION "\n"); INFO(fsg, "Number of LUNs=%d\n", fsg->nluns); @@ -3994,7 +3987,12 @@ static int __init fsg_bind(struct usb_gadget *gadget) DBG(fsg, "removable=%d, stall=%d, buflen=%u\n", mod_data.removable, mod_data.can_stall, mod_data.buflen); - DBG(fsg, "I/O thread pid: %d\n", fsg->thread_pid); + DBG(fsg, "I/O thread pid: %d\n", fsg->thread_task->pid); + + set_bit(REGISTERED, &fsg->atomic_bitflags); + + /* Tell the thread to start working */ + wake_up_process(fsg->thread_task); return 0; autoconf_fail: @@ -4046,6 +4044,7 @@ static struct usb_gadget_driver fsg_driver = { .driver = { .name = (char *) shortname, + .owner = THIS_MODULE, // .release = ... // .suspend = ... // .resume = ... @@ -4057,10 +4056,9 @@ static int __init fsg_alloc(void) { struct fsg_dev *fsg; - fsg = kmalloc(sizeof *fsg, GFP_KERNEL); + fsg = kzalloc(sizeof *fsg, GFP_KERNEL); if (!fsg) return -ENOMEM; - memset(fsg, 0, sizeof *fsg); spin_lock_init(&fsg->lock); init_rwsem(&fsg->filesem); init_waitqueue_head(&fsg->thread_wqh); @@ -4086,15 +4084,9 @@ static int __init fsg_init(void) if ((rc = fsg_alloc()) != 0) return rc; fsg = the_fsg; - if ((rc = usb_gadget_register_driver(&fsg_driver)) != 0) { + if ((rc = usb_gadget_register_driver(&fsg_driver)) != 0) fsg_free(fsg); - return rc; - } - set_bit(REGISTERED, &fsg->atomic_bitflags); - - /* Tell the thread to start working */ - complete(&fsg->thread_notifier); - return 0; + return rc; } module_init(fsg_init); diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c index eaab26f4ed37..654469778ab5 100644 --- a/drivers/usb/gadget/goku_udc.c +++ b/drivers/usb/gadget/goku_udc.c @@ -269,7 +269,7 @@ static int goku_ep_disable(struct usb_ep *_ep) /*-------------------------------------------------------------------------*/ static struct usb_request * -goku_alloc_request(struct usb_ep *_ep, unsigned gfp_flags) +goku_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags) { struct goku_request *req; @@ -327,7 +327,7 @@ goku_free_request(struct usb_ep *_ep, struct usb_request *_req) */ static void * goku_alloc_buffer(struct usb_ep *_ep, unsigned bytes, - dma_addr_t *dma, unsigned gfp_flags) + dma_addr_t *dma, gfp_t gfp_flags) { void *retval; struct goku_ep *ep; @@ -789,7 +789,7 @@ finished: /*-------------------------------------------------------------------------*/ static int -goku_queue(struct usb_ep *_ep, struct usb_request *_req, unsigned gfp_flags) +goku_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) { struct goku_request *req; struct goku_ep *ep; @@ -1970,6 +1970,7 @@ MODULE_DEVICE_TABLE (pci, pci_ids); static struct pci_driver goku_pci_driver = { .name = (char *) driver_name, .id_table = pci_ids, + .owner = THIS_MODULE, .probe = goku_probe, .remove = goku_remove, diff --git a/drivers/usb/gadget/lh7a40x_udc.c b/drivers/usb/gadget/lh7a40x_udc.c index 4842577789c9..9b3673904daf 100644 --- a/drivers/usb/gadget/lh7a40x_udc.c +++ b/drivers/usb/gadget/lh7a40x_udc.c @@ -71,13 +71,13 @@ static char *state_names[] = { static int lh7a40x_ep_enable(struct usb_ep *ep, const struct usb_endpoint_descriptor *); static int lh7a40x_ep_disable(struct usb_ep *ep); -static struct usb_request *lh7a40x_alloc_request(struct usb_ep *ep, int); +static struct usb_request *lh7a40x_alloc_request(struct usb_ep *ep, gfp_t); static void lh7a40x_free_request(struct usb_ep *ep, struct usb_request *); static void *lh7a40x_alloc_buffer(struct usb_ep *ep, unsigned, dma_addr_t *, - int); + gfp_t); static void lh7a40x_free_buffer(struct usb_ep *ep, void *, dma_addr_t, unsigned); -static int lh7a40x_queue(struct usb_ep *ep, struct usb_request *, int); +static int lh7a40x_queue(struct usb_ep *ep, struct usb_request *, gfp_t); static int lh7a40x_dequeue(struct usb_ep *ep, struct usb_request *); static int lh7a40x_set_halt(struct usb_ep *ep, int); static int lh7a40x_fifo_status(struct usb_ep *ep); @@ -1106,7 +1106,7 @@ static int lh7a40x_ep_disable(struct usb_ep *_ep) } static struct usb_request *lh7a40x_alloc_request(struct usb_ep *ep, - unsigned gfp_flags) + gfp_t gfp_flags) { struct lh7a40x_request *req; @@ -1134,7 +1134,7 @@ static void lh7a40x_free_request(struct usb_ep *ep, struct usb_request *_req) } static void *lh7a40x_alloc_buffer(struct usb_ep *ep, unsigned bytes, - dma_addr_t * dma, unsigned gfp_flags) + dma_addr_t * dma, gfp_t gfp_flags) { char *retval; @@ -1158,7 +1158,7 @@ static void lh7a40x_free_buffer(struct usb_ep *ep, void *buf, dma_addr_t dma, * NOTE: Sets INDEX register */ static int lh7a40x_queue(struct usb_ep *_ep, struct usb_request *_req, - unsigned gfp_flags) + gfp_t gfp_flags) { struct lh7a40x_request *req; struct lh7a40x_ep *ep; @@ -2140,6 +2140,7 @@ static int lh7a40x_udc_remove(struct device *_dev) static struct device_driver udc_driver = { .name = (char *)driver_name, + .owner = THIS_MODULE, .bus = &platform_bus_type, .probe = lh7a40x_udc_probe, .remove = lh7a40x_udc_remove diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index 477fab2e74d1..0dc6bb00bf72 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -376,7 +376,7 @@ static int net2280_disable (struct usb_ep *_ep) /*-------------------------------------------------------------------------*/ static struct usb_request * -net2280_alloc_request (struct usb_ep *_ep, unsigned gfp_flags) +net2280_alloc_request (struct usb_ep *_ep, gfp_t gfp_flags) { struct net2280_ep *ep; struct net2280_request *req; @@ -463,7 +463,7 @@ net2280_alloc_buffer ( struct usb_ep *_ep, unsigned bytes, dma_addr_t *dma, - unsigned gfp_flags + gfp_t gfp_flags ) { void *retval; @@ -897,7 +897,7 @@ done (struct net2280_ep *ep, struct net2280_request *req, int status) /*-------------------------------------------------------------------------*/ static int -net2280_queue (struct usb_ep *_ep, struct usb_request *_req, unsigned gfp_flags) +net2280_queue (struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) { struct net2280_request *req; struct net2280_ep *ep; @@ -2948,6 +2948,7 @@ MODULE_DEVICE_TABLE (pci, pci_ids); static struct pci_driver net2280_pci_driver = { .name = (char *) driver_name, .id_table = pci_ids, + .owner = THIS_MODULE, .probe = net2280_probe, .remove = net2280_remove, diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index ff5533e69560..41c96b0afbb3 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -269,7 +269,7 @@ static int omap_ep_disable(struct usb_ep *_ep) /*-------------------------------------------------------------------------*/ static struct usb_request * -omap_alloc_request(struct usb_ep *ep, unsigned gfp_flags) +omap_alloc_request(struct usb_ep *ep, gfp_t gfp_flags) { struct omap_req *req; @@ -298,7 +298,7 @@ omap_alloc_buffer( struct usb_ep *_ep, unsigned bytes, dma_addr_t *dma, - unsigned gfp_flags + gfp_t gfp_flags ) { void *retval; @@ -691,7 +691,7 @@ static void next_out_dma(struct omap_ep *ep, struct omap_req *req) } static void -finish_out_dma(struct omap_ep *ep, struct omap_req *req, int status) +finish_out_dma(struct omap_ep *ep, struct omap_req *req, int status, int one) { u16 count; @@ -699,6 +699,8 @@ finish_out_dma(struct omap_ep *ep, struct omap_req *req, int status) ep->dma_counter = (u16) (req->req.dma + req->req.actual); count = dma_dest_len(ep, req->req.dma + req->req.actual); count += req->req.actual; + if (one) + count--; if (count <= req->req.length) req->req.actual = count; @@ -747,7 +749,7 @@ static void dma_irq(struct omap_udc *udc, u16 irq_src) if (!list_empty(&ep->queue)) { req = container_of(ep->queue.next, struct omap_req, queue); - finish_out_dma(ep, req, 0); + finish_out_dma(ep, req, 0, dman_stat & UDC_DMA_RX_SB); } UDC_IRQ_SRC_REG = UDC_RXN_EOT; @@ -925,7 +927,7 @@ static void dma_channel_release(struct omap_ep *ep) while (UDC_RXDMA_CFG_REG & mask) udelay(10); if (req) - finish_out_dma(ep, req, -ECONNRESET); + finish_out_dma(ep, req, -ECONNRESET, 0); } omap_free_dma(ep->lch); ep->dma_channel = 0; @@ -937,7 +939,7 @@ static void dma_channel_release(struct omap_ep *ep) /*-------------------------------------------------------------------------*/ static int -omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, unsigned gfp_flags) +omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) { struct omap_ep *ep = container_of(_ep, struct omap_ep, ep); struct omap_req *req = container_of(_req, struct omap_req, req); @@ -1786,8 +1788,12 @@ static void devstate_irq(struct omap_udc *udc, u16 irq_src) udc->driver->suspend(&udc->gadget); spin_lock(&udc->lock); } + if (udc->transceiver) + otg_set_suspend(udc->transceiver, 1); } else { VDBG("resume\n"); + if (udc->transceiver) + otg_set_suspend(udc->transceiver, 0); if (udc->gadget.speed == USB_SPEED_FULL && udc->driver->resume) { spin_unlock(&udc->lock); @@ -2909,12 +2915,10 @@ static int __exit omap_udc_remove(struct device *dev) * may involve talking to an external transceiver (e.g. isp1301). */ -static int omap_udc_suspend(struct device *dev, pm_message_t message, u32 level) +static int omap_udc_suspend(struct device *dev, pm_message_t message) { u32 devstat; - if (level != SUSPEND_POWER_DOWN) - return 0; devstat = UDC_DEVSTAT_REG; /* we're requesting 48 MHz clock if the pullup is enabled @@ -2931,11 +2935,8 @@ static int omap_udc_suspend(struct device *dev, pm_message_t message, u32 level) return 0; } -static int omap_udc_resume(struct device *dev, u32 level) +static int omap_udc_resume(struct device *dev) { - if (level != RESUME_POWER_ON) - return 0; - DBG("resume + wakeup/SRP\n"); omap_pullup(&udc->gadget, 1); @@ -2948,6 +2949,7 @@ static int omap_udc_resume(struct device *dev, u32 level) static struct device_driver udc_driver = { .name = (char *) driver_name, + .owner = THIS_MODULE, .bus = &platform_bus_type, .probe = omap_udc_probe, .remove = __exit_p(omap_udc_remove), diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c index 73f8c9404156..f83a9262f953 100644 --- a/drivers/usb/gadget/pxa2xx_udc.c +++ b/drivers/usb/gadget/pxa2xx_udc.c @@ -332,7 +332,7 @@ static int pxa2xx_ep_disable (struct usb_ep *_ep) * pxa2xx_ep_alloc_request - allocate a request data structure */ static struct usb_request * -pxa2xx_ep_alloc_request (struct usb_ep *_ep, unsigned gfp_flags) +pxa2xx_ep_alloc_request (struct usb_ep *_ep, gfp_t gfp_flags) { struct pxa2xx_request *req; @@ -367,7 +367,7 @@ pxa2xx_ep_free_request (struct usb_ep *_ep, struct usb_request *_req) */ static void * pxa2xx_ep_alloc_buffer(struct usb_ep *_ep, unsigned bytes, - dma_addr_t *dma, unsigned gfp_flags) + dma_addr_t *dma, gfp_t gfp_flags) { char *retval; @@ -422,7 +422,7 @@ static inline void ep0_idle (struct pxa2xx_udc *dev) } static int -write_packet(volatile unsigned long *uddr, struct pxa2xx_request *req, unsigned max) +write_packet(volatile u32 *uddr, struct pxa2xx_request *req, unsigned max) { u8 *buf; unsigned length, count; @@ -874,7 +874,7 @@ done: /*-------------------------------------------------------------------------*/ static int -pxa2xx_ep_queue(struct usb_ep *_ep, struct usb_request *_req, unsigned gfp_flags) +pxa2xx_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) { struct pxa2xx_request *req; struct pxa2xx_ep *ep; @@ -2602,24 +2602,23 @@ static int __exit pxa2xx_udc_remove(struct device *_dev) * VBUS IRQs should probably be ignored so that the PXA device just acts * "dead" to USB hosts until system resume. */ -static int pxa2xx_udc_suspend(struct device *dev, pm_message_t state, u32 level) +static int pxa2xx_udc_suspend(struct device *dev, pm_message_t state) { struct pxa2xx_udc *udc = dev_get_drvdata(dev); - if (level == SUSPEND_POWER_DOWN) { - if (!udc->mach->udc_command) - WARN("USB host won't detect disconnect!\n"); - pullup(udc, 0); - } + if (!udc->mach->udc_command) + WARN("USB host won't detect disconnect!\n"); + pullup(udc, 0); + return 0; } -static int pxa2xx_udc_resume(struct device *dev, u32 level) +static int pxa2xx_udc_resume(struct device *dev) { struct pxa2xx_udc *udc = dev_get_drvdata(dev); - if (level == RESUME_POWER_ON) - pullup(udc, 1); + pullup(udc, 1); + return 0; } @@ -2632,6 +2631,7 @@ static int pxa2xx_udc_resume(struct device *dev, u32 level) static struct device_driver udc_driver = { .name = "pxa2xx-udc", + .owner = THIS_MODULE, .bus = &platform_bus_type, .probe = pxa2xx_udc_probe, .shutdown = pxa2xx_udc_shutdown, diff --git a/drivers/usb/gadget/pxa2xx_udc.h b/drivers/usb/gadget/pxa2xx_udc.h index a58f3e6e71f1..19a883f7d1b8 100644 --- a/drivers/usb/gadget/pxa2xx_udc.h +++ b/drivers/usb/gadget/pxa2xx_udc.h @@ -69,11 +69,11 @@ struct pxa2xx_ep { * UDDR = UDC Endpoint Data Register (the fifo) * DRCM = DMA Request Channel Map */ - volatile unsigned long *reg_udccs; - volatile unsigned long *reg_ubcr; - volatile unsigned long *reg_uddr; + volatile u32 *reg_udccs; + volatile u32 *reg_ubcr; + volatile u32 *reg_uddr; #ifdef USE_DMA - volatile unsigned long *reg_drcmr; + volatile u32 *reg_drcmr; #define drcmr(n) .reg_drcmr = & DRCMR ## n , #else #define drcmr(n) diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c index c925d9222f53..b35ac6d334f8 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c @@ -300,18 +300,18 @@ static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed, u8 type, unsigned int index, int is_otg); static struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned int len, - unsigned kmalloc_flags); + gfp_t kmalloc_flags); static void gs_free_req(struct usb_ep *ep, struct usb_request *req); static struct gs_req_entry *gs_alloc_req_entry(struct usb_ep *ep, unsigned len, - unsigned kmalloc_flags); + gfp_t kmalloc_flags); static void gs_free_req_entry(struct usb_ep *ep, struct gs_req_entry *req); -static int gs_alloc_ports(struct gs_dev *dev, unsigned kmalloc_flags); +static int gs_alloc_ports(struct gs_dev *dev, gfp_t kmalloc_flags); static void gs_free_ports(struct gs_dev *dev); /* circular buffer */ -static struct gs_buf *gs_buf_alloc(unsigned int size, unsigned kmalloc_flags); +static struct gs_buf *gs_buf_alloc(unsigned int size, gfp_t kmalloc_flags); static void gs_buf_free(struct gs_buf *gb); static void gs_buf_clear(struct gs_buf *gb); static unsigned int gs_buf_data_avail(struct gs_buf *gb); @@ -2091,7 +2091,7 @@ static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed, * usb_request or NULL if there is an error. */ static struct usb_request * -gs_alloc_req(struct usb_ep *ep, unsigned int len, unsigned kmalloc_flags) +gs_alloc_req(struct usb_ep *ep, unsigned int len, gfp_t kmalloc_flags) { struct usb_request *req; @@ -2132,7 +2132,7 @@ static void gs_free_req(struct usb_ep *ep, struct usb_request *req) * endpoint, buffer len, and kmalloc flags. */ static struct gs_req_entry * -gs_alloc_req_entry(struct usb_ep *ep, unsigned len, unsigned kmalloc_flags) +gs_alloc_req_entry(struct usb_ep *ep, unsigned len, gfp_t kmalloc_flags) { struct gs_req_entry *req; @@ -2173,7 +2173,7 @@ static void gs_free_req_entry(struct usb_ep *ep, struct gs_req_entry *req) * * The device lock is normally held when calling this function. */ -static int gs_alloc_ports(struct gs_dev *dev, unsigned kmalloc_flags) +static int gs_alloc_ports(struct gs_dev *dev, gfp_t kmalloc_flags) { int i; struct gs_port *port; @@ -2255,7 +2255,7 @@ static void gs_free_ports(struct gs_dev *dev) * * Allocate a circular buffer and all associated memory. */ -static struct gs_buf *gs_buf_alloc(unsigned int size, unsigned kmalloc_flags) +static struct gs_buf *gs_buf_alloc(unsigned int size, gfp_t kmalloc_flags) { struct gs_buf *gb; diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index 6890e773b2a2..6c58636e914b 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -612,7 +612,7 @@ static void source_sink_complete (struct usb_ep *ep, struct usb_request *req) } static struct usb_request * -source_sink_start_ep (struct usb_ep *ep, unsigned gfp_flags) +source_sink_start_ep (struct usb_ep *ep, gfp_t gfp_flags) { struct usb_request *req; int status; @@ -640,7 +640,7 @@ source_sink_start_ep (struct usb_ep *ep, unsigned gfp_flags) } static int -set_source_sink_config (struct zero_dev *dev, unsigned gfp_flags) +set_source_sink_config (struct zero_dev *dev, gfp_t gfp_flags) { int result = 0; struct usb_ep *ep; @@ -744,7 +744,7 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req) } static int -set_loopback_config (struct zero_dev *dev, unsigned gfp_flags) +set_loopback_config (struct zero_dev *dev, gfp_t gfp_flags) { int result = 0; struct usb_ep *ep; @@ -845,7 +845,7 @@ static void zero_reset_config (struct zero_dev *dev) * by limiting configuration choices (like the pxa2xx). */ static int -zero_set_config (struct zero_dev *dev, unsigned number, unsigned gfp_flags) +zero_set_config (struct zero_dev *dev, unsigned number, gfp_t gfp_flags) { int result = 0; struct usb_gadget *gadget = dev->gadget; @@ -1302,6 +1302,7 @@ static struct usb_gadget_driver zero_driver = { .driver = { .name = (char *) shortname, + .owner = THIS_MODULE, // .shutdown = ... // .suspend = ... // .resume = ... diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index 350d14fc1cc9..58321d3f314c 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -1,8 +1,9 @@ # -# Makefile for USB Host Controller Driver -# framework and drivers +# Makefile for USB Host Controller Drivers # +obj-$(CONFIG_PCI) += pci-quirks.o + obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o obj-$(CONFIG_USB_ISP116X_HCD) += isp116x-hcd.o obj-$(CONFIG_USB_OHCI_HCD) += ohci-hcd.o diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index b948ffd94f45..af3c05eb86fc 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -182,6 +182,9 @@ static int ehci_halt (struct ehci_hcd *ehci) { u32 temp = readl (&ehci->regs->status); + /* disable any irqs left enabled by previous code */ + writel (0, &ehci->regs->intr_enable); + if ((temp & STS_HALT) != 0) return 0; @@ -297,50 +300,17 @@ static void ehci_watchdog (unsigned long param) spin_unlock_irqrestore (&ehci->lock, flags); } -#ifdef CONFIG_PCI - -/* EHCI 0.96 (and later) section 5.1 says how to kick BIOS/SMM/... - * off the controller (maybe it can boot from highspeed USB disks). +/* Reboot notifiers kick in for silicon on any bus (not just pci, etc). + * This forcibly disables dma and IRQs, helping kexec and other cases + * where the next system software may expect clean state. */ -static int bios_handoff (struct ehci_hcd *ehci, int where, u32 cap) -{ - struct pci_dev *pdev = to_pci_dev(ehci_to_hcd(ehci)->self.controller); - - /* always say Linux will own the hardware */ - pci_write_config_byte(pdev, where + 3, 1); - - /* maybe wait a while for BIOS to respond */ - if (cap & (1 << 16)) { - int msec = 5000; - - do { - msleep(10); - msec -= 10; - pci_read_config_dword(pdev, where, &cap); - } while ((cap & (1 << 16)) && msec); - if (cap & (1 << 16)) { - ehci_err(ehci, "BIOS handoff failed (%d, %08x)\n", - where, cap); - // some BIOS versions seem buggy... - // return 1; - ehci_warn (ehci, "continuing after BIOS bug...\n"); - /* disable all SMIs, and clear "BIOS owns" flag */ - pci_write_config_dword(pdev, where + 4, 0); - pci_write_config_byte(pdev, where + 2, 0); - } else - ehci_dbg(ehci, "BIOS handoff succeeded\n"); - } - return 0; -} - -#endif - static int ehci_reboot (struct notifier_block *self, unsigned long code, void *null) { struct ehci_hcd *ehci; ehci = container_of (self, struct ehci_hcd, reboot_notifier); + (void) ehci_halt (ehci); /* make BIOS/etc use companion controller during reboot */ writel (0, &ehci->regs->configured_flag); @@ -363,156 +333,90 @@ static void ehci_port_power (struct ehci_hcd *ehci, int is_on) msleep(20); } +/*-------------------------------------------------------------------------*/ + +/* + * ehci_work is called from some interrupts, timers, and so on. + * it calls driver completion functions, after dropping ehci->lock. + */ +static void ehci_work (struct ehci_hcd *ehci, struct pt_regs *regs) +{ + timer_action_done (ehci, TIMER_IO_WATCHDOG); + if (ehci->reclaim_ready) + end_unlink_async (ehci, regs); + + /* another CPU may drop ehci->lock during a schedule scan while + * it reports urb completions. this flag guards against bogus + * attempts at re-entrant schedule scanning. + */ + if (ehci->scanning) + return; + ehci->scanning = 1; + scan_async (ehci, regs); + if (ehci->next_uframe != -1) + scan_periodic (ehci, regs); + ehci->scanning = 0; -/* called by khubd or root hub init threads */ + /* the IO watchdog guards against hardware or driver bugs that + * misplace IRQs, and should let us run completely without IRQs. + * such lossage has been observed on both VT6202 and VT8235. + */ + if (HC_IS_RUNNING (ehci_to_hcd(ehci)->state) && + (ehci->async->qh_next.ptr != NULL || + ehci->periodic_sched != 0)) + timer_action (ehci, TIMER_IO_WATCHDOG); +} -static int ehci_hc_reset (struct usb_hcd *hcd) +static void ehci_stop (struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); - u32 temp; - unsigned count = 256/4; - spin_lock_init (&ehci->lock); + ehci_dbg (ehci, "stop\n"); - ehci->caps = hcd->regs; - ehci->regs = hcd->regs + HC_LENGTH (readl (&ehci->caps->hc_capbase)); - dbg_hcs_params (ehci, "reset"); - dbg_hcc_params (ehci, "reset"); + /* Turn off port power on all root hub ports. */ + ehci_port_power (ehci, 0); - /* cache this readonly data; minimize chip reads */ - ehci->hcs_params = readl (&ehci->caps->hcs_params); + /* no more interrupts ... */ + del_timer_sync (&ehci->watchdog); -#ifdef CONFIG_PCI - if (hcd->self.controller->bus == &pci_bus_type) { - struct pci_dev *pdev = to_pci_dev(hcd->self.controller); + spin_lock_irq(&ehci->lock); + if (HC_IS_RUNNING (hcd->state)) + ehci_quiesce (ehci); - switch (pdev->vendor) { - case PCI_VENDOR_ID_TDI: - if (pdev->device == PCI_DEVICE_ID_TDI_EHCI) { - ehci->is_tdi_rh_tt = 1; - tdi_reset (ehci); - } - break; - case PCI_VENDOR_ID_AMD: - /* AMD8111 EHCI doesn't work, according to AMD errata */ - if (pdev->device == 0x7463) { - ehci_info (ehci, "ignoring AMD8111 (errata)\n"); - return -EIO; - } - break; - case PCI_VENDOR_ID_NVIDIA: - /* NVidia reports that certain chips don't handle - * QH, ITD, or SITD addresses above 2GB. (But TD, - * data buffer, and periodic schedule are normal.) - */ - switch (pdev->device) { - case 0x003c: /* MCP04 */ - case 0x005b: /* CK804 */ - case 0x00d8: /* CK8 */ - case 0x00e8: /* CK8S */ - if (pci_set_consistent_dma_mask(pdev, - DMA_31BIT_MASK) < 0) - ehci_warn (ehci, "can't enable NVidia " - "workaround for >2GB RAM\n"); - break; - } - break; - } + ehci_reset (ehci); + writel (0, &ehci->regs->intr_enable); + spin_unlock_irq(&ehci->lock); - /* optional debug port, normally in the first BAR */ - temp = pci_find_capability (pdev, 0x0a); - if (temp) { - pci_read_config_dword(pdev, temp, &temp); - temp >>= 16; - if ((temp & (3 << 13)) == (1 << 13)) { - temp &= 0x1fff; - ehci->debug = hcd->regs + temp; - temp = readl (&ehci->debug->control); - ehci_info (ehci, "debug port %d%s\n", - HCS_DEBUG_PORT(ehci->hcs_params), - (temp & DBGP_ENABLED) - ? " IN USE" - : ""); - if (!(temp & DBGP_ENABLED)) - ehci->debug = NULL; - } - } + /* let companion controllers work when we aren't */ + writel (0, &ehci->regs->configured_flag); + unregister_reboot_notifier (&ehci->reboot_notifier); - temp = HCC_EXT_CAPS (readl (&ehci->caps->hcc_params)); - } else - temp = 0; - - /* EHCI 0.96 and later may have "extended capabilities" */ - while (temp && count--) { - u32 cap; - - pci_read_config_dword (to_pci_dev(hcd->self.controller), - temp, &cap); - ehci_dbg (ehci, "capability %04x at %02x\n", cap, temp); - switch (cap & 0xff) { - case 1: /* BIOS/SMM/... handoff */ - if (bios_handoff (ehci, temp, cap) != 0) - return -EOPNOTSUPP; - break; - case 0: /* illegal reserved capability */ - ehci_warn (ehci, "illegal capability!\n"); - cap = 0; - /* FALLTHROUGH */ - default: /* unknown */ - break; - } - temp = (cap >> 8) & 0xff; - } - if (!count) { - ehci_err (ehci, "bogus capabilities ... PCI problems!\n"); - return -EIO; - } - if (ehci_is_TDI(ehci)) - ehci_reset (ehci); -#endif + remove_debug_files (ehci); - ehci_port_power (ehci, 0); + /* root hub is shut down separately (first, when possible) */ + spin_lock_irq (&ehci->lock); + if (ehci->async) + ehci_work (ehci, NULL); + spin_unlock_irq (&ehci->lock); + ehci_mem_cleanup (ehci); - /* at least the Genesys GL880S needs fixup here */ - temp = HCS_N_CC(ehci->hcs_params) * HCS_N_PCC(ehci->hcs_params); - temp &= 0x0f; - if (temp && HCS_N_PORTS(ehci->hcs_params) > temp) { - ehci_dbg (ehci, "bogus port configuration: " - "cc=%d x pcc=%d < ports=%d\n", - HCS_N_CC(ehci->hcs_params), - HCS_N_PCC(ehci->hcs_params), - HCS_N_PORTS(ehci->hcs_params)); - -#ifdef CONFIG_PCI - if (hcd->self.controller->bus == &pci_bus_type) { - struct pci_dev *pdev; - - pdev = to_pci_dev(hcd->self.controller); - switch (pdev->vendor) { - case 0x17a0: /* GENESYS */ - /* GL880S: should be PORTS=2 */ - temp |= (ehci->hcs_params & ~0xf); - ehci->hcs_params = temp; - break; - case PCI_VENDOR_ID_NVIDIA: - /* NF4: should be PCC=10 */ - break; - } - } +#ifdef EHCI_STATS + ehci_dbg (ehci, "irq normal %ld err %ld reclaim %ld (lost %ld)\n", + ehci->stats.normal, ehci->stats.error, ehci->stats.reclaim, + ehci->stats.lost_iaa); + ehci_dbg (ehci, "complete %ld unlink %ld\n", + ehci->stats.complete, ehci->stats.unlink); #endif - } - /* force HC to halt state */ - return ehci_halt (ehci); + dbg_status (ehci, "ehci_stop completed", readl (&ehci->regs->status)); } -static int ehci_start (struct usb_hcd *hcd) +static int ehci_run (struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); u32 temp; int retval; u32 hcc_params; - u8 sbrn = 0; int first; /* skip some things on restart paths */ @@ -551,27 +455,6 @@ static int ehci_start (struct usb_hcd *hcd) } writel (ehci->periodic_dma, &ehci->regs->frame_list); -#ifdef CONFIG_PCI - if (hcd->self.controller->bus == &pci_bus_type) { - struct pci_dev *pdev; - u16 port_wake; - - pdev = to_pci_dev(hcd->self.controller); - - /* Serial Bus Release Number is at PCI 0x60 offset */ - pci_read_config_byte(pdev, 0x60, &sbrn); - - /* port wake capability, reported by boot firmware */ - pci_read_config_word(pdev, 0x62, &port_wake); - hcd->can_wakeup = (port_wake & 1) != 0; - - /* help hc dma work well with cachelines */ - retval = pci_set_mwi(pdev); - if (retval) - ehci_dbg(ehci, "unable to enable MWI - not fatal.\n"); - } -#endif - /* * dedicate a qh for the async ring head, since we couldn't unlink * a 'real' qh without stopping the async schedule [4.8]. use it @@ -667,7 +550,7 @@ static int ehci_start (struct usb_hcd *hcd) temp = HC_VERSION(readl (&ehci->caps->hc_capbase)); ehci_info (ehci, "USB %x.%x %s, EHCI %x.%02x, driver %s\n", - ((sbrn & 0xf0)>>4), (sbrn & 0x0f), + ((ehci->sbrn & 0xf0)>>4), (ehci->sbrn & 0x0f), first ? "initialized" : "restarted", temp >> 8, temp & 0xff, DRIVER_VERSION); @@ -679,188 +562,6 @@ static int ehci_start (struct usb_hcd *hcd) return 0; } -/* always called by thread; normally rmmod */ - -static void ehci_stop (struct usb_hcd *hcd) -{ - struct ehci_hcd *ehci = hcd_to_ehci (hcd); - - ehci_dbg (ehci, "stop\n"); - - /* Turn off port power on all root hub ports. */ - ehci_port_power (ehci, 0); - - /* no more interrupts ... */ - del_timer_sync (&ehci->watchdog); - - spin_lock_irq(&ehci->lock); - if (HC_IS_RUNNING (hcd->state)) - ehci_quiesce (ehci); - - ehci_reset (ehci); - writel (0, &ehci->regs->intr_enable); - spin_unlock_irq(&ehci->lock); - - /* let companion controllers work when we aren't */ - writel (0, &ehci->regs->configured_flag); - unregister_reboot_notifier (&ehci->reboot_notifier); - - remove_debug_files (ehci); - - /* root hub is shut down separately (first, when possible) */ - spin_lock_irq (&ehci->lock); - if (ehci->async) - ehci_work (ehci, NULL); - spin_unlock_irq (&ehci->lock); - ehci_mem_cleanup (ehci); - -#ifdef EHCI_STATS - ehci_dbg (ehci, "irq normal %ld err %ld reclaim %ld (lost %ld)\n", - ehci->stats.normal, ehci->stats.error, ehci->stats.reclaim, - ehci->stats.lost_iaa); - ehci_dbg (ehci, "complete %ld unlink %ld\n", - ehci->stats.complete, ehci->stats.unlink); -#endif - - dbg_status (ehci, "ehci_stop completed", readl (&ehci->regs->status)); -} - -static int ehci_get_frame (struct usb_hcd *hcd) -{ - struct ehci_hcd *ehci = hcd_to_ehci (hcd); - return (readl (&ehci->regs->frame_index) >> 3) % ehci->periodic_size; -} - -/*-------------------------------------------------------------------------*/ - -#ifdef CONFIG_PM - -/* suspend/resume, section 4.3 */ - -/* These routines rely on the bus (pci, platform, etc) - * to handle powerdown and wakeup, and currently also on - * transceivers that don't need any software attention to set up - * the right sort of wakeup. - */ - -static int ehci_suspend (struct usb_hcd *hcd, pm_message_t message) -{ - struct ehci_hcd *ehci = hcd_to_ehci (hcd); - - if (time_before (jiffies, ehci->next_statechange)) - msleep (100); - -#ifdef CONFIG_USB_SUSPEND - (void) usb_suspend_device (hcd->self.root_hub, message); -#else - usb_lock_device (hcd->self.root_hub); - (void) ehci_hub_suspend (hcd); - usb_unlock_device (hcd->self.root_hub); -#endif - - // save (PCI) FLADJ in case of Vaux power loss - // ... we'd only use it to handle clock skew - - return 0; -} - -static int ehci_resume (struct usb_hcd *hcd) -{ - struct ehci_hcd *ehci = hcd_to_ehci (hcd); - unsigned port; - struct usb_device *root = hcd->self.root_hub; - int retval = -EINVAL; - - // maybe restore (PCI) FLADJ - - if (time_before (jiffies, ehci->next_statechange)) - msleep (100); - - /* If any port is suspended (or owned by the companion), - * we know we can/must resume the HC (and mustn't reset it). - */ - for (port = HCS_N_PORTS (ehci->hcs_params); port > 0; ) { - u32 status; - port--; - status = readl (&ehci->regs->port_status [port]); - if (!(status & PORT_POWER)) - continue; - if (status & (PORT_SUSPEND | PORT_OWNER)) { - down (&hcd->self.root_hub->serialize); - retval = ehci_hub_resume (hcd); - up (&hcd->self.root_hub->serialize); - break; - } - if (!root->children [port]) - continue; - dbg_port (ehci, __FUNCTION__, port + 1, status); - usb_set_device_state (root->children[port], - USB_STATE_NOTATTACHED); - } - - /* Else reset, to cope with power loss or flush-to-storage - * style "resume" having activated BIOS during reboot. - */ - if (port == 0) { - (void) ehci_halt (ehci); - (void) ehci_reset (ehci); - (void) ehci_hc_reset (hcd); - - /* emptying the schedule aborts any urbs */ - spin_lock_irq (&ehci->lock); - if (ehci->reclaim) - ehci->reclaim_ready = 1; - ehci_work (ehci, NULL); - spin_unlock_irq (&ehci->lock); - - /* restart; khubd will disconnect devices */ - retval = ehci_start (hcd); - - /* here we "know" root ports should always stay powered; - * but some controllers may lose all power. - */ - ehci_port_power (ehci, 1); - } - - return retval; -} - -#endif - -/*-------------------------------------------------------------------------*/ - -/* - * ehci_work is called from some interrupts, timers, and so on. - * it calls driver completion functions, after dropping ehci->lock. - */ -static void ehci_work (struct ehci_hcd *ehci, struct pt_regs *regs) -{ - timer_action_done (ehci, TIMER_IO_WATCHDOG); - if (ehci->reclaim_ready) - end_unlink_async (ehci, regs); - - /* another CPU may drop ehci->lock during a schedule scan while - * it reports urb completions. this flag guards against bogus - * attempts at re-entrant schedule scanning. - */ - if (ehci->scanning) - return; - ehci->scanning = 1; - scan_async (ehci, regs); - if (ehci->next_uframe != -1) - scan_periodic (ehci, regs); - ehci->scanning = 0; - - /* the IO watchdog guards against hardware or driver bugs that - * misplace IRQs, and should let us run completely without IRQs. - * such lossage has been observed on both VT6202 and VT8235. - */ - if (HC_IS_RUNNING (ehci_to_hcd(ehci)->state) && - (ehci->async->qh_next.ptr != NULL || - ehci->periodic_sched != 0)) - timer_action (ehci, TIMER_IO_WATCHDOG); -} - /*-------------------------------------------------------------------------*/ static irqreturn_t ehci_irq (struct usb_hcd *hcd, struct pt_regs *regs) @@ -983,7 +684,7 @@ static int ehci_urb_enqueue ( struct usb_hcd *hcd, struct usb_host_endpoint *ep, struct urb *urb, - unsigned mem_flags + gfp_t mem_flags ) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); struct list_head qtd_list; @@ -1171,106 +872,24 @@ done: return; } -/*-------------------------------------------------------------------------*/ - -static const struct hc_driver ehci_driver = { - .description = hcd_name, - .product_desc = "EHCI Host Controller", - .hcd_priv_size = sizeof(struct ehci_hcd), - - /* - * generic hardware linkage - */ - .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2, - - /* - * basic lifecycle operations - */ - .reset = ehci_hc_reset, - .start = ehci_start, -#ifdef CONFIG_PM - .suspend = ehci_suspend, - .resume = ehci_resume, -#endif - .stop = ehci_stop, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ehci_urb_enqueue, - .urb_dequeue = ehci_urb_dequeue, - .endpoint_disable = ehci_endpoint_disable, - - /* - * scheduling support - */ - .get_frame_number = ehci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ehci_hub_status_data, - .hub_control = ehci_hub_control, - .hub_suspend = ehci_hub_suspend, - .hub_resume = ehci_hub_resume, -}; +static int ehci_get_frame (struct usb_hcd *hcd) +{ + struct ehci_hcd *ehci = hcd_to_ehci (hcd); + return (readl (&ehci->regs->frame_index) >> 3) % ehci->periodic_size; +} /*-------------------------------------------------------------------------*/ -/* EHCI 1.0 doesn't require PCI */ - -#ifdef CONFIG_PCI - -/* PCI driver selection metadata; PCI hotplugging uses this */ -static const struct pci_device_id pci_ids [] = { { - /* handle any USB 2.0 EHCI controller */ - PCI_DEVICE_CLASS(((PCI_CLASS_SERIAL_USB << 8) | 0x20), ~0), - .driver_data = (unsigned long) &ehci_driver, - }, - { /* end: all zeroes */ } -}; -MODULE_DEVICE_TABLE (pci, pci_ids); - -/* pci driver glue; this is a "new style" PCI driver module */ -static struct pci_driver ehci_pci_driver = { - .name = (char *) hcd_name, - .id_table = pci_ids, - - .probe = usb_hcd_pci_probe, - .remove = usb_hcd_pci_remove, - -#ifdef CONFIG_PM - .suspend = usb_hcd_pci_suspend, - .resume = usb_hcd_pci_resume, -#endif -}; - -#endif /* PCI */ - - #define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC MODULE_DESCRIPTION (DRIVER_INFO); MODULE_AUTHOR (DRIVER_AUTHOR); MODULE_LICENSE ("GPL"); -static int __init init (void) -{ - if (usb_disabled()) - return -ENODEV; - - pr_debug ("%s: block sizes: qh %Zd qtd %Zd itd %Zd sitd %Zd\n", - hcd_name, - sizeof (struct ehci_qh), sizeof (struct ehci_qtd), - sizeof (struct ehci_itd), sizeof (struct ehci_sitd)); - - return pci_register_driver (&ehci_pci_driver); -} -module_init (init); +#ifdef CONFIG_PCI +#include "ehci-pci.c" +#endif -static void __exit cleanup (void) -{ - pci_unregister_driver (&ehci_pci_driver); -} -module_exit (cleanup); +#if !defined(CONFIG_PCI) +#error "missing bus glue for ehci-hcd" +#endif diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 18d3f2270316..88cb4ada686e 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -30,7 +30,7 @@ #ifdef CONFIG_PM -static int ehci_hub_suspend (struct usb_hcd *hcd) +static int ehci_bus_suspend (struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); int port; @@ -83,7 +83,7 @@ static int ehci_hub_suspend (struct usb_hcd *hcd) /* caller has locked the root hub, and should reset/reinit on error */ -static int ehci_hub_resume (struct usb_hcd *hcd) +static int ehci_bus_resume (struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); u32 temp; @@ -159,8 +159,8 @@ static int ehci_hub_resume (struct usb_hcd *hcd) #else -#define ehci_hub_suspend NULL -#define ehci_hub_resume NULL +#define ehci_bus_suspend NULL +#define ehci_bus_resume NULL #endif /* CONFIG_PM */ diff --git a/drivers/usb/host/ehci-mem.c b/drivers/usb/host/ehci-mem.c index 5c38ad869485..91c2ab43cbcc 100644 --- a/drivers/usb/host/ehci-mem.c +++ b/drivers/usb/host/ehci-mem.c @@ -45,7 +45,7 @@ static inline void ehci_qtd_init (struct ehci_qtd *qtd, dma_addr_t dma) INIT_LIST_HEAD (&qtd->qtd_list); } -static struct ehci_qtd *ehci_qtd_alloc (struct ehci_hcd *ehci, int flags) +static struct ehci_qtd *ehci_qtd_alloc (struct ehci_hcd *ehci, gfp_t flags) { struct ehci_qtd *qtd; dma_addr_t dma; @@ -79,7 +79,7 @@ static void qh_destroy (struct kref *kref) dma_pool_free (ehci->qh_pool, qh, qh->qh_dma); } -static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, int flags) +static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, gfp_t flags) { struct ehci_qh *qh; dma_addr_t dma; @@ -161,7 +161,7 @@ static void ehci_mem_cleanup (struct ehci_hcd *ehci) } /* remember to add cleanup code (above) if you add anything here */ -static int ehci_mem_init (struct ehci_hcd *ehci, int flags) +static int ehci_mem_init (struct ehci_hcd *ehci, gfp_t flags) { int i; diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c new file mode 100644 index 000000000000..145008853966 --- /dev/null +++ b/drivers/usb/host/ehci-pci.c @@ -0,0 +1,415 @@ +/* + * EHCI HCD (Host Controller Driver) PCI Bus Glue. + * + * Copyright (c) 2000-2004 by David Brownell + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef CONFIG_PCI +#error "This file is PCI bus glue. CONFIG_PCI must be defined." +#endif + +/*-------------------------------------------------------------------------*/ + +/* EHCI 0.96 (and later) section 5.1 says how to kick BIOS/SMM/... + * off the controller (maybe it can boot from highspeed USB disks). + */ +static int bios_handoff (struct ehci_hcd *ehci, int where, u32 cap) +{ + struct pci_dev *pdev = to_pci_dev(ehci_to_hcd(ehci)->self.controller); + + /* always say Linux will own the hardware */ + pci_write_config_byte(pdev, where + 3, 1); + + /* maybe wait a while for BIOS to respond */ + if (cap & (1 << 16)) { + int msec = 5000; + + do { + msleep(10); + msec -= 10; + pci_read_config_dword(pdev, where, &cap); + } while ((cap & (1 << 16)) && msec); + if (cap & (1 << 16)) { + ehci_err(ehci, "BIOS handoff failed (%d, %08x)\n", + where, cap); + // some BIOS versions seem buggy... + // return 1; + ehci_warn (ehci, "continuing after BIOS bug...\n"); + /* disable all SMIs, and clear "BIOS owns" flag */ + pci_write_config_dword(pdev, where + 4, 0); + pci_write_config_byte(pdev, where + 2, 0); + } else + ehci_dbg(ehci, "BIOS handoff succeeded\n"); + } + return 0; +} + +/* called by khubd or root hub init threads */ +static int ehci_pci_reset (struct usb_hcd *hcd) +{ + struct ehci_hcd *ehci = hcd_to_ehci (hcd); + u32 temp; + unsigned count = 256/4; + + spin_lock_init (&ehci->lock); + + ehci->caps = hcd->regs; + ehci->regs = hcd->regs + HC_LENGTH (readl (&ehci->caps->hc_capbase)); + dbg_hcs_params (ehci, "reset"); + dbg_hcc_params (ehci, "reset"); + + /* cache this readonly data; minimize chip reads */ + ehci->hcs_params = readl (&ehci->caps->hcs_params); + + if (hcd->self.controller->bus == &pci_bus_type) { + struct pci_dev *pdev = to_pci_dev(hcd->self.controller); + + switch (pdev->vendor) { + case PCI_VENDOR_ID_TDI: + if (pdev->device == PCI_DEVICE_ID_TDI_EHCI) { + ehci->is_tdi_rh_tt = 1; + tdi_reset (ehci); + } + break; + case PCI_VENDOR_ID_AMD: + /* AMD8111 EHCI doesn't work, according to AMD errata */ + if (pdev->device == 0x7463) { + ehci_info (ehci, "ignoring AMD8111 (errata)\n"); + return -EIO; + } + break; + case PCI_VENDOR_ID_NVIDIA: + /* NVidia reports that certain chips don't handle + * QH, ITD, or SITD addresses above 2GB. (But TD, + * data buffer, and periodic schedule are normal.) + */ + switch (pdev->device) { + case 0x003c: /* MCP04 */ + case 0x005b: /* CK804 */ + case 0x00d8: /* CK8 */ + case 0x00e8: /* CK8S */ + if (pci_set_consistent_dma_mask(pdev, + DMA_31BIT_MASK) < 0) + ehci_warn (ehci, "can't enable NVidia " + "workaround for >2GB RAM\n"); + break; + } + break; + } + + /* optional debug port, normally in the first BAR */ + temp = pci_find_capability (pdev, 0x0a); + if (temp) { + pci_read_config_dword(pdev, temp, &temp); + temp >>= 16; + if ((temp & (3 << 13)) == (1 << 13)) { + temp &= 0x1fff; + ehci->debug = hcd->regs + temp; + temp = readl (&ehci->debug->control); + ehci_info (ehci, "debug port %d%s\n", + HCS_DEBUG_PORT(ehci->hcs_params), + (temp & DBGP_ENABLED) + ? " IN USE" + : ""); + if (!(temp & DBGP_ENABLED)) + ehci->debug = NULL; + } + } + + temp = HCC_EXT_CAPS (readl (&ehci->caps->hcc_params)); + } else + temp = 0; + + /* EHCI 0.96 and later may have "extended capabilities" */ + while (temp && count--) { + u32 cap; + + pci_read_config_dword (to_pci_dev(hcd->self.controller), + temp, &cap); + ehci_dbg (ehci, "capability %04x at %02x\n", cap, temp); + switch (cap & 0xff) { + case 1: /* BIOS/SMM/... handoff */ + if (bios_handoff (ehci, temp, cap) != 0) + return -EOPNOTSUPP; + break; + case 0: /* illegal reserved capability */ + ehci_warn (ehci, "illegal capability!\n"); + cap = 0; + /* FALLTHROUGH */ + default: /* unknown */ + break; + } + temp = (cap >> 8) & 0xff; + } + if (!count) { + ehci_err (ehci, "bogus capabilities ... PCI problems!\n"); + return -EIO; + } + if (ehci_is_TDI(ehci)) + ehci_reset (ehci); + + ehci_port_power (ehci, 0); + + /* at least the Genesys GL880S needs fixup here */ + temp = HCS_N_CC(ehci->hcs_params) * HCS_N_PCC(ehci->hcs_params); + temp &= 0x0f; + if (temp && HCS_N_PORTS(ehci->hcs_params) > temp) { + ehci_dbg (ehci, "bogus port configuration: " + "cc=%d x pcc=%d < ports=%d\n", + HCS_N_CC(ehci->hcs_params), + HCS_N_PCC(ehci->hcs_params), + HCS_N_PORTS(ehci->hcs_params)); + + if (hcd->self.controller->bus == &pci_bus_type) { + struct pci_dev *pdev; + + pdev = to_pci_dev(hcd->self.controller); + switch (pdev->vendor) { + case 0x17a0: /* GENESYS */ + /* GL880S: should be PORTS=2 */ + temp |= (ehci->hcs_params & ~0xf); + ehci->hcs_params = temp; + break; + case PCI_VENDOR_ID_NVIDIA: + /* NF4: should be PCC=10 */ + break; + } + } + } + + /* force HC to halt state */ + return ehci_halt (ehci); +} + +static int ehci_pci_start (struct usb_hcd *hcd) +{ + struct ehci_hcd *ehci = hcd_to_ehci (hcd); + int result = 0; + + if (hcd->self.controller->bus == &pci_bus_type) { + struct pci_dev *pdev; + u16 port_wake; + + pdev = to_pci_dev(hcd->self.controller); + + /* Serial Bus Release Number is at PCI 0x60 offset */ + pci_read_config_byte(pdev, 0x60, &ehci->sbrn); + + /* port wake capability, reported by boot firmware */ + pci_read_config_word(pdev, 0x62, &port_wake); + hcd->can_wakeup = (port_wake & 1) != 0; + + /* help hc dma work well with cachelines */ + result = pci_set_mwi(pdev); + if (result) + ehci_dbg(ehci, "unable to enable MWI - not fatal.\n"); + } + + return ehci_run (hcd); +} + +/* always called by thread; normally rmmod */ + +static void ehci_pci_stop (struct usb_hcd *hcd) +{ + ehci_stop (hcd); +} + +/*-------------------------------------------------------------------------*/ + +#ifdef CONFIG_PM + +/* suspend/resume, section 4.3 */ + +/* These routines rely on the bus (pci, platform, etc) + * to handle powerdown and wakeup, and currently also on + * transceivers that don't need any software attention to set up + * the right sort of wakeup. + */ + +static int ehci_pci_suspend (struct usb_hcd *hcd, pm_message_t message) +{ + struct ehci_hcd *ehci = hcd_to_ehci (hcd); + + if (time_before (jiffies, ehci->next_statechange)) + msleep (100); + +#ifdef CONFIG_USB_SUSPEND + (void) usb_suspend_device (hcd->self.root_hub); +#else + usb_lock_device (hcd->self.root_hub); + (void) ehci_bus_suspend (hcd); + usb_unlock_device (hcd->self.root_hub); +#endif + + // save (PCI) FLADJ in case of Vaux power loss + // ... we'd only use it to handle clock skew + + return 0; +} + +static int ehci_pci_resume (struct usb_hcd *hcd) +{ + struct ehci_hcd *ehci = hcd_to_ehci (hcd); + unsigned port; + struct usb_device *root = hcd->self.root_hub; + int retval = -EINVAL; + + // maybe restore (PCI) FLADJ + + if (time_before (jiffies, ehci->next_statechange)) + msleep (100); + + /* If any port is suspended (or owned by the companion), + * we know we can/must resume the HC (and mustn't reset it). + */ + for (port = HCS_N_PORTS (ehci->hcs_params); port > 0; ) { + u32 status; + port--; + status = readl (&ehci->regs->port_status [port]); + if (!(status & PORT_POWER)) + continue; + if (status & (PORT_SUSPEND | PORT_OWNER)) { + down (&hcd->self.root_hub->serialize); + retval = ehci_bus_resume (hcd); + up (&hcd->self.root_hub->serialize); + break; + } + if (!root->children [port]) + continue; + dbg_port (ehci, __FUNCTION__, port + 1, status); + usb_set_device_state (root->children[port], + USB_STATE_NOTATTACHED); + } + + /* Else reset, to cope with power loss or flush-to-storage + * style "resume" having activated BIOS during reboot. + */ + if (port == 0) { + (void) ehci_halt (ehci); + (void) ehci_reset (ehci); + (void) ehci_pci_reset (hcd); + + /* emptying the schedule aborts any urbs */ + spin_lock_irq (&ehci->lock); + if (ehci->reclaim) + ehci->reclaim_ready = 1; + ehci_work (ehci, NULL); + spin_unlock_irq (&ehci->lock); + + /* restart; khubd will disconnect devices */ + retval = ehci_run (hcd); + + /* here we "know" root ports should always stay powered; + * but some controllers may lose all power. + */ + ehci_port_power (ehci, 1); + } + + return retval; +} +#endif + +static const struct hc_driver ehci_pci_hc_driver = { + .description = hcd_name, + .product_desc = "EHCI Host Controller", + .hcd_priv_size = sizeof(struct ehci_hcd), + + /* + * generic hardware linkage + */ + .irq = ehci_irq, + .flags = HCD_MEMORY | HCD_USB2, + + /* + * basic lifecycle operations + */ + .reset = ehci_pci_reset, + .start = ehci_pci_start, +#ifdef CONFIG_PM + .suspend = ehci_pci_suspend, + .resume = ehci_pci_resume, +#endif + .stop = ehci_pci_stop, + + /* + * managing i/o requests and associated device resources + */ + .urb_enqueue = ehci_urb_enqueue, + .urb_dequeue = ehci_urb_dequeue, + .endpoint_disable = ehci_endpoint_disable, + + /* + * scheduling support + */ + .get_frame_number = ehci_get_frame, + + /* + * root hub support + */ + .hub_status_data = ehci_hub_status_data, + .hub_control = ehci_hub_control, + .bus_suspend = ehci_bus_suspend, + .bus_resume = ehci_bus_resume, +}; + +/*-------------------------------------------------------------------------*/ + +/* PCI driver selection metadata; PCI hotplugging uses this */ +static const struct pci_device_id pci_ids [] = { { + /* handle any USB 2.0 EHCI controller */ + PCI_DEVICE_CLASS(((PCI_CLASS_SERIAL_USB << 8) | 0x20), ~0), + .driver_data = (unsigned long) &ehci_pci_hc_driver, + }, + { /* end: all zeroes */ } +}; +MODULE_DEVICE_TABLE (pci, pci_ids); + +/* pci driver glue; this is a "new style" PCI driver module */ +static struct pci_driver ehci_pci_driver = { + .name = (char *) hcd_name, + .id_table = pci_ids, + .owner = THIS_MODULE, + + .probe = usb_hcd_pci_probe, + .remove = usb_hcd_pci_remove, + +#ifdef CONFIG_PM + .suspend = usb_hcd_pci_suspend, + .resume = usb_hcd_pci_resume, +#endif +}; + +static int __init ehci_hcd_pci_init (void) +{ + if (usb_disabled()) + return -ENODEV; + + pr_debug ("%s: block sizes: qh %Zd qtd %Zd itd %Zd sitd %Zd\n", + hcd_name, + sizeof (struct ehci_qh), sizeof (struct ehci_qtd), + sizeof (struct ehci_itd), sizeof (struct ehci_sitd)); + + return pci_register_driver (&ehci_pci_driver); +} +module_init (ehci_hcd_pci_init); + +static void __exit ehci_hcd_pci_cleanup (void) +{ + pci_unregister_driver (&ehci_pci_driver); +} +module_exit (ehci_hcd_pci_cleanup); diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 940d38ca7d91..5bb872c3496d 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -477,7 +477,7 @@ qh_urb_transaction ( struct ehci_hcd *ehci, struct urb *urb, struct list_head *head, - int flags + gfp_t flags ) { struct ehci_qtd *qtd, *qtd_prev; dma_addr_t buf; @@ -629,7 +629,7 @@ static struct ehci_qh * qh_make ( struct ehci_hcd *ehci, struct urb *urb, - int flags + gfp_t flags ) { struct ehci_qh *qh = ehci_qh_alloc (ehci, flags); u32 info1 = 0, info2 = 0; @@ -906,7 +906,7 @@ submit_async ( struct usb_host_endpoint *ep, struct urb *urb, struct list_head *qtd_list, - unsigned mem_flags + gfp_t mem_flags ) { struct ehci_qtd *qtd; int epnum; diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index ccc7300baa6d..f0c8aa1ccd5d 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -589,7 +589,7 @@ static int intr_submit ( struct usb_host_endpoint *ep, struct urb *urb, struct list_head *qtd_list, - unsigned mem_flags + gfp_t mem_flags ) { unsigned epnum; unsigned long flags; @@ -634,7 +634,7 @@ done: /* ehci_iso_stream ops work with both ITD and SITD */ static struct ehci_iso_stream * -iso_stream_alloc (unsigned mem_flags) +iso_stream_alloc (gfp_t mem_flags) { struct ehci_iso_stream *stream; @@ -851,7 +851,7 @@ iso_stream_find (struct ehci_hcd *ehci, struct urb *urb) /* ehci_iso_sched ops can be ITD-only or SITD-only */ static struct ehci_iso_sched * -iso_sched_alloc (unsigned packets, unsigned mem_flags) +iso_sched_alloc (unsigned packets, gfp_t mem_flags) { struct ehci_iso_sched *iso_sched; int size = sizeof *iso_sched; @@ -924,7 +924,7 @@ itd_urb_transaction ( struct ehci_iso_stream *stream, struct ehci_hcd *ehci, struct urb *urb, - unsigned mem_flags + gfp_t mem_flags ) { struct ehci_itd *itd; @@ -1418,7 +1418,7 @@ itd_complete ( /*-------------------------------------------------------------------------*/ static int itd_submit (struct ehci_hcd *ehci, struct urb *urb, - unsigned mem_flags) + gfp_t mem_flags) { int status = -EINVAL; unsigned long flags; @@ -1529,7 +1529,7 @@ sitd_urb_transaction ( struct ehci_iso_stream *stream, struct ehci_hcd *ehci, struct urb *urb, - unsigned mem_flags + gfp_t mem_flags ) { struct ehci_sitd *sitd; @@ -1779,7 +1779,7 @@ sitd_complete ( static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb, - unsigned mem_flags) + gfp_t mem_flags) { int status = -EINVAL; unsigned long flags; diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index f34a0516d35f..18e257c2bdb5 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -97,6 +97,7 @@ struct ehci_hcd { /* one per controller */ #else # define COUNT(x) do {} while (0) #endif + u8 sbrn; /* packed release number */ }; /* convert between an HCD pointer and the corresponding EHCI_HCD */ diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index e142056b0d2c..ddb8fc591466 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -638,7 +638,7 @@ static irqreturn_t isp116x_irq(struct usb_hcd *hcd, struct pt_regs *regs) + msecs_to_jiffies(20) + 1); if (intstat & HCINT_RD) { DBG("---- remote wakeup\n"); - schedule_work(&isp116x->rh_resume); + usb_hcd_resume_root_hub(hcd); ret = IRQ_HANDLED; } irqstat &= ~HCuPINT_OPR; @@ -694,7 +694,7 @@ static int balance(struct isp116x *isp116x, u16 period, u16 load) static int isp116x_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep, struct urb *urb, - unsigned mem_flags) + gfp_t mem_flags) { struct isp116x *isp116x = hcd_to_isp116x(hcd); struct usb_device *udev = urb->dev; @@ -1160,7 +1160,7 @@ static int isp116x_hub_control(struct usb_hcd *hcd, #ifdef CONFIG_PM -static int isp116x_hub_suspend(struct usb_hcd *hcd) +static int isp116x_bus_suspend(struct usb_hcd *hcd) { struct isp116x *isp116x = hcd_to_isp116x(hcd); unsigned long flags; @@ -1200,7 +1200,7 @@ static int isp116x_hub_suspend(struct usb_hcd *hcd) return ret; } -static int isp116x_hub_resume(struct usb_hcd *hcd) +static int isp116x_bus_resume(struct usb_hcd *hcd) { struct isp116x *isp116x = hcd_to_isp116x(hcd); u32 val; @@ -1263,21 +1263,11 @@ static int isp116x_hub_resume(struct usb_hcd *hcd) return 0; } -static void isp116x_rh_resume(void *_hcd) -{ - struct usb_hcd *hcd = _hcd; - - usb_resume_device(hcd->self.root_hub); -} #else -#define isp116x_hub_suspend NULL -#define isp116x_hub_resume NULL - -static void isp116x_rh_resume(void *_hcd) -{ -} +#define isp116x_bus_suspend NULL +#define isp116x_bus_resume NULL #endif @@ -1636,8 +1626,8 @@ static struct hc_driver isp116x_hc_driver = { .hub_status_data = isp116x_hub_status_data, .hub_control = isp116x_hub_control, - .hub_suspend = isp116x_hub_suspend, - .hub_resume = isp116x_hub_resume, + .bus_suspend = isp116x_bus_suspend, + .bus_resume = isp116x_bus_resume, }; /*----------------------------------------------------------------*/ @@ -1732,7 +1722,6 @@ static int __init isp116x_probe(struct device *dev) isp116x->addr_reg = addr_reg; spin_lock_init(&isp116x->lock); INIT_LIST_HEAD(&isp116x->async); - INIT_WORK(&isp116x->rh_resume, isp116x_rh_resume, hcd); isp116x->board = dev->platform_data; if (!isp116x->board) { @@ -1774,22 +1763,13 @@ static int __init isp116x_probe(struct device *dev) /* Suspend of platform device */ -static int isp116x_suspend(struct device *dev, pm_message_t state, u32 phase) +static int isp116x_suspend(struct device *dev, pm_message_t state) { int ret = 0; - struct usb_hcd *hcd = dev_get_drvdata(dev); - VDBG("%s: state %x, phase %x\n", __func__, state, phase); + VDBG("%s: state %x\n", __func__, state); - if (phase != SUSPEND_DISABLE && phase != SUSPEND_POWER_DOWN) - return 0; - - ret = usb_suspend_device(hcd->self.root_hub, state); - if (!ret) { - dev->power.power_state = state; - INFO("%s suspended\n", hcd_name); - } else - ERR("%s suspend failed\n", hcd_name); + dev->power.power_state = state; return ret; } @@ -1797,21 +1777,14 @@ static int isp116x_suspend(struct device *dev, pm_message_t state, u32 phase) /* Resume platform device */ -static int isp116x_resume(struct device *dev, u32 phase) +static int isp116x_resume(struct device *dev) { int ret = 0; - struct usb_hcd *hcd = dev_get_drvdata(dev); - VDBG("%s: state %x, phase %x\n", __func__, dev->power.power_state, - phase); - if (phase != RESUME_POWER_ON) - return 0; + VDBG("%s: state %x\n", __func__, dev->power.power_state); + + dev->power.power_state = PMSG_ON; - ret = usb_resume_device(hcd->self.root_hub); - if (!ret) { - dev->power.power_state = PMSG_ON; - VDBG("%s resumed\n", (char *)hcd_name); - } return ret; } diff --git a/drivers/usb/host/isp116x.h b/drivers/usb/host/isp116x.h index 58873470dcf5..c6fec96785fe 100644 --- a/drivers/usb/host/isp116x.h +++ b/drivers/usb/host/isp116x.h @@ -253,7 +253,6 @@ static const int cc_to_error[16] = { struct isp116x { spinlock_t lock; - struct work_struct rh_resume; void __iomem *addr_reg; void __iomem *data_reg; diff --git a/drivers/usb/host/ohci-au1xxx.c b/drivers/usb/host/ohci-au1xxx.c index 3981bf15c8c7..a277e258eb6c 100644 --- a/drivers/usb/host/ohci-au1xxx.c +++ b/drivers/usb/host/ohci-au1xxx.c @@ -214,6 +214,11 @@ static const struct hc_driver ohci_au1xxx_hc_driver = { */ .hub_status_data = ohci_hub_status_data, .hub_control = ohci_hub_control, +#ifdef CONFIG_PM + .bus_suspend = ohci_bus_suspend, + .bus_resume = ohci_bus_resume, +#endif + .start_port_reset = ohci_start_port_reset, }; /*-------------------------------------------------------------------------*/ @@ -259,6 +264,7 @@ static int ohci_hcd_au1xxx_drv_resume(struct device *dev) static struct device_driver ohci_hcd_au1xxx_driver = { .name = "au1xxx-ohci", + .owner = THIS_MODULE, .bus = &platform_bus_type, .probe = ohci_hcd_au1xxx_drv_probe, .remove = ohci_hcd_au1xxx_drv_remove, diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c index 7924c74f958e..7bfffcbbd226 100644 --- a/drivers/usb/host/ohci-dbg.c +++ b/drivers/usb/host/ohci-dbg.c @@ -193,10 +193,6 @@ ohci_dump_status (struct ohci_hcd *controller, char **next, unsigned *size) maybe_print_eds (controller, "donehead", ohci_readl (controller, ®s->donehead), next, size); - - /* broken fminterval means traffic won't flow! */ - ohci_dbg (controller, "fminterval %08x\n", - ohci_readl (controller, ®s->fminterval)); } #define dbg_port_sw(hc,num,value,next,size) \ diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 67c1aa5eb1c1..5c0c6c8a7a82 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -180,7 +180,7 @@ static int ohci_urb_enqueue ( struct usb_hcd *hcd, struct usb_host_endpoint *ep, struct urb *urb, - unsigned mem_flags + gfp_t mem_flags ) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); struct ed *ed; @@ -723,7 +723,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs) ohci_vdbg (ohci, "resume detect\n"); ohci_writel (ohci, OHCI_INTR_RD, ®s->intrstatus); if (hcd->state != HC_STATE_QUIESCING) - schedule_work(&ohci->rh_resume); + usb_hcd_resume_root_hub(hcd); } if (ints & OHCI_INTR_WDH) { @@ -791,7 +791,7 @@ static void ohci_stop (struct usb_hcd *hcd) /* must not be called from interrupt context */ -#if defined(CONFIG_USB_SUSPEND) || defined(CONFIG_PM) +#ifdef CONFIG_PM static int ohci_restart (struct ohci_hcd *ohci) { diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index ce7b28da7a15..e01e77bc324b 100644 --- a/drivers/usb/host/ohci-hub.c +++ b/drivers/usb/host/ohci-hub.c @@ -36,7 +36,7 @@ /*-------------------------------------------------------------------------*/ -#if defined(CONFIG_USB_SUSPEND) || defined(CONFIG_PM) +#ifdef CONFIG_PM #define OHCI_SCHED_ENABLES \ (OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_PLE|OHCI_CTRL_IE) @@ -45,7 +45,7 @@ static void dl_done_list (struct ohci_hcd *, struct pt_regs *); static void finish_unlinks (struct ohci_hcd *, u16 , struct pt_regs *); static int ohci_restart (struct ohci_hcd *ohci); -static int ohci_hub_suspend (struct usb_hcd *hcd) +static int ohci_bus_suspend (struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); int status = 0; @@ -73,7 +73,6 @@ static int ohci_hub_suspend (struct usb_hcd *hcd) ohci_dbg (ohci, "suspend root hub\n"); /* First stop any processing */ - hcd->state = HC_STATE_QUIESCING; if (ohci->hc_control & OHCI_SCHED_ENABLES) { int limit; @@ -108,7 +107,9 @@ static int ohci_hub_suspend (struct usb_hcd *hcd) else ohci->hc_control &= ~OHCI_CTRL_RWE; - /* Suspend hub */ + /* Suspend hub ... this is the "global (to this bus) suspend" mode, + * which doesn't imply ports will first be individually suspended. + */ ohci->hc_control &= ~OHCI_CTRL_HCFS; ohci->hc_control |= OHCI_USB_SUSPEND; ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); @@ -118,8 +119,9 @@ static int ohci_hub_suspend (struct usb_hcd *hcd) ohci->next_statechange = jiffies + msecs_to_jiffies (5); done: + /* external suspend vs self autosuspend ... same effect */ if (status == 0) - hcd->state = HC_STATE_SUSPENDED; + usb_hcd_suspend_root_hub(hcd); spin_unlock_irqrestore (&ohci->lock, flags); return status; } @@ -133,7 +135,7 @@ static inline struct ed *find_head (struct ed *ed) } /* caller has locked the root hub */ -static int ohci_hub_resume (struct usb_hcd *hcd) +static int ohci_bus_resume (struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); u32 temp, enables; @@ -146,7 +148,7 @@ static int ohci_hub_resume (struct usb_hcd *hcd) ohci->hc_control = ohci_readl (ohci, &ohci->regs->control); if (ohci->hc_control & (OHCI_CTRL_IR | OHCI_SCHED_ENABLES)) { - /* this can happen after suspend-to-disk */ + /* this can happen after resuming a swsusp snapshot */ if (hcd->state == HC_STATE_RESUMING) { ohci_dbg (ohci, "BIOS/SMM active, control %03x\n", ohci->hc_control); @@ -169,11 +171,12 @@ static int ohci_hub_resume (struct usb_hcd *hcd) ohci_info (ohci, "wakeup\n"); break; case OHCI_USB_OPER: - ohci_dbg (ohci, "already resumed\n"); - status = 0; + /* this can happen after resuming a swsusp snapshot */ + ohci_dbg (ohci, "snapshot resume? reinit\n"); + status = -EBUSY; break; default: /* RESET, we lost power */ - ohci_dbg (ohci, "root hub hardware reset\n"); + ohci_dbg (ohci, "lost power\n"); status = -EBUSY; } spin_unlock_irq (&ohci->lock); @@ -198,8 +201,7 @@ static int ohci_hub_resume (struct usb_hcd *hcd) } /* Some controllers (lucent erratum) need extra-long delays */ - hcd->state = HC_STATE_RESUMING; - mdelay (20 /* usb 11.5.1.10 */ + 15); + msleep (20 /* usb 11.5.1.10 */ + 12 /* 32 msec counter */ + 1); temp = ohci_readl (ohci, &ohci->regs->control); temp &= OHCI_CTRL_HCFS; @@ -273,28 +275,10 @@ static int ohci_hub_resume (struct usb_hcd *hcd) (void) ohci_readl (ohci, &ohci->regs->control); } - hcd->state = HC_STATE_RUNNING; return 0; } -static void ohci_rh_resume (void *_hcd) -{ - struct usb_hcd *hcd = _hcd; - - usb_lock_device (hcd->self.root_hub); - (void) ohci_hub_resume (hcd); - usb_unlock_device (hcd->self.root_hub); -} - -#else - -static void ohci_rh_resume (void *_hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci (_hcd); - ohci_dbg(ohci, "rh_resume ??\n"); -} - -#endif /* CONFIG_USB_SUSPEND || CONFIG_PM */ +#endif /* CONFIG_PM */ /*-------------------------------------------------------------------------*/ @@ -367,7 +351,6 @@ done: #ifdef CONFIG_PM /* save power by suspending idle root hubs; * INTR_RD wakes us when there's work - * NOTE: if we can do this, we don't need a root hub timer! */ if (can_suspend && !changed @@ -379,8 +362,7 @@ done: && usb_trylock_device (hcd->self.root_hub) ) { ohci_vdbg (ohci, "autosuspend\n"); - (void) ohci_hub_suspend (hcd); - hcd->state = HC_STATE_RUNNING; + (void) ohci_bus_suspend (hcd); usb_unlock_device (hcd->self.root_hub); } #endif @@ -554,7 +536,7 @@ static int ohci_hub_control ( temp = RH_PS_POCI; if ((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER) - schedule_work (&ohci->rh_resume); + usb_hcd_resume_root_hub(hcd); break; case USB_PORT_FEAT_C_SUSPEND: temp = RH_PS_PSSC; diff --git a/drivers/usb/host/ohci-lh7a404.c b/drivers/usb/host/ohci-lh7a404.c index 859aca7be753..238fa4ade615 100644 --- a/drivers/usb/host/ohci-lh7a404.c +++ b/drivers/usb/host/ohci-lh7a404.c @@ -193,6 +193,11 @@ static const struct hc_driver ohci_lh7a404_hc_driver = { */ .hub_status_data = ohci_hub_status_data, .hub_control = ohci_hub_control, +#ifdef CONFIG_PM + .bus_suspend = ohci_bus_suspend, + .bus_resume = ohci_bus_resume, +#endif + .start_port_reset = ohci_start_port_reset, }; /*-------------------------------------------------------------------------*/ @@ -239,6 +244,7 @@ static int ohci_hcd_lh7a404_drv_resume(struct device *dev) static struct device_driver ohci_hcd_lh7a404_driver = { .name = "lh7a404-ohci", + .owner = THIS_MODULE, .bus = &platform_bus_type, .probe = ohci_hcd_lh7a404_drv_probe, .remove = ohci_hcd_lh7a404_drv_remove, diff --git a/drivers/usb/host/ohci-mem.c b/drivers/usb/host/ohci-mem.c index fd3c4d3714bd..bfbe328a4788 100644 --- a/drivers/usb/host/ohci-mem.c +++ b/drivers/usb/host/ohci-mem.c @@ -28,7 +28,6 @@ static void ohci_hcd_init (struct ohci_hcd *ohci) ohci->next_statechange = jiffies; spin_lock_init (&ohci->lock); INIT_LIST_HEAD (&ohci->pending); - INIT_WORK (&ohci->rh_resume, ohci_rh_resume, ohci_to_hcd(ohci)); ohci->reboot_notifier.notifier_call = ohci_reboot; } @@ -84,7 +83,7 @@ dma_to_td (struct ohci_hcd *hc, dma_addr_t td_dma) /* TDs ... */ static struct td * -td_alloc (struct ohci_hcd *hc, unsigned mem_flags) +td_alloc (struct ohci_hcd *hc, gfp_t mem_flags) { dma_addr_t dma; struct td *td; @@ -118,7 +117,7 @@ td_free (struct ohci_hcd *hc, struct td *td) /* EDs ... */ static struct ed * -ed_alloc (struct ohci_hcd *hc, unsigned mem_flags) +ed_alloc (struct ohci_hcd *hc, gfp_t mem_flags) { dma_addr_t dma; struct ed *ed; diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c index d8f3ba7ad52e..49815ec4b842 100644 --- a/drivers/usb/host/ohci-omap.c +++ b/drivers/usb/host/ohci-omap.c @@ -14,6 +14,9 @@ * This file is licenced under the GPL. */ +#include <linux/signal.h> /* SA_INTERRUPT */ +#include <linux/jiffies.h> + #include <asm/hardware.h> #include <asm/io.h> #include <asm/mach-types.h> @@ -420,9 +423,9 @@ static const struct hc_driver ohci_omap_hc_driver = { */ .hub_status_data = ohci_hub_status_data, .hub_control = ohci_hub_control, -#ifdef CONFIG_USB_SUSPEND - .hub_suspend = ohci_hub_suspend, - .hub_resume = ohci_hub_resume, +#ifdef CONFIG_PM + .bus_suspend = ohci_bus_suspend, + .bus_resume = ohci_bus_resume, #endif .start_port_reset = ohci_start_port_reset, }; @@ -455,50 +458,32 @@ static int ohci_hcd_omap_drv_remove(struct device *dev) #ifdef CONFIG_PM -static int ohci_omap_suspend(struct device *dev, pm_message_t message, u32 level) +static int ohci_omap_suspend(struct device *dev, pm_message_t message) { struct ohci_hcd *ohci = hcd_to_ohci(dev_get_drvdata(dev)); - int status = -EINVAL; - - if (level != SUSPEND_POWER_DOWN) - return 0; - - down(&ohci_to_hcd(ohci)->self.root_hub->serialize); - status = ohci_hub_suspend(ohci_to_hcd(ohci)); - if (status == 0) { - omap_ohci_clock_power(0); - ohci_to_hcd(ohci)->self.root_hub->state = - USB_STATE_SUSPENDED; - ohci_to_hcd(ohci)->state = HC_STATE_SUSPENDED; - dev->power.power_state = PMSG_SUSPEND; - } - up(&ohci_to_hcd(ohci)->self.root_hub->serialize); - return status; + + if (time_before(jiffies, ohci->next_statechange)) + msleep(5); + ohci->next_statechange = jiffies; + + omap_ohci_clock_power(0); + ohci_to_hcd(ohci)->state = HC_STATE_SUSPENDED; + dev->power.power_state = PMSG_SUSPEND; + return 0; } -static int ohci_omap_resume(struct device *dev, u32 level) +static int ohci_omap_resume(struct device *dev) { struct ohci_hcd *ohci = hcd_to_ohci(dev_get_drvdata(dev)); - int status = 0; - - if (level != RESUME_POWER_ON) - return 0; if (time_before(jiffies, ohci->next_statechange)) msleep(5); ohci->next_statechange = jiffies; + omap_ohci_clock_power(1); -#ifdef CONFIG_USB_SUSPEND - /* get extra cleanup even if remote wakeup isn't in use */ - status = usb_resume_device(ohci_to_hcd(ohci)->self.root_hub); -#else - down(&ohci_to_hcd(ohci)->self.root_hub->serialize); - status = ohci_hub_resume(ohci_to_hcd(ohci)); - up(&ohci_to_hcd(ohci)->self.root_hub->serialize); -#endif - if (status == 0) - dev->power.power_state = PMSG_ON; - return status; + dev->power.power_state = PMSG_ON; + usb_hcd_resume_root_hub(dev_get_drvdata(dev)); + return 0; } #endif @@ -510,6 +495,7 @@ static int ohci_omap_resume(struct device *dev, u32 level) */ static struct device_driver ohci_hcd_omap_driver = { .name = "ohci", + .owner = THIS_MODULE, .bus = &platform_bus_type, .probe = ohci_hcd_omap_drv_probe, .remove = ohci_hcd_omap_drv_remove, diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c index eede6be098d2..7ce1d9ef0289 100644 --- a/drivers/usb/host/ohci-pci.c +++ b/drivers/usb/host/ohci-pci.c @@ -14,6 +14,8 @@ * This file is licenced under the GPL. */ +#include <linux/jiffies.h> + #ifdef CONFIG_PPC_PMAC #include <asm/machdep.h> #include <asm/pmac_feature.h> @@ -112,23 +114,13 @@ ohci_pci_start (struct usb_hcd *hcd) static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message) { - struct ohci_hcd *ohci = hcd_to_ohci (hcd); - - /* suspend root hub, hoping it keeps power during suspend */ - if (time_before (jiffies, ohci->next_statechange)) - msleep (100); - -#ifdef CONFIG_USB_SUSPEND - (void) usb_suspend_device (hcd->self.root_hub, message); -#else - usb_lock_device (hcd->self.root_hub); - (void) ohci_hub_suspend (hcd); - usb_unlock_device (hcd->self.root_hub); -#endif + /* root hub was already suspended */ - /* let things settle down a bit */ - msleep (100); - + /* FIXME these PMAC things get called in the wrong places. ASIC + * clocks should be turned off AFTER entering D3, and on BEFORE + * trying to enter D0. Evidently the PCI layer doesn't currently + * provide the right sort of platform hooks for this ... + */ #ifdef CONFIG_PPC_PMAC if (_machine == _MACH_Pmac) { struct device_node *of_node; @@ -145,9 +137,6 @@ static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message) static int ohci_pci_resume (struct usb_hcd *hcd) { - struct ohci_hcd *ohci = hcd_to_ohci (hcd); - int retval = 0; - #ifdef CONFIG_PPC_PMAC if (_machine == _MACH_Pmac) { struct device_node *of_node; @@ -159,19 +148,8 @@ static int ohci_pci_resume (struct usb_hcd *hcd) } #endif /* CONFIG_PPC_PMAC */ - /* resume root hub */ - if (time_before (jiffies, ohci->next_statechange)) - msleep (100); -#ifdef CONFIG_USB_SUSPEND - /* get extra cleanup even if remote wakeup isn't in use */ - retval = usb_resume_device (hcd->self.root_hub); -#else - usb_lock_device (hcd->self.root_hub); - retval = ohci_hub_resume (hcd); - usb_unlock_device (hcd->self.root_hub); -#endif - - return retval; + usb_hcd_resume_root_hub(hcd); + return 0; } #endif /* CONFIG_PM */ @@ -218,9 +196,9 @@ static const struct hc_driver ohci_pci_hc_driver = { */ .hub_status_data = ohci_hub_status_data, .hub_control = ohci_hub_control, -#ifdef CONFIG_USB_SUSPEND - .hub_suspend = ohci_hub_suspend, - .hub_resume = ohci_hub_resume, +#ifdef CONFIG_PM + .bus_suspend = ohci_bus_suspend, + .bus_resume = ohci_bus_resume, #endif .start_port_reset = ohci_start_port_reset, }; @@ -240,6 +218,7 @@ MODULE_DEVICE_TABLE (pci, pci_ids); static struct pci_driver ohci_pci_driver = { .name = (char *) hcd_name, .id_table = pci_ids, + .owner = THIS_MODULE, .probe = usb_hcd_pci_probe, .remove = usb_hcd_pci_remove, diff --git a/drivers/usb/host/ohci-ppc-soc.c b/drivers/usb/host/ohci-ppc-soc.c index 251533363028..4832e57ae579 100644 --- a/drivers/usb/host/ohci-ppc-soc.c +++ b/drivers/usb/host/ohci-ppc-soc.c @@ -163,9 +163,9 @@ static const struct hc_driver ohci_ppc_soc_hc_driver = { */ .hub_status_data = ohci_hub_status_data, .hub_control = ohci_hub_control, -#ifdef CONFIG_USB_SUSPEND - .hub_suspend = ohci_hub_suspend, - .hub_resume = ohci_hub_resume, +#ifdef CONFIG_PM + .bus_suspend = ohci_bus_suspend, + .bus_resume = ohci_bus_resume, #endif .start_port_reset = ohci_start_port_reset, }; @@ -193,10 +193,11 @@ static int ohci_hcd_ppc_soc_drv_remove(struct device *dev) static struct device_driver ohci_hcd_ppc_soc_driver = { .name = "ppc-soc-ohci", + .owner = THIS_MODULE, .bus = &platform_bus_type, .probe = ohci_hcd_ppc_soc_drv_probe, .remove = ohci_hcd_ppc_soc_drv_remove, -#if defined(CONFIG_USB_SUSPEND) || defined(CONFIG_PM) +#ifdef CONFIG_PM /*.suspend = ohci_hcd_ppc_soc_drv_suspend,*/ /*.resume = ohci_hcd_ppc_soc_drv_resume,*/ #endif diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c index 2fdb262d4726..f4a4aeda40b7 100644 --- a/drivers/usb/host/ohci-pxa27x.c +++ b/drivers/usb/host/ohci-pxa27x.c @@ -20,6 +20,7 @@ */ #include <linux/device.h> +#include <linux/signal.h> #include <asm/mach-types.h> #include <asm/hardware.h> #include <asm/arch/pxa-regs.h> @@ -278,10 +279,11 @@ static const struct hc_driver ohci_pxa27x_hc_driver = { */ .hub_status_data = ohci_hub_status_data, .hub_control = ohci_hub_control, -#ifdef CONFIG_USB_SUSPEND - .hub_suspend = ohci_hub_suspend, - .hub_resume = ohci_hub_resume, +#ifdef CONFIG_PM + .bus_suspend = ohci_bus_suspend, + .bus_resume = ohci_bus_resume, #endif + .start_port_reset = ohci_start_port_reset, }; /*-------------------------------------------------------------------------*/ @@ -309,7 +311,7 @@ static int ohci_hcd_pxa27x_drv_remove(struct device *dev) return 0; } -static int ohci_hcd_pxa27x_drv_suspend(struct device *dev, pm_message_t state, u32 level) +static int ohci_hcd_pxa27x_drv_suspend(struct device *dev, pm_message_t state) { // struct platform_device *pdev = to_platform_device(dev); // struct usb_hcd *hcd = dev_get_drvdata(dev); @@ -318,7 +320,7 @@ static int ohci_hcd_pxa27x_drv_suspend(struct device *dev, pm_message_t state, u return 0; } -static int ohci_hcd_pxa27x_drv_resume(struct device *dev, u32 level) +static int ohci_hcd_pxa27x_drv_resume(struct device *dev) { // struct platform_device *pdev = to_platform_device(dev); // struct usb_hcd *hcd = dev_get_drvdata(dev); diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c index da7d5478f74d..fab420a2ce71 100644 --- a/drivers/usb/host/ohci-s3c2410.c +++ b/drivers/usb/host/ohci-s3c2410.c @@ -448,11 +448,11 @@ static const struct hc_driver ohci_s3c2410_hc_driver = { */ .hub_status_data = ohci_s3c2410_hub_status_data, .hub_control = ohci_s3c2410_hub_control, - -#if defined(CONFIG_USB_SUSPEND) && 0 - .hub_suspend = ohci_hub_suspend, - .hub_resume = ohci_hub_resume, +#ifdef CONFIG_PM + .bus_suspend = ohci_bus_suspend, + .bus_resume = ohci_bus_resume, #endif + .start_port_reset = ohci_start_port_reset, }; /* device driver */ @@ -474,6 +474,7 @@ static int ohci_hcd_s3c2410_drv_remove(struct device *dev) static struct device_driver ohci_hcd_s3c2410_driver = { .name = "s3c2410-ohci", + .owner = THIS_MODULE, .bus = &platform_bus_type, .probe = ohci_hcd_s3c2410_drv_probe, .remove = ohci_hcd_s3c2410_drv_remove, diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c index 814d2be4ee7b..fb3221ebbb29 100644 --- a/drivers/usb/host/ohci-sa1111.c +++ b/drivers/usb/host/ohci-sa1111.c @@ -235,10 +235,11 @@ static const struct hc_driver ohci_sa1111_hc_driver = { */ .hub_status_data = ohci_hub_status_data, .hub_control = ohci_hub_control, -#ifdef CONFIG_USB_SUSPEND - .hub_suspend = ohci_hub_suspend, - .hub_resume = ohci_hub_resume, +#ifdef CONFIG_PM + .bus_suspend = ohci_bus_suspend, + .bus_resume = ohci_bus_resume, #endif + .start_port_reset = ohci_start_port_reset, }; /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h index 8a9b9d9209e9..caacf14371f5 100644 --- a/drivers/usb/host/ohci.h +++ b/drivers/usb/host/ohci.h @@ -389,7 +389,6 @@ struct ohci_hcd { unsigned long next_statechange; /* suspend/resume */ u32 fminterval; /* saved register */ - struct work_struct rh_resume; struct notifier_block reboot_notifier; unsigned long flags; /* for HC bugs */ diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c new file mode 100644 index 000000000000..b7fd3f644e1e --- /dev/null +++ b/drivers/usb/host/pci-quirks.c @@ -0,0 +1,296 @@ +/* + * This file contains code to reset and initialize USB host controllers. + * Some of it includes work-arounds for PCI hardware and BIOS quirks. + * It may need to run early during booting -- before USB would normally + * initialize -- to ensure that Linux doesn't use any legacy modes. + * + * Copyright (c) 1999 Martin Mares <mj@ucw.cz> + * (and others) + */ + +#include <linux/config.h> +#ifdef CONFIG_USB_DEBUG +#define DEBUG +#else +#undef DEBUG +#endif + +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/acpi.h> + + +#define UHCI_USBLEGSUP 0xc0 /* legacy support */ +#define UHCI_USBCMD 0 /* command register */ +#define UHCI_USBINTR 4 /* interrupt register */ +#define UHCI_USBLEGSUP_RWC 0x8f00 /* the R/WC bits */ +#define UHCI_USBLEGSUP_RO 0x5040 /* R/O and reserved bits */ +#define UHCI_USBCMD_RUN 0x0001 /* RUN/STOP bit */ +#define UHCI_USBCMD_HCRESET 0x0002 /* Host Controller reset */ +#define UHCI_USBCMD_EGSM 0x0008 /* Global Suspend Mode */ +#define UHCI_USBCMD_CONFIGURE 0x0040 /* Config Flag */ +#define UHCI_USBINTR_RESUME 0x0002 /* Resume interrupt enable */ + +#define OHCI_CONTROL 0x04 +#define OHCI_CMDSTATUS 0x08 +#define OHCI_INTRSTATUS 0x0c +#define OHCI_INTRENABLE 0x10 +#define OHCI_INTRDISABLE 0x14 +#define OHCI_OCR (1 << 3) /* ownership change request */ +#define OHCI_CTRL_RWC (1 << 9) /* remote wakeup connected */ +#define OHCI_CTRL_IR (1 << 8) /* interrupt routing */ +#define OHCI_INTR_OC (1 << 30) /* ownership change */ + +#define EHCI_HCC_PARAMS 0x08 /* extended capabilities */ +#define EHCI_USBCMD 0 /* command register */ +#define EHCI_USBCMD_RUN (1 << 0) /* RUN/STOP bit */ +#define EHCI_USBSTS 4 /* status register */ +#define EHCI_USBSTS_HALTED (1 << 12) /* HCHalted bit */ +#define EHCI_USBINTR 8 /* interrupt register */ +#define EHCI_USBLEGSUP 0 /* legacy support register */ +#define EHCI_USBLEGSUP_BIOS (1 << 16) /* BIOS semaphore */ +#define EHCI_USBLEGSUP_OS (1 << 24) /* OS semaphore */ +#define EHCI_USBLEGCTLSTS 4 /* legacy control/status */ +#define EHCI_USBLEGCTLSTS_SOOE (1 << 13) /* SMI on ownership change */ + + +/* + * Make sure the controller is completely inactive, unable to + * generate interrupts or do DMA. + */ +void uhci_reset_hc(struct pci_dev *pdev, unsigned long base) +{ + /* Turn off PIRQ enable and SMI enable. (This also turns off the + * BIOS's USB Legacy Support.) Turn off all the R/WC bits too. + */ + pci_write_config_word(pdev, UHCI_USBLEGSUP, UHCI_USBLEGSUP_RWC); + + /* Reset the HC - this will force us to get a + * new notification of any already connected + * ports due to the virtual disconnect that it + * implies. + */ + outw(UHCI_USBCMD_HCRESET, base + UHCI_USBCMD); + mb(); + udelay(5); + if (inw(base + UHCI_USBCMD) & UHCI_USBCMD_HCRESET) + dev_warn(&pdev->dev, "HCRESET not completed yet!\n"); + + /* Just to be safe, disable interrupt requests and + * make sure the controller is stopped. + */ + outw(0, base + UHCI_USBINTR); + outw(0, base + UHCI_USBCMD); +} +EXPORT_SYMBOL_GPL(uhci_reset_hc); + +/* + * Initialize a controller that was newly discovered or has just been + * resumed. In either case we can't be sure of its previous state. + * + * Returns: 1 if the controller was reset, 0 otherwise. + */ +int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base) +{ + u16 legsup; + unsigned int cmd, intr; + + /* + * When restarting a suspended controller, we expect all the + * settings to be the same as we left them: + * + * PIRQ and SMI disabled, no R/W bits set in USBLEGSUP; + * Controller is stopped and configured with EGSM set; + * No interrupts enabled except possibly Resume Detect. + * + * If any of these conditions are violated we do a complete reset. + */ + pci_read_config_word(pdev, UHCI_USBLEGSUP, &legsup); + if (legsup & ~(UHCI_USBLEGSUP_RO | UHCI_USBLEGSUP_RWC)) { + dev_dbg(&pdev->dev, "%s: legsup = 0x%04x\n", + __FUNCTION__, legsup); + goto reset_needed; + } + + cmd = inw(base + UHCI_USBCMD); + if ((cmd & UHCI_USBCMD_RUN) || !(cmd & UHCI_USBCMD_CONFIGURE) || + !(cmd & UHCI_USBCMD_EGSM)) { + dev_dbg(&pdev->dev, "%s: cmd = 0x%04x\n", + __FUNCTION__, cmd); + goto reset_needed; + } + + intr = inw(base + UHCI_USBINTR); + if (intr & (~UHCI_USBINTR_RESUME)) { + dev_dbg(&pdev->dev, "%s: intr = 0x%04x\n", + __FUNCTION__, intr); + goto reset_needed; + } + return 0; + +reset_needed: + dev_dbg(&pdev->dev, "Performing full reset\n"); + uhci_reset_hc(pdev, base); + return 1; +} +EXPORT_SYMBOL_GPL(uhci_check_and_reset_hc); + +static void __devinit quirk_usb_handoff_uhci(struct pci_dev *pdev) +{ + unsigned long base = 0; + int i; + + for (i = 0; i < PCI_ROM_RESOURCE; i++) + if ((pci_resource_flags(pdev, i) & IORESOURCE_IO)) { + base = pci_resource_start(pdev, i); + break; + } + + if (base) + uhci_check_and_reset_hc(pdev, base); +} + +static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev) +{ + void __iomem *base; + int wait_time; + u32 control; + + base = ioremap_nocache(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + if (base == NULL) return; + +/* On PA-RISC, PDC can leave IR set incorrectly; ignore it there. */ +#ifndef __hppa__ + control = readl(base + OHCI_CONTROL); + if (control & OHCI_CTRL_IR) { + wait_time = 500; /* arbitrary; 5 seconds */ + writel(OHCI_INTR_OC, base + OHCI_INTRENABLE); + writel(OHCI_OCR, base + OHCI_CMDSTATUS); + while (wait_time > 0 && + readl(base + OHCI_CONTROL) & OHCI_CTRL_IR) { + wait_time -= 10; + msleep(10); + } + if (wait_time <= 0) + printk(KERN_WARNING "%s %s: early BIOS handoff " + "failed (BIOS bug ?)\n", + pdev->dev.bus_id, "OHCI"); + + /* reset controller, preserving RWC */ + writel(control & OHCI_CTRL_RWC, base + OHCI_CONTROL); + } +#endif + + /* + * disable interrupts + */ + writel(~(u32)0, base + OHCI_INTRDISABLE); + writel(~(u32)0, base + OHCI_INTRSTATUS); + + iounmap(base); +} + +static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev) +{ + int wait_time, delta; + void __iomem *base, *op_reg_base; + u32 hcc_params, val, temp; + u8 cap_length; + + base = ioremap_nocache(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + if (base == NULL) return; + + cap_length = readb(base); + op_reg_base = base + cap_length; + hcc_params = readl(base + EHCI_HCC_PARAMS); + hcc_params = (hcc_params >> 8) & 0xff; + if (hcc_params) { + pci_read_config_dword(pdev, + hcc_params + EHCI_USBLEGSUP, + &val); + if (((val & 0xff) == 1) && (val & EHCI_USBLEGSUP_BIOS)) { + /* + * Ok, BIOS is in smm mode, try to hand off... + */ + pci_read_config_dword(pdev, + hcc_params + EHCI_USBLEGCTLSTS, + &temp); + pci_write_config_dword(pdev, + hcc_params + EHCI_USBLEGCTLSTS, + temp | EHCI_USBLEGCTLSTS_SOOE); + val |= EHCI_USBLEGSUP_OS; + pci_write_config_dword(pdev, + hcc_params + EHCI_USBLEGSUP, + val); + + wait_time = 500; + do { + msleep(10); + wait_time -= 10; + pci_read_config_dword(pdev, + hcc_params + EHCI_USBLEGSUP, + &val); + } while (wait_time && (val & EHCI_USBLEGSUP_BIOS)); + if (!wait_time) { + /* + * well, possibly buggy BIOS... + */ + printk(KERN_WARNING "%s %s: early BIOS handoff " + "failed (BIOS bug ?)\n", + pdev->dev.bus_id, "EHCI"); + pci_write_config_dword(pdev, + hcc_params + EHCI_USBLEGSUP, + EHCI_USBLEGSUP_OS); + pci_write_config_dword(pdev, + hcc_params + EHCI_USBLEGCTLSTS, + 0); + } + } + } + + /* + * halt EHCI & disable its interrupts in any case + */ + val = readl(op_reg_base + EHCI_USBSTS); + if ((val & EHCI_USBSTS_HALTED) == 0) { + val = readl(op_reg_base + EHCI_USBCMD); + val &= ~EHCI_USBCMD_RUN; + writel(val, op_reg_base + EHCI_USBCMD); + + wait_time = 2000; + delta = 100; + do { + writel(0x3f, op_reg_base + EHCI_USBSTS); + udelay(delta); + wait_time -= delta; + val = readl(op_reg_base + EHCI_USBSTS); + if ((val == ~(u32)0) || (val & EHCI_USBSTS_HALTED)) { + break; + } + } while (wait_time > 0); + } + writel(0, op_reg_base + EHCI_USBINTR); + writel(0x3f, op_reg_base + EHCI_USBSTS); + + iounmap(base); + + return; +} + + + +static void __devinit quirk_usb_early_handoff(struct pci_dev *pdev) +{ + if (pdev->class == PCI_CLASS_SERIAL_USB_UHCI) + quirk_usb_handoff_uhci(pdev); + else if (pdev->class == PCI_CLASS_SERIAL_USB_OHCI) + quirk_usb_handoff_ohci(pdev); + else if (pdev->class == PCI_CLASS_SERIAL_USB_EHCI) + quirk_usb_disable_ehci(pdev); +} +DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, quirk_usb_early_handoff); diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index d42a15d10a46..40169d9cf2b1 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -818,7 +818,7 @@ static int sl811h_urb_enqueue( struct usb_hcd *hcd, struct usb_host_endpoint *hep, struct urb *urb, - unsigned mem_flags + gfp_t mem_flags ) { struct sl811 *sl811 = hcd_to_sl811(hcd); struct usb_device *udev = urb->dev; @@ -1363,7 +1363,7 @@ error: #ifdef CONFIG_PM static int -sl811h_hub_suspend(struct usb_hcd *hcd) +sl811h_bus_suspend(struct usb_hcd *hcd) { // SOFs off DBG("%s\n", __FUNCTION__); @@ -1371,7 +1371,7 @@ sl811h_hub_suspend(struct usb_hcd *hcd) } static int -sl811h_hub_resume(struct usb_hcd *hcd) +sl811h_bus_resume(struct usb_hcd *hcd) { // SOFs on DBG("%s\n", __FUNCTION__); @@ -1380,8 +1380,8 @@ sl811h_hub_resume(struct usb_hcd *hcd) #else -#define sl811h_hub_suspend NULL -#define sl811h_hub_resume NULL +#define sl811h_bus_suspend NULL +#define sl811h_bus_resume NULL #endif @@ -1623,8 +1623,8 @@ static struct hc_driver sl811h_hc_driver = { */ .hub_status_data = sl811h_hub_status_data, .hub_control = sl811h_hub_control, - .hub_suspend = sl811h_hub_suspend, - .hub_resume = sl811h_hub_resume, + .bus_suspend = sl811h_bus_suspend, + .bus_resume = sl811h_bus_resume, }; /*-------------------------------------------------------------------------*/ @@ -1784,17 +1784,14 @@ sl811h_probe(struct device *dev) */ static int -sl811h_suspend(struct device *dev, pm_message_t state, u32 phase) +sl811h_suspend(struct device *dev, pm_message_t state) { struct usb_hcd *hcd = dev_get_drvdata(dev); struct sl811 *sl811 = hcd_to_sl811(hcd); int retval = 0; - if (phase != SUSPEND_POWER_DOWN) - return retval; - if (state.event == PM_EVENT_FREEZE) - retval = sl811h_hub_suspend(hcd); + retval = sl811h_bus_suspend(hcd); else if (state.event == PM_EVENT_SUSPEND) port_power(sl811, 0); if (retval == 0) @@ -1803,14 +1800,11 @@ sl811h_suspend(struct device *dev, pm_message_t state, u32 phase) } static int -sl811h_resume(struct device *dev, u32 phase) +sl811h_resume(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); struct sl811 *sl811 = hcd_to_sl811(hcd); - if (phase != RESUME_POWER_ON) - return 0; - /* with no "check to see if VBUS is still powered" board hook, * let's assume it'd only be powered to enable remote wakeup. */ @@ -1822,7 +1816,7 @@ sl811h_resume(struct device *dev, u32 phase) } dev->power.power_state = PMSG_ON; - return sl811h_hub_resume(hcd); + return sl811h_bus_resume(hcd); } #else @@ -1837,6 +1831,7 @@ sl811h_resume(struct device *dev, u32 phase) struct device_driver sl811h_driver = { .name = (char *) hcd_name, .bus = &platform_bus_type, + .owner = THIS_MODULE, .probe = sl811h_probe, .remove = __devexit_p(sl811h_remove), diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c index 4538a98b6f9d..151154df37fa 100644 --- a/drivers/usb/host/uhci-debug.c +++ b/drivers/usb/host/uhci-debug.c @@ -348,7 +348,6 @@ static int uhci_show_urbp(struct uhci_hcd *uhci, struct urb_priv *urbp, char *bu if (urbp->urb->status != -EINPROGRESS) out += sprintf(out, "Status=%d ", urbp->urb->status); - //out += sprintf(out, "Inserttime=%lx ",urbp->inserttime); //out += sprintf(out, "FSBRtime=%lx ",urbp->fsbrtime); count = 0; @@ -446,11 +445,11 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len) out += sprintf(out, "Frame List\n"); for (i = 0; i < UHCI_NUMFRAMES; ++i) { int shown = 0; - td = uhci->fl->frame_cpu[i]; + td = uhci->frame_cpu[i]; if (!td) continue; - if (td->dma_handle != (dma_addr_t)uhci->fl->frame[i]) { + if (td->dma_handle != (dma_addr_t)uhci->frame[i]) { show_frame_num(); out += sprintf(out, " frame list does not match td->dma_handle!\n"); } diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 0c024898cbea..15e0a511069b 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -101,37 +101,16 @@ static void uhci_get_current_frame_number(struct uhci_hcd *uhci); #include "uhci-q.c" #include "uhci-hub.c" +extern void uhci_reset_hc(struct pci_dev *pdev, unsigned long base); +extern int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base); + /* - * Make sure the controller is completely inactive, unable to - * generate interrupts or do DMA. + * Finish up a host controller reset and update the recorded state. */ -static void reset_hc(struct uhci_hcd *uhci) +static void finish_reset(struct uhci_hcd *uhci) { int port; - /* Turn off PIRQ enable and SMI enable. (This also turns off the - * BIOS's USB Legacy Support.) Turn off all the R/WC bits too. - */ - pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, - USBLEGSUP_RWC); - - /* Reset the HC - this will force us to get a - * new notification of any already connected - * ports due to the virtual disconnect that it - * implies. - */ - outw(USBCMD_HCRESET, uhci->io_addr + USBCMD); - mb(); - udelay(5); - if (inw(uhci->io_addr + USBCMD) & USBCMD_HCRESET) - dev_warn(uhci_dev(uhci), "HCRESET not completed yet!\n"); - - /* Just to be safe, disable interrupt requests and - * make sure the controller is stopped. - */ - outw(0, uhci->io_addr + USBINTR); - outw(0, uhci->io_addr + USBCMD); - /* HCRESET doesn't affect the Suspend, Reset, and Resume Detect * bits in the port status and control registers. * We have to clear them by hand. @@ -153,7 +132,8 @@ static void reset_hc(struct uhci_hcd *uhci) */ static void hc_died(struct uhci_hcd *uhci) { - reset_hc(uhci); + uhci_reset_hc(to_pci_dev(uhci_dev(uhci)), uhci->io_addr); + finish_reset(uhci); uhci->hc_inaccessible = 1; } @@ -163,44 +143,8 @@ static void hc_died(struct uhci_hcd *uhci) */ static void check_and_reset_hc(struct uhci_hcd *uhci) { - u16 legsup; - unsigned int cmd, intr; - - /* - * When restarting a suspended controller, we expect all the - * settings to be the same as we left them: - * - * PIRQ and SMI disabled, no R/W bits set in USBLEGSUP; - * Controller is stopped and configured with EGSM set; - * No interrupts enabled except possibly Resume Detect. - * - * If any of these conditions are violated we do a complete reset. - */ - pci_read_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, &legsup); - if (legsup & ~(USBLEGSUP_RO | USBLEGSUP_RWC)) { - dev_dbg(uhci_dev(uhci), "%s: legsup = 0x%04x\n", - __FUNCTION__, legsup); - goto reset_needed; - } - - cmd = inw(uhci->io_addr + USBCMD); - if ((cmd & USBCMD_RS) || !(cmd & USBCMD_CF) || !(cmd & USBCMD_EGSM)) { - dev_dbg(uhci_dev(uhci), "%s: cmd = 0x%04x\n", - __FUNCTION__, cmd); - goto reset_needed; - } - - intr = inw(uhci->io_addr + USBINTR); - if (intr & (~USBINTR_RESUME)) { - dev_dbg(uhci_dev(uhci), "%s: intr = 0x%04x\n", - __FUNCTION__, intr); - goto reset_needed; - } - return; - -reset_needed: - dev_dbg(uhci_dev(uhci), "Performing full reset\n"); - reset_hc(uhci); + if (uhci_check_and_reset_hc(to_pci_dev(uhci_dev(uhci)), uhci->io_addr)) + finish_reset(uhci); } /* @@ -212,13 +156,13 @@ static void configure_hc(struct uhci_hcd *uhci) outb(USBSOF_DEFAULT, uhci->io_addr + USBSOF); /* Store the frame list base address */ - outl(uhci->fl->dma_handle, uhci->io_addr + USBFLBASEADD); + outl(uhci->frame_dma_handle, uhci->io_addr + USBFLBASEADD); /* Set the current frame number */ outw(uhci->frame_number, uhci->io_addr + USBFRNUM); - /* Mark controller as running before we enable interrupts */ - uhci_to_hcd(uhci)->state = HC_STATE_RUNNING; + /* Mark controller as not halted before we enable interrupts */ + uhci_to_hcd(uhci)->state = HC_STATE_SUSPENDED; mb(); /* Enable PIRQ */ @@ -319,6 +263,7 @@ __acquires(uhci->lock) static void start_rh(struct uhci_hcd *uhci) { + uhci_to_hcd(uhci)->state = HC_STATE_RUNNING; uhci->is_stopped = 0; smp_wmb(); @@ -437,36 +382,21 @@ static void release_uhci(struct uhci_hcd *uhci) int i; for (i = 0; i < UHCI_NUM_SKELQH; i++) - if (uhci->skelqh[i]) { - uhci_free_qh(uhci, uhci->skelqh[i]); - uhci->skelqh[i] = NULL; - } + uhci_free_qh(uhci, uhci->skelqh[i]); - if (uhci->term_td) { - uhci_free_td(uhci, uhci->term_td); - uhci->term_td = NULL; - } + uhci_free_td(uhci, uhci->term_td); - if (uhci->qh_pool) { - dma_pool_destroy(uhci->qh_pool); - uhci->qh_pool = NULL; - } + dma_pool_destroy(uhci->qh_pool); - if (uhci->td_pool) { - dma_pool_destroy(uhci->td_pool); - uhci->td_pool = NULL; - } + dma_pool_destroy(uhci->td_pool); - if (uhci->fl) { - dma_free_coherent(uhci_dev(uhci), sizeof(*uhci->fl), - uhci->fl, uhci->fl->dma_handle); - uhci->fl = NULL; - } + kfree(uhci->frame_cpu); - if (uhci->dentry) { - debugfs_remove(uhci->dentry); - uhci->dentry = NULL; - } + dma_free_coherent(uhci_dev(uhci), + UHCI_NUMFRAMES * sizeof(*uhci->frame), + uhci->frame, uhci->frame_dma_handle); + + debugfs_remove(uhci->dentry); } static int uhci_reset(struct usb_hcd *hcd) @@ -545,7 +475,6 @@ static int uhci_start(struct usb_hcd *hcd) struct uhci_hcd *uhci = hcd_to_uhci(hcd); int retval = -EBUSY; int i; - dma_addr_t dma_handle; struct dentry *dentry; hcd->uses_new_polling = 1; @@ -579,17 +508,23 @@ static int uhci_start(struct usb_hcd *hcd) init_waitqueue_head(&uhci->waitqh); - uhci->fl = dma_alloc_coherent(uhci_dev(uhci), sizeof(*uhci->fl), - &dma_handle, 0); - if (!uhci->fl) { + uhci->frame = dma_alloc_coherent(uhci_dev(uhci), + UHCI_NUMFRAMES * sizeof(*uhci->frame), + &uhci->frame_dma_handle, 0); + if (!uhci->frame) { dev_err(uhci_dev(uhci), "unable to allocate " "consistent memory for frame list\n"); - goto err_alloc_fl; + goto err_alloc_frame; } + memset(uhci->frame, 0, UHCI_NUMFRAMES * sizeof(*uhci->frame)); - memset((void *)uhci->fl, 0, sizeof(*uhci->fl)); - - uhci->fl->dma_handle = dma_handle; + uhci->frame_cpu = kcalloc(UHCI_NUMFRAMES, sizeof(*uhci->frame_cpu), + GFP_KERNEL); + if (!uhci->frame_cpu) { + dev_err(uhci_dev(uhci), "unable to allocate " + "memory for frame pointers\n"); + goto err_alloc_frame_cpu; + } uhci->td_pool = dma_pool_create("uhci_td", uhci_dev(uhci), sizeof(struct uhci_td), 16, 0); @@ -672,7 +607,7 @@ static int uhci_start(struct usb_hcd *hcd) irq = 7; /* Only place we don't use the frame list routines */ - uhci->fl->frame[i] = UHCI_PTR_QH | + uhci->frame[i] = UHCI_PTR_QH | cpu_to_le32(uhci->skelqh[irq]->dma_handle); } @@ -690,31 +625,29 @@ static int uhci_start(struct usb_hcd *hcd) * error exits: */ err_alloc_skelqh: - for (i = 0; i < UHCI_NUM_SKELQH; i++) - if (uhci->skelqh[i]) { + for (i = 0; i < UHCI_NUM_SKELQH; i++) { + if (uhci->skelqh[i]) uhci_free_qh(uhci, uhci->skelqh[i]); - uhci->skelqh[i] = NULL; - } + } uhci_free_td(uhci, uhci->term_td); - uhci->term_td = NULL; err_alloc_term_td: dma_pool_destroy(uhci->qh_pool); - uhci->qh_pool = NULL; err_create_qh_pool: dma_pool_destroy(uhci->td_pool); - uhci->td_pool = NULL; err_create_td_pool: - dma_free_coherent(uhci_dev(uhci), sizeof(*uhci->fl), - uhci->fl, uhci->fl->dma_handle); - uhci->fl = NULL; + kfree(uhci->frame_cpu); + +err_alloc_frame_cpu: + dma_free_coherent(uhci_dev(uhci), + UHCI_NUMFRAMES * sizeof(*uhci->frame), + uhci->frame, uhci->frame_dma_handle); -err_alloc_fl: +err_alloc_frame: debugfs_remove(uhci->dentry); - uhci->dentry = NULL; err_create_debug_entry: return retval; @@ -726,7 +659,7 @@ static void uhci_stop(struct usb_hcd *hcd) spin_lock_irq(&uhci->lock); if (!uhci->hc_inaccessible) - reset_hc(uhci); + hc_died(uhci); uhci_scan_schedule(uhci, NULL); spin_unlock_irq(&uhci->lock); @@ -774,14 +707,8 @@ static int uhci_suspend(struct usb_hcd *hcd, pm_message_t message) if (uhci->hc_inaccessible) /* Dead or already suspended */ goto done; -#ifndef CONFIG_USB_SUSPEND - /* Otherwise this would never happen */ - suspend_rh(uhci, UHCI_RH_SUSPENDED); -#endif - if (uhci->rh_state > UHCI_RH_SUSPENDED) { dev_warn(uhci_dev(uhci), "Root hub isn't suspended!\n"); - hcd->state = HC_STATE_RUNNING; rc = -EBUSY; goto done; }; @@ -820,10 +747,6 @@ static int uhci_resume(struct usb_hcd *hcd) check_and_reset_hc(uhci); configure_hc(uhci); -#ifndef CONFIG_USB_SUSPEND - /* Otherwise this would never happen */ - wakeup_rh(uhci); -#endif if (uhci->rh_state == UHCI_RH_RESET) suspend_rh(uhci, UHCI_RH_SUSPENDED); @@ -881,8 +804,8 @@ static const struct hc_driver uhci_driver = { #ifdef CONFIG_PM .suspend = uhci_suspend, .resume = uhci_resume, - .hub_suspend = uhci_rh_suspend, - .hub_resume = uhci_rh_resume, + .bus_suspend = uhci_rh_suspend, + .bus_resume = uhci_rh_resume, #endif .stop = uhci_stop, @@ -908,6 +831,7 @@ MODULE_DEVICE_TABLE(pci, uhci_pci_ids); static struct pci_driver uhci_pci_driver = { .name = (char *)hcd_name, .id_table = uhci_pci_ids, + .owner = THIS_MODULE, .probe = usb_hcd_pci_probe, .remove = usb_hcd_pci_remove, diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h index 282f40b75881..e576db57a926 100644 --- a/drivers/usb/host/uhci-hcd.h +++ b/drivers/usb/host/uhci-hcd.h @@ -7,6 +7,7 @@ #define usb_packetid(pipe) (usb_pipein(pipe) ? USB_PID_IN : USB_PID_OUT) #define PIPE_DEVEP_MASK 0x0007ff00 + /* * Universal Host Controller Interface data structures and defines */ @@ -82,15 +83,10 @@ #define UHCI_MAX_SOF_NUMBER 2047 /* in an SOF packet */ #define CAN_SCHEDULE_FRAMES 1000 /* how far future frames can be scheduled */ -struct uhci_frame_list { - __le32 frame[UHCI_NUMFRAMES]; - - void *frame_cpu[UHCI_NUMFRAMES]; - - dma_addr_t dma_handle; -}; -struct urb_priv; +/* + * Queue Headers + */ /* * One role of a QH is to hold a queue of TDs for some endpoint. Each QH is @@ -116,13 +112,13 @@ struct uhci_qh { struct urb_priv *urbp; - struct list_head list; /* P: uhci->frame_list_lock */ - struct list_head remove_list; /* P: uhci->remove_list_lock */ + struct list_head list; + struct list_head remove_list; } __attribute__((aligned(16))); /* * We need a special accessor for the element pointer because it is - * subject to asynchronous updates by the controller + * subject to asynchronous updates by the controller. */ static __le32 inline qh_element(struct uhci_qh *qh) { __le32 element = qh->element; @@ -131,6 +127,11 @@ static __le32 inline qh_element(struct uhci_qh *qh) { return element; } + +/* + * Transfer Descriptors + */ + /* * for TD <status>: */ @@ -183,17 +184,10 @@ static __le32 inline qh_element(struct uhci_qh *qh) { * * That's silly, the hardware doesn't care. The hardware only cares that * the hardware words are 16-byte aligned, and we can have any amount of - * sw space after the TD entry as far as I can tell. - * - * But let's just go with the documentation, at least for 32-bit machines. - * On 64-bit machines we probably want to take advantage of the fact that - * hw doesn't really care about the size of the sw-only area. - * - * Alas, not anymore, we have more than 4 words for software, woops. - * Everything still works tho, surprise! -jerdfelt + * sw space after the TD entry. * * td->link points to either another TD (not necessarily for the same urb or - * even the same endpoint), or nothing (PTR_TERM), or a QH (for queued urbs) + * even the same endpoint), or nothing (PTR_TERM), or a QH (for queued urbs). */ struct uhci_td { /* Hardware fields */ @@ -205,18 +199,16 @@ struct uhci_td { /* Software fields */ dma_addr_t dma_handle; - struct urb *urb; - - struct list_head list; /* P: urb->lock */ - struct list_head remove_list; /* P: uhci->td_remove_list_lock */ + struct list_head list; + struct list_head remove_list; int frame; /* for iso: what frame? */ - struct list_head fl_list; /* P: uhci->frame_list_lock */ + struct list_head fl_list; } __attribute__((aligned(16))); /* * We need a special accessor for the control/status word because it is - * subject to asynchronous updates by the controller + * subject to asynchronous updates by the controller. */ static u32 inline td_status(struct uhci_td *td) { __le32 status = td->status; @@ -227,6 +219,10 @@ static u32 inline td_status(struct uhci_td *td) { /* + * Skeleton Queue Headers + */ + +/* * The UHCI driver places Interrupt, Control and Bulk into QH's both * to group together TD's for one transfer, and also to faciliate queuing * of URB's. To make it easy to insert entries into the schedule, we have @@ -256,15 +252,15 @@ static u32 inline td_status(struct uhci_td *td) { * * The terminating QH is used for 2 reasons: * - To place a terminating TD which is used to workaround a PIIX bug - * (see Intel errata for explanation) + * (see Intel errata for explanation), and * - To loop back to the full-speed control queue for full-speed bandwidth - * reclamation + * reclamation. * * Isochronous transfers are stored before the start of the skeleton * schedule and don't use QH's. While the UHCI spec doesn't forbid the - * use of QH's for Isochronous, it doesn't use them either. Since we don't - * need to use them either, we follow the spec diagrams in hope that it'll - * be more compatible with future UHCI implementations. + * use of QH's for Isochronous, it doesn't use them either. And the spec + * says that queues never advance on an error completion status, which + * makes them totally unsuitable for Isochronous transfers. */ #define UHCI_NUM_SKELQH 12 @@ -314,8 +310,13 @@ static inline int __interval_to_skel(int interval) return 0; /* int128 for 128-255 ms (Max.) */ } + +/* + * The UHCI controller and root hub + */ + /* - * States for the root hub. + * States for the root hub: * * To prevent "bouncing" in the presence of electrical noise, * when there are no devices attached we delay for 1 second in the @@ -326,7 +327,7 @@ static inline int __interval_to_skel(int interval) */ enum uhci_rh_state { /* In the following states the HC must be halted. - * These two must come first */ + * These two must come first. */ UHCI_RH_RESET, UHCI_RH_SUSPENDED, @@ -338,13 +339,13 @@ enum uhci_rh_state { UHCI_RH_SUSPENDING, /* In the following states it's an error if the HC is halted. - * These two must come last */ + * These two must come last. */ UHCI_RH_RUNNING, /* The normal state */ UHCI_RH_RUNNING_NODEVS, /* Running with no devices attached */ }; /* - * This describes the full uhci information. + * The full UHCI controller information: */ struct uhci_hcd { @@ -361,7 +362,11 @@ struct uhci_hcd { struct uhci_qh *skelqh[UHCI_NUM_SKELQH]; /* Skeleton QH's */ spinlock_t lock; - struct uhci_frame_list *fl; /* P: uhci->lock */ + + dma_addr_t frame_dma_handle; /* Hardware frame list */ + __le32 *frame; + void **frame_cpu; /* CPU's frame list */ + int fsbr; /* Full-speed bandwidth reclamation */ unsigned long fsbrtimeout; /* FSBR delay */ @@ -385,22 +390,22 @@ struct uhci_hcd { unsigned long ports_timeout; /* Time to stop signalling */ /* Main list of URB's currently controlled by this HC */ - struct list_head urb_list; /* P: uhci->lock */ + struct list_head urb_list; /* List of QH's that are done, but waiting to be unlinked (race) */ - struct list_head qh_remove_list; /* P: uhci->lock */ + struct list_head qh_remove_list; unsigned int qh_remove_age; /* Age in frames */ /* List of TD's that are done, but waiting to be freed (race) */ - struct list_head td_remove_list; /* P: uhci->lock */ + struct list_head td_remove_list; unsigned int td_remove_age; /* Age in frames */ /* List of asynchronously unlinked URB's */ - struct list_head urb_remove_list; /* P: uhci->lock */ + struct list_head urb_remove_list; unsigned int urb_remove_age; /* Age in frames */ /* List of URB's awaiting completion callback */ - struct list_head complete_list; /* P: uhci->lock */ + struct list_head complete_list; int rh_numports; /* Number of root-hub ports */ @@ -419,13 +424,17 @@ static inline struct usb_hcd *uhci_to_hcd(struct uhci_hcd *uhci) #define uhci_dev(u) (uhci_to_hcd(u)->self.controller) + +/* + * Private per-URB data + */ struct urb_priv { struct list_head urb_list; struct urb *urb; struct uhci_qh *qh; /* QH for this URB */ - struct list_head td_list; /* P: urb->lock */ + struct list_head td_list; unsigned fsbr : 1; /* URB turned on FSBR */ unsigned fsbr_timeout : 1; /* URB timed out on FSBR */ @@ -434,12 +443,12 @@ struct urb_priv { /* a control transfer, retrigger */ /* the status phase */ - unsigned long inserttime; /* In jiffies */ unsigned long fsbrtime; /* In jiffies */ - struct list_head queue_list; /* P: uhci->frame_list_lock */ + struct list_head queue_list; }; + /* * Locking in uhci.c * @@ -459,6 +468,5 @@ struct urb_priv { #define PCI_VENDOR_ID_GENESYS 0x17a0 #define PCI_DEVICE_ID_GL880S_UHCI 0x8083 -#define PCI_DEVICE_ID_GL880S_EHCI 0x8084 #endif diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index ea0d168a8c67..7e46887d9e12 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -89,10 +89,10 @@ static void uhci_insert_td_frame_list(struct uhci_hcd *uhci, struct uhci_td *td, td->frame = framenum; /* Is there a TD already mapped there? */ - if (uhci->fl->frame_cpu[framenum]) { + if (uhci->frame_cpu[framenum]) { struct uhci_td *ftd, *ltd; - ftd = uhci->fl->frame_cpu[framenum]; + ftd = uhci->frame_cpu[framenum]; ltd = list_entry(ftd->fl_list.prev, struct uhci_td, fl_list); list_add_tail(&td->fl_list, &ftd->fl_list); @@ -101,29 +101,32 @@ static void uhci_insert_td_frame_list(struct uhci_hcd *uhci, struct uhci_td *td, wmb(); ltd->link = cpu_to_le32(td->dma_handle); } else { - td->link = uhci->fl->frame[framenum]; + td->link = uhci->frame[framenum]; wmb(); - uhci->fl->frame[framenum] = cpu_to_le32(td->dma_handle); - uhci->fl->frame_cpu[framenum] = td; + uhci->frame[framenum] = cpu_to_le32(td->dma_handle); + uhci->frame_cpu[framenum] = td; } } -static void uhci_remove_td(struct uhci_hcd *uhci, struct uhci_td *td) +static inline void uhci_remove_td_frame_list(struct uhci_hcd *uhci, + struct uhci_td *td) { /* If it's not inserted, don't remove it */ - if (td->frame == -1 && list_empty(&td->fl_list)) + if (td->frame == -1) { + WARN_ON(!list_empty(&td->fl_list)); return; + } - if (td->frame != -1 && uhci->fl->frame_cpu[td->frame] == td) { + if (uhci->frame_cpu[td->frame] == td) { if (list_empty(&td->fl_list)) { - uhci->fl->frame[td->frame] = td->link; - uhci->fl->frame_cpu[td->frame] = NULL; + uhci->frame[td->frame] = td->link; + uhci->frame_cpu[td->frame] = NULL; } else { struct uhci_td *ntd; ntd = list_entry(td->fl_list.next, struct uhci_td, fl_list); - uhci->fl->frame[td->frame] = cpu_to_le32(ntd->dma_handle); - uhci->fl->frame_cpu[td->frame] = ntd; + uhci->frame[td->frame] = cpu_to_le32(ntd->dma_handle); + uhci->frame_cpu[td->frame] = ntd; } } else { struct uhci_td *ptd; @@ -132,13 +135,20 @@ static void uhci_remove_td(struct uhci_hcd *uhci, struct uhci_td *td) ptd->link = td->link; } - wmb(); - td->link = UHCI_PTR_TERM; - list_del_init(&td->fl_list); td->frame = -1; } +static void unlink_isochronous_tds(struct uhci_hcd *uhci, struct urb *urb) +{ + struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv; + struct uhci_td *td; + + list_for_each_entry(td, &urbp->td_list, list) + uhci_remove_td_frame_list(uhci, td); + wmb(); +} + /* * Inserts a td list into qh. */ @@ -443,7 +453,6 @@ static struct urb_priv *uhci_alloc_urb_priv(struct uhci_hcd *uhci, struct urb *u memset((void *)urbp, 0, sizeof(*urbp)); - urbp->inserttime = jiffies; urbp->fsbrtime = jiffies; urbp->urb = urb; @@ -462,8 +471,6 @@ static void uhci_add_td_to_urb(struct urb *urb, struct uhci_td *td) { struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; - td->urb = urb; - list_add_tail(&td->list, &urbp->td_list); } @@ -473,8 +480,6 @@ static void uhci_remove_td_from_urb(struct uhci_td *td) return; list_del_init(&td->list); - - td->urb = NULL; } static void uhci_destroy_urb_priv(struct uhci_hcd *uhci, struct urb *urb) @@ -503,7 +508,6 @@ static void uhci_destroy_urb_priv(struct uhci_hcd *uhci, struct urb *urb) list_for_each_entry_safe(td, tmp, &urbp->td_list, list) { uhci_remove_td_from_urb(td); - uhci_remove_td(uhci, td); list_add(&td->remove_list, &uhci->td_remove_list); } @@ -1073,6 +1077,7 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb) struct uhci_td *td; int i, ret, frame; int status, destination; + struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv; status = TD_CTRL_ACTIVE | TD_CTRL_IOS; destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe); @@ -1081,11 +1086,7 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb) if (ret) return ret; - frame = urb->start_frame; - for (i = 0; i < urb->number_of_packets; i++, frame += urb->interval) { - if (!urb->iso_frame_desc[i].length) - continue; - + for (i = 0; i < urb->number_of_packets; i++) { td = uhci_alloc_td(uhci); if (!td) return -ENOMEM; @@ -1096,8 +1097,12 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb) if (i + 1 >= urb->number_of_packets) td->status |= cpu_to_le32(TD_CTRL_IOC); + } + frame = urb->start_frame; + list_for_each_entry(td, &urbp->td_list, list) { uhci_insert_td_frame_list(uhci, td, frame); + frame += urb->interval; } return -EINPROGRESS; @@ -1110,7 +1115,7 @@ static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb) int status; int i, ret = 0; - urb->actual_length = 0; + urb->actual_length = urb->error_count = 0; i = 0; list_for_each_entry(td, &urbp->td_list, list) { @@ -1134,6 +1139,7 @@ static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb) i++; } + unlink_isochronous_tds(uhci, urb); return ret; } @@ -1164,7 +1170,7 @@ static struct urb *uhci_find_urb_ep(struct uhci_hcd *uhci, struct urb *urb) static int uhci_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *ep, - struct urb *urb, unsigned mem_flags) + struct urb *urb, gfp_t mem_flags) { int ret; struct uhci_hcd *uhci = hcd_to_uhci(hcd); @@ -1366,6 +1372,8 @@ static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) goto done; list_del_init(&urbp->urb_list); + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) + unlink_isochronous_tds(uhci, urb); uhci_unlink_generic(uhci, urb); uhci_get_current_frame_number(uhci); diff --git a/drivers/usb/image/mdc800.c b/drivers/usb/image/mdc800.c index a330a4b50e16..1d973bcf56aa 100644 --- a/drivers/usb/image/mdc800.c +++ b/drivers/usb/image/mdc800.c @@ -425,9 +425,8 @@ static void mdc800_usb_download_notify (struct urb *urb, struct pt_regs *res) static struct usb_driver mdc800_usb_driver; static struct file_operations mdc800_device_ops; static struct usb_class_driver mdc800_class = { - .name = "usb/mdc800%d", + .name = "mdc800%d", .fops = &mdc800_device_ops, - .mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, .minor_base = MDC800_DEVICE_MINOR_BASE, }; @@ -976,13 +975,13 @@ static struct usb_driver mdc800_usb_driver = Init and Cleanup this driver (Main Functions) *************************************************************************/ -#define try(A) if (!(A)) goto cleanup_on_fail; - static int __init usb_mdc800_init (void) { int retval = -ENODEV; /* Allocate Memory */ - try (mdc800=kmalloc (sizeof (struct mdc800_data), GFP_KERNEL)); + mdc800=kmalloc (sizeof (struct mdc800_data), GFP_KERNEL); + if (!mdc800) + goto cleanup_on_fail; memset(mdc800, 0, sizeof(struct mdc800_data)); mdc800->dev = NULL; @@ -998,13 +997,25 @@ static int __init usb_mdc800_init (void) mdc800->downloaded = 0; mdc800->written = 0; - try (mdc800->irq_urb_buffer=kmalloc (8, GFP_KERNEL)); - try (mdc800->write_urb_buffer=kmalloc (8, GFP_KERNEL)); - try (mdc800->download_urb_buffer=kmalloc (64, GFP_KERNEL)); + mdc800->irq_urb_buffer=kmalloc (8, GFP_KERNEL); + if (!mdc800->irq_urb_buffer) + goto cleanup_on_fail; + mdc800->write_urb_buffer=kmalloc (8, GFP_KERNEL); + if (!mdc800->write_urb_buffer) + goto cleanup_on_fail; + mdc800->download_urb_buffer=kmalloc (64, GFP_KERNEL); + if (!mdc800->download_urb_buffer) + goto cleanup_on_fail; - try (mdc800->irq_urb=usb_alloc_urb (0, GFP_KERNEL)); - try (mdc800->download_urb=usb_alloc_urb (0, GFP_KERNEL)); - try (mdc800->write_urb=usb_alloc_urb (0, GFP_KERNEL)); + mdc800->irq_urb=usb_alloc_urb (0, GFP_KERNEL); + if (!mdc800->irq_urb) + goto cleanup_on_fail; + mdc800->download_urb=usb_alloc_urb (0, GFP_KERNEL); + if (!mdc800->download_urb) + goto cleanup_on_fail; + mdc800->write_urb=usb_alloc_urb (0, GFP_KERNEL); + if (!mdc800->write_urb) + goto cleanup_on_fail; /* Register the driver */ retval = usb_register(&mdc800_usb_driver); diff --git a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c index c84e1486054f..c89d0769b3da 100644 --- a/drivers/usb/image/microtek.c +++ b/drivers/usb/image/microtek.c @@ -773,11 +773,10 @@ static int mts_usb_probe(struct usb_interface *intf, } - new_desc = kmalloc(sizeof(struct mts_desc), GFP_KERNEL); + new_desc = kzalloc(sizeof(struct mts_desc), GFP_KERNEL); if (!new_desc) goto out; - memset(new_desc, 0, sizeof(*new_desc)); new_desc->urb = usb_alloc_urb(0, GFP_KERNEL); if (!new_desc->urb) goto out_kfree; diff --git a/drivers/usb/input/acecad.c b/drivers/usb/input/acecad.c index 74f8760d7c07..a32558b4048e 100644 --- a/drivers/usb/input/acecad.c +++ b/drivers/usb/input/acecad.c @@ -53,7 +53,7 @@ struct usb_acecad { char name[128]; char phys[64]; struct usb_device *usbdev; - struct input_dev dev; + struct input_dev *input; struct urb *irq; signed char *data; @@ -64,7 +64,7 @@ static void usb_acecad_irq(struct urb *urb, struct pt_regs *regs) { struct usb_acecad *acecad = urb->context; unsigned char *data = acecad->data; - struct input_dev *dev = &acecad->dev; + struct input_dev *dev = acecad->input; int prox, status; switch (urb->status) { @@ -135,8 +135,8 @@ static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_ struct usb_host_interface *interface = intf->cur_altsetting; struct usb_endpoint_descriptor *endpoint; struct usb_acecad *acecad; + struct input_dev *input_dev; int pipe, maxp; - char path[64]; if (interface->desc.bNumEndpoints != 1) return -ENODEV; @@ -153,8 +153,9 @@ static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_ maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); acecad = kzalloc(sizeof(struct usb_acecad), GFP_KERNEL); - if (!acecad) - return -ENOMEM; + input_dev = input_allocate_device(); + if (!acecad || !input_dev) + goto fail1; acecad->data = usb_buffer_alloc(dev, 8, SLAB_KERNEL, &acecad->data_dma); if (!acecad->data) @@ -164,6 +165,9 @@ static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_ if (!acecad->irq) goto fail2; + acecad->usbdev = dev; + acecad->input = input_dev; + if (dev->manufacturer) strlcpy(acecad->name, dev->manufacturer, sizeof(acecad->name)); @@ -173,48 +177,48 @@ static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_ strlcat(acecad->name, dev->product, sizeof(acecad->name)); } - usb_make_path(dev, path, sizeof(path)); - snprintf(acecad->phys, sizeof(acecad->phys), "%s/input0", path); + usb_make_path(dev, acecad->phys, sizeof(acecad->phys)); + strlcat(acecad->phys, "/input0", sizeof(acecad->phys)); - acecad->usbdev = dev; + input_dev->name = acecad->name; + input_dev->phys = acecad->phys; + usb_to_input_id(dev, &input_dev->id); + input_dev->cdev.dev = &intf->dev; + input_dev->private = acecad; - acecad->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - acecad->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE); - acecad->dev.keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE); - acecad->dev.keybit[LONG(BTN_DIGI)] = BIT(BTN_TOOL_PEN) |BIT(BTN_TOUCH) | BIT(BTN_STYLUS) | BIT(BTN_STYLUS2); + input_dev->open = usb_acecad_open; + input_dev->close = usb_acecad_close; + + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + input_dev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE); + input_dev->keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE); + input_dev->keybit[LONG(BTN_DIGI)] = BIT(BTN_TOOL_PEN) |BIT(BTN_TOUCH) | BIT(BTN_STYLUS) | BIT(BTN_STYLUS2); switch (id->driver_info) { case 0: - acecad->dev.absmax[ABS_X] = 5000; - acecad->dev.absmax[ABS_Y] = 3750; - acecad->dev.absmax[ABS_PRESSURE] = 512; + input_dev->absmax[ABS_X] = 5000; + input_dev->absmax[ABS_Y] = 3750; + input_dev->absmax[ABS_PRESSURE] = 512; if (!strlen(acecad->name)) snprintf(acecad->name, sizeof(acecad->name), "USB Acecad Flair Tablet %04x:%04x", - dev->descriptor.idVendor, dev->descriptor.idProduct); + le16_to_cpu(dev->descriptor.idVendor), + le16_to_cpu(dev->descriptor.idProduct)); break; case 1: - acecad->dev.absmax[ABS_X] = 3000; - acecad->dev.absmax[ABS_Y] = 2250; - acecad->dev.absmax[ABS_PRESSURE] = 1024; + input_dev->absmax[ABS_X] = 3000; + input_dev->absmax[ABS_Y] = 2250; + input_dev->absmax[ABS_PRESSURE] = 1024; if (!strlen(acecad->name)) snprintf(acecad->name, sizeof(acecad->name), "USB Acecad 302 Tablet %04x:%04x", - dev->descriptor.idVendor, dev->descriptor.idProduct); + le16_to_cpu(dev->descriptor.idVendor), + le16_to_cpu(dev->descriptor.idProduct)); break; } - acecad->dev.absfuzz[ABS_X] = 4; - acecad->dev.absfuzz[ABS_Y] = 4; - - acecad->dev.private = acecad; - acecad->dev.open = usb_acecad_open; - acecad->dev.close = usb_acecad_close; - - acecad->dev.name = acecad->name; - acecad->dev.phys = acecad->phys; - usb_to_input_id(dev, &acecad->dev.id); - acecad->dev.dev = &intf->dev; + input_dev->absfuzz[ABS_X] = 4; + input_dev->absfuzz[ABS_Y] = 4; usb_fill_int_urb(acecad->irq, dev, pipe, acecad->data, maxp > 8 ? 8 : maxp, @@ -222,17 +226,15 @@ static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_ acecad->irq->transfer_dma = acecad->data_dma; acecad->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - input_register_device(&acecad->dev); - - printk(KERN_INFO "input: %s with packet size %d on %s\n", - acecad->name, maxp, path); + input_register_device(acecad->input); usb_set_intfdata(intf, acecad); return 0; fail2: usb_buffer_free(dev, 8, acecad->data, acecad->data_dma); - fail1: kfree(acecad); + fail1: input_free_device(input_dev); + kfree(acecad); return -ENOMEM; } @@ -243,7 +245,7 @@ static void usb_acecad_disconnect(struct usb_interface *intf) usb_set_intfdata(intf, NULL); if (acecad) { usb_kill_urb(acecad->irq); - input_unregister_device(&acecad->dev); + input_unregister_device(acecad->input); usb_free_urb(acecad->irq); usb_buffer_free(interface_to_usbdev(intf), 10, acecad->data, acecad->data_dma); kfree(acecad); diff --git a/drivers/usb/input/aiptek.c b/drivers/usb/input/aiptek.c index cd0cbfe20723..1c3b472a3bca 100644 --- a/drivers/usb/input/aiptek.c +++ b/drivers/usb/input/aiptek.c @@ -317,7 +317,7 @@ struct aiptek_settings { }; struct aiptek { - struct input_dev inputdev; /* input device struct */ + struct input_dev *inputdev; /* input device struct */ struct usb_device *usbdev; /* usb device struct */ struct urb *urb; /* urb for incoming reports */ dma_addr_t data_dma; /* our dma stuffage */ @@ -402,7 +402,7 @@ static void aiptek_irq(struct urb *urb, struct pt_regs *regs) { struct aiptek *aiptek = urb->context; unsigned char *data = aiptek->data; - struct input_dev *inputdev = &aiptek->inputdev; + struct input_dev *inputdev = aiptek->inputdev; int jitterable = 0; int retval, macro, x, y, z, left, right, middle, p, dv, tip, bs, pck; @@ -955,20 +955,20 @@ static int aiptek_program_tablet(struct aiptek *aiptek) /* Query getXextension */ if ((ret = aiptek_query(aiptek, 0x01, 0x00)) < 0) return ret; - aiptek->inputdev.absmin[ABS_X] = 0; - aiptek->inputdev.absmax[ABS_X] = ret - 1; + aiptek->inputdev->absmin[ABS_X] = 0; + aiptek->inputdev->absmax[ABS_X] = ret - 1; /* Query getYextension */ if ((ret = aiptek_query(aiptek, 0x01, 0x01)) < 0) return ret; - aiptek->inputdev.absmin[ABS_Y] = 0; - aiptek->inputdev.absmax[ABS_Y] = ret - 1; + aiptek->inputdev->absmin[ABS_Y] = 0; + aiptek->inputdev->absmax[ABS_Y] = ret - 1; /* Query getPressureLevels */ if ((ret = aiptek_query(aiptek, 0x08, 0x00)) < 0) return ret; - aiptek->inputdev.absmin[ABS_PRESSURE] = 0; - aiptek->inputdev.absmax[ABS_PRESSURE] = ret - 1; + aiptek->inputdev->absmin[ABS_PRESSURE] = 0; + aiptek->inputdev->absmax[ABS_PRESSURE] = ret - 1; /* Depending on whether we are in absolute or relative mode, we will * do a switchToTablet(absolute) or switchToMouse(relative) command. @@ -1025,8 +1025,8 @@ static ssize_t show_tabletSize(struct device *dev, struct device_attribute *attr return 0; return snprintf(buf, PAGE_SIZE, "%dx%d\n", - aiptek->inputdev.absmax[ABS_X] + 1, - aiptek->inputdev.absmax[ABS_Y] + 1); + aiptek->inputdev->absmax[ABS_X] + 1, + aiptek->inputdev->absmax[ABS_Y] + 1); } /* These structs define the sysfs files, param #1 is the name of the @@ -1048,7 +1048,7 @@ static ssize_t show_tabletProductId(struct device *dev, struct device_attribute return 0; return snprintf(buf, PAGE_SIZE, "0x%04x\n", - aiptek->inputdev.id.product); + aiptek->inputdev->id.product); } static DEVICE_ATTR(product_id, S_IRUGO, show_tabletProductId, NULL); @@ -1063,7 +1063,7 @@ static ssize_t show_tabletVendorId(struct device *dev, struct device_attribute * if (aiptek == NULL) return 0; - return snprintf(buf, PAGE_SIZE, "0x%04x\n", aiptek->inputdev.id.vendor); + return snprintf(buf, PAGE_SIZE, "0x%04x\n", aiptek->inputdev->id.vendor); } static DEVICE_ATTR(vendor_id, S_IRUGO, show_tabletVendorId, NULL); @@ -1977,7 +1977,6 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id) struct input_dev *inputdev; struct input_handle *inputhandle; struct list_head *node, *next; - char path[64 + 1]; int i; int speeds[] = { 0, AIPTEK_PROGRAMMABLE_DELAY_50, @@ -1996,24 +1995,26 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id) */ speeds[0] = programmableDelay; - if ((aiptek = kmalloc(sizeof(struct aiptek), GFP_KERNEL)) == NULL) - return -ENOMEM; - memset(aiptek, 0, sizeof(struct aiptek)); + aiptek = kzalloc(sizeof(struct aiptek), GFP_KERNEL); + inputdev = input_allocate_device(); + if (!aiptek || !inputdev) + goto fail1; aiptek->data = usb_buffer_alloc(usbdev, AIPTEK_PACKET_LENGTH, SLAB_ATOMIC, &aiptek->data_dma); - if (aiptek->data == NULL) { - kfree(aiptek); - return -ENOMEM; - } + if (!aiptek->data) + goto fail1; aiptek->urb = usb_alloc_urb(0, GFP_KERNEL); - if (aiptek->urb == NULL) { - usb_buffer_free(usbdev, AIPTEK_PACKET_LENGTH, aiptek->data, - aiptek->data_dma); - kfree(aiptek); - return -ENOMEM; - } + if (!aiptek->urb) + goto fail2; + + aiptek->inputdev = inputdev; + aiptek->usbdev = usbdev; + aiptek->ifnum = intf->altsetting[0].desc.bInterfaceNumber; + aiptek->inDelay = 0; + aiptek->endDelay = 0; + aiptek->previousJitterable = 0; /* Set up the curSettings struct. Said struct contains the current * programmable parameters. The newSetting struct contains changes @@ -2036,31 +2037,48 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id) /* Both structs should have equivalent settings */ - memcpy(&aiptek->newSetting, &aiptek->curSetting, - sizeof(struct aiptek_settings)); + aiptek->newSetting = aiptek->curSetting; + + /* Determine the usb devices' physical path. + * Asketh not why we always pretend we're using "../input0", + * but I suspect this will have to be refactored one + * day if a single USB device can be a keyboard & a mouse + * & a tablet, and the inputX number actually will tell + * us something... + */ + usb_make_path(usbdev, aiptek->features.usbPath, + sizeof(aiptek->features.usbPath)); + strlcat(aiptek->features.usbPath, "/input0", + sizeof(aiptek->features.usbPath)); + + /* Set up client data, pointers to open and close routines + * for the input device. + */ + inputdev->name = "Aiptek"; + inputdev->phys = aiptek->features.usbPath; + usb_to_input_id(usbdev, &inputdev->id); + inputdev->cdev.dev = &intf->dev; + inputdev->private = aiptek; + inputdev->open = aiptek_open; + inputdev->close = aiptek_close; /* Now program the capacities of the tablet, in terms of being * an input device. */ - aiptek->inputdev.evbit[0] |= BIT(EV_KEY) + inputdev->evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_REL) | BIT(EV_MSC); - aiptek->inputdev.absbit[0] |= - (BIT(ABS_X) | - BIT(ABS_Y) | - BIT(ABS_PRESSURE) | - BIT(ABS_TILT_X) | - BIT(ABS_TILT_Y) | BIT(ABS_WHEEL) | BIT(ABS_MISC)); + inputdev->absbit[0] |= BIT(ABS_MISC); - aiptek->inputdev.relbit[0] |= + inputdev->relbit[0] |= (BIT(REL_X) | BIT(REL_Y) | BIT(REL_WHEEL) | BIT(REL_MISC)); - aiptek->inputdev.keybit[LONG(BTN_LEFT)] |= + inputdev->keybit[LONG(BTN_LEFT)] |= (BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE)); - aiptek->inputdev.keybit[LONG(BTN_DIGI)] |= + inputdev->keybit[LONG(BTN_DIGI)] |= (BIT(BTN_TOOL_PEN) | BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_PENCIL) | @@ -2070,70 +2088,26 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id) BIT(BTN_TOOL_LENS) | BIT(BTN_TOUCH) | BIT(BTN_STYLUS) | BIT(BTN_STYLUS2)); - aiptek->inputdev.mscbit[0] = BIT(MSC_SERIAL); + inputdev->mscbit[0] = BIT(MSC_SERIAL); /* Programming the tablet macro keys needs to be done with a for loop * as the keycodes are discontiguous. */ for (i = 0; i < sizeof(macroKeyEvents) / sizeof(macroKeyEvents[0]); ++i) - set_bit(macroKeyEvents[i], aiptek->inputdev.keybit); - - /* Set up client data, pointers to open and close routines - * for the input device. - */ - aiptek->inputdev.private = aiptek; - aiptek->inputdev.open = aiptek_open; - aiptek->inputdev.close = aiptek_close; + set_bit(macroKeyEvents[i], inputdev->keybit); - /* Determine the usb devices' physical path. - * Asketh not why we always pretend we're using "../input0", - * but I suspect this will have to be refactored one - * day if a single USB device can be a keyboard & a mouse - * & a tablet, and the inputX number actually will tell - * us something... - */ - if (usb_make_path(usbdev, path, 64) > 0) - sprintf(aiptek->features.usbPath, "%s/input0", path); - - /* Program the input device coordinate capacities. We do not yet + /* + * Program the input device coordinate capacities. We do not yet * know what maximum X, Y, and Z values are, so we're putting fake * values in. Later, we'll ask the tablet to put in the correct * values. */ - aiptek->inputdev.absmin[ABS_X] = 0; - aiptek->inputdev.absmax[ABS_X] = 2999; - aiptek->inputdev.absmin[ABS_Y] = 0; - aiptek->inputdev.absmax[ABS_Y] = 2249; - aiptek->inputdev.absmin[ABS_PRESSURE] = 0; - aiptek->inputdev.absmax[ABS_PRESSURE] = 511; - aiptek->inputdev.absmin[ABS_TILT_X] = AIPTEK_TILT_MIN; - aiptek->inputdev.absmax[ABS_TILT_X] = AIPTEK_TILT_MAX; - aiptek->inputdev.absmin[ABS_TILT_Y] = AIPTEK_TILT_MIN; - aiptek->inputdev.absmax[ABS_TILT_Y] = AIPTEK_TILT_MAX; - aiptek->inputdev.absmin[ABS_WHEEL] = AIPTEK_WHEEL_MIN; - aiptek->inputdev.absmax[ABS_WHEEL] = AIPTEK_WHEEL_MAX - 1; - aiptek->inputdev.absfuzz[ABS_X] = 0; - aiptek->inputdev.absfuzz[ABS_Y] = 0; - aiptek->inputdev.absfuzz[ABS_PRESSURE] = 0; - aiptek->inputdev.absfuzz[ABS_TILT_X] = 0; - aiptek->inputdev.absfuzz[ABS_TILT_Y] = 0; - aiptek->inputdev.absfuzz[ABS_WHEEL] = 0; - aiptek->inputdev.absflat[ABS_X] = 0; - aiptek->inputdev.absflat[ABS_Y] = 0; - aiptek->inputdev.absflat[ABS_PRESSURE] = 0; - aiptek->inputdev.absflat[ABS_TILT_X] = 0; - aiptek->inputdev.absflat[ABS_TILT_Y] = 0; - aiptek->inputdev.absflat[ABS_WHEEL] = 0; - aiptek->inputdev.name = "Aiptek"; - aiptek->inputdev.phys = aiptek->features.usbPath; - usb_to_input_id(usbdev, &aiptek->inputdev.id); - aiptek->inputdev.dev = &intf->dev; - - aiptek->usbdev = usbdev; - aiptek->ifnum = intf->altsetting[0].desc.bInterfaceNumber; - aiptek->inDelay = 0; - aiptek->endDelay = 0; - aiptek->previousJitterable = 0; + input_set_abs_params(inputdev, ABS_X, 0, 2999, 0, 0); + input_set_abs_params(inputdev, ABS_X, 0, 2249, 0, 0); + input_set_abs_params(inputdev, ABS_PRESSURE, 0, 511, 0, 0); + input_set_abs_params(inputdev, ABS_TILT_X, AIPTEK_TILT_MIN, AIPTEK_TILT_MAX, 0, 0); + input_set_abs_params(inputdev, ABS_TILT_Y, AIPTEK_TILT_MIN, AIPTEK_TILT_MAX, 0, 0); + input_set_abs_params(inputdev, ABS_WHEEL, AIPTEK_WHEEL_MIN, AIPTEK_WHEEL_MAX - 1, 0, 0); endpoint = &intf->altsetting[0].endpoint[0].desc; @@ -2150,28 +2124,6 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id) aiptek->urb->transfer_dma = aiptek->data_dma; aiptek->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - /* Register the tablet as an Input Device - */ - input_register_device(&aiptek->inputdev); - - /* We now will look for the evdev device which is mapped to - * the tablet. The partial name is kept in the link list of - * input_handles associated with this input device. - * What identifies an evdev input_handler is that it begins - * with 'event', continues with a digit, and that in turn - * is mapped to /{devfs}/input/eventN. - */ - inputdev = &aiptek->inputdev; - list_for_each_safe(node, next, &inputdev->h_list) { - inputhandle = to_handle(node); - if (strncmp(inputhandle->name, "event", 5) == 0) { - strcpy(aiptek->features.inputPath, inputhandle->name); - break; - } - } - - info("input: Aiptek on %s (%s)\n", path, aiptek->features.inputPath); - /* Program the tablet. This sets the tablet up in the mode * specified in newSetting, and also queries the tablet's * physical capacities. @@ -2186,13 +2138,32 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id) for (i = 0; i < sizeof(speeds) / sizeof(speeds[0]); ++i) { aiptek->curSetting.programmableDelay = speeds[i]; (void)aiptek_program_tablet(aiptek); - if (aiptek->inputdev.absmax[ABS_X] > 0) { + if (aiptek->inputdev->absmax[ABS_X] > 0) { info("input: Aiptek using %d ms programming speed\n", aiptek->curSetting.programmableDelay); break; } } + /* Register the tablet as an Input Device + */ + input_register_device(aiptek->inputdev); + + /* We now will look for the evdev device which is mapped to + * the tablet. The partial name is kept in the link list of + * input_handles associated with this input device. + * What identifies an evdev input_handler is that it begins + * with 'event', continues with a digit, and that in turn + * is mapped to input/eventN. + */ + list_for_each_safe(node, next, &inputdev->h_list) { + inputhandle = to_handle(node); + if (strncmp(inputhandle->name, "event", 5) == 0) { + strcpy(aiptek->features.inputPath, inputhandle->name); + break; + } + } + /* Associate this driver's struct with the usb interface. */ usb_set_intfdata(intf, aiptek); @@ -2207,6 +2178,12 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id) info("aiptek: error loading 'evdev' module"); return 0; + +fail2: usb_buffer_free(usbdev, AIPTEK_PACKET_LENGTH, aiptek->data, + aiptek->data_dma); +fail1: input_free_device(inputdev); + kfree(aiptek); + return -ENOMEM; } /* Forward declaration */ @@ -2234,7 +2211,7 @@ static void aiptek_disconnect(struct usb_interface *intf) /* Free & unhook everything from the system. */ usb_kill_urb(aiptek->urb); - input_unregister_device(&aiptek->inputdev); + input_unregister_device(aiptek->inputdev); aiptek_delete_files(&intf->dev); usb_free_urb(aiptek->urb); usb_buffer_free(interface_to_usbdev(intf), diff --git a/drivers/usb/input/appletouch.c b/drivers/usb/input/appletouch.c index e03c1c567a14..15840db092a5 100644 --- a/drivers/usb/input/appletouch.c +++ b/drivers/usb/input/appletouch.c @@ -39,7 +39,7 @@ #define APPLE_VENDOR_ID 0x05AC #define ATP_DEVICE(prod) \ - .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \ USB_DEVICE_ID_MATCH_INT_CLASS | \ USB_DEVICE_ID_MATCH_INT_PROTOCOL, \ .idVendor = APPLE_VENDOR_ID, \ @@ -78,9 +78,9 @@ MODULE_DEVICE_TABLE (usb, atp_table); * We try to keep the touchpad aspect ratio while still doing only simple * arithmetics. * The factors below give coordinates like: - * 0 <= x < 960 on 12" and 15" Powerbooks - * 0 <= x < 1600 on 17" Powerbooks - * 0 <= y < 646 + * 0 <= x < 960 on 12" and 15" Powerbooks + * 0 <= x < 1600 on 17" Powerbooks + * 0 <= y < 646 */ #define ATP_XFACT 64 #define ATP_YFACT 43 @@ -93,11 +93,12 @@ MODULE_DEVICE_TABLE (usb, atp_table); /* Structure to hold all of our device specific stuff */ struct atp { + char phys[64]; struct usb_device * udev; /* usb device */ struct urb * urb; /* usb request block */ signed char * data; /* transferred data */ int open; /* non-zero if opened */ - struct input_dev input; /* input dev */ + struct input_dev *input; /* input dev */ int valid; /* are the sensors valid ? */ int x_old; /* last reported x/y, */ int y_old; /* used for smoothing */ @@ -114,11 +115,11 @@ struct atp { int i; \ printk("appletouch: %s %lld", msg, (long long)jiffies); \ for (i = 0; i < ATP_XSENSORS + ATP_YSENSORS; i++) \ - printk(" %02x", tab[i]); \ - printk("\n"); \ + printk(" %02x", tab[i]); \ + printk("\n"); \ } -#define dprintk(format, a...) \ +#define dprintk(format, a...) \ do { \ if (debug) printk(format, ##a); \ } while (0) @@ -219,8 +220,8 @@ static void atp_complete(struct urb* urb, struct pt_regs* regs) for (i = 16; i < ATP_XSENSORS; i++) if (dev->xy_cur[i]) { printk("appletouch: 17\" model detected.\n"); - input_set_abs_params(&dev->input, ABS_X, 0, - (ATP_XSENSORS - 1) * + input_set_abs_params(dev->input, ABS_X, 0, + (ATP_XSENSORS - 1) * ATP_XFACT - 1, ATP_FUZZ, 0); break; @@ -260,12 +261,12 @@ static void atp_complete(struct urb* urb, struct pt_regs* regs) "Xz: %3d Yz: %3d\n", x, y, x_z, y_z); - input_report_key(&dev->input, BTN_TOUCH, 1); - input_report_abs(&dev->input, ABS_X, x); - input_report_abs(&dev->input, ABS_Y, y); - input_report_abs(&dev->input, ABS_PRESSURE, + input_report_key(dev->input, BTN_TOUCH, 1); + input_report_abs(dev->input, ABS_X, x); + input_report_abs(dev->input, ABS_Y, y); + input_report_abs(dev->input, ABS_PRESSURE, min(ATP_PRESSURE, x_z + y_z)); - atp_report_fingers(&dev->input, max(x_f, y_f)); + atp_report_fingers(dev->input, max(x_f, y_f)); } dev->x_old = x; dev->y_old = y; @@ -273,17 +274,17 @@ static void atp_complete(struct urb* urb, struct pt_regs* regs) else if (!x && !y) { dev->x_old = dev->y_old = -1; - input_report_key(&dev->input, BTN_TOUCH, 0); - input_report_abs(&dev->input, ABS_PRESSURE, 0); - atp_report_fingers(&dev->input, 0); + input_report_key(dev->input, BTN_TOUCH, 0); + input_report_abs(dev->input, ABS_PRESSURE, 0); + atp_report_fingers(dev->input, 0); /* reset the accumulator on release */ memset(dev->xy_acc, 0, sizeof(dev->xy_acc)); } - input_report_key(&dev->input, BTN_LEFT, !!dev->data[80]); + input_report_key(dev->input, BTN_LEFT, !!dev->data[80]); - input_sync(&dev->input); + input_sync(dev->input); exit: retval = usb_submit_urb(dev->urb, GFP_ATOMIC); @@ -314,21 +315,14 @@ static void atp_close(struct input_dev *input) static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id) { - struct atp *dev = NULL; + struct atp *dev; + struct input_dev *input_dev; + struct usb_device *udev = interface_to_usbdev(iface); struct usb_host_interface *iface_desc; struct usb_endpoint_descriptor *endpoint; int int_in_endpointAddr = 0; int i, retval = -ENOMEM; - /* allocate memory for our device state and initialize it */ - dev = kmalloc(sizeof(struct atp), GFP_KERNEL); - if (dev == NULL) { - err("Out of memory"); - goto err_kmalloc; - } - memset(dev, 0, sizeof(struct atp)); - - dev->udev = interface_to_usbdev(iface); /* set up the endpoint information */ /* use only the first interrupt-in endpoint */ @@ -345,70 +339,82 @@ static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id } } if (!int_in_endpointAddr) { - retval = -EIO; err("Could not find int-in endpoint"); - goto err_endpoint; + return -EIO; } - /* save our data pointer in this interface device */ - usb_set_intfdata(iface, dev); + /* allocate memory for our device state and initialize it */ + dev = kzalloc(sizeof(struct atp), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!dev || !input_dev) { + err("Out of memory"); + goto err_free_devs; + } + + dev->udev = udev; + dev->input = input_dev; dev->urb = usb_alloc_urb(0, GFP_KERNEL); if (!dev->urb) { retval = -ENOMEM; - goto err_usballoc; + goto err_free_devs; } + dev->data = usb_buffer_alloc(dev->udev, ATP_DATASIZE, GFP_KERNEL, &dev->urb->transfer_dma); if (!dev->data) { retval = -ENOMEM; - goto err_usbbufalloc; + goto err_free_urb; } - usb_fill_int_urb(dev->urb, dev->udev, - usb_rcvintpipe(dev->udev, int_in_endpointAddr), + + usb_fill_int_urb(dev->urb, udev, + usb_rcvintpipe(udev, int_in_endpointAddr), dev->data, ATP_DATASIZE, atp_complete, dev, 1); - init_input_dev(&dev->input); - dev->input.name = "appletouch"; - dev->input.dev = &iface->dev; - dev->input.private = dev; - dev->input.open = atp_open; - dev->input.close = atp_close; + usb_make_path(udev, dev->phys, sizeof(dev->phys)); + strlcat(dev->phys, "/input0", sizeof(dev->phys)); + + input_dev->name = "appletouch"; + input_dev->phys = dev->phys; + usb_to_input_id(dev->udev, &input_dev->id); + input_dev->cdev.dev = &iface->dev; - usb_to_input_id(dev->udev, &dev->input.id); + input_dev->private = dev; + input_dev->open = atp_open; + input_dev->close = atp_close; - set_bit(EV_ABS, dev->input.evbit); + set_bit(EV_ABS, input_dev->evbit); /* * 12" and 15" Powerbooks only have 16 x sensors, * 17" models are detected later. */ - input_set_abs_params(&dev->input, ABS_X, 0, + input_set_abs_params(input_dev, ABS_X, 0, (16 - 1) * ATP_XFACT - 1, ATP_FUZZ, 0); - input_set_abs_params(&dev->input, ABS_Y, 0, + input_set_abs_params(input_dev, ABS_Y, 0, (ATP_YSENSORS - 1) * ATP_YFACT - 1, ATP_FUZZ, 0); - input_set_abs_params(&dev->input, ABS_PRESSURE, 0, ATP_PRESSURE, 0, 0); + input_set_abs_params(input_dev, ABS_PRESSURE, 0, ATP_PRESSURE, 0, 0); - set_bit(EV_KEY, dev->input.evbit); - set_bit(BTN_TOUCH, dev->input.keybit); - set_bit(BTN_TOOL_FINGER, dev->input.keybit); - set_bit(BTN_TOOL_DOUBLETAP, dev->input.keybit); - set_bit(BTN_TOOL_TRIPLETAP, dev->input.keybit); - set_bit(BTN_LEFT, dev->input.keybit); + set_bit(EV_KEY, input_dev->evbit); + set_bit(BTN_TOUCH, input_dev->keybit); + set_bit(BTN_TOOL_FINGER, input_dev->keybit); + set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit); + set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit); + set_bit(BTN_LEFT, input_dev->keybit); - input_register_device(&dev->input); + input_register_device(dev->input); - printk(KERN_INFO "input: appletouch connected\n"); + /* save our data pointer in this interface device */ + usb_set_intfdata(iface, dev); return 0; -err_usbbufalloc: + err_free_urb: usb_free_urb(dev->urb); -err_usballoc: + err_free_devs: usb_set_intfdata(iface, NULL); -err_endpoint: kfree(dev); -err_kmalloc: + input_free_device(input_dev); return retval; } @@ -419,7 +425,7 @@ static void atp_disconnect(struct usb_interface *iface) usb_set_intfdata(iface, NULL); if (dev) { usb_kill_urb(dev->urb); - input_unregister_device(&dev->input); + input_unregister_device(dev->input); usb_free_urb(dev->urb); usb_buffer_free(dev->udev, ATP_DATASIZE, dev->data, dev->urb->transfer_dma); diff --git a/drivers/usb/input/ati_remote.c b/drivers/usb/input/ati_remote.c index fd99681ee483..9a2a47db9494 100644 --- a/drivers/usb/input/ati_remote.c +++ b/drivers/usb/input/ati_remote.c @@ -112,7 +112,6 @@ #define NAME_BUFSIZE 80 /* size of product name, path buffers */ #define DATA_BUFSIZE 63 /* size of URB data buffers */ -#define ATI_INPUTNUM 1 /* Which input device to register as */ static unsigned long channel_mask; module_param(channel_mask, ulong, 0444); @@ -162,7 +161,7 @@ static char accel[] = { 1, 2, 4, 6, 9, 13, 20 }; static DECLARE_MUTEX(disconnect_sem); struct ati_remote { - struct input_dev idev; + struct input_dev *idev; struct usb_device *udev; struct usb_interface *interface; @@ -198,15 +197,13 @@ struct ati_remote { #define KIND_ACCEL 7 /* Directional keypad - left, right, up, down.*/ /* Translation table from hardware messages to input events. */ -static struct -{ +static struct { short kind; unsigned char data1, data2; int type; unsigned int code; int value; -} ati_remote_tbl[] = -{ +} ati_remote_tbl[] = { /* Directional control pad axes */ {KIND_ACCEL, 0x35, 0x70, EV_REL, REL_X, -1}, /* left */ {KIND_ACCEL, 0x36, 0x71, EV_REL, REL_X, 1}, /* right */ @@ -286,7 +283,6 @@ static struct /* Local function prototypes */ static void ati_remote_dump (unsigned char *data, unsigned int actual_length); -static void ati_remote_delete (struct ati_remote *dev); static int ati_remote_open (struct input_dev *inputdev); static void ati_remote_close (struct input_dev *inputdev); static int ati_remote_sendpacket (struct ati_remote *ati_remote, u16 cmd, unsigned char *data); @@ -428,7 +424,7 @@ static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs) { struct ati_remote *ati_remote = urb->context; unsigned char *data= ati_remote->inbuf; - struct input_dev *dev = &ati_remote->idev; + struct input_dev *dev = ati_remote->idev; int index, acc; int remote_num; @@ -587,38 +583,55 @@ static void ati_remote_irq_in(struct urb *urb, struct pt_regs *regs) } /* - * ati_remote_delete + * ati_remote_alloc_buffers */ -static void ati_remote_delete(struct ati_remote *ati_remote) +static int ati_remote_alloc_buffers(struct usb_device *udev, + struct ati_remote *ati_remote) { - if (ati_remote->irq_urb) - usb_kill_urb(ati_remote->irq_urb); + ati_remote->inbuf = usb_buffer_alloc(udev, DATA_BUFSIZE, SLAB_ATOMIC, + &ati_remote->inbuf_dma); + if (!ati_remote->inbuf) + return -1; - if (ati_remote->out_urb) - usb_kill_urb(ati_remote->out_urb); + ati_remote->outbuf = usb_buffer_alloc(udev, DATA_BUFSIZE, SLAB_ATOMIC, + &ati_remote->outbuf_dma); + if (!ati_remote->outbuf) + return -1; - input_unregister_device(&ati_remote->idev); + ati_remote->irq_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!ati_remote->irq_urb) + return -1; - if (ati_remote->inbuf) - usb_buffer_free(ati_remote->udev, DATA_BUFSIZE, - ati_remote->inbuf, ati_remote->inbuf_dma); + ati_remote->out_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!ati_remote->out_urb) + return -1; - if (ati_remote->outbuf) - usb_buffer_free(ati_remote->udev, DATA_BUFSIZE, - ati_remote->outbuf, ati_remote->outbuf_dma); + return 0; +} +/* + * ati_remote_free_buffers + */ +static void ati_remote_free_buffers(struct ati_remote *ati_remote) +{ if (ati_remote->irq_urb) usb_free_urb(ati_remote->irq_urb); if (ati_remote->out_urb) usb_free_urb(ati_remote->out_urb); - kfree(ati_remote); + if (ati_remote->inbuf) + usb_buffer_free(ati_remote->udev, DATA_BUFSIZE, + ati_remote->inbuf, ati_remote->inbuf_dma); + + if (ati_remote->outbuf) + usb_buffer_free(ati_remote->udev, DATA_BUFSIZE, + ati_remote->inbuf, ati_remote->outbuf_dma); } static void ati_remote_input_init(struct ati_remote *ati_remote) { - struct input_dev *idev = &(ati_remote->idev); + struct input_dev *idev = ati_remote->idev; int i; idev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL); @@ -637,7 +650,7 @@ static void ati_remote_input_init(struct ati_remote *ati_remote) idev->phys = ati_remote->phys; usb_to_input_id(ati_remote->udev, &idev->id); - idev->dev = &ati_remote->udev->dev; + idev->cdev.dev = &ati_remote->udev->dev; } static int ati_remote_initialize(struct ati_remote *ati_remote) @@ -674,7 +687,7 @@ static int ati_remote_initialize(struct ati_remote *ati_remote) (ati_remote_sendpacket(ati_remote, 0x8007, init2))) { dev_err(&ati_remote->interface->dev, "Initializing ati_remote hardware failed.\n"); - return 1; + return -EIO; } return 0; @@ -686,95 +699,83 @@ static int ati_remote_initialize(struct ati_remote *ati_remote) static int ati_remote_probe(struct usb_interface *interface, const struct usb_device_id *id) { struct usb_device *udev = interface_to_usbdev(interface); - struct ati_remote *ati_remote = NULL; - struct usb_host_interface *iface_host; - int retval = -ENOMEM; - char path[64]; - - /* Allocate and clear an ati_remote struct */ - if (!(ati_remote = kmalloc(sizeof (struct ati_remote), GFP_KERNEL))) - return -ENOMEM; - memset(ati_remote, 0x00, sizeof (struct ati_remote)); + struct usb_host_interface *iface_host = interface->cur_altsetting; + struct usb_endpoint_descriptor *endpoint_in, *endpoint_out; + struct ati_remote *ati_remote; + struct input_dev *input_dev; + int err = -ENOMEM; - iface_host = interface->cur_altsetting; if (iface_host->desc.bNumEndpoints != 2) { err("%s: Unexpected desc.bNumEndpoints\n", __FUNCTION__); - retval = -ENODEV; - goto error; + return -ENODEV; } - ati_remote->endpoint_in = &(iface_host->endpoint[0].desc); - ati_remote->endpoint_out = &(iface_host->endpoint[1].desc); - ati_remote->udev = udev; - ati_remote->interface = interface; + endpoint_in = &iface_host->endpoint[0].desc; + endpoint_out = &iface_host->endpoint[1].desc; - if (!(ati_remote->endpoint_in->bEndpointAddress & 0x80)) { + if (!(endpoint_in->bEndpointAddress & USB_DIR_IN)) { err("%s: Unexpected endpoint_in->bEndpointAddress\n", __FUNCTION__); - retval = -ENODEV; - goto error; + return -ENODEV; } - if ((ati_remote->endpoint_in->bmAttributes & 3) != 3) { + if ((endpoint_in->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT) { err("%s: Unexpected endpoint_in->bmAttributes\n", __FUNCTION__); - retval = -ENODEV; - goto error; + return -ENODEV; } - if (le16_to_cpu(ati_remote->endpoint_in->wMaxPacketSize) == 0) { + if (le16_to_cpu(endpoint_in->wMaxPacketSize) == 0) { err("%s: endpoint_in message size==0? \n", __FUNCTION__); - retval = -ENODEV; - goto error; + return -ENODEV; } - /* Allocate URB buffers, URBs */ - ati_remote->inbuf = usb_buffer_alloc(udev, DATA_BUFSIZE, SLAB_ATOMIC, - &ati_remote->inbuf_dma); - if (!ati_remote->inbuf) - goto error; + ati_remote = kzalloc(sizeof (struct ati_remote), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!ati_remote || !input_dev) + goto fail1; - ati_remote->outbuf = usb_buffer_alloc(udev, DATA_BUFSIZE, SLAB_ATOMIC, - &ati_remote->outbuf_dma); - if (!ati_remote->outbuf) - goto error; + /* Allocate URB buffers, URBs */ + if (ati_remote_alloc_buffers(udev, ati_remote)) + goto fail2; - ati_remote->irq_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!ati_remote->irq_urb) - goto error; + ati_remote->endpoint_in = endpoint_in; + ati_remote->endpoint_out = endpoint_out; + ati_remote->udev = udev; + ati_remote->idev = input_dev; + ati_remote->interface = interface; - ati_remote->out_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!ati_remote->out_urb) - goto error; + usb_make_path(udev, ati_remote->phys, sizeof(ati_remote->phys)); + strlcpy(ati_remote->phys, "/input0", sizeof(ati_remote->phys)); - usb_make_path(udev, path, NAME_BUFSIZE); - sprintf(ati_remote->phys, "%s/input%d", path, ATI_INPUTNUM); if (udev->manufacturer) - strcat(ati_remote->name, udev->manufacturer); + strlcpy(ati_remote->name, udev->manufacturer, sizeof(ati_remote->name)); if (udev->product) - sprintf(ati_remote->name, "%s %s", ati_remote->name, udev->product); + snprintf(ati_remote->name, sizeof(ati_remote->name), + "%s %s", ati_remote->name, udev->product); if (!strlen(ati_remote->name)) - sprintf(ati_remote->name, DRIVER_DESC "(%04x,%04x)", + snprintf(ati_remote->name, sizeof(ati_remote->name), + DRIVER_DESC "(%04x,%04x)", le16_to_cpu(ati_remote->udev->descriptor.idVendor), le16_to_cpu(ati_remote->udev->descriptor.idProduct)); + ati_remote_input_init(ati_remote); + /* Device Hardware Initialization - fills in ati_remote->idev from udev. */ - retval = ati_remote_initialize(ati_remote); - if (retval) - goto error; + err = ati_remote_initialize(ati_remote); + if (err) + goto fail3; /* Set up and register input device */ - ati_remote_input_init(ati_remote); - input_register_device(&ati_remote->idev); - - dev_info(&ati_remote->interface->dev, "Input registered: %s on %s\n", - ati_remote->name, path); + input_register_device(ati_remote->idev); usb_set_intfdata(interface, ati_remote); + return 0; -error: - if (retval) - ati_remote_delete(ati_remote); - - return retval; +fail3: usb_kill_urb(ati_remote->irq_urb); + usb_kill_urb(ati_remote->out_urb); +fail2: ati_remote_free_buffers(ati_remote); +fail1: input_free_device(input_dev); + kfree(ati_remote); + return err; } /* @@ -791,7 +792,11 @@ static void ati_remote_disconnect(struct usb_interface *interface) return; } - ati_remote_delete(ati_remote); + usb_kill_urb(ati_remote->irq_urb); + usb_kill_urb(ati_remote->out_urb); + input_unregister_device(ati_remote->idev); + ati_remote_free_buffers(ati_remote); + kfree(ati_remote); } /* diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 41f92b924761..79ddce4555ab 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -1619,8 +1619,8 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) struct hid_descriptor *hdesc; struct hid_device *hid; unsigned quirks = 0, rsize = 0; - char *buf, *rdesc; - int n, insize = 0; + char *rdesc; + int n, len, insize = 0; for (n = 0; hid_blacklist[n].idVendor; n++) if ((hid_blacklist[n].idVendor == le16_to_cpu(dev->descriptor.idVendor)) && @@ -1630,10 +1630,11 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) if (quirks & HID_QUIRK_IGNORE) return NULL; - if (usb_get_extra_descriptor(interface, HID_DT_HID, &hdesc) && ((!interface->desc.bNumEndpoints) || - usb_get_extra_descriptor(&interface->endpoint[0], HID_DT_HID, &hdesc))) { - dbg("class descriptor not present\n"); - return NULL; + if (usb_get_extra_descriptor(interface, HID_DT_HID, &hdesc) && + (!interface->desc.bNumEndpoints || + usb_get_extra_descriptor(&interface->endpoint[0], HID_DT_HID, &hdesc))) { + dbg("class descriptor not present\n"); + return NULL; } for (n = 0; n < hdesc->bNumDescriptors; n++) @@ -1749,38 +1750,43 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) hid->name[0] = 0; - if (!(buf = kmalloc(64, GFP_KERNEL))) - goto fail; + if (dev->manufacturer) + strlcpy(hid->name, dev->manufacturer, sizeof(hid->name)); + + if (dev->product) { + if (dev->manufacturer) + strlcat(hid->name, " ", sizeof(hid->name)); + strlcat(hid->name, dev->product, sizeof(hid->name)); + } - if (dev->manufacturer) { - strcat(hid->name, dev->manufacturer); - if (dev->product) - snprintf(hid->name, 64, "%s %s", hid->name, dev->product); - } else if (dev->product) { - snprintf(hid->name, 128, "%s", dev->product); - } else - snprintf(hid->name, 128, "%04x:%04x", - le16_to_cpu(dev->descriptor.idVendor), - le16_to_cpu(dev->descriptor.idProduct)); - - usb_make_path(dev, buf, 64); - snprintf(hid->phys, 64, "%s/input%d", buf, - intf->altsetting[0].desc.bInterfaceNumber); + if (!strlen(hid->name)) + snprintf(hid->name, sizeof(hid->name), "HID %04x:%04x", + le16_to_cpu(dev->descriptor.idVendor), + le16_to_cpu(dev->descriptor.idProduct)); + + usb_make_path(dev, hid->phys, sizeof(hid->phys)); + strlcat(hid->phys, "/input", sizeof(hid->phys)); + len = strlen(hid->phys); + if (len < sizeof(hid->phys) - 1) + snprintf(hid->phys + len, sizeof(hid->phys) - len, + "%d", intf->altsetting[0].desc.bInterfaceNumber); if (usb_string(dev, dev->descriptor.iSerialNumber, hid->uniq, 64) <= 0) hid->uniq[0] = 0; - kfree(buf); - hid->urbctrl = usb_alloc_urb(0, GFP_KERNEL); if (!hid->urbctrl) goto fail; + usb_fill_control_urb(hid->urbctrl, dev, 0, (void *) hid->cr, hid->ctrlbuf, 1, hid_ctrl, hid); hid->urbctrl->setup_dma = hid->cr_dma; hid->urbctrl->transfer_dma = hid->ctrlbuf_dma; hid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP); + /* May be needed for some devices */ + usb_clear_halt(hid->dev, hid->urbin->pipe); + return hid; fail: @@ -1884,7 +1890,6 @@ static int hid_suspend(struct usb_interface *intf, pm_message_t message) struct hid_device *hid = usb_get_intfdata (intf); usb_kill_urb(hid->urbin); - intf->dev.power.power_state = PMSG_SUSPEND; dev_dbg(&intf->dev, "suspend\n"); return 0; } @@ -1894,7 +1899,6 @@ static int hid_resume(struct usb_interface *intf) struct hid_device *hid = usb_get_intfdata (intf); int status; - intf->dev.power.power_state = PMSG_ON; if (hid->open) status = usb_submit_urb(hid->urbin, GFP_NOIO); else diff --git a/drivers/usb/input/hid-input.c b/drivers/usb/input/hid-input.c index 0b6452248a39..9ff25eb520a6 100644 --- a/drivers/usb/input/hid-input.c +++ b/drivers/usb/input/hid-input.c @@ -76,8 +76,8 @@ static struct { static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field, struct hid_usage *usage) { - struct input_dev *input = &hidinput->input; - struct hid_device *device = hidinput->input.private; + struct input_dev *input = hidinput->input; + struct hid_device *device = input->private; int max = 0, code; unsigned long *bit = NULL; @@ -461,7 +461,8 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct if (!field->hidinput) return; - input = &field->hidinput->input; + + input = field->hidinput->input; input_regs(input, regs); @@ -533,13 +534,10 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct void hidinput_report_event(struct hid_device *hid, struct hid_report *report) { - struct list_head *lh; struct hid_input *hidinput; - list_for_each (lh, &hid->inputs) { - hidinput = list_entry(lh, struct hid_input, list); - input_sync(&hidinput->input); - } + list_for_each_entry(hidinput, &hid->inputs, list) + input_sync(hidinput->input); } static int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field) @@ -604,6 +602,7 @@ int hidinput_connect(struct hid_device *hid) struct usb_device *dev = hid->dev; struct hid_report *report; struct hid_input *hidinput = NULL; + struct input_dev *input_dev; int i, j, k; INIT_LIST_HEAD(&hid->inputs); @@ -624,25 +623,28 @@ int hidinput_connect(struct hid_device *hid) continue; if (!hidinput) { - hidinput = kmalloc(sizeof(*hidinput), GFP_KERNEL); - if (!hidinput) { + hidinput = kzalloc(sizeof(*hidinput), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!hidinput || !input_dev) { + kfree(hidinput); + input_free_device(input_dev); err("Out of memory during hid input probe"); return -1; } - memset(hidinput, 0, sizeof(*hidinput)); - list_add_tail(&hidinput->list, &hid->inputs); + input_dev->private = hid; + input_dev->event = hidinput_input_event; + input_dev->open = hidinput_open; + input_dev->close = hidinput_close; - hidinput->input.private = hid; - hidinput->input.event = hidinput_input_event; - hidinput->input.open = hidinput_open; - hidinput->input.close = hidinput_close; + input_dev->name = hid->name; + input_dev->phys = hid->phys; + input_dev->uniq = hid->uniq; + usb_to_input_id(dev, &input_dev->id); + input_dev->cdev.dev = &hid->intf->dev; - hidinput->input.name = hid->name; - hidinput->input.phys = hid->phys; - hidinput->input.uniq = hid->uniq; - usb_to_input_id(dev, &hidinput->input.id); - hidinput->input.dev = &hid->intf->dev; + hidinput->input = input_dev; + list_add_tail(&hidinput->list, &hid->inputs); } for (i = 0; i < report->maxfield; i++) @@ -657,7 +659,7 @@ int hidinput_connect(struct hid_device *hid) * UGCI) cram a lot of unrelated inputs into the * same interface. */ hidinput->report = report; - input_register_device(&hidinput->input); + input_register_device(hidinput->input); hidinput = NULL; } } @@ -667,7 +669,7 @@ int hidinput_connect(struct hid_device *hid) * only useful in this case, and not for multi-input quirks. */ if (hidinput) { hid_ff_init(hid); - input_register_device(&hidinput->input); + input_register_device(hidinput->input); } return 0; @@ -675,13 +677,11 @@ int hidinput_connect(struct hid_device *hid) void hidinput_disconnect(struct hid_device *hid) { - struct list_head *lh, *next; - struct hid_input *hidinput; + struct hid_input *hidinput, *next; - list_for_each_safe(lh, next, &hid->inputs) { - hidinput = list_entry(lh, struct hid_input, list); - input_unregister_device(&hidinput->input); + list_for_each_entry_safe(hidinput, next, &hid->inputs, list) { list_del(&hidinput->list); + input_unregister_device(hidinput->input); kfree(hidinput); } } diff --git a/drivers/usb/input/hid-lgff.c b/drivers/usb/input/hid-lgff.c index 0c4c77aa31ea..f82c9c9e5d51 100644 --- a/drivers/usb/input/hid-lgff.c +++ b/drivers/usb/input/hid-lgff.c @@ -255,22 +255,19 @@ static void hid_lgff_input_init(struct hid_device* hid) u16 idVendor = le16_to_cpu(hid->dev->descriptor.idVendor); u16 idProduct = le16_to_cpu(hid->dev->descriptor.idProduct); struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); + struct input_dev *input_dev = hidinput->input; while (dev->idVendor && (idVendor != dev->idVendor || idProduct != dev->idProduct)) dev++; - ff = dev->ff; + for (ff = dev->ff; *ff >= 0; ff++) + set_bit(*ff, input_dev->ffbit); - while (*ff >= 0) { - set_bit(*ff, hidinput->input.ffbit); - ++ff; - } - - hidinput->input.upload_effect = hid_lgff_upload_effect; - hidinput->input.flush = hid_lgff_flush; + input_dev->upload_effect = hid_lgff_upload_effect; + input_dev->flush = hid_lgff_flush; - set_bit(EV_FF, hidinput->input.evbit); - hidinput->input.ff_effects_max = LGFF_EFFECTS; + set_bit(EV_FF, input_dev->evbit); + input_dev->ff_effects_max = LGFF_EFFECTS; } static void hid_lgff_exit(struct hid_device* hid) diff --git a/drivers/usb/input/hid-tmff.c b/drivers/usb/input/hid-tmff.c index 8f6a0a6f94a9..023fd5ac31c8 100644 --- a/drivers/usb/input/hid-tmff.c +++ b/drivers/usb/input/hid-tmff.c @@ -111,6 +111,7 @@ int hid_tmff_init(struct hid_device *hid) struct tmff_device *private; struct list_head *pos; struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); + struct input_dev *input_dev = hidinput->input; private = kmalloc(sizeof(struct tmff_device), GFP_KERNEL); if (!private) @@ -155,7 +156,7 @@ int hid_tmff_init(struct hid_device *hid) private->report = report; private->rumble = field; - set_bit(FF_RUMBLE, hidinput->input.ffbit); + set_bit(FF_RUMBLE, input_dev->ffbit); break; default: @@ -164,11 +165,11 @@ int hid_tmff_init(struct hid_device *hid) } /* Fallthrough to here only when a valid usage is found */ - hidinput->input.upload_effect = hid_tmff_upload_effect; - hidinput->input.flush = hid_tmff_flush; + input_dev->upload_effect = hid_tmff_upload_effect; + input_dev->flush = hid_tmff_flush; - set_bit(EV_FF, hidinput->input.evbit); - hidinput->input.ff_effects_max = TMFF_EFFECTS; + set_bit(EV_FF, input_dev->evbit); + input_dev->ff_effects_max = TMFF_EFFECTS; } } diff --git a/drivers/usb/input/hid.h b/drivers/usb/input/hid.h index ec2412c42f1e..ee48a2276104 100644 --- a/drivers/usb/input/hid.h +++ b/drivers/usb/input/hid.h @@ -371,7 +371,7 @@ struct hid_control_fifo { struct hid_input { struct list_head list; struct hid_report *report; - struct input_dev input; + struct input_dev *input; }; struct hid_device { /* device report descriptor */ diff --git a/drivers/usb/input/hiddev.c b/drivers/usb/input/hiddev.c index d32427818af7..440377c7a0da 100644 --- a/drivers/usb/input/hiddev.c +++ b/drivers/usb/input/hiddev.c @@ -732,9 +732,8 @@ static struct file_operations hiddev_fops = { }; static struct usb_class_driver hiddev_class = { - .name = "usb/hid/hiddev%d", + .name = "hiddev%d", .fops = &hiddev_fops, - .mode = S_IFCHR | S_IRUGO | S_IWUSR, .minor_base = HIDDEV_MINOR_BASE, }; diff --git a/drivers/usb/input/itmtouch.c b/drivers/usb/input/itmtouch.c index becb87efb869..3b581853cf10 100644 --- a/drivers/usb/input/itmtouch.c +++ b/drivers/usb/input/itmtouch.c @@ -73,7 +73,7 @@ MODULE_LICENSE( DRIVER_LICENSE ); struct itmtouch_dev { struct usb_device *usbdev; /* usb device */ - struct input_dev inputdev; /* input device */ + struct input_dev *inputdev; /* input device */ struct urb *readurb; /* urb */ char rbuf[ITM_BUFSIZE]; /* data */ int users; @@ -88,9 +88,9 @@ static struct usb_device_id itmtouch_ids [] = { static void itmtouch_irq(struct urb *urb, struct pt_regs *regs) { - struct itmtouch_dev * itmtouch = urb->context; + struct itmtouch_dev *itmtouch = urb->context; unsigned char *data = urb->transfer_buffer; - struct input_dev *dev = &itmtouch->inputdev; + struct input_dev *dev = itmtouch->inputdev; int retval; switch (urb->status) { @@ -156,49 +156,62 @@ static void itmtouch_close(struct input_dev *input) static int itmtouch_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct itmtouch_dev *itmtouch; + struct input_dev *input_dev; struct usb_host_interface *interface; struct usb_endpoint_descriptor *endpoint; struct usb_device *udev = interface_to_usbdev(intf); unsigned int pipe; unsigned int maxp; - char path[PATH_SIZE]; interface = intf->cur_altsetting; endpoint = &interface->endpoint[0].desc; - if (!(itmtouch = kzalloc(sizeof(struct itmtouch_dev), GFP_KERNEL))) { + itmtouch = kzalloc(sizeof(struct itmtouch_dev), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!itmtouch || !input_dev) { err("%s - Out of memory.", __FUNCTION__); - return -ENOMEM; + goto fail; } itmtouch->usbdev = udev; + itmtouch->inputdev = input_dev; - itmtouch->inputdev.private = itmtouch; - itmtouch->inputdev.open = itmtouch_open; - itmtouch->inputdev.close = itmtouch_close; + if (udev->manufacturer) + strlcpy(itmtouch->name, udev->manufacturer, sizeof(itmtouch->name)); - usb_make_path(udev, path, PATH_SIZE); - - itmtouch->inputdev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - itmtouch->inputdev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE); - itmtouch->inputdev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); - - itmtouch->inputdev.name = itmtouch->name; - itmtouch->inputdev.phys = itmtouch->phys; - usb_to_input_id(udev, &itmtouch->inputdev.id); - itmtouch->inputdev.dev = &intf->dev; + if (udev->product) { + if (udev->manufacturer) + strlcat(itmtouch->name, " ", sizeof(itmtouch->name)); + strlcat(itmtouch->name, udev->product, sizeof(itmtouch->name)); + } if (!strlen(itmtouch->name)) sprintf(itmtouch->name, "USB ITM touchscreen"); + usb_make_path(udev, itmtouch->phys, sizeof(itmtouch->phys)); + strlcpy(itmtouch->phys, "/input0", sizeof(itmtouch->phys)); + + input_dev->name = itmtouch->name; + input_dev->phys = itmtouch->phys; + usb_to_input_id(udev, &input_dev->id); + input_dev->cdev.dev = &intf->dev; + input_dev->private = itmtouch; + + input_dev->open = itmtouch_open; + input_dev->close = itmtouch_close; + + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + input_dev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE); + input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); + /* device limits */ /* as specified by the ITM datasheet, X and Y are 12bit, * Z (pressure) is 8 bit. However, the fields are defined up * to 14 bits for future possible expansion. */ - input_set_abs_params(&itmtouch->inputdev, ABS_X, 0, 0x0FFF, 2, 0); - input_set_abs_params(&itmtouch->inputdev, ABS_Y, 0, 0x0FFF, 2, 0); - input_set_abs_params(&itmtouch->inputdev, ABS_PRESSURE, 0, 0xFF, 2, 0); + input_set_abs_params(input_dev, ABS_X, 0, 0x0FFF, 2, 0); + input_set_abs_params(input_dev, ABS_Y, 0, 0x0FFF, 2, 0); + input_set_abs_params(input_dev, ABS_PRESSURE, 0, 0xFF, 2, 0); /* initialise the URB so we can read from the transport stream */ pipe = usb_rcvintpipe(itmtouch->usbdev, endpoint->bEndpointAddress); @@ -208,22 +221,23 @@ static int itmtouch_probe(struct usb_interface *intf, const struct usb_device_id maxp = ITM_BUFSIZE; itmtouch->readurb = usb_alloc_urb(0, GFP_KERNEL); - if (!itmtouch->readurb) { dbg("%s - usb_alloc_urb failed: itmtouch->readurb", __FUNCTION__); - kfree(itmtouch); - return -ENOMEM; + goto fail; } usb_fill_int_urb(itmtouch->readurb, itmtouch->usbdev, pipe, itmtouch->rbuf, maxp, itmtouch_irq, itmtouch, endpoint->bInterval); - input_register_device(&itmtouch->inputdev); + input_register_device(itmtouch->inputdev); - printk(KERN_INFO "itmtouch: %s registered on %s\n", itmtouch->name, path); usb_set_intfdata(intf, itmtouch); return 0; + + fail: input_free_device(input_dev); + kfree(itmtouch); + return -ENOMEM; } static void itmtouch_disconnect(struct usb_interface *intf) @@ -233,7 +247,7 @@ static void itmtouch_disconnect(struct usb_interface *intf) usb_set_intfdata(intf, NULL); if (itmtouch) { - input_unregister_device(&itmtouch->inputdev); + input_unregister_device(itmtouch->inputdev); usb_kill_urb(itmtouch->readurb); usb_free_urb(itmtouch->readurb); kfree(itmtouch); diff --git a/drivers/usb/input/kbtab.c b/drivers/usb/input/kbtab.c index b6f6ac8d9c2f..a248664b5d1d 100644 --- a/drivers/usb/input/kbtab.c +++ b/drivers/usb/input/kbtab.c @@ -34,7 +34,7 @@ MODULE_PARM_DESC(kb_pressure_click, "pressure threshold for clicks"); struct kbtab { signed char *data; dma_addr_t data_dma; - struct input_dev dev; + struct input_dev *dev; struct usb_device *usbdev; struct urb *irq; int x, y; @@ -48,7 +48,7 @@ static void kbtab_irq(struct urb *urb, struct pt_regs *regs) { struct kbtab *kbtab = urb->context; unsigned char *data = kbtab->data; - struct input_dev *dev = &kbtab->dev; + struct input_dev *dev = kbtab->dev; int retval; switch (urb->status) { @@ -124,53 +124,43 @@ static int kbtab_probe(struct usb_interface *intf, const struct usb_device_id *i struct usb_device *dev = interface_to_usbdev(intf); struct usb_endpoint_descriptor *endpoint; struct kbtab *kbtab; - char path[64]; + struct input_dev *input_dev; - if (!(kbtab = kmalloc(sizeof(struct kbtab), GFP_KERNEL))) - return -ENOMEM; - memset(kbtab, 0, sizeof(struct kbtab)); + kbtab = kzalloc(sizeof(struct kbtab), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!kbtab || !input_dev) + goto fail1; kbtab->data = usb_buffer_alloc(dev, 8, GFP_KERNEL, &kbtab->data_dma); - if (!kbtab->data) { - kfree(kbtab); - return -ENOMEM; - } + if (!kbtab->data) + goto fail1; kbtab->irq = usb_alloc_urb(0, GFP_KERNEL); - if (!kbtab->irq) { - usb_buffer_free(dev, 10, kbtab->data, kbtab->data_dma); - kfree(kbtab); - return -ENOMEM; - } - - kbtab->dev.evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_MSC); - kbtab->dev.absbit[0] |= BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE); - - kbtab->dev.keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE); - - kbtab->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_PEN) | BIT(BTN_TOUCH); + if (!kbtab->irq) + goto fail2; - kbtab->dev.mscbit[0] |= BIT(MSC_SERIAL); - - kbtab->dev.absmax[ABS_X] = 0x2000; - kbtab->dev.absmax[ABS_Y] = 0x1750; - kbtab->dev.absmax[ABS_PRESSURE] = 0xff; + kbtab->usbdev = dev; + kbtab->dev = input_dev; - kbtab->dev.absfuzz[ABS_X] = 4; - kbtab->dev.absfuzz[ABS_Y] = 4; + usb_make_path(dev, kbtab->phys, sizeof(kbtab->phys)); + strlcat(kbtab->phys, "/input0", sizeof(kbtab->phys)); - kbtab->dev.private = kbtab; - kbtab->dev.open = kbtab_open; - kbtab->dev.close = kbtab_close; + input_dev->name = "KB Gear Tablet"; + input_dev->phys = kbtab->phys; + usb_to_input_id(dev, &input_dev->id); + input_dev->cdev.dev = &intf->dev; + input_dev->private = kbtab; - usb_make_path(dev, path, 64); - sprintf(kbtab->phys, "%s/input0", path); + input_dev->open = kbtab_open; + input_dev->close = kbtab_close; - kbtab->dev.name = "KB Gear Tablet"; - kbtab->dev.phys = kbtab->phys; - usb_to_input_id(dev, &kbtab->dev.id); - kbtab->dev.dev = &intf->dev; - kbtab->usbdev = dev; + input_dev->evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_MSC); + input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE); + input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_PEN) | BIT(BTN_TOUCH); + input_dev->mscbit[0] |= BIT(MSC_SERIAL); + input_set_abs_params(input_dev, ABS_X, 0, 0x2000, 4, 0); + input_set_abs_params(input_dev, ABS_X, 0, 0x1750, 4, 0); + input_set_abs_params(input_dev, ABS_PRESSURE, 0, 0xff, 0, 0); endpoint = &intf->cur_altsetting->endpoint[0].desc; @@ -181,23 +171,25 @@ static int kbtab_probe(struct usb_interface *intf, const struct usb_device_id *i kbtab->irq->transfer_dma = kbtab->data_dma; kbtab->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - input_register_device(&kbtab->dev); - - printk(KERN_INFO "input: KB Gear Tablet on %s\n", path); + input_register_device(kbtab->dev); usb_set_intfdata(intf, kbtab); - return 0; + +fail2: usb_buffer_free(dev, 10, kbtab->data, kbtab->data_dma); +fail1: input_free_device(input_dev); + kfree(kbtab); + return -ENOMEM; } static void kbtab_disconnect(struct usb_interface *intf) { - struct kbtab *kbtab = usb_get_intfdata (intf); + struct kbtab *kbtab = usb_get_intfdata(intf); usb_set_intfdata(intf, NULL); if (kbtab) { usb_kill_urb(kbtab->irq); - input_unregister_device(&kbtab->dev); + input_unregister_device(kbtab->dev); usb_free_urb(kbtab->irq); usb_buffer_free(interface_to_usbdev(intf), 10, kbtab->data, kbtab->data_dma); kfree(kbtab); diff --git a/drivers/usb/input/keyspan_remote.c b/drivers/usb/input/keyspan_remote.c index 99de1b33c07d..5b8d65f62abf 100644 --- a/drivers/usb/input/keyspan_remote.c +++ b/drivers/usb/input/keyspan_remote.c @@ -20,6 +20,7 @@ #include <linux/moduleparam.h> #include <linux/input.h> #include <linux/usb.h> +#include <linux/usb_input.h> #define DRIVER_VERSION "v0.1" #define DRIVER_AUTHOR "Michael Downey <downey@zymeta.com>" @@ -75,7 +76,7 @@ struct usb_keyspan { char name[128]; char phys[64]; struct usb_device* udev; - struct input_dev input; + struct input_dev *input; struct usb_interface* interface; struct usb_endpoint_descriptor* in_endpoint; struct urb* irq_urb; @@ -136,12 +137,11 @@ static struct usb_driver keyspan_driver; */ static void keyspan_print(struct usb_keyspan* dev) /*unsigned char* data)*/ { - char codes[4*RECV_SIZE]; + char codes[4 * RECV_SIZE]; int i; - for (i = 0; i < RECV_SIZE; i++) { - snprintf(codes+i*3, 4, "%02x ", dev->in_buffer[i]); - } + for (i = 0; i < RECV_SIZE; i++) + snprintf(codes + i * 3, 4, "%02x ", dev->in_buffer[i]); dev_info(&dev->udev->dev, "%s\n", codes); } @@ -153,7 +153,7 @@ static void keyspan_print(struct usb_keyspan* dev) /*unsigned char* data)*/ static int keyspan_load_tester(struct usb_keyspan* dev, int bits_needed) { if (dev->data.bits_left >= bits_needed) - return(0); + return 0; /* * Somehow we've missed the last message. The message will be repeated @@ -162,7 +162,7 @@ static int keyspan_load_tester(struct usb_keyspan* dev, int bits_needed) if (dev->data.pos >= dev->data.len) { dev_dbg(&dev->udev, "%s - Error ran out of data. pos: %d, len: %d\n", __FUNCTION__, dev->data.pos, dev->data.len); - return(-1); + return -1; } /* Load as much as we can into the tester. */ @@ -172,7 +172,7 @@ static int keyspan_load_tester(struct usb_keyspan* dev, int bits_needed) dev->data.bits_left += 8; } - return(0); + return 0; } /* @@ -311,10 +311,10 @@ static void keyspan_check_data(struct usb_keyspan *remote, struct pt_regs *regs) __FUNCTION__, message.system, message.button, message.toggle); if (message.toggle != remote->toggle) { - input_regs(&remote->input, regs); - input_report_key(&remote->input, keyspan_key_table[message.button], 1); - input_report_key(&remote->input, keyspan_key_table[message.button], 0); - input_sync(&remote->input); + input_regs(remote->input, regs); + input_report_key(remote->input, keyspan_key_table[message.button], 1); + input_report_key(remote->input, keyspan_key_table[message.button], 0); + input_sync(remote->input); remote->toggle = message.toggle; } @@ -397,14 +397,9 @@ static int keyspan_open(struct input_dev *dev) { struct usb_keyspan *remote = dev->private; - if (remote->open++) - return 0; - remote->irq_urb->dev = remote->udev; - if (usb_submit_urb(remote->irq_urb, GFP_KERNEL)) { - remote->open--; + if (usb_submit_urb(remote->irq_urb, GFP_KERNEL)) return -EIO; - } return 0; } @@ -413,8 +408,26 @@ static void keyspan_close(struct input_dev *dev) { struct usb_keyspan *remote = dev->private; - if (!--remote->open) - usb_kill_urb(remote->irq_urb); + usb_kill_urb(remote->irq_urb); +} + +static struct usb_endpoint_descriptor *keyspan_get_in_endpoint(struct usb_host_interface *iface) +{ + + struct usb_endpoint_descriptor *endpoint; + int i; + + for (i = 0; i < iface->desc.bNumEndpoints; ++i) { + endpoint = &iface->endpoint[i].desc; + + if ((endpoint->bEndpointAddress & USB_DIR_IN) && + ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)) { + /* we found our interrupt in endpoint */ + return endpoint; + } + } + + return NULL; } /* @@ -422,110 +435,78 @@ static void keyspan_close(struct input_dev *dev) */ static int keyspan_probe(struct usb_interface *interface, const struct usb_device_id *id) { - int i; - int retval = -ENOMEM; - char path[64]; - char *buf; - struct usb_keyspan *remote = NULL; - struct usb_host_interface *iface_desc; + struct usb_device *udev = interface_to_usbdev(interface); struct usb_endpoint_descriptor *endpoint; - struct usb_device *udev = usb_get_dev(interface_to_usbdev(interface)); + struct usb_keyspan *remote; + struct input_dev *input_dev; + int i, retval; - /* allocate memory for our device state and initialize it */ - remote = kmalloc(sizeof(*remote), GFP_KERNEL); - if (remote == NULL) { - err("Out of memory\n"); - goto error; + endpoint = keyspan_get_in_endpoint(interface->cur_altsetting); + if (!endpoint) + return -ENODEV; + + remote = kzalloc(sizeof(*remote), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!remote || !input_dev) { + retval = -ENOMEM; + goto fail1; } - memset(remote, 0x00, sizeof(*remote)); remote->udev = udev; + remote->input = input_dev; remote->interface = interface; + remote->in_endpoint = endpoint; remote->toggle = -1; /* Set to -1 so we will always not match the toggle from the first remote message. */ - /* set up the endpoint information */ - /* use only the first in interrupt endpoint */ - iface_desc = interface->cur_altsetting; - for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { - endpoint = &iface_desc->endpoint[i].desc; - - if (!remote->in_endpoint && - (endpoint->bEndpointAddress & USB_DIR_IN) && - ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)) { - /* we found our interrupt in endpoint */ - remote->in_endpoint = endpoint; - - remote->in_buffer = usb_buffer_alloc(remote->udev, RECV_SIZE, SLAB_ATOMIC, &remote->in_dma); - if (!remote->in_buffer) { - retval = -ENOMEM; - goto error; - } - } - } - - if (!remote->in_endpoint) { - err("Could not find interrupt input endpoint.\n"); - retval = -ENODEV; - goto error; + remote->in_buffer = usb_buffer_alloc(udev, RECV_SIZE, SLAB_ATOMIC, &remote->in_dma); + if (!remote->in_buffer) { + retval = -ENOMEM; + goto fail1; } remote->irq_urb = usb_alloc_urb(0, GFP_KERNEL); if (!remote->irq_urb) { - err("Failed to allocate urb.\n"); retval = -ENOMEM; - goto error; + goto fail2; } - retval = keyspan_setup(remote->udev); + retval = keyspan_setup(udev); if (retval) { - err("Failed to setup device.\n"); retval = -ENODEV; - goto error; - } - - /* - * Setup the input system with the bits we are going to be reporting - */ - remote->input.evbit[0] = BIT(EV_KEY); /* We will only report KEY events. */ - for (i = 0; i < 32; ++i) { - if (keyspan_key_table[i] != KEY_RESERVED) { - set_bit(keyspan_key_table[i], remote->input.keybit); - } + goto fail3; } - remote->input.private = remote; - remote->input.open = keyspan_open; - remote->input.close = keyspan_close; - - usb_make_path(remote->udev, path, 64); - sprintf(remote->phys, "%s/input0", path); + if (udev->manufacturer) + strlcpy(remote->name, udev->manufacturer, sizeof(remote->name)); - remote->input.name = remote->name; - remote->input.phys = remote->phys; - remote->input.id.bustype = BUS_USB; - remote->input.id.vendor = le16_to_cpu(remote->udev->descriptor.idVendor); - remote->input.id.product = le16_to_cpu(remote->udev->descriptor.idProduct); - remote->input.id.version = le16_to_cpu(remote->udev->descriptor.bcdDevice); - - if (!(buf = kmalloc(63, GFP_KERNEL))) { - usb_buffer_free(remote->udev, RECV_SIZE, remote->in_buffer, remote->in_dma); - kfree(remote); - return -ENOMEM; + if (udev->product) { + if (udev->manufacturer) + strlcat(remote->name, " ", sizeof(remote->name)); + strlcat(remote->name, udev->product, sizeof(remote->name)); } - if (remote->udev->descriptor.iManufacturer && - usb_string(remote->udev, remote->udev->descriptor.iManufacturer, buf, 63) > 0) - strcat(remote->name, buf); + if (!strlen(remote->name)) + snprintf(remote->name, sizeof(remote->name), + "USB Keyspan Remote %04x:%04x", + le16_to_cpu(udev->descriptor.idVendor), + le16_to_cpu(udev->descriptor.idProduct)); - if (remote->udev->descriptor.iProduct && - usb_string(remote->udev, remote->udev->descriptor.iProduct, buf, 63) > 0) - sprintf(remote->name, "%s %s", remote->name, buf); + usb_make_path(udev, remote->phys, sizeof(remote->phys)); + strlcat(remote->phys, "/input0", sizeof(remote->phys)); - if (!strlen(remote->name)) - sprintf(remote->name, "USB Keyspan Remote %04x:%04x", - remote->input.id.vendor, remote->input.id.product); + input_dev->name = remote->name; + input_dev->phys = remote->phys; + usb_to_input_id(udev, &input_dev->id); + input_dev->cdev.dev = &interface->dev; - kfree(buf); + input_dev->evbit[0] = BIT(EV_KEY); /* We will only report KEY events. */ + for (i = 0; i < ARRAY_SIZE(keyspan_key_table); i++) + if (keyspan_key_table[i] != KEY_RESERVED) + set_bit(keyspan_key_table[i], input_dev->keybit); + + input_dev->private = remote; + input_dev->open = keyspan_open; + input_dev->close = keyspan_close; /* * Initialize the URB to access the device. The urb gets sent to the device in keyspan_open() @@ -538,27 +519,17 @@ static int keyspan_probe(struct usb_interface *interface, const struct usb_devic remote->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; /* we can register the device now, as it is ready */ - input_register_device(&remote->input); + input_register_device(remote->input); /* save our data pointer in this interface device */ usb_set_intfdata(interface, remote); - /* let the user know what node this device is now attached to */ - info("connected: %s on %s", remote->name, path); return 0; -error: - /* - * In case of error we need to clean up any allocated buffers - */ - if (remote->irq_urb) - usb_free_urb(remote->irq_urb); - - if (remote->in_buffer) - usb_buffer_free(remote->udev, RECV_SIZE, remote->in_buffer, remote->in_dma); - - if (remote) - kfree(remote); + fail3: usb_free_urb(remote->irq_urb); + fail2: usb_buffer_free(udev, RECV_SIZE, remote->in_buffer, remote->in_dma); + fail1: kfree(remote); + input_free_device(input_dev); return retval; } @@ -570,23 +541,16 @@ static void keyspan_disconnect(struct usb_interface *interface) { struct usb_keyspan *remote; - /* prevent keyspan_open() from racing keyspan_disconnect() */ - lock_kernel(); - remote = usb_get_intfdata(interface); usb_set_intfdata(interface, NULL); if (remote) { /* We have a valid driver structure so clean up everything we allocated. */ - input_unregister_device(&remote->input); + input_unregister_device(remote->input); usb_kill_urb(remote->irq_urb); usb_free_urb(remote->irq_urb); - usb_buffer_free(interface_to_usbdev(interface), RECV_SIZE, remote->in_buffer, remote->in_dma); + usb_buffer_free(remote->udev, RECV_SIZE, remote->in_buffer, remote->in_dma); kfree(remote); } - - unlock_kernel(); - - info("USB Keyspan now disconnected"); } /* diff --git a/drivers/usb/input/map_to_7segment.h b/drivers/usb/input/map_to_7segment.h index 52ff27f15127..a424094d9fe2 100644 --- a/drivers/usb/input/map_to_7segment.h +++ b/drivers/usb/input/map_to_7segment.h @@ -79,7 +79,7 @@ struct seg7_conversion_map { static inline int map_to_seg7(struct seg7_conversion_map *map, int c) { - return c & 0x7f ? map->table[c] : -EINVAL; + return c >= 0 && c < sizeof(map->table) ? map->table[c] : -EINVAL; } #define SEG7_CONVERSION_MAP(_name, _map) \ diff --git a/drivers/usb/input/mtouchusb.c b/drivers/usb/input/mtouchusb.c index ff9275057a18..7fce526560ca 100644 --- a/drivers/usb/input/mtouchusb.c +++ b/drivers/usb/input/mtouchusb.c @@ -98,7 +98,7 @@ struct mtouch_usb { dma_addr_t data_dma; struct urb *irq; struct usb_device *udev; - struct input_dev input; + struct input_dev *input; char name[128]; char phys[64]; }; @@ -135,14 +135,14 @@ static void mtouchusb_irq(struct urb *urb, struct pt_regs *regs) goto exit; } - input_regs(&mtouch->input, regs); - input_report_key(&mtouch->input, BTN_TOUCH, + input_regs(mtouch->input, regs); + input_report_key(mtouch->input, BTN_TOUCH, MTOUCHUSB_GET_TOUCHED(mtouch->data)); - input_report_abs(&mtouch->input, ABS_X, MTOUCHUSB_GET_XC(mtouch->data)); - input_report_abs(&mtouch->input, ABS_Y, + input_report_abs(mtouch->input, ABS_X, MTOUCHUSB_GET_XC(mtouch->data)); + input_report_abs(mtouch->input, ABS_Y, (raw_coordinates ? MTOUCHUSB_MAX_RAW_YC : MTOUCHUSB_MAX_CALIB_YC) - MTOUCHUSB_GET_YC(mtouch->data)); - input_sync(&mtouch->input); + input_sync(mtouch->input); exit: retval = usb_submit_urb(urb, GFP_ATOMIC); @@ -195,10 +195,10 @@ static void mtouchusb_free_buffers(struct usb_device *udev, struct mtouch_usb *m static int mtouchusb_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct mtouch_usb *mtouch; + struct input_dev *input_dev; struct usb_host_interface *interface; struct usb_endpoint_descriptor *endpoint; struct usb_device *udev = interface_to_usbdev(intf); - char path[64]; int nRet; dbg("%s - called", __FUNCTION__); @@ -209,57 +209,55 @@ static int mtouchusb_probe(struct usb_interface *intf, const struct usb_device_i dbg("%s - setting endpoint", __FUNCTION__); endpoint = &interface->endpoint[0].desc; - if (!(mtouch = kmalloc(sizeof(struct mtouch_usb), GFP_KERNEL))) { + mtouch = kzalloc(sizeof(struct mtouch_usb), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!mtouch || !input_dev) { err("%s - Out of memory.", __FUNCTION__); - return -ENOMEM; + goto fail1; } - memset(mtouch, 0, sizeof(struct mtouch_usb)); - mtouch->udev = udev; - dbg("%s - allocating buffers", __FUNCTION__); - if (mtouchusb_alloc_buffers(udev, mtouch)) { - mtouchusb_free_buffers(udev, mtouch); - kfree(mtouch); - return -ENOMEM; - } + if (mtouchusb_alloc_buffers(udev, mtouch)) + goto fail2; - mtouch->input.private = mtouch; - mtouch->input.open = mtouchusb_open; - mtouch->input.close = mtouchusb_close; - - usb_make_path(udev, path, 64); - sprintf(mtouch->phys, "%s/input0", path); - - mtouch->input.name = mtouch->name; - mtouch->input.phys = mtouch->phys; - usb_to_input_id(udev, &mtouch->input.id); - mtouch->input.dev = &intf->dev; - - mtouch->input.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - mtouch->input.absbit[0] = BIT(ABS_X) | BIT(ABS_Y); - mtouch->input.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); - - /* Used to Scale Compensated Data and Flip Y */ - mtouch->input.absmin[ABS_X] = MTOUCHUSB_MIN_XC; - mtouch->input.absmax[ABS_X] = raw_coordinates ? - MTOUCHUSB_MAX_RAW_XC : MTOUCHUSB_MAX_CALIB_XC; - mtouch->input.absfuzz[ABS_X] = MTOUCHUSB_XC_FUZZ; - mtouch->input.absflat[ABS_X] = MTOUCHUSB_XC_FLAT; - mtouch->input.absmin[ABS_Y] = MTOUCHUSB_MIN_YC; - mtouch->input.absmax[ABS_Y] = raw_coordinates ? - MTOUCHUSB_MAX_RAW_YC : MTOUCHUSB_MAX_CALIB_YC; - mtouch->input.absfuzz[ABS_Y] = MTOUCHUSB_YC_FUZZ; - mtouch->input.absflat[ABS_Y] = MTOUCHUSB_YC_FLAT; + mtouch->udev = udev; + mtouch->input = input_dev; if (udev->manufacturer) - strcat(mtouch->name, udev->manufacturer); - if (udev->product) - sprintf(mtouch->name, "%s %s", mtouch->name, udev->product); + strlcpy(mtouch->name, udev->manufacturer, sizeof(mtouch->name)); + + if (udev->product) { + if (udev->manufacturer) + strlcat(mtouch->name, " ", sizeof(mtouch->name)); + strlcat(mtouch->name, udev->product, sizeof(mtouch->name)); + } if (!strlen(mtouch->name)) - sprintf(mtouch->name, "USB Touchscreen %04x:%04x", - mtouch->input.id.vendor, mtouch->input.id.product); + snprintf(mtouch->name, sizeof(mtouch->name), + "USB Touchscreen %04x:%04x", + le16_to_cpu(udev->descriptor.idVendor), + le16_to_cpu(udev->descriptor.idProduct)); + + usb_make_path(udev, mtouch->phys, sizeof(mtouch->phys)); + strlcpy(mtouch->phys, "/input0", sizeof(mtouch->phys)); + + input_dev->name = mtouch->name; + input_dev->phys = mtouch->phys; + usb_to_input_id(udev, &input_dev->id); + input_dev->cdev.dev = &intf->dev; + input_dev->private = mtouch; + + input_dev->open = mtouchusb_open; + input_dev->close = mtouchusb_close; + + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); + input_set_abs_params(input_dev, ABS_X, MTOUCHUSB_MIN_XC, + raw_coordinates ? MTOUCHUSB_MAX_RAW_XC : MTOUCHUSB_MAX_CALIB_XC, + MTOUCHUSB_XC_FUZZ, MTOUCHUSB_XC_FLAT); + input_set_abs_params(input_dev, ABS_Y, MTOUCHUSB_MIN_YC, + raw_coordinates ? MTOUCHUSB_MAX_RAW_YC : MTOUCHUSB_MAX_CALIB_YC, + MTOUCHUSB_YC_FUZZ, MTOUCHUSB_YC_FLAT); nRet = usb_control_msg(mtouch->udev, usb_rcvctrlpipe(udev, 0), MTOUCHUSB_RESET, @@ -272,9 +270,7 @@ static int mtouchusb_probe(struct usb_interface *intf, const struct usb_device_i mtouch->irq = usb_alloc_urb(0, GFP_KERNEL); if (!mtouch->irq) { dbg("%s - usb_alloc_urb failed: mtouch->irq", __FUNCTION__); - mtouchusb_free_buffers(udev, mtouch); - kfree(mtouch); - return -ENOMEM; + goto fail2; } dbg("%s - usb_fill_int_urb", __FUNCTION__); @@ -284,7 +280,7 @@ static int mtouchusb_probe(struct usb_interface *intf, const struct usb_device_i mtouchusb_irq, mtouch, endpoint->bInterval); dbg("%s - input_register_device", __FUNCTION__); - input_register_device(&mtouch->input); + input_register_device(mtouch->input); nRet = usb_control_msg(mtouch->udev, usb_rcvctrlpipe(udev, 0), MTOUCHUSB_ASYNC_REPORT, @@ -293,10 +289,13 @@ static int mtouchusb_probe(struct usb_interface *intf, const struct usb_device_i dbg("%s - usb_control_msg - MTOUCHUSB_ASYNC_REPORT - bytes|err: %d", __FUNCTION__, nRet); - printk(KERN_INFO "input: %s on %s\n", mtouch->name, path); usb_set_intfdata(intf, mtouch); - return 0; + +fail2: mtouchusb_free_buffers(udev, mtouch); +fail1: input_free_device(input_dev); + kfree(mtouch); + return -ENOMEM; } static void mtouchusb_disconnect(struct usb_interface *intf) @@ -308,7 +307,7 @@ static void mtouchusb_disconnect(struct usb_interface *intf) if (mtouch) { dbg("%s - mtouch is initialized, cleaning up", __FUNCTION__); usb_kill_urb(mtouch->irq); - input_unregister_device(&mtouch->input); + input_unregister_device(mtouch->input); usb_free_urb(mtouch->irq); mtouchusb_free_buffers(interface_to_usbdev(intf), mtouch); kfree(mtouch); diff --git a/drivers/usb/input/pid.c b/drivers/usb/input/pid.c index acc71ec560e9..dca5ee93a4ef 100644 --- a/drivers/usb/input/pid.c +++ b/drivers/usb/input/pid.c @@ -198,7 +198,7 @@ static int hid_pid_upload_effect(struct input_dev *dev, } effect->id = id; - dev_dbg(&pid_private->hid->dev->dev, "effect ID is %d\n.", id); + dev_dbg(&pid_private->hid->dev->dev, "effect ID is %d.\n", id); pid_private->effects[id].owner = current->pid; pid_private->effects[id].flags = (1 << FF_PID_FLAGS_USED); spin_unlock_irqrestore(&pid_private->lock, flags); @@ -262,6 +262,7 @@ int hid_pid_init(struct hid_device *hid) { struct hid_ff_pid *private; struct hid_input *hidinput = list_entry(&hid->inputs, struct hid_input, list); + struct input_dev *input_dev = hidinput->input; private = hid->ff_private = kzalloc(sizeof(struct hid_ff_pid), GFP_KERNEL); if (!private) @@ -281,11 +282,12 @@ int hid_pid_init(struct hid_device *hid) usb_fill_control_urb(private->urbffout, hid->dev, 0, (void *)&private->ffcr, private->ctrl_buffer, 8, hid_pid_ctrl_out, hid); - hidinput->input.upload_effect = hid_pid_upload_effect; - hidinput->input.flush = hid_pid_flush; - hidinput->input.ff_effects_max = 8; // A random default - set_bit(EV_FF, hidinput->input.evbit); - set_bit(EV_FF_STATUS, hidinput->input.evbit); + + input_dev->upload_effect = hid_pid_upload_effect; + input_dev->flush = hid_pid_flush; + input_dev->ff_effects_max = 8; // A random default + set_bit(EV_FF, input_dev->evbit); + set_bit(EV_FF_STATUS, input_dev->evbit); spin_lock_init(&private->lock); diff --git a/drivers/usb/input/powermate.c b/drivers/usb/input/powermate.c index ad4afe7e5897..b7476233ef5d 100644 --- a/drivers/usb/input/powermate.c +++ b/drivers/usb/input/powermate.c @@ -68,7 +68,7 @@ struct powermate_device { struct usb_ctrlrequest *configcr; dma_addr_t configcr_dma; struct usb_device *udev; - struct input_dev input; + struct input_dev *input; spinlock_t lock; int static_brightness; int pulse_speed; @@ -106,10 +106,10 @@ static void powermate_irq(struct urb *urb, struct pt_regs *regs) } /* handle updates to device state */ - input_regs(&pm->input, regs); - input_report_key(&pm->input, BTN_0, pm->data[0] & 0x01); - input_report_rel(&pm->input, REL_DIAL, pm->data[1]); - input_sync(&pm->input); + input_regs(pm->input, regs); + input_report_key(pm->input, BTN_0, pm->data[0] & 0x01); + input_report_rel(pm->input, REL_DIAL, pm->data[1]); + input_sync(pm->input); exit: retval = usb_submit_urb (urb, GFP_ATOMIC); @@ -153,10 +153,10 @@ static void powermate_sync_state(struct powermate_device *pm) Only values of 'arg' quite close to 255 are particularly useful/spectacular. */ - if (pm->pulse_speed < 255){ + if (pm->pulse_speed < 255) { op = 0; // divide arg = 255 - pm->pulse_speed; - } else if (pm->pulse_speed > 255){ + } else if (pm->pulse_speed > 255) { op = 2; // multiply arg = pm->pulse_speed - 255; } else { @@ -166,11 +166,11 @@ static void powermate_sync_state(struct powermate_device *pm) pm->configcr->wValue = cpu_to_le16( (pm->pulse_table << 8) | SET_PULSE_MODE ); pm->configcr->wIndex = cpu_to_le16( (arg << 8) | op ); pm->requires_update &= ~UPDATE_PULSE_MODE; - }else if (pm->requires_update & UPDATE_STATIC_BRIGHTNESS){ + } else if (pm->requires_update & UPDATE_STATIC_BRIGHTNESS) { pm->configcr->wValue = cpu_to_le16( SET_STATIC_BRIGHTNESS ); pm->configcr->wIndex = cpu_to_le16( pm->static_brightness ); pm->requires_update &= ~UPDATE_STATIC_BRIGHTNESS; - }else{ + } else { printk(KERN_ERR "powermate: unknown update required"); pm->requires_update = 0; /* fudge the bug */ return; @@ -228,19 +228,19 @@ static void powermate_pulse_led(struct powermate_device *pm, int static_brightne spin_lock_irqsave(&pm->lock, flags); /* mark state updates which are required */ - if (static_brightness != pm->static_brightness){ + if (static_brightness != pm->static_brightness) { pm->static_brightness = static_brightness; pm->requires_update |= UPDATE_STATIC_BRIGHTNESS; } - if (pulse_asleep != pm->pulse_asleep){ + if (pulse_asleep != pm->pulse_asleep) { pm->pulse_asleep = pulse_asleep; pm->requires_update |= (UPDATE_PULSE_ASLEEP | UPDATE_STATIC_BRIGHTNESS); } - if (pulse_awake != pm->pulse_awake){ + if (pulse_awake != pm->pulse_awake) { pm->pulse_awake = pulse_awake; pm->requires_update |= (UPDATE_PULSE_AWAKE | UPDATE_STATIC_BRIGHTNESS); } - if (pulse_speed != pm->pulse_speed || pulse_table != pm->pulse_table){ + if (pulse_speed != pm->pulse_speed || pulse_table != pm->pulse_table) { pm->pulse_speed = pulse_speed; pm->pulse_table = pulse_table; pm->requires_update |= UPDATE_PULSE_MODE; @@ -283,6 +283,7 @@ static int powermate_alloc_buffers(struct usb_device *udev, struct powermate_dev SLAB_ATOMIC, &pm->data_dma); if (!pm->data) return -1; + pm->configcr = usb_buffer_alloc(udev, sizeof(*(pm->configcr)), SLAB_ATOMIC, &pm->configcr_dma); if (!pm->configcr) @@ -308,8 +309,9 @@ static int powermate_probe(struct usb_interface *intf, const struct usb_device_i struct usb_host_interface *interface; struct usb_endpoint_descriptor *endpoint; struct powermate_device *pm; + struct input_dev *input_dev; int pipe, maxp; - char path[64]; + int err = -ENOMEM; interface = intf->cur_altsetting; endpoint = &interface->endpoint[0].desc; @@ -323,42 +325,61 @@ static int powermate_probe(struct usb_interface *intf, const struct usb_device_i 0, interface->desc.bInterfaceNumber, NULL, 0, USB_CTRL_SET_TIMEOUT); - if (!(pm = kmalloc(sizeof(struct powermate_device), GFP_KERNEL))) - return -ENOMEM; - - memset(pm, 0, sizeof(struct powermate_device)); - pm->udev = udev; + pm = kzalloc(sizeof(struct powermate_device), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!pm || !input_dev) + goto fail1; - if (powermate_alloc_buffers(udev, pm)) { - powermate_free_buffers(udev, pm); - kfree(pm); - return -ENOMEM; - } + if (powermate_alloc_buffers(udev, pm)) + goto fail2; pm->irq = usb_alloc_urb(0, GFP_KERNEL); - if (!pm->irq) { - powermate_free_buffers(udev, pm); - kfree(pm); - return -ENOMEM; - } + if (!pm->irq) + goto fail2; pm->config = usb_alloc_urb(0, GFP_KERNEL); - if (!pm->config) { - usb_free_urb(pm->irq); - powermate_free_buffers(udev, pm); - kfree(pm); - return -ENOMEM; - } + if (!pm->config) + goto fail3; + + pm->udev = udev; + pm->input = input_dev; + + usb_make_path(udev, pm->phys, sizeof(pm->phys)); + strlcpy(pm->phys, "/input0", sizeof(pm->phys)); spin_lock_init(&pm->lock); - init_input_dev(&pm->input); + + switch (le16_to_cpu(udev->descriptor.idProduct)) { + case POWERMATE_PRODUCT_NEW: + input_dev->name = pm_name_powermate; + break; + case POWERMATE_PRODUCT_OLD: + input_dev->name = pm_name_soundknob; + break; + default: + input_dev->name = pm_name_soundknob; + printk(KERN_WARNING "powermate: unknown product id %04x\n", + le16_to_cpu(udev->descriptor.idProduct)); + } + + input_dev->phys = pm->phys; + usb_to_input_id(udev, &input_dev->id); + input_dev->cdev.dev = &intf->dev; + input_dev->private = pm; + + input_dev->event = powermate_input_event; + + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_MSC); + input_dev->keybit[LONG(BTN_0)] = BIT(BTN_0); + input_dev->relbit[LONG(REL_DIAL)] = BIT(REL_DIAL); + input_dev->mscbit[LONG(MSC_PULSELED)] = BIT(MSC_PULSELED); /* get a handle to the interrupt data pipe */ pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress); maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe)); - if(maxp < POWERMATE_PAYLOAD_SIZE_MIN || maxp > POWERMATE_PAYLOAD_SIZE_MAX){ - printk("powermate: Expected payload of %d--%d bytes, found %d bytes!\n", + if (maxp < POWERMATE_PAYLOAD_SIZE_MIN || maxp > POWERMATE_PAYLOAD_SIZE_MAX) { + printk(KERN_WARNING "powermate: Expected payload of %d--%d bytes, found %d bytes!\n", POWERMATE_PAYLOAD_SIZE_MIN, POWERMATE_PAYLOAD_SIZE_MAX, maxp); maxp = POWERMATE_PAYLOAD_SIZE_MAX; } @@ -371,35 +392,11 @@ static int powermate_probe(struct usb_interface *intf, const struct usb_device_i /* register our interrupt URB with the USB system */ if (usb_submit_urb(pm->irq, GFP_KERNEL)) { - powermate_free_buffers(udev, pm); - kfree(pm); - return -EIO; /* failure */ + err = -EIO; + goto fail4; } - switch (le16_to_cpu(udev->descriptor.idProduct)) { - case POWERMATE_PRODUCT_NEW: pm->input.name = pm_name_powermate; break; - case POWERMATE_PRODUCT_OLD: pm->input.name = pm_name_soundknob; break; - default: - pm->input.name = pm_name_soundknob; - printk(KERN_WARNING "powermate: unknown product id %04x\n", - le16_to_cpu(udev->descriptor.idProduct)); - } - - pm->input.private = pm; - pm->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_MSC); - pm->input.keybit[LONG(BTN_0)] = BIT(BTN_0); - pm->input.relbit[LONG(REL_DIAL)] = BIT(REL_DIAL); - pm->input.mscbit[LONG(MSC_PULSELED)] = BIT(MSC_PULSELED); - usb_to_input_id(udev, &pm->input.id); - pm->input.event = powermate_input_event; - pm->input.dev = &intf->dev; - pm->input.phys = pm->phys; - - input_register_device(&pm->input); - - usb_make_path(udev, path, 64); - snprintf(pm->phys, 64, "%s/input0", path); - printk(KERN_INFO "input: %s on %s\n", pm->input.name, pm->input.phys); + input_register_device(pm->input); /* force an update of everything */ pm->requires_update = UPDATE_PULSE_ASLEEP | UPDATE_PULSE_AWAKE | UPDATE_PULSE_MODE | UPDATE_STATIC_BRIGHTNESS; @@ -407,6 +404,13 @@ static int powermate_probe(struct usb_interface *intf, const struct usb_device_i usb_set_intfdata(intf, pm); return 0; + +fail4: usb_free_urb(pm->config); +fail3: usb_free_urb(pm->irq); +fail2: powermate_free_buffers(udev, pm); +fail1: input_free_device(input_dev); + kfree(pm); + return err; } /* Called when a USB device we've accepted ownership of is removed */ @@ -418,7 +422,7 @@ static void powermate_disconnect(struct usb_interface *intf) if (pm) { pm->requires_update = 0; usb_kill_urb(pm->irq); - input_unregister_device(&pm->input); + input_unregister_device(pm->input); usb_free_urb(pm->irq); usb_free_urb(pm->config); powermate_free_buffers(interface_to_usbdev(intf), pm); diff --git a/drivers/usb/input/touchkitusb.c b/drivers/usb/input/touchkitusb.c index 4276c24a5080..0043e6ebcd1f 100644 --- a/drivers/usb/input/touchkitusb.c +++ b/drivers/usb/input/touchkitusb.c @@ -68,14 +68,16 @@ struct touchkit_usb { dma_addr_t data_dma; struct urb *irq; struct usb_device *udev; - struct input_dev input; + struct input_dev *input; char name[128]; char phys[64]; }; static struct usb_device_id touchkit_devices[] = { {USB_DEVICE(0x3823, 0x0001)}, + {USB_DEVICE(0x0123, 0x0001)}, {USB_DEVICE(0x0eef, 0x0001)}, + {USB_DEVICE(0x0eef, 0x0002)}, {} }; @@ -115,12 +117,12 @@ static void touchkit_irq(struct urb *urb, struct pt_regs *regs) y = TOUCHKIT_GET_Y(touchkit->data); } - input_regs(&touchkit->input, regs); - input_report_key(&touchkit->input, BTN_TOUCH, + input_regs(touchkit->input, regs); + input_report_key(touchkit->input, BTN_TOUCH, TOUCHKIT_GET_TOUCHED(touchkit->data)); - input_report_abs(&touchkit->input, ABS_X, x); - input_report_abs(&touchkit->input, ABS_Y, y); - input_sync(&touchkit->input); + input_report_abs(touchkit->input, ABS_X, x); + input_report_abs(touchkit->input, ABS_Y, y); + input_sync(touchkit->input); exit: retval = usb_submit_urb(urb, GFP_ATOMIC); @@ -171,87 +173,81 @@ static void touchkit_free_buffers(struct usb_device *udev, static int touchkit_probe(struct usb_interface *intf, const struct usb_device_id *id) { - int ret; struct touchkit_usb *touchkit; + struct input_dev *input_dev; struct usb_host_interface *interface; struct usb_endpoint_descriptor *endpoint; struct usb_device *udev = interface_to_usbdev(intf); - char path[64]; interface = intf->cur_altsetting; endpoint = &interface->endpoint[0].desc; - touchkit = kmalloc(sizeof(struct touchkit_usb), GFP_KERNEL); - if (!touchkit) - return -ENOMEM; - - memset(touchkit, 0, sizeof(struct touchkit_usb)); - touchkit->udev = udev; - - if (touchkit_alloc_buffers(udev, touchkit)) { - ret = -ENOMEM; + touchkit = kzalloc(sizeof(struct touchkit_usb), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!touchkit || !input_dev) goto out_free; - } - - touchkit->input.private = touchkit; - touchkit->input.open = touchkit_open; - touchkit->input.close = touchkit_close; - - usb_make_path(udev, path, 64); - sprintf(touchkit->phys, "%s/input0", path); - - touchkit->input.name = touchkit->name; - touchkit->input.phys = touchkit->phys; - usb_to_input_id(udev, &touchkit->input.id); - touchkit->input.dev = &intf->dev; - - touchkit->input.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - touchkit->input.absbit[0] = BIT(ABS_X) | BIT(ABS_Y); - touchkit->input.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); - - /* Used to Scale Compensated Data */ - touchkit->input.absmin[ABS_X] = TOUCHKIT_MIN_XC; - touchkit->input.absmax[ABS_X] = TOUCHKIT_MAX_XC; - touchkit->input.absfuzz[ABS_X] = TOUCHKIT_XC_FUZZ; - touchkit->input.absflat[ABS_X] = TOUCHKIT_XC_FLAT; - touchkit->input.absmin[ABS_Y] = TOUCHKIT_MIN_YC; - touchkit->input.absmax[ABS_Y] = TOUCHKIT_MAX_YC; - touchkit->input.absfuzz[ABS_Y] = TOUCHKIT_YC_FUZZ; - touchkit->input.absflat[ABS_Y] = TOUCHKIT_YC_FLAT; - - if (udev->manufacturer) - strcat(touchkit->name, udev->manufacturer); - if (udev->product) - sprintf(touchkit->name, "%s %s", touchkit->name, udev->product); - if (!strlen(touchkit->name)) - sprintf(touchkit->name, "USB Touchscreen %04x:%04x", - touchkit->input.id.vendor, touchkit->input.id.product); + if (touchkit_alloc_buffers(udev, touchkit)) + goto out_free; touchkit->irq = usb_alloc_urb(0, GFP_KERNEL); if (!touchkit->irq) { dbg("%s - usb_alloc_urb failed: touchkit->irq", __FUNCTION__); - ret = -ENOMEM; goto out_free_buffers; } + touchkit->udev = udev; + touchkit->input = input_dev; + + if (udev->manufacturer) + strlcpy(touchkit->name, udev->manufacturer, sizeof(touchkit->name)); + + if (udev->product) { + if (udev->manufacturer) + strlcat(touchkit->name, " ", sizeof(touchkit->name)); + strlcat(touchkit->name, udev->product, sizeof(touchkit->name)); + } + + if (!strlen(touchkit->name)) + snprintf(touchkit->name, sizeof(touchkit->name), + "USB Touchscreen %04x:%04x", + le16_to_cpu(udev->descriptor.idVendor), + le16_to_cpu(udev->descriptor.idProduct)); + + usb_make_path(udev, touchkit->phys, sizeof(touchkit->phys)); + strlcpy(touchkit->phys, "/input0", sizeof(touchkit->phys)); + + input_dev->name = touchkit->name; + input_dev->phys = touchkit->phys; + usb_to_input_id(udev, &input_dev->id); + input_dev->cdev.dev = &intf->dev; + input_dev->private = touchkit; + input_dev->open = touchkit_open; + input_dev->close = touchkit_close; + + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); + input_set_abs_params(input_dev, ABS_X, TOUCHKIT_MIN_XC, TOUCHKIT_MAX_XC, + TOUCHKIT_XC_FUZZ, TOUCHKIT_XC_FLAT); + input_set_abs_params(input_dev, ABS_Y, TOUCHKIT_MIN_YC, TOUCHKIT_MAX_YC, + TOUCHKIT_YC_FUZZ, TOUCHKIT_YC_FLAT); + usb_fill_int_urb(touchkit->irq, touchkit->udev, - usb_rcvintpipe(touchkit->udev, 0x81), - touchkit->data, TOUCHKIT_REPORT_DATA_SIZE, - touchkit_irq, touchkit, endpoint->bInterval); + usb_rcvintpipe(touchkit->udev, 0x81), + touchkit->data, TOUCHKIT_REPORT_DATA_SIZE, + touchkit_irq, touchkit, endpoint->bInterval); - input_register_device(&touchkit->input); + input_register_device(touchkit->input); - printk(KERN_INFO "input: %s on %s\n", touchkit->name, path); usb_set_intfdata(intf, touchkit); - return 0; out_free_buffers: touchkit_free_buffers(udev, touchkit); out_free: + input_free_device(input_dev); kfree(touchkit); - return ret; + return -ENOMEM; } static void touchkit_disconnect(struct usb_interface *intf) @@ -265,8 +261,8 @@ static void touchkit_disconnect(struct usb_interface *intf) dbg("%s - touchkit is initialized, cleaning up", __FUNCTION__); usb_set_intfdata(intf, NULL); - input_unregister_device(&touchkit->input); usb_kill_urb(touchkit->irq); + input_unregister_device(touchkit->input); usb_free_urb(touchkit->irq); touchkit_free_buffers(interface_to_usbdev(intf), touchkit); kfree(touchkit); diff --git a/drivers/usb/input/usbkbd.c b/drivers/usb/input/usbkbd.c index 28987f15eeee..226b6f90a907 100644 --- a/drivers/usb/input/usbkbd.c +++ b/drivers/usb/input/usbkbd.c @@ -66,7 +66,7 @@ static unsigned char usb_kbd_keycode[256] = { }; struct usb_kbd { - struct input_dev dev; + struct input_dev *dev; struct usb_device *usbdev; unsigned char old[8]; struct urb *irq, *led; @@ -99,29 +99,29 @@ static void usb_kbd_irq(struct urb *urb, struct pt_regs *regs) goto resubmit; } - input_regs(&kbd->dev, regs); + input_regs(kbd->dev, regs); for (i = 0; i < 8; i++) - input_report_key(&kbd->dev, usb_kbd_keycode[i + 224], (kbd->new[0] >> i) & 1); + input_report_key(kbd->dev, usb_kbd_keycode[i + 224], (kbd->new[0] >> i) & 1); for (i = 2; i < 8; i++) { if (kbd->old[i] > 3 && memscan(kbd->new + 2, kbd->old[i], 6) == kbd->new + 8) { if (usb_kbd_keycode[kbd->old[i]]) - input_report_key(&kbd->dev, usb_kbd_keycode[kbd->old[i]], 0); + input_report_key(kbd->dev, usb_kbd_keycode[kbd->old[i]], 0); else info("Unknown key (scancode %#x) released.", kbd->old[i]); } if (kbd->new[i] > 3 && memscan(kbd->old + 2, kbd->new[i], 6) == kbd->old + 8) { if (usb_kbd_keycode[kbd->new[i]]) - input_report_key(&kbd->dev, usb_kbd_keycode[kbd->new[i]], 1); + input_report_key(kbd->dev, usb_kbd_keycode[kbd->new[i]], 1); else info("Unknown key (scancode %#x) pressed.", kbd->new[i]); } } - input_sync(&kbd->dev); + input_sync(kbd->dev); memcpy(kbd->old, kbd->new, 8); @@ -227,12 +227,12 @@ static void usb_kbd_free_mem(struct usb_device *dev, struct usb_kbd *kbd) static int usb_kbd_probe(struct usb_interface *iface, const struct usb_device_id *id) { - struct usb_device * dev = interface_to_usbdev(iface); + struct usb_device *dev = interface_to_usbdev(iface); struct usb_host_interface *interface; struct usb_endpoint_descriptor *endpoint; struct usb_kbd *kbd; + struct input_dev *input_dev; int i, pipe, maxp; - char path[64]; interface = iface->cur_altsetting; @@ -240,37 +240,59 @@ static int usb_kbd_probe(struct usb_interface *iface, return -ENODEV; endpoint = &interface->endpoint[0].desc; - if (!(endpoint->bEndpointAddress & 0x80)) + if (!(endpoint->bEndpointAddress & USB_DIR_IN)) return -ENODEV; - if ((endpoint->bmAttributes & 3) != 3) + if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT) return -ENODEV; pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); - if (!(kbd = kmalloc(sizeof(struct usb_kbd), GFP_KERNEL))) - return -ENOMEM; - memset(kbd, 0, sizeof(struct usb_kbd)); + kbd = kzalloc(sizeof(struct usb_kbd), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!kbd || !input_dev) + goto fail1; - if (usb_kbd_alloc_mem(dev, kbd)) { - usb_kbd_free_mem(dev, kbd); - kfree(kbd); - return -ENOMEM; - } + if (usb_kbd_alloc_mem(dev, kbd)) + goto fail2; kbd->usbdev = dev; + kbd->dev = input_dev; + + if (dev->manufacturer) + strlcpy(kbd->name, dev->manufacturer, sizeof(kbd->name)); + + if (dev->product) { + if (dev->manufacturer) + strlcat(kbd->name, " ", sizeof(kbd->name)); + strlcat(kbd->name, dev->product, sizeof(kbd->name)); + } + + if (!strlen(kbd->name)) + snprintf(kbd->name, sizeof(kbd->name), + "USB HIDBP Keyboard %04x:%04x", + le16_to_cpu(dev->descriptor.idVendor), + le16_to_cpu(dev->descriptor.idProduct)); + + usb_make_path(dev, kbd->phys, sizeof(kbd->phys)); + strlcpy(kbd->phys, "/input0", sizeof(kbd->phys)); - kbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP); - kbd->dev.ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL) | BIT(LED_COMPOSE) | BIT(LED_KANA); + input_dev->name = kbd->name; + input_dev->phys = kbd->phys; + usb_to_input_id(dev, &input_dev->id); + input_dev->cdev.dev = &iface->dev; + input_dev->private = kbd; + + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP); + input_dev->ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL) | BIT(LED_COMPOSE) | BIT(LED_KANA); for (i = 0; i < 255; i++) - set_bit(usb_kbd_keycode[i], kbd->dev.keybit); - clear_bit(0, kbd->dev.keybit); + set_bit(usb_kbd_keycode[i], input_dev->keybit); + clear_bit(0, input_dev->keybit); - kbd->dev.private = kbd; - kbd->dev.event = usb_kbd_event; - kbd->dev.open = usb_kbd_open; - kbd->dev.close = usb_kbd_close; + input_dev->event = usb_kbd_event; + input_dev->open = usb_kbd_open; + input_dev->close = usb_kbd_close; usb_fill_int_urb(kbd->irq, dev, pipe, kbd->new, (maxp > 8 ? 8 : maxp), @@ -284,37 +306,22 @@ static int usb_kbd_probe(struct usb_interface *iface, kbd->cr->wIndex = cpu_to_le16(interface->desc.bInterfaceNumber); kbd->cr->wLength = cpu_to_le16(1); - usb_make_path(dev, path, 64); - sprintf(kbd->phys, "%s/input0", path); - - kbd->dev.name = kbd->name; - kbd->dev.phys = kbd->phys; - usb_to_input_id(dev, &kbd->dev.id); - kbd->dev.dev = &iface->dev; - - if (dev->manufacturer) - strcat(kbd->name, dev->manufacturer); - if (dev->product) - sprintf(kbd->name, "%s %s", kbd->name, dev->product); - - if (!strlen(kbd->name)) - sprintf(kbd->name, "USB HIDBP Keyboard %04x:%04x", - kbd->dev.id.vendor, kbd->dev.id.product); - usb_fill_control_urb(kbd->led, dev, usb_sndctrlpipe(dev, 0), (void *) kbd->cr, kbd->leds, 1, usb_kbd_led, kbd); kbd->led->setup_dma = kbd->cr_dma; kbd->led->transfer_dma = kbd->leds_dma; - kbd->led->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP - | URB_NO_SETUP_DMA_MAP); + kbd->led->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP); - input_register_device(&kbd->dev); - - printk(KERN_INFO "input: %s on %s\n", kbd->name, path); + input_register_device(kbd->dev); usb_set_intfdata(iface, kbd); return 0; + +fail2: usb_kbd_free_mem(dev, kbd); +fail1: input_free_device(input_dev); + kfree(kbd); + return -ENOMEM; } static void usb_kbd_disconnect(struct usb_interface *intf) @@ -324,7 +331,7 @@ static void usb_kbd_disconnect(struct usb_interface *intf) usb_set_intfdata(intf, NULL); if (kbd) { usb_kill_urb(kbd->irq); - input_unregister_device(&kbd->dev); + input_unregister_device(kbd->dev); usb_kbd_free_mem(interface_to_usbdev(intf), kbd); kfree(kbd); } diff --git a/drivers/usb/input/usbmouse.c b/drivers/usb/input/usbmouse.c index 4104dec847fb..230f6b1b314a 100644 --- a/drivers/usb/input/usbmouse.c +++ b/drivers/usb/input/usbmouse.c @@ -50,7 +50,7 @@ struct usb_mouse { char name[128]; char phys[64]; struct usb_device *usbdev; - struct input_dev dev; + struct input_dev *dev; struct urb *irq; signed char *data; @@ -61,7 +61,7 @@ static void usb_mouse_irq(struct urb *urb, struct pt_regs *regs) { struct usb_mouse *mouse = urb->context; signed char *data = mouse->data; - struct input_dev *dev = &mouse->dev; + struct input_dev *dev = mouse->dev; int status; switch (urb->status) { @@ -115,14 +115,14 @@ static void usb_mouse_close(struct input_dev *dev) usb_kill_urb(mouse->irq); } -static int usb_mouse_probe(struct usb_interface * intf, const struct usb_device_id * id) +static int usb_mouse_probe(struct usb_interface *intf, const struct usb_device_id *id) { - struct usb_device * dev = interface_to_usbdev(intf); + struct usb_device *dev = interface_to_usbdev(intf); struct usb_host_interface *interface; struct usb_endpoint_descriptor *endpoint; struct usb_mouse *mouse; + struct input_dev *input_dev; int pipe, maxp; - char path[64]; interface = intf->cur_altsetting; @@ -130,59 +130,62 @@ static int usb_mouse_probe(struct usb_interface * intf, const struct usb_device_ return -ENODEV; endpoint = &interface->endpoint[0].desc; - if (!(endpoint->bEndpointAddress & 0x80)) + if (!(endpoint->bEndpointAddress & USB_DIR_IN)) return -ENODEV; - if ((endpoint->bmAttributes & 3) != 3) + if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT) return -ENODEV; pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); - if (!(mouse = kmalloc(sizeof(struct usb_mouse), GFP_KERNEL))) - return -ENOMEM; - memset(mouse, 0, sizeof(struct usb_mouse)); + mouse = kzalloc(sizeof(struct usb_mouse), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!mouse || !input_dev) + goto fail1; mouse->data = usb_buffer_alloc(dev, 8, SLAB_ATOMIC, &mouse->data_dma); - if (!mouse->data) { - kfree(mouse); - return -ENOMEM; - } + if (!mouse->data) + goto fail1; mouse->irq = usb_alloc_urb(0, GFP_KERNEL); - if (!mouse->irq) { - usb_buffer_free(dev, 8, mouse->data, mouse->data_dma); - kfree(mouse); - return -ENODEV; - } + if (!mouse->irq) + goto fail2; mouse->usbdev = dev; + mouse->dev = input_dev; + + if (dev->manufacturer) + strlcpy(mouse->name, dev->manufacturer, sizeof(mouse->name)); - mouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); - mouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE); - mouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y); - mouse->dev.keybit[LONG(BTN_MOUSE)] |= BIT(BTN_SIDE) | BIT(BTN_EXTRA); - mouse->dev.relbit[0] |= BIT(REL_WHEEL); + if (dev->product) { + if (dev->manufacturer) + strlcat(mouse->name, " ", sizeof(mouse->name)); + strlcat(mouse->name, dev->product, sizeof(mouse->name)); + } - mouse->dev.private = mouse; - mouse->dev.open = usb_mouse_open; - mouse->dev.close = usb_mouse_close; + if (!strlen(mouse->name)) + snprintf(mouse->name, sizeof(mouse->name), + "USB HIDBP Mouse %04x:%04x", + le16_to_cpu(dev->descriptor.idVendor), + le16_to_cpu(dev->descriptor.idProduct)); - usb_make_path(dev, path, 64); - sprintf(mouse->phys, "%s/input0", path); + usb_make_path(dev, mouse->phys, sizeof(mouse->phys)); + strlcat(mouse->phys, "/input0", sizeof(mouse->phys)); - mouse->dev.name = mouse->name; - mouse->dev.phys = mouse->phys; - usb_to_input_id(dev, &mouse->dev.id); - mouse->dev.dev = &intf->dev; + input_dev->name = mouse->name; + input_dev->phys = mouse->phys; + usb_to_input_id(dev, &input_dev->id); + input_dev->cdev.dev = &intf->dev; - if (dev->manufacturer) - strcat(mouse->name, dev->manufacturer); - if (dev->product) - sprintf(mouse->name, "%s %s", mouse->name, dev->product); + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL); + input_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE); + input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y); + input_dev->keybit[LONG(BTN_MOUSE)] |= BIT(BTN_SIDE) | BIT(BTN_EXTRA); + input_dev->relbit[0] |= BIT(REL_WHEEL); - if (!strlen(mouse->name)) - sprintf(mouse->name, "USB HIDBP Mouse %04x:%04x", - mouse->dev.id.vendor, mouse->dev.id.product); + input_dev->private = mouse; + input_dev->open = usb_mouse_open; + input_dev->close = usb_mouse_close; usb_fill_int_urb(mouse->irq, dev, pipe, mouse->data, (maxp > 8 ? 8 : maxp), @@ -190,11 +193,15 @@ static int usb_mouse_probe(struct usb_interface * intf, const struct usb_device_ mouse->irq->transfer_dma = mouse->data_dma; mouse->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - input_register_device(&mouse->dev); - printk(KERN_INFO "input: %s on %s\n", mouse->name, path); + input_register_device(mouse->dev); usb_set_intfdata(intf, mouse); return 0; + +fail2: usb_buffer_free(dev, 8, mouse->data, mouse->data_dma); +fail1: input_free_device(input_dev); + kfree(mouse); + return -ENOMEM; } static void usb_mouse_disconnect(struct usb_interface *intf) @@ -204,7 +211,7 @@ static void usb_mouse_disconnect(struct usb_interface *intf) usb_set_intfdata(intf, NULL); if (mouse) { usb_kill_urb(mouse->irq); - input_unregister_device(&mouse->dev); + input_unregister_device(mouse->dev); usb_free_urb(mouse->irq); usb_buffer_free(interface_to_usbdev(intf), 8, mouse->data, mouse->data_dma); kfree(mouse); diff --git a/drivers/usb/input/wacom.c b/drivers/usb/input/wacom.c index 3b266af3048a..ea0f75773ae1 100644 --- a/drivers/usb/input/wacom.c +++ b/drivers/usb/input/wacom.c @@ -111,7 +111,7 @@ struct wacom_features { struct wacom { signed char *data; dma_addr_t data_dma; - struct input_dev dev; + struct input_dev *dev; struct usb_device *usbdev; struct urb *irq; struct wacom_features *features; @@ -135,7 +135,7 @@ static void wacom_pl_irq(struct urb *urb, struct pt_regs *regs) { struct wacom *wacom = urb->context; unsigned char *data = wacom->data; - struct input_dev *dev = &wacom->dev; + struct input_dev *dev = wacom->dev; int prox, pressure; int retval; @@ -225,7 +225,7 @@ static void wacom_ptu_irq(struct urb *urb, struct pt_regs *regs) { struct wacom *wacom = urb->context; unsigned char *data = wacom->data; - struct input_dev *dev = &wacom->dev; + struct input_dev *dev = wacom->dev; int retval; switch (urb->status) { @@ -275,7 +275,7 @@ static void wacom_penpartner_irq(struct urb *urb, struct pt_regs *regs) { struct wacom *wacom = urb->context; unsigned char *data = wacom->data; - struct input_dev *dev = &wacom->dev; + struct input_dev *dev = wacom->dev; int retval; switch (urb->status) { @@ -318,7 +318,7 @@ static void wacom_graphire_irq(struct urb *urb, struct pt_regs *regs) { struct wacom *wacom = urb->context; unsigned char *data = wacom->data; - struct input_dev *dev = &wacom->dev; + struct input_dev *dev = wacom->dev; int x, y; int retval; @@ -397,7 +397,7 @@ static int wacom_intuos_inout(struct urb *urb) { struct wacom *wacom = urb->context; unsigned char *data = wacom->data; - struct input_dev *dev = &wacom->dev; + struct input_dev *dev = wacom->dev; int idx; /* tool number */ @@ -479,7 +479,7 @@ static void wacom_intuos_general(struct urb *urb) { struct wacom *wacom = urb->context; unsigned char *data = wacom->data; - struct input_dev *dev = &wacom->dev; + struct input_dev *dev = wacom->dev; unsigned int t; /* general pen packet */ @@ -509,7 +509,7 @@ static void wacom_intuos_irq(struct urb *urb, struct pt_regs *regs) { struct wacom *wacom = urb->context; unsigned char *data = wacom->data; - struct input_dev *dev = &wacom->dev; + struct input_dev *dev = wacom->dev; unsigned int t; int idx; int retval; @@ -738,95 +738,83 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i { struct usb_device *dev = interface_to_usbdev(intf); struct usb_endpoint_descriptor *endpoint; - char rep_data[2] = {0x02, 0x02}; struct wacom *wacom; - char path[64]; + struct input_dev *input_dev; + char rep_data[2] = {0x02, 0x02}; - if (!(wacom = kmalloc(sizeof(struct wacom), GFP_KERNEL))) - return -ENOMEM; - memset(wacom, 0, sizeof(struct wacom)); + wacom = kzalloc(sizeof(struct wacom), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!wacom || !input_dev) + goto fail1; wacom->data = usb_buffer_alloc(dev, 10, GFP_KERNEL, &wacom->data_dma); - if (!wacom->data) { - kfree(wacom); - return -ENOMEM; - } + if (!wacom->data) + goto fail1; wacom->irq = usb_alloc_urb(0, GFP_KERNEL); - if (!wacom->irq) { - usb_buffer_free(dev, 10, wacom->data, wacom->data_dma); - kfree(wacom); - return -ENOMEM; - } + if (!wacom->irq) + goto fail2; + + wacom->usbdev = dev; + wacom->dev = input_dev; + usb_make_path(dev, wacom->phys, sizeof(wacom->phys)); + strlcat(wacom->phys, "/input0", sizeof(wacom->phys)); wacom->features = wacom_features + (id - wacom_ids); + if (wacom->features->pktlen > 10) + BUG(); + + input_dev->name = wacom->features->name; + usb_to_input_id(dev, &input_dev->id); - wacom->dev.evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS); - wacom->dev.absbit[0] |= BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE); - wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_PEN) | BIT(BTN_TOUCH) | BIT(BTN_STYLUS); + input_dev->cdev.dev = &intf->dev; + input_dev->private = wacom; + input_dev->open = wacom_open; + input_dev->close = wacom_close; + + input_dev->evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS); + input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_PEN) | BIT(BTN_TOUCH) | BIT(BTN_STYLUS); + input_set_abs_params(input_dev, ABS_X, 0, wacom->features->y_max, 4, 0); + input_set_abs_params(input_dev, ABS_Y, 0, wacom->features->y_max, 4, 0); + input_set_abs_params(input_dev, ABS_PRESSURE, 0, wacom->features->pressure_max, 0, 0); switch (wacom->features->type) { case GRAPHIRE: - wacom->dev.evbit[0] |= BIT(EV_REL); - wacom->dev.relbit[0] |= BIT(REL_WHEEL); - wacom->dev.absbit[0] |= BIT(ABS_DISTANCE); - wacom->dev.keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE); - wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE) | BIT(BTN_STYLUS2); + input_dev->evbit[0] |= BIT(EV_REL); + input_dev->relbit[0] |= BIT(REL_WHEEL); + input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE); + input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE) | BIT(BTN_STYLUS2); + input_set_abs_params(input_dev, ABS_DISTANCE, 0, wacom->features->distance_max, 0, 0); break; case INTUOS3: case CINTIQ: - wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_FINGER); - wacom->dev.keybit[LONG(BTN_LEFT)] |= BIT(BTN_0) | BIT(BTN_1) | BIT(BTN_2) | BIT(BTN_3) | BIT(BTN_4) | BIT(BTN_5) | BIT(BTN_6) | BIT(BTN_7); - wacom->dev.absbit[0] |= BIT(ABS_RX) | BIT(ABS_RY); + input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_FINGER); + input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_0) | BIT(BTN_1) | BIT(BTN_2) | BIT(BTN_3) | BIT(BTN_4) | BIT(BTN_5) | BIT(BTN_6) | BIT(BTN_7); + input_set_abs_params(input_dev, ABS_RX, 0, 4097, 0, 0); + input_set_abs_params(input_dev, ABS_RY, 0, 4097, 0, 0); /* fall through */ case INTUOS: - wacom->dev.evbit[0] |= BIT(EV_MSC) | BIT(EV_REL); - wacom->dev.mscbit[0] |= BIT(MSC_SERIAL); - wacom->dev.relbit[0] |= BIT(REL_WHEEL); - wacom->dev.keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE) | BIT(BTN_SIDE) | BIT(BTN_EXTRA); - wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE) | BIT(BTN_TOOL_BRUSH) + input_dev->evbit[0] |= BIT(EV_MSC) | BIT(EV_REL); + input_dev->mscbit[0] |= BIT(MSC_SERIAL); + input_dev->relbit[0] |= BIT(REL_WHEEL); + input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE) | BIT(BTN_SIDE) | BIT(BTN_EXTRA); + input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE) | BIT(BTN_TOOL_BRUSH) | BIT(BTN_TOOL_PENCIL) | BIT(BTN_TOOL_AIRBRUSH) | BIT(BTN_TOOL_LENS) | BIT(BTN_STYLUS2); - wacom->dev.absbit[0] |= BIT(ABS_DISTANCE) | BIT(ABS_WHEEL) | BIT(ABS_TILT_X) | BIT(ABS_TILT_Y) | BIT(ABS_RZ) | BIT(ABS_THROTTLE); + input_set_abs_params(input_dev, ABS_DISTANCE, 0, wacom->features->distance_max, 0, 0); + input_set_abs_params(input_dev, ABS_WHEEL, 0, 1023, 0, 0); + input_set_abs_params(input_dev, ABS_TILT_X, 0, 127, 0, 0); + input_set_abs_params(input_dev, ABS_TILT_Y, 0, 127, 0, 0); + input_set_abs_params(input_dev, ABS_RZ, -900, 899, 0, 0); + input_set_abs_params(input_dev, ABS_THROTTLE, -1023, 1023, 0, 0); break; case PL: - wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_STYLUS2) | BIT(BTN_TOOL_RUBBER); + input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_STYLUS2) | BIT(BTN_TOOL_RUBBER); break; } - wacom->dev.absmax[ABS_X] = wacom->features->x_max; - wacom->dev.absmax[ABS_Y] = wacom->features->y_max; - wacom->dev.absmax[ABS_PRESSURE] = wacom->features->pressure_max; - wacom->dev.absmax[ABS_DISTANCE] = wacom->features->distance_max; - wacom->dev.absmax[ABS_TILT_X] = 127; - wacom->dev.absmax[ABS_TILT_Y] = 127; - wacom->dev.absmax[ABS_WHEEL] = 1023; - - wacom->dev.absmax[ABS_RX] = 4097; - wacom->dev.absmax[ABS_RY] = 4097; - wacom->dev.absmin[ABS_RZ] = -900; - wacom->dev.absmax[ABS_RZ] = 899; - wacom->dev.absmin[ABS_THROTTLE] = -1023; - wacom->dev.absmax[ABS_THROTTLE] = 1023; - - wacom->dev.absfuzz[ABS_X] = 4; - wacom->dev.absfuzz[ABS_Y] = 4; - - wacom->dev.private = wacom; - wacom->dev.open = wacom_open; - wacom->dev.close = wacom_close; - - usb_make_path(dev, path, 64); - sprintf(wacom->phys, "%s/input0", path); - - wacom->dev.name = wacom->features->name; - wacom->dev.phys = wacom->phys; - usb_to_input_id(dev, &wacom->dev.id); - wacom->dev.dev = &intf->dev; - wacom->usbdev = dev; - endpoint = &intf->cur_altsetting->endpoint[0].desc; if (wacom->features->pktlen > 10) @@ -839,18 +827,20 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i wacom->irq->transfer_dma = wacom->data_dma; wacom->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - input_register_device(&wacom->dev); + input_register_device(wacom->dev); /* ask the tablet to report tablet data */ usb_set_report(intf, 3, 2, rep_data, 2); /* repeat once (not sure why the first call often fails) */ usb_set_report(intf, 3, 2, rep_data, 2); - printk(KERN_INFO "input: %s on %s\n", wacom->features->name, path); - usb_set_intfdata(intf, wacom); - return 0; + +fail2: usb_buffer_free(dev, 10, wacom->data, wacom->data_dma); +fail1: input_free_device(input_dev); + kfree(wacom); + return -ENOMEM; } static void wacom_disconnect(struct usb_interface *intf) @@ -860,7 +850,7 @@ static void wacom_disconnect(struct usb_interface *intf) usb_set_intfdata(intf, NULL); if (wacom) { usb_kill_urb(wacom->irq); - input_unregister_device(&wacom->dev); + input_unregister_device(wacom->dev); usb_free_urb(wacom->irq); usb_buffer_free(interface_to_usbdev(intf), 10, wacom->data, wacom->data_dma); kfree(wacom); diff --git a/drivers/usb/input/xpad.c b/drivers/usb/input/xpad.c index 18125e0bffa2..43112f040b6d 100644 --- a/drivers/usb/input/xpad.c +++ b/drivers/usb/input/xpad.c @@ -103,7 +103,7 @@ static struct usb_device_id xpad_table [] = { MODULE_DEVICE_TABLE (usb, xpad_table); struct usb_xpad { - struct input_dev dev; /* input device interface */ + struct input_dev *dev; /* input device interface */ struct usb_device *udev; /* usb device */ struct urb *irq_in; /* urb for interrupt in report */ @@ -125,7 +125,7 @@ struct usb_xpad { static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data, struct pt_regs *regs) { - struct input_dev *dev = &xpad->dev; + struct input_dev *dev = xpad->dev; input_regs(dev, regs); @@ -214,9 +214,9 @@ static void xpad_close (struct input_dev *dev) static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_device *udev = interface_to_usbdev (intf); - struct usb_xpad *xpad = NULL; + struct usb_xpad *xpad; + struct input_dev *input_dev; struct usb_endpoint_descriptor *ep_irq_in; - char path[64]; int i; for (i = 0; xpad_device[i].idVendor; i++) { @@ -225,89 +225,80 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id break; } - if ((xpad = kmalloc (sizeof(struct usb_xpad), GFP_KERNEL)) == NULL) { - err("cannot allocate memory for new pad"); - return -ENOMEM; - } - memset(xpad, 0, sizeof(struct usb_xpad)); + xpad = kzalloc(sizeof(struct usb_xpad), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!xpad || !input_dev) + goto fail1; xpad->idata = usb_buffer_alloc(udev, XPAD_PKT_LEN, SLAB_ATOMIC, &xpad->idata_dma); - if (!xpad->idata) { - kfree(xpad); - return -ENOMEM; - } + if (!xpad->idata) + goto fail1; xpad->irq_in = usb_alloc_urb(0, GFP_KERNEL); - if (!xpad->irq_in) { - err("cannot allocate memory for new pad irq urb"); - usb_buffer_free(udev, XPAD_PKT_LEN, xpad->idata, xpad->idata_dma); - kfree(xpad); - return -ENOMEM; - } - - ep_irq_in = &intf->cur_altsetting->endpoint[0].desc; - - usb_fill_int_urb(xpad->irq_in, udev, - usb_rcvintpipe(udev, ep_irq_in->bEndpointAddress), - xpad->idata, XPAD_PKT_LEN, xpad_irq_in, - xpad, ep_irq_in->bInterval); - xpad->irq_in->transfer_dma = xpad->idata_dma; - xpad->irq_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + if (!xpad->irq_in) + goto fail2; xpad->udev = udev; + xpad->dev = input_dev; + usb_make_path(udev, xpad->phys, sizeof(xpad->phys)); + strlcat(xpad->phys, "/input0", sizeof(xpad->phys)); - usb_to_input_id(udev, &xpad->dev.id); - xpad->dev.dev = &intf->dev; - xpad->dev.private = xpad; - xpad->dev.name = xpad_device[i].name; - xpad->dev.phys = xpad->phys; - xpad->dev.open = xpad_open; - xpad->dev.close = xpad_close; - - usb_make_path(udev, path, 64); - snprintf(xpad->phys, 64, "%s/input0", path); + input_dev->name = xpad_device[i].name; + input_dev->phys = xpad->phys; + usb_to_input_id(udev, &input_dev->id); + input_dev->cdev.dev = &intf->dev; + input_dev->private = xpad; + input_dev->open = xpad_open; + input_dev->close = xpad_close; - xpad->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); for (i = 0; xpad_btn[i] >= 0; i++) - set_bit(xpad_btn[i], xpad->dev.keybit); + set_bit(xpad_btn[i], input_dev->keybit); for (i = 0; xpad_abs[i] >= 0; i++) { signed short t = xpad_abs[i]; - set_bit(t, xpad->dev.absbit); + set_bit(t, input_dev->absbit); switch (t) { case ABS_X: case ABS_Y: case ABS_RX: case ABS_RY: /* the two sticks */ - xpad->dev.absmax[t] = 32767; - xpad->dev.absmin[t] = -32768; - xpad->dev.absflat[t] = 128; - xpad->dev.absfuzz[t] = 16; + input_set_abs_params(input_dev, t, -32768, 32767, 16, 128); break; case ABS_Z: case ABS_RZ: /* the triggers */ - xpad->dev.absmax[t] = 255; - xpad->dev.absmin[t] = 0; + input_set_abs_params(input_dev, t, 0, 255, 0, 0); break; case ABS_HAT0X: case ABS_HAT0Y: /* the d-pad */ - xpad->dev.absmax[t] = 1; - xpad->dev.absmin[t] = -1; + input_set_abs_params(input_dev, t, -1, 1, 0, 0); break; } } - input_register_device(&xpad->dev); + ep_irq_in = &intf->cur_altsetting->endpoint[0].desc; + usb_fill_int_urb(xpad->irq_in, udev, + usb_rcvintpipe(udev, ep_irq_in->bEndpointAddress), + xpad->idata, XPAD_PKT_LEN, xpad_irq_in, + xpad, ep_irq_in->bInterval); + xpad->irq_in->transfer_dma = xpad->idata_dma; + xpad->irq_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - printk(KERN_INFO "input: %s on %s", xpad->dev.name, path); + input_register_device(xpad->dev); usb_set_intfdata(intf, xpad); return 0; + +fail2: usb_buffer_free(udev, XPAD_PKT_LEN, xpad->idata, xpad->idata_dma); +fail1: input_free_device(input_dev); + kfree(xpad); + return -ENOMEM; + } static void xpad_disconnect(struct usb_interface *intf) @@ -317,7 +308,7 @@ static void xpad_disconnect(struct usb_interface *intf) usb_set_intfdata(intf, NULL); if (xpad) { usb_kill_urb(xpad->irq_in); - input_unregister_device(&xpad->dev); + input_unregister_device(xpad->dev); usb_free_urb(xpad->irq_in); usb_buffer_free(interface_to_usbdev(intf), XPAD_PKT_LEN, xpad->idata, xpad->idata_dma); kfree(xpad); diff --git a/drivers/usb/input/yealink.c b/drivers/usb/input/yealink.c index 58a176ef96a5..f526aebea502 100644 --- a/drivers/usb/input/yealink.c +++ b/drivers/usb/input/yealink.c @@ -54,6 +54,7 @@ #include <linux/module.h> #include <linux/rwsem.h> #include <linux/usb.h> +#include <linux/usb_input.h> #include "map_to_7segment.h" #include "yealink.h" @@ -101,12 +102,12 @@ static const struct lcd_segment_map { }; struct yealink_dev { - struct input_dev idev; /* input device */ + struct input_dev *idev; /* input device */ struct usb_device *udev; /* usb device */ /* irq input channel */ struct yld_ctl_packet *irq_data; - dma_addr_t irq_dma; + dma_addr_t irq_dma; struct urb *urb_irq; /* control output channel */ @@ -237,7 +238,7 @@ static int map_p1k_to_key(int scancode) */ static void report_key(struct yealink_dev *yld, int key, struct pt_regs *regs) { - struct input_dev *idev = &yld->idev; + struct input_dev *idev = yld->idev; input_regs(idev, regs); if (yld->key_code >= 0) { @@ -809,8 +810,12 @@ static int usb_cleanup(struct yealink_dev *yld, int err) } if (yld->urb_ctl) usb_free_urb(yld->urb_ctl); - if (yld->idev.dev) - input_unregister_device(&yld->idev); + if (yld->idev) { + if (err) + input_free_device(yld->idev); + else + input_unregister_device(yld->idev); + } if (yld->ctl_req) usb_buffer_free(yld->udev, sizeof(*(yld->ctl_req)), yld->ctl_req, yld->ctl_req_dma); @@ -857,7 +862,7 @@ static int usb_probe(struct usb_interface *intf, const struct usb_device_id *id) struct usb_host_interface *interface; struct usb_endpoint_descriptor *endpoint; struct yealink_dev *yld; - char path[64]; + struct input_dev *input_dev; int ret, pipe, i; i = usb_match(udev); @@ -866,17 +871,21 @@ static int usb_probe(struct usb_interface *intf, const struct usb_device_id *id) interface = intf->cur_altsetting; endpoint = &interface->endpoint[0].desc; - if (!(endpoint->bEndpointAddress & 0x80)) + if (!(endpoint->bEndpointAddress & USB_DIR_IN)) return -EIO; - if ((endpoint->bmAttributes & 3) != 3) + if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT) return -EIO; - if ((yld = kmalloc(sizeof(struct yealink_dev), GFP_KERNEL)) == NULL) + yld = kzalloc(sizeof(struct yealink_dev), GFP_KERNEL); + if (!yld) return -ENOMEM; - memset(yld, 0, sizeof(*yld)); yld->udev = udev; + yld->idev = input_dev = input_allocate_device(); + if (!input_dev) + return usb_cleanup(yld, -ENOMEM); + /* allocate usb buffers */ yld->irq_data = usb_buffer_alloc(udev, USB_PKT_LEN, SLAB_ATOMIC, &yld->irq_dma); @@ -935,42 +944,37 @@ static int usb_probe(struct usb_interface *intf, const struct usb_device_id *id) yld->urb_ctl->dev = udev; /* find out the physical bus location */ - if (usb_make_path(udev, path, sizeof(path)) > 0) - snprintf(yld->phys, sizeof(yld->phys)-1, "%s/input0", path); + usb_make_path(udev, yld->phys, sizeof(yld->phys)); + strlcat(yld->phys, "/input0", sizeof(yld->phys)); /* register settings for the input device */ - init_input_dev(&yld->idev); - yld->idev.private = yld; - yld->idev.id.bustype = BUS_USB; - yld->idev.id.vendor = le16_to_cpu(udev->descriptor.idVendor); - yld->idev.id.product = le16_to_cpu(udev->descriptor.idProduct); - yld->idev.id.version = le16_to_cpu(udev->descriptor.bcdDevice); - yld->idev.dev = &intf->dev; - yld->idev.name = yld_device[i].name; - yld->idev.phys = yld->phys; - /* yld->idev.event = input_ev; TODO */ - yld->idev.open = input_open; - yld->idev.close = input_close; + input_dev->name = yld_device[i].name; + input_dev->phys = yld->phys; + usb_to_input_id(udev, &input_dev->id); + input_dev->cdev.dev = &intf->dev; + + input_dev->private = yld; + input_dev->open = input_open; + input_dev->close = input_close; + /* input_dev->event = input_ev; TODO */ /* register available key events */ - yld->idev.evbit[0] = BIT(EV_KEY); + input_dev->evbit[0] = BIT(EV_KEY); for (i = 0; i < 256; i++) { int k = map_p1k_to_key(i); if (k >= 0) { - set_bit(k & 0xff, yld->idev.keybit); + set_bit(k & 0xff, input_dev->keybit); if (k >> 8) - set_bit(k >> 8, yld->idev.keybit); + set_bit(k >> 8, input_dev->keybit); } } - printk(KERN_INFO "input: %s on %s\n", yld->idev.name, path); - - input_register_device(&yld->idev); + input_register_device(yld->idev); usb_set_intfdata(intf, yld); /* clear visible elements */ - for (i=0; i<ARRAY_SIZE(lcdMap); i++) + for (i = 0; i < ARRAY_SIZE(lcdMap); i++) setChar(yld, i, ' '); /* display driver version on LCD line 3 */ diff --git a/drivers/usb/media/dabusb.c b/drivers/usb/media/dabusb.c index 6ca2fae99d2d..27b23c55bbc7 100644 --- a/drivers/usb/media/dabusb.c +++ b/drivers/usb/media/dabusb.c @@ -707,9 +707,8 @@ static struct file_operations dabusb_fops = }; static struct usb_class_driver dabusb_class = { - .name = "usb/dabusb%d", + .name = "dabusb%d", .fops = &dabusb_fops, - .mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, .minor_base = DABUSB_MINOR, }; diff --git a/drivers/usb/media/konicawc.c b/drivers/usb/media/konicawc.c index 20ac9e1069d4..9fe2c2710d13 100644 --- a/drivers/usb/media/konicawc.c +++ b/drivers/usb/media/konicawc.c @@ -119,7 +119,7 @@ struct konicawc { int yplanesz; /* Number of bytes in the Y plane */ unsigned int buttonsts:1; #ifdef CONFIG_INPUT - struct input_dev input; + struct input_dev *input; char input_physname[64]; #endif }; @@ -218,6 +218,57 @@ static void konicawc_adjust_picture(struct uvd *uvd) konicawc_camera_on(uvd); } +#ifdef CONFIG_INPUT + +static void konicawc_register_input(struct konicawc *cam, struct usb_device *dev) +{ + struct input_dev *input_dev; + + usb_make_path(dev, cam->input_physname, sizeof(cam->input_physname)); + strncat(cam->input_physname, "/input0", sizeof(cam->input_physname)); + + cam->input = input_dev = input_allocate_device(); + if (!input_dev) { + warn("Not enough memory for camera's input device\n"); + return; + } + + input_dev->name = "Konicawc snapshot button"; + input_dev->phys = cam->input_physname; + usb_to_input_id(dev, &input_dev->id); + input_dev->cdev.dev = &dev->dev; + + input_dev->evbit[0] = BIT(EV_KEY); + input_dev->keybit[LONG(BTN_0)] = BIT(BTN_0); + + input_dev->private = cam; + + input_register_device(cam->input); +} + +static void konicawc_unregister_input(struct konicawc *cam) +{ + if (cam->input) { + input_unregister_device(cam->input); + cam->input = NULL; + } +} + +static void konicawc_report_buttonstat(struct konicawc *cam) +{ + if (cam->input) { + input_report_key(cam->input, BTN_0, cam->buttonsts); + input_sync(cam->input); + } +} + +#else + +static inline void konicawc_register_input(struct konicawc *cam, struct usb_device *dev) { } +static inline void konicawc_unregister_input(struct konicawc *cam) { } +static inline void konicawc_report_buttonstat(struct konicawc *cam) { } + +#endif /* CONFIG_INPUT */ static int konicawc_compress_iso(struct uvd *uvd, struct urb *dataurb, struct urb *stsurb) { @@ -273,10 +324,7 @@ static int konicawc_compress_iso(struct uvd *uvd, struct urb *dataurb, struct ur if(button != cam->buttonsts) { DEBUG(2, "button: %sclicked", button ? "" : "un"); cam->buttonsts = button; -#ifdef CONFIG_INPUT - input_report_key(&cam->input, BTN_0, cam->buttonsts); - input_sync(&cam->input); -#endif + konicawc_report_buttonstat(cam); } if(sts == 0x01) { /* drop frame */ @@ -645,9 +693,9 @@ static int konicawc_set_video_mode(struct uvd *uvd, struct video_window *vw) RingQueue_Flush(&uvd->dp); cam->lastframe = -2; if(uvd->curframe != -1) { - uvd->frame[uvd->curframe].curline = 0; - uvd->frame[uvd->curframe].seqRead_Length = 0; - uvd->frame[uvd->curframe].seqRead_Index = 0; + uvd->frame[uvd->curframe].curline = 0; + uvd->frame[uvd->curframe].seqRead_Length = 0; + uvd->frame[uvd->curframe].seqRead_Index = 0; } konicawc_start_data(uvd); @@ -718,7 +766,6 @@ static void konicawc_configure_video(struct uvd *uvd) DEBUG(1, "setting initial values"); } - static int konicawc_probe(struct usb_interface *intf, const struct usb_device_id *devid) { struct usb_device *dev = interface_to_usbdev(intf); @@ -839,21 +886,8 @@ static int konicawc_probe(struct usb_interface *intf, const struct usb_device_id err("usbvideo_RegisterVideoDevice() failed."); uvd = NULL; } -#ifdef CONFIG_INPUT - /* Register input device for button */ - memset(&cam->input, 0, sizeof(struct input_dev)); - cam->input.name = "Konicawc snapshot button"; - cam->input.private = cam; - cam->input.evbit[0] = BIT(EV_KEY); - cam->input.keybit[LONG(BTN_0)] = BIT(BTN_0); - usb_to_input_id(dev, &cam->input.id); - input_register_device(&cam->input); - - usb_make_path(dev, cam->input_physname, 56); - strcat(cam->input_physname, "/input0"); - cam->input.phys = cam->input_physname; - info("konicawc: %s on %s\n", cam->input.name, cam->input.phys); -#endif + + konicawc_register_input(cam, dev); } if (uvd) { @@ -869,10 +903,9 @@ static void konicawc_free_uvd(struct uvd *uvd) int i; struct konicawc *cam = (struct konicawc *)uvd->user_data; -#ifdef CONFIG_INPUT - input_unregister_device(&cam->input); -#endif - for (i=0; i < USBVIDEO_NUMSBUF; i++) { + konicawc_unregister_input(cam); + + for (i = 0; i < USBVIDEO_NUMSBUF; i++) { usb_free_urb(cam->sts_urb[i]); cam->sts_urb[i] = NULL; } diff --git a/drivers/usb/misc/auerswald.c b/drivers/usb/misc/auerswald.c index ae4681f9f0ea..5f33f7c64885 100644 --- a/drivers/usb/misc/auerswald.c +++ b/drivers/usb/misc/auerswald.c @@ -1873,9 +1873,8 @@ static struct file_operations auerswald_fops = }; static struct usb_class_driver auerswald_class = { - .name = "usb/auer%d", + .name = "auer%d", .fops = &auerswald_fops, - .mode = S_IFCHR | S_IRUGO | S_IWUGO, .minor_base = AUER_MINOR_BASE, }; diff --git a/drivers/usb/misc/idmouse.c b/drivers/usb/misc/idmouse.c index 733acc213726..1dc3e0f73014 100644 --- a/drivers/usb/misc/idmouse.c +++ b/drivers/usb/misc/idmouse.c @@ -105,11 +105,10 @@ static struct file_operations idmouse_fops = { .release = idmouse_release, }; -/* class driver information for devfs */ +/* class driver information */ static struct usb_class_driver idmouse_class = { - .name = "usb/idmouse%d", + .name = "idmouse%d", .fops = &idmouse_fops, - .mode = S_IFCHR | S_IRUSR | S_IRGRP | S_IROTH, /* filemode (char, 444) */ .minor_base = USB_IDMOUSE_MINOR_BASE, }; @@ -320,20 +319,8 @@ static ssize_t idmouse_read(struct file *file, char __user *buffer, size_t count return -ENODEV; } - if (*ppos >= IMGSIZE) { - up (&dev->sem); - return 0; - } - - count = min ((loff_t)count, IMGSIZE - (*ppos)); - - if (copy_to_user (buffer, dev->bulk_in_buffer + *ppos, count)) { - result = -EFAULT; - } else { - result = count; - *ppos += count; - } - + result = simple_read_from_buffer(buffer, count, ppos, + dev->bulk_in_buffer, IMGSIZE); /* unlock the device */ up(&dev->sem); return result; diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c index 7d06105763d4..2703e205bc8f 100644 --- a/drivers/usb/misc/legousbtower.c +++ b/drivers/usb/misc/legousbtower.c @@ -271,12 +271,11 @@ static struct file_operations tower_fops = { /* * usb class driver info in order to get a minor number from the usb core, - * and to have the device registered with devfs and the driver core + * and to have the device registered with the driver core */ static struct usb_class_driver tower_class = { - .name = "usb/legousbtower%d", + .name = "legousbtower%d", .fops = &tower_fops, - .mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH, .minor_base = LEGO_USB_TOWER_MINOR_BASE, }; diff --git a/drivers/usb/misc/rio500.c b/drivers/usb/misc/rio500.c index 26f77e29c7a6..7d02d8ec6b1a 100644 --- a/drivers/usb/misc/rio500.c +++ b/drivers/usb/misc/rio500.c @@ -443,9 +443,8 @@ file_operations usb_rio_fops = { }; static struct usb_class_driver usb_rio_class = { - .name = "usb/rio500%d", + .name = "rio500%d", .fops = &usb_rio_fops, - .mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, .minor_base = RIO_MINOR, }; diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c index 39db3155723a..c946c9a538a0 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.c +++ b/drivers/usb/misc/sisusbvga/sisusb.c @@ -2440,7 +2440,7 @@ int sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init) { int ret = 0, slot = sisusb->font_slot, i; - struct font_desc *myfont; + const struct font_desc *myfont; u8 *tempbuf; u16 *tempbufb; size_t written; @@ -3239,12 +3239,7 @@ static struct file_operations usb_sisusb_fops = { }; static struct usb_class_driver usb_sisusb_class = { -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,13) - .name = "usb/sisusbvga%d", - .mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, -#else .name = "sisusbvga%d", -#endif .fops = &usb_sisusb_fops, .minor_base = SISUSB_MINOR }; diff --git a/drivers/usb/misc/usblcd.c b/drivers/usb/misc/usblcd.c index 096ab3029676..85f3725334b0 100644 --- a/drivers/usb/misc/usblcd.c +++ b/drivers/usb/misc/usblcd.c @@ -251,13 +251,12 @@ static struct file_operations lcd_fops = { }; /* - * * usb class driver info in order to get a minor number from the usb core, - * * and to have the device registered with devfs and the driver core - * */ + * usb class driver info in order to get a minor number from the usb core, + * and to have the device registered with the driver core + */ static struct usb_class_driver lcd_class = { - .name = "usb/lcd%d", + .name = "lcd%d", .fops = &lcd_fops, - .mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH, .minor_base = USBLCD_MINOR, }; diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c index 54799eb0bc60..2997f558159b 100644 --- a/drivers/usb/misc/usbtest.c +++ b/drivers/usb/misc/usbtest.c @@ -9,7 +9,7 @@ #include <linux/mm.h> #include <linux/module.h> #include <linux/moduleparam.h> -#include <asm/scatterlist.h> +#include <linux/scatterlist.h> #include <linux/usb.h> @@ -381,7 +381,6 @@ alloc_sglist (int nents, int max, int vary) sg = kmalloc (nents * sizeof *sg, SLAB_KERNEL); if (!sg) return NULL; - memset (sg, 0, nents * sizeof *sg); for (i = 0; i < nents; i++) { char *buf; @@ -394,9 +393,7 @@ alloc_sglist (int nents, int max, int vary) memset (buf, 0, size); /* kmalloc pages are always physically contiguous! */ - sg [i].page = virt_to_page (buf); - sg [i].offset = offset_in_page (buf); - sg [i].length = size; + sg_init_one(&sg[i], buf, size); if (vary) { size += vary; @@ -983,6 +980,7 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param) reqp->number = i % NUM_SUBCASES; reqp->expected = expected; u->setup_packet = (char *) &reqp->setup; + u->transfer_flags |= URB_NO_SETUP_DMA_MAP; u->context = &context; u->complete = ctrl_complete; @@ -1948,21 +1946,11 @@ usbtest_probe (struct usb_interface *intf, const struct usb_device_id *id) static int usbtest_suspend (struct usb_interface *intf, pm_message_t message) { - struct usbtest_dev *dev = usb_get_intfdata (intf); - - down (&dev->sem); - intf->dev.power.power_state = PMSG_SUSPEND; - up (&dev->sem); return 0; } static int usbtest_resume (struct usb_interface *intf) { - struct usbtest_dev *dev = usb_get_intfdata (intf); - - down (&dev->sem); - intf->dev.power.power_state = PMSG_ON; - up (&dev->sem); return 0; } diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c index 03fb70ef2eb3..0592cb5e6c4d 100644 --- a/drivers/usb/misc/uss720.c +++ b/drivers/usb/misc/uss720.c @@ -137,7 +137,7 @@ static void async_complete(struct urb *urb, struct pt_regs *ptregs) static struct uss720_async_request *submit_async_request(struct parport_uss720_private *priv, __u8 request, __u8 requesttype, __u16 value, __u16 index, - unsigned int mem_flags) + gfp_t mem_flags) { struct usb_device *usbdev; struct uss720_async_request *rq; @@ -204,7 +204,7 @@ static unsigned int kill_all_async_requests_priv(struct parport_uss720_private * /* --------------------------------------------------------------------- */ -static int get_1284_register(struct parport *pp, unsigned char reg, unsigned char *val, unsigned int mem_flags) +static int get_1284_register(struct parport *pp, unsigned char reg, unsigned char *val, gfp_t mem_flags) { struct parport_uss720_private *priv; struct uss720_async_request *rq; @@ -238,7 +238,7 @@ static int get_1284_register(struct parport *pp, unsigned char reg, unsigned cha return -EIO; } -static int set_1284_register(struct parport *pp, unsigned char reg, unsigned char val, unsigned int mem_flags) +static int set_1284_register(struct parport *pp, unsigned char reg, unsigned char val, gfp_t mem_flags) { struct parport_uss720_private *priv; struct uss720_async_request *rq; diff --git a/drivers/usb/mon/mon_main.c b/drivers/usb/mon/mon_main.c index 508a21028db4..c34944c75047 100644 --- a/drivers/usb/mon/mon_main.c +++ b/drivers/usb/mon/mon_main.c @@ -11,6 +11,7 @@ #include <linux/usb.h> #include <linux/debugfs.h> #include <linux/smp_lock.h> +#include <linux/notifier.h> #include "usb_mon.h" #include "../core/hcd.h" @@ -205,6 +206,23 @@ static void mon_bus_remove(struct usb_bus *ubus) up(&mon_lock); } +static int mon_notify(struct notifier_block *self, unsigned long action, + void *dev) +{ + switch (action) { + case USB_BUS_ADD: + mon_bus_add(dev); + break; + case USB_BUS_REMOVE: + mon_bus_remove(dev); + } + return NOTIFY_OK; +} + +static struct notifier_block mon_nb = { + .notifier_call = mon_notify, +}; + /* * Ops */ @@ -212,8 +230,6 @@ static struct usb_mon_operations mon_ops_0 = { .urb_submit = mon_submit, .urb_submit_error = mon_submit_error, .urb_complete = mon_complete, - .bus_add = mon_bus_add, - .bus_remove = mon_bus_remove, }; /* @@ -329,6 +345,8 @@ static int __init mon_init(void) } // MOD_INC_USE_COUNT(which_module?); + usb_register_notify(&mon_nb); + down(&usb_bus_list_lock); list_for_each_entry (ubus, &usb_bus_list, bus_list) { mon_bus_init(mondir, ubus); @@ -342,6 +360,7 @@ static void __exit mon_exit(void) struct mon_bus *mbus; struct list_head *p; + usb_unregister_notify(&mon_nb); usb_mon_deregister(); down(&mon_lock); diff --git a/drivers/usb/net/Kconfig b/drivers/usb/net/Kconfig index 8c010bb44eb8..efd6ca7e4ac5 100644 --- a/drivers/usb/net/Kconfig +++ b/drivers/usb/net/Kconfig @@ -294,7 +294,7 @@ config USB_NET_ZAURUS This also supports some related device firmware, as used in some PDAs from Olympus and some cell phones from Motorola. - If you install an alternate ROM image, such as the Linux 2.6 based + If you install an alternate image, such as the Linux 2.6 based versions of OpenZaurus, you should no longer need to support this protocol. Only the "eth-fd" or "net_fd" drivers in these devices really need this non-conformant variant of CDC Ethernet (or in diff --git a/drivers/usb/net/asix.c b/drivers/usb/net/asix.c index 861f00a43750..252a34fbb42c 100644 --- a/drivers/usb/net/asix.c +++ b/drivers/usb/net/asix.c @@ -753,7 +753,7 @@ static int ax88772_rx_fixup(struct usbnet *dev, struct sk_buff *skb) } static struct sk_buff *ax88772_tx_fixup(struct usbnet *dev, struct sk_buff *skb, - unsigned flags) + gfp_t flags) { int padlen; int headroom = skb_headroom(skb); diff --git a/drivers/usb/net/gl620a.c b/drivers/usb/net/gl620a.c index c8763ae33c73..c0f263b202a6 100644 --- a/drivers/usb/net/gl620a.c +++ b/drivers/usb/net/gl620a.c @@ -301,7 +301,7 @@ static int genelink_rx_fixup(struct usbnet *dev, struct sk_buff *skb) } static struct sk_buff * -genelink_tx_fixup(struct usbnet *dev, struct sk_buff *skb, unsigned flags) +genelink_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) { int padlen; int length = skb->len; diff --git a/drivers/usb/net/kaweth.c b/drivers/usb/net/kaweth.c index e04b0ce3611a..6bef1be6b36c 100644 --- a/drivers/usb/net/kaweth.c +++ b/drivers/usb/net/kaweth.c @@ -469,7 +469,7 @@ static int kaweth_reset(struct kaweth_device *kaweth) 0, KAWETH_CONTROL_TIMEOUT); - udelay(10000); + mdelay(10); kaweth_dbg("kaweth_reset() returns %d.",result); @@ -477,13 +477,13 @@ static int kaweth_reset(struct kaweth_device *kaweth) } static void kaweth_usb_receive(struct urb *, struct pt_regs *regs); -static int kaweth_resubmit_rx_urb(struct kaweth_device *, unsigned); +static int kaweth_resubmit_rx_urb(struct kaweth_device *, gfp_t); /**************************************************************** int_callback *****************************************************************/ -static void kaweth_resubmit_int_urb(struct kaweth_device *kaweth, int mf) +static void kaweth_resubmit_int_urb(struct kaweth_device *kaweth, gfp_t mf) { int status; @@ -550,7 +550,7 @@ static void kaweth_resubmit_tl(void *d) * kaweth_resubmit_rx_urb ****************************************************************/ static int kaweth_resubmit_rx_urb(struct kaweth_device *kaweth, - unsigned mem_flags) + gfp_t mem_flags) { int result; diff --git a/drivers/usb/net/net1080.c b/drivers/usb/net/net1080.c index a4309c4a491b..cee55f8cf64f 100644 --- a/drivers/usb/net/net1080.c +++ b/drivers/usb/net/net1080.c @@ -500,7 +500,7 @@ static int net1080_rx_fixup(struct usbnet *dev, struct sk_buff *skb) } static struct sk_buff * -net1080_tx_fixup(struct usbnet *dev, struct sk_buff *skb, unsigned flags) +net1080_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) { int padlen; struct sk_buff *skb2; diff --git a/drivers/usb/net/pegasus.c b/drivers/usb/net/pegasus.c index 6a4ffe6c3977..537eb181d985 100644 --- a/drivers/usb/net/pegasus.c +++ b/drivers/usb/net/pegasus.c @@ -1384,7 +1384,6 @@ static int pegasus_suspend (struct usb_interface *intf, pm_message_t message) usb_kill_urb(pegasus->rx_urb); usb_kill_urb(pegasus->intr_urb); } - intf->dev.power.power_state = PMSG_SUSPEND; return 0; } @@ -1392,7 +1391,6 @@ static int pegasus_resume (struct usb_interface *intf) { struct pegasus *pegasus = usb_get_intfdata(intf); - intf->dev.power.power_state = PMSG_ON; netif_device_attach (pegasus->net); if (netif_running(pegasus->net)) { pegasus->rx_urb->status = 0; diff --git a/drivers/usb/net/pegasus.h b/drivers/usb/net/pegasus.h index b98f2a833442..9fbd59b55cb6 100644 --- a/drivers/usb/net/pegasus.h +++ b/drivers/usb/net/pegasus.h @@ -181,6 +181,8 @@ PEGASUS_DEV( "Accton USB 10/100 Ethernet Adapter", VENDOR_ACCTON, 0x1046, DEFAULT_GPIO_RESET ) PEGASUS_DEV( "SpeedStream USB 10/100 Ethernet", VENDOR_ACCTON, 0x5046, DEFAULT_GPIO_RESET | PEGASUS_II ) +PEGASUS_DEV( "Philips USB 10/100 Ethernet", VENDOR_ACCTON, 0xb004, + DEFAULT_GPIO_RESET | PEGASUS_II ) PEGASUS_DEV( "ADMtek ADM8511 \"Pegasus II\" USB Ethernet", VENDOR_ADMTEK, 0x8511, DEFAULT_GPIO_RESET | PEGASUS_II | HAS_HOME_PNA ) diff --git a/drivers/usb/net/rndis_host.c b/drivers/usb/net/rndis_host.c index 2ed2e5fb7778..b5a925dc1beb 100644 --- a/drivers/usb/net/rndis_host.c +++ b/drivers/usb/net/rndis_host.c @@ -517,7 +517,7 @@ static int rndis_rx_fixup(struct usbnet *dev, struct sk_buff *skb) } static struct sk_buff * -rndis_tx_fixup(struct usbnet *dev, struct sk_buff *skb, unsigned flags) +rndis_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) { struct rndis_data_hdr *hdr; struct sk_buff *skb2; diff --git a/drivers/usb/net/rtl8150.c b/drivers/usb/net/rtl8150.c index c3d4e3589e30..787dd3591d6a 100644 --- a/drivers/usb/net/rtl8150.c +++ b/drivers/usb/net/rtl8150.c @@ -909,6 +909,7 @@ static void rtl8150_disconnect(struct usb_interface *intf) usb_set_intfdata(intf, NULL); if (dev) { set_bit(RTL8150_UNPLUG, &dev->flags); + tasklet_disable(&dev->tl); unregister_netdev(dev->netdev); unlink_all_urbs(dev); free_all_urbs(dev); diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c index 6c460918d54f..74f05c9c84d5 100644 --- a/drivers/usb/net/usbnet.c +++ b/drivers/usb/net/usbnet.c @@ -288,7 +288,7 @@ EXPORT_SYMBOL_GPL(usbnet_defer_kevent); static void rx_complete (struct urb *urb, struct pt_regs *regs); -static void rx_submit (struct usbnet *dev, struct urb *urb, unsigned flags) +static void rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags) { struct sk_buff *skb; struct skb_data *entry; @@ -1185,7 +1185,6 @@ int usbnet_suspend (struct usb_interface *intf, pm_message_t message) netif_device_detach (dev->net); (void) unlink_urbs (dev, &dev->rxq); (void) unlink_urbs (dev, &dev->txq); - intf->dev.power.power_state = PMSG_SUSPEND; return 0; } EXPORT_SYMBOL_GPL(usbnet_suspend); @@ -1194,7 +1193,6 @@ int usbnet_resume (struct usb_interface *intf) { struct usbnet *dev = usb_get_intfdata(intf); - intf->dev.power.power_state = PMSG_ON; netif_device_attach (dev->net); tasklet_schedule (&dev->bh); return 0; diff --git a/drivers/usb/net/usbnet.h b/drivers/usb/net/usbnet.h index 7aa0abd1a9bd..89fc4958eecf 100644 --- a/drivers/usb/net/usbnet.h +++ b/drivers/usb/net/usbnet.h @@ -107,7 +107,7 @@ struct driver_info { /* fixup tx packet (add framing) */ struct sk_buff *(*tx_fixup)(struct usbnet *dev, - struct sk_buff *skb, unsigned flags); + struct sk_buff *skb, gfp_t flags); /* for new devices, use the descriptor-reading code instead */ int in; /* rx endpoint */ diff --git a/drivers/usb/net/zaurus.c b/drivers/usb/net/zaurus.c index ee3b892aeabc..5d4b7d55b097 100644 --- a/drivers/usb/net/zaurus.c +++ b/drivers/usb/net/zaurus.c @@ -62,7 +62,7 @@ */ static struct sk_buff * -zaurus_tx_fixup(struct usbnet *dev, struct sk_buff *skb, unsigned flags) +zaurus_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) { int padlen; struct sk_buff *skb2; diff --git a/drivers/usb/net/zd1201.c b/drivers/usb/net/zd1201.c index c4e479ee926a..2f52261c7cc1 100644 --- a/drivers/usb/net/zd1201.c +++ b/drivers/usb/net/zd1201.c @@ -521,7 +521,7 @@ static int zd1201_setconfig(struct zd1201 *zd, int rid, void *buf, int len, int int reqlen; char seq=0; struct urb *urb; - unsigned int gfp_mask = wait ? GFP_NOIO : GFP_ATOMIC; + gfp_t gfp_mask = wait ? GFP_NOIO : GFP_ATOMIC; len += 4; /* first 4 are for header */ diff --git a/drivers/usb/serial/ChangeLog.old b/drivers/usb/serial/ChangeLog.old new file mode 100644 index 000000000000..c1b279939bbf --- /dev/null +++ b/drivers/usb/serial/ChangeLog.old @@ -0,0 +1,730 @@ +This is the contents of some of the drivers/usb/serial/ files that had old +changelog comments. They were quite old, and out of date, and we don't keep +them anymore, so I've put them here, away from the source files, in case +people still care to see them. + +- Greg Kroah-Hartman <greg@kroah.com> October 20, 2005 + +----------------------------------------------------------------------- +usb-serial.h Change Log comments: + + (03/26/2002) gkh + removed the port->tty check from port_paranoia_check() due to serial + consoles not having a tty device assigned to them. + + (12/03/2001) gkh + removed active from the port structure. + added documentation to the usb_serial_device_type structure + + (10/10/2001) gkh + added vendor and product to serial structure. Needed to determine device + owner when the device is disconnected. + + (05/30/2001) gkh + added sem to port structure and removed port_lock + + (10/05/2000) gkh + Added interrupt_in_endpointAddress and bulk_in_endpointAddress to help + fix bug with urb->dev not being set properly, now that the usb core + needs it. + + (09/11/2000) gkh + Added usb_serial_debug_data function to help get rid of #DEBUG in the + drivers. + + (08/28/2000) gkh + Added port_lock to port structure. + + (08/08/2000) gkh + Added open_count to port structure. + + (07/23/2000) gkh + Added bulk_out_endpointAddress to port structure. + + (07/19/2000) gkh, pberger, and borchers + Modifications to allow usb-serial drivers to be modules. + +----------------------------------------------------------------------- +usb-serial.c Change Log comments: + + (12/10/2002) gkh + Split the ports off into their own struct device, and added a + usb-serial bus driver. + + (11/19/2002) gkh + removed a few #ifdefs for the generic code and cleaned up the failure + logic in initialization. + + (10/02/2002) gkh + moved the console code to console.c and out of this file. + + (06/05/2002) gkh + moved location of startup() call in serial_probe() until after all + of the port information and endpoints are initialized. This makes + things easier for some drivers. + + (04/10/2002) gkh + added serial_read_proc function which creates a + /proc/tty/driver/usb-serial file. + + (03/27/2002) gkh + Got USB serial console code working properly and merged into the main + version of the tree. Thanks to Randy Dunlap for the initial version + of this code, and for pushing me to finish it up. + The USB serial console works with any usb serial driver device. + + (03/21/2002) gkh + Moved all manipulation of port->open_count into the core. Now the + individual driver's open and close functions are called only when the + first open() and last close() is called. Making the drivers a bit + smaller and simpler. + Fixed a bug if a driver didn't have the owner field set. + + (02/26/2002) gkh + Moved all locking into the main serial_* functions, instead of having + the individual drivers have to grab the port semaphore. This should + reduce races. + Reworked the MOD_INC logic a bit to always increment and decrement, even + if the generic driver is being used. + + (10/10/2001) gkh + usb_serial_disconnect() now sets the serial->dev pointer is to NULL to + help prevent child drivers from accessing the device since it is now + gone. + + (09/13/2001) gkh + Moved generic driver initialize after we have registered with the USB + core. Thanks to Randy Dunlap for pointing this problem out. + + (07/03/2001) gkh + Fixed module paramater size. Thanks to John Brockmeyer for the pointer. + Fixed vendor and product getting defined through the MODULE_PARM macro + if the Generic driver wasn't compiled in. + Fixed problem with generic_shutdown() not being called for drivers that + don't have a shutdown() function. + + (06/06/2001) gkh + added evil hack that is needed for the prolific pl2303 device due to the + crazy way its endpoints are set up. + + (05/30/2001) gkh + switched from using spinlock to a semaphore, which fixes lots of problems. + + (04/08/2001) gb + Identify version on module load. + + 2001_02_05 gkh + Fixed buffer overflows bug with the generic serial driver. Thanks to + Todd Squires <squirest@ct0.com> for fixing this. + + (01/10/2001) gkh + Fixed bug where the generic serial adaptor grabbed _any_ device that was + offered to it. + + (12/12/2000) gkh + Removed MOD_INC and MOD_DEC from poll and disconnect functions, and + moved them to the serial_open and serial_close functions. + Also fixed bug with there not being a MOD_DEC for the generic driver + (thanks to Gary Brubaker for finding this.) + + (11/29/2000) gkh + Small NULL pointer initialization cleanup which saves a bit of disk image + + (11/01/2000) Adam J. Richter + instead of using idVendor/idProduct pairs, usb serial drivers + now identify their hardware interest with usb_device_id tables, + which they usually have anyhow for use with MODULE_DEVICE_TABLE. + + (10/05/2000) gkh + Fixed bug with urb->dev not being set properly, now that the usb + core needs it. + + (09/11/2000) gkh + Removed DEBUG #ifdefs with call to usb_serial_debug_data + + (08/28/2000) gkh + Added port_lock to port structure. + Added locks for SMP safeness to generic driver + Fixed the ability to open a generic device's port more than once. + + (07/23/2000) gkh + Added bulk_out_endpointAddress to port structure. + + (07/19/2000) gkh, pberger, and borchers + Modifications to allow usb-serial drivers to be modules. + + (07/03/2000) gkh + Added more debugging to serial_ioctl call + + (06/25/2000) gkh + Changed generic_write_bulk_callback to not call wake_up_interruptible + directly, but to have port_softint do it at a safer time. + + (06/23/2000) gkh + Cleaned up debugging statements in a quest to find UHCI timeout bug. + + (05/22/2000) gkh + Changed the makefile, enabling the big CONFIG_USB_SERIAL_SOMTHING to be + removed from the individual device source files. + + (05/03/2000) gkh + Added the Digi Acceleport driver from Al Borchers and Peter Berger. + + (05/02/2000) gkh + Changed devfs and tty register code to work properly now. This was based on + the ACM driver changes by Vojtech Pavlik. + + (04/27/2000) Ryan VanderBijl + Put calls to *_paranoia_checks into one function. + + (04/23/2000) gkh + Fixed bug that Randy Dunlap found for Generic devices with no bulk out ports. + Moved when the startup code printed out the devices that are supported. + + (04/19/2000) gkh + Added driver for ZyXEL omni.net lcd plus ISDN TA + Made startup info message specify which drivers were compiled in. + + (04/03/2000) gkh + Changed the probe process to remove the module unload races. + Changed where the tty layer gets initialized to have devfs work nicer. + Added initial devfs support. + + (03/26/2000) gkh + Split driver up into device specific pieces. + + (03/19/2000) gkh + Fixed oops that could happen when device was removed while a program + was talking to the device. + Removed the static urbs and now all urbs are created and destroyed + dynamically. + Reworked the internal interface. Now everything is based on the + usb_serial_port structure instead of the larger usb_serial structure. + This fixes the bug that a multiport device could not have more than + one port open at one time. + + (03/17/2000) gkh + Added config option for debugging messages. + Added patch for keyspan pda from Brian Warner. + + (03/06/2000) gkh + Added the keyspan pda code from Brian Warner <warner@lothar.com> + Moved a bunch of the port specific stuff into its own structure. This + is in anticipation of the true multiport devices (there's a bug if you + try to access more than one port of any multiport device right now) + + (02/21/2000) gkh + Made it so that any serial devices only have to specify which functions + they want to overload from the generic function calls (great, + inheritance in C, in a driver, just what I wanted...) + Added support for set_termios and ioctl function calls. No drivers take + advantage of this yet. + Removed the #ifdef MODULE, now there is no module specific code. + Cleaned up a few comments in usb-serial.h that were wrong (thanks again + to Miles Lott). + Small fix to get_free_serial. + + (02/14/2000) gkh + Removed the Belkin and Peracom functionality from the driver due to + the lack of support from the vendor, and me not wanting people to + accidenatly buy the device, expecting it to work with Linux. + Added read_bulk_callback and write_bulk_callback to the type structure + for the needs of the FTDI and WhiteHEAT driver. + Changed all reverences to FTDI to FTDI_SIO at the request of Bill + Ryder. + Changed the output urb size back to the max endpoint size to make + the ftdi_sio driver have it easier, and due to the fact that it didn't + really increase the speed any. + + (02/11/2000) gkh + Added VISOR_FUNCTION_CONSOLE to the visor startup function. This was a + patch from Miles Lott (milos@insync.net). + Fixed bug with not restoring the minor range that a device grabs, if + the startup function fails (thanks Miles for finding this). + + (02/05/2000) gkh + Added initial framework for the Keyspan PDA serial converter so that + Brian Warner has a place to put his code. + Made the ezusb specific functions generic enough that different + devices can use them (whiteheat and keyspan_pda both need them). + Split out a whole bunch of structure and other stuff to a separate + usb-serial.h file. + Made the Visor connection messages a little more understandable, now + that Miles Lott (milos@insync.net) has gotten the Generic channel to + work. Also made them always show up in the log file. + + (01/25/2000) gkh + Added initial framework for FTDI serial converter so that Bill Ryder + has a place to put his code. + Added the vendor specific info from Handspring. Now we can print out + informational debug messages as well as understand what is happening. + + (01/23/2000) gkh + Fixed problem of crash when trying to open a port that didn't have a + device assigned to it. Made the minor node finding a little smarter, + now it looks to find a continuous space for the new device. + + (01/21/2000) gkh + Fixed bug in visor_startup with patch from Miles Lott (milos@insync.net) + Fixed get_serial_by_minor which was all messed up for multi port + devices. Fixed multi port problem for generic devices. Now the number + of ports is determined by the number of bulk out endpoints for the + generic device. + + (01/19/2000) gkh + Removed lots of cruft that was around from the old (pre urb) driver + interface. + Made the serial_table dynamic. This should save lots of memory when + the number of minor nodes goes up to 256. + Added initial support for devices that have more than one port. + Added more debugging comments for the Visor, and added a needed + set_configuration call. + + (01/17/2000) gkh + Fixed the WhiteHEAT firmware (my processing tool had a bug) + and added new debug loader firmware for it. + Removed the put_char function as it isn't really needed. + Added visor startup commands as found by the Win98 dump. + + (01/13/2000) gkh + Fixed the vendor id for the generic driver to the one I meant it to be. + + (01/12/2000) gkh + Forget the version numbering...that's pretty useless... + Made the driver able to be compiled so that the user can select which + converter they want to use. This allows people who only want the Visor + support to not pay the memory size price of the WhiteHEAT. + Fixed bug where the generic driver (idVendor=0000 and idProduct=0000) + grabbed the root hub. Not good. + + version 0.4.0 (01/10/2000) gkh + Added whiteheat.h containing the firmware for the ConnectTech WhiteHEAT + device. Added startup function to allow firmware to be downloaded to + a device if it needs to be. + Added firmware download logic to the WhiteHEAT device. + Started to add #defines to split up the different drivers for potential + configuration option. + + version 0.3.1 (12/30/99) gkh + Fixed problems with urb for bulk out. + Added initial support for multiple sets of endpoints. This enables + the Handspring Visor to be attached successfully. Only the first + bulk in / bulk out endpoint pair is being used right now. + + version 0.3.0 (12/27/99) gkh + Added initial support for the Handspring Visor based on a patch from + Miles Lott (milos@sneety.insync.net) + Cleaned up the code a bunch and converted over to using urbs only. + + version 0.2.3 (12/21/99) gkh + Added initial support for the Connect Tech WhiteHEAT converter. + Incremented the number of ports in expectation of getting the + WhiteHEAT to work properly (4 ports per connection). + Added notification on insertion and removal of what port the + device is/was connected to (and what kind of device it was). + + version 0.2.2 (12/16/99) gkh + Changed major number to the new allocated number. We're legal now! + + version 0.2.1 (12/14/99) gkh + Fixed bug that happens when device node is opened when there isn't a + device attached to it. Thanks to marek@webdesign.no for noticing this. + + version 0.2.0 (11/10/99) gkh + Split up internals to make it easier to add different types of serial + converters to the code. + Added a "generic" driver that gets it's vendor and product id + from when the module is loaded. Thanks to David E. Nelson (dnelson@jump.net) + for the idea and sample code (from the usb scanner driver.) + Cleared up any licensing questions by releasing it under the GNU GPL. + + version 0.1.2 (10/25/99) gkh + Fixed bug in detecting device. + + version 0.1.1 (10/05/99) gkh + Changed the major number to not conflict with anything else. + + version 0.1 (09/28/99) gkh + Can recognize the two different devices and start up a read from + device when asked to. Writes also work. No control signals yet, this + all is vendor specific data (i.e. no spec), also no control for + different baud rates or other bit settings. + Currently we are using the same devid as the acm driver. This needs + to change. + +----------------------------------------------------------------------- +visor.c Change Log comments: + + (06/03/2003) Judd Montgomery <judd at jpilot.org> + Added support for module parameter options for untested/unknown + devices. + + (03/09/2003) gkh + Added support for the Sony Clie NZ90V device. Thanks to Martin Brachtl + <brachtl@redgrep.cz> for the information. + + (03/05/2003) gkh + Think Treo support is now working. + + (04/03/2002) gkh + Added support for the Sony OS 4.1 devices. Thanks to Hiroyuki ARAKI + <hiro@zob.ne.jp> for the information. + + (03/27/2002) gkh + Removed assumptions that port->tty was always valid (is not true + for usb serial console devices.) + + (03/23/2002) gkh + Added support for the Palm i705 device, thanks to Thomas Riemer + <tom@netmech.com> for the information. + + (03/21/2002) gkh + Added support for the Palm m130 device, thanks to Udo Eisenbarth + <udo.eisenbarth@web.de> for the information. + + (02/27/2002) gkh + Reworked the urb handling logic. We have no more pool, but dynamically + allocate the urb and the transfer buffer on the fly. In testing this + does not incure any measurable overhead. This also relies on the fact + that we have proper reference counting logic for urbs. + + (02/21/2002) SilaS + Added initial support for the Palm m515 devices. + + (02/14/2002) gkh + Added support for the Clie S-360 device. + + (12/18/2001) gkh + Added better Clie support for 3.5 devices. Thanks to Geoffrey Levand + for the patch. + + (11/11/2001) gkh + Added support for the m125 devices, and added check to prevent oopses + for Clié devices that lie about the number of ports they have. + + (08/30/2001) gkh + Added support for the Clie devices, both the 3.5 and 4.0 os versions. + Many thanks to Daniel Burke, and Bryan Payne for helping with this. + + (08/23/2001) gkh + fixed a few potential bugs pointed out by Oliver Neukum. + + (05/30/2001) gkh + switched from using spinlock to a semaphore, which fixes lots of problems. + + (05/28/2000) gkh + Added initial support for the Palm m500 and Palm m505 devices. + + (04/08/2001) gb + Identify version on module load. + + (01/21/2000) gkh + Added write_room and chars_in_buffer, as they were previously using the + generic driver versions which is all wrong now that we are using an urb + pool. Thanks to Wolfgang Grandegger for pointing this out to me. + Removed count assignment in the write function, which was not needed anymore + either. Thanks to Al Borchers for pointing this out. + + (12/12/2000) gkh + Moved MOD_DEC to end of visor_close to be nicer, as the final write + message can sleep. + + (11/12/2000) gkh + Fixed bug with data being dropped on the floor by forcing tty->low_latency + to be on. Hopefully this fixes the OHCI issue! + + (11/01/2000) Adam J. Richter + usb_device_id table support + + (10/05/2000) gkh + Fixed bug with urb->dev not being set properly, now that the usb + core needs it. + + (09/11/2000) gkh + Got rid of always calling kmalloc for every urb we wrote out to the + device. + Added visor_read_callback so we can keep track of bytes in and out for + those people who like to know the speed of their device. + Removed DEBUG #ifdefs with call to usb_serial_debug_data + + (09/06/2000) gkh + Fixed oops in visor_exit. Need to uncomment usb_unlink_urb call _after_ + the host controller drivers set urb->dev = NULL when the urb is finished. + + (08/28/2000) gkh + Added locks for SMP safeness. + + (08/08/2000) gkh + Fixed endian problem in visor_startup. + Fixed MOD_INC and MOD_DEC logic and the ability to open a port more + than once. + + (07/23/2000) gkh + Added pool of write urbs to speed up transfers to the visor. + + (07/19/2000) gkh + Added module_init and module_exit functions to handle the fact that this + driver is a loadable module now. + + (07/03/2000) gkh + Added visor_set_ioctl and visor_set_termios functions (they don't do much + of anything, but are good for debugging.) + + (06/25/2000) gkh + Fixed bug in visor_unthrottle that should help with the disconnect in PPP + bug that people have been reporting. + + (06/23/2000) gkh + Cleaned up debugging statements in a quest to find UHCI timeout bug. + + (04/27/2000) Ryan VanderBijl + Fixed memory leak in visor_close + + (03/26/2000) gkh + Split driver up into device specific pieces. + +----------------------------------------------------------------------- +pl2303.c Change Log comments: + + 2002_Mar_26 gkh + allowed driver to work properly if there is no tty assigned to a port + (this happens for serial console devices.) + + 2001_Oct_06 gkh + Added RTS and DTR line control. Thanks to joe@bndlg.de for parts of it. + + 2001_Sep_19 gkh + Added break support. + + 2001_Aug_30 gkh + fixed oops in write_bulk_callback. + + 2001_Aug_28 gkh + reworked buffer logic to be like other usb-serial drivers. Hopefully + removing some reported problems. + + 2001_Jun_06 gkh + finished porting to 2.4 format. + + +----------------------------------------------------------------------- +io_edgeport.c Change Log comments: + + 2003_04_03 al borchers + - fixed a bug (that shows up with dosemu) where the tty struct is + used in a callback after it has been freed + + 2.3 2002_03_08 greg kroah-hartman + - fixed bug when multiple devices were attached at the same time. + + 2.2 2001_11_14 greg kroah-hartman + - fixed bug in edge_close that kept the port from being used more + than once. + - fixed memory leak on device removal. + - fixed potential double free of memory when command urb submitting + failed. + - other small cleanups when the device is removed + + 2.1 2001_07_09 greg kroah-hartman + - added support for TIOCMBIS and TIOCMBIC. + + (04/08/2001) gb + - Identify version on module load. + + 2.0 2001_03_05 greg kroah-hartman + - reworked entire driver to fit properly in with the other usb-serial + drivers. Occasional oopses still happen, but it's a good start. + + 1.2.3 (02/23/2001) greg kroah-hartman + - changed device table to work properly for 2.4.x final format. + - fixed problem with dropping data at high data rates. + + 1.2.2 (11/27/2000) greg kroah-hartman + - cleaned up more NTisms. + - Added device table for 2.4.0-test11 + + 1.2.1 (11/08/2000) greg kroah-hartman + - Started to clean up NTisms. + - Fixed problem with dev field of urb for kernels >= 2.4.0-test9 + + 1.2 (10/17/2000) David Iacovelli + Remove all EPIC code and GPL source + Fix RELEVANT_IFLAG macro to include flow control + changes port configuration changes. + Fix redefinition of SERIAL_MAGIC + Change all timeout values to 5 seconds + Tried to fix the UHCI multiple urb submission, but failed miserably. + it seems to work fine with OHCI. + ( Greg take a look at the #if 0 at end of WriteCmdUsb() we must + find a way to work arount this UHCI bug ) + + 1.1 (10/11/2000) David Iacovelli + Fix XON/XOFF flow control to support both IXON and IXOFF + + 0.9.27 (06/30/2000) David Iacovelli + Added transmit queue and now allocate urb for command writes. + + 0.9.26 (06/29/2000) David Iacovelli + Add support for 80251 based edgeport + + 0.9.25 (06/27/2000) David Iacovelli + Do not close the port if it has multiple opens. + + 0.9.24 (05/26/2000) David Iacovelli + Add IOCTLs to support RXTX and JAVA POS + and first cut at running BlackBox Demo + + 0.9.23 (05/24/2000) David Iacovelli + Add IOCTLs to support RXTX and JAVA POS + + 0.9.22 (05/23/2000) David Iacovelli + fixed bug in enumeration. If epconfig turns on mapping by + path after a device is already plugged in, we now update + the mapping correctly + + 0.9.21 (05/16/2000) David Iacovelli + Added BlockUntilChaseResp() to also wait for txcredits + Updated the way we allocate and handle write URBs + Add debug code to dump buffers + + 0.9.20 (05/01/2000) David Iacovelli + change driver to use usb/tts/ + + 0.9.19 (05/01/2000) David Iacovelli + Update code to compile if DEBUG is off + + 0.9.18 (04/28/2000) David Iacovelli + cleanup and test tty_register with devfs + + 0.9.17 (04/27/2000) greg kroah-hartman + changed tty_register around to be like the way it + was before, but now it works properly with devfs. + + 0.9.16 (04/26/2000) david iacovelli + Fixed bug in GetProductInfo() + + 0.9.15 (04/25/2000) david iacovelli + Updated enumeration + + 0.9.14 (04/24/2000) david iacovelli + Removed all config/status IOCTLS and + converted to using /proc/edgeport + still playing with devfs + + 0.9.13 (04/24/2000) david iacovelli + Removed configuration based on ttyUSB0 + Added support for configuration using /prod/edgeport + first attempt at using devfs (not working yet!) + Added IOCTL to GetProductInfo() + Added support for custom baud rates + Add support for random port numbers + + 0.9.12 (04/18/2000) david iacovelli + added additional configuration IOCTLs + use ttyUSB0 for configuration + + 0.9.11 (04/17/2000) greg kroah-hartman + fixed module initialization race conditions. + made all urbs dynamically allocated. + made driver devfs compatible. now it only registers the tty device + when the device is actually plugged in. + + 0.9.10 (04/13/2000) greg kroah-hartman + added proc interface framework. + + 0.9.9 (04/13/2000) david iacovelli + added enumeration code and ioctls to configure the device + + 0.9.8 (04/12/2000) david iacovelli + Change interrupt read start when device is plugged in + and stop when device is removed + process interrupt reads when all ports are closed + (keep value of rxBytesAvail consistent with the edgeport) + set the USB_BULK_QUEUE flag so that we can shove a bunch + of urbs at once down the pipe + + 0.9.7 (04/10/2000) david iacovelli + start to add enumeration code. + generate serial number for epic devices + add support for kdb + + 0.9.6 (03/30/2000) david iacovelli + add IOCTL to get string, manufacture, and boot descriptors + + 0.9.5 (03/14/2000) greg kroah-hartman + more error checking added to SerialOpen to try to fix UHCI open problem + + 0.9.4 (03/09/2000) greg kroah-hartman + added more error checking to handle oops when data is hanging + around and tty is abruptly closed. + + 0.9.3 (03/09/2000) david iacovelli + Add epic support for xon/xoff chars + play with performance + + 0.9.2 (03/08/2000) greg kroah-hartman + changed most "info" calls to "dbg" + implemented flow control properly in the termios call + + 0.9.1 (03/08/2000) david iacovelli + added EPIC support + enabled bootloader update + + 0.9 (03/08/2000) greg kroah-hartman + Release to IO networks. + Integrated changes that David made + made getting urbs for writing SMP safe + + 0.8 (03/07/2000) greg kroah-hartman + Release to IO networks. + Fixed problems that were seen in code by David. + Now both Edgeport/4 and Edgeport/2 works properly. + Changed most of the functions to use port instead of serial. + + 0.7 (02/27/2000) greg kroah-hartman + Milestone 3 release. + Release to IO Networks + ioctl for waiting on line change implemented. + ioctl for getting statistics implemented. + multiport support working. + lsr and msr registers are now handled properly. + change break now hooked up and working. + support for all known Edgeport devices. + + 0.6 (02/22/2000) greg kroah-hartman + Release to IO networks. + CHASE is implemented correctly when port is closed. + SerialOpen now blocks correctly until port is fully opened. + + 0.5 (02/20/2000) greg kroah-hartman + Release to IO networks. + Known problems: + modem status register changes are not sent on to the user + CHASE is not implemented when the port is closed. + + 0.4 (02/16/2000) greg kroah-hartman + Second cut at the CeBit demo. + Doesn't leak memory on every write to the port + Still small leaks on startup. + Added support for Edgeport/2 and Edgeport/8 + + 0.3 (02/15/2000) greg kroah-hartman + CeBit demo release. + Force the line settings to 4800, 8, 1, e for the demo. + Warning! This version leaks memory like crazy! + + 0.2 (01/30/2000) greg kroah-hartman + Milestone 1 release. + Device is found by USB subsystem, enumerated, fimware is downloaded + and the descriptors are printed to the debug log, config is set, and + green light starts to blink. Open port works, and data can be sent + and received at the default settings of the UART. Loopback connector + and debug log confirms this. + + 0.1 (01/23/2000) greg kroah-hartman + Initial release to help IO Networks try to set up their test system. + Edgeport4 is recognized, firmware is downloaded, config is set so + device blinks green light every 3 sec. Port is bound, but opening, + closing, and sending data do not work properly. + + diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index 9438909e87a5..7b5e8e4ee2bb 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -394,6 +394,15 @@ config USB_SERIAL_MCT_U232 To compile this driver as a module, choose M here: the module will be called mct_u232. +config USB_SERIAL_NOKIA_DKU2 + tristate "USB Nokia DKU2 Driver" + depends on USB_SERIAL + help + Say Y here if you want to use a Nokia DKU2 device. + + To compile this driver as a module, choose M here: the + module will be called nokia_dku2. + config USB_SERIAL_PL2303 tristate "USB Prolific 2303 Single Port Serial Driver" depends on USB_SERIAL diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile index 6c7cdcc99a9e..55fd461793b7 100644 --- a/drivers/usb/serial/Makefile +++ b/drivers/usb/serial/Makefile @@ -31,6 +31,7 @@ obj-$(CONFIG_USB_SERIAL_KEYSPAN_PDA) += keyspan_pda.o obj-$(CONFIG_USB_SERIAL_KLSI) += kl5kusb105.o obj-$(CONFIG_USB_SERIAL_KOBIL_SCT) += kobil_sct.o obj-$(CONFIG_USB_SERIAL_MCT_U232) += mct_u232.o +obj-$(CONFIG_USB_SERIAL_NOKIA_DKU2) += nokia_dku2.o obj-$(CONFIG_USB_SERIAL_OMNINET) += omninet.o obj-$(CONFIG_USB_SERIAL_OPTION) += option.o obj-$(CONFIG_USB_SERIAL_PL2303) += pl2303.o diff --git a/drivers/usb/serial/airprime.c b/drivers/usb/serial/airprime.c index 926d4c2c1600..1f29d8837327 100644 --- a/drivers/usb/serial/airprime.c +++ b/drivers/usb/serial/airprime.c @@ -30,9 +30,11 @@ static struct usb_driver airprime_driver = { .id_table = id_table, }; -static struct usb_serial_device_type airprime_device = { - .owner = THIS_MODULE, - .name = "airprime", +static struct usb_serial_driver airprime_device = { + .driver = { + .owner = THIS_MODULE, + .name = "airprime", + }, .id_table = id_table, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c index abb1b2c543bb..84bc0ee4f061 100644 --- a/drivers/usb/serial/belkin_sa.c +++ b/drivers/usb/serial/belkin_sa.c @@ -121,10 +121,12 @@ static struct usb_driver belkin_driver = { }; /* All of the device info needed for the serial converters */ -static struct usb_serial_device_type belkin_device = { - .owner = THIS_MODULE, - .name = "Belkin / Peracom / GoHubs USB Serial Adapter", - .short_name = "belkin", +static struct usb_serial_driver belkin_device = { + .driver = { + .owner = THIS_MODULE, + .name = "belkin", + }, + .description = "Belkin / Peracom / GoHubs USB Serial Adapter", .id_table = id_table_combined, .num_interrupt_in = 1, .num_bulk_in = 1, diff --git a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c index 2f612c2d894b..664139afcfa9 100644 --- a/drivers/usb/serial/bus.c +++ b/drivers/usb/serial/bus.c @@ -18,7 +18,7 @@ static int usb_serial_device_match (struct device *dev, struct device_driver *drv) { - struct usb_serial_device_type *driver; + struct usb_serial_driver *driver; const struct usb_serial_port *port; /* @@ -44,7 +44,7 @@ struct bus_type usb_serial_bus_type = { static int usb_serial_device_probe (struct device *dev) { - struct usb_serial_device_type *driver; + struct usb_serial_driver *driver; struct usb_serial_port *port; int retval = 0; int minor; @@ -57,13 +57,13 @@ static int usb_serial_device_probe (struct device *dev) driver = port->serial->type; if (driver->port_probe) { - if (!try_module_get(driver->owner)) { + if (!try_module_get(driver->driver.owner)) { dev_err(dev, "module get failed, exiting\n"); retval = -EIO; goto exit; } retval = driver->port_probe (port); - module_put(driver->owner); + module_put(driver->driver.owner); if (retval) goto exit; } @@ -72,7 +72,7 @@ static int usb_serial_device_probe (struct device *dev) tty_register_device (usb_serial_tty_driver, minor, dev); dev_info(&port->serial->dev->dev, "%s converter now attached to ttyUSB%d\n", - driver->name, minor); + driver->description, minor); exit: return retval; @@ -80,7 +80,7 @@ exit: static int usb_serial_device_remove (struct device *dev) { - struct usb_serial_device_type *driver; + struct usb_serial_driver *driver; struct usb_serial_port *port; int retval = 0; int minor; @@ -92,43 +92,38 @@ static int usb_serial_device_remove (struct device *dev) driver = port->serial->type; if (driver->port_remove) { - if (!try_module_get(driver->owner)) { + if (!try_module_get(driver->driver.owner)) { dev_err(dev, "module get failed, exiting\n"); retval = -EIO; goto exit; } retval = driver->port_remove (port); - module_put(driver->owner); + module_put(driver->driver.owner); } exit: minor = port->number; tty_unregister_device (usb_serial_tty_driver, minor); dev_info(dev, "%s converter now disconnected from ttyUSB%d\n", - driver->name, minor); + driver->description, minor); return retval; } -int usb_serial_bus_register(struct usb_serial_device_type *device) +int usb_serial_bus_register(struct usb_serial_driver *driver) { int retval; - if (device->short_name) - device->driver.name = (char *)device->short_name; - else - device->driver.name = (char *)device->name; - device->driver.bus = &usb_serial_bus_type; - device->driver.probe = usb_serial_device_probe; - device->driver.remove = usb_serial_device_remove; - device->driver.owner = device->owner; + driver->driver.bus = &usb_serial_bus_type; + driver->driver.probe = usb_serial_device_probe; + driver->driver.remove = usb_serial_device_remove; - retval = driver_register(&device->driver); + retval = driver_register(&driver->driver); return retval; } -void usb_serial_bus_deregister(struct usb_serial_device_type *device) +void usb_serial_bus_deregister(struct usb_serial_driver *driver) { - driver_unregister (&device->driver); + driver_unregister(&driver->driver); } diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c index 97c78c21e8d1..c5334dd89b12 100644 --- a/drivers/usb/serial/cp2101.c +++ b/drivers/usb/serial/cp2101.c @@ -67,15 +67,17 @@ MODULE_DEVICE_TABLE (usb, id_table); static struct usb_driver cp2101_driver = { .owner = THIS_MODULE, - .name = "CP2101", + .name = "cp2101", .probe = usb_serial_probe, .disconnect = usb_serial_disconnect, .id_table = id_table, }; -static struct usb_serial_device_type cp2101_device = { - .owner = THIS_MODULE, - .name = "CP2101", +static struct usb_serial_driver cp2101_device = { + .driver = { + .owner = THIS_MODULE, + .name = "cp2101", + }, .id_table = id_table, .num_interrupt_in = 0, .num_bulk_in = 0, diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c index b5b431067b08..e581e4ae8483 100644 --- a/drivers/usb/serial/cyberjack.c +++ b/drivers/usb/serial/cyberjack.c @@ -83,10 +83,12 @@ static struct usb_driver cyberjack_driver = { .id_table = id_table, }; -static struct usb_serial_device_type cyberjack_device = { - .owner = THIS_MODULE, - .name = "Reiner SCT Cyberjack USB card reader", - .short_name = "cyberjack", +static struct usb_serial_driver cyberjack_device = { + .driver = { + .owner = THIS_MODULE, + .name = "cyberjack", + }, + .description = "Reiner SCT Cyberjack USB card reader", .id_table = id_table, .num_interrupt_in = 1, .num_bulk_in = 1, diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index 9ee1aaff2fcd..af9290ed257b 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c @@ -176,10 +176,12 @@ static unsigned int cypress_buf_put(struct cypress_buf *cb, const char *buf, u static unsigned int cypress_buf_get(struct cypress_buf *cb, char *buf, unsigned int count); -static struct usb_serial_device_type cypress_earthmate_device = { - .owner = THIS_MODULE, - .name = "DeLorme Earthmate USB", - .short_name = "earthmate", +static struct usb_serial_driver cypress_earthmate_device = { + .driver = { + .owner = THIS_MODULE, + .name = "earthmate", + }, + .description = "DeLorme Earthmate USB", .id_table = id_table_earthmate, .num_interrupt_in = 1, .num_interrupt_out = 1, @@ -203,10 +205,12 @@ static struct usb_serial_device_type cypress_earthmate_device = { .write_int_callback = cypress_write_int_callback, }; -static struct usb_serial_device_type cypress_hidcom_device = { - .owner = THIS_MODULE, - .name = "HID->COM RS232 Adapter", - .short_name = "cyphidcom", +static struct usb_serial_driver cypress_hidcom_device = { + .driver = { + .owner = THIS_MODULE, + .name = "cyphidcom", + }, + .description = "HID->COM RS232 Adapter", .id_table = id_table_cyphidcomrs232, .num_interrupt_in = 1, .num_interrupt_out = 1, diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index a19a47f6cf12..dc74644a603d 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -503,10 +503,12 @@ static struct usb_driver digi_driver = { /* device info needed for the Digi serial converter */ -static struct usb_serial_device_type digi_acceleport_2_device = { - .owner = THIS_MODULE, - .name = "Digi 2 port USB adapter", - .short_name = "digi_2", +static struct usb_serial_driver digi_acceleport_2_device = { + .driver = { + .owner = THIS_MODULE, + .name = "digi_2", + }, + .description = "Digi 2 port USB adapter", .id_table = id_table_2, .num_interrupt_in = 0, .num_bulk_in = 4, @@ -530,10 +532,12 @@ static struct usb_serial_device_type digi_acceleport_2_device = { .shutdown = digi_shutdown, }; -static struct usb_serial_device_type digi_acceleport_4_device = { - .owner = THIS_MODULE, - .name = "Digi 4 port USB adapter", - .short_name = "digi_4", +static struct usb_serial_driver digi_acceleport_4_device = { + .driver = { + .owner = THIS_MODULE, + .name = "digi_4", + }, + .description = "Digi 4 port USB adapter", .id_table = id_table_4, .num_interrupt_in = 0, .num_bulk_in = 5, diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c index 8d562ab454a8..0b0546dcc7b9 100644 --- a/drivers/usb/serial/empeg.c +++ b/drivers/usb/serial/empeg.c @@ -112,9 +112,11 @@ static struct usb_driver empeg_driver = { .id_table = id_table, }; -static struct usb_serial_device_type empeg_device = { - .owner = THIS_MODULE, - .name = "Empeg", +static struct usb_serial_driver empeg_device = { + .driver = { + .owner = THIS_MODULE, + .name = "empeg", + }, .id_table = id_table, .num_interrupt_in = 0, .num_bulk_in = 1, diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 5a8631c8a4a7..61204bf7cd78 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -411,6 +411,8 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_ELV_UM100_PID) }, { USB_DEVICE(FTDI_VID, FTDI_ELV_UR100_PID) }, { USB_DEVICE(FTDI_VID, FTDI_ELV_ALC8500_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_PYRAMID_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_FHZ1000PC_PID) }, /* * These will probably use user-space drivers. Uncomment them if * you need them or use the user-specified vendor/product module @@ -428,7 +430,6 @@ static struct usb_device_id id_table_combined [] = { /* { USB_DEVICE(FTDI_VID, FTDI_ELV_T1100_PID) }, */ /* { USB_DEVICE(FTDI_VID, FTDI_ELV_PCD200_PID) }, */ /* { USB_DEVICE(FTDI_VID, FTDI_ELV_ULA200_PID) }, */ - /* { USB_DEVICE(FTDI_VID, FTDI_ELV_FHZ1000PC_PID) }, */ /* { USB_DEVICE(FTDI_VID, FTDI_ELV_CSI8_PID) }, */ /* { USB_DEVICE(FTDI_VID, FTDI_ELV_EM1000DL_PID) }, */ /* { USB_DEVICE(FTDI_VID, FTDI_ELV_PCK100_PID) }, */ @@ -471,6 +472,9 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_MHAM_Y6_PID) }, { USB_DEVICE(FTDI_VID, FTDI_MHAM_Y8_PID) }, { USB_DEVICE(EVOLUTION_VID, EVOLUTION_ER1_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ARTEMIS_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16HR_PID) }, { }, /* Optional parameter entry */ { } /* Terminating entry */ }; @@ -558,10 +562,12 @@ static unsigned short int ftdi_232am_baud_to_divisor (int baud); static __u32 ftdi_232bm_baud_base_to_divisor (int baud, int base); static __u32 ftdi_232bm_baud_to_divisor (int baud); -static struct usb_serial_device_type ftdi_sio_device = { - .owner = THIS_MODULE, - .name = "FTDI USB Serial Device", - .short_name = "ftdi_sio", +static struct usb_serial_driver ftdi_sio_device = { + .driver = { + .owner = THIS_MODULE, + .name = "ftdi_sio", + }, + .description = "FTDI USB Serial Device", .id_table = id_table_combined, .num_interrupt_in = 0, .num_bulk_in = 1, diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index 2c35d74cc6d6..ddb63df31ce6 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h @@ -199,6 +199,19 @@ #define FTDI_PIEGROUP_PID 0xF208 /* Product Id */ /* + * Definitions for Artemis astronomical USB based cameras + * Check it at http://www.artemisccd.co.uk/ + */ +#define FTDI_ARTEMIS_PID 0xDF28 /* All Artemis Cameras */ + +/* + * Definitions for ATIK Instruments astronomical USB based cameras + * Check it at http://www.atik-instruments.com/ + */ +#define FTDI_ATIK_ATK16_PID 0xDF30 /* ATIK ATK-16 Camera */ +#define FTDI_ATIK_ATK16HR_PID 0xDF31 /* ATIK ATK-16HR Camera */ + +/* * Protego product ids */ #define PROTEGO_SPECIAL_1 0xFC70 /* special/unknown device */ @@ -329,6 +342,9 @@ #define EVOLUTION_VID 0xDEEE /* Vendor ID */ #define EVOLUTION_ER1_PID 0x0300 /* ER1 Control Module */ +/* Pyramid Computer GmbH */ +#define FTDI_PYRAMID_PID 0xE6C8 /* Pyramid Appliance Display */ + /* Commands */ #define FTDI_SIO_RESET 0 /* Reset the port */ #define FTDI_SIO_MODEM_CTRL 1 /* Set the modem control register */ diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c index 2ef614d5c8f2..35820bda7ae1 100644 --- a/drivers/usb/serial/garmin_gps.c +++ b/drivers/usb/serial/garmin_gps.c @@ -1468,16 +1468,13 @@ static void garmin_shutdown (struct usb_serial *serial) } - - - - - /* All of the device info needed */ -static struct usb_serial_device_type garmin_device = { - .owner = THIS_MODULE, - .name = "Garmin GPS usb/tty", - .short_name = "garmin_gps", +static struct usb_serial_driver garmin_device = { + .driver = { + .owner = THIS_MODULE, + .name = "garmin_gps", + }, + .description = "Garmin GPS usb/tty", .id_table = id_table, .num_interrupt_in = 1, .num_bulk_in = 1, diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index 5f7d3193d355..8909208f506a 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c @@ -36,10 +36,11 @@ MODULE_PARM_DESC(product, "User specified USB idProduct"); static struct usb_device_id generic_device_ids[2]; /* Initially all zeroes. */ /* All of the device info needed for the Generic Serial Converter */ -struct usb_serial_device_type usb_serial_generic_device = { - .owner = THIS_MODULE, - .name = "Generic", - .short_name = "generic", +struct usb_serial_driver usb_serial_generic_device = { + .driver = { + .owner = THIS_MODULE, + .name = "generic", + }, .id_table = generic_device_ids, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, diff --git a/drivers/usb/serial/hp4x.c b/drivers/usb/serial/hp4x.c index 64d55fbd206e..8eadfb705601 100644 --- a/drivers/usb/serial/hp4x.c +++ b/drivers/usb/serial/hp4x.c @@ -38,15 +38,17 @@ MODULE_DEVICE_TABLE(usb, id_table); static struct usb_driver hp49gp_driver = { .owner = THIS_MODULE, - .name = "HP4X", + .name = "hp4X", .probe = usb_serial_probe, .disconnect = usb_serial_disconnect, .id_table = id_table, }; -static struct usb_serial_device_type hp49gp_device = { - .owner = THIS_MODULE, - .name = "HP4X", +static struct usb_serial_driver hp49gp_device = { + .driver = { + .owner = THIS_MODULE, + .name = "hp4X", + }, .id_table = id_table, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index 04bfe279d763..dc4c498bd1ed 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -27,225 +27,6 @@ * Networks technical support, or Peter Berger <pberger@brimson.com>, * or Al Borchers <alborchers@steinerpoint.com>. * - * Version history: - * - * 2003_04_03 al borchers - * - fixed a bug (that shows up with dosemu) where the tty struct is - * used in a callback after it has been freed - * - * 2.3 2002_03_08 greg kroah-hartman - * - fixed bug when multiple devices were attached at the same time. - * - * 2.2 2001_11_14 greg kroah-hartman - * - fixed bug in edge_close that kept the port from being used more - * than once. - * - fixed memory leak on device removal. - * - fixed potential double free of memory when command urb submitting - * failed. - * - other small cleanups when the device is removed - * - * 2.1 2001_07_09 greg kroah-hartman - * - added support for TIOCMBIS and TIOCMBIC. - * - * (04/08/2001) gb - * - Identify version on module load. - * - * 2.0 2001_03_05 greg kroah-hartman - * - reworked entire driver to fit properly in with the other usb-serial - * drivers. Occasional oopses still happen, but it's a good start. - * - * 1.2.3 (02/23/2001) greg kroah-hartman - * - changed device table to work properly for 2.4.x final format. - * - fixed problem with dropping data at high data rates. - * - * 1.2.2 (11/27/2000) greg kroah-hartman - * - cleaned up more NTisms. - * - Added device table for 2.4.0-test11 - * - * 1.2.1 (11/08/2000) greg kroah-hartman - * - Started to clean up NTisms. - * - Fixed problem with dev field of urb for kernels >= 2.4.0-test9 - * - * 1.2 (10/17/2000) David Iacovelli - * Remove all EPIC code and GPL source - * Fix RELEVANT_IFLAG macro to include flow control - * changes port configuration changes. - * Fix redefinition of SERIAL_MAGIC - * Change all timeout values to 5 seconds - * Tried to fix the UHCI multiple urb submission, but failed miserably. - * it seems to work fine with OHCI. - * ( Greg take a look at the #if 0 at end of WriteCmdUsb() we must - * find a way to work arount this UHCI bug ) - * - * 1.1 (10/11/2000) David Iacovelli - * Fix XON/XOFF flow control to support both IXON and IXOFF - * - * 0.9.27 (06/30/2000) David Iacovelli - * Added transmit queue and now allocate urb for command writes. - * - * 0.9.26 (06/29/2000) David Iacovelli - * Add support for 80251 based edgeport - * - * 0.9.25 (06/27/2000) David Iacovelli - * Do not close the port if it has multiple opens. - * - * 0.9.24 (05/26/2000) David Iacovelli - * Add IOCTLs to support RXTX and JAVA POS - * and first cut at running BlackBox Demo - * - * 0.9.23 (05/24/2000) David Iacovelli - * Add IOCTLs to support RXTX and JAVA POS - * - * 0.9.22 (05/23/2000) David Iacovelli - * fixed bug in enumeration. If epconfig turns on mapping by - * path after a device is already plugged in, we now update - * the mapping correctly - * - * 0.9.21 (05/16/2000) David Iacovelli - * Added BlockUntilChaseResp() to also wait for txcredits - * Updated the way we allocate and handle write URBs - * Add debug code to dump buffers - * - * 0.9.20 (05/01/2000) David Iacovelli - * change driver to use usb/tts/ - * - * 0.9.19 (05/01/2000) David Iacovelli - * Update code to compile if DEBUG is off - * - * 0.9.18 (04/28/2000) David Iacovelli - * cleanup and test tty_register with devfs - * - * 0.9.17 (04/27/2000) greg kroah-hartman - * changed tty_register around to be like the way it - * was before, but now it works properly with devfs. - * - * 0.9.16 (04/26/2000) david iacovelli - * Fixed bug in GetProductInfo() - * - * 0.9.15 (04/25/2000) david iacovelli - * Updated enumeration - * - * 0.9.14 (04/24/2000) david iacovelli - * Removed all config/status IOCTLS and - * converted to using /proc/edgeport - * still playing with devfs - * - * 0.9.13 (04/24/2000) david iacovelli - * Removed configuration based on ttyUSB0 - * Added support for configuration using /prod/edgeport - * first attempt at using devfs (not working yet!) - * Added IOCTL to GetProductInfo() - * Added support for custom baud rates - * Add support for random port numbers - * - * 0.9.12 (04/18/2000) david iacovelli - * added additional configuration IOCTLs - * use ttyUSB0 for configuration - * - * 0.9.11 (04/17/2000) greg kroah-hartman - * fixed module initialization race conditions. - * made all urbs dynamically allocated. - * made driver devfs compatible. now it only registers the tty device - * when the device is actually plugged in. - * - * 0.9.10 (04/13/2000) greg kroah-hartman - * added proc interface framework. - * - * 0.9.9 (04/13/2000) david iacovelli - * added enumeration code and ioctls to configure the device - * - * 0.9.8 (04/12/2000) david iacovelli - * Change interrupt read start when device is plugged in - * and stop when device is removed - * process interrupt reads when all ports are closed - * (keep value of rxBytesAvail consistent with the edgeport) - * set the USB_BULK_QUEUE flag so that we can shove a bunch - * of urbs at once down the pipe - * - * 0.9.7 (04/10/2000) david iacovelli - * start to add enumeration code. - * generate serial number for epic devices - * add support for kdb - * - * 0.9.6 (03/30/2000) david iacovelli - * add IOCTL to get string, manufacture, and boot descriptors - * - * 0.9.5 (03/14/2000) greg kroah-hartman - * more error checking added to SerialOpen to try to fix UHCI open problem - * - * 0.9.4 (03/09/2000) greg kroah-hartman - * added more error checking to handle oops when data is hanging - * around and tty is abruptly closed. - * - * 0.9.3 (03/09/2000) david iacovelli - * Add epic support for xon/xoff chars - * play with performance - * - * 0.9.2 (03/08/2000) greg kroah-hartman - * changed most "info" calls to "dbg" - * implemented flow control properly in the termios call - * - * 0.9.1 (03/08/2000) david iacovelli - * added EPIC support - * enabled bootloader update - * - * 0.9 (03/08/2000) greg kroah-hartman - * Release to IO networks. - * Integrated changes that David made - * made getting urbs for writing SMP safe - * - * 0.8 (03/07/2000) greg kroah-hartman - * Release to IO networks. - * Fixed problems that were seen in code by David. - * Now both Edgeport/4 and Edgeport/2 works properly. - * Changed most of the functions to use port instead of serial. - * - * 0.7 (02/27/2000) greg kroah-hartman - * Milestone 3 release. - * Release to IO Networks - * ioctl for waiting on line change implemented. - * ioctl for getting statistics implemented. - * multiport support working. - * lsr and msr registers are now handled properly. - * change break now hooked up and working. - * support for all known Edgeport devices. - * - * 0.6 (02/22/2000) greg kroah-hartman - * Release to IO networks. - * CHASE is implemented correctly when port is closed. - * SerialOpen now blocks correctly until port is fully opened. - * - * 0.5 (02/20/2000) greg kroah-hartman - * Release to IO networks. - * Known problems: - * modem status register changes are not sent on to the user - * CHASE is not implemented when the port is closed. - * - * 0.4 (02/16/2000) greg kroah-hartman - * Second cut at the CeBit demo. - * Doesn't leak memory on every write to the port - * Still small leaks on startup. - * Added support for Edgeport/2 and Edgeport/8 - * - * 0.3 (02/15/2000) greg kroah-hartman - * CeBit demo release. - * Force the line settings to 4800, 8, 1, e for the demo. - * Warning! This version leaks memory like crazy! - * - * 0.2 (01/30/2000) greg kroah-hartman - * Milestone 1 release. - * Device is found by USB subsystem, enumerated, fimware is downloaded - * and the descriptors are printed to the debug log, config is set, and - * green light starts to blink. Open port works, and data can be sent - * and received at the default settings of the UART. Loopback connector - * and debug log confirms this. - * - * 0.1 (01/23/2000) greg kroah-hartman - * Initial release to help IO Networks try to set up their test system. - * Edgeport4 is recognized, firmware is downloaded, config is set so - * device blinks green light every 3 sec. Port is bound, but opening, - * closing, and sending data do not work properly. - * */ #include <linux/config.h> diff --git a/drivers/usb/serial/io_tables.h b/drivers/usb/serial/io_tables.h index e7ffe02408bd..fad561c04c76 100644 --- a/drivers/usb/serial/io_tables.h +++ b/drivers/usb/serial/io_tables.h @@ -75,10 +75,12 @@ static struct usb_device_id id_table_combined [] = { MODULE_DEVICE_TABLE (usb, id_table_combined); -static struct usb_serial_device_type edgeport_2port_device = { - .owner = THIS_MODULE, - .name = "Edgeport 2 port adapter", - .short_name = "edgeport_2", +static struct usb_serial_driver edgeport_2port_device = { + .driver = { + .owner = THIS_MODULE, + .name = "edgeport_2", + }, + .description = "Edgeport 2 port adapter", .id_table = edgeport_2port_id_table, .num_interrupt_in = 1, .num_bulk_in = 1, @@ -103,10 +105,12 @@ static struct usb_serial_device_type edgeport_2port_device = { .write_bulk_callback = edge_bulk_out_data_callback, }; -static struct usb_serial_device_type edgeport_4port_device = { - .owner = THIS_MODULE, - .name = "Edgeport 4 port adapter", - .short_name = "edgeport_4", +static struct usb_serial_driver edgeport_4port_device = { + .driver = { + .owner = THIS_MODULE, + .name = "edgeport_4", + }, + .description = "Edgeport 4 port adapter", .id_table = edgeport_4port_id_table, .num_interrupt_in = 1, .num_bulk_in = 1, @@ -131,10 +135,12 @@ static struct usb_serial_device_type edgeport_4port_device = { .write_bulk_callback = edge_bulk_out_data_callback, }; -static struct usb_serial_device_type edgeport_8port_device = { - .owner = THIS_MODULE, - .name = "Edgeport 8 port adapter", - .short_name = "edgeport_8", +static struct usb_serial_driver edgeport_8port_device = { + .driver = { + .owner = THIS_MODULE, + .name = "edgeport_8", + }, + .description = "Edgeport 8 port adapter", .id_table = edgeport_8port_id_table, .num_interrupt_in = 1, .num_bulk_in = 1, diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index ebf9967f7c86..832b6d6734c0 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -2982,10 +2982,12 @@ static unsigned int edge_buf_get(struct edge_buf *eb, char *buf, } -static struct usb_serial_device_type edgeport_1port_device = { - .owner = THIS_MODULE, - .name = "Edgeport TI 1 port adapter", - .short_name = "edgeport_ti_1", +static struct usb_serial_driver edgeport_1port_device = { + .driver = { + .owner = THIS_MODULE, + .name = "edgeport_ti_1", + }, + .description = "Edgeport TI 1 port adapter", .id_table = edgeport_1port_id_table, .num_interrupt_in = 1, .num_bulk_in = 1, @@ -3010,10 +3012,12 @@ static struct usb_serial_device_type edgeport_1port_device = { .write_bulk_callback = edge_bulk_out_callback, }; -static struct usb_serial_device_type edgeport_2port_device = { - .owner = THIS_MODULE, - .name = "Edgeport TI 2 port adapter", - .short_name = "edgeport_ti_2", +static struct usb_serial_driver edgeport_2port_device = { + .driver = { + .owner = THIS_MODULE, + .name = "edgeport_ti_2", + }, + .description = "Edgeport TI 2 port adapter", .id_table = edgeport_2port_id_table, .num_interrupt_in = 1, .num_bulk_in = 2, diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c index c05c2a2a0f31..d5d066488100 100644 --- a/drivers/usb/serial/ipaq.c +++ b/drivers/usb/serial/ipaq.c @@ -92,24 +92,7 @@ static void ipaq_destroy_lists(struct usb_serial_port *port); static struct usb_device_id ipaq_id_table [] = { /* The first entry is a placeholder for the insmod-specified device */ { USB_DEVICE(0x049F, 0x0003) }, - { USB_DEVICE(0x1690, 0x0601) }, /* Askey USB Sync */ - { USB_DEVICE(0x0960, 0x0065) }, /* BCOM USB Sync 0065 */ - { USB_DEVICE(0x0960, 0x0066) }, /* BCOM USB Sync 0066 */ - { USB_DEVICE(0x0960, 0x0067) }, /* BCOM USB Sync 0067 */ - { USB_DEVICE(0x07CF, 0x2001) }, /* CASIO USB Sync 2001 */ - { USB_DEVICE(0x07CF, 0x2002) }, /* CASIO USB Sync 2002 */ - { USB_DEVICE(0x07CF, 0x2003) }, /* CASIO USB Sync 2003 */ - { USB_DEVICE(0x049F, 0x0003) }, /* Compaq iPAQ USB Sync */ - { USB_DEVICE(0x049F, 0x0032) }, /* Compaq iPAQ USB Sync */ - { USB_DEVICE(0x413C, 0x4001) }, /* Dell Axim USB Sync */ - { USB_DEVICE(0x413C, 0x4002) }, /* Dell Axim USB Sync */ - { USB_DEVICE(0x413C, 0x4003) }, /* Dell Axim USB Sync */ - { USB_DEVICE(0x413C, 0x4004) }, /* Dell Axim USB Sync */ - { USB_DEVICE(0x413C, 0x4005) }, /* Dell Axim USB Sync */ - { USB_DEVICE(0x413C, 0x4006) }, /* Dell Axim USB Sync */ - { USB_DEVICE(0x413C, 0x4007) }, /* Dell Axim USB Sync */ - { USB_DEVICE(0x413C, 0x4008) }, /* Dell Axim USB Sync */ - { USB_DEVICE(0x413C, 0x4009) }, /* Dell Axim USB Sync */ + { USB_DEVICE(0x0104, 0x00BE) }, /* Socket USB Sync */ { USB_DEVICE(0x03F0, 0x1016) }, /* HP USB Sync */ { USB_DEVICE(0x03F0, 0x1116) }, /* HP USB Sync 1611 */ { USB_DEVICE(0x03F0, 0x1216) }, /* HP USB Sync 1612 */ @@ -125,7 +108,13 @@ static struct usb_device_id ipaq_id_table [] = { { USB_DEVICE(0x03F0, 0x5016) }, /* HP USB Sync 1650 */ { USB_DEVICE(0x03F0, 0x5116) }, /* HP USB Sync 1651 */ { USB_DEVICE(0x03F0, 0x5216) }, /* HP USB Sync 1652 */ - { USB_DEVICE(0x094B, 0x0001) }, /* Linkup Systems USB Sync */ + { USB_DEVICE(0x0409, 0x00D5) }, /* NEC USB Sync */ + { USB_DEVICE(0x0409, 0x00D6) }, /* NEC USB Sync */ + { USB_DEVICE(0x0409, 0x00D7) }, /* NEC USB Sync */ + { USB_DEVICE(0x0409, 0x8024) }, /* NEC USB Sync */ + { USB_DEVICE(0x0409, 0x8025) }, /* NEC USB Sync */ + { USB_DEVICE(0x043E, 0x9C01) }, /* LGE USB Sync */ + { USB_DEVICE(0x045E, 0x00CE) }, /* Microsoft USB Sync */ { USB_DEVICE(0x045E, 0x0400) }, /* Windows Powered Pocket PC 2002 */ { USB_DEVICE(0x045E, 0x0401) }, /* Windows Powered Pocket PC 2002 */ { USB_DEVICE(0x045E, 0x0402) }, /* Windows Powered Pocket PC 2002 */ @@ -251,17 +240,81 @@ static struct usb_device_id ipaq_id_table [] = { { USB_DEVICE(0x045E, 0x04E8) }, /* Windows Powered Smartphone 2003 */ { USB_DEVICE(0x045E, 0x04E9) }, /* Windows Powered Smartphone 2003 */ { USB_DEVICE(0x045E, 0x04EA) }, /* Windows Powered Smartphone 2003 */ - { USB_DEVICE(0x0961, 0x0010) }, /* Portatec USB Sync */ - { USB_DEVICE(0x5E04, 0xCE00) }, /* SAGEM Wireless Assistant */ - { USB_DEVICE(0x0104, 0x00BE) }, /* Socket USB Sync */ + { USB_DEVICE(0x049F, 0x0003) }, /* Compaq iPAQ USB Sync */ + { USB_DEVICE(0x049F, 0x0032) }, /* Compaq iPAQ USB Sync */ + { USB_DEVICE(0x04A4, 0x0014) }, /* Hitachi USB Sync */ + { USB_DEVICE(0x04AD, 0x0301) }, /* USB Sync 0301 */ + { USB_DEVICE(0x04AD, 0x0302) }, /* USB Sync 0302 */ + { USB_DEVICE(0x04AD, 0x0303) }, /* USB Sync 0303 */ + { USB_DEVICE(0x04C5, 0x1058) }, /* FUJITSU USB Sync */ + { USB_DEVICE(0x04C5, 0x1079) }, /* FUJITSU USB Sync */ + { USB_DEVICE(0x04DA, 0x2500) }, /* Panasonic USB Sync */ + { USB_DEVICE(0x04E8, 0x5F00) }, /* Samsung NEXiO USB Sync */ + { USB_DEVICE(0x04E8, 0x5F01) }, /* Samsung NEXiO USB Sync */ + { USB_DEVICE(0x04E8, 0x5F02) }, /* Samsung NEXiO USB Sync */ + { USB_DEVICE(0x04E8, 0x5F03) }, /* Samsung NEXiO USB Sync */ + { USB_DEVICE(0x04E8, 0x5F04) }, /* Samsung NEXiO USB Sync */ + { USB_DEVICE(0x04E8, 0x6611) }, /* Samsung MITs USB Sync */ + { USB_DEVICE(0x04E8, 0x6613) }, /* Samsung MITs USB Sync */ + { USB_DEVICE(0x04E8, 0x6615) }, /* Samsung MITs USB Sync */ + { USB_DEVICE(0x04E8, 0x6617) }, /* Samsung MITs USB Sync */ + { USB_DEVICE(0x04E8, 0x6619) }, /* Samsung MITs USB Sync */ + { USB_DEVICE(0x04E8, 0x661B) }, /* Samsung MITs USB Sync */ + { USB_DEVICE(0x04E8, 0x662E) }, /* Samsung MITs USB Sync */ + { USB_DEVICE(0x04E8, 0x6630) }, /* Samsung MITs USB Sync */ + { USB_DEVICE(0x04E8, 0x6632) }, /* Samsung MITs USB Sync */ + { USB_DEVICE(0x04f1, 0x3011) }, /* JVC USB Sync */ + { USB_DEVICE(0x04F1, 0x3012) }, /* JVC USB Sync */ + { USB_DEVICE(0x0502, 0x1631) }, /* c10 Series */ + { USB_DEVICE(0x0502, 0x1632) }, /* c20 Series */ + { USB_DEVICE(0x0502, 0x16E1) }, /* Acer n10 Handheld USB Sync */ + { USB_DEVICE(0x0502, 0x16E2) }, /* Acer n20 Handheld USB Sync */ + { USB_DEVICE(0x0502, 0x16E3) }, /* Acer n30 Handheld USB Sync */ + { USB_DEVICE(0x0536, 0x01A0) }, /* HHP PDT */ + { USB_DEVICE(0x0543, 0x0ED9) }, /* ViewSonic Color Pocket PC V35 */ + { USB_DEVICE(0x0543, 0x1527) }, /* ViewSonic Color Pocket PC V36 */ + { USB_DEVICE(0x0543, 0x1529) }, /* ViewSonic Color Pocket PC V37 */ + { USB_DEVICE(0x0543, 0x152B) }, /* ViewSonic Color Pocket PC V38 */ + { USB_DEVICE(0x0543, 0x152E) }, /* ViewSonic Pocket PC */ + { USB_DEVICE(0x0543, 0x1921) }, /* ViewSonic Communicator Pocket PC */ + { USB_DEVICE(0x0543, 0x1922) }, /* ViewSonic Smartphone */ + { USB_DEVICE(0x0543, 0x1923) }, /* ViewSonic Pocket PC V30 */ + { USB_DEVICE(0x05E0, 0x2000) }, /* Symbol USB Sync */ + { USB_DEVICE(0x05E0, 0x2001) }, /* Symbol USB Sync 0x2001 */ + { USB_DEVICE(0x05E0, 0x2002) }, /* Symbol USB Sync 0x2002 */ + { USB_DEVICE(0x05E0, 0x2003) }, /* Symbol USB Sync 0x2003 */ + { USB_DEVICE(0x05E0, 0x2004) }, /* Symbol USB Sync 0x2004 */ + { USB_DEVICE(0x05E0, 0x2005) }, /* Symbol USB Sync 0x2005 */ + { USB_DEVICE(0x05E0, 0x2006) }, /* Symbol USB Sync 0x2006 */ + { USB_DEVICE(0x05E0, 0x2007) }, /* Symbol USB Sync 0x2007 */ + { USB_DEVICE(0x05E0, 0x2008) }, /* Symbol USB Sync 0x2008 */ + { USB_DEVICE(0x05E0, 0x2009) }, /* Symbol USB Sync 0x2009 */ + { USB_DEVICE(0x05E0, 0x200A) }, /* Symbol USB Sync 0x200A */ + { USB_DEVICE(0x067E, 0x1001) }, /* Intermec Mobile Computer */ + { USB_DEVICE(0x07CF, 0x2001) }, /* CASIO USB Sync 2001 */ + { USB_DEVICE(0x07CF, 0x2002) }, /* CASIO USB Sync 2002 */ + { USB_DEVICE(0x07CF, 0x2003) }, /* CASIO USB Sync 2003 */ { USB_DEVICE(0x0930, 0x0700) }, /* TOSHIBA USB Sync 0700 */ { USB_DEVICE(0x0930, 0x0705) }, /* TOSHIBA Pocket PC e310 */ + { USB_DEVICE(0x0930, 0x0706) }, /* TOSHIBA Pocket PC e740 */ { USB_DEVICE(0x0930, 0x0707) }, /* TOSHIBA Pocket PC e330 Series */ { USB_DEVICE(0x0930, 0x0708) }, /* TOSHIBA Pocket PC e350Series */ - { USB_DEVICE(0x0930, 0x0706) }, /* TOSHIBA Pocket PC e740 */ { USB_DEVICE(0x0930, 0x0709) }, /* TOSHIBA Pocket PC e750 Series */ { USB_DEVICE(0x0930, 0x070A) }, /* TOSHIBA Pocket PC e400 Series */ { USB_DEVICE(0x0930, 0x070B) }, /* TOSHIBA Pocket PC e800 Series */ + { USB_DEVICE(0x094B, 0x0001) }, /* Linkup Systems USB Sync */ + { USB_DEVICE(0x0960, 0x0065) }, /* BCOM USB Sync 0065 */ + { USB_DEVICE(0x0960, 0x0066) }, /* BCOM USB Sync 0066 */ + { USB_DEVICE(0x0960, 0x0067) }, /* BCOM USB Sync 0067 */ + { USB_DEVICE(0x0961, 0x0010) }, /* Portatec USB Sync */ + { USB_DEVICE(0x099E, 0x0052) }, /* Trimble GeoExplorer */ + { USB_DEVICE(0x099E, 0x4000) }, /* TDS Data Collector */ + { USB_DEVICE(0x0B05, 0x4200) }, /* ASUS USB Sync */ + { USB_DEVICE(0x0B05, 0x4201) }, /* ASUS USB Sync */ + { USB_DEVICE(0x0B05, 0x4202) }, /* ASUS USB Sync */ + { USB_DEVICE(0x0B05, 0x420F) }, /* ASUS USB Sync */ + { USB_DEVICE(0x0B05, 0x9200) }, /* ASUS USB Sync */ + { USB_DEVICE(0x0B05, 0x9202) }, /* ASUS USB Sync */ { USB_DEVICE(0x0BB4, 0x00CE) }, /* HTC USB Sync */ { USB_DEVICE(0x0BB4, 0x0A01) }, /* PocketPC USB Sync */ { USB_DEVICE(0x0BB4, 0x0A02) }, /* PocketPC USB Sync */ @@ -422,116 +475,67 @@ static struct usb_device_id ipaq_id_table [] = { { USB_DEVICE(0x0BB4, 0x0A9D) }, /* SmartPhone USB Sync */ { USB_DEVICE(0x0BB4, 0x0A9E) }, /* SmartPhone USB Sync */ { USB_DEVICE(0x0BB4, 0x0A9F) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0409, 0x00D5) }, /* NEC USB Sync */ - { USB_DEVICE(0x0409, 0x00D6) }, /* NEC USB Sync */ - { USB_DEVICE(0x0409, 0x00D7) }, /* NEC USB Sync */ - { USB_DEVICE(0x0409, 0x8024) }, /* NEC USB Sync */ - { USB_DEVICE(0x0409, 0x8025) }, /* NEC USB Sync */ - { USB_DEVICE(0x04A4, 0x0014) }, /* Hitachi USB Sync */ { USB_DEVICE(0x0BF8, 0x1001) }, /* Fujitsu Siemens Computers USB Sync */ - { USB_DEVICE(0x0F98, 0x0201) }, /* Cyberbank USB Sync */ - { USB_DEVICE(0x0502, 0x16E1) }, /* Acer n10 Handheld USB Sync */ - { USB_DEVICE(0x0502, 0x16E3) }, /* Acer n30 Handheld USB Sync */ - { USB_DEVICE(0x0502, 0x16E2) }, /* Acer n20 Handheld USB Sync */ - { USB_DEVICE(0x0502, 0x1631) }, /* c10 Series */ - { USB_DEVICE(0x0502, 0x1632) }, /* c20 Series */ - { USB_DEVICE(0x0B05, 0x9202) }, /* ASUS USB Sync */ - { USB_DEVICE(0x0B05, 0x420F) }, /* ASUS USB Sync */ - { USB_DEVICE(0x0B05, 0x4200) }, /* ASUS USB Sync */ - { USB_DEVICE(0x0B05, 0x4201) }, /* ASUS USB Sync */ - { USB_DEVICE(0x0B05, 0x4202) }, /* ASUS USB Sync */ - { USB_DEVICE(0x0B05, 0x9200) }, /* ASUS USB Sync */ + { USB_DEVICE(0x0C44, 0x03A2) }, /* Motorola iDEN Smartphone */ { USB_DEVICE(0x0C8E, 0x6000) }, /* Cesscom Luxian Series */ - { USB_DEVICE(0x04AD, 0x0301) }, /* USB Sync 0301 */ - { USB_DEVICE(0x04AD, 0x0302) }, /* USB Sync 0302 */ - { USB_DEVICE(0x04AD, 0x0303) }, /* USB Sync 0303 */ + { USB_DEVICE(0x0CAD, 0x9001) }, /* Motorola PowerPad Pocket PCDevice */ + { USB_DEVICE(0x0F4E, 0x0200) }, /* Freedom Scientific USB Sync */ + { USB_DEVICE(0x0F98, 0x0201) }, /* Cyberbank USB Sync */ + { USB_DEVICE(0x0FB8, 0x3001) }, /* Wistron USB Sync */ + { USB_DEVICE(0x0FB8, 0x3002) }, /* Wistron USB Sync */ + { USB_DEVICE(0x0FB8, 0x3003) }, /* Wistron USB Sync */ + { USB_DEVICE(0x0FB8, 0x4001) }, /* Wistron USB Sync */ + { USB_DEVICE(0x1066, 0x00CE) }, /* E-TEN USB Sync */ { USB_DEVICE(0x1066, 0x0300) }, /* E-TEN P3XX Pocket PC */ { USB_DEVICE(0x1066, 0x0500) }, /* E-TEN P5XX Pocket PC */ { USB_DEVICE(0x1066, 0x0600) }, /* E-TEN P6XX Pocket PC */ { USB_DEVICE(0x1066, 0x0700) }, /* E-TEN P7XX Pocket PC */ - { USB_DEVICE(0x1066, 0x00CE) }, /* E-TEN USB Sync */ - { USB_DEVICE(0x0F4E, 0x0200) }, /* Freedom Scientific USB Sync */ - { USB_DEVICE(0x04C5, 0x1058) }, /* FUJITSU USB Sync */ - { USB_DEVICE(0x04C5, 0x1079) }, /* FUJITSU USB Sync */ - { USB_DEVICE(0x067E, 0x1001) }, /* Intermec Mobile Computer */ - { USB_DEVICE(0x04f1, 0x3011) }, /* JVC USB Sync */ - { USB_DEVICE(0x04F1, 0x3012) }, /* JVC USB Sync */ - { USB_DEVICE(0x3708, 0x20CE) }, /* Legend USB Sync */ - { USB_DEVICE(0x3708, 0x21CE) }, /* Lenovo USB Sync */ - { USB_DEVICE(0x043E, 0x9C01) }, /* LGE USB Sync */ - { USB_DEVICE(0x04DA, 0x2500) }, /* Panasonic USB Sync */ - { USB_DEVICE(0x3340, 0x0B1C) }, /* Generic PPC StrongARM */ - { USB_DEVICE(0x3340, 0x0E3A) }, /* Generic PPC USB Sync */ - { USB_DEVICE(0x3340, 0x0F3A) }, /* Generic SmartPhone USB Sync */ - { USB_DEVICE(0x3340, 0x0F1C) }, /* Itautec USB Sync */ - { USB_DEVICE(0x3340, 0x1326) }, /* Itautec USB Sync */ - { USB_DEVICE(0x3340, 0x3326) }, /* MEDION Winodws Moble USB Sync */ + { USB_DEVICE(0x1114, 0x0001) }, /* Psion Teklogix Sync 753x */ + { USB_DEVICE(0x1114, 0x0004) }, /* Psion Teklogix Sync netBookPro */ + { USB_DEVICE(0x1114, 0x0006) }, /* Psion Teklogix Sync 7525 */ + { USB_DEVICE(0x1182, 0x1388) }, /* VES USB Sync */ + { USB_DEVICE(0x11D9, 0x1002) }, /* Rugged Pocket PC 2003 */ + { USB_DEVICE(0x11D9, 0x1003) }, /* Rugged Pocket PC 2003 */ + { USB_DEVICE(0x1231, 0xCE01) }, /* USB Sync 03 */ + { USB_DEVICE(0x1231, 0xCE02) }, /* USB Sync 03 */ + { USB_DEVICE(0x1690, 0x0601) }, /* Askey USB Sync */ + { USB_DEVICE(0x22B8, 0x4204) }, /* Motorola MPx200 Smartphone */ + { USB_DEVICE(0x22B8, 0x4214) }, /* Motorola MPc GSM */ + { USB_DEVICE(0x22B8, 0x4224) }, /* Motorola MPx220 Smartphone */ + { USB_DEVICE(0x22B8, 0x4234) }, /* Motorola MPc CDMA */ + { USB_DEVICE(0x22B8, 0x4244) }, /* Motorola MPx100 Smartphone */ + { USB_DEVICE(0x3340, 0x011C) }, /* Mio DigiWalker PPC StrongARM */ { USB_DEVICE(0x3340, 0x0326) }, /* Mio DigiWalker 338 */ { USB_DEVICE(0x3340, 0x0426) }, /* Mio DigiWalker 338 */ - { USB_DEVICE(0x3340, 0x011C) }, /* Mio DigiWalker PPC StrongARM */ - { USB_DEVICE(0x3340, 0x053A) }, /* Mio DigiWalker SmartPhone USB Sync */ { USB_DEVICE(0x3340, 0x043A) }, /* Mio DigiWalker USB Sync */ - { USB_DEVICE(0x3340, 0x071C) }, /* MiTAC USB Sync */ { USB_DEVICE(0x3340, 0x051C) }, /* MiTAC USB Sync 528 */ - { USB_DEVICE(0x3340, 0x2326) }, /* Vobis USB Sync */ + { USB_DEVICE(0x3340, 0x053A) }, /* Mio DigiWalker SmartPhone USB Sync */ + { USB_DEVICE(0x3340, 0x071C) }, /* MiTAC USB Sync */ + { USB_DEVICE(0x3340, 0x0B1C) }, /* Generic PPC StrongARM */ + { USB_DEVICE(0x3340, 0x0E3A) }, /* Generic PPC USB Sync */ + { USB_DEVICE(0x3340, 0x0F1C) }, /* Itautec USB Sync */ + { USB_DEVICE(0x3340, 0x0F3A) }, /* Generic SmartPhone USB Sync */ + { USB_DEVICE(0x3340, 0x1326) }, /* Itautec USB Sync */ { USB_DEVICE(0x3340, 0x191C) }, /* YAKUMO USB Sync */ + { USB_DEVICE(0x3340, 0x2326) }, /* Vobis USB Sync */ + { USB_DEVICE(0x3340, 0x3326) }, /* MEDION Winodws Moble USB Sync */ + { USB_DEVICE(0x3708, 0x20CE) }, /* Legend USB Sync */ + { USB_DEVICE(0x3708, 0x21CE) }, /* Lenovo USB Sync */ { USB_DEVICE(0x4113, 0x0210) }, /* Mobile Media Technology USB Sync */ { USB_DEVICE(0x4113, 0x0211) }, /* Mobile Media Technology USB Sync */ { USB_DEVICE(0x4113, 0x0400) }, /* Mobile Media Technology USB Sync */ { USB_DEVICE(0x4113, 0x0410) }, /* Mobile Media Technology USB Sync */ - { USB_DEVICE(0x0CAD, 0x9001) }, /* Motorola PowerPad Pocket PCDevice */ - { USB_DEVICE(0x0C44, 0x03A2) }, /* Motorola iDEN Smartphone */ - { USB_DEVICE(0x04E8, 0x6611) }, /* Samsung MITs USB Sync */ - { USB_DEVICE(0x04E8, 0x6613) }, /* Samsung MITs USB Sync */ - { USB_DEVICE(0x04E8, 0x6615) }, /* Samsung MITs USB Sync */ - { USB_DEVICE(0x04E8, 0x6617) }, /* Samsung MITs USB Sync */ - { USB_DEVICE(0x04E8, 0x6619) }, /* Samsung MITs USB Sync */ - { USB_DEVICE(0x04E8, 0x661B) }, /* Samsung MITs USB Sync */ - { USB_DEVICE(0x04E8, 0x5F00) }, /* Samsung NEXiO USB Sync */ - { USB_DEVICE(0x04E8, 0x5F01) }, /* Samsung NEXiO USB Sync */ - { USB_DEVICE(0x04E8, 0x5F02) }, /* Samsung NEXiO USB Sync */ - { USB_DEVICE(0x04E8, 0x5F03) }, /* Samsung NEXiO USB Sync */ - { USB_DEVICE(0x04E8, 0x5F04) }, /* Samsung NEXiO USB Sync */ - { USB_DEVICE(0x04E8, 0x662E) }, /* Samsung MITs USB Sync */ - { USB_DEVICE(0x04E8, 0x6630) }, /* Samsung MITs USB Sync */ - { USB_DEVICE(0x04E8, 0x6632) }, /* Samsung MITs USB Sync */ + { USB_DEVICE(0x413C, 0x4001) }, /* Dell Axim USB Sync */ + { USB_DEVICE(0x413C, 0x4002) }, /* Dell Axim USB Sync */ + { USB_DEVICE(0x413C, 0x4003) }, /* Dell Axim USB Sync */ + { USB_DEVICE(0x413C, 0x4004) }, /* Dell Axim USB Sync */ + { USB_DEVICE(0x413C, 0x4005) }, /* Dell Axim USB Sync */ + { USB_DEVICE(0x413C, 0x4006) }, /* Dell Axim USB Sync */ + { USB_DEVICE(0x413C, 0x4007) }, /* Dell Axim USB Sync */ + { USB_DEVICE(0x413C, 0x4008) }, /* Dell Axim USB Sync */ + { USB_DEVICE(0x413C, 0x4009) }, /* Dell Axim USB Sync */ { USB_DEVICE(0x4505, 0x0010) }, /* Smartphone */ - { USB_DEVICE(0x05E0, 0x2000) }, /* Symbol USB Sync */ - { USB_DEVICE(0x05E0, 0x2001) }, /* Symbol USB Sync 0x2001 */ - { USB_DEVICE(0x05E0, 0x2002) }, /* Symbol USB Sync 0x2002 */ - { USB_DEVICE(0x05E0, 0x2003) }, /* Symbol USB Sync 0x2003 */ - { USB_DEVICE(0x05E0, 0x2004) }, /* Symbol USB Sync 0x2004 */ - { USB_DEVICE(0x05E0, 0x2005) }, /* Symbol USB Sync 0x2005 */ - { USB_DEVICE(0x05E0, 0x2006) }, /* Symbol USB Sync 0x2006 */ - { USB_DEVICE(0x05E0, 0x2007) }, /* Symbol USB Sync 0x2007 */ - { USB_DEVICE(0x05E0, 0x2008) }, /* Symbol USB Sync 0x2008 */ - { USB_DEVICE(0x05E0, 0x2009) }, /* Symbol USB Sync 0x2009 */ - { USB_DEVICE(0x05E0, 0x200A) }, /* Symbol USB Sync 0x200A */ - { USB_DEVICE(0x1182, 0x1388) }, /* VES USB Sync */ - { USB_DEVICE(0x0543, 0x0ED9) }, /* ViewSonic Color Pocket PC V35 */ - { USB_DEVICE(0x0543, 0x1527) }, /* ViewSonic Color Pocket PC V36 */ - { USB_DEVICE(0x0543, 0x1529) }, /* ViewSonic Color Pocket PC V37 */ - { USB_DEVICE(0x0543, 0x152B) }, /* ViewSonic Color Pocket PC V38 */ - { USB_DEVICE(0x0543, 0x152E) }, /* ViewSonic Pocket PC */ - { USB_DEVICE(0x0543, 0x1921) }, /* ViewSonic Communicator Pocket PC */ - { USB_DEVICE(0x0543, 0x1922) }, /* ViewSonic Smartphone */ - { USB_DEVICE(0x0543, 0x1923) }, /* ViewSonic Pocket PC V30 */ - { USB_DEVICE(0x0536, 0x01A0) }, /* HHP PDT */ - { USB_DEVICE(0x099E, 0x0052) }, /* Trimble GeoExplorer */ - { USB_DEVICE(0x099E, 0x4000) }, /* TDS Data Collector */ - { USB_DEVICE(0x0FB8, 0x3001) }, /* Wistron USB Sync */ - { USB_DEVICE(0x0FB8, 0x3002) }, /* Wistron USB Sync */ - { USB_DEVICE(0x0FB8, 0x3003) }, /* Wistron USB Sync */ - { USB_DEVICE(0x0FB8, 0x4001) }, /* Wistron USB Sync */ - { USB_DEVICE(0x11D9, 0x1003) }, /* Rugged Pocket PC 2003 */ - { USB_DEVICE(0x11D9, 0x1002) }, /* Rugged Pocket PC 2003 */ - { USB_DEVICE(0x22B8, 0x4204) }, /* Motorola MPx200 Smartphone */ - { USB_DEVICE(0x22B8, 0x4214) }, /* Motorola MPc GSM */ - { USB_DEVICE(0x22B8, 0x4224) }, /* Motorola MPx220 Smartphone */ - { USB_DEVICE(0x22B8, 0x4234) }, /* Motorola MPc CDMA */ - { USB_DEVICE(0x22B8, 0x4244) }, /* Motorola MPx100 Smartphone */ - { USB_DEVICE(0x1231, 0xCE01) }, /* USB Sync 03 */ - { USB_DEVICE(0x1231, 0xCE02) }, /* USB Sync 03 */ + { USB_DEVICE(0x5E04, 0xCE00) }, /* SAGEM Wireless Assistant */ { } /* Terminating entry */ }; @@ -547,9 +551,12 @@ static struct usb_driver ipaq_driver = { /* All of the device info needed for the Compaq iPAQ */ -static struct usb_serial_device_type ipaq_device = { - .owner = THIS_MODULE, - .name = "PocketPC PDA", +static struct usb_serial_driver ipaq_device = { + .driver = { + .owner = THIS_MODULE, + .name = "ipaq", + }, + .description = "PocketPC PDA", .id_table = ipaq_id_table, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = 1, diff --git a/drivers/usb/serial/ipw.c b/drivers/usb/serial/ipw.c index 85e242459c27..a02fada85362 100644 --- a/drivers/usb/serial/ipw.c +++ b/drivers/usb/serial/ipw.c @@ -443,10 +443,12 @@ static int ipw_disconnect(struct usb_serial_port *port) return 0; } -static struct usb_serial_device_type ipw_device = { - .owner = THIS_MODULE, - .name = "IPWireless converter", - .short_name = "ipw", +static struct usb_serial_driver ipw_device = { + .driver = { + .owner = THIS_MODULE, + .name = "ipw", + }, + .description = "IPWireless converter", .id_table = usb_ipw_ids, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = 1, diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c index 937b2fdd7171..19f329e9bdcf 100644 --- a/drivers/usb/serial/ir-usb.c +++ b/drivers/usb/serial/ir-usb.c @@ -133,9 +133,12 @@ static struct usb_driver ir_driver = { }; -static struct usb_serial_device_type ir_device = { - .owner = THIS_MODULE, - .name = "IR Dongle", +static struct usb_serial_driver ir_device = { + .driver = { + .owner = THIS_MODULE, + .name = "ir-usb", + }, + .description = "IR Dongle", .id_table = id_table, .num_interrupt_in = 1, .num_bulk_in = 1, diff --git a/drivers/usb/serial/keyspan.h b/drivers/usb/serial/keyspan.h index e9b45b768aca..5cfc13b5e56f 100644 --- a/drivers/usb/serial/keyspan.h +++ b/drivers/usb/serial/keyspan.h @@ -570,10 +570,12 @@ static struct usb_device_id keyspan_4port_ids[] = { }; /* Structs for the devices, pre and post renumeration. */ -static struct usb_serial_device_type keyspan_pre_device = { - .owner = THIS_MODULE, - .name = "Keyspan - (without firmware)", - .short_name = "keyspan_no_firm", +static struct usb_serial_driver keyspan_pre_device = { + .driver = { + .owner = THIS_MODULE, + .name = "keyspan_no_firm", + }, + .description = "Keyspan - (without firmware)", .id_table = keyspan_pre_ids, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, @@ -582,10 +584,12 @@ static struct usb_serial_device_type keyspan_pre_device = { .attach = keyspan_fake_startup, }; -static struct usb_serial_device_type keyspan_1port_device = { - .owner = THIS_MODULE, - .name = "Keyspan 1 port adapter", - .short_name = "keyspan_1", +static struct usb_serial_driver keyspan_1port_device = { + .driver = { + .owner = THIS_MODULE, + .name = "keyspan_1", + }, + .description = "Keyspan 1 port adapter", .id_table = keyspan_1port_ids, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, @@ -607,10 +611,12 @@ static struct usb_serial_device_type keyspan_1port_device = { .shutdown = keyspan_shutdown, }; -static struct usb_serial_device_type keyspan_2port_device = { - .owner = THIS_MODULE, - .name = "Keyspan 2 port adapter", - .short_name = "keyspan_2", +static struct usb_serial_driver keyspan_2port_device = { + .driver = { + .owner = THIS_MODULE, + .name = "keyspan_2", + }, + .description = "Keyspan 2 port adapter", .id_table = keyspan_2port_ids, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, @@ -632,10 +638,12 @@ static struct usb_serial_device_type keyspan_2port_device = { .shutdown = keyspan_shutdown, }; -static struct usb_serial_device_type keyspan_4port_device = { - .owner = THIS_MODULE, - .name = "Keyspan 4 port adapter", - .short_name = "keyspan_4", +static struct usb_serial_driver keyspan_4port_device = { + .driver = { + .owner = THIS_MODULE, + .name = "keyspan_4", + }, + .description = "Keyspan 4 port adapter", .id_table = keyspan_4port_ids, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = 5, diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c index 635c384cb15a..cd4f48bd83b6 100644 --- a/drivers/usb/serial/keyspan_pda.c +++ b/drivers/usb/serial/keyspan_pda.c @@ -783,10 +783,12 @@ static void keyspan_pda_shutdown (struct usb_serial *serial) } #ifdef KEYSPAN -static struct usb_serial_device_type keyspan_pda_fake_device = { - .owner = THIS_MODULE, - .name = "Keyspan PDA - (prerenumeration)", - .short_name = "keyspan_pda_pre", +static struct usb_serial_driver keyspan_pda_fake_device = { + .driver = { + .owner = THIS_MODULE, + .name = "keyspan_pda_pre", + }, + .description = "Keyspan PDA - (prerenumeration)", .id_table = id_table_fake, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, @@ -797,10 +799,12 @@ static struct usb_serial_device_type keyspan_pda_fake_device = { #endif #ifdef XIRCOM -static struct usb_serial_device_type xircom_pgs_fake_device = { - .owner = THIS_MODULE, - .name = "Xircom / Entregra PGS - (prerenumeration)", - .short_name = "xircom_no_firm", +static struct usb_serial_driver xircom_pgs_fake_device = { + .driver = { + .owner = THIS_MODULE, + .name = "xircom_no_firm", + }, + .description = "Xircom / Entregra PGS - (prerenumeration)", .id_table = id_table_fake_xircom, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, @@ -810,10 +814,12 @@ static struct usb_serial_device_type xircom_pgs_fake_device = { }; #endif -static struct usb_serial_device_type keyspan_pda_device = { - .owner = THIS_MODULE, - .name = "Keyspan PDA", - .short_name = "keyspan_pda", +static struct usb_serial_driver keyspan_pda_device = { + .driver = { + .owner = THIS_MODULE, + .name = "keyspan_pda", + }, + .description = "Keyspan PDA", .id_table = id_table_std, .num_interrupt_in = 1, .num_bulk_in = 0, diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c index a11e829e38c8..a8951c0fd020 100644 --- a/drivers/usb/serial/kl5kusb105.c +++ b/drivers/usb/serial/kl5kusb105.c @@ -123,10 +123,12 @@ static struct usb_driver kl5kusb105d_driver = { .id_table = id_table, }; -static struct usb_serial_device_type kl5kusb105d_device = { - .owner = THIS_MODULE, - .name = "KL5KUSB105D / PalmConnect", - .short_name = "kl5kusb105d", +static struct usb_serial_driver kl5kusb105d_device = { + .driver = { + .owner = THIS_MODULE, + .name = "kl5kusb105d", + }, + .description = "KL5KUSB105D / PalmConnect", .id_table = id_table, .num_interrupt_in = 1, .num_bulk_in = 1, diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c index fe4c98a75171..9456dd9dd136 100644 --- a/drivers/usb/serial/kobil_sct.c +++ b/drivers/usb/serial/kobil_sct.c @@ -105,9 +105,12 @@ static struct usb_driver kobil_driver = { }; -static struct usb_serial_device_type kobil_device = { - .owner = THIS_MODULE, - .name = "KOBIL USB smart card terminal", +static struct usb_serial_driver kobil_device = { + .driver = { + .owner = THIS_MODULE, + .name = "kobil", + }, + .description = "KOBIL USB smart card terminal", .id_table = id_table, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = 0, diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c index 50b6369647d2..ca5dbadb9b7e 100644 --- a/drivers/usb/serial/mct_u232.c +++ b/drivers/usb/serial/mct_u232.c @@ -132,10 +132,12 @@ static struct usb_driver mct_u232_driver = { .id_table = id_table_combined, }; -static struct usb_serial_device_type mct_u232_device = { - .owner = THIS_MODULE, - .name = "MCT U232", - .short_name = "mct_u232", +static struct usb_serial_driver mct_u232_device = { + .driver = { + .owner = THIS_MODULE, + .name = "mct_u232", + }, + .description = "MCT U232", .id_table = id_table_combined, .num_interrupt_in = 2, .num_bulk_in = 0, diff --git a/drivers/usb/serial/nokia_dku2.c b/drivers/usb/serial/nokia_dku2.c new file mode 100644 index 000000000000..fad01bef3a64 --- /dev/null +++ b/drivers/usb/serial/nokia_dku2.c @@ -0,0 +1,142 @@ +/* + * Nokia DKU2 USB driver + * + * Copyright (C) 2004 + * Author: C Kemp + * + * This program is largely derived from work by the linux-usb group + * and associated source files. Please see the usb/serial files for + * individual credits and copyrights. + * + * 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. + * + * 20.09.2005 - Matthias Blaesing <matthias.blaesing@rwth-aachen.de> + * Added short name to device structure to make driver load into kernel 2.6.13 + * + * 20.09.2005 - Matthias Blaesing <matthias.blaesing@rwth-aachen.de> + * Added usb_deregister to exit code - to allow remove and reinsert of module + */ + + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/tty.h> +#include <linux/tty_driver.h> +#include <linux/tty_flip.h> +#include <linux/module.h> +#include <linux/usb.h> +#include "usb-serial.h" + + +#define NOKIA_VENDOR_ID 0x0421 +#define NOKIA7600_PRODUCT_ID 0x0400 +#define NOKIA6230_PRODUCT_ID 0x040f +#define NOKIA6170_PRODUCT_ID 0x0416 +#define NOKIA6670_PRODUCT_ID 0x041d +#define NOKIA6680_PRODUCT_ID 0x041e +#define NOKIA6230i_PRODUCT_ID 0x0428 + +#define NOKIA_AT_PORT 0x82 +#define NOKIA_FBUS_PORT 0x86 + +/* + * Version Information + */ +#define DRIVER_VERSION "v0.2" +#define DRIVER_AUTHOR "C Kemp" +#define DRIVER_DESC "Nokia DKU2 Driver" + +static struct usb_device_id id_table [] = { + { USB_DEVICE(NOKIA_VENDOR_ID, NOKIA7600_PRODUCT_ID) }, + { USB_DEVICE(NOKIA_VENDOR_ID, NOKIA6230_PRODUCT_ID) }, + { USB_DEVICE(NOKIA_VENDOR_ID, NOKIA6170_PRODUCT_ID) }, + { USB_DEVICE(NOKIA_VENDOR_ID, NOKIA6670_PRODUCT_ID) }, + { USB_DEVICE(NOKIA_VENDOR_ID, NOKIA6680_PRODUCT_ID) }, + { USB_DEVICE(NOKIA_VENDOR_ID, NOKIA6230i_PRODUCT_ID) }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(usb, id_table); + +/* The only thing which makes this device different from a generic + * device is that we have to set an alternative configuration to make + * the relevant endpoints available. In 2.6 this is really easy... */ +static int nokia_probe(struct usb_serial *serial, + const struct usb_device_id *id) +{ + int retval = -ENODEV; + + if (serial->interface->altsetting[0].endpoint[0].desc.bEndpointAddress == NOKIA_AT_PORT) { + /* the AT port */ + dev_info(&serial->dev->dev, "Nokia AT Port:\n"); + retval = 0; + } else if (serial->interface->num_altsetting == 2 && + serial->interface->altsetting[1].endpoint[0].desc.bEndpointAddress == NOKIA_FBUS_PORT) { + /* the FBUS port */ + dev_info(&serial->dev->dev, "Nokia FBUS Port:\n"); + usb_set_interface(serial->dev, 10, 1); + retval = 0; + } + + return retval; +} + +static struct usb_driver nokia_driver = { + .owner = THIS_MODULE, + .name = "nokia_dku2", + .probe = usb_serial_probe, + .disconnect = usb_serial_disconnect, + .id_table = id_table, +}; + +static struct usb_serial_driver nokia_serial_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "nokia_dku2", + }, + .description = "Nokia 7600/6230(i)/6170/66x0 DKU2 driver", + .id_table = id_table, + .num_interrupt_in = 1, + .num_bulk_in = 1, + .num_bulk_out = 1, + .num_ports = 1, + .probe = nokia_probe, +}; + +static int __init nokia_init(void) +{ + int retval; + + retval = usb_serial_register(&nokia_serial_driver); + if (retval) + return retval; + + retval = usb_register(&nokia_driver); + if (retval) { + usb_serial_deregister(&nokia_serial_driver); + return retval; + } + + info(DRIVER_VERSION " " DRIVER_AUTHOR); + info(DRIVER_DESC); + + return retval; +} + +static void __exit nokia_exit(void) +{ + usb_deregister(&nokia_driver); + usb_serial_deregister(&nokia_serial_driver); +} + +module_init(nokia_init); +module_exit(nokia_exit); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c index 6a99ae192df1..3caf97072ac0 100644 --- a/drivers/usb/serial/omninet.c +++ b/drivers/usb/serial/omninet.c @@ -88,10 +88,12 @@ static struct usb_driver omninet_driver = { }; -static struct usb_serial_device_type zyxel_omninet_device = { - .owner = THIS_MODULE, - .name = "ZyXEL - omni.net lcd plus usb", - .short_name = "omninet", +static struct usb_serial_driver zyxel_omninet_device = { + .driver = { + .owner = THIS_MODULE, + .name = "omninet", + }, + .description = "ZyXEL - omni.net lcd plus usb", .id_table = id_table, .num_interrupt_in = 1, .num_bulk_in = 1, diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 4989e5740d18..7716000045b7 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -105,10 +105,12 @@ static struct usb_driver option_driver = { /* The card has three separate interfaces, wich the serial driver * recognizes separately, thus num_port=1. */ -static struct usb_serial_device_type option_3port_device = { - .owner = THIS_MODULE, - .name = "Option 3G data card", - .short_name = "option", +static struct usb_serial_driver option_3port_device = { + .driver = { + .owner = THIS_MODULE, + .name = "option", + }, + .description = "Option 3G data card", .id_table = option_ids, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 3cf245bdda54..165c119bf10e 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -8,31 +8,10 @@ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * the Free Software Foundation; either version 2 of the License. * * See Documentation/usb/usb-serial.txt for more information on using this driver * - * 2002_Mar_26 gkh - * allowed driver to work properly if there is no tty assigned to a port - * (this happens for serial console devices.) - * - * 2001_Oct_06 gkh - * Added RTS and DTR line control. Thanks to joe@bndlg.de for parts of it. - * - * 2001_Sep_19 gkh - * Added break support. - * - * 2001_Aug_30 gkh - * fixed oops in write_bulk_callback. - * - * 2001_Aug_28 gkh - * reworked buffer logic to be like other usb-serial drivers. Hopefully - * removing some reported problems. - * - * 2001_Jun_06 gkh - * finished porting to 2.4 format. - * */ #include <linux/config.h> @@ -55,7 +34,6 @@ /* * Version Information */ -#define DRIVER_VERSION "v0.12" #define DRIVER_DESC "Prolific PL2303 USB to serial adaptor driver" static int debug; @@ -175,9 +153,11 @@ static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf, /* All of the device info needed for the PL2303 SIO serial converter */ -static struct usb_serial_device_type pl2303_device = { - .owner = THIS_MODULE, - .name = "PL-2303", +static struct usb_serial_driver pl2303_device = { + .driver = { + .owner = THIS_MODULE, + .name = "pl2303", + }, .id_table = id_table, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = 1, @@ -1195,7 +1175,7 @@ static int __init pl2303_init (void) retval = usb_register(&pl2303_driver); if (retval) goto failed_usb_register; - info(DRIVER_DESC " " DRIVER_VERSION); + info(DRIVER_DESC); return 0; failed_usb_register: usb_serial_deregister(&pl2303_device); @@ -1215,7 +1195,6 @@ module_init(pl2303_init); module_exit(pl2303_exit); MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_VERSION(DRIVER_VERSION); MODULE_LICENSE("GPL"); module_param(debug, bool, S_IRUGO | S_IWUSR); diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c index 96a17568cbf1..c22bdc0c4dfd 100644 --- a/drivers/usb/serial/safe_serial.c +++ b/drivers/usb/serial/safe_serial.c @@ -92,7 +92,7 @@ MODULE_DESCRIPTION (DRIVER_DESC); MODULE_LICENSE("GPL"); #if defined(CONFIG_USBD_SAFE_SERIAL_VENDOR) && !defined(CONFIG_USBD_SAFE_SERIAL_PRODUCT) -#abort "SAFE_SERIAL_VENDOR defined without SAFE_SERIAL_PRODUCT" +#error "SAFE_SERIAL_VENDOR defined without SAFE_SERIAL_PRODUCT" #endif #if ! defined(CONFIG_USBD_SAFE_SERIAL_VENDOR) @@ -397,9 +397,11 @@ static int safe_startup (struct usb_serial *serial) return 0; } -static struct usb_serial_device_type safe_device = { - .owner = THIS_MODULE, - .name = "Safe", +static struct usb_serial_driver safe_device = { + .driver = { + .owner = THIS_MODULE, + .name = "safe_serial", + }, .id_table = id_table, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index 59c88de3e7ae..205dbf7201da 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -255,9 +255,12 @@ static struct usb_driver ti_usb_driver = { .id_table = ti_id_table_combined, }; -static struct usb_serial_device_type ti_1port_device = { - .owner = THIS_MODULE, - .name = "TI USB 3410 1 port adapter", +static struct usb_serial_driver ti_1port_device = { + .driver = { + .owner = THIS_MODULE, + .name = "ti_usb_3410_5052_1", + }, + .description = "TI USB 3410 1 port adapter", .id_table = ti_id_table_3410, .num_interrupt_in = 1, .num_bulk_in = 1, @@ -282,9 +285,12 @@ static struct usb_serial_device_type ti_1port_device = { .write_bulk_callback = ti_bulk_out_callback, }; -static struct usb_serial_device_type ti_2port_device = { - .owner = THIS_MODULE, - .name = "TI USB 5052 2 port adapter", +static struct usb_serial_driver ti_2port_device = { + .driver = { + .owner = THIS_MODULE, + .name = "ti_usb_3410_5052_2", + }, + .description = "TI USB 5052 2 port adapter", .id_table = ti_id_table_5052, .num_interrupt_in = 1, .num_bulk_in = 2, diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index e77fbdfc782d..0c4881d18cd5 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -1,7 +1,7 @@ /* * USB Serial Converter driver * - * Copyright (C) 1999 - 2004 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (C) 1999 - 2005 Greg Kroah-Hartman (greg@kroah.com) * Copyright (C) 2000 Peter Berger (pberger@brimson.com) * Copyright (C) 2000 Al Borchers (borchers@steinerpoint.com) * @@ -9,316 +9,11 @@ * modify it under the terms of the GNU General Public License version * 2 as published by the Free Software Foundation. * - * This driver was originally based on the ACM driver by Armin Fuerst (which was + * This driver was originally based on the ACM driver by Armin Fuerst (which was * based on a driver by Brad Keryan) * * See Documentation/usb/usb-serial.txt for more information on using this driver * - * (12/10/2002) gkh - * Split the ports off into their own struct device, and added a - * usb-serial bus driver. - * - * (11/19/2002) gkh - * removed a few #ifdefs for the generic code and cleaned up the failure - * logic in initialization. - * - * (10/02/2002) gkh - * moved the console code to console.c and out of this file. - * - * (06/05/2002) gkh - * moved location of startup() call in serial_probe() until after all - * of the port information and endpoints are initialized. This makes - * things easier for some drivers. - * - * (04/10/2002) gkh - * added serial_read_proc function which creates a - * /proc/tty/driver/usb-serial file. - * - * (03/27/2002) gkh - * Got USB serial console code working properly and merged into the main - * version of the tree. Thanks to Randy Dunlap for the initial version - * of this code, and for pushing me to finish it up. - * The USB serial console works with any usb serial driver device. - * - * (03/21/2002) gkh - * Moved all manipulation of port->open_count into the core. Now the - * individual driver's open and close functions are called only when the - * first open() and last close() is called. Making the drivers a bit - * smaller and simpler. - * Fixed a bug if a driver didn't have the owner field set. - * - * (02/26/2002) gkh - * Moved all locking into the main serial_* functions, instead of having - * the individual drivers have to grab the port semaphore. This should - * reduce races. - * Reworked the MOD_INC logic a bit to always increment and decrement, even - * if the generic driver is being used. - * - * (10/10/2001) gkh - * usb_serial_disconnect() now sets the serial->dev pointer is to NULL to - * help prevent child drivers from accessing the device since it is now - * gone. - * - * (09/13/2001) gkh - * Moved generic driver initialize after we have registered with the USB - * core. Thanks to Randy Dunlap for pointing this problem out. - * - * (07/03/2001) gkh - * Fixed module paramater size. Thanks to John Brockmeyer for the pointer. - * Fixed vendor and product getting defined through the MODULE_PARM macro - * if the Generic driver wasn't compiled in. - * Fixed problem with generic_shutdown() not being called for drivers that - * don't have a shutdown() function. - * - * (06/06/2001) gkh - * added evil hack that is needed for the prolific pl2303 device due to the - * crazy way its endpoints are set up. - * - * (05/30/2001) gkh - * switched from using spinlock to a semaphore, which fixes lots of problems. - * - * (04/08/2001) gb - * Identify version on module load. - * - * 2001_02_05 gkh - * Fixed buffer overflows bug with the generic serial driver. Thanks to - * Todd Squires <squirest@ct0.com> for fixing this. - * - * (01/10/2001) gkh - * Fixed bug where the generic serial adaptor grabbed _any_ device that was - * offered to it. - * - * (12/12/2000) gkh - * Removed MOD_INC and MOD_DEC from poll and disconnect functions, and - * moved them to the serial_open and serial_close functions. - * Also fixed bug with there not being a MOD_DEC for the generic driver - * (thanks to Gary Brubaker for finding this.) - * - * (11/29/2000) gkh - * Small NULL pointer initialization cleanup which saves a bit of disk image - * - * (11/01/2000) Adam J. Richter - * instead of using idVendor/idProduct pairs, usb serial drivers - * now identify their hardware interest with usb_device_id tables, - * which they usually have anyhow for use with MODULE_DEVICE_TABLE. - * - * (10/05/2000) gkh - * Fixed bug with urb->dev not being set properly, now that the usb - * core needs it. - * - * (09/11/2000) gkh - * Removed DEBUG #ifdefs with call to usb_serial_debug_data - * - * (08/28/2000) gkh - * Added port_lock to port structure. - * Added locks for SMP safeness to generic driver - * Fixed the ability to open a generic device's port more than once. - * - * (07/23/2000) gkh - * Added bulk_out_endpointAddress to port structure. - * - * (07/19/2000) gkh, pberger, and borchers - * Modifications to allow usb-serial drivers to be modules. - * - * (07/03/2000) gkh - * Added more debugging to serial_ioctl call - * - * (06/25/2000) gkh - * Changed generic_write_bulk_callback to not call wake_up_interruptible - * directly, but to have port_softint do it at a safer time. - * - * (06/23/2000) gkh - * Cleaned up debugging statements in a quest to find UHCI timeout bug. - * - * (05/22/2000) gkh - * Changed the makefile, enabling the big CONFIG_USB_SERIAL_SOMTHING to be - * removed from the individual device source files. - * - * (05/03/2000) gkh - * Added the Digi Acceleport driver from Al Borchers and Peter Berger. - * - * (05/02/2000) gkh - * Changed devfs and tty register code to work properly now. This was based on - * the ACM driver changes by Vojtech Pavlik. - * - * (04/27/2000) Ryan VanderBijl - * Put calls to *_paranoia_checks into one function. - * - * (04/23/2000) gkh - * Fixed bug that Randy Dunlap found for Generic devices with no bulk out ports. - * Moved when the startup code printed out the devices that are supported. - * - * (04/19/2000) gkh - * Added driver for ZyXEL omni.net lcd plus ISDN TA - * Made startup info message specify which drivers were compiled in. - * - * (04/03/2000) gkh - * Changed the probe process to remove the module unload races. - * Changed where the tty layer gets initialized to have devfs work nicer. - * Added initial devfs support. - * - * (03/26/2000) gkh - * Split driver up into device specific pieces. - * - * (03/19/2000) gkh - * Fixed oops that could happen when device was removed while a program - * was talking to the device. - * Removed the static urbs and now all urbs are created and destroyed - * dynamically. - * Reworked the internal interface. Now everything is based on the - * usb_serial_port structure instead of the larger usb_serial structure. - * This fixes the bug that a multiport device could not have more than - * one port open at one time. - * - * (03/17/2000) gkh - * Added config option for debugging messages. - * Added patch for keyspan pda from Brian Warner. - * - * (03/06/2000) gkh - * Added the keyspan pda code from Brian Warner <warner@lothar.com> - * Moved a bunch of the port specific stuff into its own structure. This - * is in anticipation of the true multiport devices (there's a bug if you - * try to access more than one port of any multiport device right now) - * - * (02/21/2000) gkh - * Made it so that any serial devices only have to specify which functions - * they want to overload from the generic function calls (great, - * inheritance in C, in a driver, just what I wanted...) - * Added support for set_termios and ioctl function calls. No drivers take - * advantage of this yet. - * Removed the #ifdef MODULE, now there is no module specific code. - * Cleaned up a few comments in usb-serial.h that were wrong (thanks again - * to Miles Lott). - * Small fix to get_free_serial. - * - * (02/14/2000) gkh - * Removed the Belkin and Peracom functionality from the driver due to - * the lack of support from the vendor, and me not wanting people to - * accidenatly buy the device, expecting it to work with Linux. - * Added read_bulk_callback and write_bulk_callback to the type structure - * for the needs of the FTDI and WhiteHEAT driver. - * Changed all reverences to FTDI to FTDI_SIO at the request of Bill - * Ryder. - * Changed the output urb size back to the max endpoint size to make - * the ftdi_sio driver have it easier, and due to the fact that it didn't - * really increase the speed any. - * - * (02/11/2000) gkh - * Added VISOR_FUNCTION_CONSOLE to the visor startup function. This was a - * patch from Miles Lott (milos@insync.net). - * Fixed bug with not restoring the minor range that a device grabs, if - * the startup function fails (thanks Miles for finding this). - * - * (02/05/2000) gkh - * Added initial framework for the Keyspan PDA serial converter so that - * Brian Warner has a place to put his code. - * Made the ezusb specific functions generic enough that different - * devices can use them (whiteheat and keyspan_pda both need them). - * Split out a whole bunch of structure and other stuff to a separate - * usb-serial.h file. - * Made the Visor connection messages a little more understandable, now - * that Miles Lott (milos@insync.net) has gotten the Generic channel to - * work. Also made them always show up in the log file. - * - * (01/25/2000) gkh - * Added initial framework for FTDI serial converter so that Bill Ryder - * has a place to put his code. - * Added the vendor specific info from Handspring. Now we can print out - * informational debug messages as well as understand what is happening. - * - * (01/23/2000) gkh - * Fixed problem of crash when trying to open a port that didn't have a - * device assigned to it. Made the minor node finding a little smarter, - * now it looks to find a continuous space for the new device. - * - * (01/21/2000) gkh - * Fixed bug in visor_startup with patch from Miles Lott (milos@insync.net) - * Fixed get_serial_by_minor which was all messed up for multi port - * devices. Fixed multi port problem for generic devices. Now the number - * of ports is determined by the number of bulk out endpoints for the - * generic device. - * - * (01/19/2000) gkh - * Removed lots of cruft that was around from the old (pre urb) driver - * interface. - * Made the serial_table dynamic. This should save lots of memory when - * the number of minor nodes goes up to 256. - * Added initial support for devices that have more than one port. - * Added more debugging comments for the Visor, and added a needed - * set_configuration call. - * - * (01/17/2000) gkh - * Fixed the WhiteHEAT firmware (my processing tool had a bug) - * and added new debug loader firmware for it. - * Removed the put_char function as it isn't really needed. - * Added visor startup commands as found by the Win98 dump. - * - * (01/13/2000) gkh - * Fixed the vendor id for the generic driver to the one I meant it to be. - * - * (01/12/2000) gkh - * Forget the version numbering...that's pretty useless... - * Made the driver able to be compiled so that the user can select which - * converter they want to use. This allows people who only want the Visor - * support to not pay the memory size price of the WhiteHEAT. - * Fixed bug where the generic driver (idVendor=0000 and idProduct=0000) - * grabbed the root hub. Not good. - * - * version 0.4.0 (01/10/2000) gkh - * Added whiteheat.h containing the firmware for the ConnectTech WhiteHEAT - * device. Added startup function to allow firmware to be downloaded to - * a device if it needs to be. - * Added firmware download logic to the WhiteHEAT device. - * Started to add #defines to split up the different drivers for potential - * configuration option. - * - * version 0.3.1 (12/30/99) gkh - * Fixed problems with urb for bulk out. - * Added initial support for multiple sets of endpoints. This enables - * the Handspring Visor to be attached successfully. Only the first - * bulk in / bulk out endpoint pair is being used right now. - * - * version 0.3.0 (12/27/99) gkh - * Added initial support for the Handspring Visor based on a patch from - * Miles Lott (milos@sneety.insync.net) - * Cleaned up the code a bunch and converted over to using urbs only. - * - * version 0.2.3 (12/21/99) gkh - * Added initial support for the Connect Tech WhiteHEAT converter. - * Incremented the number of ports in expectation of getting the - * WhiteHEAT to work properly (4 ports per connection). - * Added notification on insertion and removal of what port the - * device is/was connected to (and what kind of device it was). - * - * version 0.2.2 (12/16/99) gkh - * Changed major number to the new allocated number. We're legal now! - * - * version 0.2.1 (12/14/99) gkh - * Fixed bug that happens when device node is opened when there isn't a - * device attached to it. Thanks to marek@webdesign.no for noticing this. - * - * version 0.2.0 (11/10/99) gkh - * Split up internals to make it easier to add different types of serial - * converters to the code. - * Added a "generic" driver that gets it's vendor and product id - * from when the module is loaded. Thanks to David E. Nelson (dnelson@jump.net) - * for the idea and sample code (from the usb scanner driver.) - * Cleared up any licensing questions by releasing it under the GNU GPL. - * - * version 0.1.2 (10/25/99) gkh - * Fixed bug in detecting device. - * - * version 0.1.1 (10/05/99) gkh - * Changed the major number to not conflict with anything else. - * - * version 0.1 (09/28/99) gkh - * Can recognize the two different devices and start up a read from - * device when asked to. Writes also work. No control signals yet, this - * all is vendor specific data (i.e. no spec), also no control for - * different baud rates or other bit settings. - * Currently we are using the same devid as the acm driver. This needs - * to change. - * */ #include <linux/config.h> @@ -342,7 +37,6 @@ /* * Version Information */ -#define DRIVER_VERSION "v2.0" #define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux/" #define DRIVER_DESC "USB Serial Driver core" @@ -427,7 +121,7 @@ static void destroy_serial(struct kref *kref) serial = to_usb_serial(kref); - dbg ("%s - %s", __FUNCTION__, serial->type->name); + dbg("%s - %s", __FUNCTION__, serial->type->description); serial->type->shutdown(serial); @@ -507,7 +201,7 @@ static int serial_open (struct tty_struct *tty, struct file * filp) /* lock this module before we call it * this may fail, which means we must bail out, * safe because we are called with BKL held */ - if (!try_module_get(serial->type->owner)) { + if (!try_module_get(serial->type->driver.owner)) { retval = -ENODEV; goto bailout_kref_put; } @@ -522,7 +216,7 @@ static int serial_open (struct tty_struct *tty, struct file * filp) return 0; bailout_module_put: - module_put(serial->type->owner); + module_put(serial->type->driver.owner); bailout_kref_put: kref_put(&serial->kref, destroy_serial); port->open_count = 0; @@ -553,7 +247,7 @@ static void serial_close(struct tty_struct *tty, struct file * filp) port->tty = NULL; } - module_put(port->serial->type->owner); + module_put(port->serial->type->driver.owner); } kref_put(&port->serial->kref, destroy_serial); @@ -711,16 +405,16 @@ static int serial_read_proc (char *page, char **start, off_t off, int count, int char tmp[40]; dbg("%s", __FUNCTION__); - length += sprintf (page, "usbserinfo:1.0 driver:%s\n", DRIVER_VERSION); + length += sprintf (page, "usbserinfo:1.0 driver:2.0\n"); for (i = 0; i < SERIAL_TTY_MINORS && length < PAGE_SIZE; ++i) { serial = usb_serial_get_by_index(i); if (serial == NULL) continue; length += sprintf (page+length, "%d:", i); - if (serial->type->owner) - length += sprintf (page+length, " module:%s", module_name(serial->type->owner)); - length += sprintf (page+length, " name:\"%s\"", serial->type->name); + if (serial->type->driver.owner) + length += sprintf (page+length, " module:%s", module_name(serial->type->driver.owner)); + length += sprintf (page+length, " name:\"%s\"", serial->type->description); length += sprintf (page+length, " vendor:%04x product:%04x", le16_to_cpu(serial->dev->descriptor.idVendor), le16_to_cpu(serial->dev->descriptor.idProduct)); @@ -823,7 +517,7 @@ static void port_release(struct device *dev) static struct usb_serial * create_serial (struct usb_device *dev, struct usb_interface *interface, - struct usb_serial_device_type *type) + struct usb_serial_driver *driver) { struct usb_serial *serial; @@ -834,22 +528,22 @@ static struct usb_serial * create_serial (struct usb_device *dev, } memset (serial, 0, sizeof(*serial)); serial->dev = usb_get_dev(dev); - serial->type = type; + serial->type = driver; serial->interface = interface; kref_init(&serial->kref); return serial; } -static struct usb_serial_device_type *search_serial_device(struct usb_interface *iface) +static struct usb_serial_driver *search_serial_device(struct usb_interface *iface) { struct list_head *p; const struct usb_device_id *id; - struct usb_serial_device_type *t; + struct usb_serial_driver *t; /* List trough know devices and see if the usb id matches */ list_for_each(p, &usb_serial_driver_list) { - t = list_entry(p, struct usb_serial_device_type, driver_list); + t = list_entry(p, struct usb_serial_driver, driver_list); id = usb_match_id(iface, t->id_table); if (id != NULL) { dbg("descriptor matches"); @@ -872,7 +566,7 @@ int usb_serial_probe(struct usb_interface *interface, struct usb_endpoint_descriptor *interrupt_out_endpoint[MAX_NUM_PORTS]; struct usb_endpoint_descriptor *bulk_in_endpoint[MAX_NUM_PORTS]; struct usb_endpoint_descriptor *bulk_out_endpoint[MAX_NUM_PORTS]; - struct usb_serial_device_type *type = NULL; + struct usb_serial_driver *type = NULL; int retval; int minor; int buffer_size; @@ -900,7 +594,7 @@ int usb_serial_probe(struct usb_interface *interface, if (type->probe) { const struct usb_device_id *id; - if (!try_module_get(type->owner)) { + if (!try_module_get(type->driver.owner)) { dev_err(&interface->dev, "module get failed, exiting\n"); kfree (serial); return -EIO; @@ -908,7 +602,7 @@ int usb_serial_probe(struct usb_interface *interface, id = usb_match_id(interface, type->id_table); retval = type->probe(serial, id); - module_put(type->owner); + module_put(type->driver.owner); if (retval) { dbg ("sub driver rejected device"); @@ -992,7 +686,7 @@ int usb_serial_probe(struct usb_interface *interface, #endif /* found all that we need */ - dev_info(&interface->dev, "%s converter detected\n", type->name); + dev_info(&interface->dev, "%s converter detected\n", type->description); #ifdef CONFIG_USB_SERIAL_GENERIC if (type == &usb_serial_generic_device) { @@ -1007,13 +701,13 @@ int usb_serial_probe(struct usb_interface *interface, if (!num_ports) { /* if this device type has a calc_num_ports function, call it */ if (type->calc_num_ports) { - if (!try_module_get(type->owner)) { + if (!try_module_get(type->driver.owner)) { dev_err(&interface->dev, "module get failed, exiting\n"); kfree (serial); return -EIO; } num_ports = type->calc_num_ports (serial); - module_put(type->owner); + module_put(type->driver.owner); } if (!num_ports) num_ports = type->num_ports; @@ -1158,12 +852,12 @@ int usb_serial_probe(struct usb_interface *interface, /* if this device type has an attach function, call it */ if (type->attach) { - if (!try_module_get(type->owner)) { + if (!try_module_get(type->driver.owner)) { dev_err(&interface->dev, "module get failed, exiting\n"); goto probe_error; } retval = type->attach (serial); - module_put(type->owner); + module_put(type->driver.owner); if (retval < 0) goto probe_error; if (retval > 0) { @@ -1330,7 +1024,7 @@ static int __init usb_serial_init(void) goto exit_generic; } - info(DRIVER_DESC " " DRIVER_VERSION); + info(DRIVER_DESC); return result; @@ -1375,7 +1069,7 @@ module_exit(usb_serial_exit); } \ } while (0) -static void fixup_generic(struct usb_serial_device_type *device) +static void fixup_generic(struct usb_serial_driver *device) { set_to_generic_if_null(device, open); set_to_generic_if_null(device, write); @@ -1387,30 +1081,33 @@ static void fixup_generic(struct usb_serial_device_type *device) set_to_generic_if_null(device, shutdown); } -int usb_serial_register(struct usb_serial_device_type *new_device) +int usb_serial_register(struct usb_serial_driver *driver) { int retval; - fixup_generic(new_device); + fixup_generic(driver); + + if (!driver->description) + driver->description = driver->driver.name; /* Add this device to our list of devices */ - list_add(&new_device->driver_list, &usb_serial_driver_list); + list_add(&driver->driver_list, &usb_serial_driver_list); - retval = usb_serial_bus_register(new_device); + retval = usb_serial_bus_register(driver); if (retval) { - err("problem %d when registering driver %s", retval, new_device->name); - list_del(&new_device->driver_list); + err("problem %d when registering driver %s", retval, driver->description); + list_del(&driver->driver_list); } else - info("USB Serial support registered for %s", new_device->name); + info("USB Serial support registered for %s", driver->description); return retval; } -void usb_serial_deregister(struct usb_serial_device_type *device) +void usb_serial_deregister(struct usb_serial_driver *device) { - info("USB Serial deregistering driver %s", device->name); + info("USB Serial deregistering driver %s", device->description); list_del(&device->driver_list); usb_serial_bus_deregister(device); } @@ -1429,7 +1126,6 @@ EXPORT_SYMBOL_GPL(usb_serial_port_softint); /* Module information */ MODULE_AUTHOR( DRIVER_AUTHOR ); MODULE_DESCRIPTION( DRIVER_DESC ); -MODULE_VERSION( DRIVER_VERSION ); MODULE_LICENSE("GPL"); module_param(debug, bool, S_IRUGO | S_IWUSR); diff --git a/drivers/usb/serial/usb-serial.h b/drivers/usb/serial/usb-serial.h index 57f92f054c75..238a5a871ed6 100644 --- a/drivers/usb/serial/usb-serial.h +++ b/drivers/usb/serial/usb-serial.h @@ -1,53 +1,13 @@ /* * USB Serial Converter driver * - * Copyright (C) 1999 - 2004 + * Copyright (C) 1999 - 2005 * Greg Kroah-Hartman (greg@kroah.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * the Free Software Foundation; either version 2 of the License. * - * See Documentation/usb/usb-serial.txt for more information on using this driver - * - * (03/26/2002) gkh - * removed the port->tty check from port_paranoia_check() due to serial - * consoles not having a tty device assigned to them. - * - * (12/03/2001) gkh - * removed active from the port structure. - * added documentation to the usb_serial_device_type structure - * - * (10/10/2001) gkh - * added vendor and product to serial structure. Needed to determine device - * owner when the device is disconnected. - * - * (05/30/2001) gkh - * added sem to port structure and removed port_lock - * - * (10/05/2000) gkh - * Added interrupt_in_endpointAddress and bulk_in_endpointAddress to help - * fix bug with urb->dev not being set properly, now that the usb core - * needs it. - * - * (09/11/2000) gkh - * Added usb_serial_debug_data function to help get rid of #DEBUG in the - * drivers. - * - * (08/28/2000) gkh - * Added port_lock to port structure. - * - * (08/08/2000) gkh - * Added open_count to port structure. - * - * (07/23/2000) gkh - * Added bulk_out_endpointAddress to port structure. - * - * (07/19/2000) gkh, pberger, and borchers - * Modifications to allow usb-serial drivers to be modules. - * - * */ @@ -143,7 +103,7 @@ static inline void usb_set_serial_port_data (struct usb_serial_port *port, void /** * usb_serial - structure used by the usb-serial core for a device * @dev: pointer to the struct usb_device for this device - * @type: pointer to the struct usb_serial_device_type for this device + * @type: pointer to the struct usb_serial_driver for this device * @interface: pointer to the struct usb_interface for this device * @minor: the starting minor number for this device * @num_ports: the number of ports this device has @@ -159,7 +119,7 @@ static inline void usb_set_serial_port_data (struct usb_serial_port *port, void */ struct usb_serial { struct usb_device * dev; - struct usb_serial_device_type * type; + struct usb_serial_driver * type; struct usb_interface * interface; unsigned char minor; unsigned char num_ports; @@ -188,13 +148,9 @@ static inline void usb_set_serial_data (struct usb_serial *serial, void *data) } /** - * usb_serial_device_type - a structure that defines a usb serial device - * @owner: pointer to the module that owns this device. - * @name: pointer to a string that describes this device. This string used + * usb_serial_driver - describes a usb serial driver + * @description: pointer to a string that describes this driver. This string used * in the syslog messages when a device is inserted or removed. - * @short_name: a pointer to a string that describes this device in - * KOBJ_NAME_LEN characters or less. This is used for the sysfs interface - * to describe the driver. * @id_table: pointer to a list of usb_device_id structures that define all * of the devices this structure can support. * @num_interrupt_in: the number of interrupt in endpoints this device will @@ -221,16 +177,19 @@ static inline void usb_set_serial_data (struct usb_serial *serial, void *data) * @shutdown: pointer to the driver's shutdown function. This will be * called when the device is removed from the system. * - * This structure is defines a USB Serial device. It provides all of + * This structure is defines a USB Serial driver. It provides all of * the information that the USB serial core code needs. If the function * pointers are defined, then the USB serial core code will call them when * the corresponding tty port functions are called. If they are not * called, the generic serial function will be used instead. + * + * The driver.owner field should be set to the module owner of this driver. + * The driver.name field should be set to the name of this driver (remember + * it will show up in sysfs, so it needs to be short and to the point. + * Useing the module name is a good idea.) */ -struct usb_serial_device_type { - struct module *owner; - char *name; - char *short_name; +struct usb_serial_driver { + const char *description; const struct usb_device_id *id_table; char num_interrupt_in; char num_interrupt_out; @@ -269,10 +228,10 @@ struct usb_serial_device_type { void (*read_bulk_callback)(struct urb *urb, struct pt_regs *regs); void (*write_bulk_callback)(struct urb *urb, struct pt_regs *regs); }; -#define to_usb_serial_driver(d) container_of(d, struct usb_serial_device_type, driver) +#define to_usb_serial_driver(d) container_of(d, struct usb_serial_driver, driver) -extern int usb_serial_register(struct usb_serial_device_type *new_device); -extern void usb_serial_deregister(struct usb_serial_device_type *device); +extern int usb_serial_register(struct usb_serial_driver *driver); +extern void usb_serial_deregister(struct usb_serial_driver *driver); extern void usb_serial_port_softint(void *private); extern int usb_serial_probe(struct usb_interface *iface, const struct usb_device_id *id); @@ -303,10 +262,10 @@ extern void usb_serial_generic_shutdown (struct usb_serial *serial); extern int usb_serial_generic_register (int debug); extern void usb_serial_generic_deregister (void); -extern int usb_serial_bus_register (struct usb_serial_device_type *device); -extern void usb_serial_bus_deregister (struct usb_serial_device_type *device); +extern int usb_serial_bus_register (struct usb_serial_driver *device); +extern void usb_serial_bus_deregister (struct usb_serial_driver *device); -extern struct usb_serial_device_type usb_serial_generic_device; +extern struct usb_serial_driver usb_serial_generic_device; extern struct bus_type usb_serial_bus_type; extern struct tty_driver *usb_serial_tty_driver; diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index 31c57adcb623..a473c1c34559 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -7,139 +7,10 @@ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * the Free Software Foundation; either version 2 of the License. * * See Documentation/usb/usb-serial.txt for more information on using this driver * - * (06/03/2003) Judd Montgomery <judd at jpilot.org> - * Added support for module parameter options for untested/unknown - * devices. - * - * (03/09/2003) gkh - * Added support for the Sony Clie NZ90V device. Thanks to Martin Brachtl - * <brachtl@redgrep.cz> for the information. - * - * (03/05/2003) gkh - * Think Treo support is now working. - * - * (04/03/2002) gkh - * Added support for the Sony OS 4.1 devices. Thanks to Hiroyuki ARAKI - * <hiro@zob.ne.jp> for the information. - * - * (03/27/2002) gkh - * Removed assumptions that port->tty was always valid (is not true - * for usb serial console devices.) - * - * (03/23/2002) gkh - * Added support for the Palm i705 device, thanks to Thomas Riemer - * <tom@netmech.com> for the information. - * - * (03/21/2002) gkh - * Added support for the Palm m130 device, thanks to Udo Eisenbarth - * <udo.eisenbarth@web.de> for the information. - * - * (02/27/2002) gkh - * Reworked the urb handling logic. We have no more pool, but dynamically - * allocate the urb and the transfer buffer on the fly. In testing this - * does not incure any measurable overhead. This also relies on the fact - * that we have proper reference counting logic for urbs. - * - * (02/21/2002) SilaS - * Added initial support for the Palm m515 devices. - * - * (02/14/2002) gkh - * Added support for the Clie S-360 device. - * - * (12/18/2001) gkh - * Added better Clie support for 3.5 devices. Thanks to Geoffrey Levand - * for the patch. - * - * (11/11/2001) gkh - * Added support for the m125 devices, and added check to prevent oopses - * for Cli devices that lie about the number of ports they have. - * - * (08/30/2001) gkh - * Added support for the Clie devices, both the 3.5 and 4.0 os versions. - * Many thanks to Daniel Burke, and Bryan Payne for helping with this. - * - * (08/23/2001) gkh - * fixed a few potential bugs pointed out by Oliver Neukum. - * - * (05/30/2001) gkh - * switched from using spinlock to a semaphore, which fixes lots of problems. - * - * (05/28/2000) gkh - * Added initial support for the Palm m500 and Palm m505 devices. - * - * (04/08/2001) gb - * Identify version on module load. - * - * (01/21/2000) gkh - * Added write_room and chars_in_buffer, as they were previously using the - * generic driver versions which is all wrong now that we are using an urb - * pool. Thanks to Wolfgang Grandegger for pointing this out to me. - * Removed count assignment in the write function, which was not needed anymore - * either. Thanks to Al Borchers for pointing this out. - * - * (12/12/2000) gkh - * Moved MOD_DEC to end of visor_close to be nicer, as the final write - * message can sleep. - * - * (11/12/2000) gkh - * Fixed bug with data being dropped on the floor by forcing tty->low_latency - * to be on. Hopefully this fixes the OHCI issue! - * - * (11/01/2000) Adam J. Richter - * usb_device_id table support - * - * (10/05/2000) gkh - * Fixed bug with urb->dev not being set properly, now that the usb - * core needs it. - * - * (09/11/2000) gkh - * Got rid of always calling kmalloc for every urb we wrote out to the - * device. - * Added visor_read_callback so we can keep track of bytes in and out for - * those people who like to know the speed of their device. - * Removed DEBUG #ifdefs with call to usb_serial_debug_data - * - * (09/06/2000) gkh - * Fixed oops in visor_exit. Need to uncomment usb_unlink_urb call _after_ - * the host controller drivers set urb->dev = NULL when the urb is finished. - * - * (08/28/2000) gkh - * Added locks for SMP safeness. - * - * (08/08/2000) gkh - * Fixed endian problem in visor_startup. - * Fixed MOD_INC and MOD_DEC logic and the ability to open a port more - * than once. - * - * (07/23/2000) gkh - * Added pool of write urbs to speed up transfers to the visor. - * - * (07/19/2000) gkh - * Added module_init and module_exit functions to handle the fact that this - * driver is a loadable module now. - * - * (07/03/2000) gkh - * Added visor_set_ioctl and visor_set_termios functions (they don't do much - * of anything, but are good for debugging.) - * - * (06/25/2000) gkh - * Fixed bug in visor_unthrottle that should help with the disconnect in PPP - * bug that people have been reporting. - * - * (06/23/2000) gkh - * Cleaned up debugging statements in a quest to find UHCI timeout bug. - * - * (04/27/2000) Ryan VanderBijl - * Fixed memory leak in visor_close - * - * (03/26/2000) gkh - * Split driver up into device specific pieces. - * */ #include <linux/config.h> @@ -161,7 +32,6 @@ /* * Version Information */ -#define DRIVER_VERSION "v2.1" #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>" #define DRIVER_DESC "USB HandSpring Visor / Palm OS driver" @@ -311,10 +181,12 @@ static struct usb_driver visor_driver = { }; /* All of the device info needed for the Handspring Visor, and Palm 4.0 devices */ -static struct usb_serial_device_type handspring_device = { - .owner = THIS_MODULE, - .name = "Handspring Visor / Palm OS", - .short_name = "visor", +static struct usb_serial_driver handspring_device = { + .driver = { + .owner = THIS_MODULE, + .name = "visor", + }, + .description = "Handspring Visor / Palm OS", .id_table = id_table, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = 2, @@ -339,10 +211,12 @@ static struct usb_serial_device_type handspring_device = { }; /* All of the device info needed for the Clie UX50, TH55 Palm 5.0 devices */ -static struct usb_serial_device_type clie_5_device = { - .owner = THIS_MODULE, - .name = "Sony Clie 5.0", - .short_name = "clie_5", +static struct usb_serial_driver clie_5_device = { + .driver = { + .owner = THIS_MODULE, + .name = "clie_5", + }, + .description = "Sony Clie 5.0", .id_table = clie_id_5_table, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = 2, @@ -367,10 +241,12 @@ static struct usb_serial_device_type clie_5_device = { }; /* device info for the Sony Clie OS version 3.5 */ -static struct usb_serial_device_type clie_3_5_device = { - .owner = THIS_MODULE, - .name = "Sony Clie 3.5", - .short_name = "clie_3.5", +static struct usb_serial_driver clie_3_5_device = { + .driver = { + .owner = THIS_MODULE, + .name = "clie_3.5", + }, + .description = "Sony Clie 3.5", .id_table = clie_id_3_5_table, .num_interrupt_in = 0, .num_bulk_in = 1, @@ -782,7 +658,7 @@ static int palm_os_3_probe (struct usb_serial *serial, const struct usb_device_i break; } dev_info(dev, "%s: port %d, is for %s use\n", - serial->type->name, + serial->type->description, connection_info->connections[i].port, string); } } @@ -791,11 +667,11 @@ static int palm_os_3_probe (struct usb_serial *serial, const struct usb_device_i */ if (num_ports == 0 || num_ports > 2) { dev_warn (dev, "%s: No valid connect info available\n", - serial->type->name); + serial->type->description); num_ports = 2; } - dev_info(dev, "%s: Number of ports: %d\n", serial->type->name, + dev_info(dev, "%s: Number of ports: %d\n", serial->type->description, num_ports); /* @@ -1125,7 +1001,7 @@ static int __init visor_init (void) retval = usb_register(&visor_driver); if (retval) goto failed_usb_register; - info(DRIVER_DESC " " DRIVER_VERSION); + info(DRIVER_DESC); return 0; failed_usb_register: diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index cf3bc30675a1..18c3183be769 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c @@ -156,10 +156,12 @@ static void whiteheat_unthrottle (struct usb_serial_port *port); static void whiteheat_read_callback (struct urb *urb, struct pt_regs *regs); static void whiteheat_write_callback (struct urb *urb, struct pt_regs *regs); -static struct usb_serial_device_type whiteheat_fake_device = { - .owner = THIS_MODULE, - .name = "Connect Tech - WhiteHEAT - (prerenumeration)", - .short_name = "whiteheatnofirm", +static struct usb_serial_driver whiteheat_fake_device = { + .driver = { + .owner = THIS_MODULE, + .name = "whiteheatnofirm", + }, + .description = "Connect Tech - WhiteHEAT - (prerenumeration)", .id_table = id_table_prerenumeration, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, @@ -169,10 +171,12 @@ static struct usb_serial_device_type whiteheat_fake_device = { .attach = whiteheat_firmware_attach, }; -static struct usb_serial_device_type whiteheat_device = { - .owner = THIS_MODULE, - .name = "Connect Tech - WhiteHEAT", - .short_name = "whiteheat", +static struct usb_serial_driver whiteheat_device = { + .driver = { + .owner = THIS_MODULE, + .name = "whiteheat", + }, + .description = "Connect Tech - WhiteHEAT", .id_table = id_table_std, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, @@ -382,10 +386,10 @@ static int whiteheat_attach (struct usb_serial *serial) usb_clear_halt(serial->dev, pipe); ret = usb_bulk_msg (serial->dev, pipe, command, 2, &alen, COMMAND_TIMEOUT_MS); if (ret) { - err("%s: Couldn't send command [%d]", serial->type->name, ret); + err("%s: Couldn't send command [%d]", serial->type->description, ret); goto no_firmware; } else if (alen != sizeof(command)) { - err("%s: Send command incomplete [%d]", serial->type->name, alen); + err("%s: Send command incomplete [%d]", serial->type->description, alen); goto no_firmware; } @@ -394,19 +398,19 @@ static int whiteheat_attach (struct usb_serial *serial) usb_clear_halt(serial->dev, pipe); ret = usb_bulk_msg (serial->dev, pipe, result, sizeof(*hw_info) + 1, &alen, COMMAND_TIMEOUT_MS); if (ret) { - err("%s: Couldn't get results [%d]", serial->type->name, ret); + err("%s: Couldn't get results [%d]", serial->type->description, ret); goto no_firmware; } else if (alen != sizeof(result)) { - err("%s: Get results incomplete [%d]", serial->type->name, alen); + err("%s: Get results incomplete [%d]", serial->type->description, alen); goto no_firmware; } else if (result[0] != command[0]) { - err("%s: Command failed [%d]", serial->type->name, result[0]); + err("%s: Command failed [%d]", serial->type->description, result[0]); goto no_firmware; } hw_info = (struct whiteheat_hw_info *)&result[1]; - info("%s: Driver %s: Firmware v%d.%02d", serial->type->name, + info("%s: Driver %s: Firmware v%d.%02d", serial->type->description, DRIVER_VERSION, hw_info->sw_major_rev, hw_info->sw_minor_rev); for (i = 0; i < serial->num_ports; i++) { @@ -414,7 +418,7 @@ static int whiteheat_attach (struct usb_serial *serial) info = (struct whiteheat_private *)kmalloc(sizeof(struct whiteheat_private), GFP_KERNEL); if (info == NULL) { - err("%s: Out of memory for port structures\n", serial->type->name); + err("%s: Out of memory for port structures\n", serial->type->description); goto no_private; } @@ -484,7 +488,7 @@ static int whiteheat_attach (struct usb_serial *serial) command_info = (struct whiteheat_command_private *)kmalloc(sizeof(struct whiteheat_command_private), GFP_KERNEL); if (command_info == NULL) { - err("%s: Out of memory for port structures\n", serial->type->name); + err("%s: Out of memory for port structures\n", serial->type->description); goto no_command_private; } @@ -501,9 +505,9 @@ static int whiteheat_attach (struct usb_serial *serial) no_firmware: /* Firmware likely not running */ - err("%s: Unable to retrieve firmware version, try replugging\n", serial->type->name); - err("%s: If the firmware is not running (status led not blinking)\n", serial->type->name); - err("%s: please contact support@connecttech.com\n", serial->type->name); + err("%s: Unable to retrieve firmware version, try replugging\n", serial->type->description); + err("%s: If the firmware is not running (status led not blinking)\n", serial->type->description); + err("%s: please contact support@connecttech.com\n", serial->type->description); return -ENODEV; no_command_private: diff --git a/drivers/usb/storage/Kconfig b/drivers/usb/storage/Kconfig index bb9819cc8826..1a9679f76f5a 100644 --- a/drivers/usb/storage/Kconfig +++ b/drivers/usb/storage/Kconfig @@ -2,7 +2,8 @@ # USB Storage driver configuration # -comment "NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information" +comment "NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'" +comment "may also be needed; see USB_STORAGE Help for more information" depends on USB config USB_STORAGE diff --git a/drivers/usb/storage/onetouch.c b/drivers/usb/storage/onetouch.c index 2c9402dc702b..89401a59f952 100644 --- a/drivers/usb/storage/onetouch.c +++ b/drivers/usb/storage/onetouch.c @@ -5,7 +5,7 @@ * Copyright (c) 2005 Nick Sillik <n.sillik@temple.edu> * * Initial work by: - * Copyright (c) 2003 Erik Thyren <erth7411@student.uu.se> + * Copyright (c) 2003 Erik Thyren <erth7411@student.uu.se> * * Based on usbmouse.c (Vojtech Pavlik) and xpad.c (Marko Friedemann) * @@ -46,7 +46,7 @@ void onetouch_release_input(void *onetouch_); struct usb_onetouch { char name[128]; char phys[64]; - struct input_dev dev; /* input device interface */ + struct input_dev *dev; /* input device interface */ struct usb_device *udev; /* usb device */ struct urb *irq; /* urb for interrupt in report */ @@ -58,7 +58,7 @@ static void usb_onetouch_irq(struct urb *urb, struct pt_regs *regs) { struct usb_onetouch *onetouch = urb->context; signed char *data = onetouch->data; - struct input_dev *dev = &onetouch->dev; + struct input_dev *dev = onetouch->dev; int status; switch (urb->status) { @@ -74,11 +74,9 @@ static void usb_onetouch_irq(struct urb *urb, struct pt_regs *regs) } input_regs(dev, regs); - - input_report_key(&onetouch->dev, ONETOUCH_BUTTON, - data[0] & 0x02); - + input_report_key(dev, ONETOUCH_BUTTON, data[0] & 0x02); input_sync(dev); + resubmit: status = usb_submit_urb (urb, SLAB_ATOMIC); if (status) @@ -113,8 +111,8 @@ int onetouch_connect_input(struct us_data *ss) struct usb_host_interface *interface; struct usb_endpoint_descriptor *endpoint; struct usb_onetouch *onetouch; + struct input_dev *input_dev; int pipe, maxp; - char path[64]; interface = ss->pusb_intf->cur_altsetting; @@ -122,62 +120,62 @@ int onetouch_connect_input(struct us_data *ss) return -ENODEV; endpoint = &interface->endpoint[2].desc; - if(!(endpoint->bEndpointAddress & USB_DIR_IN)) + if (!(endpoint->bEndpointAddress & USB_DIR_IN)) return -ENODEV; - if((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) + if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT) return -ENODEV; pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress); maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe)); - if (!(onetouch = kcalloc(1, sizeof(struct usb_onetouch), GFP_KERNEL))) - return -ENOMEM; + onetouch = kzalloc(sizeof(struct usb_onetouch), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!onetouch || !input_dev) + goto fail1; onetouch->data = usb_buffer_alloc(udev, ONETOUCH_PKT_LEN, SLAB_ATOMIC, &onetouch->data_dma); - if (!onetouch->data){ - kfree(onetouch); - return -ENOMEM; - } + if (!onetouch->data) + goto fail1; onetouch->irq = usb_alloc_urb(0, GFP_KERNEL); - if (!onetouch->irq){ - kfree(onetouch); - usb_buffer_free(udev, ONETOUCH_PKT_LEN, - onetouch->data, onetouch->data_dma); - return -ENODEV; - } - + if (!onetouch->irq) + goto fail2; onetouch->udev = udev; + onetouch->dev = input_dev; - set_bit(EV_KEY, onetouch->dev.evbit); - set_bit(ONETOUCH_BUTTON, onetouch->dev.keybit); - clear_bit(0, onetouch->dev.keybit); + if (udev->manufacturer) + strlcpy(onetouch->name, udev->manufacturer, + sizeof(onetouch->name)); + if (udev->product) { + if (udev->manufacturer) + strlcat(onetouch->name, " ", sizeof(onetouch->name)); + strlcat(onetouch->name, udev->product, sizeof(onetouch->name)); + } - onetouch->dev.private = onetouch; - onetouch->dev.open = usb_onetouch_open; - onetouch->dev.close = usb_onetouch_close; + if (!strlen(onetouch->name)) + snprintf(onetouch->name, sizeof(onetouch->name), + "Maxtor Onetouch %04x:%04x", + le16_to_cpu(udev->descriptor.idVendor), + le16_to_cpu(udev->descriptor.idProduct)); - usb_make_path(udev, path, sizeof(path)); - sprintf(onetouch->phys, "%s/input0", path); + usb_make_path(udev, onetouch->phys, sizeof(onetouch->phys)); + strlcat(onetouch->phys, "/input0", sizeof(onetouch->phys)); - onetouch->dev.name = onetouch->name; - onetouch->dev.phys = onetouch->phys; + input_dev->name = onetouch->name; + input_dev->phys = onetouch->phys; + usb_to_input_id(udev, &input_dev->id); + input_dev->cdev.dev = &udev->dev; - usb_to_input_id(udev, &onetouch->dev.id); + set_bit(EV_KEY, input_dev->evbit); + set_bit(ONETOUCH_BUTTON, input_dev->keybit); + clear_bit(0, input_dev->keybit); - onetouch->dev.dev = &udev->dev; - - if (udev->manufacturer) - strcat(onetouch->name, udev->manufacturer); - if (udev->product) - sprintf(onetouch->name, "%s %s", onetouch->name, - udev->product); - if (!strlen(onetouch->name)) - sprintf(onetouch->name, "Maxtor Onetouch %04x:%04x", - onetouch->dev.id.vendor, onetouch->dev.id.product); + input_dev->private = onetouch; + input_dev->open = usb_onetouch_open; + input_dev->close = usb_onetouch_close; usb_fill_int_urb(onetouch->irq, udev, pipe, onetouch->data, (maxp > 8 ? 8 : maxp), @@ -188,10 +186,15 @@ int onetouch_connect_input(struct us_data *ss) ss->extra_destructor = onetouch_release_input; ss->extra = onetouch; - input_register_device(&onetouch->dev); - printk(KERN_INFO "usb-input: %s on %s\n", onetouch->dev.name, path); + input_register_device(onetouch->dev); return 0; + + fail2: usb_buffer_free(udev, ONETOUCH_PKT_LEN, + onetouch->data, onetouch->data_dma); + fail1: kfree(onetouch); + input_free_device(input_dev); + return -ENOMEM; } void onetouch_release_input(void *onetouch_) @@ -200,11 +203,9 @@ void onetouch_release_input(void *onetouch_) if (onetouch) { usb_kill_urb(onetouch->irq); - input_unregister_device(&onetouch->dev); + input_unregister_device(onetouch->dev); usb_free_urb(onetouch->irq); usb_buffer_free(onetouch->udev, ONETOUCH_PKT_LEN, onetouch->data, onetouch->data_dma); - printk(KERN_INFO "usb-input: deregistering %s\n", - onetouch->dev.name); } } diff --git a/drivers/usb/storage/shuttle_usbat.c b/drivers/usb/storage/shuttle_usbat.c index 356342c6e7a2..33c55a6261bb 100644 --- a/drivers/usb/storage/shuttle_usbat.c +++ b/drivers/usb/storage/shuttle_usbat.c @@ -1,4 +1,4 @@ -/* Driver for SCM Microsystems USB-ATAPI cable +/* Driver for SCM Microsystems (a.k.a. Shuttle) USB-ATAPI cable * * $Id: shuttle_usbat.c,v 1.17 2002/04/22 03:39:43 mdharm Exp $ * @@ -67,10 +67,10 @@ static int usbat_flash_transport(struct scsi_cmnd * srb, struct us_data *us); static int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us); /* - * Convenience function to produce an ATAPI read/write sectors command + * Convenience function to produce an ATA read/write sectors command * Use cmd=0x20 for read, cmd=0x30 for write */ -static void usbat_pack_atapi_sector_cmd(unsigned char *buf, +static void usbat_pack_ata_sector_cmd(unsigned char *buf, unsigned char thistime, u32 sector, unsigned char cmd) { @@ -196,10 +196,12 @@ static int usbat_check_status(struct us_data *us) if (rc != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_FAILED; - if (*reply & 0x01 && *reply != 0x51) // error/check condition (0x51 is ok) + /* error/check condition (0x51 is ok) */ + if (*reply & 0x01 && *reply != 0x51) return USB_STOR_TRANSPORT_FAILED; - if (*reply & 0x20) // device fault + /* device fault */ + if (*reply & 0x20) return USB_STOR_TRANSPORT_FAILED; return USB_STOR_TRANSPORT_GOOD; @@ -222,29 +224,39 @@ static int usbat_set_shuttle_features(struct us_data *us, command[0] = 0x40; command[1] = USBAT_CMD_SET_FEAT; - // The only bit relevant to ATA access is bit 6 - // which defines 8 bit data access (set) or 16 bit (unset) + /* + * The only bit relevant to ATA access is bit 6 + * which defines 8 bit data access (set) or 16 bit (unset) + */ command[2] = epp_control; - // If FCQ is set in the qualifier (defined in R/W cmd), then bits U0, U1, - // ET1 and ET2 define an external event to be checked for on event of a - // _read_blocks or _write_blocks operation. The read/write will not take - // place unless the defined trigger signal is active. + /* + * If FCQ is set in the qualifier (defined in R/W cmd), then bits U0, U1, + * ET1 and ET2 define an external event to be checked for on event of a + * _read_blocks or _write_blocks operation. The read/write will not take + * place unless the defined trigger signal is active. + */ command[3] = external_trigger; - // The resultant byte of the mask operation (see mask_byte) is compared for - // equivalence with this test pattern. If equal, the read/write will take - // place. + /* + * The resultant byte of the mask operation (see mask_byte) is compared for + * equivalence with this test pattern. If equal, the read/write will take + * place. + */ command[4] = test_pattern; - // This value is logically ANDed with the status register field specified - // in the read/write command. + /* + * This value is logically ANDed with the status register field specified + * in the read/write command. + */ command[5] = mask_byte; - // If ALQ is set in the qualifier, this field contains the address of the - // registers where the byte count should be read for transferring the data. - // If ALQ is not set, then this field contains the number of bytes to be - // transferred. + /* + * If ALQ is set in the qualifier, this field contains the address of the + * registers where the byte count should be read for transferring the data. + * If ALQ is not set, then this field contains the number of bytes to be + * transferred. + */ command[6] = subcountL; command[7] = subcountH; @@ -273,26 +285,26 @@ static int usbat_wait_not_busy(struct us_data *us, int minutes) if (result!=USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; - if (*status & 0x01) { // check condition + if (*status & 0x01) { /* check condition */ result = usbat_read(us, USBAT_ATA, 0x10, status); return USB_STOR_TRANSPORT_FAILED; } - if (*status & 0x20) // device fault + if (*status & 0x20) /* device fault */ return USB_STOR_TRANSPORT_FAILED; - if ((*status & 0x80)==0x00) { // not busy + if ((*status & 0x80)==0x00) { /* not busy */ US_DEBUGP("Waited not busy for %d steps\n", i); return USB_STOR_TRANSPORT_GOOD; } if (i<500) - msleep(10); // 5 seconds + msleep(10); /* 5 seconds */ else if (i<700) - msleep(50); // 10 seconds + msleep(50); /* 10 seconds */ else if (i<1200) - msleep(100); // 50 seconds + msleep(100); /* 50 seconds */ else - msleep(1000); // X minutes + msleep(1000); /* X minutes */ } US_DEBUGP("Waited not busy for %d minutes, timing out.\n", @@ -412,9 +424,12 @@ static int usbat_hp8200e_rw_block_test(struct us_data *us, if (i==0) { cmdlen = 16; - // Write to multiple registers - // Not really sure the 0x07, 0x17, 0xfc, 0xe7 is necessary here, - // but that's what came out of the trace every single time. + /* + * Write to multiple registers + * Not really sure the 0x07, 0x17, 0xfc, 0xe7 is + * necessary here, but that's what came out of the + * trace every single time. + */ command[0] = 0x40; command[1] = access | USBAT_CMD_WRITE_REGS; command[2] = 0x07; @@ -426,7 +441,7 @@ static int usbat_hp8200e_rw_block_test(struct us_data *us, } else cmdlen = 8; - // Conditionally read or write blocks + /* Conditionally read or write blocks */ command[cmdlen-8] = (direction==DMA_TO_DEVICE ? 0x40 : 0xC0); command[cmdlen-7] = access | (direction==DMA_TO_DEVICE ? @@ -456,11 +471,6 @@ static int usbat_hp8200e_rw_block_test(struct us_data *us, } - - //US_DEBUGP("Transfer %s %d bytes, sg buffers %d\n", - // direction == DMA_TO_DEVICE ? "out" : "in", - // len, use_sg); - result = usb_stor_bulk_transfer_sg(us, pipe, content, len, use_sg, NULL); @@ -508,9 +518,9 @@ static int usbat_hp8200e_rw_block_test(struct us_data *us, if (result!=USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; - if (*status & 0x01) // check condition + if (*status & 0x01) /* check condition */ return USB_STOR_TRANSPORT_FAILED; - if (*status & 0x20) // device fault + if (*status & 0x20) /* device fault */ return USB_STOR_TRANSPORT_FAILED; US_DEBUGP("Redoing %s\n", @@ -547,32 +557,32 @@ static int usbat_multiple_write(struct us_data *us, BUG_ON(num_registers > US_IOBUF_SIZE/2); - // Write to multiple registers, ATA access + /* Write to multiple registers, ATA access */ command[0] = 0x40; command[1] = USBAT_ATA | USBAT_CMD_WRITE_REGS; - // No relevance + /* No relevance */ command[2] = 0; command[3] = 0; command[4] = 0; command[5] = 0; - // Number of bytes to be transferred (incl. addresses and data) + /* Number of bytes to be transferred (incl. addresses and data) */ command[6] = LSB_of(num_registers*2); command[7] = MSB_of(num_registers*2); - // The setup command + /* The setup command */ result = usbat_execute_command(us, command, 8); if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; - // Create the reg/data, reg/data sequence + /* Create the reg/data, reg/data sequence */ for (i=0; i<num_registers; i++) { data[i<<1] = registers[i]; data[1+(i<<1)] = data_out[i]; } - // Send the data + /* Send the data */ result = usbat_bulk_write(us, data, num_registers*2); if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; @@ -606,17 +616,17 @@ static int usbat_read_blocks(struct us_data *us, command[1] = USBAT_ATA | USBAT_CMD_COND_READ_BLOCK; command[2] = USBAT_ATA_DATA; command[3] = USBAT_ATA_STATUS; - command[4] = 0xFD; // Timeout (ms); + command[4] = 0xFD; /* Timeout (ms); */ command[5] = USBAT_QUAL_FCQ; command[6] = LSB_of(len); command[7] = MSB_of(len); - // Multiple block read setup command + /* Multiple block read setup command */ result = usbat_execute_command(us, command, 8); if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_FAILED; - // Read the blocks we just asked for + /* Read the blocks we just asked for */ result = usbat_bulk_read(us, buffer, len); if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_FAILED; @@ -647,17 +657,17 @@ static int usbat_write_blocks(struct us_data *us, command[1] = USBAT_ATA | USBAT_CMD_COND_WRITE_BLOCK; command[2] = USBAT_ATA_DATA; command[3] = USBAT_ATA_STATUS; - command[4] = 0xFD; // Timeout (ms) + command[4] = 0xFD; /* Timeout (ms) */ command[5] = USBAT_QUAL_FCQ; command[6] = LSB_of(len); command[7] = MSB_of(len); - // Multiple block write setup command + /* Multiple block write setup command */ result = usbat_execute_command(us, command, 8); if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_FAILED; - // Write the data + /* Write the data */ result = usbat_bulk_write(us, buffer, len); if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_FAILED; @@ -711,16 +721,20 @@ static int usbat_device_reset(struct us_data *us) { int rc; - // Reset peripheral, enable peripheral control signals - // (bring reset signal up) + /* + * Reset peripheral, enable peripheral control signals + * (bring reset signal up) + */ rc = usbat_write_user_io(us, USBAT_UIO_DRVRST | USBAT_UIO_OE1 | USBAT_UIO_OE0, USBAT_UIO_EPAD | USBAT_UIO_1); if (rc != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; - // Enable peripheral control signals - // (bring reset signal down) + /* + * Enable peripheral control signals + * (bring reset signal down) + */ rc = usbat_write_user_io(us, USBAT_UIO_OE1 | USBAT_UIO_OE0, USBAT_UIO_EPAD | USBAT_UIO_1); @@ -737,7 +751,7 @@ static int usbat_device_enable_cdt(struct us_data *us) { int rc; - // Enable peripheral control signals and card detect + /* Enable peripheral control signals and card detect */ rc = usbat_write_user_io(us, USBAT_UIO_ACKD | USBAT_UIO_OE1 | USBAT_UIO_OE0, USBAT_UIO_EPAD | USBAT_UIO_1); @@ -786,7 +800,7 @@ static int usbat_flash_check_media(struct us_data *us, if (rc != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; - // Check for media existence + /* Check for media existence */ rc = usbat_flash_check_media_present(uio); if (rc == USBAT_FLASH_MEDIA_NONE) { info->sense_key = 0x02; @@ -795,11 +809,11 @@ static int usbat_flash_check_media(struct us_data *us, return USB_STOR_TRANSPORT_FAILED; } - // Check for media change + /* Check for media change */ rc = usbat_flash_check_media_changed(uio); if (rc == USBAT_FLASH_MEDIA_CHANGED) { - // Reset and re-enable card detect + /* Reset and re-enable card detect */ rc = usbat_device_reset(us); if (rc != USB_STOR_TRANSPORT_GOOD) return rc; @@ -855,15 +869,15 @@ static int usbat_identify_device(struct us_data *us, if (rc != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; - // Check for error bit - if (status & 0x01) { - // Device is a CompactFlash reader/writer - US_DEBUGP("usbat_identify_device: Detected Flash reader/writer\n"); - info->devicetype = USBAT_DEV_FLASH; - } else { - // Device is HP 8200 + /* Check for error bit, or if the command 'fell through' */ + if (status == 0xA1 || !(status & 0x01)) { + /* Device is HP 8200 */ US_DEBUGP("usbat_identify_device: Detected HP8200 CDRW\n"); info->devicetype = USBAT_DEV_HP8200; + } else { + /* Device is a CompactFlash reader/writer */ + US_DEBUGP("usbat_identify_device: Detected Flash reader/writer\n"); + info->devicetype = USBAT_DEV_FLASH; } return USB_STOR_TRANSPORT_GOOD; @@ -916,7 +930,7 @@ static int usbat_flash_get_sector_count(struct us_data *us, if (!reply) return USB_STOR_TRANSPORT_ERROR; - // ATAPI command : IDENTIFY DEVICE + /* ATA command : IDENTIFY DEVICE */ rc = usbat_multiple_write(us, registers, command, 3); if (rc != USB_STOR_XFER_GOOD) { US_DEBUGP("usbat_flash_get_sector_count: Gah! identify_device failed\n"); @@ -924,7 +938,7 @@ static int usbat_flash_get_sector_count(struct us_data *us, goto leave; } - // Read device status + /* Read device status */ if (usbat_get_status(us, &status) != USB_STOR_XFER_GOOD) { rc = USB_STOR_TRANSPORT_ERROR; goto leave; @@ -932,7 +946,7 @@ static int usbat_flash_get_sector_count(struct us_data *us, msleep(100); - // Read the device identification data + /* Read the device identification data */ rc = usbat_read_block(us, reply, 512); if (rc != USB_STOR_TRANSPORT_GOOD) goto leave; @@ -977,19 +991,23 @@ static int usbat_flash_read_data(struct us_data *us, if (result != USB_STOR_TRANSPORT_GOOD) return result; - // we're working in LBA mode. according to the ATA spec, - // we can support up to 28-bit addressing. I don't know if Jumpshot - // supports beyond 24-bit addressing. It's kind of hard to test - // since it requires > 8GB CF card. + /* + * we're working in LBA mode. according to the ATA spec, + * we can support up to 28-bit addressing. I don't know if Jumpshot + * supports beyond 24-bit addressing. It's kind of hard to test + * since it requires > 8GB CF card. + */ if (sector > 0x0FFFFFFF) return USB_STOR_TRANSPORT_ERROR; totallen = sectors * info->ssize; - // Since we don't read more than 64 KB at a time, we have to create - // a bounce buffer and move the data a piece at a time between the - // bounce buffer and the actual transfer buffer. + /* + * Since we don't read more than 64 KB at a time, we have to create + * a bounce buffer and move the data a piece at a time between the + * bounce buffer and the actual transfer buffer. + */ alloclen = min(totallen, 65536u); buffer = kmalloc(alloclen, GFP_NOIO); @@ -997,27 +1015,29 @@ static int usbat_flash_read_data(struct us_data *us, return USB_STOR_TRANSPORT_ERROR; do { - // loop, never allocate or transfer more than 64k at once - // (min(128k, 255*info->ssize) is the real limit) + /* + * loop, never allocate or transfer more than 64k at once + * (min(128k, 255*info->ssize) is the real limit) + */ len = min(totallen, alloclen); thistime = (len / info->ssize) & 0xff; - // ATAPI command 0x20 (READ SECTORS) - usbat_pack_atapi_sector_cmd(command, thistime, sector, 0x20); + /* ATA command 0x20 (READ SECTORS) */ + usbat_pack_ata_sector_cmd(command, thistime, sector, 0x20); - // Write/execute ATAPI read command + /* Write/execute ATA read command */ result = usbat_multiple_write(us, registers, command, 7); if (result != USB_STOR_TRANSPORT_GOOD) goto leave; - // Read the data we just requested + /* Read the data we just requested */ result = usbat_read_blocks(us, buffer, len); if (result != USB_STOR_TRANSPORT_GOOD) goto leave; US_DEBUGP("usbat_flash_read_data: %d bytes\n", len); - // Store the data in the transfer buffer + /* Store the data in the transfer buffer */ usb_stor_access_xfer_buf(buffer, len, us->srb, &sg_idx, &sg_offset, TO_XFER_BUF); @@ -1061,19 +1081,23 @@ static int usbat_flash_write_data(struct us_data *us, if (result != USB_STOR_TRANSPORT_GOOD) return result; - // we're working in LBA mode. according to the ATA spec, - // we can support up to 28-bit addressing. I don't know if Jumpshot - // supports beyond 24-bit addressing. It's kind of hard to test - // since it requires > 8GB CF card. + /* + * we're working in LBA mode. according to the ATA spec, + * we can support up to 28-bit addressing. I don't know if the device + * supports beyond 24-bit addressing. It's kind of hard to test + * since it requires > 8GB media. + */ if (sector > 0x0FFFFFFF) return USB_STOR_TRANSPORT_ERROR; totallen = sectors * info->ssize; - // Since we don't write more than 64 KB at a time, we have to create - // a bounce buffer and move the data a piece at a time between the - // bounce buffer and the actual transfer buffer. + /* + * Since we don't write more than 64 KB at a time, we have to create + * a bounce buffer and move the data a piece at a time between the + * bounce buffer and the actual transfer buffer. + */ alloclen = min(totallen, 65536u); buffer = kmalloc(alloclen, GFP_NOIO); @@ -1081,24 +1105,26 @@ static int usbat_flash_write_data(struct us_data *us, return USB_STOR_TRANSPORT_ERROR; do { - // loop, never allocate or transfer more than 64k at once - // (min(128k, 255*info->ssize) is the real limit) + /* + * loop, never allocate or transfer more than 64k at once + * (min(128k, 255*info->ssize) is the real limit) + */ len = min(totallen, alloclen); thistime = (len / info->ssize) & 0xff; - // Get the data from the transfer buffer + /* Get the data from the transfer buffer */ usb_stor_access_xfer_buf(buffer, len, us->srb, &sg_idx, &sg_offset, FROM_XFER_BUF); - // ATAPI command 0x30 (WRITE SECTORS) - usbat_pack_atapi_sector_cmd(command, thistime, sector, 0x30); + /* ATA command 0x30 (WRITE SECTORS) */ + usbat_pack_ata_sector_cmd(command, thistime, sector, 0x30); - // Write/execute ATAPI write command + /* Write/execute ATA write command */ result = usbat_multiple_write(us, registers, command, 7); if (result != USB_STOR_TRANSPORT_GOOD) goto leave; - // Write the data + /* Write the data */ result = usbat_write_blocks(us, buffer, len); if (result != USB_STOR_TRANSPORT_GOOD) goto leave; @@ -1169,42 +1195,44 @@ static int usbat_hp8200e_handle_read10(struct us_data *us, srb->transfersize); } - // Since we only read in one block at a time, we have to create - // a bounce buffer and move the data a piece at a time between the - // bounce buffer and the actual transfer buffer. + /* + * Since we only read in one block at a time, we have to create + * a bounce buffer and move the data a piece at a time between the + * bounce buffer and the actual transfer buffer. + */ len = (65535/srb->transfersize) * srb->transfersize; US_DEBUGP("Max read is %d bytes\n", len); len = min(len, srb->request_bufflen); buffer = kmalloc(len, GFP_NOIO); - if (buffer == NULL) // bloody hell! + if (buffer == NULL) /* bloody hell! */ return USB_STOR_TRANSPORT_FAILED; sector = short_pack(data[7+3], data[7+2]); sector <<= 16; sector |= short_pack(data[7+5], data[7+4]); transferred = 0; - sg_segment = 0; // for keeping track of where we are in - sg_offset = 0; // the scatter/gather list + sg_segment = 0; /* for keeping track of where we are in */ + sg_offset = 0; /* the scatter/gather list */ while (transferred != srb->request_bufflen) { if (len > srb->request_bufflen - transferred) len = srb->request_bufflen - transferred; - data[3] = len&0xFF; // (cylL) = expected length (L) - data[4] = (len>>8)&0xFF; // (cylH) = expected length (H) + data[3] = len&0xFF; /* (cylL) = expected length (L) */ + data[4] = (len>>8)&0xFF; /* (cylH) = expected length (H) */ - // Fix up the SCSI command sector and num sectors + /* Fix up the SCSI command sector and num sectors */ - data[7+2] = MSB_of(sector>>16); // SCSI command sector + data[7+2] = MSB_of(sector>>16); /* SCSI command sector */ data[7+3] = LSB_of(sector>>16); data[7+4] = MSB_of(sector&0xFFFF); data[7+5] = LSB_of(sector&0xFFFF); if (data[7+0] == GPCMD_READ_CD) data[7+6] = 0; - data[7+7] = MSB_of(len / srb->transfersize); // SCSI command - data[7+8] = LSB_of(len / srb->transfersize); // num sectors + data[7+7] = MSB_of(len / srb->transfersize); /* SCSI command */ + data[7+8] = LSB_of(len / srb->transfersize); /* num sectors */ result = usbat_hp8200e_rw_block_test(us, USBAT_ATA, registers, data, 19, @@ -1217,16 +1245,16 @@ static int usbat_hp8200e_handle_read10(struct us_data *us, if (result != USB_STOR_TRANSPORT_GOOD) break; - // Store the data in the transfer buffer + /* Store the data in the transfer buffer */ usb_stor_access_xfer_buf(buffer, len, srb, &sg_segment, &sg_offset, TO_XFER_BUF); - // Update the amount transferred and the sector number + /* Update the amount transferred and the sector number */ transferred += len; sector += len / srb->transfersize; - } // while transferred != srb->request_bufflen + } /* while transferred != srb->request_bufflen */ kfree(buffer); return result; @@ -1237,7 +1265,7 @@ static int usbat_select_and_test_registers(struct us_data *us) int selector; unsigned char *status = us->iobuf; - // try device = master, then device = slave. + /* try device = master, then device = slave. */ for (selector = 0xA0; selector <= 0xB0; selector += 0x10) { if (usbat_write(us, USBAT_ATA, USBAT_ATA_DEVICE, selector) != USB_STOR_XFER_GOOD) @@ -1298,7 +1326,7 @@ int init_usbat(struct us_data *us) memset(us->extra, 0, sizeof(struct usbat_info)); info = (struct usbat_info *) (us->extra); - // Enable peripheral control signals + /* Enable peripheral control signals */ rc = usbat_write_user_io(us, USBAT_UIO_OE1 | USBAT_UIO_OE0, USBAT_UIO_EPAD | USBAT_UIO_1); @@ -1337,7 +1365,7 @@ int init_usbat(struct us_data *us) US_DEBUGP("INIT 5\n"); - // Enable peripheral control signals and card detect + /* Enable peripheral control signals and card detect */ rc = usbat_device_enable_cdt(us); if (rc != USB_STOR_TRANSPORT_GOOD) return rc; @@ -1364,7 +1392,7 @@ int init_usbat(struct us_data *us) US_DEBUGP("INIT 9\n"); - // At this point, we need to detect which device we are using + /* At this point, we need to detect which device we are using */ if (usbat_set_transport(us, info)) return USB_STOR_TRANSPORT_ERROR; @@ -1414,10 +1442,10 @@ static int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us) data[0] = 0x00; data[1] = 0x00; data[2] = 0x00; - data[3] = len&0xFF; // (cylL) = expected length (L) - data[4] = (len>>8)&0xFF; // (cylH) = expected length (H) - data[5] = 0xB0; // (device sel) = slave - data[6] = 0xA0; // (command) = ATA PACKET COMMAND + data[3] = len&0xFF; /* (cylL) = expected length (L) */ + data[4] = (len>>8)&0xFF; /* (cylH) = expected length (H) */ + data[5] = 0xB0; /* (device sel) = slave */ + data[6] = 0xA0; /* (command) = ATA PACKET COMMAND */ for (i=7; i<19; i++) { registers[i] = 0x10; @@ -1466,13 +1494,15 @@ static int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us) return result; } - // Write the 12-byte command header. - - // If the command is BLANK then set the timer for 75 minutes. - // Otherwise set it for 10 minutes. - - // NOTE: THE 8200 DOCUMENTATION STATES THAT BLANKING A CDRW - // AT SPEED 4 IS UNRELIABLE!!! + /* + * Write the 12-byte command header. + * + * If the command is BLANK then set the timer for 75 minutes. + * Otherwise set it for 10 minutes. + * + * NOTE: THE 8200 DOCUMENTATION STATES THAT BLANKING A CDRW + * AT SPEED 4 IS UNRELIABLE!!! + */ if ( (result = usbat_write_block(us, USBAT_ATA, srb->cmnd, 12, @@ -1481,19 +1511,18 @@ static int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us) return result; } - // If there is response data to be read in - // then do it here. + /* If there is response data to be read in then do it here. */ if (len != 0 && (srb->sc_data_direction == DMA_FROM_DEVICE)) { - // How many bytes to read in? Check cylL register + /* How many bytes to read in? Check cylL register */ if (usbat_read(us, USBAT_ATA, USBAT_ATA_LBA_ME, status) != USB_STOR_XFER_GOOD) { return USB_STOR_TRANSPORT_ERROR; } - if (len > 0xFF) { // need to read cylH also + if (len > 0xFF) { /* need to read cylH also */ len = *status; if (usbat_read(us, USBAT_ATA, USBAT_ATA_LBA_HI, status) != USB_STOR_XFER_GOOD) { @@ -1556,13 +1585,16 @@ static int usbat_flash_transport(struct scsi_cmnd * srb, struct us_data *us) if (rc != USB_STOR_TRANSPORT_GOOD) return rc; - info->ssize = 0x200; // hard coded 512 byte sectors as per ATA spec + /* hard coded 512 byte sectors as per ATA spec */ + info->ssize = 0x200; US_DEBUGP("usbat_flash_transport: READ_CAPACITY: %ld sectors, %ld bytes per sector\n", info->sectors, info->ssize); - // build the reply - // note: must return the sector number of the last sector, - // *not* the total number of sectors + /* + * build the reply + * note: must return the sector number of the last sector, + * *not* the total number of sectors + */ ((__be32 *) ptr)[0] = cpu_to_be32(info->sectors - 1); ((__be32 *) ptr)[1] = cpu_to_be32(info->ssize); usb_stor_set_xfer_buf(ptr, 8, srb); @@ -1586,7 +1618,9 @@ static int usbat_flash_transport(struct scsi_cmnd * srb, struct us_data *us) } if (srb->cmnd[0] == READ_12) { - // I don't think we'll ever see a READ_12 but support it anyway... + /* + * I don't think we'll ever see a READ_12 but support it anyway + */ block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) | ((u32)(srb->cmnd[4]) << 8) | ((u32)(srb->cmnd[5])); @@ -1608,7 +1642,9 @@ static int usbat_flash_transport(struct scsi_cmnd * srb, struct us_data *us) } if (srb->cmnd[0] == WRITE_12) { - // I don't think we'll ever see a WRITE_12 but support it anyway... + /* + * I don't think we'll ever see a WRITE_12 but support it anyway + */ block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) | ((u32)(srb->cmnd[4]) << 8) | ((u32)(srb->cmnd[5])); @@ -1645,8 +1681,10 @@ static int usbat_flash_transport(struct scsi_cmnd * srb, struct us_data *us) } if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) { - // sure. whatever. not like we can stop the user from popping - // the media out of the device (no locking doors, etc) + /* + * sure. whatever. not like we can stop the user from popping + * the media out of the device (no locking doors, etc) + */ return USB_STOR_TRANSPORT_GOOD; } diff --git a/drivers/usb/storage/shuttle_usbat.h b/drivers/usb/storage/shuttle_usbat.h index 5b8e867e2ae5..25e7d8b340b8 100644 --- a/drivers/usb/storage/shuttle_usbat.h +++ b/drivers/usb/storage/shuttle_usbat.h @@ -55,8 +55,8 @@ #define USBAT_UIO_WRITE 0 /* Qualifier bits */ -#define USBAT_QUAL_FCQ 0x20 // full compare -#define USBAT_QUAL_ALQ 0x10 // auto load subcount +#define USBAT_QUAL_FCQ 0x20 /* full compare */ +#define USBAT_QUAL_ALQ 0x10 /* auto load subcount */ /* USBAT Flash Media status types */ #define USBAT_FLASH_MEDIA_NONE 0 @@ -67,39 +67,39 @@ #define USBAT_FLASH_MEDIA_CHANGED 1 /* USBAT ATA registers */ -#define USBAT_ATA_DATA 0x10 // read/write data (R/W) -#define USBAT_ATA_FEATURES 0x11 // set features (W) -#define USBAT_ATA_ERROR 0x11 // error (R) -#define USBAT_ATA_SECCNT 0x12 // sector count (R/W) -#define USBAT_ATA_SECNUM 0x13 // sector number (R/W) -#define USBAT_ATA_LBA_ME 0x14 // cylinder low (R/W) -#define USBAT_ATA_LBA_HI 0x15 // cylinder high (R/W) -#define USBAT_ATA_DEVICE 0x16 // head/device selection (R/W) -#define USBAT_ATA_STATUS 0x17 // device status (R) -#define USBAT_ATA_CMD 0x17 // device command (W) -#define USBAT_ATA_ALTSTATUS 0x0E // status (no clear IRQ) (R) +#define USBAT_ATA_DATA 0x10 /* read/write data (R/W) */ +#define USBAT_ATA_FEATURES 0x11 /* set features (W) */ +#define USBAT_ATA_ERROR 0x11 /* error (R) */ +#define USBAT_ATA_SECCNT 0x12 /* sector count (R/W) */ +#define USBAT_ATA_SECNUM 0x13 /* sector number (R/W) */ +#define USBAT_ATA_LBA_ME 0x14 /* cylinder low (R/W) */ +#define USBAT_ATA_LBA_HI 0x15 /* cylinder high (R/W) */ +#define USBAT_ATA_DEVICE 0x16 /* head/device selection (R/W) */ +#define USBAT_ATA_STATUS 0x17 /* device status (R) */ +#define USBAT_ATA_CMD 0x17 /* device command (W) */ +#define USBAT_ATA_ALTSTATUS 0x0E /* status (no clear IRQ) (R) */ /* USBAT User I/O Data registers */ -#define USBAT_UIO_EPAD 0x80 // Enable Peripheral Control Signals -#define USBAT_UIO_CDT 0x40 // Card Detect (Read Only) - // CDT = ACKD & !UI1 & !UI0 -#define USBAT_UIO_1 0x20 // I/O 1 -#define USBAT_UIO_0 0x10 // I/O 0 -#define USBAT_UIO_EPP_ATA 0x08 // 1=EPP mode, 0=ATA mode -#define USBAT_UIO_UI1 0x04 // Input 1 -#define USBAT_UIO_UI0 0x02 // Input 0 -#define USBAT_UIO_INTR_ACK 0x01 // Interrupt (ATA & ISA)/Acknowledge (EPP) +#define USBAT_UIO_EPAD 0x80 /* Enable Peripheral Control Signals */ +#define USBAT_UIO_CDT 0x40 /* Card Detect (Read Only) */ + /* CDT = ACKD & !UI1 & !UI0 */ +#define USBAT_UIO_1 0x20 /* I/O 1 */ +#define USBAT_UIO_0 0x10 /* I/O 0 */ +#define USBAT_UIO_EPP_ATA 0x08 /* 1=EPP mode, 0=ATA mode */ +#define USBAT_UIO_UI1 0x04 /* Input 1 */ +#define USBAT_UIO_UI0 0x02 /* Input 0 */ +#define USBAT_UIO_INTR_ACK 0x01 /* Interrupt (ATA/ISA)/Acknowledge (EPP) */ /* USBAT User I/O Enable registers */ -#define USBAT_UIO_DRVRST 0x80 // Reset Peripheral -#define USBAT_UIO_ACKD 0x40 // Enable Card Detect -#define USBAT_UIO_OE1 0x20 // I/O 1 set=output/clr=input - // If ACKD=1, set OE1 to 1 also. -#define USBAT_UIO_OE0 0x10 // I/O 0 set=output/clr=input -#define USBAT_UIO_ADPRST 0x01 // Reset SCM chip +#define USBAT_UIO_DRVRST 0x80 /* Reset Peripheral */ +#define USBAT_UIO_ACKD 0x40 /* Enable Card Detect */ +#define USBAT_UIO_OE1 0x20 /* I/O 1 set=output/clr=input */ + /* If ACKD=1, set OE1 to 1 also. */ +#define USBAT_UIO_OE0 0x10 /* I/O 0 set=output/clr=input */ +#define USBAT_UIO_ADPRST 0x01 /* Reset SCM chip */ /* USBAT Features */ -#define USBAT_FEAT_ETEN 0x80 // External trigger enable +#define USBAT_FEAT_ETEN 0x80 /* External trigger enable */ #define USBAT_FEAT_U1 0x08 #define USBAT_FEAT_U0 0x04 #define USBAT_FEAT_ET1 0x02 @@ -112,12 +112,12 @@ struct usbat_info { int devicetype; /* Used for Flash readers only */ - unsigned long sectors; // total sector count - unsigned long ssize; // sector size in bytes + unsigned long sectors; /* total sector count */ + unsigned long ssize; /* sector size in bytes */ unsigned char sense_key; - unsigned long sense_asc; // additional sense code - unsigned long sense_ascq; // additional sense code qualifier + unsigned long sense_asc; /* additional sense code */ + unsigned long sense_ascq; /* additional sense code qualifier */ }; #endif diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c index c1ba5301ebfc..7ca896a342e3 100644 --- a/drivers/usb/storage/transport.c +++ b/drivers/usb/storage/transport.c @@ -636,11 +636,11 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) /* use the new buffer we have */ old_request_buffer = srb->request_buffer; - srb->request_buffer = srb->sense_buffer; + srb->request_buffer = us->sensebuf; /* set the buffer length for transfer */ old_request_bufflen = srb->request_bufflen; - srb->request_bufflen = 18; + srb->request_bufflen = US_SENSE_SIZE; /* set up for no scatter-gather use */ old_sg = srb->use_sg; @@ -652,6 +652,7 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) temp_result = us->transport(us->srb, us); /* let's clean up right away */ + memcpy(srb->sense_buffer, us->sensebuf, US_SENSE_SIZE); srb->resid = old_resid; srb->request_buffer = old_request_buffer; srb->request_bufflen = old_request_bufflen; @@ -923,6 +924,7 @@ int usb_stor_Bulk_max_lun(struct us_data *us) int result; /* issue the command */ + us->iobuf[0] = 0; result = usb_stor_control_msg(us, us->recv_ctrl_pipe, US_BULK_GET_MAX_LUN, USB_DIR_IN | USB_TYPE_CLASS | diff --git a/drivers/usb/storage/transport.h b/drivers/usb/storage/transport.h index 8d9e0663f8fe..0a362cc781ad 100644 --- a/drivers/usb/storage/transport.h +++ b/drivers/usb/storage/transport.h @@ -50,7 +50,7 @@ #define US_PR_CB 0x01 /* Control/Bulk w/o interrupt */ #define US_PR_BULK 0x50 /* bulk only */ #ifdef CONFIG_USB_STORAGE_USBAT -#define US_PR_SCM_ATAPI 0x80 /* SCM-ATAPI bridge */ +#define US_PR_USBAT 0x80 /* SCM-ATAPI bridge */ #endif #ifdef CONFIG_USB_STORAGE_SDDR09 #define US_PR_EUSB_SDDR09 0x81 /* SCM-SCSI bridge for SDDR-09 */ diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index b79dad1b598c..9e926a8f2116 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -71,12 +71,12 @@ UNUSUAL_DEV( 0x03f0, 0x0107, 0x0200, 0x0200, UNUSUAL_DEV( 0x03f0, 0x0207, 0x0001, 0x0001, "HP", "CD-Writer+ 8200e", - US_SC_8070, US_PR_SCM_ATAPI, init_usbat, 0), + US_SC_8070, US_PR_USBAT, init_usbat, 0), UNUSUAL_DEV( 0x03f0, 0x0307, 0x0001, 0x0001, "HP", "CD-Writer+ CD-4e", - US_SC_8070, US_PR_SCM_ATAPI, init_usbat, 0), + US_SC_8070, US_PR_USBAT, init_usbat, 0), #endif /* Patch submitted by Mihnea-Costin Grigore <mihnea@zulu.ro> */ @@ -106,6 +106,13 @@ UNUSUAL_DEV( 0x0411, 0x001c, 0x0113, 0x0113, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY ), +/* Reported by Stefan Werner <dustbln@gmx.de> */ +UNUSUAL_DEV( 0x0419, 0xaaf6, 0x0100, 0x0100, + "TrekStor", + "i.Beat Joy 2.0", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_IGNORE_RESIDUE ), + /* Reported by Olaf Hering <olh@suse.de> from novell bug #105878 */ UNUSUAL_DEV( 0x0424, 0x0fdc, 0x0210, 0x0210, "SMSC", @@ -244,6 +251,13 @@ UNUSUAL_DEV( 0x04da, 0x2372, 0x0000, 0x9999, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_CAPACITY | US_FL_NOT_LOCKABLE ), +/* Reported by Simeon Simeonov <simeonov_2000@yahoo.com> */ +UNUSUAL_DEV( 0x04da, 0x2373, 0x0000, 0x9999, + "LEICA", + "D-LUX Camera", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_FIX_CAPACITY | US_FL_NOT_LOCKABLE ), + /* Most of the following entries were developed with the help of * Shuttle/SCM directly. */ @@ -333,9 +347,9 @@ UNUSUAL_DEV( 0x04fc, 0x80c2, 0x0100, 0x0100, #ifdef CONFIG_USB_STORAGE_USBAT UNUSUAL_DEV( 0x04e6, 0x1010, 0x0000, 0x9999, - "SCM", - "SCM USBAT-02", - US_SC_SCSI, US_PR_SCM_ATAPI, init_usbat, + "Shuttle/SCM", + "USBAT-02", + US_SC_SCSI, US_PR_USBAT, init_usbat, US_FL_SINGLE_LUN), #endif @@ -598,6 +612,16 @@ UNUSUAL_DEV( 0x05ac, 0x1205, 0x0000, 0x9999, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_CAPACITY ), +/* + * Reported by Tyson Vinson <lornoss@gmail.com> + * This particular productId is the iPod Nano + */ +UNUSUAL_DEV( 0x05ac, 0x120a, 0x0000, 0x9999, + "Apple", + "iPod", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_FIX_CAPACITY ), + #ifdef CONFIG_USB_STORAGE_JUMPSHOT UNUSUAL_DEV( 0x05dc, 0x0001, 0x0000, 0x0001, "Lexar", @@ -702,6 +726,14 @@ UNUSUAL_DEV( 0x0781, 0x0001, 0x0200, 0x0200, US_SC_SCSI, US_PR_CB, NULL, US_FL_SINGLE_LUN ), +#ifdef CONFIG_USB_STORAGE_USBAT +UNUSUAL_DEV( 0x0781, 0x0005, 0x0005, 0x0005, + "Sandisk", + "ImageMate SDDR-05b", + US_SC_SCSI, US_PR_USBAT, init_usbat, + US_FL_SINGLE_LUN ), +#endif + UNUSUAL_DEV( 0x0781, 0x0100, 0x0100, 0x0100, "Sandisk", "ImageMate SDDR-12", @@ -724,7 +756,7 @@ UNUSUAL_DEV( 0x07ab, 0xfc01, 0x0000, 0x9999, #endif /* Reported by Eero Volotinen <eero@ping-viini.org> */ -UNUSUAL_DEV( 0x07ab, 0xfccd, 0x0406, 0x0406, +UNUSUAL_DEV( 0x07ab, 0xfccd, 0x0000, 0x9999, "Freecom Technologies", "FHD-Classic", US_SC_DEVICE, US_PR_DEVICE, NULL, diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index f9a9bfa1aef5..3847ebed2aa4 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -54,6 +54,7 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> +#include <linux/kthread.h> #include <scsi/scsi.h> #include <scsi/scsi_cmnd.h> @@ -111,11 +112,6 @@ static atomic_t total_threads = ATOMIC_INIT(0); static DECLARE_COMPLETION(threads_gone); -static int storage_probe(struct usb_interface *iface, - const struct usb_device_id *id); - -static void storage_disconnect(struct usb_interface *iface); - /* The entries in this table, except for final ones here * (USB_MASS_STORAGE_CLASS and the empty entry), correspond, * line for line with the entries of us_unsuaul_dev_list[]. @@ -233,13 +229,40 @@ static struct us_unusual_dev us_unusual_dev_list[] = { { NULL } }; -static struct usb_driver usb_storage_driver = { - .owner = THIS_MODULE, - .name = "usb-storage", - .probe = storage_probe, - .disconnect = storage_disconnect, - .id_table = storage_usb_ids, -}; + +#ifdef CONFIG_PM /* Minimal support for suspend and resume */ + +static int storage_suspend(struct usb_interface *iface, pm_message_t message) +{ + struct us_data *us = usb_get_intfdata(iface); + + /* Wait until no command is running */ + down(&us->dev_semaphore); + + US_DEBUGP("%s\n", __FUNCTION__); + iface->dev.power.power_state.event = message.event; + + /* When runtime PM is working, we'll set a flag to indicate + * whether we should autoresume when a SCSI request arrives. */ + + up(&us->dev_semaphore); + return 0; +} + +static int storage_resume(struct usb_interface *iface) +{ + struct us_data *us = usb_get_intfdata(iface); + + down(&us->dev_semaphore); + + US_DEBUGP("%s\n", __FUNCTION__); + iface->dev.power.power_state.event = PM_EVENT_ON; + + up(&us->dev_semaphore); + return 0; +} + +#endif /* CONFIG_PM */ /* * fill_inquiry_response takes an unsigned char array (which must @@ -288,22 +311,7 @@ static int usb_stor_control_thread(void * __us) struct us_data *us = (struct us_data *)__us; struct Scsi_Host *host = us_to_host(us); - lock_kernel(); - - /* - * This thread doesn't need any user-level access, - * so get rid of all our resources. - */ - daemonize("usb-storage"); current->flags |= PF_NOFREEZE; - unlock_kernel(); - - /* acquire a reference to the host, so it won't be deallocated - * until we're ready to exit */ - scsi_host_get(host); - - /* signal that we've started the thread */ - complete(&(us->notify)); for(;;) { US_DEBUGP("*** thread sleeping.\n"); @@ -467,6 +475,12 @@ static int associate_dev(struct us_data *us, struct usb_interface *intf) US_DEBUGP("I/O buffer allocation failed\n"); return -ENOMEM; } + + us->sensebuf = kmalloc(US_SENSE_SIZE, GFP_KERNEL); + if (!us->sensebuf) { + US_DEBUGP("Sense buffer allocation failed\n"); + return -ENOMEM; + } return 0; } @@ -555,8 +569,8 @@ static int get_transport(struct us_data *us) break; #ifdef CONFIG_USB_STORAGE_USBAT - case US_PR_SCM_ATAPI: - us->transport_name = "SCM/ATAPI"; + case US_PR_USBAT: + us->transport_name = "Shuttle USBAT"; us->transport = usbat_transport; us->transport_reset = usb_stor_CB_reset; us->max_lun = 1; @@ -740,6 +754,7 @@ static int get_pipes(struct us_data *us) static int usb_stor_acquire_resources(struct us_data *us) { int p; + struct task_struct *th; us->current_urb = usb_alloc_urb(0, GFP_KERNEL); if (!us->current_urb) { @@ -747,38 +762,28 @@ static int usb_stor_acquire_resources(struct us_data *us) return -ENOMEM; } - /* Lock the device while we carry out the next two operations */ - down(&us->dev_semaphore); - - /* For bulk-only devices, determine the max LUN value */ - if (us->protocol == US_PR_BULK) { - p = usb_stor_Bulk_max_lun(us); - if (p < 0) { - up(&us->dev_semaphore); - return p; - } - us->max_lun = p; - } - /* Just before we start our control thread, initialize * the device if it needs initialization */ - if (us->unusual_dev->initFunction) - us->unusual_dev->initFunction(us); - - up(&us->dev_semaphore); + if (us->unusual_dev->initFunction) { + p = us->unusual_dev->initFunction(us); + if (p) + return p; + } /* Start up our control thread */ - p = kernel_thread(usb_stor_control_thread, us, CLONE_VM); - if (p < 0) { + th = kthread_create(usb_stor_control_thread, us, "usb-storage"); + if (IS_ERR(th)) { printk(KERN_WARNING USB_STORAGE "Unable to start control thread\n"); - return p; + return PTR_ERR(th); } - us->pid = p; - atomic_inc(&total_threads); - /* Wait for the thread to start */ - wait_for_completion(&(us->notify)); + /* Take a reference to the host for the control thread and + * count it among all the threads we have launched. Then + * start it up. */ + scsi_host_get(us_to_host(us)); + atomic_inc(&total_threads); + wake_up_process(th); return 0; } @@ -812,6 +817,8 @@ static void dissociate_dev(struct us_data *us) { US_DEBUGP("-- %s\n", __FUNCTION__); + kfree(us->sensebuf); + /* Free the device-related DMA-mapped buffers */ if (us->cr) usb_buffer_free(us->pusb_dev, sizeof(*us->cr), us->cr, @@ -872,21 +879,6 @@ static int usb_stor_scan_thread(void * __us) { struct us_data *us = (struct us_data *)__us; - /* - * This thread doesn't need any user-level access, - * so get rid of all our resources. - */ - lock_kernel(); - daemonize("usb-stor-scan"); - unlock_kernel(); - - /* Acquire a reference to the host, so it won't be deallocated - * until we're ready to exit */ - scsi_host_get(us_to_host(us)); - - /* Signal that we've started the thread */ - complete(&(us->notify)); - printk(KERN_DEBUG "usb-storage: device found at %d\n", us->pusb_dev->devnum); @@ -904,6 +896,14 @@ retry: /* If the device is still connected, perform the scanning */ if (!test_bit(US_FLIDX_DISCONNECTING, &us->flags)) { + + /* For bulk-only devices, determine the max LUN value */ + if (us->protocol == US_PR_BULK && + !(us->flags & US_FL_SINGLE_LUN)) { + down(&us->dev_semaphore); + us->max_lun = usb_stor_Bulk_max_lun(us); + up(&us->dev_semaphore); + } scsi_scan_host(us_to_host(us)); printk(KERN_DEBUG "usb-storage: device scan complete\n"); @@ -923,6 +923,7 @@ static int storage_probe(struct usb_interface *intf, struct us_data *us; const int id_index = id - storage_usb_ids; int result; + struct task_struct *th; US_DEBUGP("USB Mass Storage device detected\n"); @@ -1003,17 +1004,21 @@ static int storage_probe(struct usb_interface *intf, } /* Start up the thread for delayed SCSI-device scanning */ - result = kernel_thread(usb_stor_scan_thread, us, CLONE_VM); - if (result < 0) { + th = kthread_create(usb_stor_scan_thread, us, "usb-stor-scan"); + if (IS_ERR(th)) { printk(KERN_WARNING USB_STORAGE "Unable to start the device-scanning thread\n"); quiesce_and_remove_host(us); + result = PTR_ERR(th); goto BadDevice; } - atomic_inc(&total_threads); - /* Wait for the thread to start */ - wait_for_completion(&(us->notify)); + /* Take a reference to the host for the scanning thread and + * count it among all the threads we have launched. Then + * start it up. */ + scsi_host_get(us_to_host(us)); + atomic_inc(&total_threads); + wake_up_process(th); return 0; @@ -1038,6 +1043,18 @@ static void storage_disconnect(struct usb_interface *intf) * Initialization and registration ***********************************************************************/ +static struct usb_driver usb_storage_driver = { + .owner = THIS_MODULE, + .name = "usb-storage", + .probe = storage_probe, + .disconnect = storage_disconnect, +#ifdef CONFIG_PM + .suspend = storage_suspend, + .resume = storage_resume, +#endif + .id_table = storage_usb_ids, +}; + static int __init usb_stor_init(void) { int retval; diff --git a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h index a195adae57b6..98b09711a739 100644 --- a/drivers/usb/storage/usb.h +++ b/drivers/usb/storage/usb.h @@ -117,6 +117,7 @@ enum { US_DO_ALL_FLAGS }; */ #define US_IOBUF_SIZE 64 /* Size of the DMA-mapped I/O buffer */ +#define US_SENSE_SIZE 18 /* Size of the autosense data buffer */ typedef int (*trans_cmnd)(struct scsi_cmnd *, struct us_data*); typedef int (*trans_reset)(struct us_data*); @@ -160,14 +161,12 @@ struct us_data { struct scsi_cmnd *srb; /* current srb */ unsigned int tag; /* current dCBWTag */ - /* thread information */ - int pid; /* control thread */ - /* control and bulk communications data */ struct urb *current_urb; /* USB requests */ struct usb_ctrlrequest *cr; /* control requests */ struct usb_sg_request current_sg; /* scatter-gather req. */ unsigned char *iobuf; /* I/O buffer */ + unsigned char *sensebuf; /* sense data buffer */ dma_addr_t cr_dma; /* buffer DMA addresses */ dma_addr_t iobuf_dma; diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c index 353f24d45bc1..6c3a53f8f26c 100644 --- a/drivers/usb/usb-skeleton.c +++ b/drivers/usb/usb-skeleton.c @@ -223,9 +223,8 @@ static struct file_operations skel_fops = { * and to have the device registered with devfs and the driver core */ static struct usb_class_driver skel_class = { - .name = "usb/skel%d", + .name = "skel%d", .fops = &skel_fops, - .mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH, .minor_base = USB_SKEL_MINOR_BASE, }; diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 1cd942abb580..7192b770bfb6 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -494,7 +494,7 @@ config FB_TGA config FB_VESA bool "VESA VGA graphics support" - depends on (FB = y) && (X86 || X86_64) + depends on (FB = y) && X86 select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT @@ -712,7 +712,7 @@ config FB_RIVA_DEBUG config FB_I810 tristate "Intel 810/815 support (EXPERIMENTAL)" - depends on FB && EXPERIMENTAL && PCI && X86 && !X86_64 + depends on FB && EXPERIMENTAL && PCI && X86_32 select AGP select AGP_INTEL select FB_MODE_HELPERS @@ -761,7 +761,7 @@ config FB_I810_I2C config FB_INTEL tristate "Intel 830M/845G/852GM/855GM/865G support (EXPERIMENTAL)" - depends on FB && EXPERIMENTAL && PCI && X86 && !X86_64 + depends on FB && EXPERIMENTAL && PCI && X86_32 select AGP select AGP_INTEL select FB_MODE_HELPERS @@ -1376,7 +1376,7 @@ config FB_HIT config FB_PMAG_AA bool "PMAG-AA TURBOchannel framebuffer support" - depends on (FB = y) && MACH_DECSTATION && TC + depends on (FB = y) && TC select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT @@ -1387,7 +1387,7 @@ config FB_PMAG_AA config FB_PMAG_BA bool "PMAG-BA TURBOchannel framebuffer support" - depends on (FB = y) && MACH_DECSTATION && TC + depends on (FB = y) && TC select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT @@ -1398,7 +1398,7 @@ config FB_PMAG_BA config FB_PMAGB_B bool "PMAGB-B TURBOchannel framebuffer support" - depends on (FB = y) && MACH_DECSTATION && TC + depends on (FB = y) && TC select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT @@ -1410,7 +1410,7 @@ config FB_PMAGB_B config FB_MAXINE bool "Maxine (Personal DECstation) onboard framebuffer support" - depends on (FB = y) && MACH_DECSTATION && TC + depends on (FB = y) && MACH_DECSTATION select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 1fff29f48ca8..97c5d03ac8d9 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -86,7 +86,7 @@ obj-$(CONFIG_FB_CIRRUS) += cirrusfb.o obj-$(CONFIG_FB_ASILIANT) += asiliantfb.o obj-$(CONFIG_FB_PXA) += pxafb.o obj-$(CONFIG_FB_W100) += w100fb.o -obj-$(CONFIG_FB_AU1100) += au1100fb.o fbgen.o +obj-$(CONFIG_FB_AU1100) += au1100fb.o obj-$(CONFIG_FB_PMAG_AA) += pmag-aa-fb.o obj-$(CONFIG_FB_PMAG_BA) += pmag-ba-fb.o obj-$(CONFIG_FB_PMAGB_B) += pmagb-b-fb.o diff --git a/drivers/video/amba-clcd.c b/drivers/video/amba-clcd.c index 321dbe91dc14..cde6fd8eb390 100644 --- a/drivers/video/amba-clcd.c +++ b/drivers/video/amba-clcd.c @@ -22,6 +22,7 @@ #include <linux/ioport.h> #include <linux/list.h> +#include <asm/sizes.h> #include <asm/hardware/amba.h> #include <asm/hardware/clock.h> diff --git a/drivers/video/au1100fb.c b/drivers/video/au1100fb.c index b6fe30c3ad62..a5129806172f 100644 --- a/drivers/video/au1100fb.c +++ b/drivers/video/au1100fb.c @@ -2,6 +2,11 @@ * BRIEF MODULE DESCRIPTION * Au1100 LCD Driver. * + * Rewritten for 2.6 by Embedded Alley Solutions + * <source@embeddedalley.com>, based on submissions by + * Karl Lessard <klessard@sunrisetelecom.com> + * <c.pellegrin@exadron.com> + * * Copyright 2002 MontaVista Software * Author: MontaVista Software, Inc. * ppopov@mvista.com or source@mvista.com @@ -33,298 +38,253 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 675 Mass Ave, Cambridge, MA 02139, USA. */ - +#include <linux/config.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/errno.h> #include <linux/string.h> #include <linux/mm.h> -#include <linux/tty.h> -#include <linux/slab.h> -#include <linux/delay.h> #include <linux/fb.h> #include <linux/init.h> -#include <linux/pci.h> +#include <linux/interrupt.h> +#include <linux/ctype.h> +#include <linux/dma-mapping.h> -#include <asm/au1000.h> -#include <asm/pb1100.h> -#include "au1100fb.h" +#include <asm/mach-au1x00/au1000.h> -#include <video/fbcon.h> -#include <video/fbcon-mfb.h> -#include <video/fbcon-cfb2.h> -#include <video/fbcon-cfb4.h> -#include <video/fbcon-cfb8.h> -#include <video/fbcon-cfb16.h> +#define DEBUG 0 + +#include "au1100fb.h" /* * Sanity check. If this is a new Au1100 based board, search for * the PB1100 ifdefs to make sure you modify the code accordingly. */ -#if defined(CONFIG_MIPS_PB1100) || defined(CONFIG_MIPS_DB1100) || defined(CONFIG_MIPS_HYDROGEN3) +#if defined(CONFIG_MIPS_PB1100) + #include <asm/mach-pb1x00/pb1100.h> +#elif defined(CONFIG_MIPS_DB1100) + #include <asm/mach-db1x00/db1x00.h> #else -error Unknown Au1100 board + #error "Unknown Au1100 board, Au1100 FB driver not supported" #endif -#define CMAPSIZE 16 - -static int my_lcd_index; /* default is zero */ -struct known_lcd_panels *p_lcd; -AU1100_LCD *p_lcd_reg = (AU1100_LCD *)AU1100_LCD_ADDR; - -struct au1100fb_info { - struct fb_info_gen gen; - unsigned long fb_virt_start; - unsigned long fb_size; - unsigned long fb_phys; - int mmaped; - int nohwcursor; +#define DRIVER_NAME "au1100fb" +#define DRIVER_DESC "LCD controller driver for AU1100 processors" - struct { unsigned red, green, blue, pad; } palette[256]; +#define to_au1100fb_device(_info) \ + (_info ? container_of(_info, struct au1100fb_device, info) : NULL); -#if defined(FBCON_HAS_CFB16) - u16 fbcon_cmap16[16]; -#endif +/* Bitfields format supported by the controller. Note that the order of formats + * SHOULD be the same as in the LCD_CONTROL_SBPPF field, so we can retrieve the + * right pixel format by doing rgb_bitfields[LCD_CONTROL_SBPPF_XXX >> LCD_CONTROL_SBPPF] + */ +struct fb_bitfield rgb_bitfields[][4] = +{ + /* Red, Green, Blue, Transp */ + { { 10, 6, 0 }, { 5, 5, 0 }, { 0, 5, 0 }, { 0, 0, 0 } }, + { { 11, 5, 0 }, { 5, 6, 0 }, { 0, 5, 0 }, { 0, 0, 0 } }, + { { 11, 5, 0 }, { 6, 5, 0 }, { 0, 6, 0 }, { 0, 0, 0 } }, + { { 10, 5, 0 }, { 5, 5, 0 }, { 0, 5, 0 }, { 15, 1, 0 } }, + { { 11, 5, 0 }, { 6, 5, 0 }, { 1, 5, 0 }, { 0, 1, 0 } }, + + /* The last is used to describe 12bpp format */ + { { 8, 4, 0 }, { 4, 4, 0 }, { 0, 4, 0 }, { 0, 0, 0 } }, }; - -struct au1100fb_par { - struct fb_var_screeninfo var; - - int line_length; // in bytes - int cmap_len; // color-map length +static struct fb_fix_screeninfo au1100fb_fix __initdata = { + .id = "AU1100 FB", + .xpanstep = 1, + .ypanstep = 1, + .type = FB_TYPE_PACKED_PIXELS, + .accel = FB_ACCEL_NONE, }; - -static struct au1100fb_info fb_info; -static struct au1100fb_par current_par; -static struct display disp; - -int au1100fb_init(void); -void au1100fb_setup(char *options, int *ints); -static int au1100fb_mmap(struct fb_info *fb, struct file *file, - struct vm_area_struct *vma); -static int au1100_blank(int blank_mode, struct fb_info_gen *info); -static int au1100fb_ioctl(struct inode *inode, struct file *file, u_int cmd, - u_long arg, int con, struct fb_info *info); - -void au1100_nocursor(struct display *p, int mode, int xx, int yy){}; - -static struct fb_ops au1100fb_ops = { - .owner = THIS_MODULE, - .fb_get_fix = fbgen_get_fix, - .fb_get_var = fbgen_get_var, - .fb_set_var = fbgen_set_var, - .fb_get_cmap = fbgen_get_cmap, - .fb_set_cmap = fbgen_set_cmap, - .fb_pan_display = fbgen_pan_display, - .fb_ioctl = au1100fb_ioctl, - .fb_mmap = au1100fb_mmap, +static struct fb_var_screeninfo au1100fb_var __initdata = { + .activate = FB_ACTIVATE_NOW, + .height = -1, + .width = -1, + .vmode = FB_VMODE_NONINTERLACED, }; -static void au1100_detect(void) -{ - /* - * This function should detect the current video mode settings - * and store it as the default video mode - */ +static struct au1100fb_drv_info drv_info; - /* - * Yeh, well, we're not going to change any settings so we're - * always stuck with the default ... +/* + * Set hardware with var settings. This will enable the controller with a specific + * mode, normally validated with the fb_check_var method */ - -} - -static int au1100_encode_fix(struct fb_fix_screeninfo *fix, - const void *_par, struct fb_info_gen *_info) +int au1100fb_setmode(struct au1100fb_device *fbdev) { - struct au1100fb_info *info = (struct au1100fb_info *) _info; - struct au1100fb_par *par = (struct au1100fb_par *) _par; - struct fb_var_screeninfo *var = &par->var; - - memset(fix, 0, sizeof(struct fb_fix_screeninfo)); - - fix->smem_start = info->fb_phys; - fix->smem_len = info->fb_size; - fix->type = FB_TYPE_PACKED_PIXELS; - fix->type_aux = 0; - fix->visual = (var->bits_per_pixel == 8) ? - FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; - fix->ywrapstep = 0; - fix->xpanstep = 1; - fix->ypanstep = 1; - fix->line_length = current_par.line_length; - return 0; -} + struct fb_info *info = &fbdev->info; + u32 words; + int index; -static void set_color_bitfields(struct fb_var_screeninfo *var) -{ - switch (var->bits_per_pixel) { - case 8: - var->red.offset = 0; - var->red.length = 8; - var->green.offset = 0; - var->green.length = 8; - var->blue.offset = 0; - var->blue.length = 8; - var->transp.offset = 0; - var->transp.length = 0; - break; - case 16: /* RGB 565 */ - var->red.offset = 11; - var->red.length = 5; - var->green.offset = 5; - var->green.length = 6; - var->blue.offset = 0; - var->blue.length = 5; - var->transp.offset = 0; - var->transp.length = 0; - break; + if (!fbdev) + return -EINVAL; + + /* Update var-dependent FB info */ + if (panel_is_active(fbdev->panel) || panel_is_color(fbdev->panel)) { + if (info->var.bits_per_pixel <= 8) { + /* palettized */ + info->var.red.offset = 0; + info->var.red.length = info->var.bits_per_pixel; + info->var.red.msb_right = 0; + + info->var.green.offset = 0; + info->var.green.length = info->var.bits_per_pixel; + info->var.green.msb_right = 0; + + info->var.blue.offset = 0; + info->var.blue.length = info->var.bits_per_pixel; + info->var.blue.msb_right = 0; + + info->var.transp.offset = 0; + info->var.transp.length = 0; + info->var.transp.msb_right = 0; + + info->fix.visual = FB_VISUAL_PSEUDOCOLOR; + info->fix.line_length = info->var.xres_virtual / + (8/info->var.bits_per_pixel); + } else { + /* non-palettized */ + index = (fbdev->panel->control_base & LCD_CONTROL_SBPPF_MASK) >> LCD_CONTROL_SBPPF_BIT; + info->var.red = rgb_bitfields[index][0]; + info->var.green = rgb_bitfields[index][1]; + info->var.blue = rgb_bitfields[index][2]; + info->var.transp = rgb_bitfields[index][3]; + + info->fix.visual = FB_VISUAL_TRUECOLOR; + info->fix.line_length = info->var.xres_virtual << 1; /* depth=16 */ + } + } else { + /* mono */ + info->fix.visual = FB_VISUAL_MONO10; + info->fix.line_length = info->var.xres_virtual / 8; } - var->red.msb_right = 0; - var->green.msb_right = 0; - var->blue.msb_right = 0; - var->transp.msb_right = 0; -} + info->screen_size = info->fix.line_length * info->var.yres_virtual; -static int au1100_decode_var(const struct fb_var_screeninfo *var, - void *_par, struct fb_info_gen *_info) -{ + /* Determine BPP mode and format */ + fbdev->regs->lcd_control = fbdev->panel->control_base | + ((info->var.rotate/90) << LCD_CONTROL_SM_BIT); - struct au1100fb_par *par = (struct au1100fb_par *)_par; + fbdev->regs->lcd_intenable = 0; + fbdev->regs->lcd_intstatus = 0; - /* - * Don't allow setting any of these yet: xres and yres don't - * make sense for LCD panels. - */ - if (var->xres != p_lcd->xres || - var->yres != p_lcd->yres || - var->xres != p_lcd->xres || - var->yres != p_lcd->yres) { - return -EINVAL; - } - if(var->bits_per_pixel != p_lcd->bpp) { - return -EINVAL; - } + fbdev->regs->lcd_horztiming = fbdev->panel->horztiming; - memset(par, 0, sizeof(struct au1100fb_par)); - par->var = *var; - - /* FIXME */ - switch (var->bits_per_pixel) { - case 8: - par->var.bits_per_pixel = 8; - break; - case 16: - par->var.bits_per_pixel = 16; - break; - default: - printk("color depth %d bpp not supported\n", - var->bits_per_pixel); - return -EINVAL; + fbdev->regs->lcd_verttiming = fbdev->panel->verttiming; + + fbdev->regs->lcd_clkcontrol = fbdev->panel->clkcontrol_base; + fbdev->regs->lcd_dmaaddr0 = LCD_DMA_SA_N(fbdev->fb_phys); + + if (panel_is_dual(fbdev->panel)) { + /* Second panel display seconf half of screen if possible, + * otherwise display the same as the first panel */ + if (info->var.yres_virtual >= (info->var.yres << 1)) { + fbdev->regs->lcd_dmaaddr1 = LCD_DMA_SA_N(fbdev->fb_phys + + (info->fix.line_length * + (info->var.yres_virtual >> 1))); + } else { + fbdev->regs->lcd_dmaaddr1 = LCD_DMA_SA_N(fbdev->fb_phys); + } } - set_color_bitfields(&par->var); - par->cmap_len = (par->var.bits_per_pixel == 8) ? 256 : 16; - return 0; -} -static int au1100_encode_var(struct fb_var_screeninfo *var, - const void *par, struct fb_info_gen *_info) -{ + words = info->fix.line_length / sizeof(u32); + if (!info->var.rotate || (info->var.rotate == 180)) { + words *= info->var.yres_virtual; + if (info->var.rotate /* 180 */) { + words -= (words % 8); /* should be divisable by 8 */ + } + } + fbdev->regs->lcd_words = LCD_WRD_WRDS_N(words); - *var = ((struct au1100fb_par *)par)->var; - return 0; -} + fbdev->regs->lcd_pwmdiv = 0; + fbdev->regs->lcd_pwmhi = 0; -static void -au1100_get_par(void *_par, struct fb_info_gen *_info) -{ - *(struct au1100fb_par *)_par = current_par; -} + /* Resume controller */ + fbdev->regs->lcd_control |= LCD_CONTROL_GO; -static void au1100_set_par(const void *par, struct fb_info_gen *info) -{ - /* nothing to do: we don't change any settings */ + return 0; } -static int au1100_getcolreg(unsigned regno, unsigned *red, unsigned *green, - unsigned *blue, unsigned *transp, - struct fb_info *info) +/* fb_setcolreg + * Set color in LCD palette. + */ +int au1100fb_fb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *fbi) { + struct au1100fb_device *fbdev = to_au1100fb_device(fbi); + u32 *palette = fbdev->regs->lcd_pallettebase; + u32 value; - struct au1100fb_info* i = (struct au1100fb_info*)info; - - if (regno > 255) - return 1; + if (regno > (AU1100_LCD_NBR_PALETTE_ENTRIES - 1)) + return -EINVAL; - *red = i->palette[regno].red; - *green = i->palette[regno].green; - *blue = i->palette[regno].blue; - *transp = 0; + if (fbi->var.grayscale) { + /* Convert color to grayscale */ + red = green = blue = + (19595 * red + 38470 * green + 7471 * blue) >> 16; + } - return 0; -} + if (fbi->fix.visual == FB_VISUAL_TRUECOLOR) { + /* Place color in the pseudopalette */ + if (regno > 16) + return -EINVAL; -static int au1100_setcolreg(unsigned regno, unsigned red, unsigned green, - unsigned blue, unsigned transp, - struct fb_info *info) -{ - struct au1100fb_info* i = (struct au1100fb_info *)info; - u32 rgbcol; - - if (regno > 255) - return 1; - - i->palette[regno].red = red; - i->palette[regno].green = green; - i->palette[regno].blue = blue; - - switch(p_lcd->bpp) { -#ifdef FBCON_HAS_CFB8 - case 8: - red >>= 10; - green >>= 10; - blue >>= 10; - p_lcd_reg->lcd_pallettebase[regno] = (blue&0x1f) | - ((green&0x3f)<<5) | ((red&0x1f)<<11); - break; -#endif -#ifdef FBCON_HAS_CFB16 - case 16: - i->fbcon_cmap16[regno] = - ((red & 0xf800) >> 0) | - ((green & 0xfc00) >> 5) | - ((blue & 0xf800) >> 11); - break; -#endif - default: - break; + palette = (u32*)fbi->pseudo_palette; + + red >>= (16 - fbi->var.red.length); + green >>= (16 - fbi->var.green.length); + blue >>= (16 - fbi->var.blue.length); + + value = (red << fbi->var.red.offset) | + (green << fbi->var.green.offset)| + (blue << fbi->var.blue.offset); + value &= 0xFFFF; + + } else if (panel_is_active(fbdev->panel)) { + /* COLOR TFT PALLETTIZED (use RGB 565) */ + value = (red & 0xF800)|((green >> 5) & 0x07E0)|((blue >> 11) & 0x001F); + value &= 0xFFFF; + + } else if (panel_is_color(fbdev->panel)) { + /* COLOR STN MODE */ + value = (((panel_swap_rgb(fbdev->panel) ? blue : red) >> 12) & 0x000F) | + ((green >> 8) & 0x00F0) | + (((panel_swap_rgb(fbdev->panel) ? red : blue) >> 4) & 0x0F00); + value &= 0xFFF; + } else { + /* MONOCHROME MODE */ + value = (green >> 12) & 0x000F; + value &= 0xF; } + palette[regno] = value; + return 0; } - -static int au1100_blank(int blank_mode, struct fb_info_gen *_info) +/* fb_blank + * Blank the screen. Depending on the mode, the screen will be + * activated with the backlight color, or desactivated + */ +int au1100fb_fb_blank(int blank_mode, struct fb_info *fbi) { + struct au1100fb_device *fbdev = to_au1100fb_device(fbi); + + print_dbg("fb_blank %d %p", blank_mode, fbi); switch (blank_mode) { + case VESA_NO_BLANKING: - /* turn on panel */ - //printk("turn on panel\n"); + /* Turn on panel */ + fbdev->regs->lcd_control |= LCD_CONTROL_GO; #ifdef CONFIG_MIPS_PB1100 - p_lcd_reg->lcd_control |= LCD_CONTROL_GO; - au_writew(au_readw(PB1100_G_CONTROL) | p_lcd->mode_backlight, + if (drv_info.panel_idx == 1) { + au_writew(au_readw(PB1100_G_CONTROL) + | (PB1100_G_CONTROL_BL | PB1100_G_CONTROL_VDD), PB1100_G_CONTROL); -#endif -#ifdef CONFIG_MIPS_HYDROGEN3 - /* Turn controller & power supply on, GPIO213 */ - au_writel(0x20002000, 0xB1700008); - au_writel(0x00040000, 0xB1900108); - au_writel(0x01000100, 0xB1700008); + } #endif au_sync(); break; @@ -332,12 +292,14 @@ static int au1100_blank(int blank_mode, struct fb_info_gen *_info) case VESA_VSYNC_SUSPEND: case VESA_HSYNC_SUSPEND: case VESA_POWERDOWN: - /* turn off panel */ - //printk("turn off panel\n"); + /* Turn off panel */ + fbdev->regs->lcd_control &= ~LCD_CONTROL_GO; #ifdef CONFIG_MIPS_PB1100 - au_writew(au_readw(PB1100_G_CONTROL) & ~p_lcd->mode_backlight, + if (drv_info.panel_idx == 1) { + au_writew(au_readw(PB1100_G_CONTROL) + & ~(PB1100_G_CONTROL_BL | PB1100_G_CONTROL_VDD), PB1100_G_CONTROL); - p_lcd_reg->lcd_control &= ~LCD_CONTROL_GO; + } #endif au_sync(); break; @@ -348,49 +310,87 @@ static int au1100_blank(int blank_mode, struct fb_info_gen *_info) return 0; } -static void au1100_set_disp(const void *unused, struct display *disp, - struct fb_info_gen *info) +/* fb_pan_display + * Pan display in x and/or y as specified + */ +int au1100fb_fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *fbi) { - disp->screen_base = (char *)fb_info.fb_virt_start; - - switch (disp->var.bits_per_pixel) { -#ifdef FBCON_HAS_CFB8 - case 8: - disp->dispsw = &fbcon_cfb8; - if (fb_info.nohwcursor) - fbcon_cfb8.cursor = au1100_nocursor; - break; -#endif -#ifdef FBCON_HAS_CFB16 - case 16: - disp->dispsw = &fbcon_cfb16; - disp->dispsw_data = fb_info.fbcon_cmap16; - if (fb_info.nohwcursor) - fbcon_cfb16.cursor = au1100_nocursor; - break; -#endif - default: - disp->dispsw = &fbcon_dummy; - disp->dispsw_data = NULL; - break; + struct au1100fb_device *fbdev = to_au1100fb_device(fbi); + int dy; + + print_dbg("fb_pan_display %p %p", var, fbi); + + if (!var || !fbdev) { + return -EINVAL; + } + + if (var->xoffset - fbi->var.xoffset) { + /* No support for X panning for now! */ + return -EINVAL; + } + + print_dbg("fb_pan_display 2 %p %p", var, fbi); + dy = var->yoffset - fbi->var.yoffset; + if (dy) { + + u32 dmaaddr; + + print_dbg("Panning screen of %d lines", dy); + + dmaaddr = fbdev->regs->lcd_dmaaddr0; + dmaaddr += (fbi->fix.line_length * dy); + + /* TODO: Wait for current frame to finished */ + fbdev->regs->lcd_dmaaddr0 = LCD_DMA_SA_N(dmaaddr); + + if (panel_is_dual(fbdev->panel)) { + dmaaddr = fbdev->regs->lcd_dmaaddr1; + dmaaddr += (fbi->fix.line_length * dy); + fbdev->regs->lcd_dmaaddr0 = LCD_DMA_SA_N(dmaaddr); + } + } + print_dbg("fb_pan_display 3 %p %p", var, fbi); + + return 0; +} + +/* fb_rotate + * Rotate the display of this angle. This doesn't seems to be used by the core, + * but as our hardware supports it, so why not implementing it... + */ +void au1100fb_fb_rotate(struct fb_info *fbi, int angle) +{ + struct au1100fb_device *fbdev = to_au1100fb_device(fbi); + + print_dbg("fb_rotate %p %d", fbi, angle); + + if (fbdev && (angle > 0) && !(angle % 90)) { + + fbdev->regs->lcd_control &= ~LCD_CONTROL_GO; + + fbdev->regs->lcd_control &= ~(LCD_CONTROL_SM_MASK); + fbdev->regs->lcd_control |= ((angle/90) << LCD_CONTROL_SM_BIT); + + fbdev->regs->lcd_control |= LCD_CONTROL_GO; } } -static int -au1100fb_mmap(struct fb_info *_fb, - struct file *file, - struct vm_area_struct *vma) +/* fb_mmap + * Map video memory in user space. We don't use the generic fb_mmap method mainly + * to allow the use of the TLB streaming flag (CCA=6) + */ +int au1100fb_fb_mmap(struct fb_info *fbi, struct file *file, struct vm_area_struct *vma) { + struct au1100fb_device *fbdev = to_au1100fb_device(fbi); unsigned int len; unsigned long start=0, off; - struct au1100fb_info *fb = (struct au1100fb_info *)_fb; if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) { return -EINVAL; } - start = fb_info.fb_phys & PAGE_MASK; - len = PAGE_ALIGN((start & ~PAGE_MASK) + fb_info.fb_size); + start = fbdev->fb_phys & PAGE_MASK; + len = PAGE_ALIGN((start & ~PAGE_MASK) + fbdev->fb_len); off = vma->vm_pgoff << PAGE_SHIFT; @@ -401,276 +401,309 @@ au1100fb_mmap(struct fb_info *_fb, off += start; vma->vm_pgoff = off >> PAGE_SHIFT; - pgprot_val(vma->vm_page_prot) &= ~_CACHE_MASK; - //pgprot_val(vma->vm_page_prot) |= _CACHE_CACHABLE_NONCOHERENT; + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); pgprot_val(vma->vm_page_prot) |= (6 << 9); //CCA=6 - /* This is an IO map - tell maydump to skip this VMA */ vma->vm_flags |= VM_IO; - if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, + if (io_remap_page_range(vma, vma->vm_start, off, vma->vm_end - vma->vm_start, vma->vm_page_prot)) { return -EAGAIN; } - fb->mmaped = 1; return 0; } -int au1100_pan_display(const struct fb_var_screeninfo *var, - struct fb_info_gen *info) +static struct fb_ops au1100fb_ops = { - return 0; -} + .owner = THIS_MODULE, + .fb_setcolreg = au1100fb_fb_setcolreg, + .fb_blank = au1100fb_fb_blank, + .fb_pan_display = au1100fb_fb_pan_display, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_rotate = au1100fb_fb_rotate, + .fb_mmap = au1100fb_fb_mmap, +}; -static int au1100fb_ioctl(struct inode *inode, struct file *file, u_int cmd, - u_long arg, int con, struct fb_info *info) -{ - /* nothing to do yet */ - return -EINVAL; -} -static struct fbgen_hwswitch au1100_switch = { - au1100_detect, - au1100_encode_fix, - au1100_decode_var, - au1100_encode_var, - au1100_get_par, - au1100_set_par, - au1100_getcolreg, - au1100_setcolreg, - au1100_pan_display, - au1100_blank, - au1100_set_disp -}; +/*-------------------------------------------------------------------------*/ +/* AU1100 LCD controller device driver */ -int au1100_setmode(void) +int au1100fb_drv_probe(struct device *dev) { - int words; - - /* FIXME Need to accomodate for swivel mode and 12bpp, <8bpp*/ - switch (p_lcd->mode_control & LCD_CONTROL_SM) - { - case LCD_CONTROL_SM_0: - case LCD_CONTROL_SM_180: - words = (p_lcd->xres * p_lcd->yres * p_lcd->bpp) / 32; - break; - case LCD_CONTROL_SM_90: - case LCD_CONTROL_SM_270: - /* is this correct? */ - words = (p_lcd->xres * p_lcd->bpp) / 8; - break; - default: - printk("mode_control reg not initialized\n"); + struct au1100fb_device *fbdev = NULL; + struct resource *regs_res; + unsigned long page; + u32 sys_clksrc; + + if (!dev) return -EINVAL; + + /* Allocate new device private */ + if (!(fbdev = kmalloc(sizeof(struct au1100fb_device), GFP_KERNEL))) { + print_err("fail to allocate device private record"); + return -ENOMEM; } + memset((void*)fbdev, 0, sizeof(struct au1100fb_device)); - /* - * Setup LCD controller - */ + fbdev->panel = &known_lcd_panels[drv_info.panel_idx]; - p_lcd_reg->lcd_control = p_lcd->mode_control; - p_lcd_reg->lcd_intstatus = 0; - p_lcd_reg->lcd_intenable = 0; - p_lcd_reg->lcd_horztiming = p_lcd->mode_horztiming; - p_lcd_reg->lcd_verttiming = p_lcd->mode_verttiming; - p_lcd_reg->lcd_clkcontrol = p_lcd->mode_clkcontrol; - p_lcd_reg->lcd_words = words - 1; - p_lcd_reg->lcd_dmaaddr0 = fb_info.fb_phys; + dev_set_drvdata(dev, (void*)fbdev); - /* turn on panel */ -#ifdef CONFIG_MIPS_PB1100 - au_writew(au_readw(PB1100_G_CONTROL) | p_lcd->mode_backlight, - PB1100_G_CONTROL); -#endif -#ifdef CONFIG_MIPS_HYDROGEN3 - /* Turn controller & power supply on, GPIO213 */ - au_writel(0x20002000, 0xB1700008); - au_writel(0x00040000, 0xB1900108); - au_writel(0x01000100, 0xB1700008); -#endif + /* Allocate region for our registers and map them */ + if (!(regs_res = platform_get_resource(to_platform_device(dev), + IORESOURCE_MEM, 0))) { + print_err("fail to retrieve registers resource"); + return -EFAULT; + } - p_lcd_reg->lcd_control |= LCD_CONTROL_GO; + au1100fb_fix.mmio_start = regs_res->start; + au1100fb_fix.mmio_len = regs_res->end - regs_res->start + 1; - return 0; -} + if (!request_mem_region(au1100fb_fix.mmio_start, au1100fb_fix.mmio_len, + DRIVER_NAME)) { + print_err("fail to lock memory region at 0x%08x", + au1100fb_fix.mmio_start); + return -EBUSY; + } + fbdev->regs = (struct au1100fb_regs*)KSEG1ADDR(au1100fb_fix.mmio_start); -int __init au1100fb_init(void) -{ - uint32 sys_clksrc; - unsigned long page; + print_dbg("Register memory map at %p", fbdev->regs); + print_dbg("phys=0x%08x, size=%d", fbdev->regs_phys, fbdev->regs_len); - /* - * Get the panel information/display mode and update the registry - */ - p_lcd = &panels[my_lcd_index]; - - switch (p_lcd->mode_control & LCD_CONTROL_SM) - { - case LCD_CONTROL_SM_0: - case LCD_CONTROL_SM_180: - p_lcd->xres = - (p_lcd->mode_horztiming & LCD_HORZTIMING_PPL) + 1; - p_lcd->yres = - (p_lcd->mode_verttiming & LCD_VERTTIMING_LPP) + 1; - break; - case LCD_CONTROL_SM_90: - case LCD_CONTROL_SM_270: - p_lcd->yres = - (p_lcd->mode_horztiming & LCD_HORZTIMING_PPL) + 1; - p_lcd->xres = - (p_lcd->mode_verttiming & LCD_VERTTIMING_LPP) + 1; - break; - } - /* - * Panel dimensions x bpp must be divisible by 32 - */ - if (((p_lcd->yres * p_lcd->bpp) % 32) != 0) - printk("VERT %% 32\n"); - if (((p_lcd->xres * p_lcd->bpp) % 32) != 0) - printk("HORZ %% 32\n"); - /* - * Allocate LCD framebuffer from system memory - */ - fb_info.fb_size = (p_lcd->xres * p_lcd->yres * p_lcd->bpp) / 8; - - current_par.var.xres = p_lcd->xres; - current_par.var.xres_virtual = p_lcd->xres; - current_par.var.yres = p_lcd->yres; - current_par.var.yres_virtual = p_lcd->yres; - current_par.var.bits_per_pixel = p_lcd->bpp; - - /* FIX!!! only works for 8/16 bpp */ - current_par.line_length = p_lcd->xres * p_lcd->bpp / 8; /* in bytes */ - fb_info.fb_virt_start = (unsigned long ) - __get_free_pages(GFP_ATOMIC | GFP_DMA, - get_order(fb_info.fb_size + 0x1000)); - if (!fb_info.fb_virt_start) { - printk("Unable to allocate fb memory\n"); + /* Allocate the framebuffer to the maximum screen size * nbr of video buffers */ + fbdev->fb_len = fbdev->panel->xres * fbdev->panel->yres * + (fbdev->panel->bpp >> 3) * AU1100FB_NBR_VIDEO_BUFFERS; + + fbdev->fb_mem = dma_alloc_coherent(dev, PAGE_ALIGN(fbdev->fb_len), + &fbdev->fb_phys, GFP_KERNEL); + if (!fbdev->fb_mem) { + print_err("fail to allocate frambuffer (size: %dK))", + fbdev->fb_len / 1024); return -ENOMEM; } - fb_info.fb_phys = virt_to_bus((void *)fb_info.fb_virt_start); + + au1100fb_fix.smem_start = fbdev->fb_phys; + au1100fb_fix.smem_len = fbdev->fb_len; /* * Set page reserved so that mmap will work. This is necessary * since we'll be remapping normal memory. */ - for (page = fb_info.fb_virt_start; - page < PAGE_ALIGN(fb_info.fb_virt_start + fb_info.fb_size); + for (page = (unsigned long)fbdev->fb_mem; + page < PAGE_ALIGN((unsigned long)fbdev->fb_mem + fbdev->fb_len); page += PAGE_SIZE) { +#if CONFIG_DMA_NONCOHERENT + SetPageReserved(virt_to_page(CAC_ADDR(page))); +#else SetPageReserved(virt_to_page(page)); +#endif } - memset((void *)fb_info.fb_virt_start, 0, fb_info.fb_size); - - /* set freqctrl now to allow more time to stabilize */ - /* zero-out out LCD bits */ - sys_clksrc = au_readl(SYS_CLKSRC) & ~0x000003e0; - sys_clksrc |= p_lcd->mode_toyclksrc; - au_writel(sys_clksrc, SYS_CLKSRC); - - /* FIXME add check to make sure auxpll is what is expected! */ - au1100_setmode(); - - fb_info.gen.parsize = sizeof(struct au1100fb_par); - fb_info.gen.fbhw = &au1100_switch; - - strcpy(fb_info.gen.info.modename, "Au1100 LCD"); - fb_info.gen.info.changevar = NULL; - fb_info.gen.info.node = -1; - - fb_info.gen.info.fbops = &au1100fb_ops; - fb_info.gen.info.disp = &disp; - fb_info.gen.info.switch_con = &fbgen_switch; - fb_info.gen.info.updatevar = &fbgen_update_var; - fb_info.gen.info.blank = &fbgen_blank; - fb_info.gen.info.flags = FBINFO_FLAG_DEFAULT; - - /* This should give a reasonable default video mode */ - fbgen_get_var(&disp.var, -1, &fb_info.gen.info); - fbgen_do_set_var(&disp.var, 1, &fb_info.gen); - fbgen_set_disp(-1, &fb_info.gen); - fbgen_install_cmap(0, &fb_info.gen); - if (register_framebuffer(&fb_info.gen.info) < 0) - return -EINVAL; - printk(KERN_INFO "fb%d: %s frame buffer device\n", - GET_FB_IDX(fb_info.gen.info.node), - fb_info.gen.info.modename); + print_dbg("Framebuffer memory map at %p", fbdev->fb_mem); + print_dbg("phys=0x%08x, size=%dK", fbdev->fb_phys, fbdev->fb_len / 1024); + + /* Setup LCD clock to AUX (48 MHz) */ + sys_clksrc = au_readl(SYS_CLKSRC) & ~(SYS_CS_ML_MASK | SYS_CS_DL | SYS_CS_CL); + au_writel((sys_clksrc | (1 << SYS_CS_ML_BIT)), SYS_CLKSRC); + + /* load the panel info into the var struct */ + au1100fb_var.bits_per_pixel = fbdev->panel->bpp; + au1100fb_var.xres = fbdev->panel->xres; + au1100fb_var.xres_virtual = au1100fb_var.xres; + au1100fb_var.yres = fbdev->panel->yres; + au1100fb_var.yres_virtual = au1100fb_var.yres; + + fbdev->info.screen_base = fbdev->fb_mem; + fbdev->info.fbops = &au1100fb_ops; + fbdev->info.fix = au1100fb_fix; + + if (!(fbdev->info.pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL))) { + return -ENOMEM; + } + memset(fbdev->info.pseudo_palette, 0, sizeof(u32) * 16); + + if (fb_alloc_cmap(&fbdev->info.cmap, AU1100_LCD_NBR_PALETTE_ENTRIES, 0) < 0) { + print_err("Fail to allocate colormap (%d entries)", + AU1100_LCD_NBR_PALETTE_ENTRIES); + kfree(fbdev->info.pseudo_palette); + return -EFAULT; + } + + fbdev->info.var = au1100fb_var; + + /* Set h/w registers */ + au1100fb_setmode(fbdev); + + /* Register new framebuffer */ + if (register_framebuffer(&fbdev->info) < 0) { + print_err("cannot register new framebuffer"); + goto failed; + } + + return 0; + +failed: + if (fbdev->regs) { + release_mem_region(fbdev->regs_phys, fbdev->regs_len); + } + if (fbdev->fb_mem) { + dma_free_noncoherent(dev, fbdev->fb_len, fbdev->fb_mem, fbdev->fb_phys); + } + if (fbdev->info.cmap.len != 0) { + fb_dealloc_cmap(&fbdev->info.cmap); + } + kfree(fbdev); + dev_set_drvdata(dev, NULL); return 0; } +int au1100fb_drv_remove(struct device *dev) +{ + struct au1100fb_device *fbdev = NULL; + + if (!dev) + return -ENODEV; + + fbdev = (struct au1100fb_device*) dev_get_drvdata(dev); + +#if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO) + au1100fb_fb_blank(VESA_POWERDOWN, &fbdev->info); +#endif + fbdev->regs->lcd_control &= ~LCD_CONTROL_GO; -void au1100fb_cleanup(struct fb_info *info) + /* Clean up all probe data */ + unregister_framebuffer(&fbdev->info); + + release_mem_region(fbdev->regs_phys, fbdev->regs_len); + + dma_free_coherent(dev, PAGE_ALIGN(fbdev->fb_len), fbdev->fb_mem, fbdev->fb_phys); + + fb_dealloc_cmap(&fbdev->info.cmap); + kfree(fbdev->info.pseudo_palette); + kfree((void*)fbdev); + + return 0; +} + +int au1100fb_drv_suspend(struct device *dev, u32 state, u32 level) +{ + /* TODO */ + return 0; +} + +int au1100fb_drv_resume(struct device *dev, u32 level) { - unregister_framebuffer(info); + /* TODO */ + return 0; } +static struct device_driver au1100fb_driver = { + .name = "au1100-lcd", + .bus = &platform_bus_type, -void au1100fb_setup(char *options, int *ints) + .probe = au1100fb_drv_probe, + .remove = au1100fb_drv_remove, + .suspend = au1100fb_drv_suspend, + .resume = au1100fb_drv_resume, +}; + +/*-------------------------------------------------------------------------*/ + +/* Kernel driver */ + +int au1100fb_setup(char *options) { char* this_opt; - int i; - int num_panels = sizeof(panels)/sizeof(struct known_lcd_panels); + int num_panels = ARRAY_SIZE(known_lcd_panels); + char* mode = NULL; + int panel_idx = 0; + if (num_panels <= 0) { + print_err("No LCD panels supported by driver!"); + return -EFAULT; + } - if (!options || !*options) - return; - - for(this_opt=strtok(options, ","); this_opt; - this_opt=strtok(NULL, ",")) { + if (options) { + while ((this_opt = strsep(&options,",")) != NULL) { + /* Panel option */ if (!strncmp(this_opt, "panel:", 6)) { -#if defined(CONFIG_MIPS_PB1100) || defined(CONFIG_MIPS_DB1100) - /* Read Pb1100 Switch S10 ? */ - if (!strncmp(this_opt+6, "s10", 3)) - { - int panel; - panel = *(volatile int *)0xAE000008; /* BCSR SWITCHES */ - panel >>= 8; - panel &= 0x0F; - if (panel >= num_panels) panel = 0; - my_lcd_index = panel; - } - else -#endif - /* Get the panel name, everything else if fixed */ - for (i=0; i<num_panels; i++) { - if (!strncmp(this_opt+6, panels[i].panel_name, + int i; + this_opt += 6; + for (i = 0; i < num_panels; i++) { + if (!strncmp(this_opt, + known_lcd_panels[i].name, strlen(this_opt))) { - my_lcd_index = i; + panel_idx = i; break; } } + if (i >= num_panels) { + print_warn("Panel %s not supported!", this_opt); + } + } + /* Mode option (only option that start with digit) */ + else if (isdigit(this_opt[0])) { + mode = kmalloc(strlen(this_opt) + 1, GFP_KERNEL); + strncpy(mode, this_opt, strlen(this_opt) + 1); + } + /* Unsupported option */ + else { + print_warn("Unsupported option \"%s\"", this_opt); } - else if (!strncmp(this_opt, "nohwcursor", 10)) { - printk("nohwcursor\n"); - fb_info.nohwcursor = 1; } } - printk("au1100fb: Panel %d %s\n", my_lcd_index, - panels[my_lcd_index].panel_name); -} + drv_info.panel_idx = panel_idx; + drv_info.opt_mode = mode; + print_info("Panel=%s Mode=%s", + known_lcd_panels[drv_info.panel_idx].name, + drv_info.opt_mode ? drv_info.opt_mode : "default"); + return 0; +} -#ifdef MODULE -MODULE_LICENSE("GPL"); -int init_module(void) +int __init au1100fb_init(void) { - return au1100fb_init(); + char* options; + int ret; + + print_info("" DRIVER_DESC ""); + + memset(&drv_info, 0, sizeof(drv_info)); + + if (fb_get_options(DRIVER_NAME, &options)) + return -ENODEV; + + /* Setup driver with options */ + ret = au1100fb_setup(options); + if (ret < 0) { + print_err("Fail to setup driver"); + return ret; + } + + return driver_register(&au1100fb_driver); } -void cleanup_module(void) +void __exit au1100fb_cleanup(void) { - au1100fb_cleanup(void); + driver_unregister(&au1100fb_driver); + + if (drv_info.opt_mode) + kfree(drv_info.opt_mode); } -MODULE_AUTHOR("Pete Popov <ppopov@mvista.com>"); -MODULE_DESCRIPTION("Au1100 LCD framebuffer device driver"); -#endif /* MODULE */ +module_init(au1100fb_init); +module_exit(au1100fb_cleanup); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/au1100fb.h b/drivers/video/au1100fb.h index 657c560ab73c..2855534dc235 100644 --- a/drivers/video/au1100fb.h +++ b/drivers/video/au1100fb.h @@ -30,352 +30,352 @@ #ifndef _AU1100LCD_H #define _AU1100LCD_H +#include <asm/mach-au1x00/au1000.h> + +#define print_err(f, arg...) printk(KERN_ERR DRIVER_NAME ": " f "\n", ## arg) +#define print_warn(f, arg...) printk(KERN_WARNING DRIVER_NAME ": " f "\n", ## arg) +#define print_info(f, arg...) printk(KERN_INFO DRIVER_NAME ": " f "\n", ## arg) + +#if DEBUG +#define print_dbg(f, arg...) printk(__FILE__ ": " f "\n", ## arg) +#else +#define print_dbg(f, arg...) do {} while (0) +#endif + +#if defined(__BIG_ENDIAN) +#define LCD_CONTROL_DEFAULT_PO LCD_CONTROL_PO_11 +#else +#define LCD_CONTROL_DEFAULT_PO LCD_CONTROL_PO_00 +#endif +#define LCD_CONTROL_DEFAULT_SBPPF LCD_CONTROL_SBPPF_565 + /********************************************************************/ -#define uint32 unsigned long -typedef volatile struct -{ - uint32 lcd_control; - uint32 lcd_intstatus; - uint32 lcd_intenable; - uint32 lcd_horztiming; - uint32 lcd_verttiming; - uint32 lcd_clkcontrol; - uint32 lcd_dmaaddr0; - uint32 lcd_dmaaddr1; - uint32 lcd_words; - uint32 lcd_pwmdiv; - uint32 lcd_pwmhi; - uint32 reserved[(0x0400-0x002C)/4]; - uint32 lcd_pallettebase[256]; - -} AU1100_LCD; + +/* LCD controller restrictions */ +#define AU1100_LCD_MAX_XRES 800 +#define AU1100_LCD_MAX_YRES 600 +#define AU1100_LCD_MAX_BPP 16 +#define AU1100_LCD_MAX_CLK 48000000 +#define AU1100_LCD_NBR_PALETTE_ENTRIES 256 + +/* Default number of visible screen buffer to allocate */ +#define AU1100FB_NBR_VIDEO_BUFFERS 4 /********************************************************************/ -#define AU1100_LCD_ADDR 0xB5000000 +struct au1100fb_panel +{ + const char name[25]; /* Full name <vendor>_<model> */ -/* - * Register bit definitions - */ + u32 control_base; /* Mode-independent control values */ + u32 clkcontrol_base; /* Panel pixclock preferences */ -/* lcd_control */ -#define LCD_CONTROL_SBPPF (7<<18) -#define LCD_CONTROL_SBPPF_655 (0<<18) -#define LCD_CONTROL_SBPPF_565 (1<<18) -#define LCD_CONTROL_SBPPF_556 (2<<18) -#define LCD_CONTROL_SBPPF_1555 (3<<18) -#define LCD_CONTROL_SBPPF_5551 (4<<18) -#define LCD_CONTROL_WP (1<<17) -#define LCD_CONTROL_WD (1<<16) -#define LCD_CONTROL_C (1<<15) -#define LCD_CONTROL_SM (3<<13) -#define LCD_CONTROL_SM_0 (0<<13) -#define LCD_CONTROL_SM_90 (1<<13) -#define LCD_CONTROL_SM_180 (2<<13) -#define LCD_CONTROL_SM_270 (3<<13) -#define LCD_CONTROL_DB (1<<12) -#define LCD_CONTROL_CCO (1<<11) -#define LCD_CONTROL_DP (1<<10) -#define LCD_CONTROL_PO (3<<8) -#define LCD_CONTROL_PO_00 (0<<8) -#define LCD_CONTROL_PO_01 (1<<8) -#define LCD_CONTROL_PO_10 (2<<8) -#define LCD_CONTROL_PO_11 (3<<8) -#define LCD_CONTROL_MPI (1<<7) -#define LCD_CONTROL_PT (1<<6) -#define LCD_CONTROL_PC (1<<5) -#define LCD_CONTROL_BPP (7<<1) -#define LCD_CONTROL_BPP_1 (0<<1) -#define LCD_CONTROL_BPP_2 (1<<1) -#define LCD_CONTROL_BPP_4 (2<<1) -#define LCD_CONTROL_BPP_8 (3<<1) -#define LCD_CONTROL_BPP_12 (4<<1) -#define LCD_CONTROL_BPP_16 (5<<1) -#define LCD_CONTROL_GO (1<<0) - -/* lcd_intstatus, lcd_intenable */ -#define LCD_INT_SD (1<<7) -#define LCD_INT_OF (1<<6) -#define LCD_INT_UF (1<<5) -#define LCD_INT_SA (1<<3) -#define LCD_INT_SS (1<<2) -#define LCD_INT_S1 (1<<1) -#define LCD_INT_S0 (1<<0) - -/* lcd_horztiming */ -#define LCD_HORZTIMING_HN2 (255<<24) -#define LCD_HORZTIMING_HN2_N(N) (((N)-1)<<24) -#define LCD_HORZTIMING_HN1 (255<<16) -#define LCD_HORZTIMING_HN1_N(N) (((N)-1)<<16) -#define LCD_HORZTIMING_HPW (63<<10) -#define LCD_HORZTIMING_HPW_N(N) (((N)-1)<<10) -#define LCD_HORZTIMING_PPL (1023<<0) -#define LCD_HORZTIMING_PPL_N(N) (((N)-1)<<0) - -/* lcd_verttiming */ -#define LCD_VERTTIMING_VN2 (255<<24) -#define LCD_VERTTIMING_VN2_N(N) (((N)-1)<<24) -#define LCD_VERTTIMING_VN1 (255<<16) -#define LCD_VERTTIMING_VN1_N(N) (((N)-1)<<16) -#define LCD_VERTTIMING_VPW (63<<10) -#define LCD_VERTTIMING_VPW_N(N) (((N)-1)<<10) -#define LCD_VERTTIMING_LPP (1023<<0) -#define LCD_VERTTIMING_LPP_N(N) (((N)-1)<<0) - -/* lcd_clkcontrol */ -#define LCD_CLKCONTROL_IB (1<<18) -#define LCD_CLKCONTROL_IC (1<<17) -#define LCD_CLKCONTROL_IH (1<<16) -#define LCD_CLKCONTROL_IV (1<<15) -#define LCD_CLKCONTROL_BF (31<<10) -#define LCD_CLKCONTROL_BF_N(N) (((N)-1)<<10) -#define LCD_CLKCONTROL_PCD (1023<<0) -#define LCD_CLKCONTROL_PCD_N(N) ((N)<<0) - -/* lcd_pwmdiv */ -#define LCD_PWMDIV_EN (1<<12) -#define LCD_PWMDIV_PWMDIV (2047<<0) -#define LCD_PWMDIV_PWMDIV_N(N) (((N)-1)<<0) - -/* lcd_pwmhi */ -#define LCD_PWMHI_PWMHI1 (2047<<12) -#define LCD_PWMHI_PWMHI1_N(N) ((N)<<12) -#define LCD_PWMHI_PWMHI0 (2047<<0) -#define LCD_PWMHI_PWMHI0_N(N) ((N)<<0) - -/* lcd_pallettebase - MONOCHROME */ -#define LCD_PALLETTE_MONO_MI (15<<0) -#define LCD_PALLETTE_MONO_MI_N(N) ((N)<<0) - -/* lcd_pallettebase - COLOR */ -#define LCD_PALLETTE_COLOR_BI (15<<8) -#define LCD_PALLETTE_COLOR_BI_N(N) ((N)<<8) -#define LCD_PALLETTE_COLOR_GI (15<<4) -#define LCD_PALLETTE_COLOR_GI_N(N) ((N)<<4) -#define LCD_PALLETTE_COLOR_RI (15<<0) -#define LCD_PALLETTE_COLOR_RI_N(N) ((N)<<0) - -/* lcd_palletebase - COLOR TFT PALLETIZED */ -#define LCD_PALLETTE_TFT_DC (65535<<0) -#define LCD_PALLETTE_TFT_DC_N(N) ((N)<<0) + u32 horztiming; + u32 verttiming; -/********************************************************************/ + u32 xres; /* Maximum horizontal resolution */ + u32 yres; /* Maximum vertical resolution */ + u32 bpp; /* Maximum depth supported */ +}; -struct known_lcd_panels +struct au1100fb_regs { - uint32 xres; - uint32 yres; - uint32 bpp; - unsigned char panel_name[256]; - uint32 mode_control; - uint32 mode_horztiming; - uint32 mode_verttiming; - uint32 mode_clkcontrol; - uint32 mode_pwmdiv; - uint32 mode_pwmhi; - uint32 mode_toyclksrc; - uint32 mode_backlight; + u32 lcd_control; + u32 lcd_intstatus; + u32 lcd_intenable; + u32 lcd_horztiming; + u32 lcd_verttiming; + u32 lcd_clkcontrol; + u32 lcd_dmaaddr0; + u32 lcd_dmaaddr1; + u32 lcd_words; + u32 lcd_pwmdiv; + u32 lcd_pwmhi; + u32 reserved[(0x0400-0x002C)/4]; + u32 lcd_pallettebase[256]; +}; + +struct au1100fb_device { + + struct fb_info info; /* FB driver info record */ + struct au1100fb_panel *panel; /* Panel connected to this device */ + + struct au1100fb_regs* regs; /* Registers memory map */ + size_t regs_len; + unsigned int regs_phys; + + unsigned char* fb_mem; /* FrameBuffer memory map */ + size_t fb_len; + dma_addr_t fb_phys; }; -#if defined(__BIG_ENDIAN) -#define LCD_DEFAULT_PIX_FORMAT LCD_CONTROL_PO_11 -#else -#define LCD_DEFAULT_PIX_FORMAT LCD_CONTROL_PO_00 -#endif +/********************************************************************/ -/* - * The fb driver assumes that AUX PLL is at 48MHz. That can - * cover up to 800x600 resolution; if you need higher resolution, - * you should modify the driver as needed, not just this structure. +#define LCD_CONTROL (AU1100_LCD_BASE + 0x0) + #define LCD_CONTROL_SBB_BIT 21 + #define LCD_CONTROL_SBB_MASK (0x3 << LCD_CONTROL_SBB_BIT) + #define LCD_CONTROL_SBB_1 (0 << LCD_CONTROL_SBB_BIT) + #define LCD_CONTROL_SBB_2 (1 << LCD_CONTROL_SBB_BIT) + #define LCD_CONTROL_SBB_3 (2 << LCD_CONTROL_SBB_BIT) + #define LCD_CONTROL_SBB_4 (3 << LCD_CONTROL_SBB_BIT) + #define LCD_CONTROL_SBPPF_BIT 18 + #define LCD_CONTROL_SBPPF_MASK (0x7 << LCD_CONTROL_SBPPF_BIT) + #define LCD_CONTROL_SBPPF_655 (0 << LCD_CONTROL_SBPPF_BIT) + #define LCD_CONTROL_SBPPF_565 (1 << LCD_CONTROL_SBPPF_BIT) + #define LCD_CONTROL_SBPPF_556 (2 << LCD_CONTROL_SBPPF_BIT) + #define LCD_CONTROL_SBPPF_1555 (3 << LCD_CONTROL_SBPPF_BIT) + #define LCD_CONTROL_SBPPF_5551 (4 << LCD_CONTROL_SBPPF_BIT) + #define LCD_CONTROL_WP (1<<17) + #define LCD_CONTROL_WD (1<<16) + #define LCD_CONTROL_C (1<<15) + #define LCD_CONTROL_SM_BIT 13 + #define LCD_CONTROL_SM_MASK (0x3 << LCD_CONTROL_SM_BIT) + #define LCD_CONTROL_SM_0 (0 << LCD_CONTROL_SM_BIT) + #define LCD_CONTROL_SM_90 (1 << LCD_CONTROL_SM_BIT) + #define LCD_CONTROL_SM_180 (2 << LCD_CONTROL_SM_BIT) + #define LCD_CONTROL_SM_270 (3 << LCD_CONTROL_SM_BIT) + #define LCD_CONTROL_DB (1<<12) + #define LCD_CONTROL_CCO (1<<11) + #define LCD_CONTROL_DP (1<<10) + #define LCD_CONTROL_PO_BIT 8 + #define LCD_CONTROL_PO_MASK (0x3 << LCD_CONTROL_PO_BIT) + #define LCD_CONTROL_PO_00 (0 << LCD_CONTROL_PO_BIT) + #define LCD_CONTROL_PO_01 (1 << LCD_CONTROL_PO_BIT) + #define LCD_CONTROL_PO_10 (2 << LCD_CONTROL_PO_BIT) + #define LCD_CONTROL_PO_11 (3 << LCD_CONTROL_PO_BIT) + #define LCD_CONTROL_MPI (1<<7) + #define LCD_CONTROL_PT (1<<6) + #define LCD_CONTROL_PC (1<<5) + #define LCD_CONTROL_BPP_BIT 1 + #define LCD_CONTROL_BPP_MASK (0x7 << LCD_CONTROL_BPP_BIT) + #define LCD_CONTROL_BPP_1 (0 << LCD_CONTROL_BPP_BIT) + #define LCD_CONTROL_BPP_2 (1 << LCD_CONTROL_BPP_BIT) + #define LCD_CONTROL_BPP_4 (2 << LCD_CONTROL_BPP_BIT) + #define LCD_CONTROL_BPP_8 (3 << LCD_CONTROL_BPP_BIT) + #define LCD_CONTROL_BPP_12 (4 << LCD_CONTROL_BPP_BIT) + #define LCD_CONTROL_BPP_16 (5 << LCD_CONTROL_BPP_BIT) + #define LCD_CONTROL_GO (1<<0) + +#define LCD_INTSTATUS (AU1100_LCD_BASE + 0x4) +#define LCD_INTENABLE (AU1100_LCD_BASE + 0x8) + #define LCD_INT_SD (1<<7) + #define LCD_INT_OF (1<<6) + #define LCD_INT_UF (1<<5) + #define LCD_INT_SA (1<<3) + #define LCD_INT_SS (1<<2) + #define LCD_INT_S1 (1<<1) + #define LCD_INT_S0 (1<<0) + +#define LCD_HORZTIMING (AU1100_LCD_BASE + 0xC) + #define LCD_HORZTIMING_HN2_BIT 24 + #define LCD_HORZTIMING_HN2_MASK (0xFF << LCD_HORZTIMING_HN2_BIT) + #define LCD_HORZTIMING_HN2_N(N) ((((N)-1) << LCD_HORZTIMING_HN2_BIT) & LCD_HORZTIMING_HN2_MASK) + #define LCD_HORZTIMING_HN1_BIT 16 + #define LCD_HORZTIMING_HN1_MASK (0xFF << LCD_HORZTIMING_HN1_BIT) + #define LCD_HORZTIMING_HN1_N(N) ((((N)-1) << LCD_HORZTIMING_HN1_BIT) & LCD_HORZTIMING_HN1_MASK) + #define LCD_HORZTIMING_HPW_BIT 10 + #define LCD_HORZTIMING_HPW_MASK (0x3F << LCD_HORZTIMING_HPW_BIT) + #define LCD_HORZTIMING_HPW_N(N) ((((N)-1) << LCD_HORZTIMING_HPW_BIT) & LCD_HORZTIMING_HPW_MASK) + #define LCD_HORZTIMING_PPL_BIT 0 + #define LCD_HORZTIMING_PPL_MASK (0x3FF << LCD_HORZTIMING_PPL_BIT) + #define LCD_HORZTIMING_PPL_N(N) ((((N)-1) << LCD_HORZTIMING_PPL_BIT) & LCD_HORZTIMING_PPL_MASK) + +#define LCD_VERTTIMING (AU1100_LCD_BASE + 0x10) + #define LCD_VERTTIMING_VN2_BIT 24 + #define LCD_VERTTIMING_VN2_MASK (0xFF << LCD_VERTTIMING_VN2_BIT) + #define LCD_VERTTIMING_VN2_N(N) ((((N)-1) << LCD_VERTTIMING_VN2_BIT) & LCD_VERTTIMING_VN2_MASK) + #define LCD_VERTTIMING_VN1_BIT 16 + #define LCD_VERTTIMING_VN1_MASK (0xFF << LCD_VERTTIMING_VN1_BIT) + #define LCD_VERTTIMING_VN1_N(N) ((((N)-1) << LCD_VERTTIMING_VN1_BIT) & LCD_VERTTIMING_VN1_MASK) + #define LCD_VERTTIMING_VPW_BIT 10 + #define LCD_VERTTIMING_VPW_MASK (0x3F << LCD_VERTTIMING_VPW_BIT) + #define LCD_VERTTIMING_VPW_N(N) ((((N)-1) << LCD_VERTTIMING_VPW_BIT) & LCD_VERTTIMING_VPW_MASK) + #define LCD_VERTTIMING_LPP_BIT 0 + #define LCD_VERTTIMING_LPP_MASK (0x3FF << LCD_VERTTIMING_LPP_BIT) + #define LCD_VERTTIMING_LPP_N(N) ((((N)-1) << LCD_VERTTIMING_LPP_BIT) & LCD_VERTTIMING_LPP_MASK) + +#define LCD_CLKCONTROL (AU1100_LCD_BASE + 0x14) + #define LCD_CLKCONTROL_IB (1<<18) + #define LCD_CLKCONTROL_IC (1<<17) + #define LCD_CLKCONTROL_IH (1<<16) + #define LCD_CLKCONTROL_IV (1<<15) + #define LCD_CLKCONTROL_BF_BIT 10 + #define LCD_CLKCONTROL_BF_MASK (0x1F << LCD_CLKCONTROL_BF_BIT) + #define LCD_CLKCONTROL_BF_N(N) ((((N)-1) << LCD_CLKCONTROL_BF_BIT) & LCD_CLKCONTROL_BF_MASK) + #define LCD_CLKCONTROL_PCD_BIT 0 + #define LCD_CLKCONTROL_PCD_MASK (0x3FF << LCD_CLKCONTROL_PCD_BIT) + #define LCD_CLKCONTROL_PCD_N(N) (((N) << LCD_CLKCONTROL_PCD_BIT) & LCD_CLKCONTROL_PCD_MASK) + +#define LCD_DMAADDR0 (AU1100_LCD_BASE + 0x18) +#define LCD_DMAADDR1 (AU1100_LCD_BASE + 0x1C) + #define LCD_DMA_SA_BIT 5 + #define LCD_DMA_SA_MASK (0x7FFFFFF << LCD_DMA_SA_BIT) + #define LCD_DMA_SA_N(N) ((N) & LCD_DMA_SA_MASK) + +#define LCD_WORDS (AU1100_LCD_BASE + 0x20) + #define LCD_WRD_WRDS_BIT 0 + #define LCD_WRD_WRDS_MASK (0xFFFFFFFF << LCD_WRD_WRDS_BIT) + #define LCD_WRD_WRDS_N(N) ((((N)-1) << LCD_WRD_WRDS_BIT) & LCD_WRD_WRDS_MASK) + +#define LCD_PWMDIV (AU1100_LCD_BASE + 0x24) + #define LCD_PWMDIV_EN (1<<12) + #define LCD_PWMDIV_PWMDIV_BIT 0 + #define LCD_PWMDIV_PWMDIV_MASK (0xFFF << LCD_PWMDIV_PWMDIV_BIT) + #define LCD_PWMDIV_PWMDIV_N(N) ((((N)-1) << LCD_PWMDIV_PWMDIV_BIT) & LCD_PWMDIV_PWMDIV_MASK) + +#define LCD_PWMHI (AU1100_LCD_BASE + 0x28) + #define LCD_PWMHI_PWMHI1_BIT 12 + #define LCD_PWMHI_PWMHI1_MASK (0xFFF << LCD_PWMHI_PWMHI1_BIT) + #define LCD_PWMHI_PWMHI1_N(N) (((N) << LCD_PWMHI_PWMHI1_BIT) & LCD_PWMHI_PWMHI1_MASK) + #define LCD_PWMHI_PWMHI0_BIT 0 + #define LCD_PWMHI_PWMHI0_MASK (0xFFF << LCD_PWMHI_PWMHI0_BIT) + #define LCD_PWMHI_PWMHI0_N(N) (((N) << LCD_PWMHI_PWMHI0_BIT) & LCD_PWMHI_PWMHI0_MASK) + +#define LCD_PALLETTEBASE (AU1100_LCD_BASE + 0x400) + #define LCD_PALLETTE_MONO_MI_BIT 0 + #define LCD_PALLETTE_MONO_MI_MASK (0xF << LCD_PALLETTE_MONO_MI_BIT) + #define LCD_PALLETTE_MONO_MI_N(N) (((N)<< LCD_PALLETTE_MONO_MI_BIT) & LCD_PALLETTE_MONO_MI_MASK) + + #define LCD_PALLETTE_COLOR_RI_BIT 8 + #define LCD_PALLETTE_COLOR_RI_MASK (0xF << LCD_PALLETTE_COLOR_RI_BIT) + #define LCD_PALLETTE_COLOR_RI_N(N) (((N)<< LCD_PALLETTE_COLOR_RI_BIT) & LCD_PALLETTE_COLOR_RI_MASK) + #define LCD_PALLETTE_COLOR_GI_BIT 4 + #define LCD_PALLETTE_COLOR_GI_MASK (0xF << LCD_PALLETTE_COLOR_GI_BIT) + #define LCD_PALLETTE_COLOR_GI_N(N) (((N)<< LCD_PALLETTE_COLOR_GI_BIT) & LCD_PALLETTE_COLOR_GI_MASK) + #define LCD_PALLETTE_COLOR_BI_BIT 0 + #define LCD_PALLETTE_COLOR_BI_MASK (0xF << LCD_PALLETTE_COLOR_BI_BIT) + #define LCD_PALLETTE_COLOR_BI_N(N) (((N)<< LCD_PALLETTE_COLOR_BI_BIT) & LCD_PALLETTE_COLOR_BI_MASK) + + #define LCD_PALLETTE_TFT_DC_BIT 0 + #define LCD_PALLETTE_TFT_DC_MASK (0xFFFF << LCD_PALLETTE_TFT_DC_BIT) + #define LCD_PALLETTE_TFT_DC_N(N) (((N)<< LCD_PALLETTE_TFT_DC_BIT) & LCD_PALLETTE_TFT_DC_MASK) + +/********************************************************************/ + +/* List of panels known to work with the AU1100 LCD controller. + * To add a new panel, enter the same specifications as the + * Generic_TFT one, and MAKE SURE that it doesn't conflicts + * with the controller restrictions. Restrictions are: + * + * STN color panels: max_bpp <= 12 + * STN mono panels: max_bpp <= 4 + * TFT panels: max_bpp <= 16 + * max_xres <= 800 + * max_yres <= 600 */ -struct known_lcd_panels panels[] = +static struct au1100fb_panel known_lcd_panels[] = { - { /* 0: Pb1100 LCDA: Sharp 320x240 TFT panel */ - 320, /* xres */ - 240, /* yres */ - 16, /* bpp */ - - "Sharp_320x240_16", - /* mode_control */ + /* 800x600x16bpp CRT */ + [0] = { + .name = "CRT_800x600_16", + .xres = 800, + .yres = 600, + .bpp = 16, + .control_base = 0x0004886A | + LCD_CONTROL_DEFAULT_PO | LCD_CONTROL_DEFAULT_SBPPF | + LCD_CONTROL_BPP_16, + .clkcontrol_base = 0x00020000, + .horztiming = 0x005aff1f, + .verttiming = 0x16000e57, + }, + /* just the standard LCD */ + [1] = { + .name = "WWPC LCD", + .xres = 240, + .yres = 320, + .bpp = 16, + .control_base = 0x0006806A, + .horztiming = 0x0A1010EF, + .verttiming = 0x0301013F, + .clkcontrol_base = 0x00018001, + }, + /* Sharp 320x240 TFT panel */ + [2] = { + .name = "Sharp_LQ038Q5DR01", + .xres = 320, + .yres = 240, + .bpp = 16, + .control_base = ( LCD_CONTROL_SBPPF_565 - /*LCD_CONTROL_WP*/ - /*LCD_CONTROL_WD*/ | LCD_CONTROL_C | LCD_CONTROL_SM_0 - /*LCD_CONTROL_DB*/ - /*LCD_CONTROL_CCO*/ - /*LCD_CONTROL_DP*/ - | LCD_DEFAULT_PIX_FORMAT - /*LCD_CONTROL_MPI*/ + | LCD_CONTROL_DEFAULT_PO | LCD_CONTROL_PT | LCD_CONTROL_PC | LCD_CONTROL_BPP_16 ), - - /* mode_horztiming */ + .horztiming = ( LCD_HORZTIMING_HN2_N(8) | LCD_HORZTIMING_HN1_N(60) | LCD_HORZTIMING_HPW_N(12) | LCD_HORZTIMING_PPL_N(320) ), - - /* mode_verttiming */ + .verttiming = ( LCD_VERTTIMING_VN2_N(5) | LCD_VERTTIMING_VN1_N(17) | LCD_VERTTIMING_VPW_N(1) | LCD_VERTTIMING_LPP_N(240) ), - - /* mode_clkcontrol */ - ( 0 - /*LCD_CLKCONTROL_IB*/ - /*LCD_CLKCONTROL_IC*/ - /*LCD_CLKCONTROL_IH*/ - /*LCD_CLKCONTROL_IV*/ - | LCD_CLKCONTROL_PCD_N(1) ), - - /* mode_pwmdiv */ - 0, - - /* mode_pwmhi */ - 0, - - /* mode_toyclksrc */ - ((1<<7) | (1<<6) | (1<<5)), - - /* mode_backlight */ - 6 + .clkcontrol_base = LCD_CLKCONTROL_PCD_N(1), }, - { /* 1: Pb1100 LCDC 640x480 TFT panel */ - 640, /* xres */ - 480, /* yres */ - 16, /* bpp */ - - "Generic_640x480_16", - - /* mode_control */ - 0x004806a | LCD_DEFAULT_PIX_FORMAT, - - /* mode_horztiming */ - 0x3434d67f, - - /* mode_verttiming */ - 0x0e0e39df, - - /* mode_clkcontrol */ - ( 0 - /*LCD_CLKCONTROL_IB*/ - /*LCD_CLKCONTROL_IC*/ - /*LCD_CLKCONTROL_IH*/ - /*LCD_CLKCONTROL_IV*/ - | LCD_CLKCONTROL_PCD_N(1) ), - - /* mode_pwmdiv */ - 0, - - /* mode_pwmhi */ - 0, - - /* mode_toyclksrc */ - ((1<<7) | (1<<6) | (0<<5)), - - /* mode_backlight */ - 7 + /* Hitachi SP14Q005 and possibly others */ + [3] = { + .name = "Hitachi_SP14Qxxx", + .xres = 320, + .yres = 240, + .bpp = 4, + .control_base = + ( LCD_CONTROL_C + | LCD_CONTROL_BPP_4 ), + .horztiming = + ( LCD_HORZTIMING_HN2_N(1) + | LCD_HORZTIMING_HN1_N(1) + | LCD_HORZTIMING_HPW_N(1) + | LCD_HORZTIMING_PPL_N(320) ), + .verttiming = + ( LCD_VERTTIMING_VN2_N(1) + | LCD_VERTTIMING_VN1_N(1) + | LCD_VERTTIMING_VPW_N(1) + | LCD_VERTTIMING_LPP_N(240) ), + .clkcontrol_base = LCD_CLKCONTROL_PCD_N(4), }, - { /* 2: Pb1100 LCDB 640x480 PrimeView TFT panel */ - 640, /* xres */ - 480, /* yres */ - 16, /* bpp */ - - "PrimeView_640x480_16", - - /* mode_control */ - 0x0004886a | LCD_DEFAULT_PIX_FORMAT, - - /* mode_horztiming */ - 0x0e4bfe7f, - - /* mode_verttiming */ - 0x210805df, - - /* mode_clkcontrol */ - 0x00038001, - - /* mode_pwmdiv */ - 0, - - /* mode_pwmhi */ - 0, - - /* mode_toyclksrc */ - ((1<<7) | (1<<6) | (0<<5)), - - /* mode_backlight */ - 7 + /* Generic 640x480 TFT panel */ + [4] = { + .name = "TFT_640x480_16", + .xres = 640, + .yres = 480, + .bpp = 16, + .control_base = 0x004806a | LCD_CONTROL_DEFAULT_PO, + .horztiming = 0x3434d67f, + .verttiming = 0x0e0e39df, + .clkcontrol_base = LCD_CLKCONTROL_PCD_N(1), }, - { /* 3: Pb1100 800x600x16bpp NEON CRT */ - 800, /* xres */ - 600, /* yres */ - 16, /* bpp */ - - "NEON_800x600_16", - - /* mode_control */ - 0x0004886A | LCD_DEFAULT_PIX_FORMAT, - - /* mode_horztiming */ - 0x005AFF1F, - - /* mode_verttiming */ - 0x16000E57, - - /* mode_clkcontrol */ - 0x00020000, - - /* mode_pwmdiv */ - 0, - - /* mode_pwmhi */ - 0, - - /* mode_toyclksrc */ - ((1<<7) | (1<<6) | (0<<5)), - - /* mode_backlight */ - 7 + /* Pb1100 LCDB 640x480 PrimeView TFT panel */ + [5] = { + .name = "PrimeView_640x480_16", + .xres = 640, + .yres = 480, + .bpp = 16, + .control_base = 0x0004886a | LCD_CONTROL_DEFAULT_PO, + .horztiming = 0x0e4bfe7f, + .verttiming = 0x210805df, + .clkcontrol_base = 0x00038001, }, +}; - { /* 4: Pb1100 640x480x16bpp NEON CRT */ - 640, /* xres */ - 480, /* yres */ - 16, /* bpp */ - - "NEON_640x480_16", - - /* mode_control */ - 0x0004886A | LCD_DEFAULT_PIX_FORMAT, - - /* mode_horztiming */ - 0x0052E27F, - - /* mode_verttiming */ - 0x18000DDF, - - /* mode_clkcontrol */ - 0x00020000, +struct au1100fb_drv_info { + int panel_idx; + char *opt_mode; +}; - /* mode_pwmdiv */ - 0, +/********************************************************************/ - /* mode_pwmhi */ - 0, +/* Inline helpers */ - /* mode_toyclksrc */ - ((1<<7) | (1<<6) | (0<<5)), +#define panel_is_dual(panel) (panel->control_base & LCD_CONTROL_DP) +#define panel_is_active(panel)(panel->control_base & LCD_CONTROL_PT) +#define panel_is_color(panel) (panel->control_base & LCD_CONTROL_PC) +#define panel_swap_rgb(panel) (panel->control_base & LCD_CONTROL_CCO) - /* mode_backlight */ - 7 - }, -}; #endif /* _AU1100LCD_H */ diff --git a/drivers/video/backlight/corgi_bl.c b/drivers/video/backlight/corgi_bl.c index 3c72c627e65e..1991fdb32dfb 100644 --- a/drivers/video/backlight/corgi_bl.c +++ b/drivers/video/backlight/corgi_bl.c @@ -73,17 +73,15 @@ static void corgibl_blank(int blank) } #ifdef CONFIG_PM -static int corgibl_suspend(struct device *dev, pm_message_t state, u32 level) +static int corgibl_suspend(struct device *dev, pm_message_t state) { - if (level == SUSPEND_POWER_DOWN) - corgibl_blank(FB_BLANK_POWERDOWN); + corgibl_blank(FB_BLANK_POWERDOWN); return 0; } -static int corgibl_resume(struct device *dev, u32 level) +static int corgibl_resume(struct device *dev) { - if (level == RESUME_POWER_ON) - corgibl_blank(FB_BLANK_UNBLANK); + corgibl_blank(FB_BLANK_UNBLANK); return 0; } #else diff --git a/drivers/video/cirrusfb.c b/drivers/video/cirrusfb.c index a3040429c27b..3a26f9cc8585 100644 --- a/drivers/video/cirrusfb.c +++ b/drivers/video/cirrusfb.c @@ -275,20 +275,20 @@ static const struct cirrusfb_board_info_rec { #ifdef CONFIG_PCI #define CHIP(id, btype) \ - { PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_##id, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (btype) } + { PCI_VENDOR_ID_CIRRUS, id, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (btype) } static struct pci_device_id cirrusfb_pci_table[] = { - CHIP( CIRRUS_5436, BT_ALPINE ), - CHIP( CIRRUS_5434_8, BT_ALPINE ), - CHIP( CIRRUS_5434_4, BT_ALPINE ), - CHIP( CIRRUS_5430, BT_ALPINE ), /* GD-5440 has identical id */ - CHIP( CIRRUS_7543, BT_ALPINE ), - CHIP( CIRRUS_7548, BT_ALPINE ), - CHIP( CIRRUS_5480, BT_GD5480 ), /* MacPicasso probably */ - CHIP( CIRRUS_5446, BT_PICASSO4 ), /* Picasso 4 is a GD5446 */ - CHIP( CIRRUS_5462, BT_LAGUNA ), /* CL Laguna */ - CHIP( CIRRUS_5464, BT_LAGUNA ), /* CL Laguna 3D */ - CHIP( CIRRUS_5465, BT_LAGUNA ), /* CL Laguna 3DA*/ + CHIP( PCI_DEVICE_ID_CIRRUS_5436, BT_ALPINE ), + CHIP( PCI_DEVICE_ID_CIRRUS_5434_8, BT_ALPINE ), + CHIP( PCI_DEVICE_ID_CIRRUS_5434_4, BT_ALPINE ), + CHIP( PCI_DEVICE_ID_CIRRUS_5430, BT_ALPINE ), /* GD-5440 is same id */ + CHIP( PCI_DEVICE_ID_CIRRUS_7543, BT_ALPINE ), + CHIP( PCI_DEVICE_ID_CIRRUS_7548, BT_ALPINE ), + CHIP( PCI_DEVICE_ID_CIRRUS_5480, BT_GD5480 ), /* MacPicasso likely */ + CHIP( PCI_DEVICE_ID_CIRRUS_5446, BT_PICASSO4 ), /* Picasso 4 is 5446 */ + CHIP( PCI_DEVICE_ID_CIRRUS_5462, BT_LAGUNA ), /* CL Laguna */ + CHIP( PCI_DEVICE_ID_CIRRUS_5464, BT_LAGUNA ), /* CL Laguna 3D */ + CHIP( PCI_DEVICE_ID_CIRRUS_5465, BT_LAGUNA ), /* CL Laguna 3DA*/ { 0, } }; MODULE_DEVICE_TABLE(pci, cirrusfb_pci_table); diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig index eb83a7874c71..6a9ae2b3d1ab 100644 --- a/drivers/video/console/Kconfig +++ b/drivers/video/console/Kconfig @@ -28,7 +28,7 @@ config VGA_CONSOLE config VIDEO_SELECT bool "Video mode selection support" - depends on (X86 || X86_64) && VGA_CONSOLE + depends on X86 && VGA_CONSOLE ---help--- This enables support for text mode selection on kernel startup. If you want to take advantage of some high-resolution text mode your @@ -110,7 +110,7 @@ config STI_CONSOLE config FONTS bool "Select compiled-in fonts" - depends on FRAMEBUFFER_CONSOLE + depends on FRAMEBUFFER_CONSOLE || STI_CONSOLE help Say Y here if you would like to use fonts other than the default your frame buffer console usually use. @@ -123,7 +123,7 @@ config FONTS config FONT_8x8 bool "VGA 8x8 font" if FONTS - depends on FRAMEBUFFER_CONSOLE + depends on FRAMEBUFFER_CONSOLE || STI_CONSOLE default y if !SPARC32 && !SPARC64 && !FONTS help This is the "high resolution" font for the VGA frame buffer (the one @@ -137,7 +137,7 @@ config FONT_8x8 config FONT_8x16 bool "VGA 8x16 font" if FONTS - depends on FRAMEBUFFER_CONSOLE || SGI_NEWPORT_CONSOLE=y || USB_SISUSBVGA_CON + depends on FRAMEBUFFER_CONSOLE || SGI_NEWPORT_CONSOLE=y || STI_CONSOLE || USB_SISUSBVGA_CON default y if !SPARC32 && !SPARC64 && !FONTS help This is the "high resolution" font for the VGA frame buffer (the one @@ -147,7 +147,7 @@ config FONT_8x16 config FONT_6x11 bool "Mac console 6x11 font (not supported by all drivers)" if FONTS - depends on FRAMEBUFFER_CONSOLE + depends on FRAMEBUFFER_CONSOLE || STI_CONSOLE default y if !SPARC32 && !SPARC64 && !FONTS && MAC help Small console font with Macintosh-style high-half glyphs. Some Mac diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c index e793ffd39db5..762c7a593141 100644 --- a/drivers/video/console/newport_con.c +++ b/drivers/video/console/newport_con.c @@ -32,7 +32,6 @@ #include <linux/font.h> -extern struct font_desc font_vga_8x16; extern unsigned long sgi_gfxaddr; #define FONT_DATA ((unsigned char *)font_vga_8x16.data) diff --git a/drivers/video/console/sticore.c b/drivers/video/console/sticore.c index d940f605acb6..a7bcd17112c0 100644 --- a/drivers/video/console/sticore.c +++ b/drivers/video/console/sticore.c @@ -511,12 +511,12 @@ sti_select_fbfont( struct sti_cooked_rom *cooked_rom, char *fbfont_name ) struct sti_cooked_font *cooked_font; if (!fbfont_name || !strlen(fbfont_name)) - return NULL; + return NULL; fbfont = find_font(fbfont_name); if (!fbfont) - fbfont = get_default_font(1024,768); + fbfont = get_default_font(1024,768); if (!fbfont) - return NULL; + return NULL; DPRINTK((KERN_DEBUG "selected %dx%d fb-font %s\n", fbfont->width, fbfont->height, fbfont->name)); @@ -527,7 +527,7 @@ sti_select_fbfont( struct sti_cooked_rom *cooked_rom, char *fbfont_name ) nf = kmalloc(size, GFP_KERNEL); if (!nf) - return NULL; + return NULL; memset(nf, 0, size); nf->first_char = 0; @@ -546,8 +546,8 @@ sti_select_fbfont( struct sti_cooked_rom *cooked_rom, char *fbfont_name ) cooked_font = kmalloc(sizeof(*cooked_font), GFP_KERNEL); if (!cooked_font) { - kfree(nf); - return NULL; + kfree(nf); + return NULL; } cooked_font->raw = nf; @@ -595,7 +595,7 @@ sti_select_font(struct sti_cooked_rom *rom, static void __init sti_dump_rom(struct sti_rom *rom) { - printk(KERN_INFO " id %04x-%04x, conforms to spec rev. %d.%02x\n", + printk(KERN_INFO " id %04x-%04x, conforms to spec rev. %d.%02x\n", rom->graphics_id[0], rom->graphics_id[1], rom->revno[0] >> 4, @@ -651,15 +651,16 @@ sti_search_font(struct sti_cooked_rom *rom, int height, int width) struct sti_cooked_font *font; int i = 0; - for(font = rom->font_start; font; font = font->next_font, i++) { - if((font->raw->width == width) && (font->raw->height == height)) + for (font = rom->font_start; font; font = font->next_font, i++) { + if ((font->raw->width == width) && + (font->raw->height == height)) return i; } return 0; } -#define BMODE_RELOCATE(offset) offset = (offset) / 4; -#define BMODE_LAST_ADDR_OFFS 0x50 +#define BMODE_RELOCATE(offset) offset = (offset) / 4; +#define BMODE_LAST_ADDR_OFFS 0x50 static void * __init sti_bmode_font_raw(struct sti_cooked_font *f) @@ -700,35 +701,35 @@ sti_get_bmode_rom (unsigned long address) { struct sti_rom *raw; u32 size; - struct sti_rom_font *raw_font, *font_start; - + struct sti_rom_font *raw_font, *font_start; + sti_bmode_rom_copy(address + BMODE_LAST_ADDR_OFFS, sizeof(size), &size); - - size = (size+3) / 4; + + size = (size+3) / 4; raw = kmalloc(size, GFP_KERNEL); if (raw) { - sti_bmode_rom_copy(address, size, raw); - memmove (&raw->res004, &raw->type[0], 0x3c); - raw->type[3] = raw->res004; + sti_bmode_rom_copy(address, size, raw); + memmove (&raw->res004, &raw->type[0], 0x3c); + raw->type[3] = raw->res004; - BMODE_RELOCATE (raw->region_list); - BMODE_RELOCATE (raw->font_start); + BMODE_RELOCATE (raw->region_list); + BMODE_RELOCATE (raw->font_start); - BMODE_RELOCATE (raw->init_graph); - BMODE_RELOCATE (raw->state_mgmt); - BMODE_RELOCATE (raw->font_unpmv); - BMODE_RELOCATE (raw->block_move); - BMODE_RELOCATE (raw->inq_conf); + BMODE_RELOCATE (raw->init_graph); + BMODE_RELOCATE (raw->state_mgmt); + BMODE_RELOCATE (raw->font_unpmv); + BMODE_RELOCATE (raw->block_move); + BMODE_RELOCATE (raw->inq_conf); - raw_font = ((void *)raw) + raw->font_start; - font_start = raw_font; + raw_font = ((void *)raw) + raw->font_start; + font_start = raw_font; - while (raw_font->next_font) { - BMODE_RELOCATE (raw_font->next_font); - raw_font = ((void *)font_start) + raw_font->next_font; - } + while (raw_font->next_font) { + BMODE_RELOCATE (raw_font->next_font); + raw_font = ((void *)font_start) + raw_font->next_font; + } } - return raw; + return raw; } struct sti_rom * __init @@ -736,15 +737,15 @@ sti_get_wmode_rom (unsigned long address) { struct sti_rom *raw; unsigned long size; - + /* read the ROM size directly from the struct in ROM */ size = gsc_readl(address + offsetof(struct sti_rom,last_addr)); raw = kmalloc(size, GFP_KERNEL); - if(raw) - sti_rom_copy(address, size, raw); + if (raw) + sti_rom_copy(address, size, raw); - return raw; + return raw; } int __init @@ -757,14 +758,14 @@ sti_read_rom(int wordmode, struct sti_struct *sti, unsigned long address) if (!cooked) goto out_err; - if (wordmode) - raw = sti_get_wmode_rom (address); - else - raw = sti_get_bmode_rom (address); + if (wordmode) + raw = sti_get_wmode_rom (address); + else + raw = sti_get_bmode_rom (address); + + if (!raw) + goto out_err; - if (!raw) - goto out_err; - if (!sti_cook_fonts(cooked, raw)) { printk(KERN_ERR "No font found for STI at %08lx\n", address); goto out_err; @@ -787,7 +788,7 @@ sti_read_rom(int wordmode, struct sti_struct *sti, unsigned long address) sti->font_width = sti->font->raw->width; sti->font_height = sti->font->raw->height; if (!wordmode) - sti->font->raw = sti_bmode_font_raw(sti->font); + sti->font->raw = sti_bmode_font_raw(sti->font); sti->sti_mem_request = raw->sti_mem_req; sti->graphics_id[0] = raw->graphics_id[0]; @@ -811,16 +812,16 @@ sti_try_rom_generic(unsigned long address, unsigned long hpa, struct pci_dev *pd u32 sig; if (num_sti_roms >= MAX_STI_ROMS) { - printk(KERN_WARNING "maximum number of STI ROMS reached !\n"); - return NULL; + printk(KERN_WARNING "maximum number of STI ROMS reached !\n"); + return NULL; } sti = kmalloc(sizeof(*sti), GFP_KERNEL); if (!sti) { - printk(KERN_ERR "Not enough memory !\n"); - return NULL; + printk(KERN_ERR "Not enough memory !\n"); + return NULL; } - + memset(sti, 0, sizeof(*sti)); spin_lock_init(&sti->lock); @@ -932,28 +933,21 @@ static void __init sticore_check_for_default_sti(struct sti_struct *sti, char *p */ static int __init sticore_pa_init(struct parisc_device *dev) { - unsigned long rom = 0; char pa_path[21]; struct sti_struct *sti = NULL; - - if(dev->num_addrs) { - rom = dev->addr[0]; - } - if (!rom) { - rom = dev->hpa; - DPRINTK((KERN_DEBUG "Trying STI ROM at %08lx, hpa at %08lx\n", rom, dev->hpa)); - sti = sti_try_rom_generic(rom, dev->hpa, NULL); - rom = PAGE0->proc_sti; - } - if (!sti) { - DPRINTK((KERN_DEBUG "Trying STI ROM at %08lx, hpa at %08lx\n", rom, dev->hpa)); - sti = sti_try_rom_generic(rom, dev->hpa, NULL); - } + int hpa = dev->hpa.start; + + if (dev->num_addrs && dev->addr[0]) + sti = sti_try_rom_generic(dev->addr[0], hpa, NULL); + if (!sti) + sti = sti_try_rom_generic(hpa, hpa, NULL); + if (!sti) + sti = sti_try_rom_generic(PAGE0->proc_sti, hpa, NULL); if (!sti) return 1; - + print_pa_hwpath(dev, pa_path); - sticore_check_for_default_sti (sti, pa_path); + sticore_check_for_default_sti(sti, pa_path); return 0; } diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index 809fee2140ac..56cd199605f4 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -579,6 +579,7 @@ static void vga_set_palette(struct vc_data *vc, unsigned char *table) { int i, j; + vga_w(state.vgabase, VGA_PEL_MSK, 0xff); for (i = j = 0; i < 16; i++) { vga_w(state.vgabase, VGA_PEL_IW, table[i]); vga_w(state.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2); @@ -721,6 +722,7 @@ static void vga_pal_blank(struct vgastate *state) { int i; + vga_w(state->vgabase, VGA_PEL_MSK, 0xff); for (i = 0; i < 16; i++) { vga_w(state->vgabase, VGA_PEL_IW, i); vga_w(state->vgabase, VGA_PEL_D, 0); diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index ca02aa2bfcec..e2667ddab3f1 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -1031,7 +1031,7 @@ register_framebuffer(struct fb_info *fb_info) break; fb_info->node = i; - fb_info->class_device = class_device_create(fb_class, MKDEV(FB_MAJOR, i), + fb_info->class_device = class_device_create(fb_class, NULL, MKDEV(FB_MAJOR, i), fb_info->device, "fb%d", i); if (IS_ERR(fb_info->class_device)) { /* Not fatal */ diff --git a/drivers/video/gbefb.c b/drivers/video/gbefb.c index d3c1922cb13a..485604cd4462 100644 --- a/drivers/video/gbefb.c +++ b/drivers/video/gbefb.c @@ -1126,7 +1126,7 @@ static int __init gbefb_probe(struct device *dev) gbefb_setup(options); #endif - if (!request_mem_region(GBE_BASE, sizeof(struct sgi_gbe), "GBE")) { + if (!request_region(GBE_BASE, sizeof(struct sgi_gbe), "GBE")) { printk(KERN_ERR "gbefb: couldn't reserve mmio region\n"); ret = -EBUSY; goto out_release_framebuffer; @@ -1152,12 +1152,24 @@ static int __init gbefb_probe(struct device *dev) if (gbe_mem_phys) { /* memory was allocated at boot time */ gbe_mem = ioremap_nocache(gbe_mem_phys, gbe_mem_size); + if (!gbe_mem) { + printk(KERN_ERR "gbefb: couldn't map framebuffer\n"); + ret = -ENOMEM; + goto out_tiles_free; + } + gbe_dma_addr = 0; } else { /* try to allocate memory with the classical allocator * this has high chance to fail on low memory machines */ gbe_mem = dma_alloc_coherent(NULL, gbe_mem_size, &gbe_dma_addr, GFP_KERNEL); + if (!gbe_mem) { + printk(KERN_ERR "gbefb: couldn't allocate framebuffer memory\n"); + ret = -ENOMEM; + goto out_tiles_free; + } + gbe_mem_phys = (unsigned long) gbe_dma_addr; } @@ -1165,12 +1177,6 @@ static int __init gbefb_probe(struct device *dev) mtrr_add(gbe_mem_phys, gbe_mem_size, MTRR_TYPE_WRCOMB, 1); #endif - if (!gbe_mem) { - printk(KERN_ERR "gbefb: couldn't map framebuffer\n"); - ret = -ENXIO; - goto out_tiles_free; - } - /* map framebuffer memory into tiles table */ for (i = 0; i < (gbe_mem_size >> TILE_SHIFT); i++) gbe_tiles.cpu[i] = (gbe_mem_phys >> TILE_SHIFT) + i; diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c index 1d54d3d6960b..0b9301facbd3 100644 --- a/drivers/video/imxfb.c +++ b/drivers/video/imxfb.c @@ -424,23 +424,21 @@ static void imxfb_setup_gpio(struct imxfb_info *fbi) * Power management hooks. Note that we won't be called from IRQ context, * unlike the blank functions above, so we may sleep. */ -static int imxfb_suspend(struct device *dev, pm_message_t state, u32 level) +static int imxfb_suspend(struct device *dev, pm_message_t state) { struct imxfb_info *fbi = dev_get_drvdata(dev); pr_debug("%s\n",__FUNCTION__); - if (level == SUSPEND_DISABLE || level == SUSPEND_POWER_DOWN) - imxfb_disable_controller(fbi); + imxfb_disable_controller(fbi); return 0; } -static int imxfb_resume(struct device *dev, u32 level) +static int imxfb_resume(struct device *dev) { struct imxfb_info *fbi = dev_get_drvdata(dev); pr_debug("%s\n",__FUNCTION__); - if (level == RESUME_ENABLE) - imxfb_enable_controller(fbi); + imxfb_enable_controller(fbi); return 0; } #else diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c index 194eed0a238c..6206da9dd5da 100644 --- a/drivers/video/pxafb.c +++ b/drivers/video/pxafb.c @@ -981,21 +981,19 @@ pxafb_freq_policy(struct notifier_block *nb, unsigned long val, void *data) * Power management hooks. Note that we won't be called from IRQ context, * unlike the blank functions above, so we may sleep. */ -static int pxafb_suspend(struct device *dev, pm_message_t state, u32 level) +static int pxafb_suspend(struct device *dev, pm_message_t state) { struct pxafb_info *fbi = dev_get_drvdata(dev); - if (level == SUSPEND_DISABLE || level == SUSPEND_POWER_DOWN) - set_ctrlr_state(fbi, C_DISABLE_PM); + set_ctrlr_state(fbi, C_DISABLE_PM); return 0; } -static int pxafb_resume(struct device *dev, u32 level) +static int pxafb_resume(struct device *dev) { struct pxafb_info *fbi = dev_get_drvdata(dev); - if (level == RESUME_ENABLE) - set_ctrlr_state(fbi, C_ENABLE_PM); + set_ctrlr_state(fbi, C_ENABLE_PM); return 0; } #else diff --git a/drivers/video/s1d13xxxfb.c b/drivers/video/s1d13xxxfb.c index fa98d91c42eb..cb2f7a1de947 100644 --- a/drivers/video/s1d13xxxfb.c +++ b/drivers/video/s1d13xxxfb.c @@ -655,7 +655,7 @@ bail: } #ifdef CONFIG_PM -static int s1d13xxxfb_suspend(struct device *dev, pm_message_t state, u32 level) +static int s1d13xxxfb_suspend(struct device *dev, pm_message_t state) { struct fb_info *info = dev_get_drvdata(dev); struct s1d13xxxfb_par *s1dfb = info->par; @@ -702,15 +702,12 @@ static int s1d13xxxfb_suspend(struct device *dev, pm_message_t state, u32 level) return 0; } -static int s1d13xxxfb_resume(struct device *dev, u32 level) +static int s1d13xxxfb_resume(struct device *dev) { struct fb_info *info = dev_get_drvdata(dev); struct s1d13xxxfb_par *s1dfb = info->par; struct s1d13xxxfb_pdata *pdata = NULL; - if (level != RESUME_ENABLE) - return 0; - /* awaken the chip */ s1d13xxxfb_writereg(s1dfb, S1DREG_PS_CNF, 0x10); diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c index 5ab79afb53b7..3862d3cb1fb2 100644 --- a/drivers/video/s3c2410fb.c +++ b/drivers/video/s3c2410fb.c @@ -847,37 +847,32 @@ static int s3c2410fb_remove(struct device *dev) /* suspend and resume support for the lcd controller */ -static int s3c2410fb_suspend(struct device *dev, pm_message_t state, u32 level) +static int s3c2410fb_suspend(struct device *dev, pm_message_t state) { struct fb_info *fbinfo = dev_get_drvdata(dev); struct s3c2410fb_info *info = fbinfo->par; - if (level == SUSPEND_DISABLE || level == SUSPEND_POWER_DOWN) { - s3c2410fb_stop_lcd(); + s3c2410fb_stop_lcd(); - /* sleep before disabling the clock, we need to ensure - * the LCD DMA engine is not going to get back on the bus - * before the clock goes off again (bjd) */ + /* sleep before disabling the clock, we need to ensure + * the LCD DMA engine is not going to get back on the bus + * before the clock goes off again (bjd) */ - msleep(1); - clk_disable(info->clk); - } + msleep(1); + clk_disable(info->clk); return 0; } -static int s3c2410fb_resume(struct device *dev, u32 level) +static int s3c2410fb_resume(struct device *dev) { struct fb_info *fbinfo = dev_get_drvdata(dev); struct s3c2410fb_info *info = fbinfo->par; - if (level == RESUME_ENABLE) { - clk_enable(info->clk); - msleep(1); - - s3c2410fb_init_registers(info); + clk_enable(info->clk); + msleep(1); - } + s3c2410fb_init_registers(info); return 0; } diff --git a/drivers/video/sa1100fb.c b/drivers/video/sa1100fb.c index 8000890e4271..78e5f194b0df 100644 --- a/drivers/video/sa1100fb.c +++ b/drivers/video/sa1100fb.c @@ -1309,21 +1309,19 @@ sa1100fb_freq_policy(struct notifier_block *nb, unsigned long val, * Power management hooks. Note that we won't be called from IRQ context, * unlike the blank functions above, so we may sleep. */ -static int sa1100fb_suspend(struct device *dev, pm_message_t state, u32 level) +static int sa1100fb_suspend(struct device *dev, pm_message_t state) { struct sa1100fb_info *fbi = dev_get_drvdata(dev); - if (level == SUSPEND_DISABLE || level == SUSPEND_POWER_DOWN) - set_ctrlr_state(fbi, C_DISABLE_PM); + set_ctrlr_state(fbi, C_DISABLE_PM); return 0; } -static int sa1100fb_resume(struct device *dev, u32 level) +static int sa1100fb_resume(struct device *dev) { struct sa1100fb_info *fbi = dev_get_drvdata(dev); - if (level == RESUME_ENABLE) - set_ctrlr_state(fbi, C_ENABLE_PM); + set_ctrlr_state(fbi, C_ENABLE_PM); return 0; } #else diff --git a/drivers/video/w100fb.c b/drivers/video/w100fb.c index 0030c071da8f..752bf88906a9 100644 --- a/drivers/video/w100fb.c +++ b/drivers/video/w100fb.c @@ -438,36 +438,34 @@ static void w100fb_restore_vidmem(struct w100fb_par *par) } } -static int w100fb_suspend(struct device *dev, pm_message_t state, uint32_t level) +static int w100fb_suspend(struct device *dev, pm_message_t state) { - if (level == SUSPEND_POWER_DOWN) { - struct fb_info *info = dev_get_drvdata(dev); - struct w100fb_par *par=info->par; - struct w100_tg_info *tg = par->mach->tg; - - w100fb_save_vidmem(par); - if(tg && tg->suspend) - tg->suspend(par); - w100_suspend(W100_SUSPEND_ALL); - par->blanked = 1; - } + struct fb_info *info = dev_get_drvdata(dev); + struct w100fb_par *par=info->par; + struct w100_tg_info *tg = par->mach->tg; + + w100fb_save_vidmem(par); + if(tg && tg->suspend) + tg->suspend(par); + w100_suspend(W100_SUSPEND_ALL); + par->blanked = 1; + return 0; } -static int w100fb_resume(struct device *dev, uint32_t level) +static int w100fb_resume(struct device *dev) { - if (level == RESUME_POWER_ON) { - struct fb_info *info = dev_get_drvdata(dev); - struct w100fb_par *par=info->par; - struct w100_tg_info *tg = par->mach->tg; + struct fb_info *info = dev_get_drvdata(dev); + struct w100fb_par *par=info->par; + struct w100_tg_info *tg = par->mach->tg; + + w100_hw_init(par); + w100fb_activate_var(par); + w100fb_restore_vidmem(par); + if(tg && tg->resume) + tg->resume(par); + par->blanked = 0; - w100_hw_init(par); - w100fb_activate_var(par); - w100fb_restore_vidmem(par); - if(tg && tg->resume) - tg->resume(par); - par->blanked = 0; - } return 0; } #else diff --git a/drivers/w1/w1_family.c b/drivers/w1/w1_family.c index 88c517a4c178..9e293e139a0e 100644 --- a/drivers/w1/w1_family.c +++ b/drivers/w1/w1_family.c @@ -21,6 +21,7 @@ #include <linux/spinlock.h> #include <linux/list.h> +#include <linux/sched.h> /* schedule_timeout() */ #include <linux/delay.h> #include "w1_family.h" diff --git a/drivers/zorro/zorro-sysfs.c b/drivers/zorro/zorro-sysfs.c index 04ca8840acf1..87c29d7b6c17 100644 --- a/drivers/zorro/zorro-sysfs.c +++ b/drivers/zorro/zorro-sysfs.c @@ -14,6 +14,7 @@ #include <linux/kernel.h> #include <linux/zorro.h> #include <linux/stat.h> +#include <linux/string.h> #include "zorro.h" diff --git a/drivers/zorro/zorro.c b/drivers/zorro/zorro.c index d3c05dfe20d2..0f2b40605b06 100644 --- a/drivers/zorro/zorro.c +++ b/drivers/zorro/zorro.c @@ -16,6 +16,8 @@ #include <linux/init.h> #include <linux/zorro.h> #include <linux/bitops.h> +#include <linux/string.h> + #include <asm/setup.h> #include <asm/amigahw.h> |