From e9c8862f19958846dd0c7b39d0f6216aad6c7bee Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 6 Jul 2006 00:20:47 -0400 Subject: Input: remove accept method from input_dev This method used to enforce exclusive access to iforce devices, but presenlty there are no known users of this method. Signed-off-by: Dmitry Torokhov --- drivers/input/evdev.c | 4 ---- drivers/input/input.c | 9 --------- 2 files changed, 13 deletions(-) (limited to 'drivers') diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index a29d5ce..2426a5d 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -127,14 +127,10 @@ static int evdev_open(struct inode * inode, struct file * file) { struct evdev_list *list; int i = iminor(inode) - EVDEV_MINOR_BASE; - int accept_err; if (i >= EVDEV_MINORS || !evdev_table[i] || !evdev_table[i]->exist) return -ENODEV; - if ((accept_err = input_accept_process(&(evdev_table[i]->handle), file))) - return accept_err; - if (!(list = kzalloc(sizeof(struct evdev_list), GFP_KERNEL))) return -ENOMEM; diff --git a/drivers/input/input.c b/drivers/input/input.c index a90486f..c2e4d9b 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -197,15 +197,6 @@ static void input_repeat_key(unsigned long data) mod_timer(&dev->timer, jiffies + msecs_to_jiffies(dev->rep[REP_PERIOD])); } -int input_accept_process(struct input_handle *handle, struct file *file) -{ - if (handle->dev->accept) - return handle->dev->accept(handle->dev, file); - - return 0; -} -EXPORT_SYMBOL(input_accept_process); - int input_grab_device(struct input_handle *handle) { if (handle->dev->grab) -- cgit v1.1 From c7e8dc6ee6d59bf72f5478fa6355a27750e6c7d2 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 6 Jul 2006 00:21:03 -0400 Subject: Input: add start() method to input handlers The new start() method is called immediately after connect() and also when "grabbed" device is released by its owner. This will allow input handlers to re-synchronize state of once-grabbed device with the rest of devices. Signed-off-by: Dmitry Torokhov --- drivers/char/keyboard.c | 39 ++++++++++++++++++++------------------- drivers/input/input.c | 12 ++++++++++-- 2 files changed, 30 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index 056ebe8..38de44b 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -988,7 +988,7 @@ static inline unsigned char getleds(void) * interrupt routines for this thing allows us to easily mask * this when we don't want any of the above to happen. * This allows for easy and efficient race-condition prevention - * for kbd_refresh_leds => input_event(dev, EV_LED, ...) => ... + * for kbd_start => input_event(dev, EV_LED, ...) => ... */ static void kbd_bh(unsigned long dummy) @@ -1011,23 +1011,6 @@ static void kbd_bh(unsigned long dummy) DECLARE_TASKLET_DISABLED(keyboard_tasklet, kbd_bh, 0); -/* - * This allows a newly plugged keyboard to pick the LED state. - */ -static void kbd_refresh_leds(struct input_handle *handle) -{ - unsigned char leds = ledstate; - - tasklet_disable(&keyboard_tasklet); - if (leds != 0xff) { - input_event(handle->dev, EV_LED, LED_SCROLLL, !!(leds & 0x01)); - input_event(handle->dev, EV_LED, LED_NUML, !!(leds & 0x02)); - input_event(handle->dev, EV_LED, LED_CAPSL, !!(leds & 0x04)); - input_sync(handle->dev); - } - tasklet_enable(&keyboard_tasklet); -} - #if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_ALPHA) ||\ defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_SPARC) ||\ defined(CONFIG_PARISC) || defined(CONFIG_SUPERH) ||\ @@ -1307,7 +1290,6 @@ static struct input_handle *kbd_connect(struct input_handler *handler, handle->name = "kbd"; input_open_device(handle); - kbd_refresh_leds(handle); return handle; } @@ -1318,6 +1300,24 @@ static void kbd_disconnect(struct input_handle *handle) kfree(handle); } +/* + * Start keyboard handler on the new keyboard by refreshing LED state to + * match the rest of the system. + */ +static void kbd_start(struct input_handle *handle) +{ + unsigned char leds = ledstate; + + tasklet_disable(&keyboard_tasklet); + if (leds != 0xff) { + input_event(handle->dev, EV_LED, LED_SCROLLL, !!(leds & 0x01)); + input_event(handle->dev, EV_LED, LED_NUML, !!(leds & 0x02)); + input_event(handle->dev, EV_LED, LED_CAPSL, !!(leds & 0x04)); + input_sync(handle->dev); + } + tasklet_enable(&keyboard_tasklet); +} + static struct input_device_id kbd_ids[] = { { .flags = INPUT_DEVICE_ID_MATCH_EVBIT, @@ -1338,6 +1338,7 @@ static struct input_handler kbd_handler = { .event = kbd_event, .connect = kbd_connect, .disconnect = kbd_disconnect, + .start = kbd_start, .name = "kbd", .id_table = kbd_ids, }; diff --git a/drivers/input/input.c b/drivers/input/input.c index c2e4d9b..7aeebb9 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -209,8 +209,13 @@ EXPORT_SYMBOL(input_grab_device); void input_release_device(struct input_handle *handle) { - if (handle->dev->grab == handle) + if (handle->dev->grab == handle) { handle->dev->grab = NULL; + + list_for_each_entry(handle, &handle->dev->h_list, d_node) + if (handle->handler->start) + handle->handler->start(handle); + } } EXPORT_SYMBOL(input_release_device); @@ -954,8 +959,11 @@ int input_register_device(struct input_dev *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))) + if ((handle = handler->connect(handler, dev, id))) { input_link_handle(handle); + if (handler->start) + handler->start(handle); + } input_wakeup_procfs_readers(); -- cgit v1.1 From 0e739d28762e78c746cad8edd33223550a1c6a3f Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 6 Jul 2006 00:22:43 -0400 Subject: Input: introduce input_inject_event() function Create input_inject_event() function which is to be used by input handlers as opposed to input_event() which is reserved for drivers implementing input devices. The difference is that if device is "grabbed" by some process input_inject_event() will ignore events unless sent from the handle that is currently owns the device. Signed-off-by: Dmitry Torokhov --- drivers/char/keyboard.c | 36 ++++++++++++++++++------------------ drivers/input/evdev.c | 6 +++--- drivers/input/input.c | 27 +++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index 38de44b..1e946f5 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -223,13 +223,13 @@ static void kd_nosound(unsigned long ignored) { struct list_head *node; - list_for_each(node,&kbd_handler.h_list) { + list_for_each(node, &kbd_handler.h_list) { struct input_handle *handle = to_handle_h(node); if (test_bit(EV_SND, handle->dev->evbit)) { if (test_bit(SND_TONE, handle->dev->sndbit)) - input_event(handle->dev, EV_SND, SND_TONE, 0); + input_inject_event(handle, EV_SND, SND_TONE, 0); if (test_bit(SND_BELL, handle->dev->sndbit)) - input_event(handle->dev, EV_SND, SND_BELL, 0); + input_inject_event(handle, EV_SND, SND_BELL, 0); } } } @@ -247,11 +247,11 @@ void kd_mksound(unsigned int hz, unsigned int ticks) struct input_handle *handle = to_handle_h(node); if (test_bit(EV_SND, handle->dev->evbit)) { if (test_bit(SND_TONE, handle->dev->sndbit)) { - input_event(handle->dev, EV_SND, SND_TONE, hz); + input_inject_event(handle, EV_SND, SND_TONE, hz); break; } if (test_bit(SND_BELL, handle->dev->sndbit)) { - input_event(handle->dev, EV_SND, SND_BELL, 1); + input_inject_event(handle, EV_SND, SND_BELL, 1); break; } } @@ -272,15 +272,15 @@ int kbd_rate(struct kbd_repeat *rep) unsigned int d = 0; unsigned int p = 0; - list_for_each(node,&kbd_handler.h_list) { + list_for_each(node, &kbd_handler.h_list) { struct input_handle *handle = to_handle_h(node); struct input_dev *dev = handle->dev; if (test_bit(EV_REP, dev->evbit)) { if (rep->delay > 0) - input_event(dev, EV_REP, REP_DELAY, rep->delay); + input_inject_event(handle, EV_REP, REP_DELAY, rep->delay); if (rep->period > 0) - input_event(dev, EV_REP, REP_PERIOD, rep->period); + input_inject_event(handle, EV_REP, REP_PERIOD, rep->period); d = dev->rep[REP_DELAY]; p = dev->rep[REP_PERIOD]; } @@ -988,7 +988,7 @@ static inline unsigned char getleds(void) * interrupt routines for this thing allows us to easily mask * this when we don't want any of the above to happen. * This allows for easy and efficient race-condition prevention - * for kbd_start => input_event(dev, EV_LED, ...) => ... + * for kbd_start => input_inject_event(dev, EV_LED, ...) => ... */ static void kbd_bh(unsigned long dummy) @@ -998,11 +998,11 @@ static void kbd_bh(unsigned long dummy) if (leds != ledstate) { list_for_each(node, &kbd_handler.h_list) { - struct input_handle * handle = to_handle_h(node); - input_event(handle->dev, EV_LED, LED_SCROLLL, !!(leds & 0x01)); - input_event(handle->dev, EV_LED, LED_NUML, !!(leds & 0x02)); - input_event(handle->dev, EV_LED, LED_CAPSL, !!(leds & 0x04)); - input_sync(handle->dev); + struct input_handle *handle = to_handle_h(node); + input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01)); + input_inject_event(handle, EV_LED, LED_NUML, !!(leds & 0x02)); + input_inject_event(handle, EV_LED, LED_CAPSL, !!(leds & 0x04)); + input_inject_event(handle, EV_SYN, SYN_REPORT, 0); } } @@ -1310,10 +1310,10 @@ static void kbd_start(struct input_handle *handle) tasklet_disable(&keyboard_tasklet); if (leds != 0xff) { - input_event(handle->dev, EV_LED, LED_SCROLLL, !!(leds & 0x01)); - input_event(handle->dev, EV_LED, LED_NUML, !!(leds & 0x02)); - input_event(handle->dev, EV_LED, LED_CAPSL, !!(leds & 0x04)); - input_sync(handle->dev); + input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01)); + input_inject_event(handle, EV_LED, LED_NUML, !!(leds & 0x02)); + input_inject_event(handle, EV_LED, LED_CAPSL, !!(leds & 0x04)); + input_inject_event(handle, EV_SYN, SYN_REPORT, 0); } tasklet_enable(&keyboard_tasklet); } diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 2426a5d..4bf4818 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -256,7 +256,7 @@ static ssize_t evdev_write(struct file * file, const char __user * buffer, size_ if (evdev_event_from_user(buffer + retval, &event)) return -EFAULT; - input_event(list->evdev->handle.dev, event.type, event.code, event.value); + input_inject_event(&list->evdev->handle, event.type, event.code, event.value); retval += evdev_event_size(); } @@ -424,8 +424,8 @@ static long evdev_ioctl_handler(struct file *file, unsigned int cmd, if (get_user(v, ip + 1)) return -EFAULT; - input_event(dev, EV_REP, REP_DELAY, u); - input_event(dev, EV_REP, REP_PERIOD, v); + input_inject_event(&evdev->handle, EV_REP, REP_DELAY, u); + input_inject_event(&evdev->handle, EV_REP, REP_PERIOD, v); return 0; diff --git a/drivers/input/input.c b/drivers/input/input.c index 7aeebb9..e209139 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -35,6 +35,16 @@ static LIST_HEAD(input_handler_list); static struct input_handler *input_table[8]; +/** + * input_event() - report new input event + * @handle: device that generated the event + * @type: type of the event + * @code: event code + * @value: value of the event + * + * This function should be used by drivers implementing various input devices + * See also input_inject_event() + */ void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { struct input_handle *handle; @@ -183,6 +193,23 @@ void input_event(struct input_dev *dev, unsigned int type, unsigned int code, in } EXPORT_SYMBOL(input_event); +/** + * input_inject_event() - send input event from input handler + * @handle: input handle to send event through + * @type: type of the event + * @code: event code + * @value: value of the event + * + * Similar to input_event() but will ignore event if device is "grabbed" and handle + * injecting event is not the one that owns the device. + */ +void input_inject_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) +{ + if (!handle->dev->grab || handle->dev->grab == handle) + input_event(handle->dev, type, code, value); +} +EXPORT_SYMBOL(input_inject_event); + static void input_repeat_key(unsigned long data) { struct input_dev *dev = (void *) data; -- cgit v1.1 From c7948989f84ee6e9c68cc643f8c6a635eb7a904b Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Thu, 6 Jul 2006 00:23:38 -0400 Subject: Input: wistron - fix section reference mismatches Signed-off-by: Andrew Morton Signed-off-by: Dmitry Torokhov --- drivers/input/misc/wistron_btns.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c index ccf0fae..a8efc1a 100644 --- a/drivers/input/misc/wistron_btns.c +++ b/drivers/input/misc/wistron_btns.c @@ -94,7 +94,7 @@ static void call_bios(struct regs *regs) static ssize_t __init locate_wistron_bios(void __iomem *base) { - static const unsigned char __initdata signature[] = + static unsigned char __initdata signature[] = { 0x42, 0x21, 0x55, 0x30 }; ssize_t offset; @@ -259,11 +259,11 @@ static int __init dmi_matched(struct dmi_system_id *dmi) return 1; } -static struct key_entry keymap_empty[] = { +static struct key_entry keymap_empty[] __initdata = { { KE_END, 0 } }; -static struct key_entry keymap_fs_amilo_pro_v2000[] = { +static struct key_entry keymap_fs_amilo_pro_v2000[] __initdata = { { KE_KEY, 0x01, KEY_HELP }, { KE_KEY, 0x11, KEY_PROG1 }, { KE_KEY, 0x12, KEY_PROG2 }, @@ -273,7 +273,7 @@ static struct key_entry keymap_fs_amilo_pro_v2000[] = { { KE_END, 0 } }; -static struct key_entry keymap_fujitsu_n3510[] = { +static struct key_entry keymap_fujitsu_n3510[] __initdata = { { KE_KEY, 0x11, KEY_PROG1 }, { KE_KEY, 0x12, KEY_PROG2 }, { KE_KEY, 0x36, KEY_WWW }, @@ -285,7 +285,7 @@ static struct key_entry keymap_fujitsu_n3510[] = { { KE_END, 0 } }; -static struct key_entry keymap_wistron_ms2111[] = { +static struct key_entry keymap_wistron_ms2111[] __initdata = { { KE_KEY, 0x11, KEY_PROG1 }, { KE_KEY, 0x12, KEY_PROG2 }, { KE_KEY, 0x13, KEY_PROG3 }, @@ -294,7 +294,7 @@ static struct key_entry keymap_wistron_ms2111[] = { { KE_END, 0 } }; -static struct key_entry keymap_wistron_ms2141[] = { +static struct key_entry keymap_wistron_ms2141[] __initdata = { { KE_KEY, 0x11, KEY_PROG1 }, { KE_KEY, 0x12, KEY_PROG2 }, { KE_WIFI, 0x30, 0 }, @@ -307,7 +307,7 @@ static struct key_entry keymap_wistron_ms2141[] = { { KE_END, 0 } }; -static struct key_entry keymap_acer_aspire_1500[] = { +static struct key_entry keymap_acer_aspire_1500[] __initdata = { { KE_KEY, 0x11, KEY_PROG1 }, { KE_KEY, 0x12, KEY_PROG2 }, { KE_WIFI, 0x30, 0 }, @@ -317,7 +317,7 @@ static struct key_entry keymap_acer_aspire_1500[] = { { KE_END, 0 } }; -static struct key_entry keymap_acer_travelmate_240[] = { +static struct key_entry keymap_acer_travelmate_240[] __initdata = { { KE_KEY, 0x31, KEY_MAIL }, { KE_KEY, 0x36, KEY_WWW }, { KE_KEY, 0x11, KEY_PROG1 }, @@ -327,7 +327,7 @@ static struct key_entry keymap_acer_travelmate_240[] = { { KE_END, 0 } }; -static struct key_entry keymap_aopen_1559as[] = { +static struct key_entry keymap_aopen_1559as[] __initdata = { { KE_KEY, 0x01, KEY_HELP }, { KE_KEY, 0x06, KEY_PROG3 }, { KE_KEY, 0x11, KEY_PROG1 }, @@ -343,7 +343,7 @@ static struct key_entry keymap_aopen_1559as[] = { * a list of buttons and their key codes (reported when loading this module * with force=1) and the output of dmidecode to $MODULE_AUTHOR. */ -static struct dmi_system_id dmi_ids[] = { +static struct dmi_system_id dmi_ids[] __initdata = { { .callback = dmi_matched, .ident = "Fujitsu-Siemens Amilo Pro V2000", -- cgit v1.1 From 699756199d65700e8deed59ae250439ca8684686 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 6 Jul 2006 23:54:30 -0400 Subject: Input: fm801-gp - fix use after free Fixes Coverity #id 916 Signed-off-by: Dmitry Torokhov --- drivers/input/gameport/fm801-gp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/input/gameport/fm801-gp.c b/drivers/input/gameport/fm801-gp.c index 47e93da..90de5af 100644 --- a/drivers/input/gameport/fm801-gp.c +++ b/drivers/input/gameport/fm801-gp.c @@ -106,10 +106,10 @@ static int __devinit fm801_gp_probe(struct pci_dev *pci, const struct pci_device gp->gameport = port; gp->res_port = request_region(port->io, 0x10, "FM801 GP"); if (!gp->res_port) { - kfree(gp); - gameport_free_port(port); printk(KERN_DEBUG "fm801-gp: unable to grab region 0x%x-0x%x\n", port->io, port->io + 0x0f); + gameport_free_port(port); + kfree(gp); return -EBUSY; } -- cgit v1.1 From 95349fe8144b7d18f04bdca1c2d3fb85789de4fb Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 6 Jul 2006 23:54:48 -0400 Subject: Input: libps2 - warn instead of oopsing when passed bad arguments This is more user-friendly and also fixes Coverity #id 249 Signed-off-by: Dmitry Torokhov --- drivers/input/serio/libps2.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c index 61a6f97..ed202f2 100644 --- a/drivers/input/serio/libps2.c +++ b/drivers/input/serio/libps2.c @@ -177,6 +177,11 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command) return -1; } + if (send && !param) { + WARN_ON(1); + return -1; + } + mutex_lock_nested(&ps2dev->cmd_mutex, SINGLE_DEPTH_NESTING); serio_pause_rx(ps2dev->serio); -- cgit v1.1 From 8d64d3722c6abbb43bccd518ececc5559e1962b4 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 6 Jul 2006 23:55:00 -0400 Subject: Input: iforce - check array bounds before accessing elements Fixes Coverity #id 864 Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/iforce/iforce-main.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/input/joystick/iforce/iforce-main.c b/drivers/input/joystick/iforce/iforce-main.c index 6d99e3c..dc6cfea 100644 --- a/drivers/input/joystick/iforce/iforce-main.c +++ b/drivers/input/joystick/iforce/iforce-main.c @@ -222,22 +222,22 @@ static int iforce_erase_effect(struct input_dev *dev, int effect_id) int err = 0; struct iforce_core_effect* core_effect; - /* Check who is trying to erase this effect */ - if (iforce->core_effects[effect_id].owner != current->pid) { - printk(KERN_WARNING "iforce-main.c: %d tried to erase an effect belonging to %d\n", current->pid, iforce->core_effects[effect_id].owner); - return -EACCES; - } - if (effect_id < 0 || effect_id >= FF_EFFECTS_MAX) return -EINVAL; - core_effect = iforce->core_effects + effect_id; + core_effect = &iforce->core_effects[effect_id]; + + /* Check who is trying to erase this effect */ + if (core_effect->owner != current->pid) { + printk(KERN_WARNING "iforce-main.c: %d tried to erase an effect belonging to %d\n", current->pid, core_effect->owner); + return -EACCES; + } if (test_bit(FF_MOD1_IS_USED, core_effect->flags)) - err = release_resource(&(iforce->core_effects[effect_id].mod1_chunk)); + err = release_resource(&core_effect->mod1_chunk); if (!err && test_bit(FF_MOD2_IS_USED, core_effect->flags)) - err = release_resource(&(iforce->core_effects[effect_id].mod2_chunk)); + err = release_resource(&core_effect->mod2_chunk); /*TODO: remember to change that if more FF_MOD* bits are added */ core_effect->flags[0] = 0; -- cgit v1.1 From d568df84f987a9321c1f5826a6c8678ef2bb2b70 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 12 Jul 2006 01:47:00 -0400 Subject: ACPI: handle firmware_register init errors Signed-off-by: Randy Dunlap Signed-off-by: Len Brown --- drivers/acpi/bus.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index b297769..7b77ee1 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -738,7 +739,10 @@ static int __init acpi_init(void) return -ENODEV; } - firmware_register(&acpi_subsys); + result = firmware_register(&acpi_subsys); + if (result < 0) + printk(KERN_WARNING "%s: firmware_register error: %d\n", + __FUNCTION__, result); result = acpi_bus_init(); -- cgit v1.1 From 9b6d97b64eff08b368375efcf9c1d01eba582ea2 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 12 Jul 2006 02:08:00 -0400 Subject: ACPI: scan: handle kset/kobject errors Check and handle kset_register() and kobject_register() init errors. Signed-off-by: Randy Dunlap Signed-off-by: Len Brown --- drivers/acpi/scan.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 5fcb50c..698a154 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -113,6 +114,8 @@ static struct kset acpi_namespace_kset = { static void acpi_device_register(struct acpi_device *device, struct acpi_device *parent) { + int err; + /* * Linkage * ------- @@ -138,7 +141,10 @@ static void acpi_device_register(struct acpi_device *device, device->kobj.parent = &parent->kobj; device->kobj.ktype = &ktype_acpi_ns; device->kobj.kset = &acpi_namespace_kset; - kobject_register(&device->kobj); + err = kobject_register(&device->kobj); + if (err < 0) + printk(KERN_WARNING "%s: kobject_register error: %d\n", + __FUNCTION__, err); create_sysfs_device_files(device); } @@ -1450,7 +1456,9 @@ static int __init acpi_scan_init(void) if (acpi_disabled) return 0; - kset_register(&acpi_namespace_kset); + result = kset_register(&acpi_namespace_kset); + if (result < 0) + printk(KERN_ERR PREFIX "kset_register error: %d\n", result); result = bus_register(&acpi_bus_type); if (result) { -- cgit v1.1 From b53174fb5a0e47a19e10b8ef74ab0c12a19f92dc Mon Sep 17 00:00:00 2001 From: Przemek Iskra Date: Sat, 15 Jul 2006 01:16:21 -0400 Subject: Input: iforce - add Trust Force Feedback Race Master support Signed-off-by: Vojtech Pavlik Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/iforce/iforce-main.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/input/joystick/iforce/iforce-main.c b/drivers/input/joystick/iforce/iforce-main.c index dc6cfea..b4914e7 100644 --- a/drivers/input/joystick/iforce/iforce-main.c +++ b/drivers/input/joystick/iforce/iforce-main.c @@ -79,6 +79,7 @@ static struct iforce_device iforce_device[] = { { 0x06f8, 0x0001, "Guillemot Race Leader Force Feedback", btn_wheel, abs_wheel, ff_iforce }, //? { 0x06f8, 0x0004, "Guillemot Force Feedback Racing Wheel", btn_wheel, abs_wheel, ff_iforce }, //? { 0x06f8, 0x0004, "Gullemot Jet Leader 3D", btn_joystick, abs_joystick, ff_iforce }, //? + { 0x06d6, 0x29bc, "Trust Force Feedback Race Master", btn_wheel, abs_wheel, ff_iforce }, { 0x0000, 0x0000, "Unknown I-Force Device [%04x:%04x]", btn_joystick, abs_joystick, ff_iforce } }; -- cgit v1.1 From a2b2ed2ce20ae6c335a27ae5bf8580f385014e70 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Sat, 15 Jul 2006 01:17:38 -0400 Subject: Input: fix list iteration in input_release_device() Signed-off-by: Andrew Morton Signed-off-by: Dmitry Torokhov --- drivers/input/input.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/input/input.c b/drivers/input/input.c index e209139..9c98b6d 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -236,10 +236,12 @@ EXPORT_SYMBOL(input_grab_device); void input_release_device(struct input_handle *handle) { - if (handle->dev->grab == handle) { - handle->dev->grab = NULL; + struct input_dev *dev = handle->dev; + + if (dev->grab == handle) { + dev->grab = NULL; - list_for_each_entry(handle, &handle->dev->h_list, d_node) + list_for_each_entry(handle, &dev->h_list, d_node) if (handle->handler->start) handle->handler->start(handle); } -- cgit v1.1 From cb78623517ca08a035a3f69c0ca6d68a0123e649 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sat, 15 Jul 2006 01:17:54 -0400 Subject: Input: HID - fix potential out-of-bound array access Fixes Coverity #id 978 Signed-off-by: Dmitry Torokhov --- drivers/usb/input/hid-input.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/input/hid-input.c b/drivers/usb/input/hid-input.c index 028e1ad..7208839 100644 --- a/drivers/usb/input/hid-input.c +++ b/drivers/usb/input/hid-input.c @@ -607,7 +607,8 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel } - if (usage->hat_min < usage->hat_max || usage->hat_dir) { + if (usage->type == EV_ABS && + (usage->hat_min < usage->hat_max || usage->hat_dir)) { int i; for (i = usage->code; i < usage->code + 2 && i <= max; i++) { input_set_abs_params(input, i, -1, 1, 0, 0); -- cgit v1.1 From b6d786dbe6fc19b51edd6cf6de84fd65b702c800 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 19 Jul 2006 01:08:51 -0400 Subject: Input: add missing handler->start() call The start() method need to be called every time we create a new handle. This includes not only registering new devices but also when registering new handlers. Signed-off-by: Dmitry Torokhov --- drivers/input/input.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/input.c b/drivers/input/input.c index 9c98b6d..9cb4b9a 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -1056,8 +1056,11 @@ void input_register_handler(struct input_handler *handler) list_for_each_entry(dev, &input_dev_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))) + if ((handle = handler->connect(handler, dev, id))) { input_link_handle(handle); + if (handler->start) + handler->start(handle); + } input_wakeup_procfs_readers(); } -- cgit v1.1 From 826d598242d9200ddee63fce96f03793fddee4fc Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 19 Jul 2006 01:09:10 -0400 Subject: Input: hiddev - use standard list implementation Fixes Coverity #id 303 Signed-off-by: Dmitry Torokhov --- drivers/usb/input/hiddev.c | 72 ++++++++++++++++++++++++---------------------- 1 file changed, 38 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/input/hiddev.c b/drivers/usb/input/hiddev.c index 70477f0..f6b839c 100644 --- a/drivers/usb/input/hiddev.c +++ b/drivers/usb/input/hiddev.c @@ -49,7 +49,7 @@ struct hiddev { int open; wait_queue_head_t wait; struct hid_device *hid; - struct hiddev_list *list; + struct list_head list; }; struct hiddev_list { @@ -59,7 +59,7 @@ struct hiddev_list { unsigned flags; struct fasync_struct *fasync; struct hiddev *hiddev; - struct hiddev_list *next; + struct list_head node; }; static struct hiddev *hiddev_table[HIDDEV_MINORS]; @@ -73,12 +73,15 @@ static struct hiddev *hiddev_table[HIDDEV_MINORS]; static struct hid_report * hiddev_lookup_report(struct hid_device *hid, struct hiddev_report_info *rinfo) { - unsigned flags = rinfo->report_id & ~HID_REPORT_ID_MASK; + unsigned int flags = rinfo->report_id & ~HID_REPORT_ID_MASK; + unsigned int rid = rinfo->report_id & HID_REPORT_ID_MASK; struct hid_report_enum *report_enum; + struct hid_report *report; struct list_head *list; if (rinfo->report_type < HID_REPORT_TYPE_MIN || - rinfo->report_type > HID_REPORT_TYPE_MAX) return NULL; + rinfo->report_type > HID_REPORT_TYPE_MAX) + return NULL; report_enum = hid->report_enum + (rinfo->report_type - HID_REPORT_TYPE_MIN); @@ -88,21 +91,25 @@ hiddev_lookup_report(struct hid_device *hid, struct hiddev_report_info *rinfo) break; case HID_REPORT_ID_FIRST: - list = report_enum->report_list.next; - if (list == &report_enum->report_list) + if (list_empty(&report_enum->report_list)) return NULL; - rinfo->report_id = ((struct hid_report *) list)->id; + + list = report_enum->report_list.next; + report = list_entry(list, struct hid_report, list); + rinfo->report_id = report->id; break; case HID_REPORT_ID_NEXT: - list = (struct list_head *) - report_enum->report_id_hash[rinfo->report_id & HID_REPORT_ID_MASK]; - if (list == NULL) + report = report_enum->report_id_hash[rid]; + if (!report) return NULL; - list = list->next; + + list = report->list.next; if (list == &report_enum->report_list) return NULL; - rinfo->report_id = ((struct hid_report *) list)->id; + + report = list_entry(list, struct hid_report, list); + rinfo->report_id = report->id; break; default: @@ -125,12 +132,13 @@ hiddev_lookup_usage(struct hid_device *hid, struct hiddev_usage_ref *uref) struct hid_field *field; if (uref->report_type < HID_REPORT_TYPE_MIN || - uref->report_type > HID_REPORT_TYPE_MAX) return NULL; + uref->report_type > HID_REPORT_TYPE_MAX) + return NULL; report_enum = hid->report_enum + (uref->report_type - HID_REPORT_TYPE_MIN); - list_for_each_entry(report, &report_enum->report_list, list) + list_for_each_entry(report, &report_enum->report_list, list) { for (i = 0; i < report->maxfield; i++) { field = report->field[i]; for (j = 0; j < field->maxusage; j++) { @@ -142,6 +150,7 @@ hiddev_lookup_usage(struct hid_device *hid, struct hiddev_usage_ref *uref) } } } + } return NULL; } @@ -150,9 +159,9 @@ static void hiddev_send_event(struct hid_device *hid, struct hiddev_usage_ref *uref) { struct hiddev *hiddev = hid->hiddev; - struct hiddev_list *list = hiddev->list; + struct hiddev_list *list; - while (list) { + list_for_each_entry(list, &hiddev->list, node) { if (uref->field_index != HID_FIELD_INDEX_NONE || (list->flags & HIDDEV_FLAG_REPORT) != 0) { list->buffer[list->head] = *uref; @@ -160,8 +169,6 @@ static void hiddev_send_event(struct hid_device *hid, (HIDDEV_BUFFER_SIZE - 1); kill_fasync(&list->fasync, SIGIO, POLL_IN); } - - list = list->next; } wake_up_interruptible(&hiddev->wait); @@ -180,7 +187,7 @@ void hiddev_hid_event(struct hid_device *hid, struct hid_field *field, uref.report_type = (type == HID_INPUT_REPORT) ? HID_REPORT_TYPE_INPUT : ((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT : - ((type == HID_FEATURE_REPORT) ? HID_REPORT_TYPE_FEATURE:0)); + ((type == HID_FEATURE_REPORT) ? HID_REPORT_TYPE_FEATURE : 0)); uref.report_id = field->report->id; uref.field_index = field->index; uref.usage_index = (usage - field->usage); @@ -200,7 +207,7 @@ void hiddev_report_event(struct hid_device *hid, struct hid_report *report) uref.report_type = (type == HID_INPUT_REPORT) ? HID_REPORT_TYPE_INPUT : ((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT : - ((type == HID_FEATURE_REPORT) ? HID_REPORT_TYPE_FEATURE:0)); + ((type == HID_FEATURE_REPORT) ? HID_REPORT_TYPE_FEATURE : 0)); uref.report_id = report->id; uref.field_index = HID_FIELD_INDEX_NONE; @@ -213,7 +220,9 @@ static int hiddev_fasync(int fd, struct file *file, int on) { int retval; struct hiddev_list *list = file->private_data; + retval = fasync_helper(fd, file, on, &list->fasync); + return retval < 0 ? retval : 0; } @@ -224,14 +233,9 @@ static int hiddev_fasync(int fd, struct file *file, int on) static int hiddev_release(struct inode * inode, struct file * file) { struct hiddev_list *list = file->private_data; - struct hiddev_list **listptr; - listptr = &list->hiddev->list; hiddev_fasync(-1, file, 0); - - while (*listptr && (*listptr != list)) - listptr = &((*listptr)->next); - *listptr = (*listptr)->next; + list_del(&list->node); if (!--list->hiddev->open) { if (list->hiddev->exist) @@ -248,7 +252,8 @@ static int hiddev_release(struct inode * inode, struct file * file) /* * open file op */ -static int hiddev_open(struct inode * inode, struct file * file) { +static int hiddev_open(struct inode *inode, struct file *file) +{ struct hiddev_list *list; int i = iminor(inode) - HIDDEV_MINOR_BASE; @@ -260,9 +265,7 @@ static int hiddev_open(struct inode * inode, struct file * file) { return -ENOMEM; list->hiddev = hiddev_table[i]; - list->next = hiddev_table[i]->list; - hiddev_table[i]->list = list; - + list_add_tail(&list->node, &hiddev_table[i]->list); file->private_data = list; if (!list->hiddev->open++) @@ -362,6 +365,7 @@ static ssize_t hiddev_read(struct file * file, char __user * buffer, size_t coun static unsigned int hiddev_poll(struct file *file, poll_table *wait) { struct hiddev_list *list = file->private_data; + poll_wait(file, &list->hiddev->wait, wait); if (list->head != list->tail) return POLLIN | POLLRDNORM; @@ -382,7 +386,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd struct hiddev_collection_info cinfo; struct hiddev_report_info rinfo; struct hiddev_field_info finfo; - struct hiddev_usage_ref_multi *uref_multi=NULL; + struct hiddev_usage_ref_multi *uref_multi = NULL; struct hiddev_usage_ref *uref; struct hiddev_devinfo dinfo; struct hid_report *report; @@ -764,15 +768,15 @@ int hiddev_connect(struct hid_device *hid) } init_waitqueue_head(&hiddev->wait); - - hiddev_table[hid->intf->minor - HIDDEV_MINOR_BASE] = hiddev; - + INIT_LIST_HEAD(&hiddev->list); hiddev->hid = hid; hiddev->exist = 1; hid->minor = hid->intf->minor; hid->hiddev = hiddev; + hiddev_table[hid->intf->minor - HIDDEV_MINOR_BASE] = hiddev; + return 0; } -- cgit v1.1 From 2b192908b8e74ce0753c7dff92d244735d1eeed9 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 19 Jul 2006 01:13:26 -0400 Subject: Input: keyboard - remove static variable and clean up initialization Signed-off-by: Dmitry Torokhov --- drivers/char/keyboard.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index 1e946f5..1120586 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -107,7 +107,6 @@ const int NR_TYPES = ARRAY_SIZE(max_vals); struct kbd_struct kbd_table[MAX_NR_CONSOLES]; static struct kbd_struct *kbd = kbd_table; -static struct kbd_struct kbd0; int spawnpid, spawnsig; @@ -1347,15 +1346,15 @@ int __init kbd_init(void) { int i; - kbd0.ledflagstate = kbd0.default_ledflagstate = KBD_DEFLEDS; - kbd0.ledmode = LED_SHOW_FLAGS; - kbd0.lockstate = KBD_DEFLOCK; - kbd0.slockstate = 0; - kbd0.modeflags = KBD_DEFMODE; - kbd0.kbdmode = VC_XLATE; - - for (i = 0 ; i < MAX_NR_CONSOLES ; i++) - kbd_table[i] = kbd0; + for (i = 0; i < MAX_NR_CONSOLES; i++) { + kbd_table[i].ledflagstate = KBD_DEFLEDS; + kbd_table[i].default_ledflagstate = KBD_DEFLEDS; + kbd_table[i].ledmode = LED_SHOW_FLAGS; + kbd_table[i].lockstate = KBD_DEFLOCK; + kbd_table[i].slockstate = 0; + kbd_table[i].modeflags = KBD_DEFMODE; + kbd_table[i].kbdmode = VC_XLATE; + } input_register_handler(&kbd_handler); -- cgit v1.1 From 896cdc7b802c972d625351eb47d4add22d1fccb6 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 19 Jul 2006 01:14:25 -0400 Subject: Input: keyboard - simplify emulate_raw() implementation Signed-off-by: Dmitry Torokhov --- drivers/char/keyboard.c | 51 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 34 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index 1120586..30a7454 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -1025,7 +1025,7 @@ static const unsigned short x86_keycodes[256] = 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84,118, 86, 87, 88,115,120,119,121,112,123, 92, - 284,285,309,298,312, 91,327,328,329,331,333,335,336,337,338,339, + 284,285,309, 0,312, 91,327,328,329,331,333,335,336,337,338,339, 367,288,302,304,350, 89,334,326,267,126,268,269,125,347,348,349, 360,261,262,263,268,376,100,101,321,316,373,286,289,102,351,355, 103,104,105,275,287,279,306,106,274,107,294,364,358,363,362,361, @@ -1047,38 +1047,55 @@ extern void sun_do_break(void); static int emulate_raw(struct vc_data *vc, unsigned int keycode, unsigned char up_flag) { - if (keycode > 255 || !x86_keycodes[keycode]) - return -1; + int code; switch (keycode) { case KEY_PAUSE: put_queue(vc, 0xe1); put_queue(vc, 0x1d | up_flag); put_queue(vc, 0x45 | up_flag); - return 0; + break; + case KEY_HANGEUL: if (!up_flag) put_queue(vc, 0xf2); - return 0; + break; + case KEY_HANJA: if (!up_flag) put_queue(vc, 0xf1); - return 0; - } + break; - if (keycode == KEY_SYSRQ && sysrq_alt) { - put_queue(vc, 0x54 | up_flag); - return 0; - } + case KEY_SYSRQ: + /* + * Real AT keyboards (that's what we're trying + * to emulate here emit 0xe0 0x2a 0xe0 0x37 when + * pressing PrtSc/SysRq alone, but simply 0x54 + * when pressing Alt+PrtSc/SysRq. + */ + if (sysrq_alt) { + put_queue(vc, 0x54 | up_flag); + } else { + put_queue(vc, 0xe0); + put_queue(vc, 0x2a | up_flag); + put_queue(vc, 0xe0); + put_queue(vc, 0x37 | up_flag); + } + break; + + default: + if (keycode > 255) + return -1; - if (x86_keycodes[keycode] & 0x100) - put_queue(vc, 0xe0); + code = x86_keycodes[keycode]; + if (!code) + return -1; - put_queue(vc, (x86_keycodes[keycode] & 0x7f) | up_flag); + if (code & 0x100) + put_queue(vc, 0xe0); + put_queue(vc, (code & 0x7f) | up_flag); - if (keycode == KEY_SYSRQ) { - put_queue(vc, 0xe0); - put_queue(vc, 0x37 | up_flag); + break; } return 0; -- cgit v1.1 From 2c1dd69d28cba5a51e838897e0335f82a292f366 Mon Sep 17 00:00:00 2001 From: Nick Martin Date: Wed, 19 Jul 2006 01:14:44 -0400 Subject: Input: spaceball - make 4000FLX Lefty work Although the Spaceball 4000FLX Lefty is already supported by the spaceball driver, it does not register properly due to SPACEBALL_MAX_ID being set too low. Increment SPACEBALL_MAX_ID such that the 4000FLX Lefty is properly recognized. Signed-off-by: Nick Martin Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/spaceball.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/joystick/spaceball.c b/drivers/input/joystick/spaceball.c index 75eb5ca..7a19ee0 100644 --- a/drivers/input/joystick/spaceball.c +++ b/drivers/input/joystick/spaceball.c @@ -50,7 +50,7 @@ MODULE_LICENSE("GPL"); */ #define SPACEBALL_MAX_LENGTH 128 -#define SPACEBALL_MAX_ID 8 +#define SPACEBALL_MAX_ID 9 #define SPACEBALL_1003 1 #define SPACEBALL_2003B 3 -- cgit v1.1 From 73b59a3b1c09e4bfc678400b77b96134dcfbf112 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 19 Jul 2006 01:14:55 -0400 Subject: Input: serio/gameport - check whether driver core calls succeeded Signed-off-by: Randy Dunlap Signed-off-by: Dmitry Torokhov --- drivers/input/gameport/gameport.c | 66 +++++++++++++++++++++++++++++---------- drivers/input/serio/serio.c | 65 +++++++++++++++++++++++++++++--------- 2 files changed, 100 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c index 36644bf..3f47ae5 100644 --- a/drivers/input/gameport/gameport.c +++ b/drivers/input/gameport/gameport.c @@ -53,6 +53,7 @@ static LIST_HEAD(gameport_list); static struct bus_type gameport_bus; +static void gameport_add_driver(struct gameport_driver *drv); static void gameport_add_port(struct gameport *gameport); static void gameport_destroy_port(struct gameport *gameport); static void gameport_reconnect_port(struct gameport *gameport); @@ -211,8 +212,14 @@ static void gameport_release_driver(struct gameport *gameport) static void gameport_find_driver(struct gameport *gameport) { + int error; + down_write(&gameport_bus.subsys.rwsem); - device_attach(&gameport->dev); + error = device_attach(&gameport->dev); + if (error < 0) + printk(KERN_WARNING + "gameport: device_attach() failed for %s (%s), error: %d\n", + gameport->phys, gameport->name, error); up_write(&gameport_bus.subsys.rwsem); } @@ -316,7 +323,6 @@ static void gameport_remove_duplicate_events(struct gameport_event *event) spin_unlock_irqrestore(&gameport_event_lock, flags); } - static struct gameport_event *gameport_get_event(void) { struct gameport_event *event; @@ -342,7 +348,6 @@ static struct gameport_event *gameport_get_event(void) static void gameport_handle_event(void) { struct gameport_event *event; - struct gameport_driver *gameport_drv; mutex_lock(&gameport_mutex); @@ -369,8 +374,7 @@ static void gameport_handle_event(void) break; case GAMEPORT_REGISTER_DRIVER: - gameport_drv = event->object; - driver_register(&gameport_drv->driver); + gameport_add_driver(event->object); break; default: @@ -532,6 +536,7 @@ static void gameport_init_port(struct gameport *gameport) if (gameport->parent) gameport->dev.parent = &gameport->parent->dev; + INIT_LIST_HEAD(&gameport->node); spin_lock_init(&gameport->timer_lock); init_timer(&gameport->poll_timer); gameport->poll_timer.function = gameport_run_poll_handler; @@ -544,6 +549,8 @@ static void gameport_init_port(struct gameport *gameport) */ static void gameport_add_port(struct gameport *gameport) { + int error; + if (gameport->parent) gameport->parent->child = gameport; @@ -558,8 +565,13 @@ static void gameport_add_port(struct gameport *gameport) printk(KERN_INFO "gameport: %s is %s, speed %dkHz\n", gameport->name, gameport->phys, gameport->speed); - device_add(&gameport->dev); - gameport->registered = 1; + error = device_add(&gameport->dev); + if (error) + printk(KERN_ERR + "gameport: device_add() failed for %s (%s), error: %d\n", + gameport->phys, gameport->name, error); + else + gameport->registered = 1; } /* @@ -583,10 +595,11 @@ static void gameport_destroy_port(struct gameport *gameport) if (gameport->registered) { device_del(&gameport->dev); - list_del_init(&gameport->node); gameport->registered = 0; } + list_del_init(&gameport->node); + gameport_remove_pending_events(gameport); put_device(&gameport->dev); } @@ -704,11 +717,22 @@ static int gameport_driver_remove(struct device *dev) } static struct bus_type gameport_bus = { - .name = "gameport", - .probe = gameport_driver_probe, - .remove = gameport_driver_remove, + .name = "gameport", + .probe = gameport_driver_probe, + .remove = gameport_driver_remove, }; +static void gameport_add_driver(struct gameport_driver *drv) +{ + int error; + + error = driver_register(&drv->driver); + if (error) + printk(KERN_ERR + "gameport: driver_register() failed for %s, error: %d\n", + drv->driver.name, error); +} + void __gameport_register_driver(struct gameport_driver *drv, struct module *owner) { drv->driver.bus = &gameport_bus; @@ -778,16 +802,24 @@ void gameport_close(struct gameport *gameport) static int __init gameport_init(void) { - gameport_task = kthread_run(gameport_thread, NULL, "kgameportd"); - if (IS_ERR(gameport_task)) { - printk(KERN_ERR "gameport: Failed to start kgameportd\n"); - return PTR_ERR(gameport_task); - } + int error; gameport_bus.dev_attrs = gameport_device_attrs; gameport_bus.drv_attrs = gameport_driver_attrs; gameport_bus.match = gameport_bus_match; - bus_register(&gameport_bus); + error = bus_register(&gameport_bus); + if (error) { + printk(KERN_ERR "gameport: failed to register gameport bus, error: %d\n", error); + return error; + } + + gameport_task = kthread_run(gameport_thread, NULL, "kgameportd"); + if (IS_ERR(gameport_task)) { + bus_unregister(&gameport_bus); + error = PTR_ERR(gameport_task); + printk(KERN_ERR "gameport: Failed to start kgameportd, error: %d\n", error); + return error; + } return 0; } diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index 6521034..3e76ad7 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -62,6 +62,7 @@ static LIST_HEAD(serio_list); static struct bus_type serio_bus; +static void serio_add_driver(struct serio_driver *drv); static void serio_add_port(struct serio *serio); static void serio_destroy_port(struct serio *serio); static void serio_reconnect_port(struct serio *serio); @@ -140,8 +141,14 @@ static void serio_release_driver(struct serio *serio) static void serio_find_driver(struct serio *serio) { + int error; + down_write(&serio_bus.subsys.rwsem); - device_attach(&serio->dev); + error = device_attach(&serio->dev); + if (error < 0) + printk(KERN_WARNING + "serio: device_attach() failed for %s (%s), error: %d\n", + serio->phys, serio->name, error); up_write(&serio_bus.subsys.rwsem); } @@ -272,7 +279,6 @@ static struct serio_event *serio_get_event(void) static void serio_handle_event(void) { struct serio_event *event; - struct serio_driver *serio_drv; mutex_lock(&serio_mutex); @@ -304,8 +310,7 @@ static void serio_handle_event(void) break; case SERIO_REGISTER_DRIVER: - serio_drv = event->object; - driver_register(&serio_drv->driver); + serio_add_driver(event->object); break; default: @@ -525,6 +530,7 @@ static void serio_init_port(struct serio *serio) __module_get(THIS_MODULE); + INIT_LIST_HEAD(&serio->node); spin_lock_init(&serio->lock); mutex_init(&serio->drv_mutex); device_initialize(&serio->dev); @@ -542,6 +548,8 @@ static void serio_init_port(struct serio *serio) */ static void serio_add_port(struct serio *serio) { + int error; + if (serio->parent) { serio_pause_rx(serio->parent); serio->parent->child = serio; @@ -551,9 +559,19 @@ static void serio_add_port(struct serio *serio) list_add_tail(&serio->node, &serio_list); if (serio->start) serio->start(serio); - device_add(&serio->dev); - sysfs_create_group(&serio->dev.kobj, &serio_id_attr_group); - serio->registered = 1; + error = device_add(&serio->dev); + if (error) + printk(KERN_ERR + "serio: device_add() failed for %s (%s), error: %d\n", + serio->phys, serio->name, error); + else { + serio->registered = 1; + error = sysfs_create_group(&serio->dev.kobj, &serio_id_attr_group); + if (error) + printk(KERN_ERR + "serio: sysfs_create_group() failed for %s (%s), error: %d\n", + serio->phys, serio->name, error); + } } /* @@ -583,10 +601,10 @@ static void serio_destroy_port(struct serio *serio) if (serio->registered) { sysfs_remove_group(&serio->dev.kobj, &serio_id_attr_group); device_del(&serio->dev); - list_del_init(&serio->node); serio->registered = 0; } + list_del_init(&serio->node); serio_remove_pending_events(serio); put_device(&serio->dev); } @@ -756,6 +774,17 @@ static struct bus_type serio_bus = { .remove = serio_driver_remove, }; +static void serio_add_driver(struct serio_driver *drv) +{ + int error; + + error = driver_register(&drv->driver); + if (error) + printk(KERN_ERR + "serio: driver_register() failed for %s, error: %d\n", + drv->driver.name, error); +} + void __serio_register_driver(struct serio_driver *drv, struct module *owner) { drv->driver.bus = &serio_bus; @@ -903,18 +932,26 @@ irqreturn_t serio_interrupt(struct serio *serio, static int __init serio_init(void) { - serio_task = kthread_run(serio_thread, NULL, "kseriod"); - if (IS_ERR(serio_task)) { - printk(KERN_ERR "serio: Failed to start kseriod\n"); - return PTR_ERR(serio_task); - } + int error; serio_bus.dev_attrs = serio_device_attrs; serio_bus.drv_attrs = serio_driver_attrs; serio_bus.match = serio_bus_match; serio_bus.uevent = serio_uevent; serio_bus.resume = serio_resume; - bus_register(&serio_bus); + error = bus_register(&serio_bus); + if (error) { + printk(KERN_ERR "serio: failed to register serio bus, error: %d\n", error); + return error; + } + + serio_task = kthread_run(serio_thread, NULL, "kseriod"); + if (IS_ERR(serio_task)) { + bus_unregister(&serio_bus); + error = PTR_ERR(serio_task); + printk(KERN_ERR "serio: Failed to start kseriod, error: %d\n", error); + return error; + } return 0; } -- cgit v1.1 From 4528e4da79675b4995e085046b8ffbe0415c3261 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sat, 8 Jul 2006 20:17:26 +0900 Subject: [PATCH] libata: fix autopsy ehc->i.action and ehc->i.dev handling Commit 0662c58b3265f52f708a6d59476bc7862b01f9c0 updated ata_eh_autopsy() to OR determined action to ehc->i.action to preserve action mask set directly into ehc->i.action by nested functions. This broke action mask clearing on SENSE_VALID case causing revalidation and EH complete message on successful ATAPI CC. This patch removes two local variables - action and failed_dev - which cache ehc->i.action and ehc->i.dev respectively, and make the function directly modify ehc->i.* fields to remove aliasing issues. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/scsi/libata-eh.c | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c index 4b6aa30..36a801c 100644 --- a/drivers/scsi/libata-eh.c +++ b/drivers/scsi/libata-eh.c @@ -1276,8 +1276,6 @@ static int ata_eh_speed_down(struct ata_device *dev, int is_io, static void ata_eh_autopsy(struct ata_port *ap) { struct ata_eh_context *ehc = &ap->eh_context; - unsigned int action = ehc->i.action; - struct ata_device *failed_dev = NULL; unsigned int all_err_mask = 0; int tag, is_io = 0; u32 serror; @@ -1294,7 +1292,7 @@ static void ata_eh_autopsy(struct ata_port *ap) ehc->i.serror |= serror; ata_eh_analyze_serror(ap); } else if (rc != -EOPNOTSUPP) - action |= ATA_EH_HARDRESET; + ehc->i.action |= ATA_EH_HARDRESET; /* analyze NCQ failure */ ata_eh_analyze_ncq_error(ap); @@ -1315,7 +1313,7 @@ static void ata_eh_autopsy(struct ata_port *ap) qc->err_mask |= ehc->i.err_mask; /* analyze TF */ - action |= ata_eh_analyze_tf(qc, &qc->result_tf); + ehc->i.action |= ata_eh_analyze_tf(qc, &qc->result_tf); /* DEV errors are probably spurious in case of ATA_BUS error */ if (qc->err_mask & AC_ERR_ATA_BUS) @@ -1329,11 +1327,11 @@ static void ata_eh_autopsy(struct ata_port *ap) /* SENSE_VALID trumps dev/unknown error and revalidation */ if (qc->flags & ATA_QCFLAG_SENSE_VALID) { qc->err_mask &= ~(AC_ERR_DEV | AC_ERR_OTHER); - action &= ~ATA_EH_REVALIDATE; + ehc->i.action &= ~ATA_EH_REVALIDATE; } /* accumulate error info */ - failed_dev = qc->dev; + ehc->i.dev = qc->dev; all_err_mask |= qc->err_mask; if (qc->flags & ATA_QCFLAG_IO) is_io = 1; @@ -1342,25 +1340,22 @@ static void ata_eh_autopsy(struct ata_port *ap) /* enforce default EH actions */ if (ap->pflags & ATA_PFLAG_FROZEN || all_err_mask & (AC_ERR_HSM | AC_ERR_TIMEOUT)) - action |= ATA_EH_SOFTRESET; + ehc->i.action |= ATA_EH_SOFTRESET; else if (all_err_mask) - action |= ATA_EH_REVALIDATE; + ehc->i.action |= ATA_EH_REVALIDATE; /* if we have offending qcs and the associated failed device */ - if (failed_dev) { + if (ehc->i.dev) { /* speed down */ - action |= ata_eh_speed_down(failed_dev, is_io, all_err_mask); + ehc->i.action |= ata_eh_speed_down(ehc->i.dev, is_io, + all_err_mask); /* perform per-dev EH action only on the offending device */ - ehc->i.dev_action[failed_dev->devno] |= - action & ATA_EH_PERDEV_MASK; - action &= ~ATA_EH_PERDEV_MASK; + ehc->i.dev_action[ehc->i.dev->devno] |= + ehc->i.action & ATA_EH_PERDEV_MASK; + ehc->i.action &= ~ATA_EH_PERDEV_MASK; } - /* record autopsy result */ - ehc->i.dev = failed_dev; - ehc->i.action |= action; - DPRINTK("EXIT\n"); } -- cgit v1.1 From 7c8c2cff81b2b7f6dd3f9fd7b77033c1be5d7920 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 10 Jul 2006 23:18:23 +0900 Subject: [PATCH] libata: fix eh_skip_recovery condition * (ata_dev_absent() || ata_dev_ready()) test doesn't indicate SUSPENDED state properly. Fix it. * Link resuming resets shouldn't be skipped. Don't skip recovery on EHI_RESUME_LINK. This doesn't matter for host ports as EHI_RESUME always coincides with EHI_HOTPLUGGED which makes attached disabled devices vacant. However, PMP reset causes non-hotplug link-resuming resets which shouldn't be skipped. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/scsi/libata-eh.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c index 36a801c..1dcb2c1 100644 --- a/drivers/scsi/libata-eh.c +++ b/drivers/scsi/libata-eh.c @@ -1843,15 +1843,16 @@ static int ata_eh_skip_recovery(struct ata_port *ap) for (i = 0; i < ata_port_max_devices(ap); i++) { struct ata_device *dev = &ap->device[i]; - if (ata_dev_absent(dev) || ata_dev_ready(dev)) + if (!(dev->flags & ATA_DFLAG_SUSPENDED)) break; } if (i == ata_port_max_devices(ap)) return 1; - /* always thaw frozen port and recover failed devices */ - if (ap->pflags & ATA_PFLAG_FROZEN || ata_port_nr_enabled(ap)) + /* thaw frozen port, resume link and recover failed devices */ + if ((ap->pflags & ATA_PFLAG_FROZEN) || + (ehc->i.flags & ATA_EHI_RESUME_LINK) || ata_port_nr_enabled(ap)) return 0; /* skip if class codes for all vacant slots are ATA_DEV_NONE */ -- cgit v1.1 From 13abf50df209008b5d44075bafeeab42ace56aa6 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 10 Jul 2006 23:18:46 +0900 Subject: [PATCH] libata: improve EH action and EHI flag handling Update ata_eh_about_to_do() and ata_eh_done() to improve EH action and EHI flag handling. * There are two types of EHI flags - one which expires on successful EH and the other which expires on a successful reset. Make this distinction clear. * Unlike other EH actions, reset actions are represented by two EH action masks and a EHI modifier. Implement correct about_to_do/done semantics for resets. That is, prior to reset, related EH info is sucked in from ehi and cleared, and after reset is complete, related EH info in ehc is cleared. These changes improve consistency and remove unnecessary EH actions caused by stale EH action masks and EHI flags. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/scsi/libata-eh.c | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c index 1dcb2c1..29f5934 100644 --- a/drivers/scsi/libata-eh.c +++ b/drivers/scsi/libata-eh.c @@ -764,12 +764,27 @@ static void ata_eh_about_to_do(struct ata_port *ap, struct ata_device *dev, unsigned int action) { unsigned long flags; + struct ata_eh_info *ehi = &ap->eh_info; + struct ata_eh_context *ehc = &ap->eh_context; spin_lock_irqsave(ap->lock, flags); - ata_eh_clear_action(dev, &ap->eh_info, action); + /* Reset is represented by combination of actions and EHI + * flags. Suck in all related bits before clearing eh_info to + * avoid losing requested action. + */ + if (action & ATA_EH_RESET_MASK) { + ehc->i.action |= ehi->action & ATA_EH_RESET_MASK; + ehc->i.flags |= ehi->flags & ATA_EHI_RESET_MODIFIER_MASK; + + /* make sure all reset actions are cleared & clear EHI flags */ + action |= ATA_EH_RESET_MASK; + ehi->flags &= ~ATA_EHI_RESET_MODIFIER_MASK; + } + + ata_eh_clear_action(dev, ehi, action); - if (!(ap->eh_context.i.flags & ATA_EHI_QUIET)) + if (!(ehc->i.flags & ATA_EHI_QUIET)) ap->pflags |= ATA_PFLAG_RECOVERED; spin_unlock_irqrestore(ap->lock, flags); @@ -790,6 +805,12 @@ static void ata_eh_about_to_do(struct ata_port *ap, struct ata_device *dev, static void ata_eh_done(struct ata_port *ap, struct ata_device *dev, unsigned int action) { + /* if reset is complete, clear all reset actions & reset modifier */ + if (action & ATA_EH_RESET_MASK) { + action |= ATA_EH_RESET_MASK; + ap->eh_context.i.flags &= ~ATA_EHI_RESET_MODIFIER_MASK; + } + ata_eh_clear_action(dev, &ap->eh_context.i, action); } @@ -1478,6 +1499,9 @@ static int ata_eh_reset(struct ata_port *ap, int classify, ata_reset_fn_t reset; int i, did_followup_srst, rc; + /* about to reset */ + ata_eh_about_to_do(ap, NULL, ehc->i.action & ATA_EH_RESET_MASK); + /* Determine which reset to use and record in ehc->i.action. * prereset() may examine and modify it. */ @@ -1526,8 +1550,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify, ata_port_printk(ap, KERN_INFO, "%s resetting port\n", reset == softreset ? "soft" : "hard"); - /* reset */ - ata_eh_about_to_do(ap, NULL, ATA_EH_RESET_MASK); + /* mark that this EH session started with reset */ ehc->i.flags |= ATA_EHI_DID_RESET; rc = ata_do_reset(ap, reset, classes); @@ -1590,7 +1613,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify, postreset(ap, classes); /* reset successful, schedule revalidation */ - ata_eh_done(ap, NULL, ATA_EH_RESET_MASK); + ata_eh_done(ap, NULL, ehc->i.action & ATA_EH_RESET_MASK); ehc->i.action |= ATA_EH_REVALIDATE; } -- cgit v1.1 From 59b693fbbec37765426ba0916920ff93d2e26eb3 Mon Sep 17 00:00:00 2001 From: Jay Cliburn Date: Thu, 20 Jul 2006 23:23:57 +0200 Subject: via-velocity: fix speed and link status reported by ethtool The via-velocity driver reports incorrect speed and link detected status as viewed by ethtool (and probably other tools). This patch fixes those incorrect reports and prettifies a long line. Signed-off-by: Jay Cliburn Signed-off-by: Francois Romieu --- drivers/net/via-velocity.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index f5b0078..aa9cd92 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -2742,7 +2742,7 @@ static u32 check_connection_type(struct mac_regs __iomem * regs) if (PHYSR0 & PHYSR0_SPDG) status |= VELOCITY_SPEED_1000; - if (PHYSR0 & PHYSR0_SPD10) + else if (PHYSR0 & PHYSR0_SPD10) status |= VELOCITY_SPEED_10; else status |= VELOCITY_SPEED_100; @@ -2851,8 +2851,17 @@ static int velocity_get_settings(struct net_device *dev, struct ethtool_cmd *cmd u32 status; status = check_connection_type(vptr->mac_regs); - cmd->supported = SUPPORTED_TP | SUPPORTED_Autoneg | SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full; - if (status & VELOCITY_SPEED_100) + cmd->supported = SUPPORTED_TP | + SUPPORTED_Autoneg | + SUPPORTED_10baseT_Half | + SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full | + SUPPORTED_1000baseT_Half | + SUPPORTED_1000baseT_Full; + if (status & VELOCITY_SPEED_1000) + cmd->speed = SPEED_1000; + else if (status & VELOCITY_SPEED_100) cmd->speed = SPEED_100; else cmd->speed = SPEED_10; @@ -2896,7 +2905,7 @@ static u32 velocity_get_link(struct net_device *dev) { struct velocity_info *vptr = netdev_priv(dev); struct mac_regs __iomem * regs = vptr->mac_regs; - return BYTE_REG_BITS_IS_ON(PHYSR0_LINKGD, ®s->PHYSR0) ? 0 : 1; + return BYTE_REG_BITS_IS_ON(PHYSR0_LINKGD, ®s->PHYSR0) ? 1 : 0; } static void velocity_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) -- cgit v1.1 From 8419dc8a34d765f2ff1aa4051084d54cfeff09cf Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Mon, 24 Jul 2006 03:37:52 -0400 Subject: [libata] sata_promise: comment out duplicate PCI ID This is just the for-RC fix. A 'TODO' command is added, describing what's needed for the more-complete fix. --- drivers/scsi/sata_promise.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/sata_promise.c b/drivers/scsi/sata_promise.c index 64631bd..4776f4e 100644 --- a/drivers/scsi/sata_promise.c +++ b/drivers/scsi/sata_promise.c @@ -269,8 +269,15 @@ static const struct pci_device_id pdc_ata_pci_tbl[] = { { PCI_VENDOR_ID_PROMISE, 0x6629, PCI_ANY_ID, PCI_ANY_ID, 0, 0, board_20619 }, +/* TODO: remove all associated board_20771 code, as it completely + * duplicates board_2037x code, unless reason for separation can be + * divined. + */ +#if 0 { PCI_VENDOR_ID_PROMISE, 0x3570, PCI_ANY_ID, PCI_ANY_ID, 0, 0, board_20771 }, +#endif + { } /* terminate list */ }; -- cgit v1.1 From d1a8df9136ff55e554e11ce65854c282965be8f5 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 3 Jul 2006 14:28:14 +0200 Subject: [POWERPC] fix up front-LED Kconfig This patch fixes the front-LED Kconfig issues I introduced while creating it. Apparently having a dependency isn't enough to have the select not evaluated or something like that. The patch also changes the default configuration for pmac32 select the default for the LED to be the IDE trigger. While I was at it, I completely updated the defconfig and also added snd-aoa to it. Signed-off-by: Johannes Berg Signed-off-by: Paul Mackerras --- drivers/ide/Kconfig | 14 -------------- drivers/macintosh/Kconfig | 9 +++++++++ drivers/macintosh/via-pmu-led.c | 2 +- 3 files changed, 10 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig index d1266fe2..53bba41 100644 --- a/drivers/ide/Kconfig +++ b/drivers/ide/Kconfig @@ -773,20 +773,6 @@ config BLK_DEV_IDEDMA_PMAC to transfer data to and from memory. Saying Y is safe and improves performance. -config BLK_DEV_IDE_PMAC_BLINK - bool "Blink laptop LED on drive activity (DEPRECATED)" - depends on BLK_DEV_IDE_PMAC && ADB_PMU - select ADB_PMU_LED - select LEDS_TRIGGERS - select LEDS_TRIGGER_IDE_DISK - help - This option enables the use of the sleep LED as a hard drive - activity LED. - This option is deprecated, it only selects ADB_PMU_LED and - LEDS_TRIGGER_IDE_DISK and changes the code in the new led class - device to default to the ide-disk trigger (which should be set - from userspace via sysfs). - config BLK_DEV_IDE_SWARM tristate "IDE for Sibyte evaluation boards" depends on SIBYTE_SB1xxx_SOC diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig index f5fe7fb..f18c956 100644 --- a/drivers/macintosh/Kconfig +++ b/drivers/macintosh/Kconfig @@ -90,6 +90,15 @@ config ADB_PMU_LED and the ide-disk LED trigger and configure appropriately through sysfs. +config ADB_PMU_LED_IDE + bool "Use front LED as IDE LED by default" + depends on ADB_PMU_LED + select LEDS_TRIGGERS + select LEDS_TRIGGER_IDE_DISK + help + This option makes the front LED default to the IDE trigger + so that it blinks on IDE activity. + config PMAC_SMU bool "Support for SMU based PowerMacs" depends on PPC_PMAC64 diff --git a/drivers/macintosh/via-pmu-led.c b/drivers/macintosh/via-pmu-led.c index af8375ed..5189d54 100644 --- a/drivers/macintosh/via-pmu-led.c +++ b/drivers/macintosh/via-pmu-led.c @@ -74,7 +74,7 @@ static void pmu_led_set(struct led_classdev *led_cdev, static struct led_classdev pmu_led = { .name = "pmu-front-led", -#ifdef CONFIG_BLK_DEV_IDE_PMAC_BLINK +#ifdef CONFIG_ADB_PMU_LED_IDE .default_trigger = "ide-disk", #endif .brightness_set = pmu_led_set, -- cgit v1.1 From 98c82472e98469ef23d7c680a0d6be1429540166 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Tue, 4 Jul 2006 17:07:18 +1000 Subject: [POWERPC] More offb/bootx fixes There were still some issues with offb when BootX doesn't provide a proper display node, this fixes them. This also re-instates the palette hacks that were disabled a couple of kernel versions ago when I converted to the new OF parsing, and shuffles some functions around to avoid prototypes. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- drivers/video/offb.c | 307 +++++++++++++++++++++++++++------------------------ 1 file changed, 161 insertions(+), 146 deletions(-) (limited to 'drivers') diff --git a/drivers/video/offb.c b/drivers/video/offb.c index ce5f303..0013311 100644 --- a/drivers/video/offb.c +++ b/drivers/video/offb.c @@ -62,8 +62,6 @@ struct offb_par default_par; * Interface used by the world */ -int offb_init(void); - static int offb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, u_int transp, struct fb_info *info); static int offb_blank(int blank, struct fb_info *info); @@ -72,11 +70,6 @@ static int offb_blank(int blank, struct fb_info *info); extern boot_infos_t *boot_infos; #endif -static void offb_init_nodriver(struct device_node *); -static void offb_init_fb(const char *name, const char *full_name, - int width, int height, int depth, int pitch, - unsigned long address, struct device_node *dp); - static struct fb_ops offb_ops = { .owner = THIS_MODULE, .fb_setcolreg = offb_setcolreg, @@ -229,123 +222,17 @@ static int offb_blank(int blank, struct fb_info *info) return 0; } - /* - * Initialisation - */ -int __init offb_init(void) +static void __iomem *offb_map_reg(struct device_node *np, int index, + unsigned long offset, unsigned long size) { - struct device_node *dp = NULL, *boot_disp = NULL; - - if (fb_get_options("offb", NULL)) - return -ENODEV; + struct resource r; - for (dp = NULL; (dp = of_find_node_by_type(dp, "display"));) { - if (get_property(dp, "linux,opened", NULL) && - get_property(dp, "linux,boot-display", NULL)) { - boot_disp = dp; - offb_init_nodriver(dp); - } - } - for (dp = NULL; (dp = of_find_node_by_type(dp, "display"));) { - if (get_property(dp, "linux,opened", NULL) && - dp != boot_disp) - offb_init_nodriver(dp); - } - - return 0; -} - - -static void __init offb_init_nodriver(struct device_node *dp) -{ - unsigned int len; - int i, width = 640, height = 480, depth = 8, pitch = 640; - unsigned int flags, rsize, addr_prop = 0; - unsigned long max_size = 0; - u64 rstart, address = OF_BAD_ADDR; - u32 *pp, *addrp, *up; - u64 asize; - - pp = (u32 *)get_property(dp, "linux,bootx-depth", &len); - if (pp == NULL) - pp = (u32 *)get_property(dp, "depth", &len); - if (pp && len == sizeof(u32)) - depth = *pp; - - pp = (u32 *)get_property(dp, "linux,bootx-width", &len); - if (pp == NULL) - pp = (u32 *)get_property(dp, "width", &len); - if (pp && len == sizeof(u32)) - width = *pp; - - pp = (u32 *)get_property(dp, "linux,bootx-height", &len); - if (pp == NULL) - pp = (u32 *)get_property(dp, "height", &len); - if (pp && len == sizeof(u32)) - height = *pp; - - pp = (u32 *)get_property(dp, "linux,bootx-linebytes", &len); - if (pp == NULL) - pp = (u32 *)get_property(dp, "linebytes", &len); - if (pp && len == sizeof(u32)) - pitch = *pp; - else - pitch = width * ((depth + 7) / 8); - - rsize = (unsigned long)pitch * (unsigned long)height; - - /* Ok, now we try to figure out the address of the framebuffer. - * - * Unfortunately, Open Firmware doesn't provide a standard way to do - * so. All we can do is a dodgy heuristic that happens to work in - * practice. On most machines, the "address" property contains what - * we need, though not on Matrox cards found in IBM machines. What I've - * found that appears to give good results is to go through the PCI - * ranges and pick one that is both big enough and if possible encloses - * the "address" property. If none match, we pick the biggest - */ - up = (u32 *)get_property(dp, "linux,bootx-addr", &len); - if (up == NULL) - up = (u32 *)get_property(dp, "address", &len); - if (up && len == sizeof(u32)) - addr_prop = *up; - - for (i = 0; (addrp = of_get_address(dp, i, &asize, &flags)) - != NULL; i++) { - int match_addrp = 0; - - if (!(flags & IORESOURCE_MEM)) - continue; - if (asize < rsize) - continue; - rstart = of_translate_address(dp, addrp); - if (rstart == OF_BAD_ADDR) - continue; - if (addr_prop && (rstart <= addr_prop) && - ((rstart + asize) >= (addr_prop + rsize))) - match_addrp = 1; - if (match_addrp) { - address = addr_prop; - break; - } - if (rsize > max_size) { - max_size = rsize; - address = OF_BAD_ADDR; - } - - if (address == OF_BAD_ADDR) - address = rstart; - } - if (address == OF_BAD_ADDR && addr_prop) - address = (u64)addr_prop; - if (address != OF_BAD_ADDR) { - /* kludge for valkyrie */ - if (strcmp(dp->name, "valkyrie") == 0) - address += 0x1000; - offb_init_fb(dp->name, dp->full_name, width, height, depth, - pitch, address, dp); - } + if (of_address_to_resource(np, index, &r)) + return 0; + if ((r.start + offset + size) > r.end) + return 0; + return ioremap(r.start + offset, size); } static void __init offb_init_fb(const char *name, const char *full_name, @@ -402,45 +289,39 @@ static void __init offb_init_fb(const char *name, const char *full_name, par->cmap_type = cmap_unknown; if (depth == 8) { - /* Palette hacks disabled for now */ -#if 0 if (dp && !strncmp(name, "ATY,Rage128", 11)) { - unsigned long regbase = dp->addrs[2].address; - par->cmap_adr = ioremap(regbase, 0x1FFF); - par->cmap_type = cmap_r128; + par->cmap_adr = offb_map_reg(dp, 2, 0, 0x1fff); + if (par->cmap_adr) + par->cmap_type = cmap_r128; } else if (dp && (!strncmp(name, "ATY,RageM3pA", 12) || !strncmp(name, "ATY,RageM3p12A", 14))) { - unsigned long regbase = - dp->parent->addrs[2].address; - par->cmap_adr = ioremap(regbase, 0x1FFF); - par->cmap_type = cmap_M3A; + par->cmap_adr = offb_map_reg(dp, 2, 0, 0x1fff); + if (par->cmap_adr) + par->cmap_type = cmap_M3A; } else if (dp && !strncmp(name, "ATY,RageM3pB", 12)) { - unsigned long regbase = - dp->parent->addrs[2].address; - par->cmap_adr = ioremap(regbase, 0x1FFF); - par->cmap_type = cmap_M3B; + par->cmap_adr = offb_map_reg(dp, 2, 0, 0x1fff); + if (par->cmap_adr) + par->cmap_type = cmap_M3B; } else if (dp && !strncmp(name, "ATY,Rage6", 9)) { - unsigned long regbase = dp->addrs[1].address; - par->cmap_adr = ioremap(regbase, 0x1FFF); - par->cmap_type = cmap_radeon; + par->cmap_adr = offb_map_reg(dp, 1, 0, 0x1fff); + if (par->cmap_adr) + par->cmap_type = cmap_radeon; } else if (!strncmp(name, "ATY,", 4)) { unsigned long base = address & 0xff000000UL; par->cmap_adr = ioremap(base + 0x7ff000, 0x1000) + 0xcc0; par->cmap_data = par->cmap_adr + 1; par->cmap_type = cmap_m64; - } else if (device_is_compatible(dp, "pci1014,b7")) { - unsigned long regbase = dp->addrs[0].address; - par->cmap_adr = ioremap(regbase + 0x6000, 0x1000); - par->cmap_type = cmap_gxt2000; + } else if (dp && device_is_compatible(dp, "pci1014,b7")) { + par->cmap_adr = offb_map_reg(dp, 0, 0x6000, 0x1000); + if (par->cmap_adr) + par->cmap_type = cmap_gxt2000; } -#endif - fix->visual = par->cmap_adr ? FB_VISUAL_PSEUDOCOLOR - : FB_VISUAL_STATIC_PSEUDOCOLOR; + fix->visual = (par->cmap_type != cmap_unknown) ? + FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_STATIC_PSEUDOCOLOR; } else - fix->visual = /* par->cmap_adr ? FB_VISUAL_DIRECTCOLOR - : */ FB_VISUAL_TRUECOLOR; + fix->visual = FB_VISUAL_TRUECOLOR; var->xoffset = var->yoffset = 0; switch (depth) { @@ -520,5 +401,139 @@ static void __init offb_init_fb(const char *name, const char *full_name, info->node, full_name); } + +static void __init offb_init_nodriver(struct device_node *dp, int no_real_node) +{ + unsigned int len; + int i, width = 640, height = 480, depth = 8, pitch = 640; + unsigned int flags, rsize, addr_prop = 0; + unsigned long max_size = 0; + u64 rstart, address = OF_BAD_ADDR; + u32 *pp, *addrp, *up; + u64 asize; + + pp = (u32 *)get_property(dp, "linux,bootx-depth", &len); + if (pp == NULL) + pp = (u32 *)get_property(dp, "depth", &len); + if (pp && len == sizeof(u32)) + depth = *pp; + + pp = (u32 *)get_property(dp, "linux,bootx-width", &len); + if (pp == NULL) + pp = (u32 *)get_property(dp, "width", &len); + if (pp && len == sizeof(u32)) + width = *pp; + + pp = (u32 *)get_property(dp, "linux,bootx-height", &len); + if (pp == NULL) + pp = (u32 *)get_property(dp, "height", &len); + if (pp && len == sizeof(u32)) + height = *pp; + + pp = (u32 *)get_property(dp, "linux,bootx-linebytes", &len); + if (pp == NULL) + pp = (u32 *)get_property(dp, "linebytes", &len); + if (pp && len == sizeof(u32)) + pitch = *pp; + else + pitch = width * ((depth + 7) / 8); + + rsize = (unsigned long)pitch * (unsigned long)height; + + /* Ok, now we try to figure out the address of the framebuffer. + * + * Unfortunately, Open Firmware doesn't provide a standard way to do + * so. All we can do is a dodgy heuristic that happens to work in + * practice. On most machines, the "address" property contains what + * we need, though not on Matrox cards found in IBM machines. What I've + * found that appears to give good results is to go through the PCI + * ranges and pick one that is both big enough and if possible encloses + * the "address" property. If none match, we pick the biggest + */ + up = (u32 *)get_property(dp, "linux,bootx-addr", &len); + if (up == NULL) + up = (u32 *)get_property(dp, "address", &len); + if (up && len == sizeof(u32)) + addr_prop = *up; + + /* Hack for when BootX is passing us */ + if (no_real_node) + goto skip_addr; + + for (i = 0; (addrp = of_get_address(dp, i, &asize, &flags)) + != NULL; i++) { + int match_addrp = 0; + + if (!(flags & IORESOURCE_MEM)) + continue; + if (asize < rsize) + continue; + rstart = of_translate_address(dp, addrp); + if (rstart == OF_BAD_ADDR) + continue; + if (addr_prop && (rstart <= addr_prop) && + ((rstart + asize) >= (addr_prop + rsize))) + match_addrp = 1; + if (match_addrp) { + address = addr_prop; + break; + } + if (rsize > max_size) { + max_size = rsize; + address = OF_BAD_ADDR; + } + + if (address == OF_BAD_ADDR) + address = rstart; + } + skip_addr: + if (address == OF_BAD_ADDR && addr_prop) + address = (u64)addr_prop; + if (address != OF_BAD_ADDR) { + /* kludge for valkyrie */ + if (strcmp(dp->name, "valkyrie") == 0) + address += 0x1000; + offb_init_fb(no_real_node ? "bootx" : dp->name, + no_real_node ? "display" : dp->full_name, + width, height, depth, pitch, address, + no_real_node ? dp : NULL); + } +} + +static int __init offb_init(void) +{ + struct device_node *dp = NULL, *boot_disp = NULL; + + if (fb_get_options("offb", NULL)) + return -ENODEV; + + /* Check if we have a MacOS display without a node spec */ + if (get_property(of_chosen, "linux,bootx-noscreen", NULL) != NULL) { + /* The old code tried to work out which node was the MacOS + * display based on the address. I'm dropping that since the + * lack of a node spec only happens with old BootX versions + * (users can update) and with this code, they'll still get + * a display (just not the palette hacks). + */ + offb_init_nodriver(of_chosen, 1); + } + + for (dp = NULL; (dp = of_find_node_by_type(dp, "display"));) { + if (get_property(dp, "linux,opened", NULL) && + get_property(dp, "linux,boot-display", NULL)) { + boot_disp = dp; + offb_init_nodriver(dp, 0); + } + } + for (dp = NULL; (dp = of_find_node_by_type(dp, "display"));) { + if (get_property(dp, "linux,opened", NULL) && + dp != boot_disp) + offb_init_nodriver(dp, 0); + } + + return 0; +} + + module_init(offb_init); MODULE_LICENSE("GPL"); -- cgit v1.1 From 9805cb76f7bcd3108e012270d9ef2fd8ea3bea55 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Tue, 25 Jul 2006 13:30:57 -0400 Subject: ACPI: restore some dmesg to DEBUG-only, ala 2.6.17 The ACPI_EXCEPTION() patch enabled a bunch of messages to print even in the non-DEBUG kernel. Need to change a couple back, and note that ACPI_EXCEPTION takes no \n, but ACPI_DEBUG_PRINT does. No context for object [%p]\n Device `[%s]' is not power manageable\n Signed-off-by: Len Brown --- drivers/acpi/bus.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 7b77ee1..279c4ba 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -69,7 +69,8 @@ int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device) status = acpi_get_data(handle, acpi_bus_data_handler, (void **)device); if (ACPI_FAILURE(status) || !*device) { - ACPI_EXCEPTION((AE_INFO, status, "No context for object [%p]", handle)); + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No context for object [%p]\n", + handle)); return -ENODEV; } @@ -193,7 +194,7 @@ int acpi_bus_set_power(acpi_handle handle, int state) /* Make sure this is a valid target state */ if (!device->flags.power_manageable) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device `[%s]' is not power manageable", + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device `[%s]' is not power manageable\n", device->kobj.name)); return -ENODEV; } -- cgit v1.1 From 16a74744231e57e354253567490ab9e4ccd2d605 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Wed, 5 Apr 2006 08:47:00 -0400 Subject: PCI: quirk to disable e100 interrupt if RESET failed to Without this quirk, e100 can be pulling on a shared interrupt line when another device (eg. USB) loads, causing the interrupt to scream and get disabled. http://bugzilla.kernel.org/show_bug.cgi?id=5918 Signed-off-by: Bjorn Helgaas Signed-off-by: Len Brown --- drivers/pci/quirks.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) (limited to 'drivers') diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index e3c78c3..5ca1e94 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -1511,6 +1511,63 @@ static void __devinit quirk_netmos(struct pci_dev *dev) } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NETMOS, PCI_ANY_ID, quirk_netmos); +static void __devinit quirk_e100_interrupt(struct pci_dev *dev) +{ + u16 command; + u32 bar; + u8 __iomem *csr; + u8 cmd_hi; + + switch (dev->device) { + /* PCI IDs taken from drivers/net/e100.c */ + case 0x1029: + case 0x1030 ... 0x1034: + case 0x1038 ... 0x103E: + case 0x1050 ... 0x1057: + case 0x1059: + case 0x1064 ... 0x106B: + case 0x1091 ... 0x1095: + case 0x1209: + case 0x1229: + case 0x2449: + case 0x2459: + case 0x245D: + case 0x27DC: + break; + default: + return; + } + + /* + * Some firmware hands off the e100 with interrupts enabled, + * which can cause a flood of interrupts if packets are + * received before the driver attaches to the device. So + * disable all e100 interrupts here. The driver will + * re-enable them when it's ready. + */ + pci_read_config_word(dev, PCI_COMMAND, &command); + pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &bar); + + if (!(command & PCI_COMMAND_MEMORY) || !bar) + return; + + csr = ioremap(bar, 8); + if (!csr) { + printk(KERN_WARNING "PCI: Can't map %s e100 registers\n", + pci_name(dev)); + return; + } + + cmd_hi = readb(csr + 3); + if (cmd_hi == 0) { + printk(KERN_WARNING "PCI: Firmware left %s e100 interrupts " + "enabled, disabling\n", pci_name(dev)); + writeb(1, csr + 3); + } + + iounmap(csr); +} +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, quirk_e100_interrupt); static void __devinit fixup_rev1_53c810(struct pci_dev* dev) { -- cgit v1.1 From ba4ba8a69dcb446450b5ddeca48a7bd15783f4c2 Mon Sep 17 00:00:00 2001 From: Peter Oberparleiter Date: Thu, 27 Jul 2006 14:00:23 +0200 Subject: [S390] permanent subchannel busy conditions may cause I/O stall In special conditions where a subchannel rejects the HALT I/O- instruction with a busy indication (cc 2), I/O may stall. I/O request termination logic retries HALT I/O indefinitely because it expects HALT I/O to alter the subchannel status which is not true when cc 2 is returned. In case of a busy indication, try CLEAR I/O instruction immediately. Signed-off-by: Peter Oberparleiter Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/device_fsm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index ac6e0c7..7a39e0b 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c @@ -152,7 +152,8 @@ ccw_device_cancel_halt_clear(struct ccw_device *cdev) if (cdev->private->iretry) { cdev->private->iretry--; ret = cio_halt(sch); - return (ret == 0) ? -EBUSY : ret; + if (ret != -EBUSY) + return (ret == 0) ? -EBUSY : ret; } /* halt io unsuccessful. */ cdev->private->iretry = 255; /* 255 clear retries. */ -- cgit v1.1 From 17088229846c078aa936ca64912ab221d083aca1 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Thu, 27 Jul 2006 14:00:33 +0200 Subject: [S390] duplicate ccw devices in ccwgroup. Fail to create a ccwgroup device if a ccw device is passed in twice. Signed-off-by: Cornelia Huck Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/ccwgroup.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index f26a2ee..3cba6c9 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c @@ -152,7 +152,6 @@ ccwgroup_create(struct device *root, struct ccwgroup_device *gdev; int i; int rc; - int del_drvdata; if (argc > 256) /* disallow dumb users */ return -EINVAL; @@ -163,7 +162,6 @@ ccwgroup_create(struct device *root, atomic_set(&gdev->onoff, 0); - del_drvdata = 0; for (i = 0; i < argc; i++) { gdev->cdev[i] = get_ccwdev_by_busid(cdrv, argv[i]); @@ -180,10 +178,8 @@ ccwgroup_create(struct device *root, rc = -EINVAL; goto free_dev; } - } - for (i = 0; i < argc; i++) gdev->cdev[i]->dev.driver_data = gdev; - del_drvdata = 1; + } gdev->creator_id = creator_id; gdev->count = argc; @@ -226,9 +222,9 @@ error: free_dev: for (i = 0; i < argc; i++) if (gdev->cdev[i]) { - put_device(&gdev->cdev[i]->dev); - if (del_drvdata) + if (gdev->cdev[i]->dev.driver_data == gdev) gdev->cdev[i]->dev.driver_data = NULL; + put_device(&gdev->cdev[i]->dev); } kfree(gdev); return rc; -- cgit v1.1 From d91928e906e2866563a69506bb77ffebcf50613c Mon Sep 17 00:00:00 2001 From: Pavel Machek Date: Thu, 27 Jul 2006 14:32:40 -0400 Subject: [PATCH] zd1201: workaround interference problem zd1201 has nasty tendency to emit magicall anti-wifi cloud when it is inserted into slot, but not used. Signed-off-by: Pavel Machek Signed-off-by: John W. Linville --- drivers/net/wireless/zd1201.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/zd1201.c b/drivers/net/wireless/zd1201.c index 662ecc8..c52e9bcf 100644 --- a/drivers/net/wireless/zd1201.c +++ b/drivers/net/wireless/zd1201.c @@ -1820,6 +1820,8 @@ static int zd1201_probe(struct usb_interface *interface, zd->dev->name); usb_set_intfdata(interface, zd); + zd1201_enable(zd); /* zd1201 likes to startup enabled, */ + zd1201_disable(zd); /* interfering with all the wifis in range */ return 0; err_net: -- cgit v1.1 From 8fa9ea18e831417159b7b1a76a944f117252f9ec Mon Sep 17 00:00:00 2001 From: Robert Schulze Date: Wed, 5 Jul 2006 22:52:43 +0200 Subject: [PATCH] airo: should select crypto_aes The driver airo (for Cisco Wlan-Cards) complains about "failed to load transform for AES", when it is loaded and CRYPTO_AES is not selected in Kconfig. Signed-off-by: John W. Linville --- drivers/net/wireless/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index fa9d2c4..2e8ac99 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -447,6 +447,7 @@ config AIRO_CS tristate "Cisco/Aironet 34X/35X/4500/4800 PCMCIA cards" depends on NET_RADIO && PCMCIA && (BROKEN || !M32R) select CRYPTO + select CRYPTO_AES ---help--- This is the standard Linux driver to support Cisco/Aironet PCMCIA 802.11 wireless cards. This driver is the same as the Aironet -- cgit v1.1 From 345f6b8beb20338a2d792bf5974d01d457abee53 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Tue, 11 Jul 2006 23:16:34 +0100 Subject: [PATCH] softmac: do shared key auth in workqueue Johann Uhrmann reported a bcm43xx crash and Michael Buesch tracked it down to a problem with the new shared key auth code (recursive calls into the driver) This patch (effectively Michael's patch with a couple of small modifications) solves the problem by sending the authentication challenge response frame from a workqueue entry. I also removed a lone \n from the bcm43xx messages relating to authentication mode - this small change was previously discussed but not patched in. Signed-off-by: Daniel Drake Acked-by: Johannes Berg Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 3889f79..df317c1 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -3701,7 +3701,7 @@ static void bcm43xx_ieee80211_set_security(struct net_device *net_dev, } if (sec->flags & SEC_AUTH_MODE) { secinfo->auth_mode = sec->auth_mode; - dprintk(", .auth_mode = %d\n", sec->auth_mode); + dprintk(", .auth_mode = %d", sec->auth_mode); } dprintk("\n"); if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED && -- cgit v1.1 From fe397d469fa3fbc678383ffbd0630e4849cca688 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 14 Jul 2006 11:41:47 -0400 Subject: [PATCH] orinoco: fix setting transmit key only When determining whether there's a key to set or not, orinoco should be looking at the key length, not the key data. Otherwise confusion reigns when trying to set TX key only, passing in zero-length key, but non-NULL pointer. Key length takes precedence over non-NULL key data. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index d6ed578..317ace7 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -2875,7 +2875,7 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, if (orinoco_lock(priv, &flags) != 0) return -EBUSY; - if (erq->pointer) { + if (erq->length > 0) { if ((index < 0) || (index >= ORINOCO_MAX_KEYS)) index = priv->tx_key; @@ -2918,7 +2918,7 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, if (erq->flags & IW_ENCODE_RESTRICTED) restricted = 1; - if (erq->pointer) { + if (erq->pointer && erq->length > 0) { priv->keys[index].len = cpu_to_le16(xlen); memset(priv->keys[index].data, 0, sizeof(priv->keys[index].data)); -- cgit v1.1 From 8279d2e6062673f31c59ad9e2104024123154267 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Thu, 6 Jul 2006 18:03:06 +1000 Subject: [POWERPC] Xserve G5 thermal control fixes The thermal control for the Xserve G5s had a few issues. For one, the way to program the RPM fans speeds into the FCU is different between it and the desktop models, which I didn't figure out until recently, and it was missing a control loop for the slots fan, running it too fast. Both of those problems were causing the machine to be much more noisy than necessary. This patch also changes the fixed value of the slots fan for desktop G5s to 40% instead of 50%. It seems to still have a pretty good airflow that way and is much less noisy. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- drivers/macintosh/therm_pm72.c | 218 ++++++++++++++++++++++++++++++++++++++--- drivers/macintosh/therm_pm72.h | 33 ++++++- 2 files changed, 234 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/macintosh/therm_pm72.c b/drivers/macintosh/therm_pm72.c index c1fe0b3..20bf672 100644 --- a/drivers/macintosh/therm_pm72.c +++ b/drivers/macintosh/therm_pm72.c @@ -95,6 +95,17 @@ * - Use min/max macros here or there * - Latest darwin updated U3H min fan speed to 20% PWM * + * July. 06, 2006 : 1.3 + * - Fix setting of RPM fans on Xserve G5 (they were going too fast) + * - Add missing slots fan control loop for Xserve G5 + * - Lower fixed slots fan speed from 50% to 40% on desktop G5s. We + * still can't properly implement the control loop for these, so let's + * reduce the noise a little bit, it appears that 40% still gives us + * a pretty good air flow + * - Add code to "tickle" the FCU regulary so it doesn't think that + * we are gone while in fact, the machine just didn't need any fan + * speed change lately + * */ #include @@ -121,7 +132,7 @@ #include "therm_pm72.h" -#define VERSION "1.2b2" +#define VERSION "1.3" #undef DEBUG @@ -146,6 +157,7 @@ static struct basckside_pid_params backside_params; static struct backside_pid_state backside_state; static struct drives_pid_state drives_state; static struct dimm_pid_state dimms_state; +static struct slots_pid_state slots_state; static int state; static int cpu_count; static int cpu_pid_type; @@ -154,7 +166,8 @@ static struct completion ctrl_complete; static int critical_state; static int rackmac; static s32 dimm_output_clamp; - +static int fcu_rpm_shift; +static int fcu_tickle_ticks; static DECLARE_MUTEX(driver_lock); /* @@ -495,13 +508,20 @@ static int start_fcu(void) rc = fan_write_reg(0x2e, &buf, 1); if (rc < 0) return -EIO; + rc = fan_read_reg(0, &buf, 1); + if (rc < 0) + return -EIO; + fcu_rpm_shift = (buf == 1) ? 2 : 3; + printk(KERN_DEBUG "FCU Initialized, RPM fan shift is %d\n", + fcu_rpm_shift); + return 0; } static int set_rpm_fan(int fan_index, int rpm) { unsigned char buf[2]; - int rc, id; + int rc, id, min, max; if (fcu_fans[fan_index].type != FCU_FAN_RPM) return -EINVAL; @@ -509,12 +529,15 @@ static int set_rpm_fan(int fan_index, int rpm) if (id == FCU_FAN_ABSENT_ID) return -EINVAL; - if (rpm < 300) - rpm = 300; - else if (rpm > 8191) - rpm = 8191; - buf[0] = rpm >> 5; - buf[1] = rpm << 3; + min = 2400 >> fcu_rpm_shift; + max = 56000 >> fcu_rpm_shift; + + if (rpm < min) + rpm = min; + else if (rpm > max) + rpm = max; + buf[0] = rpm >> (8 - fcu_rpm_shift); + buf[1] = rpm << fcu_rpm_shift; rc = fan_write_reg(0x10 + (id * 2), buf, 2); if (rc < 0) return -EIO; @@ -551,7 +574,7 @@ static int get_rpm_fan(int fan_index, int programmed) if (rc != 2) return -EIO; - return (buf[0] << 5) | buf[1] >> 3; + return (buf[0] << (8 - fcu_rpm_shift)) | buf[1] >> fcu_rpm_shift; } static int set_pwm_fan(int fan_index, int pwm) @@ -609,6 +632,26 @@ static int get_pwm_fan(int fan_index) return (buf[0] * 1000) / 2559; } +static void tickle_fcu(void) +{ + int pwm; + + pwm = get_pwm_fan(SLOTS_FAN_PWM_INDEX); + + DBG("FCU Tickle, slots fan is: %d\n", pwm); + if (pwm < 0) + pwm = 100; + + if (!rackmac) { + pwm = SLOTS_FAN_DEFAULT_PWM; + } else if (pwm < SLOTS_PID_OUTPUT_MIN) + pwm = SLOTS_PID_OUTPUT_MIN; + + /* That is hopefully enough to make the FCU happy */ + set_pwm_fan(SLOTS_FAN_PWM_INDEX, pwm); +} + + /* * Utility routine to read the CPU calibration EEPROM data * from the device-tree @@ -715,6 +758,9 @@ BUILD_SHOW_FUNC_INT(backside_fan_pwm, backside_state.pwm) BUILD_SHOW_FUNC_FIX(drives_temperature, drives_state.last_temp) BUILD_SHOW_FUNC_INT(drives_fan_rpm, drives_state.rpm) +BUILD_SHOW_FUNC_FIX(slots_temperature, slots_state.last_temp) +BUILD_SHOW_FUNC_INT(slots_fan_pwm, slots_state.pwm) + BUILD_SHOW_FUNC_FIX(dimms_temperature, dimms_state.last_temp) static DEVICE_ATTR(cpu0_temperature,S_IRUGO,show_cpu0_temperature,NULL); @@ -735,6 +781,9 @@ static DEVICE_ATTR(backside_fan_pwm,S_IRUGO,show_backside_fan_pwm,NULL); static DEVICE_ATTR(drives_temperature,S_IRUGO,show_drives_temperature,NULL); static DEVICE_ATTR(drives_fan_rpm,S_IRUGO,show_drives_fan_rpm,NULL); +static DEVICE_ATTR(slots_temperature,S_IRUGO,show_slots_temperature,NULL); +static DEVICE_ATTR(slots_fan_pwm,S_IRUGO,show_slots_fan_pwm,NULL); + static DEVICE_ATTR(dimms_temperature,S_IRUGO,show_dimms_temperature,NULL); /* @@ -1076,6 +1125,9 @@ static void do_monitor_cpu_rack(struct cpu_pid_state *state) fan_min = dimm_output_clamp; fan_min = max(fan_min, (int)state->mpu.rminn_intake_fan); + DBG(" CPU min mpu = %d, min dimm = %d\n", + state->mpu.rminn_intake_fan, dimm_output_clamp); + state->rpm = max(state->rpm, (int)fan_min); state->rpm = min(state->rpm, (int)state->mpu.rmaxn_intake_fan); state->intake_rpm = state->rpm; @@ -1374,7 +1426,8 @@ static void do_monitor_drives(struct drives_pid_state *state) DBG(" current rpm: %d\n", state->rpm); /* Get some sensor readings */ - temp = le16_to_cpu(i2c_smbus_read_word_data(state->monitor, DS1775_TEMP)) << 8; + temp = le16_to_cpu(i2c_smbus_read_word_data(state->monitor, + DS1775_TEMP)) << 8; state->last_temp = temp; DBG(" temp: %d.%03d, target: %d.%03d\n", FIX32TOPRINT(temp), FIX32TOPRINT(DRIVES_PID_INPUT_TARGET)); @@ -1575,7 +1628,7 @@ static int init_dimms_state(struct dimm_pid_state *state) } /* - * Dispose of the state data for the drives control loop + * Dispose of the state data for the DIMM control loop */ static void dispose_dimms_state(struct dimm_pid_state *state) { @@ -1588,6 +1641,127 @@ static void dispose_dimms_state(struct dimm_pid_state *state) state->monitor = NULL; } +/* + * Slots fan control loop + */ +static void do_monitor_slots(struct slots_pid_state *state) +{ + s32 temp, integral, derivative; + s64 integ_p, deriv_p, prop_p, sum; + int i, rc; + + if (--state->ticks != 0) + return; + state->ticks = SLOTS_PID_INTERVAL; + + DBG("slots:\n"); + + /* Check fan status */ + rc = get_pwm_fan(SLOTS_FAN_PWM_INDEX); + if (rc < 0) { + printk(KERN_WARNING "Error %d reading slots fan !\n", rc); + /* XXX What do we do now ? */ + } else + state->pwm = rc; + DBG(" current pwm: %d\n", state->pwm); + + /* Get some sensor readings */ + temp = le16_to_cpu(i2c_smbus_read_word_data(state->monitor, + DS1775_TEMP)) << 8; + state->last_temp = temp; + DBG(" temp: %d.%03d, target: %d.%03d\n", FIX32TOPRINT(temp), + FIX32TOPRINT(SLOTS_PID_INPUT_TARGET)); + + /* Store temperature and error in history array */ + state->cur_sample = (state->cur_sample + 1) % SLOTS_PID_HISTORY_SIZE; + state->sample_history[state->cur_sample] = temp; + state->error_history[state->cur_sample] = temp - SLOTS_PID_INPUT_TARGET; + + /* If first loop, fill the history table */ + if (state->first) { + for (i = 0; i < (SLOTS_PID_HISTORY_SIZE - 1); i++) { + state->cur_sample = (state->cur_sample + 1) % + SLOTS_PID_HISTORY_SIZE; + state->sample_history[state->cur_sample] = temp; + state->error_history[state->cur_sample] = + temp - SLOTS_PID_INPUT_TARGET; + } + state->first = 0; + } + + /* Calculate the integral term */ + sum = 0; + integral = 0; + for (i = 0; i < SLOTS_PID_HISTORY_SIZE; i++) + integral += state->error_history[i]; + integral *= SLOTS_PID_INTERVAL; + DBG(" integral: %08x\n", integral); + integ_p = ((s64)SLOTS_PID_G_r) * (s64)integral; + DBG(" integ_p: %d\n", (int)(integ_p >> 36)); + sum += integ_p; + + /* Calculate the derivative term */ + derivative = state->error_history[state->cur_sample] - + state->error_history[(state->cur_sample + SLOTS_PID_HISTORY_SIZE - 1) + % SLOTS_PID_HISTORY_SIZE]; + derivative /= SLOTS_PID_INTERVAL; + deriv_p = ((s64)SLOTS_PID_G_d) * (s64)derivative; + DBG(" deriv_p: %d\n", (int)(deriv_p >> 36)); + sum += deriv_p; + + /* Calculate the proportional term */ + prop_p = ((s64)SLOTS_PID_G_p) * (s64)(state->error_history[state->cur_sample]); + DBG(" prop_p: %d\n", (int)(prop_p >> 36)); + sum += prop_p; + + /* Scale sum */ + sum >>= 36; + + DBG(" sum: %d\n", (int)sum); + state->pwm = (s32)sum; + + state->pwm = max(state->pwm, SLOTS_PID_OUTPUT_MIN); + state->pwm = min(state->pwm, SLOTS_PID_OUTPUT_MAX); + + DBG("** DRIVES PWM: %d\n", (int)state->pwm); + set_pwm_fan(SLOTS_FAN_PWM_INDEX, state->pwm); +} + +/* + * Initialize the state structure for the slots bay fan control loop + */ +static int init_slots_state(struct slots_pid_state *state) +{ + state->ticks = 1; + state->first = 1; + state->pwm = 50; + + state->monitor = attach_i2c_chip(XSERVE_SLOTS_LM75, "slots_temp"); + if (state->monitor == NULL) + return -ENODEV; + + device_create_file(&of_dev->dev, &dev_attr_slots_temperature); + device_create_file(&of_dev->dev, &dev_attr_slots_fan_pwm); + + return 0; +} + +/* + * Dispose of the state data for the slots control loop + */ +static void dispose_slots_state(struct slots_pid_state *state) +{ + if (state->monitor == NULL) + return; + + device_remove_file(&of_dev->dev, &dev_attr_slots_temperature); + device_remove_file(&of_dev->dev, &dev_attr_slots_fan_pwm); + + detach_i2c_chip(state->monitor); + state->monitor = NULL; +} + + static int call_critical_overtemp(void) { char *argv[] = { critical_overtemp_path, NULL }; @@ -1617,14 +1791,17 @@ static int main_control_loop(void *x) goto out; } - /* Set the PCI fan once for now */ - set_pwm_fan(SLOTS_FAN_PWM_INDEX, SLOTS_FAN_DEFAULT_PWM); + /* Set the PCI fan once for now on non-RackMac */ + if (!rackmac) + set_pwm_fan(SLOTS_FAN_PWM_INDEX, SLOTS_FAN_DEFAULT_PWM); /* Initialize ADCs */ initialize_adc(&cpu_state[0]); if (cpu_state[1].monitor != NULL) initialize_adc(&cpu_state[1]); + fcu_tickle_ticks = FCU_TICKLE_TICKS; + up(&driver_lock); while (state == state_attached) { @@ -1634,6 +1811,12 @@ static int main_control_loop(void *x) down(&driver_lock); + /* Tickle the FCU just in case */ + if (--fcu_tickle_ticks < 0) { + fcu_tickle_ticks = FCU_TICKLE_TICKS; + tickle_fcu(); + } + /* First, we always calculate the new DIMMs state on an Xserve */ if (rackmac) do_monitor_dimms(&dimms_state); @@ -1654,7 +1837,9 @@ static int main_control_loop(void *x) } /* Then, the rest */ do_monitor_backside(&backside_state); - if (!rackmac) + if (rackmac) + do_monitor_slots(&slots_state); + else do_monitor_drives(&drives_state); up(&driver_lock); @@ -1696,6 +1881,7 @@ static void dispose_control_loops(void) dispose_cpu_state(&cpu_state[1]); dispose_backside_state(&backside_state); dispose_drives_state(&drives_state); + dispose_slots_state(&slots_state); dispose_dimms_state(&dimms_state); } @@ -1745,6 +1931,8 @@ static int create_control_loops(void) goto fail; if (rackmac && init_dimms_state(&dimms_state)) goto fail; + if (rackmac && init_slots_state(&slots_state)) + goto fail; if (!rackmac && init_drives_state(&drives_state)) goto fail; diff --git a/drivers/macintosh/therm_pm72.h b/drivers/macintosh/therm_pm72.h index fc7e9b7..393cc9d 100644 --- a/drivers/macintosh/therm_pm72.h +++ b/drivers/macintosh/therm_pm72.h @@ -105,6 +105,7 @@ static char * critical_overtemp_path = "/sbin/critical_overtemp"; #define DRIVES_DALLAS_ID 0x94 #define BACKSIDE_MAX_ID 0x98 #define XSERVE_DIMMS_LM87 0x25a +#define XSERVE_SLOTS_LM75 0x290 /* * Some MAX6690, DS1775, LM87 register definitions @@ -198,7 +199,7 @@ struct drives_pid_state #define SLOTS_FAN_PWM_DEFAULT_ID 2 #define SLOTS_FAN_PWM_INDEX 2 -#define SLOTS_FAN_DEFAULT_PWM 50 /* Do better here ! */ +#define SLOTS_FAN_DEFAULT_PWM 40 /* Do better here ! */ /* @@ -206,7 +207,7 @@ struct drives_pid_state */ #define DIMM_PID_G_d 0 #define DIMM_PID_G_p 0 -#define DIMM_PID_G_r 0x6553600 +#define DIMM_PID_G_r 0x06553600 #define DIMM_PID_INPUT_TARGET 3276800 #define DIMM_PID_INTERVAL 1 #define DIMM_PID_OUTPUT_MAX 14000 @@ -226,6 +227,31 @@ struct dimm_pid_state }; +/* + * PID factors for the Xserve Slots control loop + */ +#define SLOTS_PID_G_d 0 +#define SLOTS_PID_G_p 0 +#define SLOTS_PID_G_r 0x00100000 +#define SLOTS_PID_INPUT_TARGET 3200000 +#define SLOTS_PID_INTERVAL 1 +#define SLOTS_PID_OUTPUT_MAX 100 +#define SLOTS_PID_OUTPUT_MIN 20 +#define SLOTS_PID_HISTORY_SIZE 20 + +struct slots_pid_state +{ + int ticks; + struct i2c_client * monitor; + s32 sample_history[SLOTS_PID_HISTORY_SIZE]; + s32 error_history[SLOTS_PID_HISTORY_SIZE]; + int cur_sample; + s32 last_temp; + int first; + int pwm; +}; + + /* Desktops */ @@ -283,6 +309,9 @@ struct cpu_pid_state s32 pump_max; }; +/* Tickle FCU every 10 seconds */ +#define FCU_TICKLE_TICKS 10 + /* * Driver state */ -- cgit v1.1 From 4c962b5a42e5fc24e2d5d73896732cf3578da260 Mon Sep 17 00:00:00 2001 From: Danny van Dyk Date: Tue, 11 Jul 2006 22:25:28 +0100 Subject: [POWERPC] PMAC_APM_EMU should depend on ADB_PMU This patch fixes undefined refereneces to pmu_ symbols on 2.6.17. Signed-Off-By: Danny van Dyk Signed-off-by: Daniel Drake Signed-off-by: Paul Mackerras --- drivers/macintosh/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig index f18c956..44708b5 100644 --- a/drivers/macintosh/Kconfig +++ b/drivers/macintosh/Kconfig @@ -109,7 +109,7 @@ config PMAC_SMU config PMAC_APM_EMU tristate "APM emulation" - depends on PPC_PMAC && PPC32 && PM + depends on PPC_PMAC && PPC32 && PM && ADB_PMU config PMAC_MEDIABAY bool "Support PowerBook hotswap media bay" -- cgit v1.1 From 361934849e9c0418950bedf667732f36337d88b9 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Fri, 28 Jul 2006 08:54:59 +0200 Subject: [PATCH] ide: option to disable cache flushes for buggy drives Some drives claim they support cache flushing, but get seriously confused if you try. Add this option to be able to boot with barriers enabled by default. Signed-off-by: Jens Axboe --- drivers/ide/ide-disk.c | 2 +- drivers/ide/ide.c | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c index f712e4c..7cf3eb0 100644 --- a/drivers/ide/ide-disk.c +++ b/drivers/ide/ide-disk.c @@ -776,7 +776,7 @@ static void update_ordered(ide_drive_t *drive) * not available so we don't need to recheck that. */ capacity = idedisk_capacity(drive); - barrier = ide_id_has_flush_cache(id) && + barrier = ide_id_has_flush_cache(id) && !drive->noflush && (drive->addressing == 0 || capacity <= (1ULL << 28) || ide_id_has_flush_cache_ext(id)); diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index 05fbd92..defd4b4 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -1539,7 +1539,7 @@ static int __init ide_setup(char *s) const char *hd_words[] = { "none", "noprobe", "nowerr", "cdrom", "serialize", "autotune", "noautotune", "minus8", "swapdata", "bswap", - "minus11", "remap", "remap63", "scsi", NULL }; + "noflush", "remap", "remap63", "scsi", NULL }; unit = s[2] - 'a'; hw = unit / MAX_DRIVES; unit = unit % MAX_DRIVES; @@ -1578,6 +1578,9 @@ static int __init ide_setup(char *s) case -10: /* "bswap" */ drive->bswap = 1; goto done; + case -11: /* noflush */ + drive->noflush = 1; + goto done; case -12: /* "remap" */ drive->remap_0_to_1 = 1; goto done; -- cgit v1.1 From 0a8348d08677ad77ee353f96eb8745c693a05a13 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Fri, 28 Jul 2006 08:58:26 +0200 Subject: [PATCH] ide: if the id fields looks screwy, disable DMA It's the safer choice. Originally due to a bug in itx821x, but a generally sound thing to do. Signed-off-by: Jens Axboe --- drivers/ide/ide-dma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c index 98918fb..7c3a13e 100644 --- a/drivers/ide/ide-dma.c +++ b/drivers/ide/ide-dma.c @@ -750,7 +750,7 @@ void ide_dma_verbose(ide_drive_t *drive) goto bug_dma_off; printk(", DMA"); } else if (id->field_valid & 1) { - printk(", BUG"); + goto bug_dma_off; } return; bug_dma_off: -- cgit v1.1 From 71ef51cc1756d1c56b57c70e7cc27a3559c81ee6 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Fri, 28 Jul 2006 09:02:17 +0200 Subject: [PATCH] it821x: fix ide dma setup bug Only enable dma for a valid speed setting. Signed-off-by: Jens Axboe --- drivers/ide/pci/it821x.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/ide/pci/it821x.c b/drivers/ide/pci/it821x.c index 3cb0442..e9bad18 100644 --- a/drivers/ide/pci/it821x.c +++ b/drivers/ide/pci/it821x.c @@ -498,9 +498,14 @@ static int config_chipset_for_dma (ide_drive_t *drive) { u8 speed = ide_dma_speed(drive, it821x_ratemask(drive)); - config_it821x_chipset_for_pio(drive, !speed); - it821x_tune_chipset(drive, speed); - return ide_dma_enable(drive); + if (speed) { + config_it821x_chipset_for_pio(drive, 0); + it821x_tune_chipset(drive, speed); + + return ide_dma_enable(drive); + } + + return 0; } /** -- cgit v1.1 From a75ad3c27a6ad78c4306cac939938050dcde54f3 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Fri, 28 Jul 2006 09:04:09 +0200 Subject: [PATCH] scsi: kill overeager "not-ready" messages HAL and friends have a tendency to trigger this one all the time. It's not really interesting, so kill it. The vendor kernels all do anyways. Signed-off-by: Jens Axboe --- drivers/scsi/scsi_ioctl.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c index a89c411..32293f4 100644 --- a/drivers/scsi/scsi_ioctl.c +++ b/drivers/scsi/scsi_ioctl.c @@ -110,11 +110,8 @@ static int ioctl_internal_command(struct scsi_device *sdev, char *cmd, sshdr.asc, sshdr.ascq); break; case NOT_READY: /* This happens if there is no disc in drive */ - if (sdev->removable && (cmd[0] != TEST_UNIT_READY)) { - printk(KERN_INFO "Device not ready. Make sure" - " there is a disc in the drive.\n"); + if (sdev->removable) break; - } case UNIT_ATTENTION: if (sdev->removable) { sdev->changed = 1; -- cgit v1.1 From 93853fd0d492524e9172297d8e8b8364dc2c4c59 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Fri, 28 Jul 2006 01:09:40 -0700 Subject: [SUNLANCE]: fix compilation on sparc-UP Signed-off-by: Alexey Dobriyan Signed-off-by: David S. Miller --- drivers/net/sunlance.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c index 1ef9fd3..0e3fdf7 100644 --- a/drivers/net/sunlance.c +++ b/drivers/net/sunlance.c @@ -1537,7 +1537,7 @@ static int __init sparc_lance_init(void) { if ((idprom->id_machtype == (SM_SUN4|SM_4_330)) || (idprom->id_machtype == (SM_SUN4|SM_4_470))) { - memset(&sun4_sdev, 0, sizeof(sdev)); + memset(&sun4_sdev, 0, sizeof(struct sbus_dev)); sun4_sdev.reg_addrs[0].phys_addr = sun4_eth_physaddr; sun4_sdev.irqs[0] = 6; return sparc_lance_probe_one(&sun4_sdev, NULL, NULL); @@ -1547,16 +1547,16 @@ static int __init sparc_lance_init(void) static int __exit sunlance_sun4_remove(void) { - struct lance_private *lp = dev_get_drvdata(&sun4_sdev->dev); + struct lance_private *lp = dev_get_drvdata(&sun4_sdev.ofdev.dev); struct net_device *net_dev = lp->dev; unregister_netdevice(net_dev); - lance_free_hwresources(root_lance_dev); + lance_free_hwresources(lp); free_netdev(net_dev); - dev_set_drvdata(&sun4_sdev->dev, NULL); + dev_set_drvdata(&sun4_sdev.ofdev.dev, NULL); return 0; } -- cgit v1.1 From b2b3c121076961333977f485f0d54c22121df920 Mon Sep 17 00:00:00 2001 From: Grant Grundler Date: Mon, 17 Jul 2006 07:22:45 -0600 Subject: [SCSI] sym2: claim only "Storage" class The follow patch fixes a problem for Matt Taggart. The Compaq system he had (dl380?) has a SmartArray device that exposes the 53c1510 device in both RAID and "normal" modes. The difference is in RAID mode, the smart array driver (IIRC) should claim the device instead of sym2 driver. Patch below prevents sym2 from claiming the device when the RAID "daughter board" is attached. Signed-off-by: Grant Grundler Signed-off-by: James Bottomley --- drivers/scsi/sym53c8xx_2/sym_glue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c index 8c50507..739d3ef 100644 --- a/drivers/scsi/sym53c8xx_2/sym_glue.c +++ b/drivers/scsi/sym53c8xx_2/sym_glue.c @@ -2084,7 +2084,7 @@ static struct pci_device_id sym2_id_table[] __devinitdata = { { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C860, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_53C1510, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, + PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_SCSI<<8, 0xffff00, 0UL }, { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C896, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C895, -- cgit v1.1 From 8d4fbd3f978ba49498dc7c6430368c4ff86a09fc Mon Sep 17 00:00:00 2001 From: HighPoint Linux Team Date: Mon, 24 Jul 2006 15:48:54 +0800 Subject: [SCSI] hptiop: wrong register used in hptiop_reset_hba() IOP reset message should be posted to inbound message register instead of outbound message register. Signed-off-by: HighPoint Linux Team Signed-off-by: James Bottomley --- drivers/scsi/hptiop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/hptiop.c b/drivers/scsi/hptiop.c index ab2f8b2..74d4d22 100644 --- a/drivers/scsi/hptiop.c +++ b/drivers/scsi/hptiop.c @@ -577,7 +577,7 @@ static int hptiop_reset_hba(struct hptiop_hba *hba) if (atomic_xchg(&hba->resetting, 1) == 0) { atomic_inc(&hba->reset_count); writel(IOPMU_INBOUND_MSG0_RESET, - &hba->iop->outbound_msgaddr0); + &hba->iop->inbound_msgaddr0); hptiop_pci_posting_flush(hba->iop); } -- cgit v1.1 From d82967c70658a408ea6cae5dc989ba8b2c0999e1 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Mon, 24 Jul 2006 15:47:11 -0500 Subject: [SCSI] iscsi bugfixes: send correct error values to userspace In the xmit patch we are sending a -EXXX value to iscsi_conn_failure which is causing userspace to get confused. We should be sending a ISCSI_ERR_* value that userspace understands. Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/iscsi_tcp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 848fb2a..88dafdf 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -843,7 +843,7 @@ more: if (rc == -EAGAIN) goto nomore; else { - iscsi_conn_failure(conn, rc); + iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); return 0; } } @@ -859,7 +859,7 @@ more: } tcp_conn->in_progress = IN_PROGRESS_DATA_RECV; } else if (rc) { - iscsi_conn_failure(conn, rc); + iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); return 0; } } @@ -897,7 +897,7 @@ more: if (rc) { if (rc == -EAGAIN) goto again; - iscsi_conn_failure(conn, rc); + iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); return 0; } tcp_conn->in.copy -= tcp_conn->in.padding; -- cgit v1.1 From b6c395ed0387c824ddf125d3b74b576a2575c149 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Mon, 24 Jul 2006 15:47:15 -0500 Subject: [SCSI] iscsi bugfixes: fix r2t handling The iscsi tcp code can pluck multiple rt2s from the tasks's r2tqueue in the xmit code. This can result in the task being queued on the xmit queue but gettting completed at the same time. This patch fixes the above bug by making the fifo a list so we always remove the entry on the list del. Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/iscsi_tcp.c | 45 +++++++++++------------- drivers/scsi/libiscsi.c | 90 ++++++++++++++++++++---------------------------- 2 files changed, 59 insertions(+), 76 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 88dafdf..ab324d9 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -185,11 +185,19 @@ iscsi_hdr_extract(struct iscsi_tcp_conn *tcp_conn) * must be called with session lock */ static void -__iscsi_ctask_cleanup(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) +iscsi_tcp_cleanup_ctask(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) { struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; + struct iscsi_r2t_info *r2t; struct scsi_cmnd *sc; + /* flush ctask's r2t queues */ + while (__kfifo_get(tcp_ctask->r2tqueue, (void*)&r2t, sizeof(void*))) { + __kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t, + sizeof(void*)); + debug_scsi("iscsi_tcp_cleanup_ctask pending r2t dropped\n"); + } + sc = ctask->sc; if (unlikely(!sc)) return; @@ -374,6 +382,7 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) spin_unlock(&session->lock); return 0; } + rc = __kfifo_get(tcp_ctask->r2tpool.queue, (void*)&r2t, sizeof(void*)); BUG_ON(!rc); @@ -399,7 +408,7 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) tcp_ctask->exp_r2tsn = r2tsn + 1; tcp_ctask->xmstate |= XMSTATE_SOL_HDR; __kfifo_put(tcp_ctask->r2tqueue, (void*)&r2t, sizeof(void*)); - __kfifo_put(conn->xmitqueue, (void*)&ctask, sizeof(void*)); + list_move_tail(&ctask->running, &conn->xmitqueue); scsi_queue_work(session->host, &conn->xmitwork); conn->r2t_pdus_cnt++; @@ -484,7 +493,7 @@ iscsi_tcp_hdr_recv(struct iscsi_conn *conn) goto copy_hdr; spin_lock(&session->lock); - __iscsi_ctask_cleanup(conn, tcp_conn->in.ctask); + iscsi_tcp_cleanup_ctask(conn, tcp_conn->in.ctask); rc = __iscsi_complete_pdu(conn, hdr, NULL, 0); spin_unlock(&session->lock); break; @@ -745,10 +754,11 @@ static int iscsi_scsi_data_in(struct iscsi_conn *conn) done: /* check for non-exceptional status */ if (tcp_conn->in.hdr->flags & ISCSI_FLAG_DATA_STATUS) { - debug_scsi("done [sc %lx res %d itt 0x%x]\n", - (long)sc, sc->result, ctask->itt); + debug_scsi("done [sc %lx res %d itt 0x%x flags 0x%x]\n", + (long)sc, sc->result, ctask->itt, + tcp_conn->in.hdr->flags); spin_lock(&conn->session->lock); - __iscsi_ctask_cleanup(conn, ctask); + iscsi_tcp_cleanup_ctask(conn, ctask); __iscsi_complete_pdu(conn, tcp_conn->in.hdr, NULL, 0); spin_unlock(&conn->session->lock); } @@ -769,7 +779,7 @@ iscsi_data_recv(struct iscsi_conn *conn) break; case ISCSI_OP_SCSI_CMD_RSP: spin_lock(&conn->session->lock); - __iscsi_ctask_cleanup(conn, tcp_conn->in.ctask); + iscsi_tcp_cleanup_ctask(conn, tcp_conn->in.ctask); spin_unlock(&conn->session->lock); case ISCSI_OP_TEXT_RSP: case ISCSI_OP_LOGIN_RSP: @@ -1308,7 +1318,7 @@ iscsi_tcp_cmd_init(struct iscsi_cmd_task *ctask) ctask->imm_count - ctask->unsol_count; - debug_scsi("cmd [itt %x total %d imm %d imm_data %d " + debug_scsi("cmd [itt 0x%x total %d imm %d imm_data %d " "r2t_data %d]\n", ctask->itt, ctask->total_length, ctask->imm_count, ctask->unsol_count, tcp_ctask->r2t_data_count); @@ -1636,7 +1646,7 @@ handle_xmstate_sol_data(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) } solicit_again: /* - * send Data-Out whitnin this R2T sequence. + * send Data-Out within this R2T sequence. */ if (!r2t->data_count) goto data_out_done; @@ -1731,7 +1741,7 @@ handle_xmstate_w_pad(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; struct iscsi_tcp_conn *tcp_conn = conn->dd_data; struct iscsi_data_task *dtask = tcp_ctask->dtask; - int sent, rc; + int sent = 0, rc; tcp_ctask->xmstate &= ~XMSTATE_W_PAD; iscsi_buf_init_iov(&tcp_ctask->sendbuf, (char*)&tcp_ctask->pad, @@ -2002,20 +2012,6 @@ iscsi_tcp_conn_bind(struct iscsi_cls_session *cls_session, } static void -iscsi_tcp_cleanup_ctask(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) -{ - struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; - struct iscsi_r2t_info *r2t; - - /* flush ctask's r2t queues */ - while (__kfifo_get(tcp_ctask->r2tqueue, (void*)&r2t, sizeof(void*))) - __kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t, - sizeof(void*)); - - __iscsi_ctask_cleanup(conn, ctask); -} - -static void iscsi_tcp_suspend_conn_rx(struct iscsi_conn *conn) { struct iscsi_tcp_conn *tcp_conn = conn->dd_data; @@ -2057,6 +2053,7 @@ iscsi_tcp_mgmt_init(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask, iscsi_buf_init_iov(&tcp_mtask->headbuf, (char*)mtask->hdr, sizeof(struct iscsi_hdr)); tcp_mtask->xmstate = XMSTATE_IMM_HDR; + tcp_mtask->sent = 0; if (mtask->data_count) iscsi_buf_init_iov(&tcp_mtask->sendbuf, (char*)mtask->data, diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 7e6e031..1a8cd20 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -189,6 +189,7 @@ static void iscsi_complete_command(struct iscsi_session *session, { struct scsi_cmnd *sc = ctask->sc; + ctask->state = ISCSI_TASK_COMPLETED; ctask->sc = NULL; list_del_init(&ctask->running); __kfifo_put(session->cmdpool.queue, (void*)&ctask, sizeof(void*)); @@ -568,20 +569,24 @@ static int iscsi_data_xmit(struct iscsi_conn *conn) } /* process command queue */ - while (__kfifo_get(conn->xmitqueue, (void*)&conn->ctask, - sizeof(void*))) { + spin_lock_bh(&conn->session->lock); + while (!list_empty(&conn->xmitqueue)) { /* * iscsi tcp may readd the task to the xmitqueue to send * write data */ - spin_lock_bh(&conn->session->lock); - if (list_empty(&conn->ctask->running)) - list_add_tail(&conn->ctask->running, &conn->run_list); + conn->ctask = list_entry(conn->xmitqueue.next, + struct iscsi_cmd_task, running); + conn->ctask->state = ISCSI_TASK_RUNNING; + list_move_tail(conn->xmitqueue.next, &conn->run_list); spin_unlock_bh(&conn->session->lock); + rc = tt->xmit_cmd_task(conn, conn->ctask); if (rc) goto again; + spin_lock_bh(&conn->session->lock); } + spin_unlock_bh(&conn->session->lock); /* done with this ctask */ conn->ctask = NULL; @@ -691,6 +696,7 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) sc->SCp.phase = session->age; sc->SCp.ptr = (char *)ctask; + ctask->state = ISCSI_TASK_PENDING; ctask->mtask = NULL; ctask->conn = conn; ctask->sc = sc; @@ -700,7 +706,7 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) session->tt->init_cmd_task(ctask); - __kfifo_put(conn->xmitqueue, (void*)&ctask, sizeof(void*)); + list_add_tail(&ctask->running, &conn->xmitqueue); debug_scsi( "ctask enq [%s cid %d sc %lx itt 0x%x len %d cmdsn %d win %d]\n", sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read", @@ -977,31 +983,27 @@ static int iscsi_exec_abort_task(struct scsi_cmnd *sc, /* * xmit mutex and session lock must be held */ -#define iscsi_remove_task(tasktype) \ -static struct iscsi_##tasktype * \ -iscsi_remove_##tasktype(struct kfifo *fifo, uint32_t itt) \ -{ \ - int i, nr_tasks = __kfifo_len(fifo) / sizeof(void*); \ - struct iscsi_##tasktype *task; \ - \ - debug_scsi("searching %d tasks\n", nr_tasks); \ - \ - for (i = 0; i < nr_tasks; i++) { \ - __kfifo_get(fifo, (void*)&task, sizeof(void*)); \ - debug_scsi("check task %u\n", task->itt); \ - \ - if (task->itt == itt) { \ - debug_scsi("matched task\n"); \ - return task; \ - } \ - \ - __kfifo_put(fifo, (void*)&task, sizeof(void*)); \ - } \ - return NULL; \ -} +static struct iscsi_mgmt_task * +iscsi_remove_mgmt_task(struct kfifo *fifo, uint32_t itt) +{ + int i, nr_tasks = __kfifo_len(fifo) / sizeof(void*); + struct iscsi_mgmt_task *task; + + debug_scsi("searching %d tasks\n", nr_tasks); + + for (i = 0; i < nr_tasks; i++) { + __kfifo_get(fifo, (void*)&task, sizeof(void*)); + debug_scsi("check task %u\n", task->itt); + + if (task->itt == itt) { + debug_scsi("matched task\n"); + return task; + } -iscsi_remove_task(mgmt_task); -iscsi_remove_task(cmd_task); + __kfifo_put(fifo, (void*)&task, sizeof(void*)); + } + return NULL; +} static int iscsi_ctask_mtask_cleanup(struct iscsi_cmd_task *ctask) { @@ -1043,7 +1045,6 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) struct iscsi_cmd_task *ctask = (struct iscsi_cmd_task *)sc->SCp.ptr; struct iscsi_conn *conn = ctask->conn; struct iscsi_session *session = conn->session; - struct iscsi_cmd_task *pending_ctask; int rc; conn->eh_abort_cnt++; @@ -1071,17 +1072,8 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) goto failed; } - /* check for the easy pending cmd abort */ - pending_ctask = iscsi_remove_cmd_task(conn->xmitqueue, ctask->itt); - if (pending_ctask) { - /* iscsi_tcp queues write transfers on the xmitqueue */ - if (list_empty(&pending_ctask->running)) { - debug_scsi("found pending task\n"); - goto success; - } else - __kfifo_put(conn->xmitqueue, (void*)&pending_ctask, - sizeof(void*)); - } + if (ctask->state == ISCSI_TASK_PENDING) + goto success; conn->tmabort_state = TMABORT_INITIAL; @@ -1263,6 +1255,7 @@ iscsi_session_setup(struct iscsi_transport *iscsit, if (cmd_task_size) ctask->dd_data = &ctask[1]; ctask->itt = cmd_i; + INIT_LIST_HEAD(&ctask->running); } spin_lock_init(&session->lock); @@ -1282,6 +1275,7 @@ iscsi_session_setup(struct iscsi_transport *iscsit, if (mgmt_task_size) mtask->dd_data = &mtask[1]; mtask->itt = ISCSI_MGMT_ITT_OFFSET + cmd_i; + INIT_LIST_HEAD(&mtask->running); } if (scsi_add_host(shost, NULL)) @@ -1361,12 +1355,7 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, uint32_t conn_idx) conn->tmabort_state = TMABORT_INITIAL; INIT_LIST_HEAD(&conn->run_list); INIT_LIST_HEAD(&conn->mgmt_run_list); - - /* initialize general xmit PDU commands queue */ - conn->xmitqueue = kfifo_alloc(session->cmds_max * sizeof(void*), - GFP_KERNEL, NULL); - if (conn->xmitqueue == ERR_PTR(-ENOMEM)) - goto xmitqueue_alloc_fail; + INIT_LIST_HEAD(&conn->xmitqueue); /* initialize general immediate & non-immediate PDU commands queue */ conn->immqueue = kfifo_alloc(session->mgmtpool_max * sizeof(void*), @@ -1410,8 +1399,6 @@ login_mtask_alloc_fail: mgmtqueue_alloc_fail: kfifo_free(conn->immqueue); immqueue_alloc_fail: - kfifo_free(conn->xmitqueue); -xmitqueue_alloc_fail: iscsi_destroy_conn(cls_conn); return NULL; } @@ -1489,7 +1476,6 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn) session->cmdsn = session->max_cmdsn = session->exp_cmdsn = 1; spin_unlock_bh(&session->lock); - kfifo_free(conn->xmitqueue); kfifo_free(conn->immqueue); kfifo_free(conn->mgmtqueue); @@ -1572,7 +1558,7 @@ static void fail_all_commands(struct iscsi_conn *conn) struct iscsi_cmd_task *ctask, *tmp; /* flush pending */ - while (__kfifo_get(conn->xmitqueue, (void*)&ctask, sizeof(void*))) { + list_for_each_entry_safe(ctask, tmp, &conn->xmitqueue, running) { debug_scsi("failing pending sc %p itt 0x%x\n", ctask->sc, ctask->itt); fail_command(conn, ctask, DID_BUS_BUSY << 16); -- cgit v1.1 From 275fd7d129fdd16d1dc0ec6a8d60bd6b72a76e31 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Mon, 24 Jul 2006 15:47:17 -0500 Subject: [SCSI] iscsi bugfixes: handle data rsp errors if iscsi_data_rsp fails we must bail out. Since the pdu values like data length are invalid we cannot continue to process the data since it could over run buffers. This fixes a bug with cisco 5428s where that target is sending too much data. Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/iscsi_tcp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index ab324d9..7d78459 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -486,6 +486,8 @@ iscsi_tcp_hdr_recv(struct iscsi_conn *conn) case ISCSI_OP_SCSI_DATA_IN: tcp_conn->in.ctask = session->cmds[itt]; rc = iscsi_data_rsp(conn, tcp_conn->in.ctask); + if (rc) + return rc; /* fall through */ case ISCSI_OP_SCSI_CMD_RSP: tcp_conn->in.ctask = session->cmds[itt]; @@ -532,7 +534,7 @@ copy_hdr: * skbs to complete the command then we have to copy the header * for later use */ - if (tcp_conn->in.zero_copy_hdr && tcp_conn->in.copy < + if (tcp_conn->in.zero_copy_hdr && tcp_conn->in.copy <= (tcp_conn->in.datalen + tcp_conn->in.padding + (conn->datadgst_en ? 4 : 0))) { debug_tcp("Copying header for later use. in.copy %d in.datalen" -- cgit v1.1 From 7ea8b82847293c2311cf08fc3ed31ab0e452a27e Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Mon, 24 Jul 2006 15:47:22 -0500 Subject: [SCSI] iscsi bugfixes: fix abort handling Abort handler fixes. If a connection is dropped and reconnected while an abort is running then we should assume the recovery code will clean up the abort. Not doing so causes a oops. And if a command completes then we get the status for the abort, we do not need to call into the LLD to cleanup the resources. Doing this causes and oops in iser because it ends up freeing some resources twice. Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/libiscsi.c | 71 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 46 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 1a8cd20..4e2ca8f 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -276,6 +276,25 @@ out: return rc; } +static void iscsi_tmf_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr) +{ + struct iscsi_tm_rsp *tmf = (struct iscsi_tm_rsp *)hdr; + + conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1; + conn->tmfrsp_pdus_cnt++; + + if (conn->tmabort_state != TMABORT_INITIAL) + return; + + if (tmf->response == ISCSI_TMF_RSP_COMPLETE) + conn->tmabort_state = TMABORT_SUCCESS; + else if (tmf->response == ISCSI_TMF_RSP_NO_TASK) + conn->tmabort_state = TMABORT_NOT_FOUND; + else + conn->tmabort_state = TMABORT_FAILED; + wake_up(&conn->ehwait); +} + /** * __iscsi_complete_pdu - complete pdu * @conn: iscsi conn @@ -361,16 +380,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, break; } - conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1; - conn->tmfrsp_pdus_cnt++; - if (conn->tmabort_state == TMABORT_INITIAL) { - conn->tmabort_state = - ((struct iscsi_tm_rsp *)hdr)-> - response == ISCSI_TMF_RSP_COMPLETE ? - TMABORT_SUCCESS:TMABORT_FAILED; - /* unblock eh_abort() */ - wake_up(&conn->ehwait); - } + iscsi_tmf_rsp(conn, hdr); break; case ISCSI_OP_NOOP_IN: if (hdr->ttt != ISCSI_RESERVED_TAG) { @@ -1029,12 +1039,13 @@ static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, { struct scsi_cmnd *sc; - conn->session->tt->cleanup_cmd_task(conn, ctask); - iscsi_ctask_mtask_cleanup(ctask); - sc = ctask->sc; if (!sc) return; + + conn->session->tt->cleanup_cmd_task(conn, ctask); + iscsi_ctask_mtask_cleanup(ctask); + sc->result = err; sc->resid = sc->request_bufflen; iscsi_complete_command(conn->session, ctask); @@ -1062,8 +1073,11 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) goto failed; /* ctask completed before time out */ - if (!ctask->sc) - goto success; + if (!ctask->sc) { + spin_unlock_bh(&session->lock); + debug_scsi("sc completed while abort in progress\n"); + goto success_rel_mutex; + } /* what should we do here ? */ if (conn->ctask == ctask) { @@ -1073,7 +1087,7 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) } if (ctask->state == ISCSI_TASK_PENDING) - goto success; + goto success_cleanup; conn->tmabort_state = TMABORT_INITIAL; @@ -1081,25 +1095,31 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) rc = iscsi_exec_abort_task(sc, ctask); spin_lock_bh(&session->lock); - iscsi_ctask_mtask_cleanup(ctask); if (rc || sc->SCp.phase != session->age || session->state != ISCSI_STATE_LOGGED_IN) goto failed; + iscsi_ctask_mtask_cleanup(ctask); - /* ctask completed before tmf abort response */ - if (!ctask->sc) { - debug_scsi("sc completed while abort in progress\n"); - goto success; - } - - if (conn->tmabort_state != TMABORT_SUCCESS) { + switch (conn->tmabort_state) { + case TMABORT_SUCCESS: + goto success_cleanup; + case TMABORT_NOT_FOUND: + if (!ctask->sc) { + /* ctask completed before tmf abort response */ + spin_unlock_bh(&session->lock); + debug_scsi("sc completed while abort in progress\n"); + goto success_rel_mutex; + } + /* fall through */ + default: + /* timedout or failed */ spin_unlock_bh(&session->lock); iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); spin_lock_bh(&session->lock); goto failed; } -success: +success_cleanup: debug_scsi("abort success [sc %lx itt 0x%x]\n", (long)sc, ctask->itt); spin_unlock_bh(&session->lock); @@ -1113,6 +1133,7 @@ success: spin_unlock(&session->lock); write_unlock_bh(conn->recv_lock); +success_rel_mutex: mutex_unlock(&conn->xmitmutex); return SUCCESS; -- cgit v1.1 From 1c83469d36a9dd30dbf1fb9fc5ca3be3a0e64ff4 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Mon, 24 Jul 2006 15:47:26 -0500 Subject: [SCSI] iscsi bugfixes: fix oops when iser is flushing io When we enter recovery and flush the running commands we cannot freee the connection before flushing the commands. Some commands may have a reference to the connection that needs to be released before. iscsi_stop was forcing the term and suspend too early and was causing a oops in iser, so this patch removes those callbacks all together and allows the LLD to handle that detail. Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/infiniband/ulp/iser/iscsi_iser.c | 22 +---------- drivers/scsi/iscsi_tcp.c | 67 ++++++++++++++------------------ drivers/scsi/libiscsi.c | 12 ++---- 3 files changed, 34 insertions(+), 67 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c index 34b0da5..1437d7e 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.c +++ b/drivers/infiniband/ulp/iser/iscsi_iser.c @@ -378,21 +378,6 @@ iscsi_iser_conn_start(struct iscsi_cls_conn *cls_conn) return iser_conn_set_full_featured_mode(conn); } -static void -iscsi_iser_conn_terminate(struct iscsi_conn *conn) -{ - struct iscsi_iser_conn *iser_conn = conn->dd_data; - struct iser_conn *ib_conn = iser_conn->ib_conn; - - BUG_ON(!ib_conn); - /* starts conn teardown process, waits until all previously * - * posted buffers get flushed, deallocates all conn resources */ - iser_conn_terminate(ib_conn); - iser_conn->ib_conn = NULL; - conn->recv_lock = NULL; -} - - static struct iscsi_transport iscsi_iser_transport; static struct iscsi_cls_session * @@ -555,13 +540,13 @@ iscsi_iser_ep_poll(__u64 ep_handle, int timeout_ms) static void iscsi_iser_ep_disconnect(__u64 ep_handle) { - struct iser_conn *ib_conn = iscsi_iser_ib_conn_lookup(ep_handle); + struct iser_conn *ib_conn; + ib_conn = iscsi_iser_ib_conn_lookup(ep_handle); if (!ib_conn) return; iser_err("ib conn %p state %d\n",ib_conn, ib_conn->state); - iser_conn_terminate(ib_conn); } @@ -614,9 +599,6 @@ static struct iscsi_transport iscsi_iser_transport = { .get_session_param = iscsi_session_get_param, .start_conn = iscsi_iser_conn_start, .stop_conn = iscsi_conn_stop, - /* these are called as part of conn recovery */ - .suspend_conn_recv = NULL, /* FIXME is/how this relvant to iser? */ - .terminate_conn = iscsi_iser_conn_terminate, /* IO */ .send_pdu = iscsi_conn_send_pdu, .get_stats = iscsi_iser_conn_get_stats, diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 7d78459..b6c68be 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -1040,9 +1040,8 @@ iscsi_conn_set_callbacks(struct iscsi_conn *conn) } static void -iscsi_conn_restore_callbacks(struct iscsi_conn *conn) +iscsi_conn_restore_callbacks(struct iscsi_tcp_conn *tcp_conn) { - struct iscsi_tcp_conn *tcp_conn = conn->dd_data; struct sock *sk = tcp_conn->sock->sk; /* restore socket callbacks, see also: iscsi_conn_set_callbacks() */ @@ -1933,6 +1932,23 @@ tcp_conn_alloc_fail: } static void +iscsi_tcp_release_conn(struct iscsi_conn *conn) +{ + struct iscsi_tcp_conn *tcp_conn = conn->dd_data; + + if (!tcp_conn->sock) + return; + + sock_hold(tcp_conn->sock->sk); + iscsi_conn_restore_callbacks(tcp_conn); + sock_put(tcp_conn->sock->sk); + + sock_release(tcp_conn->sock); + tcp_conn->sock = NULL; + conn->recv_lock = NULL; +} + +static void iscsi_tcp_conn_destroy(struct iscsi_cls_conn *cls_conn) { struct iscsi_conn *conn = cls_conn->dd_data; @@ -1942,6 +1958,7 @@ iscsi_tcp_conn_destroy(struct iscsi_cls_conn *cls_conn) if (conn->hdrdgst_en || conn->datadgst_en) digest = 1; + iscsi_tcp_release_conn(conn); iscsi_conn_teardown(cls_conn); /* now free tcp_conn */ @@ -1965,6 +1982,15 @@ iscsi_tcp_conn_destroy(struct iscsi_cls_conn *cls_conn) kfree(tcp_conn); } +static void +iscsi_tcp_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) +{ + struct iscsi_conn *conn = cls_conn->dd_data; + + iscsi_conn_stop(cls_conn, flag); + iscsi_tcp_release_conn(conn); +} + static int iscsi_tcp_conn_bind(struct iscsi_cls_session *cls_session, struct iscsi_cls_conn *cls_conn, uint64_t transport_eph, @@ -2013,38 +2039,6 @@ iscsi_tcp_conn_bind(struct iscsi_cls_session *cls_session, return 0; } -static void -iscsi_tcp_suspend_conn_rx(struct iscsi_conn *conn) -{ - struct iscsi_tcp_conn *tcp_conn = conn->dd_data; - struct sock *sk; - - if (!tcp_conn->sock) - return; - - sk = tcp_conn->sock->sk; - write_lock_bh(&sk->sk_callback_lock); - set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx); - write_unlock_bh(&sk->sk_callback_lock); -} - -static void -iscsi_tcp_terminate_conn(struct iscsi_conn *conn) -{ - struct iscsi_tcp_conn *tcp_conn = conn->dd_data; - - if (!tcp_conn->sock) - return; - - sock_hold(tcp_conn->sock->sk); - iscsi_conn_restore_callbacks(conn); - sock_put(tcp_conn->sock->sk); - - sock_release(tcp_conn->sock); - tcp_conn->sock = NULL; - conn->recv_lock = NULL; -} - /* called with host lock */ static void iscsi_tcp_mgmt_init(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask, @@ -2413,10 +2407,7 @@ static struct iscsi_transport iscsi_tcp_transport = { .get_conn_param = iscsi_tcp_conn_get_param, .get_session_param = iscsi_session_get_param, .start_conn = iscsi_conn_start, - .stop_conn = iscsi_conn_stop, - /* these are called as part of conn recovery */ - .suspend_conn_recv = iscsi_tcp_suspend_conn_rx, - .terminate_conn = iscsi_tcp_terminate_conn, + .stop_conn = iscsi_tcp_conn_stop, /* IO */ .send_pdu = iscsi_conn_send_pdu, .get_stats = iscsi_conn_get_stats, diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 4e2ca8f..36f520b 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -1440,12 +1440,6 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn) set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); mutex_lock(&conn->xmitmutex); - if (conn->c_stage == ISCSI_CONN_INITIAL_STAGE) { - if (session->tt->suspend_conn_recv) - session->tt->suspend_conn_recv(conn); - - session->tt->terminate_conn(conn); - } spin_lock_bh(&session->lock); conn->c_stage = ISCSI_CONN_CLEANUP_WAIT; @@ -1622,8 +1616,9 @@ static void iscsi_start_session_recovery(struct iscsi_session *session, set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); spin_unlock_bh(&session->lock); - if (session->tt->suspend_conn_recv) - session->tt->suspend_conn_recv(conn); + write_lock_bh(conn->recv_lock); + set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx); + write_unlock_bh(conn->recv_lock); mutex_lock(&conn->xmitmutex); /* @@ -1642,7 +1637,6 @@ static void iscsi_start_session_recovery(struct iscsi_session *session, } } - session->tt->terminate_conn(conn); /* * flush queues. */ -- cgit v1.1 From 63f75cc8a7e6ce453e38a7b90cdcae83d63f1ea7 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Mon, 24 Jul 2006 15:47:29 -0500 Subject: [SCSI] iscsi bugfixes: fix oops when removing session We are touching the cls_session after we have freed it. This causes a oops. Signed-off-by: Or Gerlitz Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/libiscsi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 36f520b..c989bc6 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -1337,6 +1337,7 @@ void iscsi_session_teardown(struct iscsi_cls_session *cls_session) { struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); struct iscsi_session *session = iscsi_hostdata(shost->hostdata); + struct module *owner = cls_session->transport->owner; scsi_remove_host(shost); @@ -1345,7 +1346,7 @@ void iscsi_session_teardown(struct iscsi_cls_session *cls_session) iscsi_destroy_session(cls_session); scsi_host_put(shost); - module_put(cls_session->transport->owner); + module_put(owner); } EXPORT_SYMBOL_GPL(iscsi_session_teardown); -- cgit v1.1 From 9aaa2b4621280b6de1ecfb6dd7cd5cbe59fd1264 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Mon, 24 Jul 2006 15:47:34 -0500 Subject: [SCSI] iscsi bugfixes: dont use GFP_KERNEL for sending errors iscsi_tcp can send error events from soft irq context so we cannot use GFP_KERNEL. Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/scsi_transport_iscsi.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 7b9e8fa..30a47c1 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -634,13 +634,13 @@ mempool_zone_get_skb(struct mempool_zone *zone) } static int -iscsi_broadcast_skb(struct mempool_zone *zone, struct sk_buff *skb) +iscsi_broadcast_skb(struct mempool_zone *zone, struct sk_buff *skb, gfp_t gfp) { unsigned long flags; int rc; skb_get(skb); - rc = netlink_broadcast(nls, skb, 0, 1, GFP_KERNEL); + rc = netlink_broadcast(nls, skb, 0, 1, gfp); if (rc < 0) { mempool_free(skb, zone->pool); printk(KERN_ERR "iscsi: can not broadcast skb (%d)\n", rc); @@ -749,7 +749,7 @@ void iscsi_conn_error(struct iscsi_cls_conn *conn, enum iscsi_err error) ev->r.connerror.cid = conn->cid; ev->r.connerror.sid = iscsi_conn_get_sid(conn); - iscsi_broadcast_skb(conn->z_error, skb); + iscsi_broadcast_skb(conn->z_error, skb, GFP_ATOMIC); dev_printk(KERN_INFO, &conn->dev, "iscsi: detected conn error (%d)\n", error); @@ -895,7 +895,7 @@ int iscsi_if_destroy_session_done(struct iscsi_cls_conn *conn) * this will occur if the daemon is not up, so we just warn * the user and when the daemon is restarted it will handle it */ - rc = iscsi_broadcast_skb(conn->z_pdu, skb); + rc = iscsi_broadcast_skb(conn->z_pdu, skb, GFP_KERNEL); if (rc < 0) dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of " "session destruction event. Check iscsi daemon\n"); @@ -958,7 +958,7 @@ int iscsi_if_create_session_done(struct iscsi_cls_conn *conn) * this will occur if the daemon is not up, so we just warn * the user and when the daemon is restarted it will handle it */ - rc = iscsi_broadcast_skb(conn->z_pdu, skb); + rc = iscsi_broadcast_skb(conn->z_pdu, skb, GFP_KERNEL); if (rc < 0) dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of " "session creation event. Check iscsi daemon\n"); -- cgit v1.1 From c8dc1e523b0f1e6dd71cdabd8c7d7587c6dc27f9 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Mon, 24 Jul 2006 15:47:39 -0500 Subject: [SCSI] iscsi bugfixes: reduce memory allocations We currently try to allocate a max_recv_data_segment_length which can be very large (default is 64K), and common uses are up to 1MB. It is very very difficult to allocte this much contiguous memory and it turns out we never even use it. We really only need a couple of pages, so this patch has us allocates just what we know what we need today. Later if vendors start adding vendor specific data and we need to handle large buffers we can do this, but for the last 4 years we have not seen anyone do this or request it. Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/iscsi_tcp.c | 83 ++++++++++++++---------------------------------- drivers/scsi/iscsi_tcp.h | 2 -- drivers/scsi/libiscsi.c | 10 ++++-- 3 files changed, 30 insertions(+), 65 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index b6c68be..aa20adc 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -511,13 +511,28 @@ iscsi_tcp_hdr_recv(struct iscsi_conn *conn) break; case ISCSI_OP_LOGIN_RSP: case ISCSI_OP_TEXT_RSP: - case ISCSI_OP_LOGOUT_RSP: - case ISCSI_OP_NOOP_IN: case ISCSI_OP_REJECT: case ISCSI_OP_ASYNC_EVENT: + /* + * It is possible that we could get a PDU with a buffer larger + * than 8K, but there are no targets that currently do this. + * For now we fail until we find a vendor that needs it + */ + if (DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH < + tcp_conn->in.datalen) { + printk(KERN_ERR "iscsi_tcp: received buffer of len %u " + "but conn buffer is only %u (opcode %0x)\n", + tcp_conn->in.datalen, + DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH, opcode); + rc = ISCSI_ERR_PROTO; + break; + } + if (tcp_conn->in.datalen) goto copy_hdr; /* fall through */ + case ISCSI_OP_LOGOUT_RSP: + case ISCSI_OP_NOOP_IN: case ISCSI_OP_SCSI_TMFUNC_RSP: rc = iscsi_complete_pdu(conn, hdr, NULL, 0); break; @@ -625,9 +640,9 @@ iscsi_ctask_copy(struct iscsi_tcp_conn *tcp_conn, struct iscsi_cmd_task *ctask, * byte counters. **/ static inline int -iscsi_tcp_copy(struct iscsi_tcp_conn *tcp_conn) +iscsi_tcp_copy(struct iscsi_conn *conn) { - void *buf = tcp_conn->data; + struct iscsi_tcp_conn *tcp_conn = conn->dd_data; int buf_size = tcp_conn->in.datalen; int buf_left = buf_size - tcp_conn->data_copied; int size = min(tcp_conn->in.copy, buf_left); @@ -638,7 +653,7 @@ iscsi_tcp_copy(struct iscsi_tcp_conn *tcp_conn) BUG_ON(size <= 0); rc = skb_copy_bits(tcp_conn->in.skb, tcp_conn->in.offset, - (char*)buf + tcp_conn->data_copied, size); + (char*)conn->data + tcp_conn->data_copied, size); BUG_ON(rc); tcp_conn->in.offset += size; @@ -785,22 +800,21 @@ iscsi_data_recv(struct iscsi_conn *conn) spin_unlock(&conn->session->lock); case ISCSI_OP_TEXT_RSP: case ISCSI_OP_LOGIN_RSP: - case ISCSI_OP_NOOP_IN: case ISCSI_OP_ASYNC_EVENT: case ISCSI_OP_REJECT: /* * Collect data segment to the connection's data * placeholder */ - if (iscsi_tcp_copy(tcp_conn)) { + if (iscsi_tcp_copy(conn)) { rc = -EAGAIN; goto exit; } - rc = iscsi_complete_pdu(conn, tcp_conn->in.hdr, tcp_conn->data, + rc = iscsi_complete_pdu(conn, tcp_conn->in.hdr, conn->data, tcp_conn->in.datalen); if (!rc && conn->datadgst_en && opcode != ISCSI_OP_LOGIN_RSP) - iscsi_recv_digest_update(tcp_conn, tcp_conn->data, + iscsi_recv_digest_update(tcp_conn, conn->data, tcp_conn->in.datalen); break; default: @@ -1911,21 +1925,9 @@ iscsi_tcp_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx) tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER; /* initial operational parameters */ tcp_conn->hdr_size = sizeof(struct iscsi_hdr); - tcp_conn->data_size = DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH; - - /* allocate initial PDU receive place holder */ - if (tcp_conn->data_size <= PAGE_SIZE) - tcp_conn->data = kmalloc(tcp_conn->data_size, GFP_KERNEL); - else - tcp_conn->data = (void*)__get_free_pages(GFP_KERNEL, - get_order(tcp_conn->data_size)); - if (!tcp_conn->data) - goto max_recv_dlenght_alloc_fail; return cls_conn; -max_recv_dlenght_alloc_fail: - kfree(tcp_conn); tcp_conn_alloc_fail: iscsi_conn_teardown(cls_conn); return NULL; @@ -1973,12 +1975,6 @@ iscsi_tcp_conn_destroy(struct iscsi_cls_conn *cls_conn) crypto_free_tfm(tcp_conn->data_rx_tfm); } - /* free conn->data, size = MaxRecvDataSegmentLength */ - if (tcp_conn->data_size <= PAGE_SIZE) - kfree(tcp_conn->data); - else - free_pages((unsigned long)tcp_conn->data, - get_order(tcp_conn->data_size)); kfree(tcp_conn); } @@ -2131,39 +2127,6 @@ iscsi_conn_set_param(struct iscsi_cls_conn *cls_conn, enum iscsi_param param, int value; switch(param) { - case ISCSI_PARAM_MAX_RECV_DLENGTH: { - char *saveptr = tcp_conn->data; - gfp_t flags = GFP_KERNEL; - - sscanf(buf, "%d", &value); - if (tcp_conn->data_size >= value) { - iscsi_set_param(cls_conn, param, buf, buflen); - break; - } - - spin_lock_bh(&session->lock); - if (conn->stop_stage == STOP_CONN_RECOVER) - flags = GFP_ATOMIC; - spin_unlock_bh(&session->lock); - - if (value <= PAGE_SIZE) - tcp_conn->data = kmalloc(value, flags); - else - tcp_conn->data = (void*)__get_free_pages(flags, - get_order(value)); - if (tcp_conn->data == NULL) { - tcp_conn->data = saveptr; - return -ENOMEM; - } - if (tcp_conn->data_size <= PAGE_SIZE) - kfree(saveptr); - else - free_pages((unsigned long)saveptr, - get_order(tcp_conn->data_size)); - iscsi_set_param(cls_conn, param, buf, buflen); - tcp_conn->data_size = value; - break; - } case ISCSI_PARAM_HDRDGST_EN: iscsi_set_param(cls_conn, param, buf, buflen); tcp_conn->hdr_size = sizeof(struct iscsi_hdr); diff --git a/drivers/scsi/iscsi_tcp.h b/drivers/scsi/iscsi_tcp.h index 8083028..6a4ee70 100644 --- a/drivers/scsi/iscsi_tcp.h +++ b/drivers/scsi/iscsi_tcp.h @@ -78,8 +78,6 @@ struct iscsi_tcp_conn { char hdrext[4*sizeof(__u16) + sizeof(__u32)]; int data_copied; - char *data; /* data placeholder */ - int data_size; /* actual recv_dlength */ int stop_stage; /* conn_stop() flag: * * stop to recover, * * stop to terminate */ diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index c989bc6..03b3dee 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -360,6 +360,10 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, switch(opcode) { case ISCSI_OP_LOGOUT_RSP: + if (datalen) { + rc = ISCSI_ERR_PROTO; + break; + } conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1; /* fall through */ case ISCSI_OP_LOGIN_RSP: @@ -383,7 +387,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, iscsi_tmf_rsp(conn, hdr); break; case ISCSI_OP_NOOP_IN: - if (hdr->ttt != ISCSI_RESERVED_TAG) { + if (hdr->ttt != ISCSI_RESERVED_TAG || datalen) { rc = ISCSI_ERR_PROTO; break; } @@ -1405,7 +1409,7 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, uint32_t conn_idx) data = kmalloc(DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH, GFP_KERNEL); if (!data) goto login_mtask_data_alloc_fail; - conn->login_mtask->data = data; + conn->login_mtask->data = conn->data = data; init_timer(&conn->tmabort_timer); mutex_init(&conn->xmitmutex); @@ -1477,7 +1481,7 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn) } spin_lock_bh(&session->lock); - kfree(conn->login_mtask->data); + kfree(conn->data); __kfifo_put(session->mgmtpool.queue, (void*)&conn->login_mtask, sizeof(void*)); list_del(&conn->item); -- cgit v1.1 From 40527afea1a3b18ee5754e17d6f807176e03f1f2 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Mon, 24 Jul 2006 15:47:45 -0500 Subject: [SCSI] iscsi bugfixes: pass errors from complete_pdu to caller Must pass ISCSI_ERR values from the recv path and propogate them upwards. Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/iscsi_tcp.c | 2 +- drivers/scsi/libiscsi.c | 27 ++++++++++++++++++--------- 2 files changed, 19 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index aa20adc..33534f6 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -885,7 +885,7 @@ more: } tcp_conn->in_progress = IN_PROGRESS_DATA_RECV; } else if (rc) { - iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); + iscsi_conn_failure(conn, rc); return 0; } } diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 03b3dee..c628c63 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -372,7 +372,8 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, * login related PDU's exp_statsn is handled in * userspace */ - rc = iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen); + if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen)) + rc = ISCSI_ERR_CONN_FAILED; list_del(&mtask->running); if (conn->login_mtask != mtask) __kfifo_put(session->mgmtpool.queue, @@ -393,7 +394,8 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, } conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1; - rc = iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen); + if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen)) + rc = ISCSI_ERR_CONN_FAILED; list_del(&mtask->running); if (conn->login_mtask != mtask) __kfifo_put(session->mgmtpool.queue, @@ -406,14 +408,21 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, } else if (itt == ISCSI_RESERVED_TAG) { switch(opcode) { case ISCSI_OP_NOOP_IN: - if (!datalen) { - rc = iscsi_check_assign_cmdsn(session, - (struct iscsi_nopin*)hdr); - if (!rc && hdr->ttt != ISCSI_RESERVED_TAG) - rc = iscsi_recv_pdu(conn->cls_conn, - hdr, NULL, 0); - } else + if (datalen) { rc = ISCSI_ERR_PROTO; + break; + } + + rc = iscsi_check_assign_cmdsn(session, + (struct iscsi_nopin*)hdr); + if (rc) + break; + + if (hdr->ttt == ISCSI_RESERVED_TAG) + break; + + if (iscsi_recv_pdu(conn->cls_conn, hdr, NULL, 0)) + rc = ISCSI_ERR_CONN_FAILED; break; case ISCSI_OP_REJECT: /* we need sth like iscsi_reject_rsp()*/ -- cgit v1.1 From f3ff0c3627df90aa28be98803b10289bb348e4e6 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Mon, 24 Jul 2006 15:47:50 -0500 Subject: [SCSI] iscsi bugfixes: fix mem leaks in libiscsi We were leaking some strings. This patch just frees them. Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/libiscsi.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index c628c63..5884cd2 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -1357,6 +1357,8 @@ void iscsi_session_teardown(struct iscsi_cls_session *cls_session) iscsi_pool_free(&session->mgmtpool, (void**)session->mgmt_cmds); iscsi_pool_free(&session->cmdpool, (void**)session->cmds); + kfree(session->targetname); + iscsi_destroy_session(cls_session); scsi_host_put(shost); module_put(owner); @@ -1491,6 +1493,7 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn) spin_lock_bh(&session->lock); kfree(conn->data); + kfree(conn->persistent_address); __kfifo_put(session->mgmtpool.queue, (void*)&conn->login_mtask, sizeof(void*)); list_del(&conn->item); -- cgit v1.1 From f4246b33c774bb4330eb6286beed6d3c9f4373c4 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Mon, 24 Jul 2006 15:47:54 -0500 Subject: [SCSI] iscsi bugfixes: update and move version number The version info is useful for iscsi tcp, iser and qla4xxx so move to transport class. Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/iscsi_tcp.c | 6 +----- drivers/scsi/scsi_transport_iscsi.c | 5 +++++ 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 33534f6..058f094 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -43,13 +43,10 @@ #include "iscsi_tcp.h" -#define ISCSI_TCP_VERSION "1.0-595" - MODULE_AUTHOR("Dmitry Yusupov , " "Alex Aizman "); MODULE_DESCRIPTION("iSCSI/TCP data-path"); MODULE_LICENSE("GPL"); -MODULE_VERSION(ISCSI_TCP_VERSION); /* #define DEBUG_TCP */ #define DEBUG_ASSERT @@ -2317,8 +2314,7 @@ static void iscsi_tcp_session_destroy(struct iscsi_cls_session *cls_session) } static struct scsi_host_template iscsi_sht = { - .name = "iSCSI Initiator over TCP/IP, v" - ISCSI_TCP_VERSION, + .name = "iSCSI Initiator over TCP/IP", .queuecommand = iscsi_queuecommand, .change_queue_depth = iscsi_change_queue_depth, .can_queue = ISCSI_XMIT_CMDS_MAX - 1, diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 30a47c1..2ecd141 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -34,6 +34,7 @@ #define ISCSI_SESSION_ATTRS 11 #define ISCSI_CONN_ATTRS 11 #define ISCSI_HOST_ATTRS 0 +#define ISCSI_TRANSPORT_VERSION "1.1-646" struct iscsi_internal { int daemon_pid; @@ -1613,6 +1614,9 @@ static __init int iscsi_transport_init(void) { int err; + printk(KERN_INFO "Loading iSCSI transport class v%s.", + ISCSI_TRANSPORT_VERSION); + err = class_register(&iscsi_transport_class); if (err) return err; @@ -1678,3 +1682,4 @@ MODULE_AUTHOR("Mike Christie , " "Alex Aizman "); MODULE_DESCRIPTION("iSCSI Transport Interface"); MODULE_LICENSE("GPL"); +MODULE_VERSION(ISCSI_TRANSPORT_VERSION); -- cgit v1.1 From fbf6080225a03aa2b3671acacebdf615f1d3f6ba Mon Sep 17 00:00:00 2001 From: "Ju, Seokmann" Date: Tue, 25 Jul 2006 08:44:48 -0600 Subject: [SCSI] megaraid_{mm,mbox}: 64-bit DMA capability checker This patch contains - a fix for 64-bit DMA capability check in megaraid_{mm,mbox} driver. - includes changes (going back to 32-bit DMA mask if 64-bit DMA mask failes) suggested by James with previous patch. - addition of SATA 150-4/6 as commented by Vasily Averin. With patch, the driver access PCIconfiguration space with dedicated offset to read a signature. If the signature read, it means that the controller has capability to handle 64-bit DMA. Without this patch, the driver used to blindly claim 64-bit DMA capability. The issue has been reported by Vasily Averin [vvs@sw.ru]. Thank you Vasily for the reporting. Signed-Off By: Seokmann Ju Signed-off-by: James Bottomley --- drivers/scsi/megaraid/mega_common.h | 3 +++ drivers/scsi/megaraid/megaraid_mbox.c | 34 ++++++++++++++++++++++++++++------ drivers/scsi/megaraid/megaraid_mbox.h | 4 ++-- 3 files changed, 33 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/megaraid/mega_common.h b/drivers/scsi/megaraid/mega_common.h index 4675343..12e3812 100644 --- a/drivers/scsi/megaraid/mega_common.h +++ b/drivers/scsi/megaraid/mega_common.h @@ -37,6 +37,9 @@ #define LSI_MAX_CHANNELS 16 #define LSI_MAX_LOGICAL_DRIVES_64LD (64+1) +#define HBA_SIGNATURE_64_BIT 0x299 +#define PCI_CONF_AMISIG64 0xa4 + /** * scb_t - scsi command control block diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c index 9271513..e671af0 100644 --- a/drivers/scsi/megaraid/megaraid_mbox.c +++ b/drivers/scsi/megaraid/megaraid_mbox.c @@ -10,7 +10,7 @@ * 2 of the License, or (at your option) any later version. * * FILE : megaraid_mbox.c - * Version : v2.20.4.8 (Apr 11 2006) + * Version : v2.20.4.9 (Jul 16 2006) * * Authors: * Atul Mukker @@ -720,6 +720,7 @@ megaraid_init_mbox(adapter_t *adapter) struct pci_dev *pdev; mraid_device_t *raid_dev; int i; + uint32_t magic64; adapter->ito = MBOX_TIMEOUT; @@ -863,12 +864,33 @@ megaraid_init_mbox(adapter_t *adapter) // Set the DMA mask to 64-bit. All supported controllers as capable of // DMA in this range - if (pci_set_dma_mask(adapter->pdev, DMA_64BIT_MASK) != 0) { - - con_log(CL_ANN, (KERN_WARNING - "megaraid: could not set DMA mask for 64-bit.\n")); + pci_read_config_dword(adapter->pdev, PCI_CONF_AMISIG64, &magic64); + + if (((magic64 == HBA_SIGNATURE_64_BIT) && + ((adapter->pdev->subsystem_device != + PCI_SUBSYS_ID_MEGARAID_SATA_150_6) || + (adapter->pdev->subsystem_device != + PCI_SUBSYS_ID_MEGARAID_SATA_150_4))) || + (adapter->pdev->vendor == PCI_VENDOR_ID_LSI_LOGIC && + adapter->pdev->device == PCI_DEVICE_ID_VERDE) || + (adapter->pdev->vendor == PCI_VENDOR_ID_LSI_LOGIC && + adapter->pdev->device == PCI_DEVICE_ID_DOBSON) || + (adapter->pdev->vendor == PCI_VENDOR_ID_LSI_LOGIC && + adapter->pdev->device == PCI_DEVICE_ID_LINDSAY) || + (adapter->pdev->vendor == PCI_VENDOR_ID_DELL && + adapter->pdev->device == PCI_DEVICE_ID_PERC4_DI_EVERGLADES) || + (adapter->pdev->vendor == PCI_VENDOR_ID_DELL && + adapter->pdev->device == PCI_DEVICE_ID_PERC4E_DI_KOBUK)) { + if (pci_set_dma_mask(adapter->pdev, DMA_64BIT_MASK)) { + con_log(CL_ANN, (KERN_WARNING + "megaraid: DMA mask for 64-bit failed\n")); - goto out_free_sysfs_res; + if (pci_set_dma_mask (adapter->pdev, DMA_32BIT_MASK)) { + con_log(CL_ANN, (KERN_WARNING + "megaraid: 32-bit DMA mask failed\n")); + goto out_free_sysfs_res; + } + } } // setup tasklet for DPC diff --git a/drivers/scsi/megaraid/megaraid_mbox.h b/drivers/scsi/megaraid/megaraid_mbox.h index 868fb0e..2b5a328 100644 --- a/drivers/scsi/megaraid/megaraid_mbox.h +++ b/drivers/scsi/megaraid/megaraid_mbox.h @@ -21,8 +21,8 @@ #include "megaraid_ioctl.h" -#define MEGARAID_VERSION "2.20.4.8" -#define MEGARAID_EXT_VERSION "(Release Date: Mon Apr 11 12:27:22 EST 2006)" +#define MEGARAID_VERSION "2.20.4.9" +#define MEGARAID_EXT_VERSION "(Release Date: Sun Jul 16 12:27:22 EST 2006)" /* -- cgit v1.1 From aa677bc7445147f663ebde69d248a30839bada76 Mon Sep 17 00:00:00 2001 From: "Ju, Seokmann" Date: Tue, 25 Jul 2006 08:44:58 -0600 Subject: [SCSI] megaraid_{mm,mbox}: a fix on INQUIRY with EVPD With this patch, driver will protect data corruption created by INQUIRY with EVPD request to megaraid controllers. As specified in the changelog, megaraid F/W already has fixed the issue and being under process of release. Meanwhile, driver will protect the system with this patch. Signed-Off By: Seokmann Ju Signed-off-by: James Bottomley --- drivers/scsi/megaraid/mega_common.h | 3 +++ drivers/scsi/megaraid/megaraid_mbox.c | 8 ++++++++ 2 files changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/megaraid/mega_common.h b/drivers/scsi/megaraid/mega_common.h index 12e3812..8cd0bd1 100644 --- a/drivers/scsi/megaraid/mega_common.h +++ b/drivers/scsi/megaraid/mega_common.h @@ -40,6 +40,9 @@ #define HBA_SIGNATURE_64_BIT 0x299 #define PCI_CONF_AMISIG64 0xa4 +#define MEGA_SCSI_INQ_EVPD 1 +#define MEGA_INVALID_FIELD_IN_CDB 0x24 + /** * scb_t - scsi command control block diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c index e671af0..cd982c8 100644 --- a/drivers/scsi/megaraid/megaraid_mbox.c +++ b/drivers/scsi/megaraid/megaraid_mbox.c @@ -1644,6 +1644,14 @@ megaraid_mbox_build_cmd(adapter_t *adapter, struct scsi_cmnd *scp, int *busy) rdev->last_disp |= (1L << SCP2CHANNEL(scp)); } + if (scp->cmnd[1] & MEGA_SCSI_INQ_EVPD) { + scp->sense_buffer[0] = 0x70; + scp->sense_buffer[2] = ILLEGAL_REQUEST; + scp->sense_buffer[12] = MEGA_INVALID_FIELD_IN_CDB; + scp->result = CHECK_CONDITION << 1; + return NULL; + } + /* Fall through */ case READ_CAPACITY: -- cgit v1.1 From 0b4972d59170e13ab0236e8a7148112052590c01 Mon Sep 17 00:00:00 2001 From: "Ju, Seokmann" Date: Tue, 25 Jul 2006 08:45:06 -0600 Subject: [SCSI] megaraid_{mm,mbox}: a fix on "kernel unaligned access address" issue There was an issue in the data structure defined by megaraid driver casuing "kernel unaligned access.." messages to be displayed during IOCTL on IA64 platform. The issue has been reported/fixed by Sakurai Hiroomi [sakurai_hiro@soft.fujitsu.com]. Signed-Off By: Seokmann Ju Signed-off-by: James Bottomley --- drivers/scsi/megaraid/megaraid_ioctl.h | 4 ++++ drivers/scsi/megaraid/megaraid_mm.c | 2 +- drivers/scsi/megaraid/megaraid_mm.h | 4 ++-- 3 files changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/megaraid/megaraid_ioctl.h b/drivers/scsi/megaraid/megaraid_ioctl.h index bdaee14..b8aa342 100644 --- a/drivers/scsi/megaraid/megaraid_ioctl.h +++ b/drivers/scsi/megaraid/megaraid_ioctl.h @@ -132,6 +132,10 @@ typedef struct uioc { /* Driver Data: */ void __user * user_data; uint32_t user_data_len; + + /* 64bit alignment */ + uint32_t pad_for_64bit_align; + mraid_passthru_t __user *user_pthru; mraid_passthru_t *pthru32; diff --git a/drivers/scsi/megaraid/megaraid_mm.c b/drivers/scsi/megaraid/megaraid_mm.c index e8f534f..d85b9a8 100644 --- a/drivers/scsi/megaraid/megaraid_mm.c +++ b/drivers/scsi/megaraid/megaraid_mm.c @@ -10,7 +10,7 @@ * 2 of the License, or (at your option) any later version. * * FILE : megaraid_mm.c - * Version : v2.20.2.6 (Mar 7 2005) + * Version : v2.20.2.7 (Jul 16 2006) * * Common management module */ diff --git a/drivers/scsi/megaraid/megaraid_mm.h b/drivers/scsi/megaraid/megaraid_mm.h index 3d9e67d..c8762b2 100644 --- a/drivers/scsi/megaraid/megaraid_mm.h +++ b/drivers/scsi/megaraid/megaraid_mm.h @@ -27,9 +27,9 @@ #include "megaraid_ioctl.h" -#define LSI_COMMON_MOD_VERSION "2.20.2.6" +#define LSI_COMMON_MOD_VERSION "2.20.2.7" #define LSI_COMMON_MOD_EXT_VERSION \ - "(Release Date: Mon Mar 7 00:01:03 EST 2005)" + "(Release Date: Sun Jul 16 00:01:03 EST 2006)" #define LSI_DBGLVL dbglevel -- cgit v1.1 From 9a71db721a2cbb9921b929b2699ab181f5a3c6c0 Mon Sep 17 00:00:00 2001 From: Brice Goglin Date: Fri, 21 Jul 2006 15:49:32 -0400 Subject: [PATCH] myri10ge - Always do a dummy RDMA after loading the firmware Always do a dummy RDMA after loading the firmware to work around buggy PCIe chipsets which do not implement resending properly. This is so cheap as to be almost free, and should never have been conditional on the tx boundary != 4096. Signed-off-by: Brice Goglin Signed-off-by: Jeff Garzik --- drivers/net/myri10ge/myri10ge.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index 07ca948..c3e52c8 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -620,7 +620,7 @@ static int myri10ge_load_firmware(struct myri10ge_priv *mgp) return -ENXIO; } dev_info(&mgp->pdev->dev, "handoff confirmed\n"); - myri10ge_dummy_rdma(mgp, mgp->tx.boundary != 4096); + myri10ge_dummy_rdma(mgp, 1); return 0; } -- cgit v1.1 From 187ff3b8575569668cde9021b9fe70386a4131fb Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 19 Jul 2006 14:08:42 -0700 Subject: [PATCH] skge: chip clock rate typo Okay, Fix both typo's in one patch .The impact is that the incorrect value was being computed for blinking LED and interrupt moderation values. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/skge.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/skge.c b/drivers/net/skge.c index 82200bf..7de9a07 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -516,10 +516,7 @@ static int skge_set_pauseparam(struct net_device *dev, /* Chip internal frequency for clock calculations */ static inline u32 hwkhz(const struct skge_hw *hw) { - if (hw->chip_id == CHIP_ID_GENESIS) - return 53215; /* or: 53.125 MHz */ - else - return 78215; /* or: 78.125 MHz */ + return (hw->chip_id == CHIP_ID_GENESIS) ? 53125 : 78125; } /* Chip HZ to microseconds */ -- cgit v1.1 From 061b623c54c5722fbb55fddbbdacbf97e8a82701 Mon Sep 17 00:00:00 2001 From: Andrew de Quincey Date: Mon, 10 Jul 2006 03:34:14 -0300 Subject: V4L/DVB (4291): Add dvbpll i2c device check. Some cards have multiple possible addresses for their PLLs, with no other way to tell if a PLL is present or not apart from probing to see if an i2c device is present. This adds a quick check to see if an i2c device is present at the given i2c address. Signed-off-by: Andrew de Quincey Acked-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/dvb-pll.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c index a189683..b9a3388 100644 --- a/drivers/media/dvb/frontends/dvb-pll.c +++ b/drivers/media/dvb/frontends/dvb-pll.c @@ -613,7 +613,20 @@ static struct dvb_tuner_ops dvb_pll_tuner_ops = { int dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, struct i2c_adapter *i2c, struct dvb_pll_desc *desc) { + u8 b1 [] = { 0 }; + struct i2c_msg msg [] = { { .addr = pll_addr, .flags = 0, .buf = NULL, .len = 0 }, + { .addr = pll_addr, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; struct dvb_pll_priv *priv = NULL; + int ret; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + ret = i2c_transfer (i2c, msg, 2); + if (ret != 2) + return -1; + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); priv = kzalloc(sizeof(struct dvb_pll_priv), GFP_KERNEL); if (priv == NULL) -- cgit v1.1 From 04c56d0e5b27f1f65e4d20b46731d55341d42a6a Mon Sep 17 00:00:00 2001 From: Andrew de Quincey Date: Mon, 10 Jul 2006 03:34:14 -0300 Subject: V4L/DVB (4292): Fix DISEQC regression The changes to add frontend reinitialisation moved the position where the init() op is called into the frontend thread. Unfortunately, since DISEQC operations do not use the frontend thread, this meant that DISEQC could be called against an uninitalised frontend, leading to all sorts of trouble. Patch fixes this by reinstating the original fronted intialisation call. Signed-off-by: Andrew de Quincey Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 59ac35d..57b34cd 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -526,7 +526,9 @@ static int dvb_frontend_thread(void *data) fepriv->delay = 3*HZ; fepriv->status = 0; fepriv->wakeup = 0; - fepriv->reinitialise = 1; + fepriv->reinitialise = 0; + + dvb_frontend_init(fe); while (1) { up(&fepriv->sem); /* is locked when we enter the thread... */ @@ -1013,17 +1015,18 @@ static int dvb_frontend_open(struct inode *inode, struct file *file) return ret; if ((file->f_flags & O_ACCMODE) != O_RDONLY) { + + /* normal tune mode when opened R/W */ + fepriv->tune_mode_flags &= ~FE_TUNE_MODE_ONESHOT; + fepriv->tone = -1; + fepriv->voltage = -1; + ret = dvb_frontend_start (fe); if (ret) dvb_generic_release (inode, file); /* empty event queue */ fepriv->events.eventr = fepriv->events.eventw = 0; - - /* normal tune mode when opened R/W */ - fepriv->tune_mode_flags &= ~FE_TUNE_MODE_ONESHOT; - fepriv->tone = -1; - fepriv->voltage = -1; } return ret; -- cgit v1.1 From f2813093810276a2a3c1f116f23baf2ab7a669bd Mon Sep 17 00:00:00 2001 From: Andrew de Quincey Date: Mon, 10 Jul 2006 03:34:15 -0300 Subject: V4L/DVB (4293): Fix unstable DISEQC behaviour on budget cards. Use the stv0299 native DISEQC implementation instead of the bitbanging one as required by the ves1893. This was originally found by Oliver Endriss. Signed-off-by: Andrew de Quincey Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/ttpci/budget.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c index 35761f1..1b4d884 100644 --- a/drivers/media/dvb/ttpci/budget.c +++ b/drivers/media/dvb/ttpci/budget.c @@ -375,9 +375,6 @@ static void frontend_init(struct budget *budget) if (budget->dvb_frontend) { budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params; budget->dvb_frontend->tuner_priv = &budget->i2c_adap; - budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd; - budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst; - budget->dvb_frontend->ops.set_tone = budget_set_tone; break; } break; -- cgit v1.1 From 93e2b1ae97dedd66ca0cb8ac1a5ceb4904631091 Mon Sep 17 00:00:00 2001 From: Andrew de Quincey Date: Mon, 10 Jul 2006 03:34:15 -0300 Subject: V4L/DVB (4294): Fix broken tda665x PLL definition. It was pointed out on the mailing list that this PLL definition is broken. I went back to the original dibusb driver and confirmed it used to use these settings, as well as consulting the datasheet. Signed-off-by: Andrew de Quincey Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/dvb-pll.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c index b9a3388..fce5c42 100644 --- a/drivers/media/dvb/frontends/dvb-pll.c +++ b/drivers/media/dvb/frontends/dvb-pll.c @@ -194,11 +194,11 @@ struct dvb_pll_desc dvb_pll_tda665x = { { 253834000, 36249333, 166667, 0xca, 0x62 /* 011 0 0 0 10 */ }, { 383834000, 36249333, 166667, 0xca, 0xa2 /* 101 0 0 0 10 */ }, { 443834000, 36249333, 166667, 0xca, 0xc2 /* 110 0 0 0 10 */ }, - { 444000000, 36249333, 166667, 0xca, 0xc3 /* 110 0 0 0 11 */ }, - { 583834000, 36249333, 166667, 0xca, 0x63 /* 011 0 0 0 11 */ }, - { 793834000, 36249333, 166667, 0xca, 0xa3 /* 101 0 0 0 11 */ }, - { 444834000, 36249333, 166667, 0xca, 0xc3 /* 110 0 0 0 11 */ }, - { 861000000, 36249333, 166667, 0xca, 0xe3 /* 111 0 0 0 11 */ }, + { 444000000, 36249333, 166667, 0xca, 0xc4 /* 110 0 0 1 00 */ }, + { 583834000, 36249333, 166667, 0xca, 0x64 /* 011 0 0 1 00 */ }, + { 793834000, 36249333, 166667, 0xca, 0xa4 /* 101 0 0 1 00 */ }, + { 444834000, 36249333, 166667, 0xca, 0xc4 /* 110 0 0 1 00 */ }, + { 861000000, 36249333, 166667, 0xca, 0xe4 /* 111 0 0 1 00 */ }, } }; EXPORT_SYMBOL(dvb_pll_tda665x); -- cgit v1.1 From 6a85774741f1ef1a47ba0670e99c97e892930cad Mon Sep 17 00:00:00 2001 From: Marco Schluessler Date: Mon, 10 Jul 2006 03:34:16 -0300 Subject: V4L/DVB (4295): Fix typo in comment for TDA9819 Fix typo in comment for TDA9819 Signed-off-by: Marco Schluessler Signed-off-by: Andrew de Quincey Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/ttpci/av7110.c | 4 ++-- drivers/media/dvb/ttpci/av7110_v4l.c | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c index 500f15c..4506165 100644 --- a/drivers/media/dvb/ttpci/av7110.c +++ b/drivers/media/dvb/ttpci/av7110.c @@ -2203,8 +2203,8 @@ static int frontend_init(struct av7110 *av7110) av7110->fe->ops.tuner_ops.set_params = nexusca_stv0297_tuner_set_params; /* set TDA9819 into DVB mode */ - saa7146_setgpio(av7110->dev, 1, SAA7146_GPIO_OUTLO); // TDA9198 pin9(STD) - saa7146_setgpio(av7110->dev, 3, SAA7146_GPIO_OUTLO); // TDA9198 pin30(VIF) + saa7146_setgpio(av7110->dev, 1, SAA7146_GPIO_OUTLO); // TDA9819 pin9(STD) + saa7146_setgpio(av7110->dev, 3, SAA7146_GPIO_OUTLO); // TDA9819 pin30(VIF) /* tuner on this needs a slower i2c bus speed */ av7110->dev->i2c_bitrate = SAA7146_I2C_BUS_BIT_RATE_240; diff --git a/drivers/media/dvb/ttpci/av7110_v4l.c b/drivers/media/dvb/ttpci/av7110_v4l.c index 6405546..6ffe53f 100644 --- a/drivers/media/dvb/ttpci/av7110_v4l.c +++ b/drivers/media/dvb/ttpci/av7110_v4l.c @@ -272,8 +272,8 @@ static int av7110_dvb_c_switch(struct saa7146_fh *fh) if (ves1820_writereg(dev, 0x09, 0x0f, 0x60)) dprintk(1, "setting band in demodulator failed.\n"); } else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) { - saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); // TDA9198 pin9(STD) - saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI); // TDA9198 pin30(VIF) + saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); // TDA9819 pin9(STD) + saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI); // TDA9819 pin30(VIF) } if (i2c_writereg(av7110, 0x48, 0x02, 0xd0) != 1) dprintk(1, "saa7113 write failed @ card %d", av7110->dvb_adapter.num); @@ -308,8 +308,8 @@ static int av7110_dvb_c_switch(struct saa7146_fh *fh) if (ves1820_writereg(dev, 0x09, 0x0f, 0x20)) dprintk(1, "setting band in demodulator failed.\n"); } else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) { - saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTLO); // TDA9198 pin9(STD) - saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); // TDA9198 pin30(VIF) + saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTLO); // TDA9819 pin9(STD) + saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); // TDA9819 pin30(VIF) } } @@ -750,8 +750,8 @@ int av7110_init_analog_module(struct av7110 *av7110) if (ves1820_writereg(av7110->dev, 0x09, 0x0f, 0x20)) dprintk(1, "setting band in demodulator failed.\n"); } else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) { - saa7146_setgpio(av7110->dev, 1, SAA7146_GPIO_OUTLO); // TDA9198 pin9(STD) - saa7146_setgpio(av7110->dev, 3, SAA7146_GPIO_OUTLO); // TDA9198 pin30(VIF) + saa7146_setgpio(av7110->dev, 1, SAA7146_GPIO_OUTLO); // TDA9819 pin9(STD) + saa7146_setgpio(av7110->dev, 3, SAA7146_GPIO_OUTLO); // TDA9819 pin30(VIF) } /* init the saa7113 */ -- cgit v1.1 From 6ba475042f0ca54bf055ce94b2a1e4656ed143f9 Mon Sep 17 00:00:00 2001 From: Andrew de Quincey Date: Mon, 10 Jul 2006 03:34:16 -0300 Subject: V4L/DVB (4296): Remove stradis MODULE_DEVICE_INFO definition To prevent autoloading of the driver, as it then conflicts with every other saa7146 device in existence. Signed-off-by: Andrew de Quincey Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/stradis.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/stradis.c b/drivers/media/video/stradis.c index b36ba9f..5686547 100644 --- a/drivers/media/video/stradis.c +++ b/drivers/media/video/stradis.c @@ -2181,7 +2181,6 @@ static struct pci_device_id stradis_pci_tbl[] = { { 0 } }; -MODULE_DEVICE_TABLE(pci, stradis_pci_tbl); static struct pci_driver stradis_driver = { .name = "stradis", -- cgit v1.1 From c526e224e4075eff788a992f59bc4a9006b12923 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sat, 15 Jul 2006 09:08:26 -0300 Subject: V4L/DVB (4298): Check all __must_check warnings in bttv. Signed-off-by: Randy Dunlap Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/bt8xx/bttv-driver.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index 5764a89..63e8316 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -3909,6 +3909,8 @@ static void bttv_unregister_video(struct bttv *btv) /* register video4linux devices */ static int __devinit bttv_register_video(struct bttv *btv) { + int ret; + if (no_overlay <= 0) { bttv_video_template.type |= VID_TYPE_OVERLAY; } else { @@ -3923,7 +3925,10 @@ static int __devinit bttv_register_video(struct bttv *btv) goto err; printk(KERN_INFO "bttv%d: registered device video%d\n", btv->c.nr,btv->video_dev->minor & 0x1f); - video_device_create_file(btv->video_dev, &class_device_attr_card); + ret = video_device_create_file(btv->video_dev, &class_device_attr_card); + if (ret < 0) + printk(KERN_WARNING "bttv: video_device_create_file error: " + "%d\n", ret); /* vbi */ btv->vbi_dev = vdev_init(btv, &bttv_vbi_template, "vbi"); @@ -4287,6 +4292,8 @@ static struct pci_driver bttv_pci_driver = { static int bttv_init_module(void) { + int ret; + bttv_num = 0; printk(KERN_INFO "bttv: driver version %d.%d.%d loaded\n", @@ -4308,7 +4315,11 @@ static int bttv_init_module(void) bttv_check_chipset(); - bus_register(&bttv_sub_bus_type); + ret = bus_register(&bttv_sub_bus_type); + if (ret < 0) { + printk(KERN_WARNING "bttv: bus_register error: %d\n", ret); + return ret; + } return pci_register_driver(&bttv_pci_driver); } -- cgit v1.1 From d5fdd1354e04658ea25150cc152a395bb6ecb6da Mon Sep 17 00:00:00 2001 From: Hartmut Hackmann Date: Sat, 15 Jul 2006 09:45:34 -0300 Subject: V4L/DVB (4306): Support non interlaced capture by default for saa713x This patch just sets the option noninterlaced to 1 by default since it has no known disadvantages. It is still possibe to get the old behaviour by setting noninterlaced=0. Signed-off-by: Hartmut Hackmann Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-video.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index e4156ec..8277958 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -40,7 +40,7 @@ static unsigned int video_debug = 0; static unsigned int gbuffers = 8; -static unsigned int noninterlaced = 0; +static unsigned int noninterlaced = 1; static unsigned int gbufsize = 720*576*4; static unsigned int gbufsize_max = 720*576*4; module_param(video_debug, int, 0644); @@ -48,7 +48,7 @@ MODULE_PARM_DESC(video_debug,"enable debug messages [video]"); module_param(gbuffers, int, 0444); MODULE_PARM_DESC(gbuffers,"number of capture buffers, range 2-32"); module_param(noninterlaced, int, 0644); -MODULE_PARM_DESC(noninterlaced,"video input is noninterlaced"); +MODULE_PARM_DESC(noninterlaced,"capture non interlaced video"); #define dprintk(fmt, arg...) if (video_debug) \ printk(KERN_DEBUG "%s/video: " fmt, dev->name , ## arg) -- cgit v1.1 From 7845701820c420454bcfdc4902fad68901d9ff83 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sat, 15 Jul 2006 15:19:56 -0300 Subject: V4L/DVB (4310): Saa7134: rename dmasound_{init, exit} Two different exports with the same name are not a good idea: $ grep -r EXPORT_SYMBOL\(dmasound_init\) * drivers/media/video/saa7134/saa7134-core.c:EXPORT_SYMBOL(dmasound_init); sound/oss/dmasound/dmasound_core.c:EXPORT_SYMBOL(dmasound_init); $ This patch renames the saa7134 dmasound_{init,exit} to saa7134_dmasound_{init,exit}. Signed-off-by: Adrian Bunk Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-alsa.c | 10 +++++----- drivers/media/video/saa7134/saa7134-core.c | 16 ++++++++-------- drivers/media/video/saa7134/saa7134-oss.c | 10 +++++----- drivers/media/video/saa7134/saa7134.h | 4 ++-- 4 files changed, 20 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c index f1fd69e..d73cff1 100644 --- a/drivers/media/video/saa7134/saa7134-alsa.c +++ b/drivers/media/video/saa7134/saa7134-alsa.c @@ -997,9 +997,9 @@ static int saa7134_alsa_init(void) struct saa7134_dev *dev = NULL; struct list_head *list; - if (!dmasound_init && !dmasound_exit) { - dmasound_init = alsa_device_init; - dmasound_exit = alsa_device_exit; + if (!saa7134_dmasound_init && !saa7134_dmasound_exit) { + saa7134_dmasound_init = alsa_device_init; + saa7134_dmasound_exit = alsa_device_exit; } else { printk(KERN_WARNING "saa7134 ALSA: can't load, DMA sound handler already assigned (probably to OSS)\n"); return -EBUSY; @@ -1036,8 +1036,8 @@ static void saa7134_alsa_exit(void) snd_card_free(snd_saa7134_cards[idx]); } - dmasound_init = NULL; - dmasound_exit = NULL; + saa7134_dmasound_init = NULL; + saa7134_dmasound_exit = NULL; printk(KERN_INFO "saa7134 ALSA driver for DMA sound unloaded\n"); return; diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index 6e97cc8..be3a81f 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -95,8 +95,8 @@ LIST_HEAD(saa7134_devlist); static LIST_HEAD(mops_list); static unsigned int saa7134_devcount; -int (*dmasound_init)(struct saa7134_dev *dev); -int (*dmasound_exit)(struct saa7134_dev *dev); +int (*saa7134_dmasound_init)(struct saa7134_dev *dev); +int (*saa7134_dmasound_exit)(struct saa7134_dev *dev); #define dprintk(fmt, arg...) if (core_debug) \ printk(KERN_DEBUG "%s/core: " fmt, dev->name , ## arg) @@ -1008,8 +1008,8 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, /* check for signal */ saa7134_irq_video_intl(dev); - if (dmasound_init && !dev->dmasound.priv_data) { - dmasound_init(dev); + if (saa7134_dmasound_init && !dev->dmasound.priv_data) { + saa7134_dmasound_init(dev); } return 0; @@ -1036,8 +1036,8 @@ static void __devexit saa7134_finidev(struct pci_dev *pci_dev) struct saa7134_mpeg_ops *mops; /* Release DMA sound modules if present */ - if (dmasound_exit && dev->dmasound.priv_data) { - dmasound_exit(dev); + if (saa7134_dmasound_exit && dev->dmasound.priv_data) { + saa7134_dmasound_exit(dev); } /* debugging ... */ @@ -1169,8 +1169,8 @@ EXPORT_SYMBOL(saa7134_boards); /* ----------------- for the DMA sound modules --------------- */ -EXPORT_SYMBOL(dmasound_init); -EXPORT_SYMBOL(dmasound_exit); +EXPORT_SYMBOL(saa7134_dmasound_init); +EXPORT_SYMBOL(saa7134_dmasound_exit); EXPORT_SYMBOL(saa7134_pgtable_free); EXPORT_SYMBOL(saa7134_pgtable_build); EXPORT_SYMBOL(saa7134_pgtable_alloc); diff --git a/drivers/media/video/saa7134/saa7134-oss.c b/drivers/media/video/saa7134/saa7134-oss.c index 3895d05..2e3ba5f 100644 --- a/drivers/media/video/saa7134/saa7134-oss.c +++ b/drivers/media/video/saa7134/saa7134-oss.c @@ -993,9 +993,9 @@ static int saa7134_oss_init(void) struct saa7134_dev *dev = NULL; struct list_head *list; - if (!dmasound_init && !dmasound_exit) { - dmasound_init = oss_device_init; - dmasound_exit = oss_device_exit; + if (!saa7134_dmasound_init && !saa7134_dmasound_exit) { + saa7134_dmasound_init = oss_device_init; + saa7134_dmasound_exit = oss_device_exit; } else { printk(KERN_WARNING "saa7134 OSS: can't load, DMA sound handler already assigned (probably to ALSA)\n"); return -EBUSY; @@ -1037,8 +1037,8 @@ static void saa7134_oss_exit(void) } - dmasound_init = NULL; - dmasound_exit = NULL; + saa7134_dmasound_init = NULL; + saa7134_dmasound_exit = NULL; printk(KERN_INFO "saa7134 OSS driver for DMA sound unloaded\n"); diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index d5ee99c..c04ce61 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -586,8 +586,8 @@ void saa7134_dma_free(struct videobuf_queue *q,struct saa7134_buf *buf); int saa7134_set_dmabits(struct saa7134_dev *dev); -extern int (*dmasound_init)(struct saa7134_dev *dev); -extern int (*dmasound_exit)(struct saa7134_dev *dev); +extern int (*saa7134_dmasound_init)(struct saa7134_dev *dev); +extern int (*saa7134_dmasound_exit)(struct saa7134_dev *dev); /* ----------------------------------------------------------- */ -- cgit v1.1 From a62c61d3820417e8efac8796f0a46d7ab337af8d Mon Sep 17 00:00:00 2001 From: Ricardo Cerqueira Date: Mon, 17 Jul 2006 16:34:27 -0300 Subject: V4L/DVB (4313): Bugfix for keycode calculation on NPG remotes Fix keycode calculations (all codes for this remote were wrong due to a lost + sign) Signed-off-by: Ricardo Cerqueira Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-input.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c index 72b630a..c255646 100644 --- a/drivers/media/video/cx88/cx88-input.c +++ b/drivers/media/video/cx88/cx88-input.c @@ -89,7 +89,7 @@ static void cx88_ir_handle_key(struct cx88_IR *ir) auxgpio = cx_read(MO_GP1_IO); /* Take out the parity part */ - gpio+=(gpio & 0x7fd) + (auxgpio & 0xef); + gpio=(gpio & 0x7fd) + (auxgpio & 0xef); } else auxgpio = gpio; -- cgit v1.1 From d9cd2d9b61898354f5dbabdc490dd6ef309ebbd4 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 17 Jul 2006 17:15:26 -0300 Subject: V4L/DVB (4314): Set the Auxiliary Byte when tuning LG H06xF in analog mode With the LG H06xF tuners, an auxiliary byte must be sent after the standard four-byte i2c sequence. The code that does this is currently in the wrong place, causing random bytes to be written to the tuner over i2c in the set_type function. This patch moves this code from set_type to default_set_tv_freq. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-core.c | 8 -------- drivers/media/video/tuner-simple.c | 19 +++++++++++++++++-- 2 files changed, 17 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index f7eb402..277d351 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -196,14 +196,6 @@ static void set_type(struct i2c_client *c, unsigned int type, i2c_master_send(c, buffer, 4); default_tuner_init(c); break; - case TUNER_LG_TDVS_H06XF: - /* Set the Auxiliary Byte. */ - buffer[2] &= ~0x20; - buffer[2] |= 0x18; - buffer[3] = 0x20; - i2c_master_send(c, buffer, 4); - default_tuner_init(c); - break; case TUNER_PHILIPS_TD1316: buffer[0] = 0x0b; buffer[1] = 0xdc; diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c index d071c5c..abe37cf 100644 --- a/drivers/media/video/tuner-simple.c +++ b/drivers/media/video/tuner-simple.c @@ -339,7 +339,20 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq) if (4 != (rc = i2c_master_send(c,buffer,4))) tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc); - if (t->type == TUNER_MICROTUNE_4042FI5) { + switch (t->type) { + case TUNER_LG_TDVS_H06XF: + /* Set the Auxiliary Byte. */ + buffer[0] = buffer[2]; + buffer[0] &= ~0x20; + buffer[0] |= 0x18; + buffer[1] = 0x20; + tuner_dbg("tv 0x%02x 0x%02x\n",buffer[0],buffer[1]); + + if (2 != (rc = i2c_master_send(c,buffer,2))) + tuner_warn("i2c i/o error: rc == %d (should be 2)\n",rc); + break; + case TUNER_MICROTUNE_4042FI5: + { // FIXME - this may also work for other tuners unsigned long timeout = jiffies + msecs_to_jiffies(1); u8 status_byte = 0; @@ -364,10 +377,12 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq) buffer[2] = config; buffer[3] = cb; tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n", - buffer[0],buffer[1],buffer[2],buffer[3]); + buffer[0],buffer[1],buffer[2],buffer[3]); if (4 != (rc = i2c_master_send(c,buffer,4))) tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc); + break; + } } } -- cgit v1.1 From 3117beec7e43f91ce156cacf033a712c7e22737d Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Wed, 19 Jul 2006 13:23:38 -0300 Subject: V4L/DVB (4316): Check __must_check warnings Check __must_check warnings for class_device_register and class_device_create_file video_device_create_file was declared as a void, but instead should return the int value of class_device_create_file. Move the check from bttv-driver.c into v4l2-dev.h, because all other callers of video_device_create_file must also be checked. Replace the call to class_device_create_file in videodev.c with video_device_create_file, as defined in v4l2-dev.h, so that the return value of class_device_create_file will be checked. Check the return value of class_device_register in videodev.c and pvrusb2-sysfs.c Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/bt8xx/bttv-driver.c | 8 ++----- drivers/media/video/pvrusb2/pvrusb2-sysfs.c | 33 ++++++++++++++++++++++++----- drivers/media/video/videodev.c | 11 +++++++--- 3 files changed, 38 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index 63e8316..6db5e4e 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -3909,8 +3909,6 @@ static void bttv_unregister_video(struct bttv *btv) /* register video4linux devices */ static int __devinit bttv_register_video(struct bttv *btv) { - int ret; - if (no_overlay <= 0) { bttv_video_template.type |= VID_TYPE_OVERLAY; } else { @@ -3925,10 +3923,8 @@ static int __devinit bttv_register_video(struct bttv *btv) goto err; printk(KERN_INFO "bttv%d: registered device video%d\n", btv->c.nr,btv->video_dev->minor & 0x1f); - ret = video_device_create_file(btv->video_dev, &class_device_attr_card); - if (ret < 0) - printk(KERN_WARNING "bttv: video_device_create_file error: " - "%d\n", ret); + + video_device_create_file(btv->video_dev, &class_device_attr_card); /* vbi */ btv->vbi_dev = vdev_init(btv, &bttv_vbi_template, "vbi"); diff --git a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c index 6af55a8..ef46d4f 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c +++ b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c @@ -600,6 +600,8 @@ static ssize_t debugcmd_store(struct class_device *,const char *,size_t count); static void pvr2_sysfs_add_debugifc(struct pvr2_sysfs *sfp) { struct pvr2_sysfs_debugifc *dip; + int ret; + dip = kmalloc(sizeof(*dip),GFP_KERNEL); if (!dip) return; memset(dip,0,sizeof(*dip)); @@ -613,8 +615,14 @@ static void pvr2_sysfs_add_debugifc(struct pvr2_sysfs *sfp) dip->attr_debuginfo.attr.mode = S_IRUGO; dip->attr_debuginfo.show = debuginfo_show; sfp->debugifc = dip; - class_device_create_file(sfp->class_dev,&dip->attr_debugcmd); - class_device_create_file(sfp->class_dev,&dip->attr_debuginfo); + ret = class_device_create_file(sfp->class_dev,&dip->attr_debugcmd); + if (ret < 0) + printk(KERN_WARNING "%s: class_device_create_file error: %d\n", + __FUNCTION__, ret); + ret = class_device_create_file(sfp->class_dev,&dip->attr_debuginfo); + if (ret < 0) + printk(KERN_WARNING "%s: class_device_create_file error: %d\n", + __FUNCTION__, ret); } @@ -709,6 +717,8 @@ static void class_dev_create(struct pvr2_sysfs *sfp, { struct usb_device *usb_dev; struct class_device *class_dev; + int ret; + usb_dev = pvr2_hdw_get_dev(sfp->channel.hdw); if (!usb_dev) return; class_dev = kmalloc(sizeof(*class_dev),GFP_KERNEL); @@ -733,20 +743,33 @@ static void class_dev_create(struct pvr2_sysfs *sfp, sfp->class_dev = class_dev; class_dev->class_data = sfp; - class_device_register(class_dev); + ret = class_device_register(class_dev); + if (ret) { + printk(KERN_ERR "%s: class_device_register failed\n", + __FUNCTION__); + kfree(class_dev); + return; + } sfp->attr_v4l_minor_number.attr.owner = THIS_MODULE; sfp->attr_v4l_minor_number.attr.name = "v4l_minor_number"; sfp->attr_v4l_minor_number.attr.mode = S_IRUGO; sfp->attr_v4l_minor_number.show = v4l_minor_number_show; sfp->attr_v4l_minor_number.store = NULL; - class_device_create_file(sfp->class_dev,&sfp->attr_v4l_minor_number); + ret = class_device_create_file(sfp->class_dev,&sfp->attr_v4l_minor_number); + if (ret < 0) + printk(KERN_WARNING "%s: class_device_create_file error: %d\n", + __FUNCTION__, ret); + sfp->attr_unit_number.attr.owner = THIS_MODULE; sfp->attr_unit_number.attr.name = "unit_number"; sfp->attr_unit_number.attr.mode = S_IRUGO; sfp->attr_unit_number.show = unit_number_show; sfp->attr_unit_number.store = NULL; - class_device_create_file(sfp->class_dev,&sfp->attr_unit_number); + ret = class_device_create_file(sfp->class_dev,&sfp->attr_unit_number); + if (ret < 0) + printk(KERN_WARNING "%s: class_device_create_file error: %d\n", + __FUNCTION__, ret); pvr2_sysfs_add_controls(sfp); #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c index b26ebaf..4c3f926 100644 --- a/drivers/media/video/videodev.c +++ b/drivers/media/video/videodev.c @@ -1512,6 +1512,7 @@ int video_register_device(struct video_device *vfd, int type, int nr) int i=0; int base; int end; + int ret; char *name_base; switch(type) @@ -1571,9 +1572,13 @@ int video_register_device(struct video_device *vfd, int type, int nr) vfd->class_dev.class = &video_class; vfd->class_dev.devt = MKDEV(VIDEO_MAJOR, vfd->minor); sprintf(vfd->class_dev.class_id, "%s%d", name_base, i - base); - class_device_register(&vfd->class_dev); - class_device_create_file(&vfd->class_dev, - &class_device_attr_name); + ret = class_device_register(&vfd->class_dev); + if (ret) { + printk(KERN_ERR "%s: class_device_register failed\n", + __FUNCTION__); + return ret; + } + video_device_create_file(vfd, &class_device_attr_name); #if 1 /* needed until all drivers are fixed */ -- cgit v1.1 From 32e4c3a5622e832938aa0272e21a292564ff090a Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Tue, 18 Jul 2006 22:55:23 -0300 Subject: V4L/DVB (4323): [budget/budget-av/budget-ci/budget-patch drivers] fixed DMA start/stop code Fix bug reported by Andrew de Quincey: After cold boot the saa7146 DMA did not start if the demuxer was opened before the frontend has locked to the signal. DMA transfers will be started now if (and only if) the frontend is locked and data should be sent to the demuxer. Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/ttpci/budget-av.c | 3 ++ drivers/media/dvb/ttpci/budget-ci.c | 2 ++ drivers/media/dvb/ttpci/budget-core.c | 57 ++++++++++++++++++++++++++-------- drivers/media/dvb/ttpci/budget-patch.c | 2 ++ drivers/media/dvb/ttpci/budget.c | 2 ++ drivers/media/dvb/ttpci/budget.h | 7 +++-- 6 files changed, 57 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c index 5f111d4..2d21fec 100644 --- a/drivers/media/dvb/ttpci/budget-av.c +++ b/drivers/media/dvb/ttpci/budget-av.c @@ -1303,6 +1303,9 @@ static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extensio budget_av->budget.dvb_adapter.priv = budget_av; frontend_init(budget_av); ciintf_init(budget_av); + + ttpci_budget_init_hooks(&budget_av->budget); + return 0; } diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c index 4b966ee..ffbbb3e 100644 --- a/drivers/media/dvb/ttpci/budget-ci.c +++ b/drivers/media/dvb/ttpci/budget-ci.c @@ -1101,6 +1101,8 @@ static int budget_ci_attach(struct saa7146_dev *dev, struct saa7146_pci_extensio budget_ci->budget.dvb_adapter.priv = budget_ci; frontend_init(budget_ci); + ttpci_budget_init_hooks(&budget_ci->budget); + return 0; } diff --git a/drivers/media/dvb/ttpci/budget-core.c b/drivers/media/dvb/ttpci/budget-core.c index e4cf777..e15562f 100644 --- a/drivers/media/dvb/ttpci/budget-core.c +++ b/drivers/media/dvb/ttpci/budget-core.c @@ -63,9 +63,6 @@ static int stop_ts_capture(struct budget *budget) { dprintk(2, "budget: %p\n", budget); - if (--budget->feeding) - return budget->feeding; - saa7146_write(budget->dev, MC1, MASK_20); // DMA3 off SAA7146_IER_DISABLE(budget->dev, MASK_10); return 0; @@ -77,8 +74,8 @@ static int start_ts_capture(struct budget *budget) dprintk(2, "budget: %p\n", budget); - if (budget->feeding) - return ++budget->feeding; + if (!budget->feeding || !budget->fe_synced) + return 0; saa7146_write(dev, MC1, MASK_20); // DMA3 off @@ -139,7 +136,33 @@ static int start_ts_capture(struct budget *budget) SAA7146_IER_ENABLE(budget->dev, MASK_10); /* VPE */ saa7146_write(dev, MC1, (MASK_04 | MASK_20)); /* DMA3 on */ - return ++budget->feeding; + return 0; +} + +static int budget_read_fe_status(struct dvb_frontend *fe, fe_status_t *status) +{ + struct budget *budget = (struct budget *) fe->dvb->priv; + int synced; + int ret; + + if (budget->read_fe_status) + ret = budget->read_fe_status(fe, status); + else + ret = -EINVAL; + + if (!ret) { + synced = (*status & FE_HAS_LOCK); + if (synced != budget->fe_synced) { + budget->fe_synced = synced; + spin_lock(&budget->feedlock); + if (synced) + start_ts_capture(budget); + else + stop_ts_capture(budget); + spin_unlock(&budget->feedlock); + } + } + return ret; } static void vpeirq(unsigned long data) @@ -267,7 +290,7 @@ static int budget_start_feed(struct dvb_demux_feed *feed) { struct dvb_demux *demux = feed->demux; struct budget *budget = (struct budget *) demux->priv; - int status; + int status = 0; dprintk(2, "budget: %p\n", budget); @@ -276,7 +299,8 @@ static int budget_start_feed(struct dvb_demux_feed *feed) spin_lock(&budget->feedlock); feed->pusi_seen = 0; /* have a clean section start */ - status = start_ts_capture(budget); + if (budget->feeding++ == 0) + status = start_ts_capture(budget); spin_unlock(&budget->feedlock); return status; } @@ -285,12 +309,13 @@ static int budget_stop_feed(struct dvb_demux_feed *feed) { struct dvb_demux *demux = feed->demux; struct budget *budget = (struct budget *) demux->priv; - int status; + int status = 0; dprintk(2, "budget: %p\n", budget); spin_lock(&budget->feedlock); - status = stop_ts_capture(budget); + if (--budget->feeding == 0) + status = stop_ts_capture(budget); spin_unlock(&budget->feedlock); return status; } @@ -470,6 +495,14 @@ err: return ret; } +void ttpci_budget_init_hooks(struct budget *budget) +{ + if (budget->dvb_frontend && !budget->read_fe_status) { + budget->read_fe_status = budget->dvb_frontend->ops.read_status; + budget->dvb_frontend->ops.read_status = budget_read_fe_status; + } +} + int ttpci_budget_deinit(struct budget *budget) { struct saa7146_dev *dev = budget->dev; @@ -508,11 +541,8 @@ void ttpci_budget_set_video_port(struct saa7146_dev *dev, int video_port) spin_lock(&budget->feedlock); budget->video_port = video_port; if (budget->feeding) { - int oldfeeding = budget->feeding; - budget->feeding = 1; stop_ts_capture(budget); start_ts_capture(budget); - budget->feeding = oldfeeding; } spin_unlock(&budget->feedlock); } @@ -520,6 +550,7 @@ void ttpci_budget_set_video_port(struct saa7146_dev *dev, int video_port) EXPORT_SYMBOL_GPL(ttpci_budget_debiread); EXPORT_SYMBOL_GPL(ttpci_budget_debiwrite); EXPORT_SYMBOL_GPL(ttpci_budget_init); +EXPORT_SYMBOL_GPL(ttpci_budget_init_hooks); EXPORT_SYMBOL_GPL(ttpci_budget_deinit); EXPORT_SYMBOL_GPL(ttpci_budget_irq10_handler); EXPORT_SYMBOL_GPL(ttpci_budget_set_video_port); diff --git a/drivers/media/dvb/ttpci/budget-patch.c b/drivers/media/dvb/ttpci/budget-patch.c index ee60ce9..5722744 100644 --- a/drivers/media/dvb/ttpci/budget-patch.c +++ b/drivers/media/dvb/ttpci/budget-patch.c @@ -617,6 +617,8 @@ static int budget_patch_attach (struct saa7146_dev* dev, struct saa7146_pci_exte budget->dvb_adapter.priv = budget; frontend_init(budget); + ttpci_budget_init_hooks(budget); + return 0; } diff --git a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c index 1b4d884..863dffb 100644 --- a/drivers/media/dvb/ttpci/budget.c +++ b/drivers/media/dvb/ttpci/budget.c @@ -471,6 +471,8 @@ static int budget_attach (struct saa7146_dev* dev, struct saa7146_pci_extension_ budget->dvb_adapter.priv = budget; frontend_init(budget); + ttpci_budget_init_hooks(budget); + return 0; } diff --git a/drivers/media/dvb/ttpci/budget.h b/drivers/media/dvb/ttpci/budget.h index ecea3a1..e8a5c79 100644 --- a/drivers/media/dvb/ttpci/budget.h +++ b/drivers/media/dvb/ttpci/budget.h @@ -52,9 +52,6 @@ struct budget { struct dmx_frontend hw_frontend; struct dmx_frontend mem_frontend; - int fe_synced; - struct mutex pid_mutex; - int ci_present; int video_port; @@ -74,6 +71,9 @@ struct budget { struct dvb_adapter dvb_adapter; struct dvb_frontend *dvb_frontend; + int (*read_fe_status)(struct dvb_frontend *fe, fe_status_t *status); + int fe_synced; + void *priv; }; @@ -106,6 +106,7 @@ static struct saa7146_pci_extension_data x_var = { \ extern int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev, struct saa7146_pci_extension_data *info, struct module *owner); +extern void ttpci_budget_init_hooks(struct budget *budget); extern int ttpci_budget_deinit(struct budget *budget); extern void ttpci_budget_irq10_handler(struct saa7146_dev *dev, u32 * isr); extern void ttpci_budget_set_video_port(struct saa7146_dev *dev, int video_port); -- cgit v1.1 From e61b6fc58b4a0b07f1ccfc67bf2b84a2848fcb2c Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Tue, 18 Jul 2006 22:42:18 -0300 Subject: V4L/DVB (4337): Refine dead code elimination in pvrusb2 Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-hdw.c | 8 ++++++-- drivers/media/video/pvrusb2/pvrusb2-io.c | 9 ++++++--- drivers/media/video/pvrusb2/pvrusb2-io.h | 2 ++ drivers/media/video/pvrusb2/pvrusb2-ioread.c | 5 +++-- 4 files changed, 17 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index 9b48abc..be1e5cc 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -852,7 +852,6 @@ unsigned long pvr2_hdw_get_sn(struct pvr2_hdw *hdw) return hdw->serial_number; } - int pvr2_hdw_get_unit_number(struct pvr2_hdw *hdw) { return hdw->unit_number; @@ -2318,7 +2317,6 @@ void pvr2_hdw_poll_trigger_unlocked(struct pvr2_hdw *hdw) } } - /* Return name for this driver instance */ const char *pvr2_hdw_get_driver_name(struct pvr2_hdw *hdw) { @@ -2542,6 +2540,10 @@ static void pvr2_ctl_timeout(unsigned long data) } +/* Issue a command and get a response from the device. This extended + version includes a probe flag (which if set means that device errors + should not be logged or treated as fatal) and a timeout in jiffies. + This can be used to non-lethally probe the health of endpoint 1. */ static int pvr2_send_request_ex(struct pvr2_hdw *hdw, unsigned int timeout,int probe_fl, void *write_data,unsigned int write_len, @@ -2970,6 +2972,7 @@ int pvr2_hdw_cmd_decoder_reset(struct pvr2_hdw *hdw) } +/* Stop / start video stream transport */ static int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl) { int status; @@ -3068,6 +3071,7 @@ int pvr2_hdw_gpio_chg_out(struct pvr2_hdw *hdw,u32 msk,u32 val) } +/* Find I2C address of eeprom */ static int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw) { int result; diff --git a/drivers/media/video/pvrusb2/pvrusb2-io.c b/drivers/media/video/pvrusb2/pvrusb2-io.c index 681f79c..1e39376 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-io.c +++ b/drivers/media/video/pvrusb2/pvrusb2-io.c @@ -26,6 +26,8 @@ #include #include +static const char *pvr2_buffer_state_decode(enum pvr2_buffer_state); + #define BUFFER_SIG 0x47653271 // #define SANITY_CHECK_BUFFERS @@ -515,6 +517,10 @@ void pvr2_stream_set_callback(struct pvr2_stream *sp, } /* Query / set the nominal buffer count */ +int pvr2_stream_get_buffer_count(struct pvr2_stream *sp) +{ + return sp->buffer_target_count; +} int pvr2_stream_set_buffer_count(struct pvr2_stream *sp,unsigned int cnt) { @@ -553,7 +559,6 @@ int pvr2_stream_get_ready_count(struct pvr2_stream *sp) return sp->r_count; } - void pvr2_stream_kill(struct pvr2_stream *sp) { struct pvr2_buffer *bp; @@ -607,7 +612,6 @@ int pvr2_buffer_queue(struct pvr2_buffer *bp) return ret; } - int pvr2_buffer_set_buffer(struct pvr2_buffer *bp,void *ptr,unsigned int cnt) { int ret = 0; @@ -646,7 +650,6 @@ int pvr2_buffer_get_status(struct pvr2_buffer *bp) return bp->status; } - int pvr2_buffer_get_id(struct pvr2_buffer *bp) { return bp->id; diff --git a/drivers/media/video/pvrusb2/pvrusb2-io.h b/drivers/media/video/pvrusb2/pvrusb2-io.h index 96285ad..93279cc 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-io.h +++ b/drivers/media/video/pvrusb2/pvrusb2-io.h @@ -47,6 +47,7 @@ void pvr2_stream_set_callback(struct pvr2_stream *, void *data); /* Query / set the nominal buffer count */ +int pvr2_stream_get_buffer_count(struct pvr2_stream *); int pvr2_stream_set_buffer_count(struct pvr2_stream *,unsigned int); /* Get a pointer to a buffer that is either idle, ready, or is specified @@ -58,6 +59,7 @@ struct pvr2_buffer *pvr2_stream_get_buffer(struct pvr2_stream *sp,int id); /* Find out how many buffers are idle or ready */ int pvr2_stream_get_ready_count(struct pvr2_stream *); + /* Kill all pending buffers and throw away any ready buffers as well */ void pvr2_stream_kill(struct pvr2_stream *); diff --git a/drivers/media/video/pvrusb2/pvrusb2-ioread.c b/drivers/media/video/pvrusb2/pvrusb2-ioread.c index f7a2e22..b71f9a9 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-ioread.c +++ b/drivers/media/video/pvrusb2/pvrusb2-ioread.c @@ -213,7 +213,9 @@ int pvr2_ioread_setup(struct pvr2_ioread *cp,struct pvr2_stream *sp) " pvr2_ioread_setup (tear-down) id=%p",cp); pvr2_ioread_stop(cp); pvr2_stream_kill(cp->stream); - pvr2_stream_set_buffer_count(cp->stream,0); + if (pvr2_stream_get_buffer_count(cp->stream)) { + pvr2_stream_set_buffer_count(cp->stream,0); + } cp->stream = NULL; } if (sp) { @@ -251,7 +253,6 @@ int pvr2_ioread_set_enabled(struct pvr2_ioread *cp,int fl) return ret; } - static int pvr2_ioread_get_buffer(struct pvr2_ioread *cp) { int stat; -- cgit v1.1 From 55c05b6d226f68266d1f88dd81795b04d096b1c8 Mon Sep 17 00:00:00 2001 From: Andrew de Quincey Date: Sun, 16 Jul 2006 19:41:41 -0300 Subject: V4L/DVB (4311): Fix possible dvb-pll oops Supplying a NULL i2c adapter to dvb_pll_attach is allowed, for example with mt352 demods. However, the pll i2c probe will segfault because it does not check for this. Signed-off-by: Andrew de Quincey Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/dvb-pll.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c index fce5c42..4c8a506 100644 --- a/drivers/media/dvb/frontends/dvb-pll.c +++ b/drivers/media/dvb/frontends/dvb-pll.c @@ -619,14 +619,16 @@ int dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, struct i2c_adapter *i2 struct dvb_pll_priv *priv = NULL; int ret; - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - ret = i2c_transfer (i2c, msg, 2); - if (ret != 2) - return -1; - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); + if (i2c != NULL) { + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + ret = i2c_transfer (i2c, msg, 2); + if (ret != 2) + return -1; + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + } priv = kzalloc(sizeof(struct dvb_pll_priv), GFP_KERNEL); if (priv == NULL) -- cgit v1.1 From 95faba22d8b81f0cd85b995232b7d05c45a26f3e Mon Sep 17 00:00:00 2001 From: Andrew de Quincey Date: Tue, 18 Jul 2006 16:37:13 -0300 Subject: V4L/DVB (4322): Fix dvb-pll autoprobing Trent Piepho pointed out that the pll test i2c transmission is slightly wrong; it was transmitting a zero length message, and then reading from the PLL. This was wrong; it should only be transmitting a single read i2c message. Signed-off-by: Andrew de Quincey Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/dvb-pll.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c index 4c8a506..2be33f2 100644 --- a/drivers/media/dvb/frontends/dvb-pll.c +++ b/drivers/media/dvb/frontends/dvb-pll.c @@ -614,8 +614,7 @@ static struct dvb_tuner_ops dvb_pll_tuner_ops = { int dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, struct i2c_adapter *i2c, struct dvb_pll_desc *desc) { u8 b1 [] = { 0 }; - struct i2c_msg msg [] = { { .addr = pll_addr, .flags = 0, .buf = NULL, .len = 0 }, - { .addr = pll_addr, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; + struct i2c_msg msg = { .addr = pll_addr, .flags = I2C_M_RD, .buf = b1, .len = 1 }; struct dvb_pll_priv *priv = NULL; int ret; @@ -623,8 +622,8 @@ int dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, struct i2c_adapter *i2 if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); - ret = i2c_transfer (i2c, msg, 2); - if (ret != 2) + ret = i2c_transfer (i2c, &msg, 1); + if (ret != 1) return -1; if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); -- cgit v1.1 From eb4eeccc18246c852fffc771efc3c07a547aeb97 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 21 Jul 2006 18:53:23 -0300 Subject: V4L/DVB (4341): VIDIOCSMICROCODE were missing on compat_ioctl32 video_code size is 24 on i386 and 32 on x86_64, so a proper handling is needed on compat_ioctl32 to fix it. This code should be tested, since just *a few* boards use this ioctl. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/compat_ioctl32.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/compat_ioctl32.c b/drivers/media/video/compat_ioctl32.c index 353d02b..9dddff4 100644 --- a/drivers/media/video/compat_ioctl32.c +++ b/drivers/media/video/compat_ioctl32.c @@ -490,6 +490,23 @@ static inline int put_v4l2_input(struct v4l2_input *kp, struct v4l2_input __user return 0; } +struct video_code32 +{ + char loadwhat[16]; /* name or tag of file being passed */ + compat_int_t datasize; + unsigned char *data; +}; + +static inline int microcode32(struct video_code *kp, struct video_code32 __user *up) +{ + if(!access_ok(VERIFY_READ, up, sizeof(struct video_code32)) || + copy_from_user(kp->loadwhat, up->loadwhat, sizeof (up->loadwhat)) || + get_user(kp->datasize, &up->datasize) || + copy_from_user(kp->data, up->data, up->datasize)) + return -EFAULT; + return 0; +} + #define VIDIOCGTUNER32 _IOWR('v',4, struct video_tuner32) #define VIDIOCSTUNER32 _IOW('v',5, struct video_tuner32) #define VIDIOCGWIN32 _IOR('v',9, struct video_window32) @@ -498,6 +515,7 @@ static inline int put_v4l2_input(struct v4l2_input *kp, struct v4l2_input __user #define VIDIOCSFBUF32 _IOW('v',12, struct video_buffer32) #define VIDIOCGFREQ32 _IOR('v',14, u32) #define VIDIOCSFREQ32 _IOW('v',15, u32) +#define VIDIOCSMICROCODE32 _IOW('v',27, struct video_code32) /* VIDIOC_ENUMINPUT32 is VIDIOC_ENUMINPUT minus 4 bytes of padding alignement */ #define VIDIOC_ENUMINPUT32 VIDIOC_ENUMINPUT - _IOC(0, 0, 0, 4) @@ -590,6 +608,7 @@ static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg struct video_tuner vt; struct video_buffer vb; struct video_window vw; + struct video_code vc; struct v4l2_format v2f; struct v4l2_buffer v2b; struct v4l2_framebuffer v2fb; @@ -628,6 +647,7 @@ static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg case VIDIOC_G_INPUT32: cmd = VIDIOC_G_INPUT; break; case VIDIOC_S_INPUT32: cmd = VIDIOC_S_INPUT; break; case VIDIOC_TRY_FMT32: cmd = VIDIOC_TRY_FMT; break; + case VIDIOCSMICROCODE32: cmd = VIDIOCSMICROCODE; break; }; switch(cmd) { @@ -703,6 +723,10 @@ static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg case VIDIOC_G_FBUF: case VIDIOC_G_INPUT: compatible_arg = 0; + case VIDIOCSMICROCODE: + err = microcode32(&karg.vc, up); + compatible_arg = 0; + break; }; if(err) -- cgit v1.1 From 985bc96e27c729b8b686126ed26bba9fbaaf562d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 23 Jul 2006 06:31:19 -0300 Subject: V4L/DVB (4343): Fix for compilation without V4L1 or V4L1_COMPAT Removed usage of HAVE_V4L1 Including videodev.h will just include videodev2.h if V4L1 is not supported V4L1 code at core drivers will honor CONFIG_V4L1_COMPAT stuff Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-video.c | 4 ++-- drivers/media/video/msp3400-driver.c | 10 +++++++++- drivers/media/video/saa7134/saa7134-video.c | 2 +- drivers/media/video/tuner-core.c | 23 ++++++++++++----------- drivers/media/video/v4l2-common.c | 24 ++++++++++++++---------- drivers/media/video/videodev.c | 8 ++++++-- drivers/media/video/vivi.c | 4 ++-- 7 files changed, 46 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index 2225d4b..ff4e7ed 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -1226,7 +1226,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file, struct v4l2_format *f = arg; return cx8800_try_fmt(dev,fh,f); } -#ifdef HAVE_V4L1 +#ifdef CONFIG_V4L1_COMPAT /* --- streaming capture ------------------------------------- */ case VIDIOCGMBUF: { @@ -1585,7 +1585,7 @@ static int radio_do_ioctl(struct inode *inode, struct file *file, *id = 0; return 0; } -#ifdef HAVE_V4L1 +#ifdef CONFIG_V4L1_COMPAT case VIDIOCSTUNER: { struct video_tuner *v = arg; diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c index dbb75a7..56246b8 100644 --- a/drivers/media/video/msp3400-driver.c +++ b/drivers/media/video/msp3400-driver.c @@ -362,7 +362,7 @@ int msp_sleep(struct msp_state *state, int timeout) } /* ------------------------------------------------------------------------ */ - +#ifdef CONFIG_VIDEO_V4L1 static int msp_mode_v4l2_to_v4l1(int rxsubchans, int audmode) { if (rxsubchans == V4L2_TUNER_SUB_MONO) @@ -384,6 +384,7 @@ static int msp_mode_v4l1_to_v4l2(int mode) return V4L2_TUNER_MODE_LANG1; return V4L2_TUNER_MODE_MONO; } +#endif static int msp_get_ctrl(struct i2c_client *client, struct v4l2_control *ctrl) { @@ -509,6 +510,7 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) /* --- v4l ioctls --- */ /* take care: bttv does userspace copying, we'll get a kernel pointer here... */ +#ifdef CONFIG_VIDEO_V4L1 case VIDIOCGAUDIO: { struct video_audio *va = arg; @@ -577,6 +579,12 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) } case VIDIOCSFREQ: + { + /* new channel -- kick audio carrier scan */ + msp_wake_thread(client); + break; + } +#endif case VIDIOC_S_FREQUENCY: { /* new channel -- kick audio carrier scan */ diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index 8277958..8656f24 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -2087,7 +2087,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file, struct v4l2_format *f = arg; return saa7134_try_fmt(dev,fh,f); } -#ifdef HAVE_V4L1 +#ifdef CONFIG_V4L1_COMPAT case VIDIOCGMBUF: { struct video_mbuf *mbuf = arg; diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 277d351..40590ba 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -590,6 +590,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) if (t->standby) t->standby (client); break; +#ifdef CONFIG_VIDEO_V4L1 case VIDIOCSAUDIO: if (check_mode(t, "VIDIOCSAUDIO") == EINVAL) return 0; @@ -599,17 +600,6 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) /* Should be implemented, since bttv calls it */ tuner_dbg("VIDIOCSAUDIO not implemented.\n"); break; - case TDA9887_SET_CONFIG: - if (t->type == TUNER_TDA9887) { - int *i = arg; - - t->tda9887_config = *i; - set_freq(client, t->tv_freq); - } - break; - /* --- v4l ioctls --- */ - /* take care: bttv does userspace copying, we'll get a - kernel pointer here... */ case VIDIOCSCHAN: { static const v4l2_std_id map[] = { @@ -693,7 +683,18 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO; return 0; } +#endif + case TDA9887_SET_CONFIG: + if (t->type == TUNER_TDA9887) { + int *i = arg; + t->tda9887_config = *i; + set_freq(client, t->tv_freq); + } + break; + /* --- v4l ioctls --- */ + /* take care: bttv does userspace copying, we'll get a + kernel pointer here... */ case VIDIOC_S_STD: { v4l2_std_id *id = arg; diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c index f06dc19..2ecbeff 100644 --- a/drivers/media/video/v4l2-common.c +++ b/drivers/media/video/v4l2-common.c @@ -202,7 +202,7 @@ static char *v4l2_memory_names[] = { /* ------------------------------------------------------------------ */ /* debug help functions */ -#ifdef HAVE_V4L1 +#ifdef CONFIG_V4L1_COMPAT static const char *v4l1_ioctls[] = { [_IOC_NR(VIDIOCGCAP)] = "VIDIOCGCAP", [_IOC_NR(VIDIOCGCHAN)] = "VIDIOCGCHAN", @@ -301,7 +301,7 @@ static const char *v4l2_ioctls[] = { #define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls) static const char *v4l2_int_ioctls[] = { -#ifdef HAVE_VIDEO_DECODER +#ifdef CONFIG_V4L1_COMPAT [_IOC_NR(DECODER_GET_CAPABILITIES)] = "DECODER_GET_CAPABILITIES", [_IOC_NR(DECODER_GET_STATUS)] = "DECODER_GET_STATUS", [_IOC_NR(DECODER_SET_NORM)] = "DECODER_SET_NORM", @@ -367,7 +367,7 @@ void v4l_printk_ioctl(unsigned int cmd) (_IOC_NR(cmd) < V4L2_INT_IOCTLS) ? v4l2_int_ioctls[_IOC_NR(cmd)] : "UNKNOWN", dir, cmd); break; -#ifdef HAVE_V4L1 +#ifdef CONFIG_V4L1_COMPAT case 'v': printk("v4l1 ioctl %s, dir=%s (0x%08x)\n", (_IOC_NR(cmd) < V4L1_IOCTLS) ? @@ -414,6 +414,7 @@ void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg) printk ("%s: tuner type=%d\n", s, *p); break; } +#ifdef CONFIG_VIDEO_V4L1_COMPAT case DECODER_SET_VBI_BYPASS: case DECODER_ENABLE_OUTPUT: case DECODER_GET_STATUS: @@ -424,6 +425,7 @@ void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg) case VIDIOCCAPTURE: case VIDIOCSYNC: case VIDIOCSWRITEMODE: +#endif case TUNER_SET_TYPE_ADDR: case TUNER_SET_STANDBY: case TDA9887_SET_CONFIG: @@ -755,6 +757,7 @@ void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg) p->afc); break; } +#ifdef CONFIG_VIDEO_V4L1_COMPAT case VIDIOCGVBIFMT: case VIDIOCSVBIFMT: { @@ -924,6 +927,14 @@ void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg) p->clipcount); break; } + case VIDIOCGFREQ: + case VIDIOCSFREQ: + { + unsigned long *p=arg; + printk ("%s: value=%lu\n", s, *p); + break; + } +#endif case VIDIOC_INT_AUDIO_CLOCK_FREQ: case VIDIOC_INT_I2S_CLOCK_FREQ: case VIDIOC_INT_S_STANDBY: @@ -933,13 +944,6 @@ void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg) printk ("%s: value=%d\n", s, *p); break; } - case VIDIOCGFREQ: - case VIDIOCSFREQ: - { - unsigned long *p=arg; - printk ("%s: value=%lu\n", s, *p); - break; - } case VIDIOC_G_STD: case VIDIOC_S_STD: case VIDIOC_QUERYSTD: diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c index 4c3f926..5c52819 100644 --- a/drivers/media/video/videodev.c +++ b/drivers/media/video/videodev.c @@ -760,7 +760,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, ret=vfd->vidioc_overlay(file, fh, *i); break; } -#ifdef HAVE_V4L1 +#ifdef CONFIG_V4L1_COMPAT /* --- streaming capture ------------------------------------- */ case VIDIOCGMBUF: { @@ -1578,7 +1578,11 @@ int video_register_device(struct video_device *vfd, int type, int nr) __FUNCTION__); return ret; } - video_device_create_file(vfd, &class_device_attr_name); + ret = class_device_create_file(&vfd->class_dev, &class_device_attr_name); + if (ret < 0) { + printk(KERN_WARNING "%s error: %d\n", __FUNCTION__, ret); + return ret; + } #if 1 /* needed until all drivers are fixed */ diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index 41d23c8..38bd0c1 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -986,7 +986,7 @@ static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *p) file->f_flags & O_NONBLOCK)); } -#ifdef HAVE_V4L1 +#ifdef CONFIG_V4L1_COMPAT static int vidiocgmbuf (struct file *file, void *priv, struct video_mbuf *mbuf) { struct vivi_fh *fh=priv; @@ -1328,7 +1328,7 @@ static struct video_device vivi = { .vidioc_s_ctrl = vidioc_s_ctrl, .vidioc_streamon = vidioc_streamon, .vidioc_streamoff = vidioc_streamoff, -#ifdef HAVE_V4L1 +#ifdef CONFIG_V4L1_COMPAT .vidiocgmbuf = vidiocgmbuf, #endif .tvnorms = tvnorms, -- cgit v1.1 From fb0b664c22b80df62c9e555afcde6a8dab08f4f0 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 23 Jul 2006 06:32:05 -0300 Subject: V4L/DVB (4344): Fix broken dependencies on media Kconfig Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Kconfig | 4 ++-- drivers/media/video/bt8xx/Kconfig | 2 +- drivers/media/video/cpia2/Kconfig | 2 +- drivers/media/video/usbvideo/Kconfig | 8 ++++---- 4 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 6d532f1..fe56862 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -145,7 +145,7 @@ config VIDEO_SAA5246A config VIDEO_SAA5249 tristate "SAA5249 Teletext processor" - depends on VIDEO_DEV && I2C + depends on VIDEO_DEV && I2C && VIDEO_V4L1 help Support for I2C bus based teletext using the SAA5249 chip. At the moment this is only useful on some European WinTV cards. @@ -155,7 +155,7 @@ config VIDEO_SAA5249 config TUNER_3036 tristate "SAB3036 tuner" - depends on VIDEO_DEV && I2C + depends on VIDEO_DEV && I2C && VIDEO_V4L1 help Say Y here to include support for Philips SAB3036 compatible tuners. If in doubt, say N. diff --git a/drivers/media/video/bt8xx/Kconfig b/drivers/media/video/bt8xx/Kconfig index 153f6a4..cdcf556 100644 --- a/drivers/media/video/bt8xx/Kconfig +++ b/drivers/media/video/bt8xx/Kconfig @@ -1,6 +1,6 @@ config VIDEO_BT848 tristate "BT848 Video For Linux" - depends on VIDEO_DEV && PCI && I2C && VIDEO_V4L2 + depends on VIDEO_DEV && PCI && I2C && VIDEO_V4L1 select I2C_ALGOBIT select FW_LOADER select VIDEO_BTCX diff --git a/drivers/media/video/cpia2/Kconfig b/drivers/media/video/cpia2/Kconfig index 513cc09..e39a961 100644 --- a/drivers/media/video/cpia2/Kconfig +++ b/drivers/media/video/cpia2/Kconfig @@ -1,6 +1,6 @@ config VIDEO_CPIA2 tristate "CPiA2 Video For Linux" - depends on VIDEO_DEV && USB + depends on VIDEO_DEV && USB && VIDEO_V4L1 ---help--- This is the video4linux driver for cameras based on Vision's CPiA2 (Colour Processor Interface ASIC), such as the Digital Blue QX5 diff --git a/drivers/media/video/usbvideo/Kconfig b/drivers/media/video/usbvideo/Kconfig index 59fb899..a0fd82b 100644 --- a/drivers/media/video/usbvideo/Kconfig +++ b/drivers/media/video/usbvideo/Kconfig @@ -3,7 +3,7 @@ config VIDEO_USBVIDEO config USB_VICAM tristate "USB 3com HomeConnect (aka vicam) support (EXPERIMENTAL)" - depends on USB && VIDEO_V4L1 && EXPERIMENTAL + depends on USB && VIDEO_DEV && VIDEO_V4L1 && EXPERIMENTAL select VIDEO_USBVIDEO ---help--- Say Y here if you have 3com homeconnect camera (vicam). @@ -13,7 +13,7 @@ config USB_VICAM config USB_IBMCAM tristate "USB IBM (Xirlink) C-it Camera support" - depends on USB && VIDEO_V4L1 + depends on USB && VIDEO_DEV && VIDEO_V4L1 select VIDEO_USBVIDEO ---help--- Say Y here if you want to connect a IBM "C-It" camera, also known as @@ -28,7 +28,7 @@ config USB_IBMCAM config USB_KONICAWC tristate "USB Konica Webcam support" - depends on USB && VIDEO_V4L1 + depends on USB && VIDEO_DEV && VIDEO_V4L1 select VIDEO_USBVIDEO ---help--- Say Y here if you want support for webcams based on a Konica @@ -39,7 +39,7 @@ config USB_KONICAWC config USB_QUICKCAM_MESSENGER tristate "USB Logitech Quickcam Messenger" - depends on USB && VIDEO_DEV + depends on USB && VIDEO_DEV && VIDEO_V4L1 select VIDEO_USBVIDEO ---help--- Say Y or M here to enable support for the USB Logitech Quickcam -- cgit v1.1 From df2732706c745c827762aaf51892f281fb937680 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 24 Jul 2006 15:19:37 -0300 Subject: V4L/DVB (4365): OVERLAY flag were enabled by mistake A patch from Aug, 17 activated by mistake OVERLAY flag on cx88-video, together with several cx88-blackbird cleanups. This makes the cx88 driver to report: /dev/video0 [v4l2]: ioctl VIDIOC_G_FBUF: Invalid argument instead of: /dev/video0 [v4l2]: no overlay support Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-video.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index ff4e7ed..547cdbd 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -1180,7 +1180,6 @@ static int video_do_ioctl(struct inode *inode, struct file *file, V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | V4L2_CAP_VBI_CAPTURE | - V4L2_CAP_VIDEO_OVERLAY | 0; if (UNSET != core->tuner_type) cap->capabilities |= V4L2_CAP_TUNER; -- cgit v1.1 From 53dd8def52100ed8be4dae0cf1c2dc1f7e0fcd2c Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Tue, 25 Jul 2006 09:31:42 -0300 Subject: V4L/DVB (4367): Videodev: Handle class_device related errors Add proper error checking and roll-back for failure of class_device_create_file() in videodev.c. Print error messages and unroll partially created sysfs entries. Also, failure of class_device_register() in video_register_device() is handled correctly. It was failing to de-allocate the minor number. This must be done in video_register_device(), since the caller has no way of knowing if failure occurred before or after the class device was registered. Also added an error message if video_register_device() is called with an unknown type, which should never happen. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videodev.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c index 5c52819..caa4f73 100644 --- a/drivers/media/video/videodev.c +++ b/drivers/media/video/videodev.c @@ -1538,6 +1538,8 @@ int video_register_device(struct video_device *vfd, int type, int nr) name_base = "radio"; break; default: + printk(KERN_ERR "%s called with unknown type: %d\n", + __FUNCTION__, type); return -1; } @@ -1592,6 +1594,15 @@ int video_register_device(struct video_device *vfd, int type, int nr) "http://lwn.net/Articles/36850/\n", vfd->name); #endif return 0; + +fail_classdev: + class_device_unregister(&vfd->class_dev); +fail_minor: + mutex_lock(&videodev_lock); + video_device[vfd->minor] = NULL; + vfd->minor = -1; + mutex_unlock(&videodev_lock); + return ret; } /** -- cgit v1.1 From d94fc9a08e51432d0d5fc0f74a4f705d7b49c251 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Sat, 29 Jul 2006 17:18:06 -0300 Subject: V4L/DVB (4368): Bttv: use class_device_create_file and handle errors Revert bttv-driver.c from video_device_create_file() to use class_device_create_file() again. video_device_create_file() is only available when V4L1 is on. Proper error checking is added for failure of class_device_create_file(). Will print error message and unroll partially created sysfs entries. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/bt8xx/bttv-driver.c | 8 ++++++-- drivers/media/video/videodev.c | 7 ++++--- 2 files changed, 10 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index 6db5e4e..20dff7c 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -3923,8 +3923,12 @@ static int __devinit bttv_register_video(struct bttv *btv) goto err; printk(KERN_INFO "bttv%d: registered device video%d\n", btv->c.nr,btv->video_dev->minor & 0x1f); - - video_device_create_file(btv->video_dev, &class_device_attr_card); + if (class_device_create_file(&btv->video_dev->class_dev, + &class_device_attr_card)<0) { + printk(KERN_ERR "bttv%d: class_device_create_file 'card' " + "failed\n", btv->c.nr); + goto err; + } /* vbi */ btv->vbi_dev = vdev_init(btv, &bttv_vbi_template, "vbi"); diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c index caa4f73..46848e2 100644 --- a/drivers/media/video/videodev.c +++ b/drivers/media/video/videodev.c @@ -1578,12 +1578,13 @@ int video_register_device(struct video_device *vfd, int type, int nr) if (ret) { printk(KERN_ERR "%s: class_device_register failed\n", __FUNCTION__); - return ret; + goto fail_minor; } ret = class_device_create_file(&vfd->class_dev, &class_device_attr_name); if (ret < 0) { - printk(KERN_WARNING "%s error: %d\n", __FUNCTION__, ret); - return ret; + printk(KERN_ERR "%s: class_device_create_file 'name' failed\n", + __FUNCTION__); + goto fail_classdev; } #if 1 -- cgit v1.1 From 08d41808362a3663c0856c9720ad940a61156fb5 Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Sat, 22 Jul 2006 21:26:30 -0300 Subject: V4L/DVB (4373): Correctly handle sysfs error leg file removal in pvrusb2 Take note of which sysfs files / groups that the pvrusb2 successfully creates and only delete those specific items when tearing things down. (Previously we just blindly tore everything down every time.) Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-sysfs.c | 62 +++++++++++++++++++++++------ 1 file changed, 50 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c index ef46d4f..d1dda5c 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c +++ b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c @@ -44,12 +44,16 @@ struct pvr2_sysfs { struct kobj_type ktype; struct class_device_attribute attr_v4l_minor_number; struct class_device_attribute attr_unit_number; + int v4l_minor_number_created_ok; + int unit_number_created_ok; }; #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC struct pvr2_sysfs_debugifc { struct class_device_attribute attr_debugcmd; struct class_device_attribute attr_debuginfo; + int debugcmd_created_ok; + int debuginfo_created_ok; }; #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */ @@ -67,6 +71,7 @@ struct pvr2_sysfs_ctl_item { struct pvr2_sysfs_ctl_item *item_next; struct attribute *attr_gen[7]; struct attribute_group grp; + int created_ok; char name[80]; }; @@ -487,6 +492,7 @@ static void pvr2_sysfs_add_control(struct pvr2_sysfs *sfp,int ctl_id) struct pvr2_sysfs_func_set *fp; struct pvr2_ctrl *cptr; unsigned int cnt,acnt; + int ret; if ((ctl_id < 0) || (ctl_id >= (sizeof(funcs)/sizeof(funcs[0])))) { return; @@ -589,7 +595,13 @@ static void pvr2_sysfs_add_control(struct pvr2_sysfs *sfp,int ctl_id) cip->grp.name = cip->name; cip->grp.attrs = cip->attr_gen; - sysfs_create_group(&sfp->class_dev->kobj,&cip->grp); + ret = sysfs_create_group(&sfp->class_dev->kobj,&cip->grp); + if (ret) { + printk(KERN_WARNING "%s: sysfs_create_group error: %d\n", + __FUNCTION__, ret); + return; + } + cip->created_ok = !0; } #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC @@ -616,22 +628,33 @@ static void pvr2_sysfs_add_debugifc(struct pvr2_sysfs *sfp) dip->attr_debuginfo.show = debuginfo_show; sfp->debugifc = dip; ret = class_device_create_file(sfp->class_dev,&dip->attr_debugcmd); - if (ret < 0) + if (ret < 0) { printk(KERN_WARNING "%s: class_device_create_file error: %d\n", __FUNCTION__, ret); + } else { + dip->debugcmd_created_ok = !0; + } ret = class_device_create_file(sfp->class_dev,&dip->attr_debuginfo); - if (ret < 0) + if (ret < 0) { printk(KERN_WARNING "%s: class_device_create_file error: %d\n", __FUNCTION__, ret); + } else { + dip->debuginfo_created_ok = !0; + } } static void pvr2_sysfs_tear_down_debugifc(struct pvr2_sysfs *sfp) { if (!sfp->debugifc) return; - class_device_remove_file(sfp->class_dev, - &sfp->debugifc->attr_debuginfo); - class_device_remove_file(sfp->class_dev,&sfp->debugifc->attr_debugcmd); + if (sfp->debugifc->debuginfo_created_ok) { + class_device_remove_file(sfp->class_dev, + &sfp->debugifc->attr_debuginfo); + } + if (sfp->debugifc->debugcmd_created_ok) { + class_device_remove_file(sfp->class_dev, + &sfp->debugifc->attr_debugcmd); + } kfree(sfp->debugifc); sfp->debugifc = NULL; } @@ -653,7 +676,9 @@ static void pvr2_sysfs_tear_down_controls(struct pvr2_sysfs *sfp) struct pvr2_sysfs_ctl_item *cip1,*cip2; for (cip1 = sfp->item_first; cip1; cip1 = cip2) { cip2 = cip1->item_next; - sysfs_remove_group(&sfp->class_dev->kobj,&cip1->grp); + if (cip1->created_ok) { + sysfs_remove_group(&sfp->class_dev->kobj,&cip1->grp); + } pvr2_sysfs_trace("Destroying pvr2_sysfs_ctl_item id=%p",cip1); kfree(cip1); } @@ -683,8 +708,14 @@ static void class_dev_destroy(struct pvr2_sysfs *sfp) pvr2_sysfs_tear_down_debugifc(sfp); #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */ pvr2_sysfs_tear_down_controls(sfp); - class_device_remove_file(sfp->class_dev,&sfp->attr_v4l_minor_number); - class_device_remove_file(sfp->class_dev,&sfp->attr_unit_number); + if (sfp->v4l_minor_number_created_ok) { + class_device_remove_file(sfp->class_dev, + &sfp->attr_v4l_minor_number); + } + if (sfp->unit_number_created_ok) { + class_device_remove_file(sfp->class_dev, + &sfp->attr_unit_number); + } pvr2_sysfs_trace("Destroying class_dev id=%p",sfp->class_dev); sfp->class_dev->class_data = NULL; class_device_unregister(sfp->class_dev); @@ -756,10 +787,14 @@ static void class_dev_create(struct pvr2_sysfs *sfp, sfp->attr_v4l_minor_number.attr.mode = S_IRUGO; sfp->attr_v4l_minor_number.show = v4l_minor_number_show; sfp->attr_v4l_minor_number.store = NULL; - ret = class_device_create_file(sfp->class_dev,&sfp->attr_v4l_minor_number); - if (ret < 0) + ret = class_device_create_file(sfp->class_dev, + &sfp->attr_v4l_minor_number); + if (ret < 0) { printk(KERN_WARNING "%s: class_device_create_file error: %d\n", __FUNCTION__, ret); + } else { + sfp->v4l_minor_number_created_ok = !0; + } sfp->attr_unit_number.attr.owner = THIS_MODULE; sfp->attr_unit_number.attr.name = "unit_number"; @@ -767,9 +802,12 @@ static void class_dev_create(struct pvr2_sysfs *sfp, sfp->attr_unit_number.show = unit_number_show; sfp->attr_unit_number.store = NULL; ret = class_device_create_file(sfp->class_dev,&sfp->attr_unit_number); - if (ret < 0) + if (ret < 0) { printk(KERN_WARNING "%s: class_device_create_file error: %d\n", __FUNCTION__, ret); + } else { + sfp->unit_number_created_ok = !0; + } pvr2_sysfs_add_controls(sfp); #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC -- cgit v1.1 From 8c313111a2c843610f58d57b4e02159fecef4bbf Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Tue, 25 Jul 2006 20:37:03 -0300 Subject: V4L/DVB (4379): Videodev: Check return value of class_device_register() correctly Errors are return values < 0, not != 0. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videodev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c index 46848e2..0fc90cd 100644 --- a/drivers/media/video/videodev.c +++ b/drivers/media/video/videodev.c @@ -1575,7 +1575,7 @@ int video_register_device(struct video_device *vfd, int type, int nr) vfd->class_dev.devt = MKDEV(VIDEO_MAJOR, vfd->minor); sprintf(vfd->class_dev.class_id, "%s%d", name_base, i - base); ret = class_device_register(&vfd->class_dev); - if (ret) { + if (ret < 0) { printk(KERN_ERR "%s: class_device_register failed\n", __FUNCTION__); goto fail_minor; -- cgit v1.1 From ddecbe112b057c333a8e055fb417451a02b9df78 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Wed, 26 Jul 2006 17:08:29 -0300 Subject: V4L/DVB (4380): Bttv: Revert VBI_OFFSET to previous value, it works better A previous patch changed VBI_OFFSET to match what the datasheets say it should be. However, the bt8x8 datasheets are wrong. The old value of 244 is closer to what is actually observed. The real value appears to not be constant and is different for different chip revisions. Acked-by: Alan Cox Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/bt8xx/bttv-vbi.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/bt8xx/bttv-vbi.c b/drivers/media/video/bt8xx/bttv-vbi.c index 8c9f0f7..63676e7 100644 --- a/drivers/media/video/bt8xx/bttv-vbi.c +++ b/drivers/media/video/bt8xx/bttv-vbi.c @@ -31,11 +31,16 @@ #include #include "bttvp.h" -/* Offset from line sync pulse leading edge (0H) in 1 / sampling_rate: - bt8x8 /HRESET pulse starts at 0H and has length 64 / fCLKx1 (E|O_VTC - HSFMT = 0). VBI_HDELAY (always 0) is an offset from the trailing edge - of /HRESET in 1 / fCLKx1, and the sampling_rate tvnorm->Fsc is fCLKx2. */ -#define VBI_OFFSET ((64 + 0) * 2) +/* Offset from line sync pulse leading edge (0H) to start of VBI capture, + in fCLKx2 pixels. According to the datasheet, VBI capture starts + VBI_HDELAY fCLKx1 pixels from the tailing edgeof /HRESET, and /HRESET + is 64 fCLKx1 pixels wide. VBI_HDELAY is set to 0, so this should be + (64 + 0) * 2 = 128 fCLKx2 pixels. But it's not! The datasheet is + Just Plain Wrong. The real value appears to be different for + different revisions of the bt8x8 chips, and to be affected by the + horizontal scaling factor. Experimentally, the value is measured + to be about 244. */ +#define VBI_OFFSET 244 #define VBI_DEFLINES 16 #define VBI_MAXLINES 32 -- cgit v1.1 From 822cfbff2ef49a08d1b9618d50f81b475d4f936c Mon Sep 17 00:00:00 2001 From: Chandra Seetharaman Date: Sun, 30 Jul 2006 03:03:04 -0700 Subject: [PATCH] Process Events: Fix biarch compatibility issue. use __u64 timestamp Events sent by Process Events Connector from a 64-bit kernel are not binary compatible with a 32-bit userspace program because the "timestamp" field (struct timespec) is not arch independent. This affects the fields that follow "timestamp" as they will be be off by 8 bytes. This is a problem for 32-bit userspace programs running with 64-bit kernels on ppc64, s390, x86-64.. any "biarch" system. Matt had submitted a different solution to lkml as an RFC earlier. We have since switched to a solution recommended by Evgeniy Polyakov. This patch fixes the problem by changing the timestamp to be a __u64, which stores the number of nanoseconds. Tested on a x86_64 system with both 32 bit application and 64 bit application and on a i386 system. Signed-off-by: Chandra Seetharaman Signed-off-by: Matt Helsley Cc: Evgeniy Polyakov Cc: Guillaume Thouvenin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/connector/cn_proc.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/connector/cn_proc.c b/drivers/connector/cn_proc.c index 498aa37..3ece692 100644 --- a/drivers/connector/cn_proc.c +++ b/drivers/connector/cn_proc.c @@ -51,6 +51,7 @@ void proc_fork_connector(struct task_struct *task) struct cn_msg *msg; struct proc_event *ev; __u8 buffer[CN_PROC_MSG_SIZE]; + struct timespec ts; if (atomic_read(&proc_event_num_listeners) < 1) return; @@ -58,7 +59,8 @@ void proc_fork_connector(struct task_struct *task) msg = (struct cn_msg*)buffer; ev = (struct proc_event*)msg->data; get_seq(&msg->seq, &ev->cpu); - ktime_get_ts(&ev->timestamp); /* get high res monotonic timestamp */ + ktime_get_ts(&ts); /* get high res monotonic timestamp */ + ev->timestamp_ns = timespec_to_ns(&ts); ev->what = PROC_EVENT_FORK; ev->event_data.fork.parent_pid = task->real_parent->pid; ev->event_data.fork.parent_tgid = task->real_parent->tgid; @@ -76,6 +78,7 @@ void proc_exec_connector(struct task_struct *task) { struct cn_msg *msg; struct proc_event *ev; + struct timespec ts; __u8 buffer[CN_PROC_MSG_SIZE]; if (atomic_read(&proc_event_num_listeners) < 1) @@ -84,7 +87,8 @@ void proc_exec_connector(struct task_struct *task) msg = (struct cn_msg*)buffer; ev = (struct proc_event*)msg->data; get_seq(&msg->seq, &ev->cpu); - ktime_get_ts(&ev->timestamp); + ktime_get_ts(&ts); /* get high res monotonic timestamp */ + ev->timestamp_ns = timespec_to_ns(&ts); ev->what = PROC_EVENT_EXEC; ev->event_data.exec.process_pid = task->pid; ev->event_data.exec.process_tgid = task->tgid; @@ -100,6 +104,7 @@ void proc_id_connector(struct task_struct *task, int which_id) struct cn_msg *msg; struct proc_event *ev; __u8 buffer[CN_PROC_MSG_SIZE]; + struct timespec ts; if (atomic_read(&proc_event_num_listeners) < 1) return; @@ -118,7 +123,8 @@ void proc_id_connector(struct task_struct *task, int which_id) } else return; get_seq(&msg->seq, &ev->cpu); - ktime_get_ts(&ev->timestamp); + ktime_get_ts(&ts); /* get high res monotonic timestamp */ + ev->timestamp_ns = timespec_to_ns(&ts); memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id)); msg->ack = 0; /* not used */ @@ -131,6 +137,7 @@ void proc_exit_connector(struct task_struct *task) struct cn_msg *msg; struct proc_event *ev; __u8 buffer[CN_PROC_MSG_SIZE]; + struct timespec ts; if (atomic_read(&proc_event_num_listeners) < 1) return; @@ -138,7 +145,8 @@ void proc_exit_connector(struct task_struct *task) msg = (struct cn_msg*)buffer; ev = (struct proc_event*)msg->data; get_seq(&msg->seq, &ev->cpu); - ktime_get_ts(&ev->timestamp); + ktime_get_ts(&ts); /* get high res monotonic timestamp */ + ev->timestamp_ns = timespec_to_ns(&ts); ev->what = PROC_EVENT_EXIT; ev->event_data.exit.process_pid = task->pid; ev->event_data.exit.process_tgid = task->tgid; @@ -164,6 +172,7 @@ static void cn_proc_ack(int err, int rcvd_seq, int rcvd_ack) struct cn_msg *msg; struct proc_event *ev; __u8 buffer[CN_PROC_MSG_SIZE]; + struct timespec ts; if (atomic_read(&proc_event_num_listeners) < 1) return; @@ -171,7 +180,8 @@ static void cn_proc_ack(int err, int rcvd_seq, int rcvd_ack) msg = (struct cn_msg*)buffer; ev = (struct proc_event*)msg->data; msg->seq = rcvd_seq; - ktime_get_ts(&ev->timestamp); + ktime_get_ts(&ts); /* get high res monotonic timestamp */ + ev->timestamp_ns = timespec_to_ns(&ts); ev->cpu = -1; ev->what = PROC_EVENT_NONE; ev->event_data.ack.err = err; -- cgit v1.1 From 5e44ef238b7eb607532e89249e7b2523faf77a92 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sun, 30 Jul 2006 03:03:07 -0700 Subject: [PATCH] drivers/char/pc8736x_gpio.c: unexport a static struct A static struct mustn't be exported. Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/pc8736x_gpio.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/char/pc8736x_gpio.c b/drivers/char/pc8736x_gpio.c index 645eb81..84e5a68 100644 --- a/drivers/char/pc8736x_gpio.c +++ b/drivers/char/pc8736x_gpio.c @@ -221,7 +221,6 @@ static struct nsc_gpio_ops pc8736x_gpio_ops = { .gpio_change = pc8736x_gpio_change, .gpio_current = pc8736x_gpio_current }; -EXPORT_SYMBOL(pc8736x_gpio_ops); static int pc8736x_gpio_open(struct inode *inode, struct file *file) { -- cgit v1.1 From 1e86240f3fd33f8052141778ad3dffe2c96184d7 Mon Sep 17 00:00:00 2001 From: Michal Schmidt Date: Sun, 30 Jul 2006 03:03:29 -0700 Subject: [PATCH] IDE: Touch NMI watchdog during resume from STR When resuming from suspend-to-RAM, the NMI watchdog detects a lockup in ide_wait_not_busy. Here's a screenshot of the trace taken by a digital camera: http://www.uamt.feec.vutbr.cz/rizeni/pom/DSC03510-2.JPG Let's touch the NMI watchdog in ide_wait_not_busy. The system then resumes correctly from STR. [akpm@osdl.org: modular build fix] Signed-off-by: Michal Schmidt Acked-by: Alan Cox Cc: Bartlomiej Zolnierkiewicz Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/ide/ide-iops.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c index 6571652..77703ac 100644 --- a/drivers/ide/ide-iops.c +++ b/drivers/ide/ide-iops.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -1243,6 +1244,7 @@ int ide_wait_not_busy(ide_hwif_t *hwif, unsigned long timeout) if (stat == 0xff) return -ENODEV; touch_softlockup_watchdog(); + touch_nmi_watchdog(); } return -EBUSY; } -- cgit v1.1 From 8e185d83398b2708f50207bc12d0e0a70bd70767 Mon Sep 17 00:00:00 2001 From: Arjan van de Ven Date: Sun, 30 Jul 2006 03:03:30 -0700 Subject: [PATCH] lockdep: annotate pktcdvd natural device hierarchy The pkt_*_dev functions operate on not-this-blockdevice, and that is sufficiently checked at setup time. As a result there is a natural hierarchy, which needs nesting annotations Signed-off-by: Arjan van de Ven Cc: Peter Osterlund Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/block/pktcdvd.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index bde2c64..451b996 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -2577,19 +2577,19 @@ static int pkt_ctl_ioctl(struct inode *inode, struct file *file, unsigned int cm case PKT_CTRL_CMD_SETUP: if (!capable(CAP_SYS_ADMIN)) return -EPERM; - mutex_lock(&ctl_mutex); + mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); ret = pkt_setup_dev(&ctrl_cmd); mutex_unlock(&ctl_mutex); break; case PKT_CTRL_CMD_TEARDOWN: if (!capable(CAP_SYS_ADMIN)) return -EPERM; - mutex_lock(&ctl_mutex); + mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); ret = pkt_remove_dev(&ctrl_cmd); mutex_unlock(&ctl_mutex); break; case PKT_CTRL_CMD_STATUS: - mutex_lock(&ctl_mutex); + mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); pkt_get_status(&ctrl_cmd); mutex_unlock(&ctl_mutex); break; -- cgit v1.1 From e4b57e0842621f597d744b193ea325d62724596b Mon Sep 17 00:00:00 2001 From: Michal Feix Date: Sun, 30 Jul 2006 03:03:31 -0700 Subject: [PATCH] nbd: Check magic before doing anything else We should check magic sequence in reply packet before trying to find request with it's request handle. This also solves the problem with "Unexpected reply" message beeing logged, when packet with invalid magic is received. Signed-off-by: Michal Feix Acked-by: Paul Clements Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/block/nbd.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 0a1b1ea..31a0b60 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -300,6 +300,15 @@ static struct request *nbd_read_stat(struct nbd_device *lo) lo->disk->disk_name, result); goto harderror; } + + if (ntohl(reply.magic) != NBD_REPLY_MAGIC) { + printk(KERN_ERR "%s: Wrong magic (0x%lx)\n", + lo->disk->disk_name, + (unsigned long)ntohl(reply.magic)); + result = -EPROTO; + goto harderror; + } + req = nbd_find_request(lo, reply.handle); if (unlikely(IS_ERR(req))) { result = PTR_ERR(req); @@ -312,13 +321,6 @@ static struct request *nbd_read_stat(struct nbd_device *lo) goto harderror; } - if (ntohl(reply.magic) != NBD_REPLY_MAGIC) { - printk(KERN_ERR "%s: Wrong magic (0x%lx)\n", - lo->disk->disk_name, - (unsigned long)ntohl(reply.magic)); - result = -EPROTO; - goto harderror; - } if (ntohl(reply.error)) { printk(KERN_ERR "%s: Other side returned error (%d)\n", lo->disk->disk_name, ntohl(reply.error)); -- cgit v1.1 From f0df33bcab4b687f0f18b9ebd69d374642e46a0e Mon Sep 17 00:00:00 2001 From: Michal Feix Date: Sun, 30 Jul 2006 03:03:32 -0700 Subject: [PATCH] nbd: Abort request on data reception failure When reading from nbd device, we need to receive all the data after receiving reply packet from the server - otherwise such request will never be ended. If socket is closed right after accepting reply control packet and in the middle of waiting for read data, nbd_read_stat() returns NULL and nbd_end_request() is not called. This patch fixes it. Signed-off-by: Michal Feix Acked-by: Paul Clements Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/block/nbd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 31a0b60..bdbade9 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -341,7 +341,8 @@ static struct request *nbd_read_stat(struct nbd_device *lo) printk(KERN_ERR "%s: Receive data failed (result %d)\n", lo->disk->disk_name, result); - goto harderror; + req->errors++; + return req; } dprintk(DBG_RX, "%s: request %p: got %d bytes data\n", lo->disk->disk_name, req, bvec->bv_len); -- cgit v1.1 From be6b5a3505fa0cd54c3b5959a39293f47c648980 Mon Sep 17 00:00:00 2001 From: Chandra Seetharaman Date: Sun, 30 Jul 2006 03:03:37 -0700 Subject: [PATCH] cpu hotplug: use hotplug version of registration in late inits Use hotplug version of register_cpu_notifier in late init functions. Signed-off-by: Chandra Seetharaman Cc: "Luck, Tony" Cc: Martin Schwidefsky Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/base/topology.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/base/topology.c b/drivers/base/topology.c index c2d6216..3ef9d51 100644 --- a/drivers/base/topology.c +++ b/drivers/base/topology.c @@ -139,7 +139,7 @@ static int __cpuinit topology_sysfs_init(void) (void *)(long)i); } - register_cpu_notifier(&topology_cpu_notifier); + register_hotcpu_notifier(&topology_cpu_notifier); return 0; } -- cgit v1.1 From d75763d24063cafe28ace8863560da9c968ee099 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 30 Jul 2006 03:03:41 -0700 Subject: [PATCH] pci/search: cleanups, add to kernel-api.tmpl Clean up kernel-doc comments in drivers/pci/search.c (line sizes and typos). Enable that source file in DocBook/kernel-api.tmpl. Signed-off-by: Randy Dunlap Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pci/search.c | 46 +++++++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/search.c b/drivers/pci/search.c index 622b3f8..f8ae2b7 100644 --- a/drivers/pci/search.c +++ b/drivers/pci/search.c @@ -61,7 +61,7 @@ struct pci_bus * __devinit pci_find_bus(int domain, int busnr) * @from: Previous PCI bus found, or %NULL for new search. * * Iterates through the list of known PCI busses. A new search is - * initiated by passing %NULL to the @from argument. Otherwise if + * initiated by passing %NULL as the @from argument. Otherwise if * @from is not %NULL, searches continue from next device on the * global list. */ @@ -148,13 +148,14 @@ struct pci_dev * pci_get_slot(struct pci_bus *bus, unsigned int devfn) * @from: Previous PCI device found in search, or %NULL for new search. * * Iterates through the list of known PCI devices. If a PCI device is - * found with a matching @vendor, @device, @ss_vendor and @ss_device, a pointer to its - * device structure is returned. Otherwise, %NULL is returned. - * A new search is initiated by passing %NULL to the @from argument. - * Otherwise if @from is not %NULL, searches continue from next device on the global list. + * found with a matching @vendor, @device, @ss_vendor and @ss_device, a + * pointer to its device structure is returned. Otherwise, %NULL is returned. + * A new search is initiated by passing %NULL as the @from argument. + * Otherwise if @from is not %NULL, searches continue from next device + * on the global list. * - * NOTE: Do not use this function anymore, use pci_get_subsys() instead, as - * the pci device returned by this function can disappear at any moment in + * NOTE: Do not use this function any more; use pci_get_subsys() instead, as + * the PCI device returned by this function can disappear at any moment in * time. */ static struct pci_dev * pci_find_subsys(unsigned int vendor, @@ -191,14 +192,15 @@ exit: * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids * @from: Previous PCI device found in search, or %NULL for new search. * - * Iterates through the list of known PCI devices. If a PCI device is - * found with a matching @vendor and @device, a pointer to its device structure is + * Iterates through the list of known PCI devices. If a PCI device is found + * with a matching @vendor and @device, a pointer to its device structure is * returned. Otherwise, %NULL is returned. - * A new search is initiated by passing %NULL to the @from argument. - * Otherwise if @from is not %NULL, searches continue from next device on the global list. + * A new search is initiated by passing %NULL as the @from argument. + * Otherwise if @from is not %NULL, searches continue from next device + * on the global list. * - * NOTE: Do not use this function anymore, use pci_get_device() instead, as - * the pci device returned by this function can disappear at any moment in + * NOTE: Do not use this function any more; use pci_get_device() instead, as + * the PCI device returned by this function can disappear at any moment in * time. */ struct pci_dev * @@ -215,11 +217,11 @@ pci_find_device(unsigned int vendor, unsigned int device, const struct pci_dev * * @ss_device: PCI subsystem device id to match, or %PCI_ANY_ID to match all device ids * @from: Previous PCI device found in search, or %NULL for new search. * - * Iterates through the list of known PCI devices. If a PCI device is - * found with a matching @vendor, @device, @ss_vendor and @ss_device, a pointer to its + * Iterates through the list of known PCI devices. If a PCI device is found + * with a matching @vendor, @device, @ss_vendor and @ss_device, a pointer to its * device structure is returned, and the reference count to the device is * incremented. Otherwise, %NULL is returned. A new search is initiated by - * passing %NULL to the @from argument. Otherwise if @from is not %NULL, + * passing %NULL as the @from argument. Otherwise if @from is not %NULL, * searches continue from next device on the global list. * The reference count for @from is always decremented if it is not %NULL. */ @@ -262,7 +264,7 @@ exit: * found with a matching @vendor and @device, the reference count to the * device is incremented and a pointer to its device structure is returned. * Otherwise, %NULL is returned. A new search is initiated by passing %NULL - * to the @from argument. Otherwise if @from is not %NULL, searches continue + * as the @from argument. Otherwise if @from is not %NULL, searches continue * from next device on the global list. The reference count for @from is * always decremented if it is not %NULL. */ @@ -279,11 +281,13 @@ pci_get_device(unsigned int vendor, unsigned int device, struct pci_dev *from) * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids * @from: Previous PCI device found in search, or %NULL for new search. * - * Iterates through the list of known PCI devices in the reverse order of pci_find_device(). + * Iterates through the list of known PCI devices in the reverse order of + * pci_find_device(). * If a PCI device is found with a matching @vendor and @device, a pointer to * its device structure is returned. Otherwise, %NULL is returned. - * A new search is initiated by passing %NULL to the @from argument. - * Otherwise if @from is not %NULL, searches continue from previous device on the global list. + * A new search is initiated by passing %NULL as the @from argument. + * Otherwise if @from is not %NULL, searches continue from previous device + * on the global list. */ struct pci_dev * pci_find_device_reverse(unsigned int vendor, unsigned int device, const struct pci_dev *from) @@ -317,7 +321,7 @@ exit: * found with a matching @class, the reference count to the device is * incremented and a pointer to its device structure is returned. * Otherwise, %NULL is returned. - * A new search is initiated by passing %NULL to the @from argument. + * A new search is initiated by passing %NULL as the @from argument. * Otherwise if @from is not %NULL, searches continue from next device * on the global list. The reference count for @from is always decremented * if it is not %NULL. -- cgit v1.1 From 9578bcf4ecaf447cb4bb0891309fad73ff5c00e3 Mon Sep 17 00:00:00 2001 From: Brent Casavant Date: Sun, 30 Jul 2006 03:03:46 -0700 Subject: [PATCH] sgiioc4: Always share IRQ The SGI IOC4 IDE device always shares an interrupt with other devices which are part of IOC4. As such, IDEPCI_SHARE_IRQ should always be enabled when BLK_DEV_SGIIOC4 is enabled. Signed-off-by: Brent Casavant Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/ide/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig index d1266fe2..556958e 100644 --- a/drivers/ide/Kconfig +++ b/drivers/ide/Kconfig @@ -682,6 +682,7 @@ config BLK_DEV_SVWKS config BLK_DEV_SGIIOC4 tristate "Silicon Graphics IOC4 chipset ATA/ATAPI support" depends on (IA64_SGI_SN2 || IA64_GENERIC) && SGI_IOC4 + select IDEPCI_SHARE_IRQ help This driver adds PIO & MultiMode DMA-2 support for the SGI IOC4 chipset, which has one channel and can support two devices. -- cgit v1.1 From 7ca7b5c42e783b74a57387418bfcfea072fc46d6 Mon Sep 17 00:00:00 2001 From: Frederik Deweerdt Date: Sun, 30 Jul 2006 03:03:46 -0700 Subject: [PATCH] mdacon: fix __init section warnings WARNING: drivers/video/console/mdacon.o - Section mismatch: reference to .init.text: from .text between 'mdacon_startup' (at offset 0x123) and 'mdacon_init' WARNING: drivers/video/console/mdacon.o - Section mismatch: reference to .init.text: from .text between 'mdacon_startup' (at offset 0x18b) and 'mdacon_init' Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/console/mdacon.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/video/console/mdacon.c b/drivers/video/console/mdacon.c index 52ed12b..eb4d03f 100644 --- a/drivers/video/console/mdacon.c +++ b/drivers/video/console/mdacon.c @@ -197,7 +197,7 @@ static int __init mdacon_setup(char *str) __setup("mdacon=", mdacon_setup); #endif -static int __init mda_detect(void) +static int mda_detect(void) { int count=0; u16 *p, p_save; @@ -282,7 +282,7 @@ static int __init mda_detect(void) return 1; } -static void __init mda_initialize(void) +static void mda_initialize(void) { write_mda_b(97, 0x00); /* horizontal total */ write_mda_b(80, 0x01); /* horizontal displayed */ -- cgit v1.1 From f47ad214926b1dbcc591fd71562e36f1529936b5 Mon Sep 17 00:00:00 2001 From: Daniel Ritz Date: Sun, 30 Jul 2006 03:03:47 -0700 Subject: [PATCH] pcmcia: fix ioctl for GET_STATUS and GET_CONFIGURATION_INFO the p_dev == NULL checks are wrong. the called functions handle a NULL p_dev on their own. w/o this patch output of cardcctl status and cardctl config is broken for cardbus cards or when the slot is empty. Signed-off-by: Daniel Ritz Cc: Dominik Brodowski Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pcmcia/pcmcia_ioctl.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/pcmcia/pcmcia_ioctl.c b/drivers/pcmcia/pcmcia_ioctl.c index 738b1ef..9ad18e6 100644 --- a/drivers/pcmcia/pcmcia_ioctl.c +++ b/drivers/pcmcia/pcmcia_ioctl.c @@ -601,12 +601,8 @@ static int ds_ioctl(struct inode * inode, struct file * file, ret = CS_BAD_ARGS; else { struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->config.Function); - if (p_dev == NULL) - ret = CS_BAD_ARGS; - else { - ret = pccard_get_configuration_info(s, p_dev, &buf->config); - pcmcia_put_dev(p_dev); - } + ret = pccard_get_configuration_info(s, p_dev, &buf->config); + pcmcia_put_dev(p_dev); } break; case DS_GET_FIRST_TUPLE: @@ -636,12 +632,8 @@ static int ds_ioctl(struct inode * inode, struct file * file, ret = CS_BAD_ARGS; else { struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->status.Function); - if (p_dev == NULL) - ret = CS_BAD_ARGS; - else { - ret = pccard_get_status(s, p_dev, &buf->status); - pcmcia_put_dev(p_dev); - } + ret = pccard_get_status(s, p_dev, &buf->status); + pcmcia_put_dev(p_dev); } break; case DS_VALIDATE_CIS: -- cgit v1.1 From 47a31976cadb9a2d25a2896762cb0e678470a29b Mon Sep 17 00:00:00 2001 From: Daniel Ritz Date: Sun, 30 Jul 2006 03:03:49 -0700 Subject: [PATCH] pcmcia: fix ioctl GET_CONFIGURATION_INFO for pcmcia_cards Values displayed when by cardctl config are horribly wrong for 16bit cards. this fixes it up by not using memcpy() since source and target struct are very different. Signed-off-by: Daniel Ritz Cc: Dominik Brodowski Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pcmcia/pcmcia_resource.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c index 7bf25b8..c832339 100644 --- a/drivers/pcmcia/pcmcia_resource.c +++ b/drivers/pcmcia/pcmcia_resource.c @@ -245,10 +245,17 @@ int pccard_get_configuration_info(struct pcmcia_socket *s, return CS_SUCCESS; } - /* !!! This is a hack !!! */ - memcpy(&config->Attributes, &c->Attributes, sizeof(config_t)); - config->Attributes |= CONF_VALID_CLIENT; - config->CardValues = c->CardValues; + config->Attributes = c->Attributes | CONF_VALID_CLIENT; + config->Vcc = s->socket.Vcc; + config->Vpp1 = config->Vpp2 = s->socket.Vpp; + config->IntType = c->IntType; + config->ConfigBase = c->ConfigBase; + config->Status = c->Status; + config->Pin = c->Pin; + config->Copy = c->Copy; + config->Option = c->Option; + config->ExtStatus = c->ExtStatus; + config->Present = config->CardValues = c->CardValues; config->IRQAttributes = c->irq.Attributes; config->AssignedIRQ = s->irq.AssignedIRQ; config->BasePort1 = c->io.BasePort1; -- cgit v1.1 From a04b61d3dc68857dcc81a5761268c96056742fb2 Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Sun, 30 Jul 2006 03:03:52 -0700 Subject: [PATCH] hide onboard graphics drivers on G5 Hide the video drivers for onboard graphics found in early PCI PowerMacs in Apple G5 config files. drivers/built-in.o: In function `.platinumfb_probe': platinumfb.c:(.text+0x377a0): undefined reference to `.nvram_read_byte' platinumfb.c:(.text+0x37830): undefined reference to `.nvram_read_byte' drivers/built-in.o: In function `.control_init': controlfb.c:(.init.text+0x1938): undefined reference to `.nvram_read_byte' controlfb.c:(.init.text+0x1968): undefined reference to `.nvram_read_byte' drivers/built-in.o: In function `.valkyriefb_init': (.init.text+0x2300): undefined reference to `.nvram_read_byte' drivers/built-in.o:(.init.text+0x239c): more undefined references to `.nvram_read_byte' follow Signed-off-by: Olaf Hering Cc: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/Kconfig | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 6533b0f..82288a7 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -420,7 +420,7 @@ config FB_OF config FB_CONTROL bool "Apple \"control\" display support" - depends on (FB = y) && PPC_PMAC + depends on (FB = y) && PPC_PMAC && PPC32 select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT @@ -431,7 +431,7 @@ config FB_CONTROL config FB_PLATINUM bool "Apple \"platinum\" display support" - depends on (FB = y) && PPC_PMAC + depends on (FB = y) && PPC_PMAC && PPC32 select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT @@ -442,7 +442,7 @@ config FB_PLATINUM config FB_VALKYRIE bool "Apple \"valkyrie\" display support" - depends on (FB = y) && (MAC || PPC_PMAC) + depends on (FB = y) && (MAC || (PPC_PMAC && PPC32)) select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT @@ -453,7 +453,7 @@ config FB_VALKYRIE config FB_CT65550 bool "Chips 65550 display support" - depends on (FB = y) && PPC + depends on (FB = y) && PPC32 select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT -- cgit v1.1 From 3ae192080cb4d007792d13522efa98ebe7f15475 Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Sun, 30 Jul 2006 03:03:55 -0700 Subject: [PATCH] Fix swsusp with PNP BIOS swsusp is unable to suspend my machine (DTK FortisPro TOP-5A notebook) with kernel 2.6.17.5 because it's unable to suspend PNP device 00:16 (mouse). The problem is in PNP BIOS. pnp_bus_suspend() calls pnp_stop_dev() for the device if the device can be disabled according to pnp_can_disable(). The problem is that pnpbios_disable_resources() returns -EPERM if the device is not dynamic (!pnpbios_is_dynamic()) but insert_device() happily sets PNP_DISABLE capability/flag even if the device is not dynamic. So we try to disable non-dynamic devices which will fail. This patch prevents insert_device() from setting PNP_DISABLE if the device is not dynamic and fixes suspend on my system. Signed-off-by: Ondrej Zary Cc: Pavel Machek Cc: "Rafael J. Wysocki" Cc: Bjorn Helgaas Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pnp/pnpbios/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c index b154b3f..551f58e 100644 --- a/drivers/pnp/pnpbios/core.c +++ b/drivers/pnp/pnpbios/core.c @@ -346,7 +346,7 @@ static int insert_device(struct pnp_dev *dev, struct pnp_bios_node * node) dev->flags = node->flags; if (!(dev->flags & PNPBIOS_NO_CONFIG)) dev->capabilities |= PNP_CONFIGURABLE; - if (!(dev->flags & PNPBIOS_NO_DISABLE)) + if (!(dev->flags & PNPBIOS_NO_DISABLE) && pnpbios_is_dynamic(dev)) dev->capabilities |= PNP_DISABLE; dev->capabilities |= PNP_READ; if (pnpbios_is_dynamic(dev)) -- cgit v1.1 From 58690664456b597796e58958861f365e096a1609 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sun, 30 Jul 2006 03:04:04 -0700 Subject: [PATCH] hwrng: fix intel probe error unwind The intel hwrng leaks an iomapped resource, if hwrng_register() failes. This fixes it. Signed-off-by: Michael Buesch Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/hw_random/intel-rng.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/char/hw_random/intel-rng.c b/drivers/char/hw_random/intel-rng.c index 6594bd5..ccd7e71 100644 --- a/drivers/char/hw_random/intel-rng.c +++ b/drivers/char/hw_random/intel-rng.c @@ -164,7 +164,7 @@ static int __init mod_init(void) if (err) { printk(KERN_ERR PFX "RNG registering failed (%d)\n", err); - goto out; + goto err_unmap; } out: return err; -- cgit v1.1 From 072d3d1acb452f4abd8d3d20af661f2e28854b59 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sun, 30 Jul 2006 03:04:05 -0700 Subject: [PATCH] hwrng: fix geode probe error unwind The geode hwrng leaks an iomapped resource, if hwrng_register() fails. This fixes it. Signed-off-by: Michael Buesch Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/hw_random/geode-rng.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/char/hw_random/geode-rng.c b/drivers/char/hw_random/geode-rng.c index be61f22..d37ced0 100644 --- a/drivers/char/hw_random/geode-rng.c +++ b/drivers/char/hw_random/geode-rng.c @@ -107,10 +107,14 @@ found: if (err) { printk(KERN_ERR PFX "RNG registering failed (%d)\n", err); - goto out; + goto err_unmap; } out: return err; + +err_unmap: + iounmap(mem); + goto out; } static void __exit mod_exit(void) -- cgit v1.1 From 256154fbc31c25a8df4d398232acfa9d4892224c Mon Sep 17 00:00:00 2001 From: "Antonino A. Daplas" Date: Sun, 30 Jul 2006 03:04:17 -0700 Subject: [PATCH] fbdev: statically link the framebuffer notification functions The backlight and lcd subsystems can be notified by the framebuffer layer of blanking events. However, these subsystems, as a whole, can function independently from the framebuffer layer. But in order to enable to the lcd and backlight subsystems, the framebuffer has to be compiled also, effectively sucking in a huge amount of unneeded code. To prevent dependency problems, separate out the framebuffer notification mechanism from the framebuffer layer and permanently link it to the kernel. Signed-off-by: Antonino Daplas Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/Kconfig | 2 +- drivers/video/Makefile | 1 + drivers/video/backlight/Kconfig | 4 +-- drivers/video/fb_notify.c | 46 +++++++++++++++++++++++++++++++++++ drivers/video/fbmem.c | 54 +++++++++-------------------------------- 5 files changed, 61 insertions(+), 46 deletions(-) create mode 100644 drivers/video/fb_notify.c (limited to 'drivers') diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 82288a7..728cb56 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -1620,7 +1620,7 @@ if FB || SGI_NEWPORT_CONSOLE source "drivers/video/logo/Kconfig" endif -if FB && SYSFS +if SYSFS source "drivers/video/backlight/Kconfig" endif diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 95563c9..481c6c9 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -4,6 +4,7 @@ # Each configuration option enables a list of files. +obj-y += fb_notify.o obj-$(CONFIG_FB) += fb.o fb-y := fbmem.o fbmon.o fbcmap.o fbsysfs.o \ modedb.o fbcvt.o diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index 022f9d3..02f1529 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -10,7 +10,7 @@ menuconfig BACKLIGHT_LCD_SUPPORT config BACKLIGHT_CLASS_DEVICE tristate "Lowlevel Backlight controls" - depends on BACKLIGHT_LCD_SUPPORT && FB + depends on BACKLIGHT_LCD_SUPPORT default m help This framework adds support for low-level control of the LCD @@ -26,7 +26,7 @@ config BACKLIGHT_DEVICE config LCD_CLASS_DEVICE tristate "Lowlevel LCD controls" - depends on BACKLIGHT_LCD_SUPPORT && FB + depends on BACKLIGHT_LCD_SUPPORT default m help This framework adds support for low-level control of LCD. diff --git a/drivers/video/fb_notify.c b/drivers/video/fb_notify.c new file mode 100644 index 0000000..8c02038 --- /dev/null +++ b/drivers/video/fb_notify.c @@ -0,0 +1,46 @@ +/* + * linux/drivers/video/fb_notify.c + * + * Copyright (C) 2006 Antonino Daplas + * + * 2001 - Documented with DocBook + * - Brad Douglas + * + * 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. + */ +#include +#include + +static BLOCKING_NOTIFIER_HEAD(fb_notifier_list); + +/** + * fb_register_client - register a client notifier + * @nb: notifier block to callback on events + */ +int fb_register_client(struct notifier_block *nb) +{ + return blocking_notifier_chain_register(&fb_notifier_list, nb); +} +EXPORT_SYMBOL(fb_register_client); + +/** + * fb_unregister_client - unregister a client notifier + * @nb: notifier block to callback on events + */ +int fb_unregister_client(struct notifier_block *nb) +{ + return blocking_notifier_chain_unregister(&fb_notifier_list, nb); +} +EXPORT_SYMBOL(fb_unregister_client); + +/** + * fb_notifier_call_chain - notify clients of fb_events + * + */ +int fb_notifier_call_chain(unsigned long val, void *v) +{ + return blocking_notifier_call_chain(&fb_notifier_list, val, v); +} +EXPORT_SYMBOL_GPL(fb_notifier_call_chain); diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 4fc9df4..17961e3 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -52,7 +52,6 @@ #define FBPIXMAPSIZE (1024 * 8) -static BLOCKING_NOTIFIER_HEAD(fb_notifier_list); struct fb_info *registered_fb[FB_MAX]; int num_registered_fb; @@ -791,8 +790,7 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var) event.info = info; event.data = &mode1; - ret = blocking_notifier_call_chain(&fb_notifier_list, - FB_EVENT_MODE_DELETE, &event); + ret = fb_notifier_call_chain(FB_EVENT_MODE_DELETE, &event); } if (!ret) @@ -837,8 +835,7 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var) info->flags &= ~FBINFO_MISC_USEREVENT; event.info = info; - blocking_notifier_call_chain(&fb_notifier_list, - evnt, &event); + fb_notifier_call_chain(evnt, &event); } } } @@ -861,8 +858,7 @@ fb_blank(struct fb_info *info, int blank) event.info = info; event.data = ␣ - blocking_notifier_call_chain(&fb_notifier_list, - FB_EVENT_BLANK, &event); + fb_notifier_call_chain(FB_EVENT_BLANK, &event); } return ret; @@ -933,8 +929,7 @@ fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, con2fb.framebuffer = -1; event.info = info; event.data = &con2fb; - blocking_notifier_call_chain(&fb_notifier_list, - FB_EVENT_GET_CONSOLE_MAP, &event); + fb_notifier_call_chain(FB_EVENT_GET_CONSOLE_MAP, &event); return copy_to_user(argp, &con2fb, sizeof(con2fb)) ? -EFAULT : 0; case FBIOPUT_CON2FBMAP: @@ -952,9 +947,8 @@ fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, return -EINVAL; event.info = info; event.data = &con2fb; - return blocking_notifier_call_chain(&fb_notifier_list, - FB_EVENT_SET_CONSOLE_MAP, - &event); + return fb_notifier_call_chain(FB_EVENT_SET_CONSOLE_MAP, + &event); case FBIOBLANK: acquire_console_sem(); info->flags |= FBINFO_MISC_USEREVENT; @@ -1330,8 +1324,7 @@ register_framebuffer(struct fb_info *fb_info) registered_fb[i] = fb_info; event.info = fb_info; - blocking_notifier_call_chain(&fb_notifier_list, - FB_EVENT_FB_REGISTERED, &event); + fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event); return 0; } @@ -1365,30 +1358,11 @@ unregister_framebuffer(struct fb_info *fb_info) fb_cleanup_class_device(fb_info); class_device_destroy(fb_class, MKDEV(FB_MAJOR, i)); event.info = fb_info; - blocking_notifier_call_chain(&fb_notifier_list, - FB_EVENT_FB_UNREGISTERED, &event); + fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event); return 0; } /** - * fb_register_client - register a client notifier - * @nb: notifier block to callback on events - */ -int fb_register_client(struct notifier_block *nb) -{ - return blocking_notifier_chain_register(&fb_notifier_list, nb); -} - -/** - * fb_unregister_client - unregister a client notifier - * @nb: notifier block to callback on events - */ -int fb_unregister_client(struct notifier_block *nb) -{ - return blocking_notifier_chain_unregister(&fb_notifier_list, nb); -} - -/** * fb_set_suspend - low level driver signals suspend * @info: framebuffer affected * @state: 0 = resuming, !=0 = suspending @@ -1403,13 +1377,11 @@ void fb_set_suspend(struct fb_info *info, int state) event.info = info; if (state) { - blocking_notifier_call_chain(&fb_notifier_list, - FB_EVENT_SUSPEND, &event); + fb_notifier_call_chain(FB_EVENT_SUSPEND, &event); info->state = FBINFO_STATE_SUSPENDED; } else { info->state = FBINFO_STATE_RUNNING; - blocking_notifier_call_chain(&fb_notifier_list, - FB_EVENT_RESUME, &event); + fb_notifier_call_chain(FB_EVENT_RESUME, &event); } } @@ -1480,9 +1452,7 @@ int fb_new_modelist(struct fb_info *info) if (!list_empty(&info->modelist)) { event.info = info; - err = blocking_notifier_call_chain(&fb_notifier_list, - FB_EVENT_NEW_MODELIST, - &event); + err = fb_notifier_call_chain(FB_EVENT_NEW_MODELIST, &event); } return err; @@ -1594,8 +1564,6 @@ EXPORT_SYMBOL(fb_blank); EXPORT_SYMBOL(fb_pan_display); EXPORT_SYMBOL(fb_get_buffer_offset); EXPORT_SYMBOL(fb_set_suspend); -EXPORT_SYMBOL(fb_register_client); -EXPORT_SYMBOL(fb_unregister_client); EXPORT_SYMBOL(fb_get_options); MODULE_LICENSE("GPL"); -- cgit v1.1 From 994aad251acab32a5d40d4a9501dc3e736562b6d Mon Sep 17 00:00:00 2001 From: Volker Braun Date: Sun, 30 Jul 2006 03:04:18 -0700 Subject: [PATCH] radeonfb sleep fixes Many IBM Thinkpad T4* models and some R* and X* with radeon video cards draw too much power when suspended to RAM, reducing drastically the battery lifetime. The solution is to enable suspend-to-D2 on these machines. They are whitelisted through their subsystem vendor/device ID. This fixes http://bugzilla.kernel.org/show_bug.cgi?id=3022 The patch introduces a framework to alter the pm_mode and reinit_func fields of the radeonfb_info structure based on a whitelist. This should facilitate future hardware-dependent workarounds. The workaround for the Samsung P35 that is already in the radeonfb code has been rewritten using this framework. The behavior can be overridden with module options: i) video=radeonfb:force_sleep=1 enable suspend-to-D2 also on non-whitelisted machines (useful for testing new notebook models), ii) video=radeonfb:ignore_devlist=1 Disable checking the whitelist and do not apply any workarounds. Cc: Benjamin Herrenschmidt Cc: "Antonino A. Daplas" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/aty/radeon_base.c | 18 ++++- drivers/video/aty/radeon_pm.c | 146 ++++++++++++++++++++++++++++++++++------ drivers/video/aty/radeonfb.h | 6 +- 3 files changed, 145 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c index 8d85fc5..8e3400d 100644 --- a/drivers/video/aty/radeon_base.c +++ b/drivers/video/aty/radeon_base.c @@ -266,6 +266,8 @@ static int force_measure_pll = 0; #ifdef CONFIG_MTRR static int nomtrr = 0; #endif +static int force_sleep; +static int ignore_devlist; /* * prototypes @@ -2327,9 +2329,9 @@ static int __devinit radeonfb_pci_register (struct pci_dev *pdev, /* -2 is special: means ON on mobility chips and do not * change on others */ - radeonfb_pm_init(rinfo, rinfo->is_mobility ? 1 : -1); + radeonfb_pm_init(rinfo, rinfo->is_mobility ? 1 : -1, ignore_devlist, force_sleep); } else - radeonfb_pm_init(rinfo, default_dynclk); + radeonfb_pm_init(rinfo, default_dynclk, ignore_devlist, force_sleep); pci_set_drvdata(pdev, info); @@ -2477,6 +2479,12 @@ static int __init radeonfb_setup (char *options) force_measure_pll = 1; } else if (!strncmp(this_opt, "ignore_edid", 11)) { ignore_edid = 1; +#if defined(CONFIG_PM) && defined(CONFIG_X86) + } else if (!strncmp(this_opt, "force_sleep", 11)) { + force_sleep = 1; + } else if (!strncmp(this_opt, "ignore_devlist", 14)) { + ignore_devlist = 1; +#endif } else mode_option = this_opt; } @@ -2532,3 +2540,9 @@ module_param(panel_yres, int, 0); MODULE_PARM_DESC(panel_yres, "int: set panel yres"); module_param(mode_option, charp, 0); MODULE_PARM_DESC(mode_option, "Specify resolution as \"x[-][@]\" "); +#if defined(CONFIG_PM) && defined(CONFIG_X86) +module_param(force_sleep, bool, 0); +MODULE_PARM_DESC(force_sleep, "bool: force D2 sleep mode on all hardware"); +module_param(ignore_devlist, bool, 0); +MODULE_PARM_DESC(ignore_devlist, "bool: ignore workarounds for bugs in specific laptops"); +#endif diff --git a/drivers/video/aty/radeon_pm.c b/drivers/video/aty/radeon_pm.c index c709176..f31e606 100644 --- a/drivers/video/aty/radeon_pm.c +++ b/drivers/video/aty/radeon_pm.c @@ -27,6 +27,99 @@ #include "ati_ids.h" +static void radeon_reinitialize_M10(struct radeonfb_info *rinfo); + +/* + * Workarounds for bugs in PC laptops: + * - enable D2 sleep in some IBM Thinkpads + * - special case for Samsung P35 + * + * Whitelist by subsystem vendor/device because + * its the subsystem vendor's fault! + */ + +#if defined(CONFIG_PM) && defined(CONFIG_X86) +struct radeon_device_id { + const char *ident; /* (arbitrary) Name */ + const unsigned short subsystem_vendor; /* Subsystem Vendor ID */ + const unsigned short subsystem_device; /* Subsystem Device ID */ + const enum radeon_pm_mode pm_mode_modifier; /* modify pm_mode */ + const reinit_function_ptr new_reinit_func; /* changed reinit_func */ +}; + +#define BUGFIX(model, sv, sd, pm, fn) { \ + .ident = model, \ + .subsystem_vendor = sv, \ + .subsystem_device = sd, \ + .pm_mode_modifier = pm, \ + .new_reinit_func = fn \ +} + +static struct radeon_device_id radeon_workaround_list[] = { + BUGFIX("IBM Thinkpad R32", + PCI_VENDOR_ID_IBM, 0x1905, + radeon_pm_d2, NULL), + BUGFIX("IBM Thinkpad R40", + PCI_VENDOR_ID_IBM, 0x0526, + radeon_pm_d2, NULL), + BUGFIX("IBM Thinkpad R40", + PCI_VENDOR_ID_IBM, 0x0527, + radeon_pm_d2, NULL), + BUGFIX("IBM Thinkpad R50/R51/T40/T41", + PCI_VENDOR_ID_IBM, 0x0531, + radeon_pm_d2, NULL), + BUGFIX("IBM Thinkpad R51/T40/T41/T42", + PCI_VENDOR_ID_IBM, 0x0530, + radeon_pm_d2, NULL), + BUGFIX("IBM Thinkpad T30", + PCI_VENDOR_ID_IBM, 0x0517, + radeon_pm_d2, NULL), + BUGFIX("IBM Thinkpad T40p", + PCI_VENDOR_ID_IBM, 0x054d, + radeon_pm_d2, NULL), + BUGFIX("IBM Thinkpad T42", + PCI_VENDOR_ID_IBM, 0x0550, + radeon_pm_d2, NULL), + BUGFIX("IBM Thinkpad X31/X32", + PCI_VENDOR_ID_IBM, 0x052f, + radeon_pm_d2, NULL), + BUGFIX("Samsung P35", + PCI_VENDOR_ID_SAMSUNG, 0xc00c, + radeon_pm_off, radeon_reinitialize_M10), + { .ident = NULL } +}; + +static int radeon_apply_workarounds(struct radeonfb_info *rinfo) +{ + struct radeon_device_id *id; + + for (id = radeon_workaround_list; id->ident != NULL; id++ ) + if ((id->subsystem_vendor == rinfo->pdev->subsystem_vendor ) && + (id->subsystem_device == rinfo->pdev->subsystem_device )) { + + /* we found a device that requires workaround */ + printk(KERN_DEBUG "radeonfb: %s detected" + ", enabling workaround\n", id->ident); + + rinfo->pm_mode |= id->pm_mode_modifier; + + if (id->new_reinit_func != NULL) + rinfo->reinit_func = id->new_reinit_func; + + return 1; + } + return 0; /* not found */ +} + +#else /* defined(CONFIG_PM) && defined(CONFIG_X86) */ +static inline int radeon_apply_workarounds(struct radeonfb_info *rinfo) +{ + return 0; +} +#endif /* defined(CONFIG_PM) && defined(CONFIG_X86) */ + + + static void radeon_pm_disable_dynamic_mode(struct radeonfb_info *rinfo) { u32 tmp; @@ -852,18 +945,26 @@ static void radeon_pm_setup_for_suspend(struct radeonfb_info *rinfo) /* because both INPLL and OUTPLL take the same lock, that's why. */ tmp = INPLL( pllMCLK_MISC) | MCLK_MISC__EN_MCLK_TRISTATE_IN_SUSPEND; OUTPLL( pllMCLK_MISC, tmp); - - /* AGP PLL control */ - if (rinfo->family <= CHIP_FAMILY_RV280) { - OUTREG(BUS_CNTL1, INREG(BUS_CNTL1) | BUS_CNTL1__AGPCLK_VALID); - OUTREG(BUS_CNTL1, - (INREG(BUS_CNTL1) & ~BUS_CNTL1__MOBILE_PLATFORM_SEL_MASK) - | (2<family <= CHIP_FAMILY_RV280) { + OUTREG(BUS_CNTL1, INREG(BUS_CNTL1) | BUS_CNTL1__AGPCLK_VALID); + OUTREG(BUS_CNTL1, + (INREG(BUS_CNTL1) & ~BUS_CNTL1__MOBILE_PLATFORM_SEL_MASK) + | (2<pm_reg = pci_find_capability(rinfo->pdev, PCI_CAP_ID_PM); @@ -2729,22 +2830,13 @@ void radeonfb_pm_init(struct radeonfb_info *rinfo, int dynclk) } #if defined(CONFIG_PM) +#if defined(CONFIG_PPC_PMAC) /* Check if we can power manage on suspend/resume. We can do * D2 on M6, M7 and M9, and we can resume from D3 cold a few other * "Mac" cards, but that's all. We need more infos about what the * BIOS does tho. Right now, all this PM stuff is pmac-only for that * reason. --BenH */ - /* Special case for Samsung P35 laptops - */ - if ((rinfo->pdev->vendor == PCI_VENDOR_ID_ATI) && - (rinfo->pdev->device == PCI_CHIP_RV350_NP) && - (rinfo->pdev->subsystem_vendor == PCI_VENDOR_ID_SAMSUNG) && - (rinfo->pdev->subsystem_device == 0xc00c)) { - rinfo->reinit_func = radeon_reinitialize_M10; - rinfo->pm_mode |= radeon_pm_off; - } -#if defined(CONFIG_PPC_PMAC) if (machine_is(powermac) && rinfo->of_node) { if (rinfo->is_mobility && rinfo->pm_reg && rinfo->family <= CHIP_FAMILY_RV250) @@ -2790,6 +2882,18 @@ void radeonfb_pm_init(struct radeonfb_info *rinfo, int dynclk) } #endif /* defined(CONFIG_PPC_PMAC) */ #endif /* defined(CONFIG_PM) */ + + if (ignore_devlist) + printk(KERN_DEBUG + "radeonfb: skipping test for device workarounds\n"); + else + radeon_apply_workarounds(rinfo); + + if (force_sleep) { + printk(KERN_DEBUG + "radeonfb: forcefully enabling D2 sleep mode\n"); + rinfo->pm_mode |= radeon_pm_d2; + } } void radeonfb_pm_exit(struct radeonfb_info *rinfo) diff --git a/drivers/video/aty/radeonfb.h b/drivers/video/aty/radeonfb.h index 38657b2..d5ff224 100644 --- a/drivers/video/aty/radeonfb.h +++ b/drivers/video/aty/radeonfb.h @@ -273,6 +273,8 @@ enum radeon_pm_mode { radeon_pm_off = 0x00000002, /* Can resume from D3 cold */ }; +typedef void (*reinit_function_ptr)(struct radeonfb_info *rinfo); + struct radeonfb_info { struct fb_info *info; @@ -338,7 +340,7 @@ struct radeonfb_info { int dynclk; int no_schedule; enum radeon_pm_mode pm_mode; - void (*reinit_func)(struct radeonfb_info *rinfo); + reinit_function_ptr reinit_func; /* Lock on register access */ spinlock_t reg_lock; @@ -600,7 +602,7 @@ extern int radeon_probe_i2c_connector(struct radeonfb_info *rinfo, int conn, u8 /* PM Functions */ extern int radeonfb_pci_suspend(struct pci_dev *pdev, pm_message_t state); extern int radeonfb_pci_resume(struct pci_dev *pdev); -extern void radeonfb_pm_init(struct radeonfb_info *rinfo, int dynclk); +extern void radeonfb_pm_init(struct radeonfb_info *rinfo, int dynclk, int ignore_devlist, int force_sleep); extern void radeonfb_pm_exit(struct radeonfb_info *rinfo); /* Monitor probe functions */ -- cgit v1.1 From 4b755999d6e0c1d988fb448289abb6c226cd8c36 Mon Sep 17 00:00:00 2001 From: Michael Hanselmann Date: Sun, 30 Jul 2006 03:04:19 -0700 Subject: [PATCH] powermac: More powermac backlight fixes This patch fixes several problems: - The legacy backlight value might be set at interrupt time. Introduced a worker to prevent it from directly calling the backlight code. - via-pmu allows the backlight to be grabbed, in which case we need to prevent other kernel code from changing the brightness. - Don't send PMU requests in via-pmu-backlight when the machine is about to sleep or waking up. - More Kconfig fixes. Signed-off-by: Michael Hanselmann Cc: Benjamin Herrenschmidt Cc: "Antonino A. Daplas" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/macintosh/Kconfig | 2 -- drivers/macintosh/adbhid.c | 14 ++------ drivers/macintosh/via-pmu-backlight.c | 68 ++++++++++++++++++++++++++++------- drivers/macintosh/via-pmu.c | 39 ++++++++------------ drivers/video/Kconfig | 28 ++++++--------- drivers/video/aty/aty128fb.c | 3 ++ drivers/video/aty/atyfb_base.c | 4 +-- 7 files changed, 87 insertions(+), 71 deletions(-) (limited to 'drivers') diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig index f5fe7fb..d162307 100644 --- a/drivers/macintosh/Kconfig +++ b/drivers/macintosh/Kconfig @@ -115,8 +115,6 @@ config PMAC_BACKLIGHT bool "Backlight control for LCD screens" depends on ADB_PMU && FB = y && (BROKEN || !PPC64) select FB_BACKLIGHT - select BACKLIGHT_CLASS_DEVICE - select BACKLIGHT_LCD_SUPPORT help Say Y here to enable Macintosh specific extensions of the generic backlight code. With this enabled, the brightness keys on older diff --git a/drivers/macintosh/adbhid.c b/drivers/macintosh/adbhid.c index 545be1e..c69d23b 100644 --- a/drivers/macintosh/adbhid.c +++ b/drivers/macintosh/adbhid.c @@ -45,14 +45,11 @@ #include #include +#include #ifdef CONFIG_PPC_PMAC #include #endif -#ifdef CONFIG_PMAC_BACKLIGHT -#include -#endif - MODULE_AUTHOR("Franz Sirl "); #define KEYB_KEYREG 0 /* register # for key up/down data */ @@ -237,11 +234,6 @@ static struct adb_ids keyboard_ids; static struct adb_ids mouse_ids; static struct adb_ids buttons_ids; -#ifdef CONFIG_PMAC_BACKLIGHT -/* Exported to via-pmu.c */ -int disable_kernel_backlight = 0; -#endif /* CONFIG_PMAC_BACKLIGHT */ - /* Kind of keyboard, see Apple technote 1152 */ #define ADB_KEYBOARD_UNKNOWN 0 #define ADB_KEYBOARD_ANSI 0x0100 @@ -527,7 +519,7 @@ adbhid_buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int auto case 0xa: /* brightness decrease */ #ifdef CONFIG_PMAC_BACKLIGHT - if (!disable_kernel_backlight && down) + if (down) pmac_backlight_key_down(); #endif input_report_key(adbhid[id]->input, KEY_BRIGHTNESSDOWN, down); @@ -535,7 +527,7 @@ adbhid_buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int auto case 0x9: /* brightness increase */ #ifdef CONFIG_PMAC_BACKLIGHT - if (!disable_kernel_backlight && down) + if (down) pmac_backlight_key_up(); #endif input_report_key(adbhid[id]->input, KEY_BRIGHTNESSUP, down); diff --git a/drivers/macintosh/via-pmu-backlight.c b/drivers/macintosh/via-pmu-backlight.c index b42d05f..d3f8d75 100644 --- a/drivers/macintosh/via-pmu-backlight.c +++ b/drivers/macintosh/via-pmu-backlight.c @@ -15,8 +15,9 @@ #define MAX_PMU_LEVEL 0xFF -static struct device_node *vias; static struct backlight_properties pmu_backlight_data; +static spinlock_t pmu_backlight_lock; +static int sleeping; static int pmu_backlight_get_level_brightness(struct fb_info *info, int level) @@ -40,23 +41,36 @@ static int pmu_backlight_update_status(struct backlight_device *bd) { struct fb_info *info = class_get_devdata(&bd->class_dev); struct adb_request req; - int pmulevel, level = bd->props->brightness; + unsigned long flags; + int level = bd->props->brightness; - if (vias == NULL) - return -ENODEV; + spin_lock_irqsave(&pmu_backlight_lock, flags); + + /* Don't update brightness when sleeping */ + if (sleeping) + goto out; if (bd->props->power != FB_BLANK_UNBLANK || bd->props->fb_blank != FB_BLANK_UNBLANK) level = 0; - pmulevel = pmu_backlight_get_level_brightness(info, level); + if (level > 0) { + int pmulevel = pmu_backlight_get_level_brightness(info, level); - pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT, pmulevel); - pmu_wait_complete(&req); + pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT, pmulevel); + pmu_wait_complete(&req); - pmu_request(&req, NULL, 2, PMU_POWER_CTRL, - PMU_POW_BACKLIGHT | (level > 0 ? PMU_POW_ON : PMU_POW_OFF)); - pmu_wait_complete(&req); + pmu_request(&req, NULL, 2, PMU_POWER_CTRL, + PMU_POW_BACKLIGHT | PMU_POW_ON); + pmu_wait_complete(&req); + } else { + pmu_request(&req, NULL, 2, PMU_POWER_CTRL, + PMU_POW_BACKLIGHT | PMU_POW_OFF); + pmu_wait_complete(&req); + } + +out: + spin_unlock_irqrestore(&pmu_backlight_lock, flags); return 0; } @@ -73,15 +87,39 @@ static struct backlight_properties pmu_backlight_data = { .max_brightness = (FB_BACKLIGHT_LEVELS - 1), }; -void __init pmu_backlight_init(struct device_node *in_vias) +#ifdef CONFIG_PM +static int pmu_backlight_sleep_call(struct pmu_sleep_notifier *self, int when) +{ + unsigned long flags; + + spin_lock_irqsave(&pmu_backlight_lock, flags); + + switch (when) { + case PBOOK_SLEEP_REQUEST: + sleeping = 1; + break; + case PBOOK_WAKE: + sleeping = 0; + break; + } + + spin_unlock_irqrestore(&pmu_backlight_lock, flags); + + return PBOOK_SLEEP_OK; +} + +static struct pmu_sleep_notifier pmu_backlight_sleep_notif = { + .notifier_call = pmu_backlight_sleep_call, +}; +#endif + +void __init pmu_backlight_init() { struct backlight_device *bd; struct fb_info *info; char name[10]; int level, autosave; - vias = in_vias; - /* Special case for the old PowerBook since I can't test on it */ autosave = machine_is_compatible("AAPL,3400/2400") || @@ -141,6 +179,10 @@ void __init pmu_backlight_init(struct device_node *in_vias) pmac_backlight = bd; mutex_unlock(&pmac_backlight_mutex); +#ifdef CONFIG_PM + pmu_register_sleep_notifier(&pmu_backlight_sleep_notif); +#endif + printk("pmubl: Backlight initialized (%s)\n", name); return; diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index 06ca80b..ea38680 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -16,7 +16,6 @@ * a sleep or a freq. switch * - Move sleep code out of here to pmac_pm, merge into new * common PM infrastructure - * - Move backlight code out as well * - Save/Restore PCI space properly * */ @@ -60,9 +59,7 @@ #include #include #include -#ifdef CONFIG_PMAC_BACKLIGHT #include -#endif #include "via-pmu-event.h" @@ -177,10 +174,6 @@ static int query_batt_timer = BATTERY_POLLING_COUNT; static struct adb_request batt_req; static struct proc_dir_entry *proc_pmu_batt[PMU_MAX_BATTERIES]; -#if defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT) -extern int disable_kernel_backlight; -#endif /* defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT) */ - int __fake_sleep; int asleep; BLOCKING_NOTIFIER_HEAD(sleep_notifier_list); @@ -466,7 +459,7 @@ static int __init via_pmu_dev_init(void) #ifdef CONFIG_PMAC_BACKLIGHT /* Initialize backlight */ - pmu_backlight_init(vias); + pmu_backlight_init(); #endif #ifdef CONFIG_PPC32 @@ -1403,11 +1396,8 @@ next: else if ((1 << pirq) & PMU_INT_SNDBRT) { #ifdef CONFIG_PMAC_BACKLIGHT if (len == 3) -#ifdef CONFIG_INPUT_ADBHID - if (!disable_kernel_backlight) -#endif /* CONFIG_INPUT_ADBHID */ - pmac_backlight_set_legacy_brightness(data[1] >> 4); -#endif /* CONFIG_PMAC_BACKLIGHT */ + pmac_backlight_set_legacy_brightness_pmu(data[1] >> 4); +#endif } /* Tick interrupt */ else if ((1 << pirq) & PMU_INT_TICK) { @@ -2414,7 +2404,7 @@ struct pmu_private { spinlock_t lock; #if defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT) int backlight_locker; -#endif /* defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT) */ +#endif }; static LIST_HEAD(all_pmu_pvt); @@ -2464,7 +2454,7 @@ pmu_open(struct inode *inode, struct file *file) spin_lock_irqsave(&all_pvt_lock, flags); #if defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT) pp->backlight_locker = 0; -#endif /* defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT) */ +#endif list_add(&pp->list, &all_pmu_pvt); spin_unlock_irqrestore(&all_pvt_lock, flags); file->private_data = pp; @@ -2559,13 +2549,12 @@ pmu_release(struct inode *inode, struct file *file) spin_lock_irqsave(&all_pvt_lock, flags); list_del(&pp->list); spin_unlock_irqrestore(&all_pvt_lock, flags); + #if defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT) - if (pp->backlight_locker) { - spin_lock_irqsave(&pmu_lock, flags); - disable_kernel_backlight--; - spin_unlock_irqrestore(&pmu_lock, flags); - } -#endif /* defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT) */ + if (pp->backlight_locker) + pmac_backlight_enable(); +#endif + kfree(pp); } unlock_kernel(); @@ -2642,18 +2631,18 @@ pmu_ioctl(struct inode * inode, struct file *filp, #ifdef CONFIG_INPUT_ADBHID case PMU_IOC_GRAB_BACKLIGHT: { struct pmu_private *pp = filp->private_data; - unsigned long flags; if (pp->backlight_locker) return 0; + pp->backlight_locker = 1; - spin_lock_irqsave(&pmu_lock, flags); - disable_kernel_backlight++; - spin_unlock_irqrestore(&pmu_lock, flags); + pmac_backlight_disable(); + return 0; } #endif /* CONFIG_INPUT_ADBHID */ #endif /* CONFIG_PMAC_BACKLIGHT_LEGACY */ + case PMU_IOC_GET_MODEL: return put_user(pmu_kind, argp); case PMU_IOC_HAS_ADB: diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 728cb56..c40b9b8 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -86,9 +86,11 @@ config FB_MACMODES default n config FB_BACKLIGHT - bool - depends on FB - default n + bool + depends on FB + select BACKLIGHT_LCD_SUPPORT + select BACKLIGHT_CLASS_DEVICE + default n config FB_MODE_HELPERS bool "Enable Video Mode Handling Helpers" @@ -721,10 +723,8 @@ config FB_NVIDIA_I2C config FB_NVIDIA_BACKLIGHT bool "Support for backlight control" - depends on FB_NVIDIA && PPC_PMAC + depends on FB_NVIDIA && PMAC_BACKLIGHT select FB_BACKLIGHT - select BACKLIGHT_LCD_SUPPORT - select BACKLIGHT_CLASS_DEVICE default y help Say Y here if you want to control the backlight of your display. @@ -769,10 +769,8 @@ config FB_RIVA_DEBUG config FB_RIVA_BACKLIGHT bool "Support for backlight control" - depends on FB_RIVA && PPC_PMAC + depends on FB_RIVA && PMAC_BACKLIGHT select FB_BACKLIGHT - select BACKLIGHT_LCD_SUPPORT - select BACKLIGHT_CLASS_DEVICE default y help Say Y here if you want to control the backlight of your display. @@ -1025,10 +1023,8 @@ config FB_RADEON_I2C config FB_RADEON_BACKLIGHT bool "Support for backlight control" - depends on FB_RADEON && PPC_PMAC + depends on FB_RADEON && PMAC_BACKLIGHT select FB_BACKLIGHT - select BACKLIGHT_LCD_SUPPORT - select BACKLIGHT_CLASS_DEVICE default y help Say Y here if you want to control the backlight of your display. @@ -1059,10 +1055,8 @@ config FB_ATY128 config FB_ATY128_BACKLIGHT bool "Support for backlight control" - depends on FB_ATY128 && PPC_PMAC + depends on FB_ATY128 && PMAC_BACKLIGHT select FB_BACKLIGHT - select BACKLIGHT_LCD_SUPPORT - select BACKLIGHT_CLASS_DEVICE default y help Say Y here if you want to control the backlight of your display. @@ -1111,10 +1105,8 @@ config FB_ATY_GX config FB_ATY_BACKLIGHT bool "Support for backlight control" - depends on FB_ATY && PPC_PMAC + depends on FB_ATY && PMAC_BACKLIGHT select FB_BACKLIGHT - select BACKLIGHT_LCD_SUPPORT - select BACKLIGHT_CLASS_DEVICE default y help Say Y here if you want to control the backlight of your display. diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c index c64a717..8b08121 100644 --- a/drivers/video/aty/aty128fb.c +++ b/drivers/video/aty/aty128fb.c @@ -455,7 +455,10 @@ static void do_wait_for_fifo(u16 entries, struct aty128fb_par *par); static void wait_for_fifo(u16 entries, struct aty128fb_par *par); static void wait_for_idle(struct aty128fb_par *par); static u32 depth_to_dst(u32 depth); + +#ifdef CONFIG_FB_ATY128_BACKLIGHT static void aty128_bl_set_power(struct fb_info *info, int power); +#endif #define BIOS_IN8(v) (readb(bios + (v))) #define BIOS_IN16(v) (readb(bios + (v)) | \ diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c index 1507d19..053ff63 100644 --- a/drivers/video/aty/atyfb_base.c +++ b/drivers/video/aty/atyfb_base.c @@ -2812,7 +2812,7 @@ static int atyfb_blank(int blank, struct fb_info *info) if (par->lock_blank || par->asleep) return 0; -#ifdef CONFIG_PMAC_BACKLIGHT +#ifdef CONFIG_FB_ATY_BACKLIGHT if (machine_is(powermac) && blank > FB_BLANK_NORMAL) aty_bl_set_power(info, FB_BLANK_POWERDOWN); #elif defined(CONFIG_FB_ATY_GENERIC_LCD) @@ -2844,7 +2844,7 @@ static int atyfb_blank(int blank, struct fb_info *info) } aty_st_le32(CRTC_GEN_CNTL, gen_cntl, par); -#ifdef CONFIG_PMAC_BACKLIGHT +#ifdef CONFIG_FB_ATY_BACKLIGHT if (machine_is(powermac) && blank <= FB_BLANK_NORMAL) aty_bl_set_power(info, FB_BLANK_UNBLANK); #elif defined(CONFIG_FB_ATY_GENERIC_LCD) -- cgit v1.1 From b1367d2a2817e6199092b43fe01c1eed3374c4e4 Mon Sep 17 00:00:00 2001 From: Arthur Othieno Date: Sun, 30 Jul 2006 03:04:20 -0700 Subject: [PATCH] nvidiafb: remove redundant CONFIG_PCI check CONFIG_FB_NVIDIA already depends on CONFIG_PCI in drivers/video/Kconfig. Driver does an extra ``sanity check'' which is then redundant. Signed-off-by: Arthur Othieno Cc: Antonino Daplas Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/nvidia/nvidia.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c index 9f2066f..d0ca0d8 100644 --- a/drivers/video/nvidia/nvidia.c +++ b/drivers/video/nvidia/nvidia.c @@ -34,10 +34,6 @@ #include "nv_proto.h" #include "nv_dma.h" -#ifndef CONFIG_PCI /* sanity check */ -#error This driver requires PCI support. -#endif - #undef CONFIG_FB_NVIDIA_DEBUG #ifdef CONFIG_FB_NVIDIA_DEBUG #define NVTRACE printk -- cgit v1.1 From ce38cac48209d270d07fd6d1a8e94446b37abcd5 Mon Sep 17 00:00:00 2001 From: Guido Guenther Date: Sun, 30 Jul 2006 03:04:21 -0700 Subject: [PATCH] rivafb/nvidiafb: race between register_framebuffer and *_bl_init Since we now use the generic backlight infrastructure, I think we need to call rivafb_bl_init before calling register_framebuffer since otherwise rivafb_bl_init might race with the framebuffer layer already opening the device and setting up the video mode. In this case we might end up with a not yet fully intialized backlight (info->bl_dev still NULL) when calling riva_bl_set_power via rivafb_set_par/rivafb_load_video_mode and the kernel dies without any further notice during boot. This fixes booting current git on a PB 6,1. In this case radeonfb/atyfb would be affected too - I can fix that too but don't have any hardware to test this on. Cc: "Antonino A. Daplas" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/nvidia/nvidia.c | 5 ++--- drivers/video/riva/fbdev.c | 7 +++---- 2 files changed, 5 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c index d0ca0d8..d4f8501 100644 --- a/drivers/video/nvidia/nvidia.c +++ b/drivers/video/nvidia/nvidia.c @@ -1299,20 +1299,19 @@ static int __devinit nvidiafb_probe(struct pci_dev *pd, nvidia_save_vga(par, &par->SavedReg); + pci_set_drvdata(pd, info); + nvidia_bl_init(par); if (register_framebuffer(info) < 0) { printk(KERN_ERR PFX "error registering nVidia framebuffer\n"); goto err_out_iounmap_fb; } - pci_set_drvdata(pd, info); printk(KERN_INFO PFX "PCI nVidia %s framebuffer (%dMB @ 0x%lX)\n", info->fix.id, par->FbMapSize / (1024 * 1024), info->fix.smem_start); - nvidia_bl_init(par); - NVTRACE_LEAVE(); return 0; diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c index 33dddba..76fc9d3 100644 --- a/drivers/video/riva/fbdev.c +++ b/drivers/video/riva/fbdev.c @@ -2132,6 +2132,9 @@ static int __devinit rivafb_probe(struct pci_dev *pd, fb_destroy_modedb(info->monspecs.modedb); info->monspecs.modedb = NULL; + + pci_set_drvdata(pd, info); + riva_bl_init(info->par); ret = register_framebuffer(info); if (ret < 0) { printk(KERN_ERR PFX @@ -2139,8 +2142,6 @@ static int __devinit rivafb_probe(struct pci_dev *pd, goto err_iounmap_screen_base; } - pci_set_drvdata(pd, info); - printk(KERN_INFO PFX "PCI nVidia %s framebuffer ver %s (%dMB @ 0x%lX)\n", info->fix.id, @@ -2148,8 +2149,6 @@ static int __devinit rivafb_probe(struct pci_dev *pd, info->fix.smem_len / (1024 * 1024), info->fix.smem_start); - riva_bl_init(info->par); - NVTRACE_LEAVE(); return 0; -- cgit v1.1 From 9c9a43ed2734081124407c779b36a4761c41139b Mon Sep 17 00:00:00 2001 From: Mattia Dongili Date: Wed, 5 Jul 2006 23:12:20 +0200 Subject: [CPUFREQ] return error when failing to set minfreq I just stumbled on this bug/feature, this is how to reproduce it: # echo 450000 > /sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq # echo 450000 > /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq # echo powersave > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor # cpufreq-info -p 450000 450000 powersave # echo 1800000 > /sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq ; echo $? 0 # cpufreq-info -p 450000 450000 powersave Here it is. The kernel refuses to set a min_freq higher than the max_freq but it allows a max_freq lower than min_freq (lowering min_freq also). This behaviour is pretty straightforward (but undocumented) and it doesn't return an error altough failing to accomplish the requested action (set min_freq). The problem (IMO) is basically that userspace is not allowed to set a full policy atomically while the kernel always does that thus it must enforce an ordering on operations. The attached patch returns -EINVAL if trying to increase frequencies starting from scaling_min_freq and documents the correct ordering of writes. Signed-off-by: Mattia Dongili Signed-off-by: Dominik Brodowski Signed-off-by: Dave Jones -- --- drivers/cpufreq/cpufreq.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index bc1088d..ad996c7 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1343,6 +1343,11 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data, struct cpufreq_poli memcpy(&policy->cpuinfo, &data->cpuinfo, sizeof(struct cpufreq_cpuinfo)); + if (policy->min > data->min && policy->min > policy->max) { + ret = -EINVAL; + goto error_out; + } + /* verify the cpu speed can be set within this limit */ ret = cpufreq_driver->verify(policy); if (ret) -- cgit v1.1 From 3bcb09a35641f2840bd59d8f82154f830dca282c Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Thu, 6 Jul 2006 12:30:26 -0700 Subject: [CPUFREQ] [1/2] add __find_governor helper and clean up some error handling. Adds a __find_governor() helper function to look up a governor by name. Also restructures some error handling to conform to the "single-exit" model which is generally preferred for kernel code. Signed-off-by: Jeremy Fitzhardinge Signed-off-by: Dave Jones --- drivers/cpufreq/cpufreq.c | 57 ++++++++++++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index ad996c7..9b41637 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -284,39 +284,52 @@ EXPORT_SYMBOL_GPL(cpufreq_notify_transition); * SYSFS INTERFACE * *********************************************************************/ +static struct cpufreq_governor *__find_governor(const char *str_governor) +{ + struct cpufreq_governor *t; + + list_for_each_entry(t, &cpufreq_governor_list, governor_list) + if (!strnicmp(str_governor,t->name,CPUFREQ_NAME_LEN)) + return t; + + return NULL; +} + /** * cpufreq_parse_governor - parse a governor string */ static int cpufreq_parse_governor (char *str_governor, unsigned int *policy, struct cpufreq_governor **governor) { + int err = -EINVAL; + if (!cpufreq_driver) - return -EINVAL; + goto out; + if (cpufreq_driver->setpolicy) { if (!strnicmp(str_governor, "performance", CPUFREQ_NAME_LEN)) { *policy = CPUFREQ_POLICY_PERFORMANCE; - return 0; + err = 0; } else if (!strnicmp(str_governor, "powersave", CPUFREQ_NAME_LEN)) { *policy = CPUFREQ_POLICY_POWERSAVE; - return 0; + err = 0; } - return -EINVAL; - } else { + } else if (cpufreq_driver->target) { struct cpufreq_governor *t; + mutex_lock(&cpufreq_governor_mutex); - if (!cpufreq_driver || !cpufreq_driver->target) - goto out; - list_for_each_entry(t, &cpufreq_governor_list, governor_list) { - if (!strnicmp(str_governor,t->name,CPUFREQ_NAME_LEN)) { - *governor = t; - mutex_unlock(&cpufreq_governor_mutex); - return 0; - } + + t = __find_governor(str_governor); + + if (t != NULL) { + *governor = t; + err = 0; } -out: + mutex_unlock(&cpufreq_governor_mutex); } - return -EINVAL; + out: + return err; } @@ -1265,23 +1278,21 @@ static int __cpufreq_governor(struct cpufreq_policy *policy, unsigned int event) int cpufreq_register_governor(struct cpufreq_governor *governor) { - struct cpufreq_governor *t; + int err; if (!governor) return -EINVAL; mutex_lock(&cpufreq_governor_mutex); - list_for_each_entry(t, &cpufreq_governor_list, governor_list) { - if (!strnicmp(governor->name,t->name,CPUFREQ_NAME_LEN)) { - mutex_unlock(&cpufreq_governor_mutex); - return -EBUSY; - } + err = -EBUSY; + if (__find_governor(governor->name) == NULL) { + err = 0; + list_add(&governor->governor_list, &cpufreq_governor_list); } - list_add(&governor->governor_list, &cpufreq_governor_list); mutex_unlock(&cpufreq_governor_mutex); - return 0; + return err; } EXPORT_SYMBOL_GPL(cpufreq_register_governor); -- cgit v1.1 From ea71497020c55cd39221e0abad5c1752ac6e3f47 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Thu, 6 Jul 2006 12:32:01 -0700 Subject: [CPUFREQ] [2/2] demand load governor modules. Demand-load cpufreq governor modules if needed. Signed-off-by: Jeremy Fitzhardinge Signed-off-by: Dave Jones --- drivers/cpufreq/cpufreq.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'drivers') diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 9b41637..b3df613 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -321,6 +321,23 @@ static int cpufreq_parse_governor (char *str_governor, unsigned int *policy, t = __find_governor(str_governor); + if (t == NULL) { + char *name = kasprintf(GFP_KERNEL, "cpufreq_%s", str_governor); + + if (name) { + int ret; + + mutex_unlock(&cpufreq_governor_mutex); + ret = request_module(name); + mutex_lock(&cpufreq_governor_mutex); + + if (ret == 0) + t = __find_governor(str_governor); + } + + kfree(name); + } + if (t != NULL) { *governor = t; err = 0; -- cgit v1.1 From dba654d1508e7060c7d79ab2f63a00325fd84270 Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Sat, 8 Jul 2006 00:27:49 +0200 Subject: kbuild: hardcode value of YACC&LEX for aic7-triple-x When we introduced -rR then aic7xxx no loger could pick up definition of YACC&LEX from make - so do it explicit now. Signed-off-by: Sam Ravnborg --- drivers/scsi/aic7xxx/aicasm/Makefile | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/aic7xxx/aicasm/Makefile b/drivers/scsi/aic7xxx/aicasm/Makefile index 8c91fda..b98c5c1 100644 --- a/drivers/scsi/aic7xxx/aicasm/Makefile +++ b/drivers/scsi/aic7xxx/aicasm/Makefile @@ -14,6 +14,8 @@ LIBS= -ldb clean-files:= ${GENSRCS} ${GENHDRS} $(YSRCS:.y=.output) $(PROG) # Override default kernel CFLAGS. This is a userland app. AICASM_CFLAGS:= -I/usr/include -I. +LEX= flex +YACC= bison YFLAGS= -d NOMAN= noman -- cgit v1.1 From 99f65f25c19a7a8a5789c300c2a575cff3453382 Mon Sep 17 00:00:00 2001 From: Ulrich Kunitz Date: Tue, 1 Aug 2006 23:43:30 +0200 Subject: [PATCH] zd1211rw: Fixes radiotap header There has been a problem in the radiotap header. Monitor mode works now with tcpdump 3.94 + libpcap 0.9.4. ethereal 0.99.0 + libpcap 0.9.4 is broken, because it doesn't find the right offset for the IEEE 802.11 header. Signed-off-by: Ulrich Kunitz Signed-off-by: John W. Linville --- drivers/net/wireless/zd1211rw/zd_mac.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 3bdc54d..b394303 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -713,10 +713,10 @@ static int zd_mac_tx(struct zd_mac *mac, struct ieee80211_txb *txb, int pri) struct zd_rt_hdr { struct ieee80211_radiotap_header rt_hdr; u8 rt_flags; + u8 rt_rate; u16 rt_channel; u16 rt_chbitmask; - u16 rt_rate; -}; +} __attribute__((packed)); static void fill_rt_header(void *buffer, struct zd_mac *mac, const struct ieee80211_rx_stats *stats, @@ -735,14 +735,14 @@ static void fill_rt_header(void *buffer, struct zd_mac *mac, if (status->decryption_type & (ZD_RX_WEP64|ZD_RX_WEP128|ZD_RX_WEP256)) hdr->rt_flags |= IEEE80211_RADIOTAP_F_WEP; + hdr->rt_rate = stats->rate / 5; + /* FIXME: 802.11a */ hdr->rt_channel = cpu_to_le16(ieee80211chan2mhz( _zd_chip_get_channel(&mac->chip))); hdr->rt_chbitmask = cpu_to_le16(IEEE80211_CHAN_2GHZ | ((status->frame_status & ZD_RX_FRAME_MODULATION_MASK) == ZD_RX_OFDM ? IEEE80211_CHAN_OFDM : IEEE80211_CHAN_CCK)); - - hdr->rt_rate = stats->rate / 5; } /* Returns 1 if the data packet is for us and 0 otherwise. */ -- cgit v1.1 From 71eae25ece9ee6bc2fe9500c9c06bfbb46c55fb2 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Tue, 1 Aug 2006 23:43:31 +0200 Subject: [PATCH] zd1211rw: Pass more management frame types up to host We'll be needing these at some point... Signed-off-by: Daniel Drake Signed-off-by: Ulrich Kunitz Signed-off-by: John W. Linville --- drivers/net/wireless/zd1211rw/zd_chip.h | 4 +++- drivers/net/wireless/zd1211rw/zd_mac.c | 6 ++++-- 2 files changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h index 8051210..0eb9c8f 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.h +++ b/drivers/net/wireless/zd1211rw/zd_chip.h @@ -461,10 +461,12 @@ #define CR_RX_FILTER CTL_REG(0x068c) #define RX_FILTER_ASSOC_RESPONSE 0x0002 +#define RX_FILTER_REASSOC_RESPONSE 0x0008 #define RX_FILTER_PROBE_RESPONSE 0x0020 #define RX_FILTER_BEACON 0x0100 +#define RX_FILTER_DISASSOC 0x0400 #define RX_FILTER_AUTH 0x0800 -/* Sniff modus sets filter to 0xfffff */ +/* Monitor mode sets filter to 0xfffff */ #define CR_ACK_TIMEOUT_EXT CTL_REG(0x0690) #define CR_BCN_FIFO_SEMAPHORE CTL_REG(0x0694) diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index b394303..1cf1fda 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -136,8 +136,10 @@ static int reset_mode(struct zd_mac *mac) { struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); struct zd_ioreq32 ioreqs[3] = { - { CR_RX_FILTER, RX_FILTER_BEACON|RX_FILTER_PROBE_RESPONSE| - RX_FILTER_AUTH|RX_FILTER_ASSOC_RESPONSE }, + { CR_RX_FILTER, RX_FILTER_BEACON | RX_FILTER_PROBE_RESPONSE | + RX_FILTER_AUTH | RX_FILTER_ASSOC_RESPONSE | + RX_FILTER_REASSOC_RESPONSE | + RX_FILTER_DISASSOC }, { CR_SNIFFER_ON, 0U }, { CR_ENCRYPTION_TYPE, NO_WEP }, }; -- cgit v1.1 From 40da08bca6f4e7dec4a75c3c47800e5f4ca4e567 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Tue, 1 Aug 2006 23:43:32 +0200 Subject: [PATCH] zd1211rw: Fix software encryption/decryption Apparently the ZD1211 doesn't mind, but the ZD1211B absolutely must be told that encryption is happening in software. Signed-off-by: Daniel Drake Signed-off-by: Ulrich Kunitz Signed-off-by: John W. Linville --- drivers/net/wireless/zd1211rw/zd_mac.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 1cf1fda..a66625c 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -108,7 +108,9 @@ int zd_mac_init_hw(struct zd_mac *mac, u8 device_type) if (r) goto disable_int; - r = zd_set_encryption_type(chip, NO_WEP); + /* We must inform the device that we are doing encryption/decryption in + * software at the moment. */ + r = zd_set_encryption_type(chip, ENC_SNIFFER); if (r) goto disable_int; @@ -141,7 +143,6 @@ static int reset_mode(struct zd_mac *mac) RX_FILTER_REASSOC_RESPONSE | RX_FILTER_DISASSOC }, { CR_SNIFFER_ON, 0U }, - { CR_ENCRYPTION_TYPE, NO_WEP }, }; if (ieee->iw_mode == IW_MODE_MONITOR) { -- cgit v1.1 From b1162b639cc13d5a1ab9bcbd0a502599ddf49f86 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Tue, 1 Aug 2006 23:43:33 +0200 Subject: [PATCH] zd1211rw: Remove bogus assert This function is never called in interrupt context, and it doesn't matter if it is called in IRQ context or not. Signed-off-by: Daniel Drake Signed-off-by: Ulrich Kunitz Signed-off-by: John W. Linville --- drivers/net/wireless/zd1211rw/zd_usb.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index 72f9052..f9a93f6 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -323,7 +323,6 @@ static void disable_read_regs_int(struct zd_usb *usb) { struct zd_usb_interrupt *intr = &usb->intr; - ZD_ASSERT(in_interrupt()); spin_lock(&intr->lock); intr->read_regs_enabled = 0; spin_unlock(&intr->lock); -- cgit v1.1 From b269825b9bb2c925bbaf4365ec9fa4c6a16e46b4 Mon Sep 17 00:00:00 2001 From: Ulrich Kunitz Date: Tue, 1 Aug 2006 23:43:34 +0200 Subject: [PATCH] zd1211rw: Fixed endianess issue with length info tag detection Discovered a problem while accessing www.python.org on my PPC32. The problem was pretty consistent for all sticks. The reason was that while testing for the length info tag, I ignored the endianess of the host system. Please recognize that converting the constant to little endian, we create faster code. Signed-off-by: Ulrich Kunitz Signed-off-by: John W. Linville --- drivers/net/wireless/zd1211rw/zd_usb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index f9a93f6..6320984 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -544,11 +544,11 @@ static void handle_rx_packet(struct zd_usb *usb, const u8 *buffer, * be padded. Unaligned access might also happen if the length_info * structure is not present. */ - if (get_unaligned(&length_info->tag) == RX_LENGTH_INFO_TAG) { + if (get_unaligned(&length_info->tag) == cpu_to_le16(RX_LENGTH_INFO_TAG)) + { unsigned int l, k, n; for (i = 0, l = 0;; i++) { - k = le16_to_cpu(get_unaligned( - &length_info->length[i])); + k = le16_to_cpu(get_unaligned(&length_info->length[i])); n = l+k; if (n > length) return; -- cgit v1.1 From fde627b54ce7bef094157074f3adb9b6e1a96d4c Mon Sep 17 00:00:00 2001 From: Ulrich Kunitz Date: Tue, 1 Aug 2006 23:43:35 +0200 Subject: [PATCH] zd1211rw: Packet filter fix for managed (STA) mode I had problems with my AVM Fritz!Box access point. It appeared that the AP deauthorized me and the softmac didn't reconnect me. This patch handles the problem. Signed-off-by: Ulrich Kunitz Signed-off-by: John W. Linville --- drivers/net/wireless/zd1211rw/zd_chip.c | 4 ++-- drivers/net/wireless/zd1211rw/zd_chip.h | 6 +++--- drivers/net/wireless/zd1211rw/zd_mac.c | 5 +---- 3 files changed, 6 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c index efc9c4b..da9d06b 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.c +++ b/drivers/net/wireless/zd1211rw/zd_chip.c @@ -797,7 +797,7 @@ static int zd1211_hw_init_hmac(struct zd_chip *chip) { CR_ADDA_MBIAS_WARMTIME, 0x30000808 }, { CR_ZD1211_RETRY_MAX, 0x2 }, { CR_SNIFFER_ON, 0 }, - { CR_RX_FILTER, AP_RX_FILTER }, + { CR_RX_FILTER, STA_RX_FILTER }, { CR_GROUP_HASH_P1, 0x00 }, { CR_GROUP_HASH_P2, 0x80000000 }, { CR_REG1, 0xa4 }, @@ -844,7 +844,7 @@ static int zd1211b_hw_init_hmac(struct zd_chip *chip) { CR_ZD1211B_AIFS_CTL2, 0x008C003C }, { CR_ZD1211B_TXOP, 0x01800824 }, { CR_SNIFFER_ON, 0 }, - { CR_RX_FILTER, AP_RX_FILTER }, + { CR_RX_FILTER, STA_RX_FILTER }, { CR_GROUP_HASH_P1, 0x00 }, { CR_GROUP_HASH_P2, 0x80000000 }, { CR_REG1, 0xa4 }, diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h index 0eb9c8f..069d2b4 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.h +++ b/drivers/net/wireless/zd1211rw/zd_chip.h @@ -466,6 +466,9 @@ #define RX_FILTER_BEACON 0x0100 #define RX_FILTER_DISASSOC 0x0400 #define RX_FILTER_AUTH 0x0800 +#define AP_RX_FILTER 0x0400feff +#define STA_RX_FILTER 0x0000ffff + /* Monitor mode sets filter to 0xfffff */ #define CR_ACK_TIMEOUT_EXT CTL_REG(0x0690) @@ -548,9 +551,6 @@ #define CR_ZD1211B_TXOP CTL_REG(0x0b20) #define CR_ZD1211B_RETRY_MAX CTL_REG(0x0b28) -#define AP_RX_FILTER 0x0400feff -#define STA_RX_FILTER 0x0000ffff - #define CWIN_SIZE 0x007f043f diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index a66625c..d6f3e02 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -138,10 +138,7 @@ static int reset_mode(struct zd_mac *mac) { struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); struct zd_ioreq32 ioreqs[3] = { - { CR_RX_FILTER, RX_FILTER_BEACON | RX_FILTER_PROBE_RESPONSE | - RX_FILTER_AUTH | RX_FILTER_ASSOC_RESPONSE | - RX_FILTER_REASSOC_RESPONSE | - RX_FILTER_DISASSOC }, + { CR_RX_FILTER, STA_RX_FILTER }, { CR_SNIFFER_ON, 0U }, }; -- cgit v1.1 From 9cac2c35e26cc44978df654306bb92d7cfe7e2de Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 30 Jul 2006 20:20:54 -0700 Subject: [ATALK]: Make CONFIG_DEV_APPLETALK a tristate. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Otherwise we allow building appletalk drivers in-kernel when CONFIG_ATALK is modular. That doesn't work because these drivers use symbols such as "alloc_talkdev" which is exported from code built by CONFIG_ATALK. Noticed by Toralf Förster. Signed-off-by: David S. Miller --- drivers/net/appletalk/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/appletalk/Kconfig b/drivers/net/appletalk/Kconfig index b14e890..0a0e0cd 100644 --- a/drivers/net/appletalk/Kconfig +++ b/drivers/net/appletalk/Kconfig @@ -29,7 +29,7 @@ config ATALK even politically correct people are allowed to say Y here. config DEV_APPLETALK - bool "Appletalk interfaces support" + tristate "Appletalk interfaces support" depends on ATALK help AppleTalk is the protocol that Apple computers can use to communicate -- cgit v1.1 From e795d092507d571d66f2ec98d3efdc7dd284bf80 Mon Sep 17 00:00:00 2001 From: Tom Tucker Date: Sun, 30 Jul 2006 20:44:19 -0700 Subject: [NET] infiniband: Cleanup ib_addr module to use the netevents Signed-off-by: Tom Tucker Signed-off-by: Steve Wise Signed-off-by: David S. Miller --- drivers/infiniband/core/addr.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c index d294bbc..1205e80 100644 --- a/drivers/infiniband/core/addr.c +++ b/drivers/infiniband/core/addr.c @@ -35,6 +35,7 @@ #include #include #include +#include #include MODULE_AUTHOR("Sean Hefty"); @@ -326,25 +327,22 @@ void rdma_addr_cancel(struct rdma_dev_addr *addr) } EXPORT_SYMBOL(rdma_addr_cancel); -static int addr_arp_recv(struct sk_buff *skb, struct net_device *dev, - struct packet_type *pkt, struct net_device *orig_dev) +static int netevent_callback(struct notifier_block *self, unsigned long event, + void *ctx) { - struct arphdr *arp_hdr; + if (event == NETEVENT_NEIGH_UPDATE) { + struct neighbour *neigh = ctx; - arp_hdr = (struct arphdr *) skb->nh.raw; - - if (arp_hdr->ar_op == htons(ARPOP_REQUEST) || - arp_hdr->ar_op == htons(ARPOP_REPLY)) - set_timeout(jiffies); - - kfree_skb(skb); + if (neigh->dev->type == ARPHRD_INFINIBAND && + (neigh->nud_state & NUD_VALID)) { + set_timeout(jiffies); + } + } return 0; } -static struct packet_type addr_arp = { - .type = __constant_htons(ETH_P_ARP), - .func = addr_arp_recv, - .af_packet_priv = (void*) 1, +static struct notifier_block nb = { + .notifier_call = netevent_callback }; static int addr_init(void) @@ -353,13 +351,13 @@ static int addr_init(void) if (!addr_wq) return -ENOMEM; - dev_add_pack(&addr_arp); + register_netevent_notifier(&nb); return 0; } static void addr_cleanup(void) { - dev_remove_pack(&addr_arp); + unregister_netevent_notifier(&nb); destroy_workqueue(addr_wq); } -- cgit v1.1 From a20e9c6291f27cac4a9ab450d124794c012f87d4 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 31 Jul 2006 22:38:16 -0700 Subject: [TG3]: Convert to netdev_alloc_skb Signed-off-by: David S. Miller --- drivers/net/tg3.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 1b8138f..6f97962 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -68,8 +68,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.63" -#define DRV_MODULE_RELDATE "July 25, 2006" +#define DRV_MODULE_VERSION "3.64" +#define DRV_MODULE_RELDATE "July 31, 2006" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 @@ -3097,7 +3097,7 @@ static int tg3_alloc_rx_skb(struct tg3 *tp, u32 opaque_key, * Callers depend upon this behavior and assume that * we leave everything unchanged if we fail. */ - skb = dev_alloc_skb(skb_size); + skb = netdev_alloc_skb(tp->dev, skb_size); if (skb == NULL) return -ENOMEM; @@ -3270,7 +3270,7 @@ static int tg3_rx(struct tg3 *tp, int budget) tg3_recycle_rx(tp, opaque_key, desc_idx, *post_ptr); - copy_skb = dev_alloc_skb(len + 2); + copy_skb = netdev_alloc_skb(tp->dev, len + 2); if (copy_skb == NULL) goto drop_it_no_recycle; @@ -8618,7 +8618,7 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) err = -EIO; tx_len = 1514; - skb = dev_alloc_skb(tx_len); + skb = netdev_alloc_skb(tp->dev, tx_len); if (!skb) return -ENOMEM; -- cgit v1.1 From 87f5032e0ca149bd03f0e2b46071b0c4a2312e82 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 31 Jul 2006 22:39:40 -0700 Subject: [E1000]: Convert to netdev_alloc_skb Signed-off-by: David S. Miller --- drivers/net/e1000/e1000_main.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index da62db8..627f224 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -3127,7 +3127,7 @@ e1000_change_mtu(struct net_device *netdev, int new_mtu) break; } - /* NOTE: dev_alloc_skb reserves 16 bytes, and typically NET_IP_ALIGN + /* NOTE: netdev_alloc_skb reserves 16 bytes, and typically NET_IP_ALIGN * means we reserve 2 more, this pushes us to allocate from the next * larger slab size * i.e. RXBUFFER_2048 --> size-4096 slab */ @@ -3708,7 +3708,7 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter, #define E1000_CB_LENGTH 256 if (length < E1000_CB_LENGTH) { struct sk_buff *new_skb = - dev_alloc_skb(length + NET_IP_ALIGN); + netdev_alloc_skb(netdev, length + NET_IP_ALIGN); if (new_skb) { skb_reserve(new_skb, NET_IP_ALIGN); new_skb->dev = netdev; @@ -3979,7 +3979,7 @@ e1000_alloc_rx_buffers(struct e1000_adapter *adapter, while (cleaned_count--) { if (!(skb = buffer_info->skb)) - skb = dev_alloc_skb(bufsz); + skb = netdev_alloc_skb(netdev, bufsz); else { skb_trim(skb, 0); goto map_skb; @@ -3997,7 +3997,7 @@ e1000_alloc_rx_buffers(struct e1000_adapter *adapter, DPRINTK(RX_ERR, ERR, "skb align check failed: %u bytes " "at %p\n", bufsz, skb->data); /* Try again, without freeing the previous */ - skb = dev_alloc_skb(bufsz); + skb = netdev_alloc_skb(netdev, bufsz); /* Failed allocation, critical failure */ if (!skb) { dev_kfree_skb(oldskb); @@ -4121,7 +4121,8 @@ e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter, rx_desc->read.buffer_addr[j+1] = ~0; } - skb = dev_alloc_skb(adapter->rx_ps_bsize0 + NET_IP_ALIGN); + skb = netdev_alloc_skb(netdev, + adapter->rx_ps_bsize0 + NET_IP_ALIGN); if (unlikely(!skb)) { adapter->alloc_rx_buff_failed++; -- cgit v1.1 From c7c17423b9ea3c5559cfb480a00844f1df9eed06 Mon Sep 17 00:00:00 2001 From: Greg Edwards Date: Fri, 28 Jul 2006 10:03:55 -0500 Subject: [IA64] add platform check to snsc driver init Add a platform check to the snsc driver init function, to prevent loading on non-sn2 systems. Signed-off-by: Greg Edwards Signed-off-by: Tony Luck --- drivers/char/snsc.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/char/snsc.c b/drivers/char/snsc.c index afc6eda..07e0b75 100644 --- a/drivers/char/snsc.c +++ b/drivers/char/snsc.c @@ -374,7 +374,12 @@ scdrv_init(void) struct sysctl_data_s *scd; void *salbuf; dev_t first_dev, dev; - nasid_t event_nasid = ia64_sn_get_console_nasid(); + nasid_t event_nasid; + + if (!ia64_platform_is("sn2")) + return -ENODEV; + + event_nasid = ia64_sn_get_console_nasid(); if (alloc_chrdev_region(&first_dev, 0, num_cnodes, SYSCTL_BASENAME) < 0) { -- cgit v1.1 From 8b2e76687b39213725207b4a4264e11e8c7b86e6 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Wed, 5 Jul 2006 02:38:56 -0700 Subject: USB: AT91 UDC updates, mostly power management UDC updates for AT91 series processors: - Get ready for at91sam926x processors (ARMv5tej not ARMv4t) - Suspend/resume support now behaves properly - In "standby" mode, UDC can be a source of system wakeup events (host resume, device connect/disconnect, etc) - Fix IRQ storming issues, seemingly related to clock disabling changes that went in a while back And minor cleanups, especially whitespace. Signed-off-by: David Brownell Signed-off-by: Andrew Victor Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/at91_udc.c | 176 +++++++++++++++++++++++++++--------------- drivers/usb/gadget/at91_udc.h | 1 + 2 files changed, 113 insertions(+), 64 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index 1c459ff..cfebca0 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -57,19 +57,23 @@ /* * This controller is simple and PIO-only. It's used in many AT91-series - * ARMv4T controllers, including the at91rm9200 (arm920T, with MMU), - * at91sam9261 (arm926ejs, with MMU), and several no-mmu versions. + * full speed USB controllers, including the at91rm9200 (arm920T, with MMU), + * at91sam926x (arm926ejs, with MMU), and several no-mmu versions. * * This driver expects the board has been wired with two GPIOs suppporting * a VBUS sensing IRQ, and a D+ pullup. (They may be omitted, but the - * testing hasn't covered such cases.) The pullup is most important; it + * testing hasn't covered such cases.) + * + * The pullup is most important (so it's integrated on sam926x parts). It * provides software control over whether the host enumerates the device. + * * The VBUS sensing helps during enumeration, and allows both USB clocks * (and the transceiver) to stay gated off until they're necessary, saving - * power. During USB suspend, the 48 MHz clock is gated off. + * power. During USB suspend, the 48 MHz clock is gated off in hardware; + * it may also be gated off by software during some Linux sleep states. */ -#define DRIVER_VERSION "8 March 2005" +#define DRIVER_VERSION "3 May 2006" static const char driver_name [] = "at91_udc"; static const char ep0name[] = "ep0"; @@ -316,9 +320,15 @@ static void done(struct at91_ep *ep, struct at91_request *req, int status) * * There are also state bits like FORCESTALL, EPEDS, DIR, and EPTYPE * that shouldn't normally be changed. + * + * NOTE at91sam9260 docs mention synch between UDPCK and MCK clock domains, + * implying a need to wait for one write to complete (test relevant bits) + * before starting the next write. This shouldn't be an issue given how + * infrequently we write, except maybe for write-then-read idioms. */ #define SET_FX (AT91_UDP_TXPKTRDY) -#define CLR_FX (RX_DATA_READY | AT91_UDP_RXSETUP | AT91_UDP_STALLSENT | AT91_UDP_TXCOMP) +#define CLR_FX (RX_DATA_READY | AT91_UDP_RXSETUP \ + | AT91_UDP_STALLSENT | AT91_UDP_TXCOMP) /* pull OUT packet data from the endpoint's fifo */ static int read_fifo (struct at91_ep *ep, struct at91_request *req) @@ -472,7 +482,8 @@ static void nuke(struct at91_ep *ep, int status) /*-------------------------------------------------------------------------*/ -static int at91_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) +static int at91_ep_enable(struct usb_ep *_ep, + const struct usb_endpoint_descriptor *desc) { struct at91_ep *ep = container_of(_ep, struct at91_ep, ep); struct at91_udc *dev = ep->udc; @@ -582,11 +593,12 @@ static int at91_ep_disable (struct usb_ep * _ep) * interesting for request or buffer allocation. */ -static struct usb_request *at91_ep_alloc_request (struct usb_ep *_ep, unsigned int gfp_flags) +static struct usb_request * +at91_ep_alloc_request(struct usb_ep *_ep, unsigned int gfp_flags) { struct at91_request *req; - req = kcalloc(1, sizeof (struct at91_request), SLAB_KERNEL); + req = kcalloc(1, sizeof (struct at91_request), gfp_flags); if (!req) return NULL; @@ -862,6 +874,7 @@ static void stop_activity(struct at91_udc *udc) if (udc->gadget.speed == USB_SPEED_UNKNOWN) driver = NULL; udc->gadget.speed = USB_SPEED_UNKNOWN; + udc->suspended = 0; for (i = 0; i < NUM_ENDPOINTS; i++) { struct at91_ep *ep = &udc->ep[i]; @@ -889,8 +902,8 @@ static void clk_off(struct at91_udc *udc) return; udc->clocked = 0; udc->gadget.speed = USB_SPEED_UNKNOWN; - clk_disable(udc->iclk); clk_disable(udc->fclk); + clk_disable(udc->iclk); } /* @@ -911,9 +924,6 @@ static void pullup(struct at91_udc *udc, int is_on) at91_udp_write(AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS); at91_set_gpio_value(udc->board.pullup_pin, 0); clk_off(udc); - - // REVISIT: with transceiver disabled, will D- float - // so that a host would falsely detect a device? } } @@ -1290,7 +1300,8 @@ static void handle_ep0(struct at91_udc *udc) if (udc->wait_for_addr_ack) { u32 tmp; - at91_udp_write(AT91_UDP_FADDR, AT91_UDP_FEN | udc->addr); + at91_udp_write(AT91_UDP_FADDR, + AT91_UDP_FEN | udc->addr); tmp = at91_udp_read(AT91_UDP_GLB_STAT); tmp &= ~AT91_UDP_FADDEN; if (udc->addr) @@ -1361,9 +1372,10 @@ static irqreturn_t at91_udc_irq (int irq, void *_udc, struct pt_regs *r) u32 rescans = 5; while (rescans--) { - u32 status = at91_udp_read(AT91_UDP_ISR); + u32 status; - status &= at91_udp_read(AT91_UDP_IMR); + status = at91_udp_read(AT91_UDP_ISR) + & at91_udp_read(AT91_UDP_IMR); if (!status) break; @@ -1379,18 +1391,17 @@ static irqreturn_t at91_udc_irq (int irq, void *_udc, struct pt_regs *r) stop_activity(udc); /* enable ep0 */ - at91_udp_write(AT91_UDP_CSR(0), AT91_UDP_EPEDS | AT91_UDP_EPTYPE_CTRL); + at91_udp_write(AT91_UDP_CSR(0), + AT91_UDP_EPEDS | AT91_UDP_EPTYPE_CTRL); udc->gadget.speed = USB_SPEED_FULL; udc->suspended = 0; at91_udp_write(AT91_UDP_IER, AT91_UDP_EP(0)); /* * NOTE: this driver keeps clocks off unless the - * USB host is present. That saves power, and also - * eliminates IRQs (reset, resume, suspend) that can - * otherwise flood from the controller. If your - * board doesn't support VBUS detection, suspend and - * resume irq logic may need more attention... + * USB host is present. That saves power, but for + * boards that don't support VBUS detection, both + * clocks need to be active most of the time. */ /* host initiated suspend (3+ms bus idle) */ @@ -1452,13 +1463,19 @@ static irqreturn_t at91_udc_irq (int irq, void *_udc, struct pt_regs *r) /*-------------------------------------------------------------------------*/ +static void nop_release(struct device *dev) +{ + /* nothing to free */ +} + static struct at91_udc controller = { .gadget = { - .ops = &at91_udc_ops, - .ep0 = &controller.ep[0].ep, - .name = driver_name, - .dev = { - .bus_id = "gadget" + .ops = &at91_udc_ops, + .ep0 = &controller.ep[0].ep, + .name = driver_name, + .dev = { + .bus_id = "gadget", + .release = nop_release, } }, .ep[0] = { @@ -1468,7 +1485,8 @@ static struct at91_udc controller = { }, .udc = &controller, .maxpacket = 8, - .creg = (void __iomem *)(AT91_VA_BASE_UDP + AT91_UDP_CSR(0)), + .creg = (void __iomem *)(AT91_VA_BASE_UDP + + AT91_UDP_CSR(0)), .int_mask = 1 << 0, }, .ep[1] = { @@ -1479,7 +1497,8 @@ static struct at91_udc controller = { .udc = &controller, .is_pingpong = 1, .maxpacket = 64, - .creg = (void __iomem *)(AT91_VA_BASE_UDP + AT91_UDP_CSR(1)), + .creg = (void __iomem *)(AT91_VA_BASE_UDP + + AT91_UDP_CSR(1)), .int_mask = 1 << 1, }, .ep[2] = { @@ -1490,7 +1509,8 @@ static struct at91_udc controller = { .udc = &controller, .is_pingpong = 1, .maxpacket = 64, - .creg = (void __iomem *)(AT91_VA_BASE_UDP + AT91_UDP_CSR(2)), + .creg = (void __iomem *)(AT91_VA_BASE_UDP + + AT91_UDP_CSR(2)), .int_mask = 1 << 2, }, .ep[3] = { @@ -1501,7 +1521,8 @@ static struct at91_udc controller = { }, .udc = &controller, .maxpacket = 8, - .creg = (void __iomem *)(AT91_VA_BASE_UDP + AT91_UDP_CSR(3)), + .creg = (void __iomem *)(AT91_VA_BASE_UDP + + AT91_UDP_CSR(3)), .int_mask = 1 << 3, }, .ep[4] = { @@ -1512,7 +1533,8 @@ static struct at91_udc controller = { .udc = &controller, .is_pingpong = 1, .maxpacket = 256, - .creg = (void __iomem *)(AT91_VA_BASE_UDP + AT91_UDP_CSR(4)), + .creg = (void __iomem *)(AT91_VA_BASE_UDP + + AT91_UDP_CSR(4)), .int_mask = 1 << 4, }, .ep[5] = { @@ -1523,10 +1545,11 @@ static struct at91_udc controller = { .udc = &controller, .is_pingpong = 1, .maxpacket = 256, - .creg = (void __iomem *)(AT91_VA_BASE_UDP + AT91_UDP_CSR(5)), + .creg = (void __iomem *)(AT91_VA_BASE_UDP + + AT91_UDP_CSR(5)), .int_mask = 1 << 5, }, - /* ep6 and ep7 are also reserved */ + /* ep6 and ep7 are also reserved (custom silicon might use them) */ }; static irqreturn_t at91_vbus_irq(int irq, void *_udc, struct pt_regs *r) @@ -1593,6 +1616,7 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver) local_irq_disable(); udc->enabled = 0; + at91_udp_write(AT91_UDP_IDR, ~0); pullup(udc, 0); local_irq_enable(); @@ -1624,6 +1648,16 @@ static int __devinit at91udc_probe(struct platform_device *pdev) return -ENODEV; } + if (pdev->num_resources != 2) { + DBG("invalid num_resources"); + return -ENODEV; + } + if ((pdev->resource[0].flags != IORESOURCE_MEM) + || (pdev->resource[1].flags != IORESOURCE_IRQ)) { + DBG("invalid resource type"); + return -ENODEV; + } + if (!request_mem_region(AT91_BASE_UDP, SZ_16K, driver_name)) { DBG("someone's using UDC memory\n"); return -EBUSY; @@ -1649,19 +1683,26 @@ static int __devinit at91udc_probe(struct platform_device *pdev) if (retval < 0) goto fail0; - /* disable everything until there's a gadget driver and vbus */ - pullup(udc, 0); + /* don't do anything until we have both gadget driver and VBUS */ + clk_enable(udc->iclk); + at91_udp_write(AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS); + at91_udp_write(AT91_UDP_IDR, 0xffffffff); + clk_disable(udc->iclk); /* request UDC and maybe VBUS irqs */ - if (request_irq(AT91_ID_UDP, at91_udc_irq, IRQF_DISABLED, driver_name, udc)) { - DBG("request irq %d failed\n", AT91_ID_UDP); + udc->udp_irq = platform_get_irq(pdev, 0); + if (request_irq(udc->udp_irq, at91_udc_irq, + IRQF_DISABLED, driver_name, udc)) { + DBG("request irq %d failed\n", udc->udp_irq); retval = -EBUSY; goto fail1; } if (udc->board.vbus_pin > 0) { - if (request_irq(udc->board.vbus_pin, at91_vbus_irq, IRQF_DISABLED, driver_name, udc)) { - DBG("request vbus irq %d failed\n", udc->board.vbus_pin); - free_irq(AT91_ID_UDP, udc); + if (request_irq(udc->board.vbus_pin, at91_vbus_irq, + IRQF_DISABLED, driver_name, udc)) { + DBG("request vbus irq %d failed\n", + udc->board.vbus_pin); + free_irq(udc->udp_irq, udc); retval = -EBUSY; goto fail1; } @@ -1670,6 +1711,7 @@ static int __devinit at91udc_probe(struct platform_device *pdev) udc->vbus = 1; } dev_set_drvdata(dev, udc); + device_init_wakeup(dev, 1); create_debug_file(udc); INFO("%s version %s\n", driver_name, DRIVER_VERSION); @@ -1678,14 +1720,14 @@ static int __devinit at91udc_probe(struct platform_device *pdev) fail1: device_unregister(&udc->gadget.dev); fail0: - release_mem_region(AT91_VA_BASE_UDP, SZ_16K); + release_mem_region(AT91_BASE_UDP, SZ_16K); DBG("%s probe failed, %d\n", driver_name, retval); return retval; } -static int __devexit at91udc_remove(struct platform_device *dev) +static int __devexit at91udc_remove(struct platform_device *pdev) { - struct at91_udc *udc = platform_get_drvdata(dev); + struct at91_udc *udc = platform_get_drvdata(pdev); DBG("remove\n"); @@ -1694,10 +1736,11 @@ static int __devexit at91udc_remove(struct platform_device *dev) if (udc->driver != 0) usb_gadget_unregister_driver(udc->driver); + device_init_wakeup(&pdev->dev, 0); remove_debug_file(udc); if (udc->board.vbus_pin > 0) free_irq(udc->board.vbus_pin, udc); - free_irq(AT91_ID_UDP, udc); + free_irq(udc->udp_irq, udc); device_unregister(&udc->gadget.dev); release_mem_region(AT91_BASE_UDP, SZ_16K); @@ -1708,31 +1751,36 @@ static int __devexit at91udc_remove(struct platform_device *dev) } #ifdef CONFIG_PM -static int at91udc_suspend(struct platform_device *dev, pm_message_t mesg) +static int at91udc_suspend(struct platform_device *pdev, pm_message_t mesg) { - struct at91_udc *udc = platform_get_drvdata(dev); + struct at91_udc *udc = platform_get_drvdata(pdev); + int wake = udc->driver && device_may_wakeup(&pdev->dev); - /* - * The "safe" suspend transitions are opportunistic ... e.g. when - * the USB link is suspended (48MHz clock autogated off), or when - * it's disconnected (programmatically gated off, elsewhere). - * Then we can suspend, and the chip can enter slow clock mode. - * - * The problem case is some component (user mode?) suspending this - * device while it's active, with the 48 MHz clock in use. There - * are two basic approaches: (a) veto suspend levels involving slow - * clock mode, (b) disconnect, so 48 MHz will no longer be in use - * and we can enter slow clock mode. This uses (b) for now, since - * it's simplest until AT91 PM exists and supports the other option. + /* Unless we can act normally to the host (letting it wake us up + * whenever it has work for us) force disconnect. Wakeup requires + * PLLB for USB events (signaling for reset, wakeup, or incoming + * tokens) and VBUS irqs (on systems which support them). */ - if (udc->vbus && !udc->suspended) + if ((!udc->suspended && udc->addr) + || !wake + || at91_suspend_entering_slow_clock()) { pullup(udc, 0); + disable_irq_wake(udc->udp_irq); + } else + enable_irq_wake(udc->udp_irq); + + if (udc->board.vbus_pin > 0) { + if (wake) + enable_irq_wake(udc->board.vbus_pin); + else + disable_irq_wake(udc->board.vbus_pin); + } return 0; } -static int at91udc_resume(struct platform_device *dev) +static int at91udc_resume(struct platform_device *pdev) { - struct at91_udc *udc = platform_get_drvdata(dev); + struct at91_udc *udc = platform_get_drvdata(pdev); /* maybe reconnect to host; if so, clocks on */ pullup(udc, 1); @@ -1748,7 +1796,7 @@ static struct platform_driver at91_udc = { .remove = __devexit_p(at91udc_remove), .shutdown = at91udc_shutdown, .suspend = at91udc_suspend, - .resume = at91udc_resume, + .resume = at91udc_resume, .driver = { .name = (char *) driver_name, .owner = THIS_MODULE, @@ -1767,6 +1815,6 @@ static void __devexit udc_exit_module(void) } module_exit(udc_exit_module); -MODULE_DESCRIPTION("AT91RM9200 udc driver"); +MODULE_DESCRIPTION("AT91 udc driver"); MODULE_AUTHOR("Thomas Rathbone, David Brownell"); MODULE_LICENSE("GPL"); diff --git a/drivers/usb/gadget/at91_udc.h b/drivers/usb/gadget/at91_udc.h index 5a4799c..882af42 100644 --- a/drivers/usb/gadget/at91_udc.h +++ b/drivers/usb/gadget/at91_udc.h @@ -141,6 +141,7 @@ struct at91_udc { struct clk *iclk, *fclk; struct platform_device *pdev; struct proc_dir_entry *pde; + int udp_irq; }; static inline struct at91_udc *to_udc(struct usb_gadget *g) -- cgit v1.1 From 0365ee0a8f7450c5e79302930d461e58161a96a1 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Mon, 19 Jun 2006 14:27:20 -0700 Subject: USB: AT91 OHCI updates, mostly power management OHCI updates for AT91 series processors: - Get ready for at91sam926x processors (ARMv5tej not ARMv4t) - Suspend/resume support now behaves properly - In "standby" mode, OHCI can be a source of system wakeup events (remote wakeup, device connect/disconnect, etc) And minor cleanups. Signed-off-by: David Brownell Signed-off-by: Andrew Victor Signed-off-by: Greg Kroah-Hartman --- drivers/usb/Kconfig | 2 +- drivers/usb/host/ohci-at91.c | 88 +++++++++++++++++++++++++++++--------------- drivers/usb/host/ohci-hcd.c | 3 +- 3 files changed, 62 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index 2ee742d..0050431 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -24,7 +24,7 @@ config USB_ARCH_HAS_OHCI default y if ARCH_S3C2410 default y if PXA27x default y if ARCH_EP93XX - default y if ARCH_AT91RM9200 + default y if (ARCH_AT91RM9200 || ARCH_AT91SAM9261) # PPC: default y if STB03xxx default y if PPC_MPC52xx diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index cdbafb7..85cc059 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -4,7 +4,7 @@ * Copyright (C) 2004 SAN People (Pty) Ltd. * Copyright (C) 2005 Thibaut VARENE * - * AT91RM9200 Bus Glue + * AT91 Bus Glue * * Based on fragments of 2.4 driver by Rick Bronson. * Based on ohci-omap.c @@ -19,12 +19,13 @@ #include #include -#ifndef CONFIG_ARCH_AT91RM9200 -#error "CONFIG_ARCH_AT91RM9200 must be defined." +#ifndef CONFIG_ARCH_AT91 +#error "CONFIG_ARCH_AT91 must be defined." #endif /* interface and function clocks */ static struct clk *iclk, *fclk; +static int clocked; extern int usb_disabled(void); @@ -35,13 +36,14 @@ static void at91_start_hc(struct platform_device *pdev) struct usb_hcd *hcd = platform_get_drvdata(pdev); struct ohci_regs __iomem *regs = hcd->regs; - dev_dbg(&pdev->dev, "starting AT91RM9200 OHCI USB Controller\n"); + dev_dbg(&pdev->dev, "start\n"); /* * Start the USB clocks. */ clk_enable(iclk); clk_enable(fclk); + clocked = 1; /* * The USB host controller must remain in reset. @@ -54,7 +56,7 @@ static void at91_stop_hc(struct platform_device *pdev) struct usb_hcd *hcd = platform_get_drvdata(pdev); struct ohci_regs __iomem *regs = hcd->regs; - dev_dbg(&pdev->dev, "stopping AT91RM9200 OHCI USB Controller\n"); + dev_dbg(&pdev->dev, "stop\n"); /* * Put the USB host controller into reset. @@ -66,6 +68,7 @@ static void at91_stop_hc(struct platform_device *pdev) */ clk_disable(fclk); clk_disable(iclk); + clocked = 0; } @@ -78,14 +81,15 @@ static int usb_hcd_at91_remove (struct usb_hcd *, struct platform_device *); /** - * usb_hcd_at91_probe - initialize AT91RM9200-based HCDs + * usb_hcd_at91_probe - initialize AT91-based HCDs * Context: !in_interrupt() * * Allocates basic resources for this USB host controller, and * then invokes the start() method for the HCD associated with it * through the hotplug entry's driver_data. */ -int usb_hcd_at91_probe (const struct hc_driver *driver, struct platform_device *pdev) +static int usb_hcd_at91_probe(const struct hc_driver *driver, + struct platform_device *pdev) { int retval; struct usb_hcd *hcd = NULL; @@ -95,12 +99,13 @@ int usb_hcd_at91_probe (const struct hc_driver *driver, struct platform_device * return -ENODEV; } - if ((pdev->resource[0].flags != IORESOURCE_MEM) || (pdev->resource[1].flags != IORESOURCE_IRQ)) { + if ((pdev->resource[0].flags != IORESOURCE_MEM) + || (pdev->resource[1].flags != IORESOURCE_IRQ)) { pr_debug("hcd probe: invalid resource type\n"); return -ENODEV; } - hcd = usb_create_hcd(driver, &pdev->dev, "at91rm9200"); + hcd = usb_create_hcd(driver, &pdev->dev, "at91"); if (!hcd) return -ENOMEM; hcd->rsrc_start = pdev->resource[0].start; @@ -149,21 +154,23 @@ int usb_hcd_at91_probe (const struct hc_driver *driver, struct platform_device * /* may be called with controller, bus, and devices active */ /** - * usb_hcd_at91_remove - shutdown processing for AT91RM9200-based HCDs + * usb_hcd_at91_remove - shutdown processing for AT91-based HCDs * @dev: USB Host Controller being removed * Context: !in_interrupt() * * Reverses the effect of usb_hcd_at91_probe(), first invoking * the HCD's stop() method. It is always called from a thread - * context, normally "rmmod", "apmd", or something similar. + * context, "rmmod" or something similar. * */ -static int usb_hcd_at91_remove (struct usb_hcd *hcd, struct platform_device *pdev) +static int usb_hcd_at91_remove(struct usb_hcd *hcd, + struct platform_device *pdev) { usb_remove_hcd(hcd); at91_stop_hc(pdev); iounmap(hcd->regs); release_mem_region(hcd->rsrc_start, hcd->rsrc_len); + disable_irq_wake(hcd->irq); clk_put(fclk); clk_put(iclk); @@ -178,19 +185,21 @@ static int usb_hcd_at91_remove (struct usb_hcd *hcd, struct platform_device *pde static int __devinit ohci_at91_start (struct usb_hcd *hcd) { -// struct at91_ohci_data *board = hcd->self.controller->platform_data; + struct at91_usbh_data *board = hcd->self.controller->platform_data; struct ohci_hcd *ohci = hcd_to_ohci (hcd); + struct usb_device *root = hcd->self.root_hub; int ret; if ((ret = ohci_init(ohci)) < 0) return ret; + root->maxchild = board->ports; + if ((ret = ohci_run(ohci)) < 0) { err("can't start %s", hcd->self.bus_name); ohci_stop(hcd); return ret; } -// hcd->self.root_hub->maxchild = board->ports; return 0; } @@ -198,7 +207,7 @@ ohci_at91_start (struct usb_hcd *hcd) static const struct hc_driver ohci_at91_hc_driver = { .description = hcd_name, - .product_desc = "AT91RM9200 OHCI", + .product_desc = "AT91 OHCI", .hcd_priv_size = sizeof(struct ohci_hcd), /* @@ -240,33 +249,54 @@ static const struct hc_driver ohci_at91_hc_driver = { /*-------------------------------------------------------------------------*/ -static int ohci_hcd_at91_drv_probe(struct platform_device *dev) +static int ohci_hcd_at91_drv_probe(struct platform_device *pdev) { - return usb_hcd_at91_probe(&ohci_at91_hc_driver, dev); + device_init_wakeup(&pdev->dev, 1); + return usb_hcd_at91_probe(&ohci_at91_hc_driver, pdev); } -static int ohci_hcd_at91_drv_remove(struct platform_device *dev) +static int ohci_hcd_at91_drv_remove(struct platform_device *pdev) { - return usb_hcd_at91_remove(platform_get_drvdata(dev), dev); + device_init_wakeup(&pdev->dev, 0); + return usb_hcd_at91_remove(platform_get_drvdata(pdev), pdev); } #ifdef CONFIG_PM -/* REVISIT suspend/resume look "too" simple here */ - static int -ohci_hcd_at91_drv_suspend(struct platform_device *dev, pm_message_t mesg) +ohci_hcd_at91_drv_suspend(struct platform_device *pdev, pm_message_t mesg) { - clk_disable(fclk); - clk_disable(iclk); + struct usb_hcd *hcd = platform_get_drvdata(pdev); + struct ohci_hcd *ohci = hcd_to_ohci(hcd); + + if (device_may_wakeup(&pdev->dev)) + enable_irq_wake(hcd->irq); + else + disable_irq_wake(hcd->irq); + + /* + * The integrated transceivers seem unable to notice disconnect, + * reconnect, or wakeup without the 48 MHz clock active. so for + * correctness, always discard connection state (using reset). + * + * REVISIT: some boards will be able to turn VBUS off... + */ + if (at91_suspend_entering_slow_clock()) { + ohci_usb_reset (ohci); + clk_disable(fclk); + clk_disable(iclk); + clocked = 0; + } return 0; } -static int ohci_hcd_at91_drv_resume(struct platform_device *dev) +static int ohci_hcd_at91_drv_resume(struct platform_device *pdev) { - clk_enable(iclk); - clk_enable(fclk); + if (!clocked) { + clk_enable(iclk); + clk_enable(fclk); + } return 0; } @@ -275,7 +305,7 @@ static int ohci_hcd_at91_drv_resume(struct platform_device *dev) #define ohci_hcd_at91_drv_resume NULL #endif -MODULE_ALIAS("at91rm9200-ohci"); +MODULE_ALIAS("at91_ohci"); static struct platform_driver ohci_hcd_at91_driver = { .probe = ohci_hcd_at91_drv_probe, @@ -283,7 +313,7 @@ static struct platform_driver ohci_hcd_at91_driver = { .suspend = ohci_hcd_at91_drv_suspend, .resume = ohci_hcd_at91_drv_resume, .driver = { - .name = "at91rm9200-ohci", + .name = "at91_ohci", .owner = THIS_MODULE, }, }; diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index afef5ac..94d8cf4 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -913,7 +913,7 @@ MODULE_LICENSE ("GPL"); #include "ohci-ppc-soc.c" #endif -#ifdef CONFIG_ARCH_AT91RM9200 +#if defined(CONFIG_ARCH_AT91RM9200) || defined(CONFIG_ARCH_AT91SAM9261) #include "ohci-at91.c" #endif @@ -927,6 +927,7 @@ MODULE_LICENSE ("GPL"); || defined (CONFIG_SOC_AU1X00) \ || defined (CONFIG_USB_OHCI_HCD_PPC_SOC) \ || defined (CONFIG_ARCH_AT91RM9200) \ + || defined (CONFIG_ARCH_AT91SAM9261) \ ) #error "missing bus glue for ohci-hcd" #endif -- cgit v1.1 From b3fdab59b8f5d8e42fa339be74cd015dc1a3192f Mon Sep 17 00:00:00 2001 From: Matthias Urlichs Date: Wed, 2 Aug 2006 16:41:41 -0700 Subject: USB: Option driver: removed change history and linux/version.h include Signed-off-by: Matthias Urlichs Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 28 +--------------------------- 1 file changed, 1 insertion(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index f0530c1..2a07945 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -9,33 +9,7 @@ Portions copied from the Keyspan driver by Hugh Blemings - History: - - 2005-05-19 v0.1 Initial version, based on incomplete docs - and analysis of misbehavior with the standard driver - 2005-05-20 v0.2 Extended the input buffer to avoid losing - random 64-byte chunks of data - 2005-05-21 v0.3 implemented chars_in_buffer() - turned on low_latency - simplified the code somewhat - 2005-05-24 v0.4 option_write() sometimes deadlocked under heavy load - removed some dead code - added sponsor notice - coding style clean-up - 2005-06-20 v0.4.1 add missing braces :-/ - killed end-of-line whitespace - 2005-07-15 v0.4.2 rename WLAN product to FUSION, add FUSION2 - 2005-09-10 v0.4.3 added HUAWEI E600 card and Audiovox AirCard - 2005-09-20 v0.4.4 increased recv buffer size: the card sometimes - wants to send >2000 bytes. - 2006-04-10 v0.5 fixed two array overrun errors :-/ - 2006-04-21 v0.5.1 added support for Sierra Wireless MC8755 - 2006-05-15 v0.6 re-enable multi-port support - 2006-06-01 v0.6.1 add COBRA - 2006-06-01 v0.6.2 add backwards-compatibility stuff - 2006-06-01 v0.6.3 add Novatel Wireless - 2006-06-01 v0.7 Option => GSM - 2006-06-01 v0.7.1 add COBRA2 + History: see the git log. Work sponsored by: Sigos GmbH, Germany -- cgit v1.1 From 02b2ac5b0370b1157a5a99f2fdf006644b9b86d5 Mon Sep 17 00:00:00 2001 From: Matthias Urlichs Date: Wed, 2 Aug 2006 16:41:41 -0700 Subject: USB: Option driver: Short driver names were identical The short driver names were not unique, which prevented the driver from actually loading. Also, one of the ioctl pointers was missing. Signed-Off-By: Matthias Urlichs Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 2a07945..283383d 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -128,7 +128,7 @@ static struct usb_driver option_driver = { static struct usb_serial_driver option_3port_device = { .driver = { .owner = THIS_MODULE, - .name = "option", + .name = "option3", }, .description = "GSM modem (3-port)", .id_table = option_ids3, @@ -143,6 +143,7 @@ static struct usb_serial_driver option_3port_device = { .chars_in_buffer = option_chars_in_buffer, .throttle = option_rx_throttle, .unthrottle = option_rx_unthrottle, + .ioctl = option_ioctl, .set_termios = option_set_termios, .break_ctl = option_break_ctl, .tiocmget = option_tiocmget, @@ -155,7 +156,7 @@ static struct usb_serial_driver option_3port_device = { static struct usb_serial_driver option_1port_device = { .driver = { .owner = THIS_MODULE, - .name = "option", + .name = "option1", }, .description = "GSM modem (1-port)", .id_table = option_ids1, @@ -630,7 +631,6 @@ static void option_setup_urbs(struct usb_serial *serial) dbg("%s", __FUNCTION__); - for (i = 0; i < serial->num_ports; i++) { port = serial->port[i]; portdata = usb_get_serial_port_data(port); -- cgit v1.1 From 31fcbb733812bca52e8bee96d62ba56df0fc408b Mon Sep 17 00:00:00 2001 From: Matthias Urlichs Date: Wed, 12 Jul 2006 08:35:29 +0200 Subject: USB: Let option driver handle Anydata CDMA modems. Remove anydata driver. Signed-off-by: Jon K Hellan Signed-Off-By: Matthias Urlichs Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/Kconfig | 24 ++++----- drivers/usb/serial/Makefile | 1 - drivers/usb/serial/anydata.c | 123 ------------------------------------------- drivers/usb/serial/option.c | 4 ++ 4 files changed, 13 insertions(+), 139 deletions(-) delete mode 100644 drivers/usb/serial/anydata.c (limited to 'drivers') diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index ac33bd4..f5b9438 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -62,15 +62,6 @@ config USB_SERIAL_AIRPRIME To compile this driver as a module, choose M here: the module will be called airprime. -config USB_SERIAL_ANYDATA - tristate "USB AnyData CDMA Wireless Driver" - depends on USB_SERIAL - help - Say Y here if you want to use a AnyData CDMA device. - - To compile this driver as a module, choose M here: the - module will be called anydata. - config USB_SERIAL_ARK3116 tristate "USB ARK Micro 3116 USB Serial Driver (EXPERIMENTAL)" depends on USB_SERIAL && EXPERIMENTAL @@ -502,15 +493,18 @@ config USB_SERIAL_XIRCOM module will be called keyspan_pda. config USB_SERIAL_OPTION - tristate "USB driver for GSM modems" + tristate "USB driver for GSM and CDMA modems" depends on USB_SERIAL help - Say Y here if you have an "Option" GSM PCMCIA card - (or an OEM version: branded Huawei, Audiovox, or Novatel). + Say Y here if you have a GSM or CDMA modem that's connected to USB. + + This driver also supports several PCMCIA cards which have a + built-in OHCI-USB adapter and an internally-connected GSM modem. + The USB bus on these cards is not accessible externally. - These cards feature a built-in OHCI-USB adapter and an - internally-connected GSM modem. The USB bus is not - accessible externally. + Supported devices include (some of?) those made by: + Option, Huawei, Audiovox, Sierra Wireless, Novatel Wireless, or + Anydata. To compile this driver as a module, choose M here: the module will be called option. diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile index 35d4acc..8efed2c 100644 --- a/drivers/usb/serial/Makefile +++ b/drivers/usb/serial/Makefile @@ -12,7 +12,6 @@ usbserial-obj-$(CONFIG_USB_EZUSB) += ezusb.o usbserial-objs := usb-serial.o generic.o bus.o $(usbserial-obj-y) obj-$(CONFIG_USB_SERIAL_AIRPRIME) += airprime.o -obj-$(CONFIG_USB_SERIAL_ANYDATA) += anydata.o obj-$(CONFIG_USB_SERIAL_ARK3116) += ark3116.o obj-$(CONFIG_USB_SERIAL_BELKIN) += belkin_sa.o obj-$(CONFIG_USB_SERIAL_CP2101) += cp2101.o diff --git a/drivers/usb/serial/anydata.c b/drivers/usb/serial/anydata.c deleted file mode 100644 index 01843ef..0000000 --- a/drivers/usb/serial/anydata.c +++ /dev/null @@ -1,123 +0,0 @@ -/* - * AnyData CDMA Serial USB driver - * - * Copyright (C) 2005 Greg Kroah-Hartman - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include - -static struct usb_device_id id_table [] = { - { USB_DEVICE(0x16d5, 0x6501) }, /* AirData CDMA device */ - { }, -}; -MODULE_DEVICE_TABLE(usb, id_table); - -/* if overridden by the user, then use their value for the size of the - * read and write urbs */ -static int buffer_size; -static int debug; - -static struct usb_driver anydata_driver = { - .name = "anydata", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, - .no_dynamic_id = 1, -}; - -static int anydata_open(struct usb_serial_port *port, struct file *filp) -{ - char *buffer; - int result = 0; - - dbg("%s - port %d", __FUNCTION__, port->number); - - if (buffer_size) { - /* override the default buffer sizes */ - buffer = kmalloc(buffer_size, GFP_KERNEL); - if (!buffer) { - dev_err(&port->dev, "%s - out of memory.\n", - __FUNCTION__); - return -ENOMEM; - } - kfree (port->read_urb->transfer_buffer); - port->read_urb->transfer_buffer = buffer; - port->read_urb->transfer_buffer_length = buffer_size; - - buffer = kmalloc(buffer_size, GFP_KERNEL); - if (!buffer) { - dev_err(&port->dev, "%s - out of memory.\n", - __FUNCTION__); - return -ENOMEM; - } - kfree (port->write_urb->transfer_buffer); - port->write_urb->transfer_buffer = buffer; - port->write_urb->transfer_buffer_length = buffer_size; - port->bulk_out_size = buffer_size; - } - - /* Start reading from the device */ - usb_fill_bulk_urb(port->read_urb, port->serial->dev, - usb_rcvbulkpipe(port->serial->dev, - port->bulk_in_endpointAddress), - port->read_urb->transfer_buffer, - port->read_urb->transfer_buffer_length, - usb_serial_generic_read_bulk_callback, port); - result = usb_submit_urb(port->read_urb, GFP_KERNEL); - if (result) - dev_err(&port->dev, - "%s - failed submitting read urb, error %d\n", - __FUNCTION__, result); - - return result; -} - -static struct usb_serial_driver anydata_device = { - .driver = { - .owner = THIS_MODULE, - .name = "anydata", - }, - .id_table = id_table, - .num_interrupt_in = NUM_DONT_CARE, - .num_bulk_in = NUM_DONT_CARE, - .num_bulk_out = NUM_DONT_CARE, - .num_ports = 1, - .open = anydata_open, -}; - -static int __init anydata_init(void) -{ - int retval; - - retval = usb_serial_register(&anydata_device); - if (retval) - return retval; - retval = usb_register(&anydata_driver); - if (retval) - usb_serial_deregister(&anydata_device); - return retval; -} - -static void __exit anydata_exit(void) -{ - usb_deregister(&anydata_driver); - usb_serial_deregister(&anydata_device); -} - -module_init(anydata_init); -module_exit(anydata_exit); -MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); -module_param(buffer_size, int, 0); -MODULE_PARM_DESC(buffer_size, "Size of the transfer buffers"); diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 283383d..b020f13 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -72,6 +72,7 @@ static int option_send_setup(struct usb_serial_port *port); #define AUDIOVOX_VENDOR_ID 0x0F3D #define SIERRAWIRELESS_VENDOR_ID 0x1199 #define NOVATELWIRELESS_VENDOR_ID 0x1410 +#define ANYDATA_VENDOR_ID 0x16d5 #define OPTION_PRODUCT_OLD 0x5000 #define OPTION_PRODUCT_FUSION 0x6000 @@ -82,6 +83,7 @@ static int option_send_setup(struct usb_serial_port *port); #define AUDIOVOX_PRODUCT_AIRCARD 0x0112 #define SIERRAWIRELESS_PRODUCT_MC8755 0x6802 #define NOVATELWIRELESS_PRODUCT_U740 0x1400 +#define ANYDATA_PRODUCT_ID 0x6501 static struct usb_device_id option_ids[] = { { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_OLD) }, @@ -93,6 +95,7 @@ static struct usb_device_id option_ids[] = { { USB_DEVICE(AUDIOVOX_VENDOR_ID, AUDIOVOX_PRODUCT_AIRCARD) }, { USB_DEVICE(SIERRAWIRELESS_VENDOR_ID, SIERRAWIRELESS_PRODUCT_MC8755) }, { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID,NOVATELWIRELESS_PRODUCT_U740) }, + { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ID) }, { } /* Terminating entry */ }; @@ -105,6 +108,7 @@ static struct usb_device_id option_ids1[] = { { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) }, { USB_DEVICE(AUDIOVOX_VENDOR_ID, AUDIOVOX_PRODUCT_AIRCARD) }, { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID,NOVATELWIRELESS_PRODUCT_U740) }, + { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ID) }, { } /* Terminating entry */ }; static struct usb_device_id option_ids3[] = { -- cgit v1.1 From 7c1c2f73e00b5d0413399a14b7ab9e80db94926f Mon Sep 17 00:00:00 2001 From: Matthias Urlichs Date: Thu, 20 Jul 2006 04:56:00 +0200 Subject: USB: Drop Sierra Wireless MC8755 from the Option driver This device is now supported by sierra.c. From: Matthias Urlichs Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index b020f13..1df36cb 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -16,7 +16,7 @@ This driver exists because the "normal" serial driver doesn't work too well with GSM modems. Issues: - data loss -- one single Receive URB is not nearly enough - - nonstandard flow (Option devices) and multiplex (Sierra) control + - nonstandard flow (Option devices) control - controlling the baud rate doesn't make sense This driver is named "option" because the most common device it's @@ -70,7 +70,6 @@ static int option_send_setup(struct usb_serial_port *port); #define OPTION_VENDOR_ID 0x0AF0 #define HUAWEI_VENDOR_ID 0x12D1 #define AUDIOVOX_VENDOR_ID 0x0F3D -#define SIERRAWIRELESS_VENDOR_ID 0x1199 #define NOVATELWIRELESS_VENDOR_ID 0x1410 #define ANYDATA_VENDOR_ID 0x16d5 @@ -81,7 +80,6 @@ static int option_send_setup(struct usb_serial_port *port); #define OPTION_PRODUCT_COBRA2 0x6600 #define HUAWEI_PRODUCT_E600 0x1001 #define AUDIOVOX_PRODUCT_AIRCARD 0x0112 -#define SIERRAWIRELESS_PRODUCT_MC8755 0x6802 #define NOVATELWIRELESS_PRODUCT_U740 0x1400 #define ANYDATA_PRODUCT_ID 0x6501 @@ -93,7 +91,6 @@ static struct usb_device_id option_ids[] = { { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA2) }, { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) }, { USB_DEVICE(AUDIOVOX_VENDOR_ID, AUDIOVOX_PRODUCT_AIRCARD) }, - { USB_DEVICE(SIERRAWIRELESS_VENDOR_ID, SIERRAWIRELESS_PRODUCT_MC8755) }, { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID,NOVATELWIRELESS_PRODUCT_U740) }, { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ID) }, { } /* Terminating entry */ @@ -112,7 +109,6 @@ static struct usb_device_id option_ids1[] = { { } /* Terminating entry */ }; static struct usb_device_id option_ids3[] = { - { USB_DEVICE(SIERRAWIRELESS_VENDOR_ID, SIERRAWIRELESS_PRODUCT_MC8755) }, { } /* Terminating entry */ }; -- cgit v1.1 From a01c452ee3a185a35140939c6dca08d77240b863 Mon Sep 17 00:00:00 2001 From: Matthias Urlichs Date: Thu, 20 Jul 2006 05:01:21 +0200 Subject: USB: Removed 3-port device handler from Option driver Dead code. From: Matthias Urlichs Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 36 ------------------------------------ 1 file changed, 36 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 1df36cb..c856e6f 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -108,9 +108,6 @@ static struct usb_device_id option_ids1[] = { { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ID) }, { } /* Terminating entry */ }; -static struct usb_device_id option_ids3[] = { - { } /* Terminating entry */ -}; MODULE_DEVICE_TABLE(usb, option_ids); @@ -125,33 +122,6 @@ static struct usb_driver option_driver = { /* The card has three separate interfaces, which the serial driver * recognizes separately, thus num_port=1. */ -static struct usb_serial_driver option_3port_device = { - .driver = { - .owner = THIS_MODULE, - .name = "option3", - }, - .description = "GSM modem (3-port)", - .id_table = option_ids3, - .num_interrupt_in = NUM_DONT_CARE, - .num_bulk_in = NUM_DONT_CARE, - .num_bulk_out = NUM_DONT_CARE, - .num_ports = 3, - .open = option_open, - .close = option_close, - .write = option_write, - .write_room = option_write_room, - .chars_in_buffer = option_chars_in_buffer, - .throttle = option_rx_throttle, - .unthrottle = option_rx_unthrottle, - .ioctl = option_ioctl, - .set_termios = option_set_termios, - .break_ctl = option_break_ctl, - .tiocmget = option_tiocmget, - .tiocmset = option_tiocmset, - .attach = option_startup, - .shutdown = option_shutdown, - .read_int_callback = option_instat_callback, -}; static struct usb_serial_driver option_1port_device = { .driver = { @@ -220,9 +190,6 @@ static int __init option_init(void) retval = usb_serial_register(&option_1port_device); if (retval) goto failed_1port_device_register; - retval = usb_serial_register(&option_3port_device); - if (retval) - goto failed_3port_device_register; retval = usb_register(&option_driver); if (retval) goto failed_driver_register; @@ -232,8 +199,6 @@ static int __init option_init(void) return 0; failed_driver_register: - usb_serial_deregister (&option_3port_device); -failed_3port_device_register: usb_serial_deregister (&option_1port_device); failed_1port_device_register: return retval; @@ -242,7 +207,6 @@ failed_1port_device_register: static void __exit option_exit(void) { usb_deregister (&option_driver); - usb_serial_deregister (&option_3port_device); usb_serial_deregister (&option_1port_device); } -- cgit v1.1 From a11570f2a48cbb6e10c520b46193e7b1b4b9245c Mon Sep 17 00:00:00 2001 From: Li Yang Date: Fri, 14 Jul 2006 19:58:14 +0800 Subject: USB: Fix Freescale high-speed USB host dependency The high-speed USB SOC only exists on MPC834x family not MPC83xx family. Signed-off-by: Li Yang Acked-by: Kumar Gala Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-hcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 85b0b4a..d63177a 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -892,7 +892,7 @@ MODULE_LICENSE ("GPL"); #define PCI_DRIVER ehci_pci_driver #endif -#ifdef CONFIG_PPC_83xx +#ifdef CONFIG_MPC834x #include "ehci-fsl.c" #define PLATFORM_DRIVER ehci_fsl_driver #endif -- cgit v1.1 From aec0d50b8a86bf04ea8e5885fef4f498d5d3168c Mon Sep 17 00:00:00 2001 From: Norihiko Tomiyama Date: Thu, 13 Jul 2006 09:43:02 +0900 Subject: USB: adding support for SHARP WS003SH to ipaq.c This small patch enables a support of "SHARP WS003SH". "SHARP WS003SH" (usullary called "W-ZERO3") is most polular All-in-one handheld CellPhone-plus-WindowsMobile5.0 in Japan. "SHARP WS003SH" has two modes, "Modem" and "ActiveSync". But, "ActiveSync" mode uses NDIS connection. Therefore, ipaq.c can only support "Modem" mode. http://www.sharp.co.jp/ws/ (Japanese Site) http://greggman.com/edit/editheadlines/2005-12-24.htm From: Norihiko Tomiyama Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ipaq.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c index 59c5d99..7e1bd5d 100644 --- a/drivers/usb/serial/ipaq.c +++ b/drivers/usb/serial/ipaq.c @@ -250,6 +250,7 @@ static struct usb_device_id ipaq_id_table [] = { { USB_DEVICE(0x04C5, 0x1058) }, /* FUJITSU USB Sync */ { USB_DEVICE(0x04C5, 0x1079) }, /* FUJITSU USB Sync */ { USB_DEVICE(0x04DA, 0x2500) }, /* Panasonic USB Sync */ + { USB_DEVICE(0x04DD, 0x9102) }, /* SHARP WS003SH USB Modem */ { USB_DEVICE(0x04E8, 0x5F00) }, /* Samsung NEXiO USB Sync */ { USB_DEVICE(0x04E8, 0x5F01) }, /* Samsung NEXiO USB Sync */ { USB_DEVICE(0x04E8, 0x5F02) }, /* Samsung NEXiO USB Sync */ -- cgit v1.1 From 274a4bbc9df34d83485e67ad5200a43bd3c69600 Mon Sep 17 00:00:00 2001 From: Dave Platt Date: Tue, 18 Jul 2006 21:26:54 -0700 Subject: USB: Additional PID for the ftdi_sio driver Here's a short patch which adds one PID to the set of devices supported by the ftdi_sio driver. The device in question is a DLP module used as part of a ham radio USB-to-packet adapter. From: Dave Platt Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 1 + drivers/usb/serial/ftdi_sio.h | 4 ++++ 2 files changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index b458aed..a20da85 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -337,6 +337,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_MTXORB_6_PID) }, { USB_DEVICE(FTDI_VID, FTDI_PERLE_ULTRAPORT_PID) }, { USB_DEVICE(FTDI_VID, FTDI_PIEGROUP_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_TNC_X_PID) }, { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2101_PID) }, { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2102_PID) }, { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2103_PID) }, diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index 04ef90f..9f7343a 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h @@ -182,6 +182,10 @@ /* http://home.earthlink.net/~jrhees/USBUIRT/index.htm */ #define FTDI_USB_UIRT_PID 0xF850 /* Product Id */ +/* TNC-X USB-to-packet-radio adapter, versions prior to 3.0 (DLP module) */ + +#define FTDI_TNC_X_PID 0xEBE0 + /* * ELV USB devices submitted by Christian Abt of ELV (www.elv.de). * All of these devices use FTDI's vendor ID (0x0403). -- cgit v1.1 From b7aa94b682dc6b6dcdc01d36f8e65cef5aae81e2 Mon Sep 17 00:00:00 2001 From: Kim Oldfield Date: Tue, 25 Jul 2006 15:54:59 +1000 Subject: USB: New USB ID for Belkin Serial Adapter Can you add the USB IDs for the Belkin USB Serial adapter (P/N F5U257) to the pl2303 driver in the Linux Kernel? Are you the appropriate person to approach for this? I recently purchased a Belkin USB Serial adapter (P/N F5U257) and found that it didn't work. After a bit of experimentation I found that it works with the pl2303 driver once the ID has been added. See attached patch to fix this. Also attached is the output from lsusb -v just in case you require any information from there. From: Kim Oldfield Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/pl2303.c | 1 + drivers/usb/serial/pl2303.h | 4 ++++ 2 files changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 259db31..efbbc0a 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -81,6 +81,7 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(SPEEDDRAGON_VENDOR_ID, SPEEDDRAGON_PRODUCT_ID) }, { USB_DEVICE(OTI_VENDOR_ID, OTI_PRODUCT_ID) }, { USB_DEVICE(DATAPILOT_U2_VENDOR_ID, DATAPILOT_U2_PRODUCT_ID) }, + { USB_DEVICE(BELKIN_VENDOR_ID, BELKIN_PRODUCT_ID) }, { } /* Terminating entry */ }; diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h index d9c1e6e..a692ac6 100644 --- a/drivers/usb/serial/pl2303.h +++ b/drivers/usb/serial/pl2303.h @@ -89,3 +89,7 @@ /* DATAPILOT Universal-2 Phone Cable */ #define DATAPILOT_U2_VENDOR_ID 0x0731 #define DATAPILOT_U2_PRODUCT_ID 0x2003 + +/* Belkin "F5U257" Serial Adapter */ +#define BELKIN_VENDOR_ID 0x050d +#define BELKIN_PRODUCT_ID 0x0257 -- cgit v1.1 From 3c332422f78159a0f5e4bc5f0ed8bbcbf51d9462 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Wed, 26 Jul 2006 13:59:23 +0100 Subject: usb-storage: Add US_FL_IGNORE_DEVICE flag; ignore ZyXEL G220F This patch adds a new unusual_devs flag for when usb-storage needs to ignore a device that it would otherwise claim. We need to ignore the ZyXEL G220F as it is a virtual CDROM drive which includes the windows driver for this USB-WLAN adapter. After the windows driver is installed on a windows system, it converts it into a WLAN adapter (by ejecting the virtual disc). The virtual CDROM is of no interest to Linux users. The zd1211rw driver will automatically perform the eject operation, we just need to ensure that usb-storage does not claim the device. Signed-off-by: Daniel Drake Signed-off-by: Matthew Dharm Signed-off-by: Phil Dibowitz Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/unusual_devs.h | 10 +++++++++- drivers/usb/storage/usb.c | 13 +++++++++++-- 2 files changed, 20 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index a5ca449..ca6c56f 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -1106,7 +1106,15 @@ UNUSUAL_DEV( 0x0a17, 0x006, 0x0000, 0xffff, "Optio S/S4", US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY ), - + +/* This is a virtual windows driver CD, which the zd1211rw driver automatically + * converts into a WLAN device. */ +UNUSUAL_DEV( 0x0ace, 0x2011, 0x0101, 0x0101, + "ZyXEL", + "G-220F USB-WLAN Install", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_IGNORE_DEVICE ), + #ifdef CONFIG_USB_STORAGE_ISD200 UNUSUAL_DEV( 0x0bf6, 0xa001, 0x0100, 0x0110, "ATI", diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index 5ee19be..8d7bdcb 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -483,7 +483,7 @@ static struct us_unusual_dev *find_unusual(const struct usb_device_id *id) } /* Get the unusual_devs entries and the string descriptors */ -static void get_device_info(struct us_data *us, const struct usb_device_id *id) +static int get_device_info(struct us_data *us, const struct usb_device_id *id) { struct usb_device *dev = us->pusb_dev; struct usb_interface_descriptor *idesc = @@ -500,6 +500,11 @@ static void get_device_info(struct us_data *us, const struct usb_device_id *id) unusual_dev->useTransport; us->flags = USB_US_ORIG_FLAGS(id->driver_info); + if (us->flags & US_FL_IGNORE_DEVICE) { + printk(KERN_INFO USB_STORAGE "device ignored\n"); + return -ENODEV; + } + /* * This flag is only needed when we're in high-speed, so let's * disable it if we're in full-speed @@ -541,6 +546,8 @@ static void get_device_info(struct us_data *us, const struct usb_device_id *id) msgs[msg], UTS_RELEASE); } + + return 0; } /* Get the transport settings */ @@ -969,7 +976,9 @@ static int storage_probe(struct usb_interface *intf, * of the match from the usb_device_id table, so we can find the * corresponding entry in the private table. */ - get_device_info(us, id); + result = get_device_info(us, id); + if (result) + goto BadDevice; /* Get the transport, protocol, and pipe settings */ result = get_transport(us); -- cgit v1.1 From eda30fdeec30aec05bc8d644eb6f2509fb5ad43c Mon Sep 17 00:00:00 2001 From: Phil Dibowitz Date: Wed, 26 Jul 2006 22:36:29 -0700 Subject: USB: unusual_devs device removal This entry has been a mystery for some time. I had sent this patch as an RFC a while ago, and now we've had two reports of this not being needed, so I'm removing it. In the event there are reports of breakage, we should revert this patch, but add a US_FL_NEED_OVERRIDE flag. Signed-off-by: Phil Dibowitz Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/unusual_devs.h | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index ca6c56f..0f0874f 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -627,18 +627,6 @@ UNUSUAL_DEV( 0x0595, 0x4343, 0x0000, 0x2210, "Digital Camera EX-20 DSC", US_SC_8070, US_PR_DEVICE, NULL, 0 ), -/* The entry was here before I took over, and had US_SC_RBC. It turns - * out that isn't needed. Additionally, Torsten Eriksson - * is able to use his device fine - * without this entry at all - but I don't suspect that will be true - * for all users (the protocol is likely needed), so is staying at - * this time. - Phil Dibowitz - */ -UNUSUAL_DEV( 0x059f, 0xa601, 0x0200, 0x0200, - "LaCie", - "USB Hard Disk", - US_SC_DEVICE, US_PR_CB, NULL, 0 ), - /* Submitted by Joel Bourquard * Some versions of this device need the SubClass and Protocol overrides * while others don't. -- cgit v1.1 From 6ad576bb6715c1da1bb5c2ce59c3747368bba41f Mon Sep 17 00:00:00 2001 From: Oliver Bock Date: Thu, 27 Jul 2006 21:34:58 +0200 Subject: USB: cypress driver comment updates Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/cypress_cy7c63.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/misc/cypress_cy7c63.c b/drivers/usb/misc/cypress_cy7c63.c index e091d32..a4062a6 100644 --- a/drivers/usb/misc/cypress_cy7c63.c +++ b/drivers/usb/misc/cypress_cy7c63.c @@ -12,8 +12,13 @@ * the single I/O ports of the device. * * Supported vendors: AK Modul-Bus Computer GmbH -* Supported devices: CY7C63001A-PC (to be continued...) -* Supported functions: Read/Write Ports (to be continued...) +* (Firmware "Port-Chip") +* +* Supported devices: CY7C63001A-PC +* CY7C63001C-PXC +* CY7C63001C-SXC +* +* Supported functions: Read/Write Ports * * * This program is free software; you can redistribute it and/or -- cgit v1.1 From 23219c134865d524357e9bb90e5badb422ac8fff Mon Sep 17 00:00:00 2001 From: Peter Chubb Date: Tue, 25 Jul 2006 20:39:14 +1000 Subject: USB: Patch for rtl8150 to fix unplug problems The RTL8150 driver currently crashes the kernel if the USB lead is unplugged while the device is active. The attached patch adds error handling to tell the network layer that the device has gone away when the device is unplugged. With this patch, the device can be plugged and unplugged to one's hearts' content, without crashing anything. Oh, I've also added rudimentary suspend and resume methods. Signed-off-by: Peter Chubb Acked-by: Petko Manolov Signed-off-by: Greg Kroah-Hartman --- drivers/usb/net/rtl8150.c | 83 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 71 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/net/rtl8150.c b/drivers/usb/net/rtl8150.c index e5e6e4f..bd09232 100644 --- a/drivers/usb/net/rtl8150.c +++ b/drivers/usb/net/rtl8150.c @@ -175,6 +175,8 @@ static inline struct sk_buff *pull_skb(rtl8150_t *); static void rtl8150_disconnect(struct usb_interface *intf); static int rtl8150_probe(struct usb_interface *intf, const struct usb_device_id *id); +static int rtl8150_suspend(struct usb_interface *intf, pm_message_t message); +static int rtl8150_resume(struct usb_interface *intf); static const char driver_name [] = "rtl8150"; @@ -183,6 +185,8 @@ static struct usb_driver rtl8150_driver = { .probe = rtl8150_probe, .disconnect = rtl8150_disconnect, .id_table = rtl8150_table, + .suspend = rtl8150_suspend, + .resume = rtl8150_resume }; /* @@ -238,9 +242,11 @@ static int async_set_registers(rtl8150_t * dev, u16 indx, u16 size) usb_fill_control_urb(dev->ctrl_urb, dev->udev, usb_sndctrlpipe(dev->udev, 0), (char *) &dev->dr, &dev->rx_creg, size, ctrl_callback, dev); - if ((ret = usb_submit_urb(dev->ctrl_urb, GFP_ATOMIC))) + if ((ret = usb_submit_urb(dev->ctrl_urb, GFP_ATOMIC))) { + if (ret == -ENODEV) + netif_device_detach(dev->netdev); err("control request submission failed: %d", ret); - else + } else set_bit(RX_REG_SET, &dev->flags); return ret; @@ -416,6 +422,7 @@ static void read_bulk_callback(struct urb *urb, struct pt_regs *regs) struct sk_buff *skb; struct net_device *netdev; u16 rx_stat; + int status; dev = urb->context; if (!dev) @@ -465,7 +472,10 @@ static void read_bulk_callback(struct urb *urb, struct pt_regs *regs) goon: usb_fill_bulk_urb(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1), dev->rx_skb->data, RTL8150_MTU, read_bulk_callback, dev); - if (usb_submit_urb(dev->rx_urb, GFP_ATOMIC)) { + status = usb_submit_urb(dev->rx_urb, GFP_ATOMIC); + if (status == -ENODEV) + netif_device_detach(dev->netdev); + else if (status) { set_bit(RX_URB_FAIL, &dev->flags); goto resched; } else { @@ -481,6 +491,7 @@ static void rx_fixup(unsigned long data) { rtl8150_t *dev; struct sk_buff *skb; + int status; dev = (rtl8150_t *)data; @@ -499,10 +510,13 @@ static void rx_fixup(unsigned long data) usb_fill_bulk_urb(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1), dev->rx_skb->data, RTL8150_MTU, read_bulk_callback, dev); try_again: - if (usb_submit_urb(dev->rx_urb, GFP_ATOMIC)) { + status = usb_submit_urb(dev->rx_urb, GFP_ATOMIC); + if (status == -ENODEV) { + netif_device_detach(dev->netdev); + } else if (status) { set_bit(RX_URB_FAIL, &dev->flags); goto tlsched; - } else { + } else { clear_bit(RX_URB_FAIL, &dev->flags); } @@ -574,12 +588,43 @@ static void intr_callback(struct urb *urb, struct pt_regs *regs) resubmit: status = usb_submit_urb (urb, SLAB_ATOMIC); - if (status) + if (status == -ENODEV) + netif_device_detach(dev->netdev); + else if (status) err ("can't resubmit intr, %s-%s/input0, status %d", dev->udev->bus->bus_name, dev->udev->devpath, status); } +static int rtl8150_suspend(struct usb_interface *intf, pm_message_t message) +{ + rtl8150_t *dev = usb_get_intfdata(intf); + + netif_device_detach(dev->netdev); + + if (netif_running(dev->netdev)) { + usb_kill_urb(dev->rx_urb); + usb_kill_urb(dev->intr_urb); + } + return 0; +} + +static int rtl8150_resume(struct usb_interface *intf) +{ + rtl8150_t *dev = usb_get_intfdata(intf); + + netif_device_attach(dev->netdev); + if (netif_running(dev->netdev)) { + dev->rx_urb->status = 0; + dev->rx_urb->actual_length = 0; + read_bulk_callback(dev->rx_urb, NULL); + + dev->intr_urb->status = 0; + dev->intr_urb->actual_length = 0; + intr_callback(dev->intr_urb, NULL); + } + return 0; +} /* ** @@ -690,9 +735,14 @@ static int rtl8150_start_xmit(struct sk_buff *skb, struct net_device *netdev) usb_fill_bulk_urb(dev->tx_urb, dev->udev, usb_sndbulkpipe(dev->udev, 2), skb->data, count, write_bulk_callback, dev); if ((res = usb_submit_urb(dev->tx_urb, GFP_ATOMIC))) { - warn("failed tx_urb %d\n", res); - dev->stats.tx_errors++; - netif_start_queue(netdev); + /* Can we get/handle EPIPE here? */ + if (res == -ENODEV) + netif_device_detach(dev->netdev); + else { + warn("failed tx_urb %d\n", res); + dev->stats.tx_errors++; + netif_start_queue(netdev); + } } else { dev->stats.tx_packets++; dev->stats.tx_bytes += skb->len; @@ -729,16 +779,25 @@ static int rtl8150_open(struct net_device *netdev) usb_fill_bulk_urb(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1), dev->rx_skb->data, RTL8150_MTU, read_bulk_callback, dev); - if ((res = usb_submit_urb(dev->rx_urb, GFP_KERNEL))) + if ((res = usb_submit_urb(dev->rx_urb, GFP_KERNEL))) { + if (res == -ENODEV) + netif_device_detach(dev->netdev); warn("%s: rx_urb submit failed: %d", __FUNCTION__, res); + return res; + } usb_fill_int_urb(dev->intr_urb, dev->udev, usb_rcvintpipe(dev->udev, 3), dev->intr_buff, INTBUFSIZE, intr_callback, dev, dev->intr_interval); - if ((res = usb_submit_urb(dev->intr_urb, GFP_KERNEL))) + if ((res = usb_submit_urb(dev->intr_urb, GFP_KERNEL))) { + if (res == -ENODEV) + netif_device_detach(dev->netdev); warn("%s: intr_urb submit failed: %d", __FUNCTION__, res); - netif_start_queue(netdev); + usb_kill_urb(dev->rx_urb); + return res; + } enable_net_traffic(dev); set_carrier(netdev); + netif_start_queue(netdev); return res; } -- cgit v1.1 From 168ffc444663e34a20e6d04b6c31e5d495b283fb Mon Sep 17 00:00:00 2001 From: Marko Macek Date: Sun, 30 Jul 2006 01:55:12 -0700 Subject: USB: ati_remote.c: autorepeat fix When HZ is set to 250 (new default) or 100, the time span during which repeated events from the device are ignored could be too small due to ms->jiffies rounding. This causes the auto repeat to kick in early making it impossible for the user to generate individual press/release events. Increate the timeout to compensate. Signed-off-by: Marko Macek Cc: Dmitry Torokhov Cc: Vojtech Pavlik Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/input/ati_remote.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/input/ati_remote.c b/drivers/usb/input/ati_remote.c index 05d2d60..df198cf 100644 --- a/drivers/usb/input/ati_remote.c +++ b/drivers/usb/input/ati_remote.c @@ -152,9 +152,8 @@ static const char accel[] = { 1, 2, 4, 6, 9, 13, 20 }; * events. The hardware generates 5 events for the first keypress * and we have to take this into account for an accurate repeat * behaviour. - * (HZ / 20) == 50 ms and works well for me. */ -#define FILTER_TIME (HZ / 20) +#define FILTER_TIME 60 /* msec */ struct ati_remote { struct input_dev *idev; @@ -467,7 +466,7 @@ static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs) /* Filter duplicate events which happen "too close" together. */ if ((ati_remote->old_data[0] == data[1]) && (ati_remote->old_data[1] == data[2]) && - time_before(jiffies, ati_remote->old_jiffies + FILTER_TIME)) { + time_before(jiffies, ati_remote->old_jiffies + msecs_to_jiffies(FILTER_TIME))) { ati_remote->repeat_count++; } else { ati_remote->repeat_count = 0; -- cgit v1.1 From be0c8015a2e981b9079cb5f0e2bf868fa10249ae Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Mon, 31 Jul 2006 01:43:53 +0200 Subject: USB: fix the USB_GADGET_DUMMY_HCD dependencies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If USB=m, USB_GADGET=y, the option USB_GADGET_DUMMY_HCD mustn't be offered since selecting it results in a compile error. This patch fixes kernel Bugzilla #6534 reported by Toralf Förster. Signed-off-by: Adrian Bunk Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 363b2ad..1a32d96 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -207,7 +207,7 @@ config USB_AT91 config USB_GADGET_DUMMY_HCD boolean "Dummy HCD (DEVELOPMENT)" - depends on USB && EXPERIMENTAL + depends on (USB=y || (USB=m && USB_GADGET=m)) && EXPERIMENTAL select USB_GADGET_DUALSPEED help This host controller driver emulates USB, looping all data transfer -- cgit v1.1 From b4dbda1a22d236842b75be4e2679a96a4fd72632 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 28 Jul 2006 17:07:34 -0400 Subject: USB: dummy-hcd: disable interrupts during req->complete This patch (as756) fixes a bug in dummy-hcd found by the lockdep checker. In one of the code paths, the driver did not disable interrupts before calling a request completion routine. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/dummy_hcd.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 4be4719..7d1c22c 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -609,7 +609,8 @@ static int dummy_dequeue (struct usb_ep *_ep, struct usb_request *_req) if (!dum->driver) return -ESHUTDOWN; - spin_lock_irqsave (&dum->lock, flags); + local_irq_save (flags); + spin_lock (&dum->lock); list_for_each_entry (req, &ep->queue, queue) { if (&req->req == _req) { list_del_init (&req->queue); @@ -618,7 +619,7 @@ static int dummy_dequeue (struct usb_ep *_ep, struct usb_request *_req) break; } } - spin_unlock_irqrestore (&dum->lock, flags); + spin_unlock (&dum->lock); if (retval == 0) { dev_dbg (udc_dev(dum), @@ -626,6 +627,7 @@ static int dummy_dequeue (struct usb_ep *_ep, struct usb_request *_req) req, _ep->name, _req->length, _req->buf); _req->complete (_ep, _req); } + local_irq_restore (flags); return retval; } -- cgit v1.1 From de1caa475120c716ff33d344b5ffefc288ed77c7 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 31 Jul 2006 10:10:28 -0400 Subject: USB: unusual_devs entry for Nokia 3250 Here is another unusual_devs entry (as760) for another Nokia device, this time the 3250. From: Mario Rettig Signed-off-by: Alan Stern Signed-off-by: Phil Dibowitz Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/unusual_devs.h | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 0f0874f..2793f9a 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -145,6 +145,13 @@ UNUSUAL_DEV( 0x0420, 0x0001, 0x0100, 0x0100, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_IGNORE_RESIDUE ), +/* Reported by Mario Rettig */ +UNUSUAL_DEV( 0x0421, 0x042e, 0x0100, 0x0100, + "Nokia", + "Nokia 3250", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ), + /* Reported by Sumedha Swamy and * Einar Th. Einarsson */ UNUSUAL_DEV( 0x0421, 0x0444, 0x0100, 0x0100, -- cgit v1.1 From f443ddf1057776ed99d5006bbbefb018fcf7ce3a Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 31 Jul 2006 10:16:24 -0400 Subject: USB: UHCI: Don't test the Short Packet Detect bit Apparently some UHCI controllers change the value of the Short Packet Detect (SPD) bit in the TD status word -- presumably when they receive a short packet. This patch (as759) changes uhci-hcd to avoid assuming that the bit is unchanged; in fact, the driver no longer looks at SPD at all. This fixes the second problem reported in Bugzilla #6752. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/uhci-q.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index c9d72ac..66c3f61 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -943,7 +943,9 @@ static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb) /* We received a short packet */ if (urb->transfer_flags & URB_SHORT_NOT_OK) ret = -EREMOTEIO; - else if (ctrlstat & TD_CTRL_SPD) + + /* Fixup needed only if this isn't the URB's last TD */ + else if (&td->list != urbp->td_list.prev) ret = 1; } -- cgit v1.1 From 27fb4f0a7f00fda4044de44dcbe4d65b8359cc38 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 2 Aug 2006 16:49:37 -0700 Subject: Revert "[PATCH] USB: convert usb class devices to real devices" This reverts bd00949647ddcea47ce4ea8bb2cfcfc98ebf9f2a commit because it required a newer version of udev to work properly than what is currently documented in Documentation/Changes. Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/file.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c index abee0f5..8de4f8c 100644 --- a/drivers/usb/core/file.c +++ b/drivers/usb/core/file.c @@ -194,13 +194,14 @@ int usb_register_dev(struct usb_interface *intf, ++temp; else temp = name; - intf->usb_dev = device_create(usb_class->class, &intf->dev, - MKDEV(USB_MAJOR, minor), "%s", temp); - if (IS_ERR(intf->usb_dev)) { + intf->class_dev = class_device_create(usb_class->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); - retval = PTR_ERR(intf->usb_dev); + retval = PTR_ERR(intf->class_dev); } exit: return retval; @@ -241,8 +242,8 @@ void usb_deregister_dev(struct usb_interface *intf, spin_unlock (&minor_lock); snprintf(name, BUS_ID_SIZE, class_driver->name, intf->minor - minor_base); - device_destroy(usb_class->class, MKDEV(USB_MAJOR, intf->minor)); - intf->usb_dev = NULL; + class_device_destroy(usb_class->class, MKDEV(USB_MAJOR, intf->minor)); + intf->class_dev = NULL; intf->minor = -1; destroy_usb_class(); } -- cgit v1.1 From cae74b30dd98c10baa5b47b4698bf67e5eb15687 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 2 Aug 2006 16:52:10 -0700 Subject: Revert "[PATCH] USB: move usb_device_class class devices to be real devices" This reverts c182274ffe1277f4e7c564719a696a37cacf74ea commit because it required a newer version of udev to work properly than what is currently documented in Documentation/Changes. Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/devio.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index f7bdd94..218621b 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -517,19 +517,19 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, unsig static struct usb_device *usbdev_lookup_minor(int minor) { - struct device *device; - struct usb_device *udev = NULL; + struct class_device *class_dev; + struct usb_device *dev = NULL; down(&usb_device_class->sem); - list_for_each_entry(device, &usb_device_class->devices, node) { - if (device->devt == MKDEV(USB_DEVICE_MAJOR, minor)) { - udev = device->platform_data; + 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 udev; + return dev; }; /* @@ -1580,16 +1580,16 @@ static void usbdev_add(struct usb_device *dev) { int minor = ((dev->bus->busnum-1) * 128) + (dev->devnum-1); - dev->usbfs_dev = device_create(usb_device_class, &dev->dev, - MKDEV(USB_DEVICE_MAJOR, minor), + 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->usbfs_dev->platform_data = dev; + dev->class_dev->class_data = dev; } static void usbdev_remove(struct usb_device *dev) { - device_unregister(dev->usbfs_dev); + class_device_unregister(dev->class_dev); } static int usbdev_notify(struct notifier_block *self, unsigned long action, -- cgit v1.1 From bf74c7479ef47652005a2418eeb0d867451690da Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Wed, 26 Jul 2006 16:02:53 +0300 Subject: IB/mthca: Fix mthca_array_clear() thinko mthca_array_clear() does not clear the slot if the used count is positive. This leads to crashes in mthca_qp_event() since that uses mthca_array_get() to check that the qp is valid. Discovered by Ali Ayoub. Signed-off-by: Michael S. Tsirkin Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_allocator.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mthca/mthca_allocator.c b/drivers/infiniband/hw/mthca/mthca_allocator.c index 9ba3211..848e583 100644 --- a/drivers/infiniband/hw/mthca/mthca_allocator.c +++ b/drivers/infiniband/hw/mthca/mthca_allocator.c @@ -144,7 +144,9 @@ void mthca_array_clear(struct mthca_array *array, int index) if (--array->page_list[p].used == 0) { free_page((unsigned long) array->page_list[p].page); array->page_list[p].page = NULL; - } + } else + array->page_list[p].page[index & (PAGE_SIZE / + sizeof (void *) - 1)] = NULL; if (array->page_list[p].used < 0) pr_debug("Array %p index %d page %d with ref count %d < 0\n", -- cgit v1.1 From 69e9fbb460fa8766428960439841ffcf565032c1 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Thu, 3 Aug 2006 09:44:22 -0700 Subject: IB/mthca: Clean up mthca array index mask Define a constant MTHCA_ARRAY_MASK to replace repeated uses of (PAGE_SIZE / sizeof (void *) - 1) in mthca array code. Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_allocator.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mthca/mthca_allocator.c b/drivers/infiniband/hw/mthca/mthca_allocator.c index 848e583..25157f5 100644 --- a/drivers/infiniband/hw/mthca/mthca_allocator.c +++ b/drivers/infiniband/hw/mthca/mthca_allocator.c @@ -108,14 +108,15 @@ void mthca_alloc_cleanup(struct mthca_alloc *alloc) * serialize access to the array. */ +#define MTHCA_ARRAY_MASK (PAGE_SIZE / sizeof (void *) - 1) + void *mthca_array_get(struct mthca_array *array, int index) { int p = (index * sizeof (void *)) >> PAGE_SHIFT; - if (array->page_list[p].page) { - int i = index & (PAGE_SIZE / sizeof (void *) - 1); - return array->page_list[p].page[i]; - } else + if (array->page_list[p].page) + return array->page_list[p].page[index & MTHCA_ARRAY_MASK]; + else return NULL; } @@ -130,8 +131,7 @@ int mthca_array_set(struct mthca_array *array, int index, void *value) if (!array->page_list[p].page) return -ENOMEM; - array->page_list[p].page[index & (PAGE_SIZE / sizeof (void *) - 1)] = - value; + array->page_list[p].page[index & MTHCA_ARRAY_MASK] = value; ++array->page_list[p].used; return 0; @@ -145,8 +145,7 @@ void mthca_array_clear(struct mthca_array *array, int index) free_page((unsigned long) array->page_list[p].page); array->page_list[p].page = NULL; } else - array->page_list[p].page[index & (PAGE_SIZE / - sizeof (void *) - 1)] = NULL; + array->page_list[p].page[index & MTHCA_ARRAY_MASK] = NULL; if (array->page_list[p].used < 0) pr_debug("Array %p index %d page %d with ref count %d < 0\n", -- cgit v1.1 From 75df23e229acab85b704f4603bdf5efdc7960e6a Mon Sep 17 00:00:00 2001 From: Sean Hefty Date: Tue, 25 Jul 2006 19:52:01 +0300 Subject: IB/cm: Fix error handling in ib_send_cm_req Report error code rather than success (0) on failure allocating timewait_info in ib_send_cm_req(). Signed-off-by: Sean Hefty Signed-off-by: Roland Dreier --- drivers/infiniband/core/cm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c index f85c97f..0de335b 100644 --- a/drivers/infiniband/core/cm.c +++ b/drivers/infiniband/core/cm.c @@ -975,8 +975,10 @@ int ib_send_cm_req(struct ib_cm_id *cm_id, cm_id_priv->timewait_info = cm_create_timewait_info(cm_id_priv-> id.local_id); - if (IS_ERR(cm_id_priv->timewait_info)) + if (IS_ERR(cm_id_priv->timewait_info)) { + ret = PTR_ERR(cm_id_priv->timewait_info); goto out; + } ret = cm_init_av_by_path(param->primary_path, &cm_id_priv->av); if (ret) -- cgit v1.1 From d916a8f1b43b358685b1672390ead11f2d3b74c6 Mon Sep 17 00:00:00 2001 From: Ishai Rabinovitz Date: Tue, 25 Jul 2006 19:54:09 +0300 Subject: IB/srp: Fix crash in srp_reconnect_target Protect against srp_reset_device() clearing the req_queue while srp_reconnect_target() is in progress (note that state change at the top of srp_reconnect_target() is not sufficient for this since srp_reset_device() ignores the state). Signed-off-by: Ishai Rabinovitz Signed-off-by: Michael S. Tsirkin Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/srp/ib_srp.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 8f472e7..ff94e4e 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -526,8 +526,10 @@ static int srp_reconnect_target(struct srp_target_port *target) while (ib_poll_cq(target->cq, 1, &wc) > 0) ; /* nothing */ + spin_lock_irq(target->scsi_host->host_lock); list_for_each_entry_safe(req, tmp, &target->req_queue, list) srp_reset_req(target, req); + spin_unlock_irq(target->scsi_host->host_lock); target->rx_head = 0; target->tx_head = 0; -- cgit v1.1 From 559ce8f150d7d031c79c4d79173860f1bdfe3ce4 Mon Sep 17 00:00:00 2001 From: Ishai Rabinovitz Date: Thu, 3 Aug 2006 10:35:43 -0700 Subject: IB/srp: Work around data corruption bug on Mellanox targets Data corruption has been seen with Mellanox SRP targets when FMRs create a memory region with I/O virtual address != 0. Add a workaround that disables FMR merging for Mellanox targets (OUI 0002c9). Signed-off-by: Ishai Rabinovitz Signed-off-by: Michael S. Tsirkin Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/srp/ib_srp.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index ff94e4e..8257d5a 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -77,6 +77,14 @@ MODULE_PARM_DESC(topspin_workarounds, static const u8 topspin_oui[3] = { 0x00, 0x05, 0xad }; +static int mellanox_workarounds = 1; + +module_param(mellanox_workarounds, int, 0444); +MODULE_PARM_DESC(mellanox_workarounds, + "Enable workarounds for Mellanox SRP target bugs if != 0"); + +static const u8 mellanox_oui[3] = { 0x00, 0x02, 0xc9 }; + static void srp_add_one(struct ib_device *device); static void srp_remove_one(struct ib_device *device); static void srp_completion(struct ib_cq *cq, void *target_ptr); @@ -569,7 +577,7 @@ err: return ret; } -static int srp_map_fmr(struct srp_device *dev, struct scatterlist *scat, +static int srp_map_fmr(struct srp_target_port *target, struct scatterlist *scat, int sg_cnt, struct srp_request *req, struct srp_direct_buf *buf) { @@ -579,10 +587,15 @@ static int srp_map_fmr(struct srp_device *dev, struct scatterlist *scat, int page_cnt; int i, j; int ret; + struct srp_device *dev = target->srp_host->dev; if (!dev->fmr_pool) return -ENODEV; + if ((sg_dma_address(&scat[0]) & ~dev->fmr_page_mask) && + mellanox_workarounds && !memcmp(&target->ioc_guid, mellanox_oui, 3)) + return -EINVAL; + len = page_cnt = 0; for (i = 0; i < sg_cnt; ++i) { if (sg_dma_address(&scat[i]) & ~dev->fmr_page_mask) { @@ -685,7 +698,7 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target, buf->va = cpu_to_be64(sg_dma_address(scat)); buf->key = cpu_to_be32(target->srp_host->dev->mr->rkey); buf->len = cpu_to_be32(sg_dma_len(scat)); - } else if (srp_map_fmr(target->srp_host->dev, scat, count, req, + } else if (srp_map_fmr(target, scat, count, req, (void *) cmd->add_data)) { /* * FMR mapping failed, and the scatterlist has more -- cgit v1.1 From 8ddc7c5326064434048ec1ecfe57659e08345cc1 Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Thu, 13 Jul 2006 11:00:39 +0300 Subject: IB/ipoib: Remove broken link from Kconfig and documentation Remove references to the IPoIB IETF working group as it has been closed. Signed-off-by: Or Gerlitz Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/ipoib/Kconfig | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/ulp/ipoib/Kconfig b/drivers/infiniband/ulp/ipoib/Kconfig index 13d6d01..d74653d 100644 --- a/drivers/infiniband/ulp/ipoib/Kconfig +++ b/drivers/infiniband/ulp/ipoib/Kconfig @@ -6,8 +6,7 @@ config INFINIBAND_IPOIB transports IP packets over InfiniBand so you can use your IB device as a fancy NIC. - The IPoIB protocol is defined by the IETF ipoib working - group: . + See Documentation/infiniband/ipoib.txt for more information config INFINIBAND_IPOIB_DEBUG bool "IP-over-InfiniBand debugging" if EMBEDDED -- cgit v1.1 From fd60ae404f104f12369e654af9cf03b1f1047661 Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Thu, 3 Aug 2006 10:56:42 -0700 Subject: IB/uverbs: Avoid a crash on device hot remove Wait until all users have closed their device context before allowing device unregistration to complete. This prevents a crash caused by referring to stale data structures. A better solution would be to have a way to revoke contexts rather than waiting for userspace to close the context, but that's a much bigger change that will have to wait. For now let's at least avoid the crash. Signed-off-by: Jack Morgenstein Signed-off-by: Michael S. Tsirkin Signed-off-by: Roland Dreier --- drivers/infiniband/core/uverbs.h | 2 ++ drivers/infiniband/core/uverbs_main.c | 8 +++++++- 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h index bb9bee5..102a59c 100644 --- a/drivers/infiniband/core/uverbs.h +++ b/drivers/infiniband/core/uverbs.h @@ -42,6 +42,7 @@ #include #include #include +#include #include #include @@ -69,6 +70,7 @@ struct ib_uverbs_device { struct kref ref; + struct completion comp; int devnum; struct cdev *dev; struct class_device *class_dev; diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index e725ccc..4e16314 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -122,7 +122,7 @@ static void ib_uverbs_release_dev(struct kref *ref) struct ib_uverbs_device *dev = container_of(ref, struct ib_uverbs_device, ref); - kfree(dev); + complete(&dev->comp); } void ib_uverbs_release_ucq(struct ib_uverbs_file *file, @@ -740,6 +740,7 @@ static void ib_uverbs_add_one(struct ib_device *device) return; kref_init(&uverbs_dev->ref); + init_completion(&uverbs_dev->comp); spin_lock(&map_lock); uverbs_dev->devnum = find_first_zero_bit(dev_map, IB_UVERBS_MAX_DEVICES); @@ -793,6 +794,8 @@ err_cdev: err: kref_put(&uverbs_dev->ref, ib_uverbs_release_dev); + wait_for_completion(&uverbs_dev->comp); + kfree(uverbs_dev); return; } @@ -812,7 +815,10 @@ static void ib_uverbs_remove_one(struct ib_device *device) spin_unlock(&map_lock); clear_bit(uverbs_dev->devnum, dev_map); + kref_put(&uverbs_dev->ref, ib_uverbs_release_dev); + wait_for_completion(&uverbs_dev->comp); + kfree(uverbs_dev); } static int uverbs_event_get_sb(struct file_system_type *fs_type, int flags, -- cgit v1.1 From 60854838596906ebae7f32e4de921e150e669b60 Mon Sep 17 00:00:00 2001 From: Henrik Kretzschmar Date: Thu, 6 Jul 2006 18:05:51 +0400 Subject: pcie: fix warnings when CONFIG_PM=n Signed-off-by: Henrik Kretzschmar Signed-off-by: Alexey Dobriyan Signed-off-by: Greg Kroah-Hartman --- drivers/pci/pcie/portdrv_pci.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c index 50bfc1b..d0a3797 100644 --- a/drivers/pci/pcie/portdrv_pci.c +++ b/drivers/pci/pcie/portdrv_pci.c @@ -30,23 +30,6 @@ MODULE_LICENSE("GPL"); /* global data */ static const char device_name[] = "pcieport-driver"; -static int pcie_portdrv_save_config(struct pci_dev *dev) -{ - return pci_save_state(dev); -} - -static int pcie_portdrv_restore_config(struct pci_dev *dev) -{ - int retval; - - pci_restore_state(dev); - retval = pci_enable_device(dev); - if (retval) - return retval; - pci_set_master(dev); - return 0; -} - /* * pcie_portdrv_probe - Probe PCI-Express port devices * @dev: PCI-Express port device being probed @@ -86,6 +69,23 @@ static void pcie_portdrv_remove (struct pci_dev *dev) } #ifdef CONFIG_PM +static int pcie_portdrv_save_config(struct pci_dev *dev) +{ + return pci_save_state(dev); +} + +static int pcie_portdrv_restore_config(struct pci_dev *dev) +{ + int retval; + + pci_restore_state(dev); + retval = pci_enable_device(dev); + if (retval) + return retval; + pci_set_master(dev); + return 0; +} + static int pcie_portdrv_suspend (struct pci_dev *dev, pm_message_t state) { int ret = pcie_port_device_suspend(dev, state); -- cgit v1.1 From e4fd1f4a6e05335d464fe003c164fea850a3b3f3 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 6 Jul 2006 21:36:01 -0700 Subject: PCIE: cleanup on probe error If pcie_portdrv_probe() fails but it had already called pci_enable_device(), then call pci_disable_device() when returning error. Is there some reason that this isn't being done? or was it just missed? Signed-off-by: Randy Dunlap Signed-off-by: Greg Kroah-Hartman --- drivers/pci/pcie/portdrv_pci.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c index d0a3797..478d0d2 100644 --- a/drivers/pci/pcie/portdrv_pci.c +++ b/drivers/pci/pcie/portdrv_pci.c @@ -56,8 +56,10 @@ static int __devinit pcie_portdrv_probe (struct pci_dev *dev, "%s->Dev[%04x:%04x] has invalid IRQ. Check vendor BIOS\n", __FUNCTION__, dev->device, dev->vendor); } - if (pcie_port_device_register(dev)) + if (pcie_port_device_register(dev)) { + pci_disable_device(dev); return -ENOMEM; + } return 0; } -- cgit v1.1 From c8439cfccc4143b79f70d18015336d9fec0563e2 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 18 Jul 2006 14:33:16 -0700 Subject: PCI: pci/search: EXPORTs cannot be __devinit EXPORTed symbols cannot be __init/__devinit. Signed-off-by: Randy Dunlap Signed-off-by: Greg Kroah-Hartman --- drivers/pci/search.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/search.c b/drivers/pci/search.c index f8ae2b7..d529462 100644 --- a/drivers/pci/search.c +++ b/drivers/pci/search.c @@ -41,7 +41,7 @@ pci_do_find_bus(struct pci_bus* bus, unsigned char busnr) * in the global list of PCI buses. If the bus is found, a pointer to its * data structure is returned. If no bus is found, %NULL is returned. */ -struct pci_bus * __devinit pci_find_bus(int domain, int busnr) +struct pci_bus * pci_find_bus(int domain, int busnr) { struct pci_bus *bus = NULL; struct pci_bus *tmp_bus; -- cgit v1.1 From 998be20fdff12274cd0e6a9f71ce1a93abf40718 Mon Sep 17 00:00:00 2001 From: Kristen Carlson Accardi Date: Wed, 26 Jul 2006 10:52:33 -0700 Subject: PCI Hotplug: add acpiphp to MAINTAINERS Add acpiphp to the MAINTAINERS file. Signed-off-by: Kristen Carlson Accardi Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/acpiphp_core.c | 3 +-- drivers/pci/hotplug/acpiphp_glue.c | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/hotplug/acpiphp_core.c b/drivers/pci/hotplug/acpiphp_core.c index 34de569..e2fef60 100644 --- a/drivers/pci/hotplug/acpiphp_core.c +++ b/drivers/pci/hotplug/acpiphp_core.c @@ -27,8 +27,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * Send feedback to , - * + * Send feedback to * */ diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index ef95d12..ae67a8f 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -26,7 +26,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * Send feedback to + * Send feedback to * */ -- cgit v1.1 From 321311af25cbb65d3cc177e3777fedd526814ecc Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 31 Jul 2006 08:53:15 +0200 Subject: PCI: Unhide the SMBus on Asus PU-DLS Unhide the SMBus controller on the Asus PU-DLS board. This fixes bug #6763. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/pci/quirks.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index e3c78c3..fb08bc9 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -990,6 +990,11 @@ static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev) case 0x8070: /* P4G8X Deluxe */ asus_hides_smbus = 1; } + if (dev->device == PCI_DEVICE_ID_INTEL_E7501_MCH) + switch (dev->subsystem_device) { + case 0x80c9: /* PU-DLS */ + asus_hides_smbus = 1; + } if (dev->device == PCI_DEVICE_ID_INTEL_82855GM_HB) switch (dev->subsystem_device) { case 0x1751: /* M2N notebook */ @@ -1058,6 +1063,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82845G_HB, asu DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82850_HB, asus_hides_smbus_hostbridge ); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82865_HB, asus_hides_smbus_hostbridge ); 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_E7501_MCH, 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 ); @@ -1081,6 +1087,7 @@ static void __init asus_hides_smbus_lpc(struct pci_dev *dev) } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, asus_hides_smbus_lpc ); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, asus_hides_smbus_lpc ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, asus_hides_smbus_lpc ); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, asus_hides_smbus_lpc ); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, asus_hides_smbus_lpc ); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, asus_hides_smbus_lpc ); -- cgit v1.1 From 5669021e40964303994a20633548732c6bb26636 Mon Sep 17 00:00:00 2001 From: Kristen Carlson Accardi Date: Tue, 1 Aug 2006 14:59:19 -0700 Subject: PCI: docking station: remove dock uevents Remove uevent dock notifications. There are no consumers of these events at present, and uevents are likely not the correct way to send this type of event anyway. Until I get some kind of idea if anyone in userspace cares about dock events, I will just not send any. Signed-off-by: Kristen Carlson Accardi Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/dock.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 1c0a39d..578b99b 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -58,8 +58,8 @@ struct dock_dependent_device { }; #define DOCK_DOCKING 0x00000001 -#define DOCK_EVENT KOBJ_DOCK -#define UNDOCK_EVENT KOBJ_UNDOCK +#define DOCK_EVENT 3 +#define UNDOCK_EVENT 2 static struct dock_station *dock_station; @@ -322,11 +322,10 @@ static void hotplug_dock_devices(struct dock_station *ds, u32 event) static void dock_event(struct dock_station *ds, u32 event, int num) { - struct acpi_device *device; - - device = dock_create_acpi_device(ds->handle); - if (device) - kobject_uevent(&device->kobj, num); + /* + * we don't do events until someone tells me that + * they would like to have them. + */ } /** -- cgit v1.1 From 2131ca8915ae545c596f94e75b692be2811d9c03 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 13 Jul 2006 11:35:41 +0200 Subject: PNP: Add missing casts in printk() arguments Some resource_size_t values are fed to printk() without handling the fact that they can have different size depending on your .config. Signed-off-by: Pierre Ossman Signed-off-by: Greg Kroah-Hartman --- drivers/pnp/interface.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/pnp/interface.c b/drivers/pnp/interface.c index 3163e3d..9d8b415 100644 --- a/drivers/pnp/interface.c +++ b/drivers/pnp/interface.c @@ -265,8 +265,8 @@ static ssize_t pnp_show_current_resources(struct device *dmdev, struct device_at pnp_printf(buffer," disabled\n"); else pnp_printf(buffer," 0x%llx-0x%llx\n", - pnp_port_start(dev, i), - pnp_port_end(dev, i)); + (unsigned long long)pnp_port_start(dev, i), + (unsigned long long)pnp_port_end(dev, i)); } } for (i = 0; i < PNP_MAX_MEM; i++) { @@ -276,8 +276,8 @@ static ssize_t pnp_show_current_resources(struct device *dmdev, struct device_at pnp_printf(buffer," disabled\n"); else pnp_printf(buffer," 0x%llx-0x%llx\n", - pnp_mem_start(dev, i), - pnp_mem_end(dev, i)); + (unsigned long long)pnp_mem_start(dev, i), + (unsigned long long)pnp_mem_end(dev, i)); } } for (i = 0; i < PNP_MAX_IRQ; i++) { @@ -287,7 +287,7 @@ static ssize_t pnp_show_current_resources(struct device *dmdev, struct device_at pnp_printf(buffer," disabled\n"); else pnp_printf(buffer," %lld\n", - pnp_irq(dev, i)); + (unsigned long long)pnp_irq(dev, i)); } } for (i = 0; i < PNP_MAX_DMA; i++) { @@ -297,7 +297,7 @@ static ssize_t pnp_show_current_resources(struct device *dmdev, struct device_at pnp_printf(buffer," disabled\n"); else pnp_printf(buffer," %lld\n", - pnp_dma(dev, i)); + (unsigned long long)pnp_dma(dev, i)); } } ret = (buffer->curr - buf); -- cgit v1.1 From b41477f32a5aaf39a77741c0138b16f16a636c70 Mon Sep 17 00:00:00 2001 From: Ananda Raju Date: Mon, 24 Jul 2006 19:52:49 -0400 Subject: [PATCH] s2io driver bug fixes #1 This patch contains some of the bug fixes and enhancements done to s2io driver. Following are the brief description of changes 1. Introduced macro "S2IO_PARM_INT" for declaring integer load parameter 2. UDP_RR test failure, memset txdl after Tx completion 3. PXE boot may leave adapter in unknown state so do reset in probe. 4. Add Tx completion code in netpoll 5. In s2io_vpd_read() move array vpd_data[] to pointer, saves stack memory 6. Fix bug in ethtool online test Signed-off-by: Ananda Raju Signed-off-by: Jeff Garzik --- drivers/net/s2io.c | 158 +++++++++++++++++++++++++++-------------------------- drivers/net/s2io.h | 5 ++ 2 files changed, 85 insertions(+), 78 deletions(-) (limited to 'drivers') diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index e1fe3a0..4a4e38b 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -370,38 +370,50 @@ static const u64 fix_mac[] = { END_SIGN }; +MODULE_AUTHOR("Raghavendra Koushik "); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_VERSION); + + /* Module Loadable parameters. */ -static unsigned int tx_fifo_num = 1; -static unsigned int tx_fifo_len[MAX_TX_FIFOS] = - {DEFAULT_FIFO_0_LEN, [1 ...(MAX_TX_FIFOS - 1)] = DEFAULT_FIFO_1_7_LEN}; -static unsigned int rx_ring_num = 1; -static unsigned int rx_ring_sz[MAX_RX_RINGS] = - {[0 ...(MAX_RX_RINGS - 1)] = SMALL_BLK_CNT}; -static unsigned int rts_frm_len[MAX_RX_RINGS] = - {[0 ...(MAX_RX_RINGS - 1)] = 0 }; -static unsigned int rx_ring_mode = 1; -static unsigned int use_continuous_tx_intrs = 1; -static unsigned int rmac_pause_time = 0x100; -static unsigned int mc_pause_threshold_q0q3 = 187; -static unsigned int mc_pause_threshold_q4q7 = 187; -static unsigned int shared_splits; -static unsigned int tmac_util_period = 5; -static unsigned int rmac_util_period = 5; -static unsigned int bimodal = 0; -static unsigned int l3l4hdr_size = 128; -#ifndef CONFIG_S2IO_NAPI -static unsigned int indicate_max_pkts; -#endif +S2IO_PARM_INT(tx_fifo_num, 1); +S2IO_PARM_INT(rx_ring_num, 1); + + +S2IO_PARM_INT(rx_ring_mode, 1); +S2IO_PARM_INT(use_continuous_tx_intrs, 1); +S2IO_PARM_INT(rmac_pause_time, 0x100); +S2IO_PARM_INT(mc_pause_threshold_q0q3, 187); +S2IO_PARM_INT(mc_pause_threshold_q4q7, 187); +S2IO_PARM_INT(shared_splits, 0); +S2IO_PARM_INT(tmac_util_period, 5); +S2IO_PARM_INT(rmac_util_period, 5); +S2IO_PARM_INT(bimodal, 0); +S2IO_PARM_INT(l3l4hdr_size, 128); /* Frequency of Rx desc syncs expressed as power of 2 */ -static unsigned int rxsync_frequency = 3; +S2IO_PARM_INT(rxsync_frequency, 3); /* Interrupt type. Values can be 0(INTA), 1(MSI), 2(MSI_X) */ -static unsigned int intr_type = 0; +S2IO_PARM_INT(intr_type, 0); /* Large receive offload feature */ -static unsigned int lro = 0; +S2IO_PARM_INT(lro, 0); /* Max pkts to be aggregated by LRO at one time. If not specified, * aggregation happens until we hit max IP pkt size(64K) */ -static unsigned int lro_max_pkts = 0xFFFF; +S2IO_PARM_INT(lro_max_pkts, 0xFFFF); +#ifndef CONFIG_S2IO_NAPI +S2IO_PARM_INT(indicate_max_pkts, 0); +#endif + +static unsigned int tx_fifo_len[MAX_TX_FIFOS] = + {DEFAULT_FIFO_0_LEN, [1 ...(MAX_TX_FIFOS - 1)] = DEFAULT_FIFO_1_7_LEN}; +static unsigned int rx_ring_sz[MAX_RX_RINGS] = + {[0 ...(MAX_RX_RINGS - 1)] = SMALL_BLK_CNT}; +static unsigned int rts_frm_len[MAX_RX_RINGS] = + {[0 ...(MAX_RX_RINGS - 1)] = 0 }; + +module_param_array(tx_fifo_len, uint, NULL, 0); +module_param_array(rx_ring_sz, uint, NULL, 0); +module_param_array(rts_frm_len, uint, NULL, 0); /* * S2IO device table. @@ -464,10 +476,9 @@ static int init_shared_mem(struct s2io_nic *nic) size += config->tx_cfg[i].fifo_len; } if (size > MAX_AVAILABLE_TXDS) { - DBG_PRINT(ERR_DBG, "%s: Requested TxDs too high, ", - __FUNCTION__); + DBG_PRINT(ERR_DBG, "s2io: Requested TxDs too high, "); DBG_PRINT(ERR_DBG, "Requested: %d, max supported: 8192\n", size); - return FAILURE; + return -EINVAL; } lst_size = (sizeof(TxD_t) * config->max_txds); @@ -547,6 +558,7 @@ static int init_shared_mem(struct s2io_nic *nic) nic->ufo_in_band_v = kmalloc((sizeof(u64) * size), GFP_KERNEL); if (!nic->ufo_in_band_v) return -ENOMEM; + memset(nic->ufo_in_band_v, 0, size); /* Allocation and initialization of RXDs in Rings */ size = 0; @@ -1213,7 +1225,7 @@ static int init_nic(struct s2io_nic *nic) break; } - /* Enable Tx FIFO partition 0. */ + /* Enable all configured Tx FIFO partitions */ val64 = readq(&bar0->tx_fifo_partition_0); val64 |= (TX_FIFO_PARTITION_EN); writeq(val64, &bar0->tx_fifo_partition_0); @@ -1650,7 +1662,7 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag) writeq(temp64, &bar0->general_int_mask); /* * If Hercules adapter enable GPIO otherwise - * disabled all PCIX, Flash, MDIO, IIC and GPIO + * disable all PCIX, Flash, MDIO, IIC and GPIO * interrupts for now. * TODO */ @@ -2119,7 +2131,7 @@ static struct sk_buff *s2io_txdl_getskb(fifo_info_t *fifo_data, TxD_t *txdlp, in frag->size, PCI_DMA_TODEVICE); } } - txdlp->Host_Control = 0; + memset(txdlp,0, (sizeof(TxD_t) * fifo_data->max_txds)); return(skb); } @@ -2614,23 +2626,23 @@ no_rx: } #endif +#ifdef CONFIG_NET_POLL_CONTROLLER /** - * s2io_netpoll - Rx interrupt service handler for netpoll support + * s2io_netpoll - netpoll event handler entry point * @dev : pointer to the device structure. * Description: - * Polling 'interrupt' - used by things like netconsole to send skbs - * without having to re-enable interrupts. It's not called while - * the interrupt routine is executing. + * This function will be called by upper layer to check for events on the + * interface in situations where interrupts are disabled. It is used for + * specific in-kernel networking tasks, such as remote consoles and kernel + * debugging over the network (example netdump in RedHat). */ - -#ifdef CONFIG_NET_POLL_CONTROLLER static void s2io_netpoll(struct net_device *dev) { nic_t *nic = dev->priv; mac_info_t *mac_control; struct config_param *config; XENA_dev_config_t __iomem *bar0 = nic->bar0; - u64 val64; + u64 val64 = 0xFFFFFFFFFFFFFFFFULL; int i; disable_irq(dev->irq); @@ -2639,9 +2651,17 @@ static void s2io_netpoll(struct net_device *dev) mac_control = &nic->mac_control; config = &nic->config; - val64 = readq(&bar0->rx_traffic_int); writeq(val64, &bar0->rx_traffic_int); + writeq(val64, &bar0->tx_traffic_int); + + /* we need to free up the transmitted skbufs or else netpoll will + * run out of skbs and will fail and eventually netpoll application such + * as netdump will fail. + */ + for (i = 0; i < config->tx_fifo_num; i++) + tx_intr_handler(&mac_control->fifos[i]); + /* check for received packet and indicate up to network */ for (i = 0; i < config->rx_ring_num; i++) rx_intr_handler(&mac_control->rings[i]); @@ -3327,7 +3347,7 @@ static void s2io_reset(nic_t * sp) /* Clear certain PCI/PCI-X fields after reset */ if (sp->device_type == XFRAME_II_DEVICE) { - /* Clear parity err detect bit */ + /* Clear "detected parity error" bit */ pci_write_config_word(sp->pdev, PCI_STATUS, 0x8000); /* Clearing PCIX Ecc status register */ @@ -4942,7 +4962,8 @@ static int write_eeprom(nic_t * sp, int off, u64 data, int cnt) } static void s2io_vpd_read(nic_t *nic) { - u8 vpd_data[256],data; + u8 *vpd_data; + u8 data; int i=0, cnt, fail = 0; int vpd_addr = 0x80; @@ -4955,6 +4976,10 @@ static void s2io_vpd_read(nic_t *nic) vpd_addr = 0x50; } + vpd_data = kmalloc(256, GFP_KERNEL); + if (!vpd_data) + return; + for (i = 0; i < 256; i +=4 ) { pci_write_config_byte(nic->pdev, (vpd_addr + 2), i); pci_read_config_byte(nic->pdev, (vpd_addr + 2), &data); @@ -4977,6 +5002,7 @@ static void s2io_vpd_read(nic_t *nic) memset(nic->product_name, 0, vpd_data[1]); memcpy(nic->product_name, &vpd_data[3], vpd_data[1]); } + kfree(vpd_data); } /** @@ -5295,7 +5321,7 @@ static int s2io_link_test(nic_t * sp, uint64_t * data) else *data = 0; - return 0; + return *data; } /** @@ -6337,7 +6363,7 @@ static int s2io_card_up(nic_t * sp) s2io_set_multicast(dev); if (sp->lro) { - /* Initialize max aggregatable pkts based on MTU */ + /* Initialize max aggregatable pkts per session based on MTU */ sp->lro_max_aggr_per_sess = ((1<<16) - 1) / dev->mtu; /* Check if we can use(if specified) user provided value */ if (lro_max_pkts < sp->lro_max_aggr_per_sess) @@ -6438,7 +6464,7 @@ static void s2io_tx_watchdog(struct net_device *dev) * @cksum : FCS checksum of the frame. * @ring_no : the ring from which this RxD was extracted. * Description: - * This function is called by the Tx interrupt serivce routine to perform + * This function is called by the Rx interrupt serivce routine to perform * some OS related operations on the SKB before passing it to the upper * layers. It mainly checks if the checksum is OK, if so adds it to the * SKBs cksum variable, increments the Rx packet count and passes the SKB @@ -6698,33 +6724,6 @@ static void s2io_init_pci(nic_t * sp) pci_read_config_word(sp->pdev, PCI_COMMAND, &pci_cmd); } -MODULE_AUTHOR("Raghavendra Koushik "); -MODULE_LICENSE("GPL"); -MODULE_VERSION(DRV_VERSION); - -module_param(tx_fifo_num, int, 0); -module_param(rx_ring_num, int, 0); -module_param(rx_ring_mode, int, 0); -module_param_array(tx_fifo_len, uint, NULL, 0); -module_param_array(rx_ring_sz, uint, NULL, 0); -module_param_array(rts_frm_len, uint, NULL, 0); -module_param(use_continuous_tx_intrs, int, 1); -module_param(rmac_pause_time, int, 0); -module_param(mc_pause_threshold_q0q3, int, 0); -module_param(mc_pause_threshold_q4q7, int, 0); -module_param(shared_splits, int, 0); -module_param(tmac_util_period, int, 0); -module_param(rmac_util_period, int, 0); -module_param(bimodal, bool, 0); -module_param(l3l4hdr_size, int , 0); -#ifndef CONFIG_S2IO_NAPI -module_param(indicate_max_pkts, int, 0); -#endif -module_param(rxsync_frequency, int, 0); -module_param(intr_type, int, 0); -module_param(lro, int, 0); -module_param(lro_max_pkts, int, 0); - static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type) { if ( tx_fifo_num > 8) { @@ -6832,8 +6831,8 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) } 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); + DBG_PRINT(ERR_DBG, "Request Regions failed\n"); + pci_disable_device(pdev); return -ENODEV; } } @@ -6957,7 +6956,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) /* initialize the shared memory used by the NIC and the host */ if (init_shared_mem(sp)) { DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n", - __FUNCTION__); + dev->name); ret = -ENOMEM; goto mem_alloc_failed; } @@ -7094,6 +7093,9 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) dev->addr_len = ETH_ALEN; memcpy(dev->dev_addr, sp->def_mac_addr, ETH_ALEN); + /* reset Nic and bring it to known state */ + s2io_reset(sp); + /* * Initialize the tasklet status and link state flags * and the card state parameter @@ -7131,11 +7133,11 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) goto register_failed; } s2io_vpd_read(sp); - DBG_PRINT(ERR_DBG, "%s: Neterion %s",dev->name, sp->product_name); - DBG_PRINT(ERR_DBG, "(rev %d), Driver version %s\n", - get_xena_rev_id(sp->pdev), - s2io_driver_version); DBG_PRINT(ERR_DBG, "Copyright(c) 2002-2005 Neterion Inc.\n"); + DBG_PRINT(ERR_DBG, "%s: Neterion %s (rev %d)\n",dev->name, + sp->product_name, get_xena_rev_id(sp->pdev)); + DBG_PRINT(ERR_DBG, "%s: Driver version %s\n", dev->name, + s2io_driver_version); DBG_PRINT(ERR_DBG, "%s: MAC ADDR: " "%02x:%02x:%02x:%02x:%02x:%02x\n", dev->name, sp->def_mac_addr[0].mac_addr[0], diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index 217097b..1654f71 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h @@ -1011,4 +1011,9 @@ static void clear_lro_session(lro_t *lro); static void queue_rx_frame(struct sk_buff *skb); static void update_L3L4_header(nic_t *sp, lro_t *lro); static void lro_append_pkt(nic_t *sp, lro_t *lro, struct sk_buff *skb, u32 tcp_len); + +#define S2IO_PARM_INT(X, def_val) \ + static unsigned int X = def_val;\ + module_param(X , uint, 0); + #endif /* _S2IO_H */ -- cgit v1.1 From 75c30b1368faaa9c740536b91a15a33aab62f30b Mon Sep 17 00:00:00 2001 From: Ananda Raju Date: Mon, 24 Jul 2006 19:55:09 -0400 Subject: [PATCH] s2io driver bug fixes #2 This patch contains some of the bug fixes and enhancements done to s2io driver. Following are the brief description of changes 1. code cleanup to handle gso modification better 2. Move repeated code in rx path, to a common function s2io_chk_rx_buffers() 3. Bug fix in MSI interrupt 4. clear statistics when card is down 5. Avoid linked list traversing in lro aggregation. 6. Use pci_dma_sync_single_for_cpu for buffer0 in case of 2/3 buffer mode. 7. ethtool tso get/set functions to set clear NETIF_F_TSO6 8. Stop LRO aggregation when we receive ECN notification Signed-off-by: Ananda Raju Signed-off-by: Jeff Garzik --- drivers/net/s2io.c | 228 ++++++++++++++++++++++------------------------------- drivers/net/s2io.h | 5 ++ 2 files changed, 98 insertions(+), 135 deletions(-) (limited to 'drivers') diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 4a4e38b..132ed32 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -76,7 +76,7 @@ #include "s2io.h" #include "s2io-regs.h" -#define DRV_VERSION "2.0.14.2" +#define DRV_VERSION "2.0.15.2" /* S2io Driver name & version. */ static char s2io_driver_name[] = "Neterion"; @@ -2383,9 +2383,14 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no) skb->data = (void *) (unsigned long)tmp; skb->tail = (void *) (unsigned long)tmp; - ((RxD3_t*)rxdp)->Buffer0_ptr = - pci_map_single(nic->pdev, ba->ba_0, BUF0_LEN, + if (!(((RxD3_t*)rxdp)->Buffer0_ptr)) + ((RxD3_t*)rxdp)->Buffer0_ptr = + pci_map_single(nic->pdev, ba->ba_0, BUF0_LEN, PCI_DMA_FROMDEVICE); + else + pci_dma_sync_single_for_device(nic->pdev, + (dma_addr_t) ((RxD3_t*)rxdp)->Buffer0_ptr, + BUF0_LEN, PCI_DMA_FROMDEVICE); rxdp->Control_2 = SET_BUFFER0_SIZE_3(BUF0_LEN); if (nic->rxd_mode == RXD_MODE_3B) { /* Two buffer mode */ @@ -2398,10 +2403,13 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no) (nic->pdev, skb->data, dev->mtu + 4, PCI_DMA_FROMDEVICE); - /* Buffer-1 will be dummy buffer not used */ - ((RxD3_t*)rxdp)->Buffer1_ptr = - pci_map_single(nic->pdev, ba->ba_1, BUF1_LEN, - PCI_DMA_FROMDEVICE); + /* Buffer-1 will be dummy buffer. Not used */ + if (!(((RxD3_t*)rxdp)->Buffer1_ptr)) { + ((RxD3_t*)rxdp)->Buffer1_ptr = + pci_map_single(nic->pdev, + ba->ba_1, BUF1_LEN, + PCI_DMA_FROMDEVICE); + } rxdp->Control_2 |= SET_BUFFER1_SIZE_3(1); rxdp->Control_2 |= SET_BUFFER2_SIZE_3 (dev->mtu + 4); @@ -2728,7 +2736,7 @@ static void rx_intr_handler(ring_info_t *ring_data) /* If your are next to put index then it's FIFO full condition */ if ((get_block == put_block) && (get_info.offset + 1) == put_info.offset) { - DBG_PRINT(ERR_DBG, "%s: Ring Full\n",dev->name); + DBG_PRINT(INTR_DBG, "%s: Ring Full\n",dev->name); break; } skb = (struct sk_buff *) ((unsigned long)rxdp->Host_Control); @@ -2748,18 +2756,15 @@ static void rx_intr_handler(ring_info_t *ring_data) HEADER_SNAP_SIZE, PCI_DMA_FROMDEVICE); } else if (nic->rxd_mode == RXD_MODE_3B) { - pci_unmap_single(nic->pdev, (dma_addr_t) + pci_dma_sync_single_for_cpu(nic->pdev, (dma_addr_t) ((RxD3_t*)rxdp)->Buffer0_ptr, BUF0_LEN, PCI_DMA_FROMDEVICE); pci_unmap_single(nic->pdev, (dma_addr_t) - ((RxD3_t*)rxdp)->Buffer1_ptr, - BUF1_LEN, PCI_DMA_FROMDEVICE); - pci_unmap_single(nic->pdev, (dma_addr_t) ((RxD3_t*)rxdp)->Buffer2_ptr, dev->mtu + 4, PCI_DMA_FROMDEVICE); } else { - pci_unmap_single(nic->pdev, (dma_addr_t) + pci_dma_sync_single_for_cpu(nic->pdev, (dma_addr_t) ((RxD3_t*)rxdp)->Buffer0_ptr, BUF0_LEN, PCI_DMA_FROMDEVICE); pci_unmap_single(nic->pdev, (dma_addr_t) @@ -3548,7 +3553,7 @@ static void restore_xmsi_data(nic_t *nic) u64 val64; int i; - for (i=0; i< nic->avail_msix_vectors; 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)); @@ -3567,7 +3572,7 @@ static void store_xmsi_data(nic_t *nic) int i; /* Store and display */ - for (i=0; i< nic->avail_msix_vectors; i++) { + 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)) { @@ -3828,13 +3833,11 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) TxD_t *txdp; TxFIFO_element_t __iomem *tx_fifo; unsigned long flags; -#ifdef NETIF_F_TSO - int mss; -#endif u16 vlan_tag = 0; int vlan_priority = 0; mac_info_t *mac_control; struct config_param *config; + int offload_type; mac_control = &sp->mac_control; config = &sp->config; @@ -3882,13 +3885,11 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) return 0; } - txdp->Control_1 = 0; - txdp->Control_2 = 0; + offload_type = s2io_offload_type(skb); #ifdef NETIF_F_TSO - mss = skb_shinfo(skb)->gso_size; - if (skb_shinfo(skb)->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)) { + if (offload_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)) { txdp->Control_1 |= TXD_TCP_LSO_EN; - txdp->Control_1 |= TXD_TCP_LSO_MSS(mss); + txdp->Control_1 |= TXD_TCP_LSO_MSS(s2io_tcp_mss(skb)); } #endif if (skb->ip_summed == CHECKSUM_HW) { @@ -3906,10 +3907,10 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) } frg_len = skb->len - skb->data_len; - if (skb_shinfo(skb)->gso_type == SKB_GSO_UDP) { + if (offload_type == SKB_GSO_UDP) { int ufo_size; - ufo_size = skb_shinfo(skb)->gso_size; + ufo_size = s2io_udp_mss(skb); ufo_size &= ~7; txdp->Control_1 |= TXD_UFO_EN; txdp->Control_1 |= TXD_UFO_MSS(ufo_size); @@ -3926,16 +3927,13 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) sp->ufo_in_band_v, sizeof(u64), PCI_DMA_TODEVICE); txdp++; - txdp->Control_1 = 0; - txdp->Control_2 = 0; } txdp->Buffer_Pointer = pci_map_single (sp->pdev, skb->data, frg_len, PCI_DMA_TODEVICE); txdp->Host_Control = (unsigned long) skb; txdp->Control_1 |= TXD_BUFFER0_SIZE(frg_len); - - if (skb_shinfo(skb)->gso_type == SKB_GSO_UDP) + if (offload_type == SKB_GSO_UDP) txdp->Control_1 |= TXD_UFO_EN; frg_cnt = skb_shinfo(skb)->nr_frags; @@ -3950,12 +3948,12 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) (sp->pdev, frag->page, frag->page_offset, frag->size, PCI_DMA_TODEVICE); txdp->Control_1 = TXD_BUFFER0_SIZE(frag->size); - if (skb_shinfo(skb)->gso_type == SKB_GSO_UDP) + if (offload_type == SKB_GSO_UDP) txdp->Control_1 |= TXD_UFO_EN; } txdp->Control_1 |= TXD_GATHER_CODE_LAST; - if (skb_shinfo(skb)->gso_type == SKB_GSO_UDP) + if (offload_type == SKB_GSO_UDP) frg_cnt++; /* as Txd0 was used for inband header */ tx_fifo = mac_control->tx_FIFO_start[queue]; @@ -3964,13 +3962,9 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) val64 = (TX_FIFO_LAST_TXD_NUM(frg_cnt) | TX_FIFO_FIRST_LIST | TX_FIFO_LAST_LIST); - -#ifdef NETIF_F_TSO - if (mss) - val64 |= TX_FIFO_SPECIAL_FUNC; -#endif - if (skb_shinfo(skb)->gso_type == SKB_GSO_UDP) + if (offload_type) val64 |= TX_FIFO_SPECIAL_FUNC; + writeq(val64, &tx_fifo->List_Control); mmiowb(); @@ -4004,13 +3998,41 @@ s2io_alarm_handle(unsigned long data) mod_timer(&sp->alarm_timer, jiffies + HZ / 2); } +static int s2io_chk_rx_buffers(nic_t *sp, int rng_n) +{ + int rxb_size, level; + + if (!sp->lro) { + 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 -1; + } + clear_bit(0, (&sp->tasklet_status)); + } else if (level == LOW) + tasklet_schedule(&sp->task); + + } else if (fill_rx_buffers(sp, rng_n) == -ENOMEM) { + DBG_PRINT(ERR_DBG, "%s:Out of memory", sp->dev->name); + DBG_PRINT(ERR_DBG, " in Rx Intr!!\n"); + } + return 0; +} + 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; @@ -4032,35 +4054,8 @@ s2io_msi_handle(int irq, void *dev_id, struct pt_regs *regs) * 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++) { - if (!sp->lro) { - 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); - } - } - else if (fill_rx_buffers(sp, i) == -ENOMEM) { - DBG_PRINT(ERR_DBG, "%s:Out of memory", - dev->name); - DBG_PRINT(ERR_DBG, " in Rx Intr!!\n"); - break; - } - } + for (i = 0; i < config->rx_ring_num; i++) + s2io_chk_rx_buffers(sp, i); atomic_dec(&sp->isr_cnt); return IRQ_HANDLED; @@ -4071,39 +4066,13 @@ 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; - struct net_device *dev = (struct net_device *) dev_id; - int rxb_size, level, rng_n; atomic_inc(&sp->isr_cnt); - rx_intr_handler(ring); - rng_n = ring->ring_no; - if (!sp->lro) { - 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); - } - } - else if (fill_rx_buffers(sp, rng_n) == -ENOMEM) { - DBG_PRINT(ERR_DBG, "%s:Out of memory", dev->name); - DBG_PRINT(ERR_DBG, " in Rx Intr!!\n"); - } + rx_intr_handler(ring); + s2io_chk_rx_buffers(sp, ring->ring_no); atomic_dec(&sp->isr_cnt); - return IRQ_HANDLED; } @@ -4268,37 +4237,8 @@ static irqreturn_t s2io_isr(int irq, void *dev_id, struct pt_regs *regs) * else schedule a tasklet to reallocate the buffers. */ #ifndef CONFIG_S2IO_NAPI - for (i = 0; i < config->rx_ring_num; i++) { - if (!sp->lro) { - int ret; - 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); - writeq(org_mask, &bar0->general_int_mask); - return IRQ_HANDLED; - } - clear_bit(0, (&sp->tasklet_status)); - } else if (level == LOW) { - tasklet_schedule(&sp->task); - } - } - else if (fill_rx_buffers(sp, i) == -ENOMEM) { - DBG_PRINT(ERR_DBG, "%s:Out of memory", - dev->name); - DBG_PRINT(ERR_DBG, " in Rx intr!!\n"); - break; - } - } + for (i = 0; i < config->rx_ring_num; i++) + s2io_chk_rx_buffers(sp, i); #endif writeq(org_mask, &bar0->general_int_mask); atomic_dec(&sp->isr_cnt); @@ -4328,6 +4268,8 @@ static void s2io_updt_stats(nic_t *sp) if (cnt == 5) break; /* Updt failed */ } while(1); + } else { + memset(sp->mac_control.stats_info, 0, sizeof(StatInfo_t)); } } @@ -5779,6 +5721,19 @@ static int s2io_ethtool_op_set_tx_csum(struct net_device *dev, u32 data) return 0; } +static u32 s2io_ethtool_op_get_tso(struct net_device *dev) +{ + return (dev->features & NETIF_F_TSO) != 0; +} +static int s2io_ethtool_op_set_tso(struct net_device *dev, u32 data) +{ + if (data) + dev->features |= (NETIF_F_TSO | NETIF_F_TSO6); + else + dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6); + + return 0; +} static struct ethtool_ops netdev_ethtool_ops = { .get_settings = s2io_ethtool_gset, @@ -5799,8 +5754,8 @@ static struct ethtool_ops netdev_ethtool_ops = { .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, #ifdef NETIF_F_TSO - .get_tso = ethtool_op_get_tso, - .set_tso = ethtool_op_set_tso, + .get_tso = s2io_ethtool_op_get_tso, + .set_tso = s2io_ethtool_op_set_tso, #endif .get_ufo = ethtool_op_get_ufo, .set_ufo = ethtool_op_set_ufo, @@ -7438,8 +7393,13 @@ static int verify_l3_l4_lro_capable(lro_t *l_lro, struct iphdr *ip, if (ip->ihl != 5) /* IP has options */ return -1; + /* If we see CE codepoint in IP header, packet is not mergeable */ + if (INET_ECN_is_ce(ipv4_get_dsfield(ip))) + return -1; + + /* If we see ECE or CWR flags in TCP header, packet is not mergeable */ if (tcp->urg || tcp->psh || tcp->rst || tcp->syn || tcp->fin || - !tcp->ack) { + tcp->ece || tcp->cwr || !tcp->ack) { /* * Currently recognize only the ack control word and * any other control field being set would result in @@ -7593,18 +7553,16 @@ static void queue_rx_frame(struct sk_buff *skb) static void lro_append_pkt(nic_t *sp, lro_t *lro, struct sk_buff *skb, u32 tcp_len) { - struct sk_buff *tmp, *first = lro->parent; + struct sk_buff *first = lro->parent; first->len += tcp_len; first->data_len = lro->frags_len; skb_pull(skb, (skb->len - tcp_len)); - if ((tmp = skb_shinfo(first)->frag_list)) { - while (tmp->next) - tmp = tmp->next; - tmp->next = skb; - } + if (skb_shinfo(first)->frag_list) + lro->last_frag->next = skb; else skb_shinfo(first)->frag_list = skb; + lro->last_frag = skb; sp->mac_control.stats_info->sw_stat.clubbed_frms_cnt++; return; } diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index 1654f71..5ed49c3 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h @@ -719,6 +719,7 @@ struct msix_info_st { /* Data structure to represent a LRO session */ typedef struct lro { struct sk_buff *parent; + struct sk_buff *last_frag; u8 *l2h; struct iphdr *iph; struct tcphdr *tcph; @@ -1012,6 +1013,10 @@ static void queue_rx_frame(struct sk_buff *skb); static void update_L3L4_header(nic_t *sp, lro_t *lro); static void lro_append_pkt(nic_t *sp, lro_t *lro, struct sk_buff *skb, u32 tcp_len); +#define s2io_tcp_mss(skb) skb_shinfo(skb)->gso_size +#define s2io_udp_mss(skb) skb_shinfo(skb)->gso_size +#define s2io_offload_type(skb) skb_shinfo(skb)->gso_type + #define S2IO_PARM_INT(X, def_val) \ static unsigned int X = def_val;\ module_param(X , uint, 0); -- cgit v1.1 From 817acf5ebd9ea21f134fc90064b0f6686c5b169d Mon Sep 17 00:00:00 2001 From: Sergei Shtylylov Date: Wed, 26 Jul 2006 00:53:53 +0400 Subject: [PATCH] Stop calling phy_stop_interrupts() twice Prevent phylib from freeing PHY IRQ twice on closing an eth device: phy_disconnect() first calls phy_stop_interrupts(), then it calls phy_stop_machine() which in turn calls phy_stop_interrupts() making the kernel complain on each bootup... Signed-off-by: Sergei Shtylyov Signed-off-by: Jeff Garzik --- drivers/net/phy/phy.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 7d5c223..f5aad77 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -419,9 +419,8 @@ void phy_start_machine(struct phy_device *phydev, /* phy_stop_machine * - * description: Stops the state machine timer, sets the state to - * UP (unless it wasn't up yet), and then frees the interrupt, - * if it is in use. This function must be called BEFORE + * description: Stops the state machine timer, sets the state to UP + * (unless it wasn't up yet). This function must be called BEFORE * phy_detach. */ void phy_stop_machine(struct phy_device *phydev) @@ -433,9 +432,6 @@ void phy_stop_machine(struct phy_device *phydev) phydev->state = PHY_UP; spin_unlock(&phydev->lock); - if (phydev->irq != PHY_POLL) - phy_stop_interrupts(phydev); - phydev->adjust_state = NULL; } -- cgit v1.1 From e454358ace657af953b5b289f49cf733973f41e4 Mon Sep 17 00:00:00 2001 From: Brice Goglin Date: Sun, 30 Jul 2006 00:14:09 -0400 Subject: [PATCH] myri10ge - Write the firmware in 256-bytes chunks When writing the firmware to the NIC, the FIFO is 256-bytes long, so we use 256-bytes chunks and a read to wait until the previous write is done. Signed-off-by: Brice Goglin Signed-off-by: Jeff Garzik --- drivers/net/myri10ge/myri10ge.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index c3e52c8..198c6f0 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -448,6 +448,7 @@ static int myri10ge_load_hotplug_firmware(struct myri10ge_priv *mgp, u32 * size) struct mcp_gen_header *hdr; size_t hdr_offset; int status; + unsigned i; if ((status = request_firmware(&fw, mgp->fw_name, dev)) < 0) { dev_err(dev, "Unable to load %s firmware image via hotplug\n", @@ -479,18 +480,12 @@ static int myri10ge_load_hotplug_firmware(struct myri10ge_priv *mgp, u32 * size) goto abort_with_fw; crc = crc32(~0, fw->data, fw->size); - if (mgp->tx.boundary == 2048) { - /* Avoid PCI burst on chipset with unaligned completions. */ - int i; - __iomem u32 *ptr = (__iomem u32 *) (mgp->sram + - MYRI10GE_FW_OFFSET); - for (i = 0; i < fw->size / 4; i++) { - __raw_writel(((u32 *) fw->data)[i], ptr + i); - wmb(); - } - } else { - myri10ge_pio_copy(mgp->sram + MYRI10GE_FW_OFFSET, fw->data, - fw->size); + for (i = 0; i < fw->size; i += 256) { + myri10ge_pio_copy(mgp->sram + MYRI10GE_FW_OFFSET + i, + fw->data + i, + min(256U, (unsigned)(fw->size - i))); + mb(); + readb(mgp->sram); } /* corruption checking is good for parity recovery and buggy chipset */ memcpy_fromio(fw->data, mgp->sram + MYRI10GE_FW_OFFSET, fw->size); -- cgit v1.1 From c54772e751c0262073e85a7aa87f093fc0dd44f1 Mon Sep 17 00:00:00 2001 From: Brice Goglin Date: Sun, 30 Jul 2006 00:14:15 -0400 Subject: [PATCH] myri10ge - Fix spurious invokations of the watchdog reset handler Fix spurious invocations of the watchdog reset handler. Signed-off-by: Brice Goglin Signed-off-by: Jeff Garzik --- drivers/net/myri10ge/myri10ge.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index 198c6f0..06440a8 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -177,6 +177,7 @@ struct myri10ge_priv { struct work_struct watchdog_work; struct timer_list watchdog_timer; int watchdog_tx_done; + int watchdog_tx_req; int watchdog_resets; int tx_linearized; int pause; @@ -2542,7 +2543,8 @@ static void myri10ge_watchdog_timer(unsigned long arg) mgp = (struct myri10ge_priv *)arg; if (mgp->tx.req != mgp->tx.done && - mgp->tx.done == mgp->watchdog_tx_done) + mgp->tx.done == mgp->watchdog_tx_done && + mgp->watchdog_tx_req != mgp->watchdog_tx_done) /* nic seems like it might be stuck.. */ schedule_work(&mgp->watchdog_work); else @@ -2551,6 +2553,7 @@ static void myri10ge_watchdog_timer(unsigned long arg) jiffies + myri10ge_watchdog_timeout * HZ); mgp->watchdog_tx_done = mgp->tx.done; + mgp->watchdog_tx_req = mgp->tx.req; } static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) -- cgit v1.1 From f1d39b291e2263f5e2f2ec5d4061802f76d8ae67 Mon Sep 17 00:00:00 2001 From: Unicorn Chang Date: Tue, 1 Aug 2006 12:18:07 +0800 Subject: [PATCH] ahci: skip protocol test altogether in spurious interrupt code Skip protocol test altogether in spurious interrupt code. If PIOS is received when it shouldn't, ahci will raise protocol violation. Signed-off-by: Unicorn Chang Signed-off-by: Jeff Garzik --- drivers/scsi/ahci.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c index 77e7202a..904c25f 100644 --- a/drivers/scsi/ahci.c +++ b/drivers/scsi/ahci.c @@ -940,14 +940,8 @@ static void ahci_host_intr(struct ata_port *ap) return; /* ignore interim PIO setup fis interrupts */ - if (ata_tag_valid(ap->active_tag)) { - struct ata_queued_cmd *qc = - ata_qc_from_tag(ap, ap->active_tag); - - if (qc && qc->tf.protocol == ATA_PROT_PIO && - (status & PORT_IRQ_PIOS_FIS)) - return; - } + if (ata_tag_valid(ap->active_tag) && (status & PORT_IRQ_PIOS_FIS)) + return; if (ata_ratelimit()) ata_port_printk(ap, KERN_INFO, "spurious interrupt " -- cgit v1.1 From c3cf30a989efec8144225517e0b2f82c955e3966 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sat, 5 Aug 2006 03:59:11 +0900 Subject: [PATCH] libata: fix ata_port_detach() for old EH ports ata_prot_detach() did nothing for old EH ports and thus SCSI hosts associated with those ports are left dangling after they are detached leaving stale devices and causing oops eventually. Make ata_port_detach() remove SCSI hosts for old EH ports. Signed-off-by: Tejun Heo --- drivers/scsi/libata-core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 386e5f2..bca92dd3 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -5558,7 +5558,7 @@ void ata_port_detach(struct ata_port *ap) int i; if (!ap->ops->error_handler) - return; + goto skip_eh; /* tell EH we're leaving & flush EH */ spin_lock_irqsave(ap->lock, flags); @@ -5594,6 +5594,7 @@ void ata_port_detach(struct ata_port *ap) cancel_delayed_work(&ap->hotplug_task); flush_workqueue(ata_aux_wq); + skip_eh: /* remove the associated SCSI host */ scsi_remove_host(ap->host); } -- cgit v1.1 From f814b75f4ed2ed58cd7bc876a0a9406f984aac6d Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sat, 5 Aug 2006 03:59:13 +0900 Subject: [PATCH] ata_piix: fix host_set private_data intialization To get host_set->private_data initialized reliably, all pinfos need to point to the same hpriv. Restore pinfo->private_data after pata pinfo assignment. Signed-off-by: Tejun Heo --- drivers/scsi/ata_piix.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c index 19745a3..298e464 100644 --- a/drivers/scsi/ata_piix.c +++ b/drivers/scsi/ata_piix.c @@ -828,6 +828,7 @@ static void __devinit piix_init_sata_map(struct pci_dev *pdev, case IDE: WARN_ON((i & 1) || map[i + 1] != IDE); pinfo[i / 2] = piix_port_info[ich5_pata]; + pinfo[i / 2].private_data = hpriv; i++; printk(" IDE IDE"); break; -- cgit v1.1 From f31e945c50e47b7163c6018928aa93b66e8f22f0 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sat, 5 Aug 2006 03:59:15 +0900 Subject: [PATCH] sata_sil24: don't set probe_ent->mmio_base sata_sil24 doesn't make use of probe_ent->mmio_base and setting this field causes the area to be released twice on detach. Don't set probe_ent->mmio_base. Signed-off-by: Tejun Heo --- drivers/scsi/sata_sil24.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c index 2e0f4a4..3f368c7 100644 --- a/drivers/scsi/sata_sil24.c +++ b/drivers/scsi/sata_sil24.c @@ -1106,7 +1106,6 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) probe_ent->irq = pdev->irq; probe_ent->irq_flags = IRQF_SHARED; - probe_ent->mmio_base = port_base; probe_ent->private_data = hpriv; hpriv->host_base = host_base; -- cgit v1.1 From 6543bc0777fadf129d8ee7ac82e0090fb0480403 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Sat, 5 Aug 2006 03:59:17 +0900 Subject: [PATCH] [libata] manually inline ata_host_remove() (tj: this is for the following ata_device_add() fix) Signed-off-by: Jeff Garzik Signed-off-by: Tejun Heo --- drivers/scsi/libata-core.c | 31 ++++++------------------------- 1 file changed, 6 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index bca92dd3..509b0488 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -5185,28 +5185,6 @@ void ata_host_stop (struct ata_host_set *host_set) iounmap(host_set->mmio_base); } - -/** - * ata_host_remove - Unregister SCSI host structure with upper layers - * @ap: Port to unregister - * @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) -{ - struct Scsi_Host *sh = ap->host; - - DPRINTK("ENTER\n"); - - if (do_unregister) - scsi_remove_host(sh); - - ap->ops->port_stop(ap); -} - /** * ata_dev_init - Initialize an ata_device structure * @dev: Device structure to initialize @@ -5532,8 +5510,11 @@ int ata_device_add(const struct ata_probe_ent *ent) err_out: for (i = 0; i < count; i++) { - ata_host_remove(host_set->ports[i], 1); - scsi_host_put(host_set->ports[i]->host); + struct ata_port *ap = host_set->ports[i]; + + scsi_remove_host(ap->host); + ap->ops->port_stop(ap); + scsi_host_put(ap->host); } err_free_ret: kfree(host_set); @@ -5663,7 +5644,7 @@ int ata_scsi_release(struct Scsi_Host *host) DPRINTK("ENTER\n"); ap->ops->port_disable(ap); - ata_host_remove(ap, 0); + ap->ops->port_stop(ap); DPRINTK("EXIT\n"); return 1; -- cgit v1.1 From 77f3f879387cc5fce6c7a4ca7777c586fe6291cd Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sat, 5 Aug 2006 03:59:19 +0900 Subject: [PATCH] libata: fix ata_device_add() error path In the error path, ata_device_add() * dereferences null host_set->ports[] element. * calls scsi_remove_host() on not-yet-added shost. This patch fixes both bugs. The first problem was spotted and initial patch submitted by Dave Jones . The second problem was mentioned and fixed by Jeff Garzik in a larger cleanup patch. Cc: Dave Jones Cc: Jeff Garzik Signed-off-by: Tejun Heo --- drivers/scsi/libata-core.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 509b0488..16fc2dd 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -5511,10 +5511,10 @@ int ata_device_add(const struct ata_probe_ent *ent) err_out: for (i = 0; i < count; i++) { struct ata_port *ap = host_set->ports[i]; - - scsi_remove_host(ap->host); - ap->ops->port_stop(ap); - scsi_host_put(ap->host); + if (ap) { + ap->ops->port_stop(ap); + scsi_host_put(ap->host); + } } err_free_ret: kfree(host_set); -- cgit v1.1 From 22479e1c0d111c60d29a4759408394cbdc7548a5 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 4 Aug 2006 22:51:51 -0400 Subject: Input: keyboard - change to use kzalloc Signed-off-by: Dmitry Torokhov --- drivers/char/keyboard.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index 30a7454..3e90aac 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -1297,9 +1297,9 @@ static struct input_handle *kbd_connect(struct input_handler *handler, if (i == BTN_MISC && !test_bit(EV_SND, dev->evbit)) return NULL; - if (!(handle = kmalloc(sizeof(struct input_handle), GFP_KERNEL))) + handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL); + if (!handle) return NULL; - memset(handle, 0, sizeof(struct input_handle)); handle->dev = dev; handle->handler = handler; -- cgit v1.1 From 0c19fcd83793be248f8108a52f895c8d0034b182 Mon Sep 17 00:00:00 2001 From: Roberto Castagnola Date: Fri, 4 Aug 2006 22:52:13 -0400 Subject: Input: logips2pp - fix button mapping for MX300 MX300 does not have an EXTRA_BTN - it is a simple wheel mouse with an additional task-switcher button, which is reported as side button (and not task button). Signed-off-by: Daniel Drake Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/logips2pp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/input/mouse/logips2pp.c b/drivers/input/mouse/logips2pp.c index 2f0d288..54b696c 100644 --- a/drivers/input/mouse/logips2pp.c +++ b/drivers/input/mouse/logips2pp.c @@ -238,8 +238,7 @@ static struct ps2pp_info *get_model_info(unsigned char model) { 100, PS2PP_KIND_MX, /* MX510 */ PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN | PS2PP_EXTRA_BTN | PS2PP_NAV_BTN }, - { 111, PS2PP_KIND_MX, /* MX300 */ - PS2PP_WHEEL | PS2PP_EXTRA_BTN | PS2PP_TASK_BTN }, + { 111, PS2PP_KIND_MX, PS2PP_WHEEL | PS2PP_SIDE_BTN }, /* MX300 reports task button as side */ { 112, PS2PP_KIND_MX, /* MX500 */ PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN | PS2PP_EXTRA_BTN | PS2PP_NAV_BTN }, -- cgit v1.1 From 184dd2751c653a572c79c1fff969000b8880da40 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 4 Aug 2006 22:52:26 -0400 Subject: Input: trackpoint - activate protocol when resuming Trackpoint driver was not sending the magic knock sequence upon resume causing incorrect device behavior after resuming from disk. Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/trackpoint.c | 52 ++++++++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/input/mouse/trackpoint.c b/drivers/input/mouse/trackpoint.c index 6d9ec9a..ae5871a 100644 --- a/drivers/input/mouse/trackpoint.c +++ b/drivers/input/mouse/trackpoint.c @@ -183,21 +183,26 @@ static struct attribute_group trackpoint_attr_group = { .attrs = trackpoint_attrs, }; -static void trackpoint_disconnect(struct psmouse *psmouse) +static int trackpoint_start_protocol(struct psmouse *psmouse, unsigned char *firmware_id) { - sysfs_remove_group(&psmouse->ps2dev.serio->dev.kobj, &trackpoint_attr_group); + unsigned char param[2] = { 0 }; - kfree(psmouse->private); - psmouse->private = NULL; + if (ps2_command(&psmouse->ps2dev, param, MAKE_PS2_CMD(0, 2, TP_READ_ID))) + return -1; + + if (param[0] != TP_MAGIC_IDENT) + return -1; + + if (firmware_id) + *firmware_id = param[1]; + + return 0; } static int trackpoint_sync(struct psmouse *psmouse) { - unsigned char toggle; struct trackpoint_data *tp = psmouse->private; - - if (!tp) - return -1; + unsigned char toggle; /* Disable features that may make device unusable with this driver */ trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_TWOHAND, &toggle); @@ -263,27 +268,38 @@ static void trackpoint_defaults(struct trackpoint_data *tp) tp->ext_dev = TP_DEF_EXT_DEV; } +static void trackpoint_disconnect(struct psmouse *psmouse) +{ + sysfs_remove_group(&psmouse->ps2dev.serio->dev.kobj, &trackpoint_attr_group); + + kfree(psmouse->private); + psmouse->private = NULL; +} + +static int trackpoint_reconnect(struct psmouse *psmouse) +{ + if (trackpoint_start_protocol(psmouse, NULL)) + return -1; + + if (trackpoint_sync(psmouse)) + return -1; + + return 0; +} + int trackpoint_detect(struct psmouse *psmouse, int set_properties) { struct trackpoint_data *priv; struct ps2dev *ps2dev = &psmouse->ps2dev; unsigned char firmware_id; unsigned char button_info; - unsigned char param[2]; - - param[0] = param[1] = 0; - if (ps2_command(ps2dev, param, MAKE_PS2_CMD(0, 2, TP_READ_ID))) - return -1; - - if (param[0] != TP_MAGIC_IDENT) + if (trackpoint_start_protocol(psmouse, &firmware_id)) return -1; if (!set_properties) return 0; - firmware_id = param[1]; - if (trackpoint_read(&psmouse->ps2dev, TP_EXT_BTN, &button_info)) { printk(KERN_WARNING "trackpoint.c: failed to get extended button data\n"); button_info = 0; @@ -296,7 +312,7 @@ int trackpoint_detect(struct psmouse *psmouse, int set_properties) psmouse->vendor = "IBM"; psmouse->name = "TrackPoint"; - psmouse->reconnect = trackpoint_sync; + psmouse->reconnect = trackpoint_reconnect; psmouse->disconnect = trackpoint_disconnect; trackpoint_defaults(priv); -- cgit v1.1 From 3d0f0fa0cb554541e10cb8cb84104e4b10828468 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 4 Aug 2006 22:52:46 -0400 Subject: Input: atkbd - restore repeat rate when resuming Make the AT keyboard driver restore previously set repeat rate when resuming. Noticed by Linus Torvalds. Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/atkbd.c | 103 ++++++++++++++++++++++++----------------- 1 file changed, 60 insertions(+), 43 deletions(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index ce1f10e..6bfa0cf 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c @@ -482,13 +482,7 @@ out: return IRQ_HANDLED; } -/* - * atkbd_event_work() is used to complete processing of events that - * can not be processed by input_event() which is often called from - * interrupt context. - */ - -static void atkbd_event_work(void *data) +static int atkbd_set_repeat_rate(struct atkbd *atkbd) { const short period[32] = { 33, 37, 42, 46, 50, 54, 58, 63, 67, 75, 83, 92, 100, 109, 116, 125, @@ -496,41 +490,64 @@ static void atkbd_event_work(void *data) const short delay[4] = { 250, 500, 750, 1000 }; - struct atkbd *atkbd = data; + struct input_dev *dev = atkbd->dev; + unsigned char param; + int i = 0, j = 0; + + while (i < ARRAY_SIZE(period) - 1 && period[i] < dev->rep[REP_PERIOD]) + i++; + dev->rep[REP_PERIOD] = period[i]; + + while (j < ARRAY_SIZE(period) - 1 && delay[j] < dev->rep[REP_DELAY]) + j++; + dev->rep[REP_DELAY] = delay[j]; + + param = i | (j << 5); + return ps2_command(&atkbd->ps2dev, ¶m, ATKBD_CMD_SETREP); +} + +static int atkbd_set_leds(struct atkbd *atkbd) +{ struct input_dev *dev = atkbd->dev; unsigned char param[2]; - int i, j; - mutex_lock(&atkbd->event_mutex); + param[0] = (test_bit(LED_SCROLLL, dev->led) ? 1 : 0) + | (test_bit(LED_NUML, dev->led) ? 2 : 0) + | (test_bit(LED_CAPSL, dev->led) ? 4 : 0); + if (ps2_command(&atkbd->ps2dev, param, ATKBD_CMD_SETLEDS)) + return -1; - if (test_and_clear_bit(ATKBD_LED_EVENT_BIT, &atkbd->event_mask)) { - param[0] = (test_bit(LED_SCROLLL, dev->led) ? 1 : 0) - | (test_bit(LED_NUML, dev->led) ? 2 : 0) - | (test_bit(LED_CAPSL, dev->led) ? 4 : 0); - ps2_command(&atkbd->ps2dev, param, ATKBD_CMD_SETLEDS); - - if (atkbd->extra) { - param[0] = 0; - param[1] = (test_bit(LED_COMPOSE, dev->led) ? 0x01 : 0) - | (test_bit(LED_SLEEP, dev->led) ? 0x02 : 0) - | (test_bit(LED_SUSPEND, dev->led) ? 0x04 : 0) - | (test_bit(LED_MISC, dev->led) ? 0x10 : 0) - | (test_bit(LED_MUTE, dev->led) ? 0x20 : 0); - ps2_command(&atkbd->ps2dev, param, ATKBD_CMD_EX_SETLEDS); - } + if (atkbd->extra) { + param[0] = 0; + param[1] = (test_bit(LED_COMPOSE, dev->led) ? 0x01 : 0) + | (test_bit(LED_SLEEP, dev->led) ? 0x02 : 0) + | (test_bit(LED_SUSPEND, dev->led) ? 0x04 : 0) + | (test_bit(LED_MISC, dev->led) ? 0x10 : 0) + | (test_bit(LED_MUTE, dev->led) ? 0x20 : 0); + if (ps2_command(&atkbd->ps2dev, param, ATKBD_CMD_EX_SETLEDS)) + return -1; } - if (test_and_clear_bit(ATKBD_REP_EVENT_BIT, &atkbd->event_mask)) { - i = j = 0; - while (i < 31 && period[i] < dev->rep[REP_PERIOD]) - i++; - while (j < 3 && delay[j] < dev->rep[REP_DELAY]) - j++; - dev->rep[REP_PERIOD] = period[i]; - dev->rep[REP_DELAY] = delay[j]; - param[0] = i | (j << 5); - ps2_command(&atkbd->ps2dev, param, ATKBD_CMD_SETREP); - } + return 0; +} + +/* + * atkbd_event_work() is used to complete processing of events that + * can not be processed by input_event() which is often called from + * interrupt context. + */ + +static void atkbd_event_work(void *data) +{ + struct atkbd *atkbd = data; + + mutex_lock(&atkbd->event_mutex); + + if (test_and_clear_bit(ATKBD_LED_EVENT_BIT, &atkbd->event_mask)) + atkbd_set_leds(atkbd); + + if (test_and_clear_bit(ATKBD_REP_EVENT_BIT, &atkbd->event_mask)) + atkbd_set_repeat_rate(atkbd); mutex_unlock(&atkbd->event_mutex); } @@ -975,7 +992,6 @@ static int atkbd_reconnect(struct serio *serio) { struct atkbd *atkbd = serio_get_drvdata(serio); struct serio_driver *drv = serio->drv; - unsigned char param[1]; if (!atkbd || !drv) { printk(KERN_DEBUG "atkbd: reconnect request, but serio is disconnected, ignoring...\n"); @@ -985,10 +1001,6 @@ 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); - if (atkbd_probe(atkbd)) return -1; if (atkbd->set != atkbd_select_set(atkbd, atkbd->set, atkbd->extra)) @@ -996,8 +1008,13 @@ static int atkbd_reconnect(struct serio *serio) atkbd_activate(atkbd); - if (ps2_command(&atkbd->ps2dev, param, ATKBD_CMD_SETLEDS)) - return -1; +/* + * Restore repeat rate and LEDs (that were reset by atkbd_activate) + * to pre-resume state + */ + if (!atkbd->softrepeat) + atkbd_set_repeat_rate(atkbd); + atkbd_set_leds(atkbd); } atkbd_enable(atkbd); -- cgit v1.1 From c669869710abd1ba47f25569ccc478c42f62a888 Mon Sep 17 00:00:00 2001 From: Edwin Huffstutler Date: Fri, 4 Aug 2006 22:53:02 -0400 Subject: Input: ati_remote - make filter time a module parameter Signed-off-by: Dmitry Torokhov --- drivers/usb/input/ati_remote.c | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/input/ati_remote.c b/drivers/usb/input/ati_remote.c index df198cf..b00232c 100644 --- a/drivers/usb/input/ati_remote.c +++ b/drivers/usb/input/ati_remote.c @@ -111,6 +111,16 @@ #define NAME_BUFSIZE 80 /* size of product name, path buffers */ #define DATA_BUFSIZE 63 /* size of URB data buffers */ +/* + * Duplicate event filtering time. + * Sequential, identical KIND_FILTERED inputs with less than + * FILTER_TIME milliseconds between them are considered as repeat + * events. The hardware generates 5 events for the first keypress + * and we have to take this into account for an accurate repeat + * behaviour. + */ +#define FILTER_TIME 60 /* msec */ + static unsigned long channel_mask; module_param(channel_mask, ulong, 0444); MODULE_PARM_DESC(channel_mask, "Bitmask of remote control channels to ignore"); @@ -119,6 +129,10 @@ static int debug; module_param(debug, int, 0444); MODULE_PARM_DESC(debug, "Enable extra debug messages and information"); +static int repeat_filter = FILTER_TIME; +module_param(repeat_filter, int, 0644); +MODULE_PARM_DESC(repeat_filter, "Repeat filter time, default = 60 msec"); + #define dbginfo(dev, format, arg...) do { if (debug) dev_info(dev , format , ## arg); } while (0) #undef err #define err(format, arg...) printk(KERN_ERR format , ## arg) @@ -146,15 +160,6 @@ static char init2[] = { 0x01, 0x00, 0x20, 0x14, 0x20, 0x20, 0x20 }; /* Acceleration curve for directional control pad */ static const char accel[] = { 1, 2, 4, 6, 9, 13, 20 }; -/* Duplicate event filtering time. - * Sequential, identical KIND_FILTERED inputs with less than - * FILTER_TIME jiffies between them are considered as repeat - * events. The hardware generates 5 events for the first keypress - * and we have to take this into account for an accurate repeat - * behaviour. - */ -#define FILTER_TIME 60 /* msec */ - struct ati_remote { struct input_dev *idev; struct usb_device *udev; @@ -464,9 +469,9 @@ static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs) if (ati_remote_tbl[index].kind == KIND_FILTERED) { /* Filter duplicate events which happen "too close" together. */ - if ((ati_remote->old_data[0] == data[1]) && - (ati_remote->old_data[1] == data[2]) && - time_before(jiffies, ati_remote->old_jiffies + msecs_to_jiffies(FILTER_TIME))) { + if (ati_remote->old_data[0] == data[1] && + ati_remote->old_data[1] == data[2] && + time_before(jiffies, ati_remote->old_jiffies + msecs_to_jiffies(repeat_filter))) { ati_remote->repeat_count++; } else { ati_remote->repeat_count = 0; @@ -476,8 +481,8 @@ static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs) ati_remote->old_data[1] = data[2]; ati_remote->old_jiffies = jiffies; - if ((ati_remote->repeat_count > 0) - && (ati_remote->repeat_count < 5)) + if (ati_remote->repeat_count > 0 && + ati_remote->repeat_count < 5) return; -- cgit v1.1 From c605b679144a39f291debd7031a4ada0337f02ef Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 4 Aug 2006 22:53:15 -0400 Subject: Input: ati_remote - relax permissions sysfs module parameters Allow changing debug and channel_mask parameters on the fly. Signed-off-by: Dmitry Torokhov --- drivers/usb/input/ati_remote.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/input/ati_remote.c b/drivers/usb/input/ati_remote.c index b00232c..bdf144b 100644 --- a/drivers/usb/input/ati_remote.c +++ b/drivers/usb/input/ati_remote.c @@ -122,11 +122,11 @@ #define FILTER_TIME 60 /* msec */ static unsigned long channel_mask; -module_param(channel_mask, ulong, 0444); +module_param(channel_mask, ulong, 0644); MODULE_PARM_DESC(channel_mask, "Bitmask of remote control channels to ignore"); static int debug; -module_param(debug, int, 0444); +module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Enable extra debug messages and information"); static int repeat_filter = FILTER_TIME; -- cgit v1.1 From c3c38fbd0cc8cc200a65b2ca7700e4dddedc13a0 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 4 Aug 2006 22:53:24 -0400 Subject: Input: ati_remote - add missing input_sync() When emulating button toggle drivers need to send input_sync() between 'down' and 'up' events, otherwise some users might miss keypress because device's state is only considered finalized after EV_SYN/SYN_REPORT is received. Signed-off-by: Dmitry Torokhov --- drivers/usb/input/ati_remote.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/usb/input/ati_remote.c b/drivers/usb/input/ati_remote.c index bdf144b..5a56f6c 100644 --- a/drivers/usb/input/ati_remote.c +++ b/drivers/usb/input/ati_remote.c @@ -489,6 +489,7 @@ static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs) input_regs(dev, regs); input_event(dev, ati_remote_tbl[index].type, ati_remote_tbl[index].code, 1); + input_sync(dev); input_event(dev, ati_remote_tbl[index].type, ati_remote_tbl[index].code, 0); input_sync(dev); -- cgit v1.1 From 2ffc1ccad85e8c2e81a6a4beb390fb4ce143256b Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 4 Aug 2006 22:53:37 -0400 Subject: Input: ati_remote - use msec instead of jiffies By using milliseconds instead of jiffies to calculate acceleration factor we make the code immune to changes in HZ. Signed-off-by: Dmitry Torokhov --- drivers/usb/input/ati_remote.c | 135 +++++++++++++++++++++++------------------ 1 file changed, 77 insertions(+), 58 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/input/ati_remote.c b/drivers/usb/input/ati_remote.c index 5a56f6c..3719fcb 100644 --- a/drivers/usb/input/ati_remote.c +++ b/drivers/usb/input/ati_remote.c @@ -157,9 +157,6 @@ MODULE_DEVICE_TABLE(usb, ati_remote_table); static char init1[] = { 0x01, 0x00, 0x20, 0x14 }; static char init2[] = { 0x01, 0x00, 0x20, 0x14, 0x20, 0x20, 0x20 }; -/* Acceleration curve for directional control pad */ -static const char accel[] = { 1, 2, 4, 6, 9, 13, 20 }; - struct ati_remote { struct input_dev *idev; struct usb_device *udev; @@ -417,6 +414,43 @@ static int ati_remote_event_lookup(int rem, unsigned char d1, unsigned char d2) } /* + * ati_remote_compute_accel + * + * Implements acceleration curve for directional control pad + * If elapsed time since last event is > 1/4 second, user "stopped", + * so reset acceleration. Otherwise, user is probably holding the control + * pad down, so we increase acceleration, ramping up over two seconds to + * a maximum speed. + */ +static int ati_remote_compute_accel(struct ati_remote *ati_remote) +{ + static const char accel[] = { 1, 2, 4, 6, 9, 13, 20 }; + unsigned long now = jiffies; + int acc; + + if (time_after(now, ati_remote->old_jiffies + msecs_to_jiffies(250))) { + acc = 1; + ati_remote->acc_jiffies = now; + } + else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(125))) + acc = accel[0]; + else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(250))) + acc = accel[1]; + else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(500))) + acc = accel[2]; + else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(1000))) + acc = accel[3]; + else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(1500))) + acc = accel[4]; + else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(2000))) + acc = accel[5]; + else + acc = accel[6]; + + return acc; +} + +/* * ati_remote_report_input */ static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs) @@ -494,63 +528,48 @@ static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs) ati_remote_tbl[index].code, 0); input_sync(dev); - return; - } + } else { - /* - * Other event kinds are from the directional control pad, and have an - * acceleration factor applied to them. Without this acceleration, the - * control pad is mostly unusable. - * - * If elapsed time since last event is > 1/4 second, user "stopped", - * so reset acceleration. Otherwise, user is probably holding the control - * pad down, so we increase acceleration, ramping up over two seconds to - * a maximum speed. The acceleration curve is #defined above. - */ - if (time_after(jiffies, ati_remote->old_jiffies + (HZ >> 2))) { - acc = 1; - ati_remote->acc_jiffies = jiffies; - } - else if (time_before(jiffies, ati_remote->acc_jiffies + (HZ >> 3))) acc = accel[0]; - else if (time_before(jiffies, ati_remote->acc_jiffies + (HZ >> 2))) acc = accel[1]; - else if (time_before(jiffies, ati_remote->acc_jiffies + (HZ >> 1))) acc = accel[2]; - else if (time_before(jiffies, ati_remote->acc_jiffies + HZ)) acc = accel[3]; - else if (time_before(jiffies, ati_remote->acc_jiffies + HZ+(HZ>>1))) acc = accel[4]; - else if (time_before(jiffies, ati_remote->acc_jiffies + (HZ << 1))) acc = accel[5]; - else acc = accel[6]; - - input_regs(dev, regs); - switch (ati_remote_tbl[index].kind) { - case KIND_ACCEL: - input_event(dev, ati_remote_tbl[index].type, - ati_remote_tbl[index].code, - ati_remote_tbl[index].value * acc); - break; - case KIND_LU: - input_report_rel(dev, REL_X, -acc); - input_report_rel(dev, REL_Y, -acc); - break; - case KIND_RU: - input_report_rel(dev, REL_X, acc); - input_report_rel(dev, REL_Y, -acc); - break; - case KIND_LD: - input_report_rel(dev, REL_X, -acc); - input_report_rel(dev, REL_Y, acc); - break; - case KIND_RD: - input_report_rel(dev, REL_X, acc); - input_report_rel(dev, REL_Y, acc); - break; - default: - dev_dbg(&ati_remote->interface->dev, "ati_remote kind=%d\n", - ati_remote_tbl[index].kind); - } - input_sync(dev); + /* + * Other event kinds are from the directional control pad, and have an + * acceleration factor applied to them. Without this acceleration, the + * control pad is mostly unusable. + */ + acc = ati_remote_compute_accel(ati_remote); - ati_remote->old_jiffies = jiffies; - ati_remote->old_data[0] = data[1]; - ati_remote->old_data[1] = data[2]; + input_regs(dev, regs); + switch (ati_remote_tbl[index].kind) { + case KIND_ACCEL: + input_event(dev, ati_remote_tbl[index].type, + ati_remote_tbl[index].code, + ati_remote_tbl[index].value * acc); + break; + case KIND_LU: + input_report_rel(dev, REL_X, -acc); + input_report_rel(dev, REL_Y, -acc); + break; + case KIND_RU: + input_report_rel(dev, REL_X, acc); + input_report_rel(dev, REL_Y, -acc); + break; + case KIND_LD: + input_report_rel(dev, REL_X, -acc); + input_report_rel(dev, REL_Y, acc); + break; + case KIND_RD: + input_report_rel(dev, REL_X, acc); + input_report_rel(dev, REL_Y, acc); + break; + default: + dev_dbg(&ati_remote->interface->dev, "ati_remote kind=%d\n", + ati_remote_tbl[index].kind); + } + input_sync(dev); + + ati_remote->old_jiffies = jiffies; + ati_remote->old_data[0] = data[1]; + ati_remote->old_data[1] = data[2]; + } } /* -- cgit v1.1 From c723e08af18e60cda3bbc90e0d6fb688587aeb9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juha=20=5B=18=EA=F6l=E4?= Date: Sun, 6 Aug 2006 09:58:22 +0100 Subject: [ARM] 3744/1: MMC: mmcqd gets stuck when block queue is plugged MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Patch from Juha [êölä When the block queue is plugged, mq->req must be set to NULL. Otherwise mq->req might be left non-NULL, even though mmcqd is not processing a request, thus preventing the MMC queue thread from being woken up when new requests do arrive. Signed-off-by: Juha Yrjola Signed-off-by: Russell King --- drivers/mmc/mmc_queue.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mmc/mmc_queue.c b/drivers/mmc/mmc_queue.c index 0b9682e..74f8cde 100644 --- a/drivers/mmc/mmc_queue.c +++ b/drivers/mmc/mmc_queue.c @@ -79,7 +79,8 @@ static int mmc_queue_thread(void *d) spin_lock_irq(q->queue_lock); set_current_state(TASK_INTERRUPTIBLE); if (!blk_queue_plugged(q)) - mq->req = req = elv_next_request(q); + req = elv_next_request(q); + mq->req = req; spin_unlock_irq(q->queue_lock); if (!req) { -- cgit v1.1 From 927cbe8a3e9ebc466f76af5a5278a520dc2d5699 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sat, 5 Aug 2006 12:13:45 -0700 Subject: [PATCH] drivers/edac/edac_mc.h must #include MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With CONFIG_PCI=n: CC drivers/edac/edac_mc.o drivers/edac/edac_mc.c: In function ‘add_mc_to_global_list’: drivers/edac/edac_mc.c:1362: error: implicit declaration of function ‘to_platform_device’ drivers/edac/edac_mc.c:1362: error: invalid type argument of ‘->’ drivers/edac/edac_mc.c: In function ‘edac_mc_add_mc’: drivers/edac/edac_mc.c:1467: error: invalid type argument of ‘->’ drivers/edac/edac_mc.c: In function ‘edac_mc_del_mc’: drivers/edac/edac_mc.c:1504: error: invalid type argument of ‘->’ Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/edac/edac_mc.h | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/edac/edac_mc.h b/drivers/edac/edac_mc.h index bf6ab8a..a1cfd4e 100644 --- a/drivers/edac/edac_mc.h +++ b/drivers/edac/edac_mc.h @@ -29,6 +29,7 @@ #include #include #include +#include #define EDAC_MC_LABEL_LEN 31 #define MC_PROC_NAME_MAX_LEN 7 -- cgit v1.1 From c3760ae1f914cf4479301a92c58ae65824ac5894 Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Sat, 5 Aug 2006 12:13:59 -0700 Subject: [PATCH] crash in aty128_set_lcd_enable() on PowerBook Current Linus tree crashes in aty128_set_lcd_enable() because par->pdev is NULL. This happens since at least a week. Call trace is: aty128_set_lcd_enable aty128fb_set_par fbcon_init visual_init take_over_console fbcon_takeover notifier_call_chain blocking_notifier_call_chain register_framebuffer aty128fb_probe pci_device_probe bus_for_each_dev driver_attach bus_add_driver driver_register __pci_register_driver aty128fb_init init kernel_thread - info->fix was assigned twice. - par->vram_size is assigned in aty128_probe(), no need to redo it again in aty128_init() - register_framebuffer() uses uninitialized struct members, move it past par->pdev assignment and past aty128_bl_init(). Signed-off-by: Olaf Hering Acked-by: Antonino Daplas Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/aty/aty128fb.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c index 8b08121..3e827e0 100644 --- a/drivers/video/aty/aty128fb.c +++ b/drivers/video/aty/aty128fb.c @@ -1913,9 +1913,6 @@ static int __devinit aty128_init(struct pci_dev *pdev, const struct pci_device_i u8 chip_rev; u32 dac; - if (!par->vram_size) /* may have already been probed */ - par->vram_size = aty_ld_le32(CONFIG_MEMSIZE) & 0x03FFFFFF; - /* Get the chip revision */ chip_rev = (aty_ld_le32(CONFIG_CNTL) >> 16) & 0x1F; @@ -2028,9 +2025,6 @@ static int __devinit aty128_init(struct pci_dev *pdev, const struct pci_device_i aty128_init_engine(par); - if (register_framebuffer(info) < 0) - return 0; - par->pm_reg = pci_find_capability(pdev, PCI_CAP_ID_PM); par->pdev = pdev; par->asleep = 0; @@ -2040,6 +2034,9 @@ static int __devinit aty128_init(struct pci_dev *pdev, const struct pci_device_i aty128_bl_init(par); #endif + if (register_framebuffer(info) < 0) + return 0; + printk(KERN_INFO "fb%d: %s frame buffer device on %s\n", info->node, info->fix.id, video_card); @@ -2089,7 +2086,6 @@ static int __devinit aty128_probe(struct pci_dev *pdev, const struct pci_device_ par = info->par; info->pseudo_palette = par->pseudo_palette; - info->fix = aty128fb_fix; /* Virtualize mmio region */ info->fix.mmio_start = reg_addr; -- cgit v1.1 From af2bc7d222c2700ccda060184d7bced7d7cb9fc2 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Sat, 5 Aug 2006 12:14:04 -0700 Subject: [PATCH] omap-rng build fix Seems like the omap-rng driver in the main tree predates the switch from to ... now it builds OK. Signed-off-by: David Brownell Signed-off-by: Michael Buesch Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/hw_random/omap-rng.c | 51 ++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/char/hw_random/omap-rng.c b/drivers/char/hw_random/omap-rng.c index 819516b..a01d796 100644 --- a/drivers/char/hw_random/omap-rng.c +++ b/drivers/char/hw_random/omap-rng.c @@ -25,12 +25,12 @@ #include #include #include +#include #include -#include +#include #include #include -#include #define RNG_OUT_REG 0x00 /* Output register */ #define RNG_STAT_REG 0x04 /* Status register @@ -52,7 +52,7 @@ static void __iomem *rng_base; static struct clk *rng_ick; -static struct device *rng_dev; +static struct platform_device *rng_dev; static u32 omap_rng_read_reg(int reg) { @@ -83,9 +83,8 @@ static struct hwrng omap_rng_ops = { .data_read = omap_rng_data_read, }; -static int __init omap_rng_probe(struct device *dev) +static int __init omap_rng_probe(struct platform_device *pdev) { - struct platform_device *pdev = to_platform_device(dev); struct resource *res, *mem; int ret; @@ -95,16 +94,14 @@ static int __init omap_rng_probe(struct device *dev) */ BUG_ON(rng_dev); - if (cpu_is_omap24xx()) { + if (cpu_is_omap24xx()) { rng_ick = clk_get(NULL, "rng_ick"); if (IS_ERR(rng_ick)) { - dev_err(dev, "Could not get rng_ick\n"); + dev_err(&pdev->dev, "Could not get rng_ick\n"); ret = PTR_ERR(rng_ick); return ret; - } - else { - clk_use(rng_ick); - } + } else + clk_enable(rng_ick); } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -117,7 +114,7 @@ static int __init omap_rng_probe(struct device *dev) if (mem == NULL) return -EBUSY; - dev_set_drvdata(dev, mem); + dev_set_drvdata(&pdev->dev, mem); rng_base = (u32 __iomem *)io_p2v(res->start); ret = hwrng_register(&omap_rng_ops); @@ -127,25 +124,25 @@ static int __init omap_rng_probe(struct device *dev) return ret; } - dev_info(dev, "OMAP Random Number Generator ver. %02x\n", + dev_info(&pdev->dev, "OMAP Random Number Generator ver. %02x\n", omap_rng_read_reg(RNG_REV_REG)); omap_rng_write_reg(RNG_MASK_REG, 0x1); - rng_dev = dev; + rng_dev = pdev; return 0; } -static int __exit omap_rng_remove(struct device *dev) +static int __exit omap_rng_remove(struct platform_device *pdev) { - struct resource *mem = dev_get_drvdata(dev); + struct resource *mem = dev_get_drvdata(&pdev->dev); hwrng_unregister(&omap_rng_ops); omap_rng_write_reg(RNG_MASK_REG, 0x0); if (cpu_is_omap24xx()) { - clk_unuse(rng_ick); + clk_disable(rng_ick); clk_put(rng_ick); } @@ -157,18 +154,16 @@ static int __exit omap_rng_remove(struct device *dev) #ifdef CONFIG_PM -static int omap_rng_suspend(struct device *dev, pm_message_t message, u32 level) +static int omap_rng_suspend(struct platform_device *pdev, pm_message_t message) { omap_rng_write_reg(RNG_MASK_REG, 0x0); - return 0; } -static int omap_rng_resume(struct device *dev, pm_message_t message, u32 level) +static int omap_rng_resume(struct platform_device *pdev) { omap_rng_write_reg(RNG_MASK_REG, 0x1); - - return 1; + return 0; } #else @@ -179,9 +174,11 @@ static int omap_rng_resume(struct device *dev, pm_message_t message, u32 level) #endif -static struct device_driver omap_rng_driver = { - .name = "omap_rng", - .bus = &platform_bus_type, +static struct platform_driver omap_rng_driver = { + .driver = { + .name = "omap_rng", + .owner = THIS_MODULE, + }, .probe = omap_rng_probe, .remove = __exit_p(omap_rng_remove), .suspend = omap_rng_suspend, @@ -193,12 +190,12 @@ static int __init omap_rng_init(void) if (!cpu_is_omap16xx() && !cpu_is_omap24xx()) return -ENODEV; - return driver_register(&omap_rng_driver); + return platform_driver_register(&omap_rng_driver); } static void __exit omap_rng_exit(void) { - driver_unregister(&omap_rng_driver); + platform_driver_unregister(&omap_rng_driver); } module_init(omap_rng_init); -- cgit v1.1 From f9abd1ace43d6186268856dbec2ebf411218d6ca Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Sat, 5 Aug 2006 12:14:07 -0700 Subject: [PATCH] md: Fix a bug that recently crept into md/linear A recent patch that allowed linear arrays to be reconfigured on-line allowed in a bug which results in divide by zero - not all mddev->array_size were converted to conf->array_size. This patch finished the conversion and fixed the bug. The offending patch was commit 7c7546ccf6463edbeee8d9aac6de7be1cd80d08a. Thanks to Simon Kirby for the bug report. Cc: Simon Kirby Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/md/linear.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/md/linear.c b/drivers/md/linear.c index ff83c9b..b99c19c 100644 --- a/drivers/md/linear.c +++ b/drivers/md/linear.c @@ -162,7 +162,7 @@ static linear_conf_t *linear_conf(mddev_t *mddev, int raid_disks) goto out; } - min_spacing = mddev->array_size; + min_spacing = conf->array_size; sector_div(min_spacing, PAGE_SIZE/sizeof(struct dev_info *)); /* min_spacing is the minimum spacing that will fit the hash @@ -171,7 +171,7 @@ static linear_conf_t *linear_conf(mddev_t *mddev, int raid_disks) * that is larger than min_spacing as use the size of that as * the actual spacing */ - conf->hash_spacing = mddev->array_size; + conf->hash_spacing = conf->array_size; for (i=0; i < cnt-1 ; i++) { sector_t sz = 0; int j; @@ -228,7 +228,7 @@ static linear_conf_t *linear_conf(mddev_t *mddev, int raid_disks) curr_offset = 0; i = 0; for (curr_offset = 0; - curr_offset < mddev->array_size; + curr_offset < conf->array_size; curr_offset += conf->hash_spacing) { while (i < mddev->raid_disks-1 && -- cgit v1.1 From fd2d54300369690500fc9b1bac9440d2ee81913a Mon Sep 17 00:00:00 2001 From: Rodolfo Giometti Date: Sat, 5 Aug 2006 12:14:19 -0700 Subject: [PATCH] au1100fb: info->var.rotate fix Fix "info->var.rotate" data settings. This info should be deduced directly from "fbdev->panel->control_base" defined into au1100fb.h. Signed-off-by: Rodolfo Giometti Signed-off-by: Antonino Daplas Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/au1100fb.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/video/au1100fb.c b/drivers/video/au1100fb.c index a92a91f..26086bf 100644 --- a/drivers/video/au1100fb.c +++ b/drivers/video/au1100fb.c @@ -164,10 +164,11 @@ int au1100fb_setmode(struct au1100fb_device *fbdev) } info->screen_size = info->fix.line_length * info->var.yres_virtual; + info->var.rotate = ((fbdev->panel->control_base&LCD_CONTROL_SM_MASK) \ + >> LCD_CONTROL_SM_BIT) * 90; /* Determine BPP mode and format */ - fbdev->regs->lcd_control = fbdev->panel->control_base | - ((info->var.rotate/90) << LCD_CONTROL_SM_BIT); + fbdev->regs->lcd_control = fbdev->panel->control_base; fbdev->regs->lcd_intenable = 0; fbdev->regs->lcd_intstatus = 0; -- cgit v1.1 From bb39e419740435b7fbb0314e376ba468be7db67a Mon Sep 17 00:00:00 2001 From: Rodolfo Giometti Date: Sat, 5 Aug 2006 12:14:22 -0700 Subject: [PATCH] au1100fb: Fix startup sequence - fix up the start up sequence. This new sequence allow you to correctly enable the LCD controller even if the bootloader has already did it. - fix up a wrong indentation issue. Signed-off-by: Rodolfo Giometti Signed-off-by: Antonino Daplas Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/au1100fb.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/video/au1100fb.c b/drivers/video/au1100fb.c index 26086bf..f25d5d6 100644 --- a/drivers/video/au1100fb.c +++ b/drivers/video/au1100fb.c @@ -156,7 +156,7 @@ int au1100fb_setmode(struct au1100fb_device *fbdev) 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; @@ -169,16 +169,11 @@ int au1100fb_setmode(struct au1100fb_device *fbdev) /* Determine BPP mode and format */ fbdev->regs->lcd_control = fbdev->panel->control_base; - - fbdev->regs->lcd_intenable = 0; - fbdev->regs->lcd_intstatus = 0; - fbdev->regs->lcd_horztiming = fbdev->panel->horztiming; - fbdev->regs->lcd_verttiming = fbdev->panel->verttiming; - fbdev->regs->lcd_clkcontrol = fbdev->panel->clkcontrol_base; - + fbdev->regs->lcd_intenable = 0; + fbdev->regs->lcd_intstatus = 0; fbdev->regs->lcd_dmaaddr0 = LCD_DMA_SA_N(fbdev->fb_phys); if (panel_is_dual(fbdev->panel)) { @@ -207,6 +202,8 @@ int au1100fb_setmode(struct au1100fb_device *fbdev) /* Resume controller */ fbdev->regs->lcd_control |= LCD_CONTROL_GO; + mdelay(10); + au1100fb_fb_blank(VESA_NO_BLANKING, info); return 0; } -- cgit v1.1 From 229395c90aadbadef76bacf52b9cb3326f509e93 Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Sat, 5 Aug 2006 12:14:36 -0700 Subject: [PATCH] pSeries hvsi char driver null pointer deref Under certain rare circumstances, it appears that there can be be a NULL-pointer deref when a user fiddles with terminal emeulation programs while outpu is being sent to the console. This patch checks for and avoids a NULL-pointer deref. Signed-off-by: Hollis Blanchard Signed-off-by: Linas Vepstas Cc: Paul Fulghum Acked-by: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/hvsi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/char/hvsi.c b/drivers/char/hvsi.c index 41db806..54cbb58 100644 --- a/drivers/char/hvsi.c +++ b/drivers/char/hvsi.c @@ -311,7 +311,8 @@ static void hvsi_recv_control(struct hvsi_struct *hp, uint8_t *packet, /* CD went away; no more connection */ pr_debug("hvsi%i: CD dropped\n", hp->index); hp->mctrl &= TIOCM_CD; - if (!(hp->tty->flags & CLOCAL)) + /* If userland hasn't done an open(2) yet, hp->tty is NULL. */ + if (hp->tty && !(hp->tty->flags & CLOCAL)) *to_hangup = hp->tty; } break; -- cgit v1.1 From 64e0cc38b69b8d43ab9793f50e4bb09cea0e6bb9 Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Sat, 5 Aug 2006 12:14:39 -0700 Subject: [PATCH] pSeries: hvsi char driver janitorial cleanup A set of tty line discipline cleanup patches were introduced before the dawn of time, in kernel version 2.4.21. This patch performs that cleanup for the hvsi driver. The hvsi driver is used only on IBM pSeries PowerPC boxes. The driver was originally written by Hollis Blanchard, who has delegated maintainership to me. So this my first and maybe only patch in this official new role, because this driver is otherwise bug-free :-) Alan: "Actually its also a bug fix, tty->ldisc should be locked by refcounting and the helpers do this for you." Signed-off-by: Linas Vepstas Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Acked-by: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/hvsi.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/char/hvsi.c b/drivers/char/hvsi.c index 54cbb58..017f755 100644 --- a/drivers/char/hvsi.c +++ b/drivers/char/hvsi.c @@ -987,10 +987,7 @@ static void hvsi_write_worker(void *arg) start_j = 0; #endif /* DEBUG */ wake_up_all(&hp->emptyq); - if (test_bit(TTY_DO_WRITE_WAKEUP, &hp->tty->flags) - && hp->tty->ldisc.write_wakeup) - hp->tty->ldisc.write_wakeup(hp->tty); - wake_up_interruptible(&hp->tty->write_wait); + tty_wakeup(hp->tty); } out: -- cgit v1.1 From 453c3e478e94004606b394b9ea57de71094e7c6a Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Sat, 5 Aug 2006 12:14:43 -0700 Subject: [PATCH] eicon: fix define conflict with ptrace * MODE_MASK is unused in eicon driver. * Conflicts with a ptrace stuff on arm. drivers/isdn/hardware/eicon/divasync.h:259:1: warning: "MODE_MASK" redefined include2/asm/ptrace.h:48:1: warning: this is the location of the previous definition Signed-off-by: Alexey Dobriyan Acked-by: Karsten Keil Acked-by: Armin Schindler Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/isdn/hardware/eicon/divasync.h | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/isdn/hardware/eicon/divasync.h b/drivers/isdn/hardware/eicon/divasync.h index 0a5be7f..af3eb9e 100644 --- a/drivers/isdn/hardware/eicon/divasync.h +++ b/drivers/isdn/hardware/eicon/divasync.h @@ -256,7 +256,6 @@ typedef struct #define NO_ORDER_CHECK_MASK 0x00000010 #define LOW_CHANNEL_MASK 0x00000020 #define NO_HSCX30_MASK 0x00000040 -#define MODE_MASK 0x00000080 #define SET_BOARD 0x00001000 #define SET_CRC4 0x00030000 #define SET_L1_TRISTATE 0x00040000 -- cgit v1.1 From e31f59ce593b073ee14241781edfb0637697eeb6 Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Sat, 5 Aug 2006 12:14:53 -0700 Subject: [PATCH] ieee1394: sbp2: enable auto spin-up for Maxtor disks At least Maxtor OneTouch III require a "start stop unit" command after auto spin-down before the next access can proceed. This patch activates the responsible code in scsi_mod for all Maxtor SBP-2 disks. https://bugzilla.novell.com/show_bug.cgi?id=183011 Maybe that should be done for all SBP-2 disks, but better be cautious. Signed-off-by: Stefan Richter Cc: Jody McIntyre Cc: Ben Collins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/ieee1394/sbp2.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c index aaa74f2..b08755e 100644 --- a/drivers/ieee1394/sbp2.c +++ b/drivers/ieee1394/sbp2.c @@ -2515,6 +2515,9 @@ static int sbp2scsi_slave_configure(struct scsi_device *sdev) sdev->skip_ms_page_8 = 1; if (scsi_id->workarounds & SBP2_WORKAROUND_FIX_CAPACITY) sdev->fix_capacity = 1; + if (scsi_id->ne->guid_vendor_id == 0x0010b9 && /* Maxtor's OUI */ + (sdev->type == TYPE_DISK || sdev->type == TYPE_RBC)) + sdev->allow_restart = 1; return 0; } -- cgit v1.1 From fa25d8d6d3fa0fecd00cd4b909011291eae9257d Mon Sep 17 00:00:00 2001 From: KAMEZAWA Hiroyuki Date: Sat, 5 Aug 2006 12:15:02 -0700 Subject: [PATCH] memory hotadd fixes: avoid check in acpi add_memory() does all necessary check to avoid collision. then, acpi layer doesn't have to check region by itself. (*) pfn_valid() just returns page struct is valid or not. It returns 0 if a section has been already added even is ioresource is not added. ioresource collision check in mm/memory_hotplug.c can do more precise collistion check. added enabled bit check just for sanity check.. Signed-off-by: KAMEZAWA Hiroyuki Cc: Keith Mannthey Cc: Yasunori Goto Cc: Dave Hansen Cc: "Brown, Len" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/acpi/acpi_memhotplug.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c index 81e970a..e9175ea 100644 --- a/drivers/acpi/acpi_memhotplug.c +++ b/drivers/acpi/acpi_memhotplug.c @@ -230,17 +230,10 @@ static int acpi_memory_enable_device(struct acpi_memory_device *mem_device) * (i.e. memory-hot-remove function) */ list_for_each_entry(info, &mem_device->res_list, list) { - u64 start_pfn, end_pfn; - - start_pfn = info->start_addr >> PAGE_SHIFT; - end_pfn = (info->start_addr + info->length - 1) >> PAGE_SHIFT; - - if (pfn_valid(start_pfn) || pfn_valid(end_pfn)) { - /* already enabled. try next area */ + if (info->enabled) { /* just sanity check...*/ num_enabled++; continue; } - result = add_memory(node, info->start_addr, info->length); if (result) continue; -- cgit v1.1 From 5d2870faaa1fdcec795a6bf4dbbfc3e5d57fd7ab Mon Sep 17 00:00:00 2001 From: KAMEZAWA Hiroyuki Date: Sat, 5 Aug 2006 12:15:04 -0700 Subject: [PATCH] memory hotadd fixes: avoid registering res twice both of acpi_memory_enable_device() and acpi_memory_add_device() may evaluate _CRS method. We should avoid evaluate device's resource twice if we could get it successfully in past. Signed-off-by: KAMEZWA Hiroyuki Cc: Keith Mannthey Cc: Yasunori Goto Cc: Dave Hansen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/acpi/acpi_memhotplug.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c index e9175ea..b0d4b14 100644 --- a/drivers/acpi/acpi_memhotplug.c +++ b/drivers/acpi/acpi_memhotplug.c @@ -129,11 +129,15 @@ acpi_memory_get_device_resources(struct acpi_memory_device *mem_device) struct acpi_memory_info *info, *n; + if (!list_empty(&mem_device->res_list)) + return 0; + status = acpi_walk_resources(mem_device->device->handle, METHOD_NAME__CRS, acpi_memory_get_resource, mem_device); if (ACPI_FAILURE(status)) { list_for_each_entry_safe(info, n, &mem_device->res_list, list) kfree(info); + INIT_LIST_HEAD(&mem_device->res_list); return -EINVAL; } -- cgit v1.1 From 2b8de5f50e4a302b83ebcd5b0120621336d50bd6 Mon Sep 17 00:00:00 2001 From: matthieu castet Date: Sat, 5 Aug 2006 12:15:12 -0700 Subject: [PATCH] pnpacpi: reject ACPI_PRODUCER resources A patch in -mm kernel correct the parsing of "address resources" of pnpacpi. Before we assumed it was memory only, but it could be also IO. But this change show an hidden bug : some resources could be producer type that are not handled by pnp layer. So we should ignore the producer resources. This patch fixes bug 6292 (http://bugzilla.kernel.org/show_bug.cgi?id=6292). Some devices like PNP0A03 have 0xd00-0xffff and 0x0-0xcf7 as IO producer resources. Before correcting "address resources" parsing, it was seen as memory and was harmless, because nobody tried to reserve this memory range as it should be IO. With the correction it become IO resources, and make failed all others device that want to register IO in this range and use pnp layer (like a ISA sound card). The solution is to ignore producer resources Signed-off-by: Matthieu CASTET Signed-off-by: Uwe Bugla Cc: Bjorn Helgaas Cc: Adam Belay Cc: "Brown, Len" Acked-by: Shaohua Li Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pnp/pnpacpi/rsparser.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c index 2122688..dc79b0a 100644 --- a/drivers/pnp/pnpacpi/rsparser.c +++ b/drivers/pnp/pnpacpi/rsparser.c @@ -173,6 +173,9 @@ pnpacpi_parse_allocated_address_space(struct pnp_resource_table *res_table, return; } + if (p->producer_consumer == ACPI_PRODUCER) + return; + if (p->resource_type == ACPI_MEMORY_RANGE) pnpacpi_parse_allocated_memresource(res_table, p->minimum, p->address_length); @@ -252,9 +255,14 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, break; case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: + if (res->data.ext_address64.producer_consumer == ACPI_PRODUCER) + return AE_OK; break; case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: + if (res->data.extended_irq.producer_consumer == ACPI_PRODUCER) + return AE_OK; + for (i = 0; i < res->data.extended_irq.interrupt_count; i++) { pnpacpi_parse_allocated_irqresource(res_table, res->data.extended_irq.interrupts[i], -- cgit v1.1 From 3e3183bab0257a6d02038658c53b491e1378612f Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Sat, 5 Aug 2006 12:15:19 -0700 Subject: [PATCH] SCX200_ACB: eliminate spurious timeout errors While busy-waiting for completion, check the hardware after scheduling; don't schedule and then immediately check the _timeout_. If the yield() took a long time (as it does on my OLPC prototype board when it's busy), we'd report a timeout even though the hardware was now ready. This fixes it, and also switches the yield() for a cond_resched() because we don't actually want to be _that_ nice about it. I see nice tightly-packed SMBus transactions now, rather than waiting for milliseconds between successive phases. Actually, we shouldn't be busy-waiting here at all. We should be using interrupts. That's an exercise for another day though. Signed-off-by: David Woodhouse Cc: Christer Weinigel Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/i2c/busses/scx200_acb.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c index ced309f..eae9e81 100644 --- a/drivers/i2c/busses/scx200_acb.c +++ b/drivers/i2c/busses/scx200_acb.c @@ -232,7 +232,7 @@ static void scx200_acb_poll(struct scx200_acb_iface *iface) unsigned long timeout; timeout = jiffies + POLL_TIMEOUT; - while (time_before(jiffies, timeout)) { + while (1) { status = inb(ACBST); /* Reset the status register to avoid the hang */ @@ -242,7 +242,10 @@ static void scx200_acb_poll(struct scx200_acb_iface *iface) scx200_acb_machine(iface, status); return; } - yield(); + if (time_after(jiffies, timeout)) + break; + cpu_relax(); + cond_resched(); } dev_err(&iface->adapter.dev, "timeout in state %s\n", -- cgit v1.1 From 64ba88182962698a8cb75792372c1dddaef82989 Mon Sep 17 00:00:00 2001 From: James Smart Date: Wed, 2 Aug 2006 15:24:34 -0400 Subject: [SCSI] lpfc 8.1.7 : Add statistics reset callback for FC transport Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_attr.c | 90 +++++++++++++++++++++++++++++++++++++++++-- drivers/scsi/lpfc/lpfc_sli.c | 3 ++ drivers/scsi/lpfc/lpfc_sli.h | 14 +++++++ 3 files changed, 103 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 5c68cdd..762d623 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -1210,8 +1210,10 @@ lpfc_get_stats(struct Scsi_Host *shost) struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata; struct lpfc_sli *psli = &phba->sli; struct fc_host_statistics *hs = &phba->link_stats; + struct lpfc_lnk_stat * lso = &psli->lnk_stat_offsets; LPFC_MBOXQ_t *pmboxq; MAILBOX_t *pmb; + unsigned long seconds; int rc = 0; pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); @@ -1272,22 +1274,103 @@ lpfc_get_stats(struct Scsi_Host *shost) hs->invalid_crc_count = pmb->un.varRdLnk.crcCnt; hs->error_frames = pmb->un.varRdLnk.crcCnt; + hs->link_failure_count -= lso->link_failure_count; + hs->loss_of_sync_count -= lso->loss_of_sync_count; + hs->loss_of_signal_count -= lso->loss_of_signal_count; + hs->prim_seq_protocol_err_count -= lso->prim_seq_protocol_err_count; + hs->invalid_tx_word_count -= lso->invalid_tx_word_count; + hs->invalid_crc_count -= lso->invalid_crc_count; + hs->error_frames -= lso->error_frames; + if (phba->fc_topology == TOPOLOGY_LOOP) { hs->lip_count = (phba->fc_eventTag >> 1); + hs->lip_count -= lso->link_events; hs->nos_count = -1; } else { hs->lip_count = -1; hs->nos_count = (phba->fc_eventTag >> 1); + hs->nos_count -= lso->link_events; } hs->dumped_frames = -1; -/* FIX ME */ - /*hs->SecondsSinceLastReset = (jiffies - lpfc_loadtime) / HZ;*/ + seconds = get_seconds(); + if (seconds < psli->stats_start) + hs->seconds_since_last_reset = seconds + + ((unsigned long)-1 - psli->stats_start); + else + hs->seconds_since_last_reset = seconds - psli->stats_start; return hs; } +static void +lpfc_reset_stats(struct Scsi_Host *shost) +{ + struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata; + struct lpfc_sli *psli = &phba->sli; + struct lpfc_lnk_stat * lso = &psli->lnk_stat_offsets; + LPFC_MBOXQ_t *pmboxq; + MAILBOX_t *pmb; + int rc = 0; + + pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!pmboxq) + return; + memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t)); + + pmb = &pmboxq->mb; + pmb->mbxCommand = MBX_READ_STATUS; + pmb->mbxOwner = OWN_HOST; + pmb->un.varWords[0] = 0x1; /* reset request */ + pmboxq->context1 = NULL; + + if ((phba->fc_flag & FC_OFFLINE_MODE) || + (!(psli->sli_flag & LPFC_SLI2_ACTIVE))) + rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL); + else + rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2); + + if (rc != MBX_SUCCESS) { + if (rc == MBX_TIMEOUT) + pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl; + else + mempool_free(pmboxq, phba->mbox_mem_pool); + return; + } + + memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t)); + pmb->mbxCommand = MBX_READ_LNK_STAT; + pmb->mbxOwner = OWN_HOST; + pmboxq->context1 = NULL; + + if ((phba->fc_flag & FC_OFFLINE_MODE) || + (!(psli->sli_flag & LPFC_SLI2_ACTIVE))) + rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL); + else + rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2); + + if (rc != MBX_SUCCESS) { + if (rc == MBX_TIMEOUT) + pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl; + else + mempool_free( pmboxq, phba->mbox_mem_pool); + return; + } + + lso->link_failure_count = pmb->un.varRdLnk.linkFailureCnt; + lso->loss_of_sync_count = pmb->un.varRdLnk.lossSyncCnt; + lso->loss_of_signal_count = pmb->un.varRdLnk.lossSignalCnt; + lso->prim_seq_protocol_err_count = pmb->un.varRdLnk.primSeqErrCnt; + lso->invalid_tx_word_count = pmb->un.varRdLnk.invalidXmitWord; + lso->invalid_crc_count = pmb->un.varRdLnk.crcCnt; + lso->error_frames = pmb->un.varRdLnk.crcCnt; + lso->link_events = (phba->fc_eventTag >> 1); + + psli->stats_start = get_seconds(); + + return; +} /* * The LPFC driver treats linkdown handling as target loss events so there @@ -1431,8 +1514,7 @@ struct fc_function_template lpfc_transport_functions = { */ .get_fc_host_stats = lpfc_get_stats, - - /* the LPFC driver doesn't support resetting stats yet */ + .reset_fc_host_stats = lpfc_reset_stats, .dd_fcrport_size = sizeof(struct lpfc_rport_data), .show_rport_maxframe_size = 1, diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 350a625..f453fcc 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -1792,6 +1792,9 @@ lpfc_sli_brdrestart(struct lpfc_hba * phba) spin_unlock_irq(phba->host->host_lock); + memset(&psli->lnk_stat_offsets, 0, sizeof(psli->lnk_stat_offsets)); + psli->stats_start = get_seconds(); + if (skip_post) mdelay(100); else diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h index d8ef0d2..478e799 100644 --- a/drivers/scsi/lpfc/lpfc_sli.h +++ b/drivers/scsi/lpfc/lpfc_sli.h @@ -172,6 +172,18 @@ struct lpfc_sli_stat { uint32_t mbox_busy; /* Mailbox cmd busy */ }; +/* Structure to store link status values when port stats are reset */ +struct lpfc_lnk_stat { + uint32_t link_failure_count; + uint32_t loss_of_sync_count; + uint32_t loss_of_signal_count; + uint32_t prim_seq_protocol_err_count; + uint32_t invalid_tx_word_count; + uint32_t invalid_crc_count; + uint32_t error_frames; + uint32_t link_events; +}; + /* Structure used to hold SLI information */ struct lpfc_sli { uint32_t num_rings; @@ -201,6 +213,8 @@ struct lpfc_sli { struct lpfc_iocbq ** iocbq_lookup; /* array to lookup IOCB by IOTAG */ size_t iocbq_lookup_len; /* current lengs of the array */ uint16_t last_iotag; /* last allocated IOTAG */ + unsigned long stats_start; /* in seconds */ + struct lpfc_lnk_stat lnk_stat_offsets; }; /* Given a pointer to the start of the ring, and the slot number of -- cgit v1.1 From a309a6b6e64b8147b7cfe7388237fb83834f58c9 Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 1 Aug 2006 07:33:43 -0400 Subject: [SCSI] lpfc 8.1.7 : Fix failing firmware download due to mailbox delays needing to be longer Fix failing firmware download due to mailbox delays needing to be longer. Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_attr.c | 3 ++- drivers/scsi/lpfc/lpfc_crtn.h | 1 + drivers/scsi/lpfc/lpfc_mbox.c | 16 ++++++++++++++++ drivers/scsi/lpfc/lpfc_sli.c | 11 +++++++---- drivers/scsi/lpfc/lpfc_sli.h | 6 ++++++ 5 files changed, 32 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 762d623..4ccce14 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -1000,7 +1000,8 @@ sysfs_mbox_read(struct kobject *kobj, char *buf, loff_t off, size_t count) spin_unlock_irq(phba->host->host_lock); rc = lpfc_sli_issue_mbox_wait (phba, phba->sysfs_mbox.mbox, - phba->fc_ratov * 2); + lpfc_mbox_tmo_val(phba, + phba->sysfs_mbox.mbox->mb.mbxCommand) * HZ); spin_lock_irq(phba->host->host_lock); } diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index 517e9e4..2a17646 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -127,6 +127,7 @@ void lpfc_config_port(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_kill_board(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_mbox_put(struct lpfc_hba *, LPFC_MBOXQ_t *); LPFC_MBOXQ_t *lpfc_mbox_get(struct lpfc_hba *); +int lpfc_mbox_tmo_val(struct lpfc_hba *, int); int lpfc_mem_alloc(struct lpfc_hba *); void lpfc_mem_free(struct lpfc_hba *); diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c index e42f22a..4d016c2 100644 --- a/drivers/scsi/lpfc/lpfc_mbox.c +++ b/drivers/scsi/lpfc/lpfc_mbox.c @@ -651,3 +651,19 @@ lpfc_mbox_get(struct lpfc_hba * phba) return mbq; } + +int +lpfc_mbox_tmo_val(struct lpfc_hba *phba, int cmd) +{ + switch (cmd) { + case MBX_WRITE_NV: /* 0x03 */ + case MBX_UPDATE_CFG: /* 0x1B */ + case MBX_DOWN_LOAD: /* 0x1C */ + case MBX_DEL_LD_ENTRY: /* 0x1D */ + case MBX_LOAD_AREA: /* 0x81 */ + case MBX_FLASH_WR_ULA: /* 0x98 */ + case MBX_LOAD_EXP_ROM: /* 0x9C */ + return LPFC_MBOX_TMO_FLASH_CMD; + } + return LPFC_MBOX_TMO; +} diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index f453fcc..4dc2d58 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -2197,7 +2197,8 @@ lpfc_sli_issue_mbox(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmbox, uint32_t flag) return (MBX_NOT_FINISHED); } /* timeout active mbox command */ - mod_timer(&psli->mbox_tmo, jiffies + HZ * LPFC_MBOX_TMO); + mod_timer(&psli->mbox_tmo, (jiffies + + (HZ * lpfc_mbox_tmo_val(phba, mb->mbxCommand)))); } /* Mailbox cmd issue */ @@ -2257,7 +2258,6 @@ lpfc_sli_issue_mbox(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmbox, uint32_t flag) break; case MBX_POLL: - i = 0; psli->mbox_active = NULL; if (psli->sli_flag & LPFC_SLI2_ACTIVE) { /* First read mbox status word */ @@ -2271,11 +2271,14 @@ lpfc_sli_issue_mbox(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmbox, uint32_t flag) /* Read the HBA Host Attention Register */ ha_copy = readl(phba->HAregaddr); + i = lpfc_mbox_tmo_val(phba, mb->mbxCommand); + i *= 1000; /* Convert to ms */ + /* Wait for command to complete */ while (((word0 & OWN_CHIP) == OWN_CHIP) || (!(ha_copy & HA_MBATT) && (phba->hba_state > LPFC_WARM_START))) { - if (i++ >= 100) { + if (i-- <= 0) { psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; spin_unlock_irqrestore(phba->host->host_lock, drvr_flag); @@ -2293,7 +2296,7 @@ lpfc_sli_issue_mbox(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmbox, uint32_t flag) /* Can be in interrupt context, do not sleep */ /* (or might be called with interrupts disabled) */ - mdelay(i); + mdelay(1); spin_lock_irqsave(phba->host->host_lock, drvr_flag); diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h index 478e799..e26de6809 100644 --- a/drivers/scsi/lpfc/lpfc_sli.h +++ b/drivers/scsi/lpfc/lpfc_sli.h @@ -225,3 +225,9 @@ struct lpfc_sli { #define LPFC_MBOX_TMO 30 /* Sec tmo for outstanding mbox command */ +#define LPFC_MBOX_TMO_FLASH_CMD 300 /* Sec tmo for outstanding FLASH write + * or erase cmds. This is especially + * long because of the potential of + * multiple flash erases that can be + * spawned. + */ -- cgit v1.1 From 1c067a42413c4f39c907443b8f5979cd4d82f0ff Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 1 Aug 2006 07:33:52 -0400 Subject: [SCSI] lpfc 8.1.7 : Fix race condition between lpfc_sli_issue_mbox and lpfc_online Fix race condition between lpfc_sli_issue_mbox and lpfc_online Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_sli.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 4dc2d58..fbf108c 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -1711,15 +1711,13 @@ lpfc_sli_brdreset(struct lpfc_hba * phba) phba->fc_myDID = 0; phba->fc_prevDID = 0; - psli->sli_flag = 0; - /* Turn off parity checking and serr during the physical reset */ pci_read_config_word(phba->pcidev, PCI_COMMAND, &cfg_value); pci_write_config_word(phba->pcidev, PCI_COMMAND, (cfg_value & ~(PCI_COMMAND_PARITY | PCI_COMMAND_SERR))); - psli->sli_flag &= ~LPFC_SLI2_ACTIVE; + psli->sli_flag &= ~(LPFC_SLI2_ACTIVE | LPFC_PROCESS_LA); /* Now toggle INITFF bit in the Host Control Register */ writel(HC_INITFF, phba->HCregaddr); mdelay(1); @@ -1905,6 +1903,9 @@ lpfc_sli_hba_setup(struct lpfc_hba * phba) } while (resetcount < 2 && !done) { + spin_lock_irq(phba->host->host_lock); + phba->sli.sli_flag |= LPFC_SLI_MBOX_ACTIVE; + spin_unlock_irq(phba->host->host_lock); phba->hba_state = LPFC_STATE_UNKNOWN; lpfc_sli_brdrestart(phba); msleep(2500); @@ -1912,6 +1913,9 @@ lpfc_sli_hba_setup(struct lpfc_hba * phba) if (rc) break; + spin_lock_irq(phba->host->host_lock); + phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; + spin_unlock_irq(phba->host->host_lock); resetcount++; /* Call pre CONFIG_PORT mailbox command initialization. A value of 0 -- cgit v1.1 From 8f6d98d2e05c38cb08fbda5e38e5f87d361c3cac Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 1 Aug 2006 07:34:00 -0400 Subject: [SCSI] lpfc 8.1.7 : Short bug fixes Short bug fixes: - Fix iocbq list corruption due to missing list_del's in ct handling - Missing unlock in lpfc_sli_next_iotag() - Fix initialization of can_queue value - Differentiate sysfs mailbox errors with different codes. Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_attr.c | 6 +++--- drivers/scsi/lpfc/lpfc_ct.c | 1 + drivers/scsi/lpfc/lpfc_init.c | 12 +++++++++++- drivers/scsi/lpfc/lpfc_sli.c | 5 +++-- 4 files changed, 18 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 4ccce14..76f8bd5 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -884,7 +884,7 @@ sysfs_mbox_write(struct kobject *kobj, char *buf, loff_t off, size_t count) phba->sysfs_mbox.mbox == NULL ) { sysfs_mbox_idle(phba); spin_unlock_irq(host->host_lock); - return -EINVAL; + return -EAGAIN; } } @@ -1008,7 +1008,7 @@ sysfs_mbox_read(struct kobject *kobj, char *buf, loff_t off, size_t count) if (rc != MBX_SUCCESS) { sysfs_mbox_idle(phba); spin_unlock_irq(host->host_lock); - return -ENODEV; + return (rc == MBX_TIMEOUT) ? -ETIME : -ENODEV; } phba->sysfs_mbox.state = SMBOX_READING; } @@ -1017,7 +1017,7 @@ sysfs_mbox_read(struct kobject *kobj, char *buf, loff_t off, size_t count) printk(KERN_WARNING "mbox_read: Bad State\n"); sysfs_mbox_idle(phba); spin_unlock_irq(host->host_lock); - return -EINVAL; + return -EAGAIN; } memcpy(buf, (uint8_t *) & phba->sysfs_mbox.mbox->mb + off, count); diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index b65ee57..cab2d9d 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -131,6 +131,7 @@ lpfc_ct_unsol_event(struct lpfc_hba * phba, } ct_unsol_event_exit_piocbq: + list_del(&head); if (pmbuf) { list_for_each_entry_safe(matp, next_matp, &pmbuf->list, list) { lpfc_mbuf_free(phba, matp->virt, matp->phys); diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index ef47b82..16dc8c8 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -1616,7 +1616,11 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) goto out_free_iocbq; } - /* We can rely on a queue depth attribute only after SLI HBA setup */ + /* + * Set initial can_queue value since 0 is no longer supported and + * scsi_add_host will fail. This will be adjusted later based on the + * max xri value determined in hba setup. + */ host->can_queue = phba->cfg_hba_queue_depth - 10; /* Tell the midlayer we support 16 byte commands */ @@ -1656,6 +1660,12 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) goto out_free_irq; } + /* + * hba setup may have changed the hba_queue_depth so we need to adjust + * the value of can_queue. + */ + host->can_queue = phba->cfg_hba_queue_depth - 10; + lpfc_discovery_wait(phba); if (phba->cfg_poll & DISABLE_FCP_RING_INT) { diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index fbf108c..9802ee8 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -320,7 +320,8 @@ lpfc_sli_next_iotag(struct lpfc_hba * phba, struct lpfc_iocbq * iocbq) kfree(old_arr); return iotag; } - } + } else + spin_unlock_irq(phba->host->host_lock); lpfc_printf_log(phba, KERN_ERR,LOG_SLI, "%d:0318 Failed to allocate IOTAG.last IOTAG is %d\n", @@ -1399,11 +1400,11 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba * phba, next_iocb, &saveq->list, list) { + list_del(&rspiocbp->list); lpfc_sli_release_iocbq(phba, rspiocbp); } } - lpfc_sli_release_iocbq(phba, saveq); } } -- cgit v1.1 From dca9479be891eac33e53ab37769e18c3259646da Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 1 Aug 2006 07:34:08 -0400 Subject: [SCSI] lpfc 8.1.7 : ID String and Message fixes ID String and Message fixes - Fix switch symbolic name registration to match cross-OS values - Replace printk's with more standard lpfc_printf_log calls - Make all lpfc_printf_log message numbers unique Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_ct.c | 12 ++++-------- drivers/scsi/lpfc/lpfc_els.c | 6 +++--- drivers/scsi/lpfc/lpfc_hbadisc.c | 12 ++++++------ drivers/scsi/lpfc/lpfc_nportdisc.c | 2 +- drivers/scsi/lpfc/lpfc_scsi.c | 2 +- drivers/scsi/lpfc/lpfc_sli.c | 28 ++++++++++++++++------------ 6 files changed, 31 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index cab2d9d..bbb7310 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -482,7 +482,7 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, if (CTrsp->CommandResponse.bits.CmdRsp == be16_to_cpu(SLI_CT_RESPONSE_FS_ACC)) { lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, - "%d:0239 NameServer Rsp " + "%d:0208 NameServer Rsp " "Data: x%x\n", phba->brd_no, phba->fc_flag); @@ -589,13 +589,9 @@ lpfc_get_hba_sym_node_name(struct lpfc_hba * phba, uint8_t * symbp) lpfc_decode_firmware_rev(phba, fwrev, 0); - if (phba->Port[0]) { - sprintf(symbp, "Emulex %s Port %s FV%s DV%s", phba->ModelName, - phba->Port, fwrev, lpfc_release_version); - } else { - sprintf(symbp, "Emulex %s FV%s DV%s", phba->ModelName, - fwrev, lpfc_release_version); - } + sprintf(symbp, "Emulex %s FV%s DV%s", phba->ModelName, + fwrev, lpfc_release_version); + return; } /* diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index b89f6cb..60f5cca 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -2839,7 +2839,7 @@ lpfc_els_rsp_rps_acc(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) /* Xmit ELS RPS ACC response tag */ lpfc_printf_log(phba, KERN_INFO, LOG_ELS, - "%d:0128 Xmit ELS RPS ACC response tag x%x " + "%d:0118 Xmit ELS RPS ACC response tag x%x " "Data: x%x x%x x%x x%x x%x\n", phba->brd_no, elsiocb->iocb.ulpIoTag, @@ -2948,7 +2948,7 @@ lpfc_els_rsp_rpl_acc(struct lpfc_hba * phba, uint16_t cmdsize, /* Xmit ELS RPL ACC response tag */ lpfc_printf_log(phba, KERN_INFO, LOG_ELS, - "%d:0128 Xmit ELS RPL ACC response tag x%x " + "%d:0120 Xmit ELS RPL ACC response tag x%x " "Data: x%x x%x x%x x%x x%x\n", phba->brd_no, elsiocb->iocb.ulpIoTag, @@ -3109,7 +3109,7 @@ lpfc_els_rcv_fan(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, struct lpfc_nodelist *ndlp, *next_ndlp; /* FAN received */ - lpfc_printf_log(phba, KERN_INFO, LOG_ELS, "%d:265 FAN received\n", + lpfc_printf_log(phba, KERN_INFO, LOG_ELS, "%d:0265 FAN received\n", phba->brd_no); icmd = &cmdiocb->iocb; diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 4d6cf99..1c3f268 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -1782,7 +1782,7 @@ lpfc_findnode_did(struct lpfc_hba * phba, uint32_t order, uint32_t did) /* LOG change to REGLOGIN */ /* FIND node DID reglogin */ lpfc_printf_log(phba, KERN_INFO, LOG_NODE, - "%d:0931 FIND node DID reglogin" + "%d:0901 FIND node DID reglogin" " Data: x%p x%x x%x x%x\n", phba->brd_no, ndlp, ndlp->nlp_DID, @@ -1805,7 +1805,7 @@ lpfc_findnode_did(struct lpfc_hba * phba, uint32_t order, uint32_t did) /* LOG change to PRLI */ /* FIND node DID prli */ lpfc_printf_log(phba, KERN_INFO, LOG_NODE, - "%d:0931 FIND node DID prli " + "%d:0902 FIND node DID prli " "Data: x%p x%x x%x x%x\n", phba->brd_no, ndlp, ndlp->nlp_DID, @@ -1828,7 +1828,7 @@ lpfc_findnode_did(struct lpfc_hba * phba, uint32_t order, uint32_t did) /* LOG change to NPR */ /* FIND node DID npr */ lpfc_printf_log(phba, KERN_INFO, LOG_NODE, - "%d:0931 FIND node DID npr " + "%d:0903 FIND node DID npr " "Data: x%p x%x x%x x%x\n", phba->brd_no, ndlp, ndlp->nlp_DID, @@ -1851,7 +1851,7 @@ lpfc_findnode_did(struct lpfc_hba * phba, uint32_t order, uint32_t did) /* LOG change to UNUSED */ /* FIND node DID unused */ lpfc_printf_log(phba, KERN_INFO, LOG_NODE, - "%d:0931 FIND node DID unused " + "%d:0905 FIND node DID unused " "Data: x%p x%x x%x x%x\n", phba->brd_no, ndlp, ndlp->nlp_DID, @@ -2335,7 +2335,7 @@ lpfc_disc_timeout_handler(struct lpfc_hba *phba) initlinkmbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!initlinkmbox) { lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, - "%d:0226 Device Discovery " + "%d:0206 Device Discovery " "completion error\n", phba->brd_no); phba->hba_state = LPFC_HBA_ERROR; @@ -2365,7 +2365,7 @@ lpfc_disc_timeout_handler(struct lpfc_hba *phba) if (!clearlambox) { clrlaerr = 1; lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, - "%d:0226 Device Discovery " + "%d:0207 Device Discovery " "completion error\n", phba->brd_no); phba->hba_state = LPFC_HBA_ERROR; diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index bd0b0e2..b38021a 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -179,7 +179,7 @@ lpfc_els_abort(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, /* Abort outstanding I/O on NPort */ lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, - "%d:0201 Abort outstanding I/O on NPort x%x " + "%d:0205 Abort outstanding I/O on NPort x%x " "Data: x%x x%x x%x\n", phba->brd_no, ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi); diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index a760a44..0811c82 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -1104,7 +1104,7 @@ lpfc_reset_bus_handler(struct scsi_cmnd *cmnd) ndlp->rport->dd_data); if (ret != SUCCESS) { lpfc_printf_log(phba, KERN_ERR, LOG_FCP, - "%d:0713 Bus Reset on target %d failed\n", + "%d:0700 Bus Reset on target %d failed\n", phba->brd_no, i); err_count++; } diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 9802ee8..70f4d5a 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -970,9 +970,11 @@ void lpfc_sli_poll_fcp_ring(struct lpfc_hba * phba) * resources need to be recovered. */ if (unlikely(irsp->ulpCommand == CMD_XRI_ABORTED_CX)) { - printk(KERN_INFO "%s: IOCB cmd 0x%x processed." - " Skipping completion\n", __FUNCTION__, - irsp->ulpCommand); + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "%d:0314 IOCB cmd 0x%x" + " processed. Skipping" + " completion", phba->brd_no, + irsp->ulpCommand); break; } @@ -1105,7 +1107,7 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba * phba, if (unlikely(irsp->ulpStatus)) { /* Rsp ring error: IOCB */ lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, - "%d:0326 Rsp Ring %d error: IOCB Data: " + "%d:0336 Rsp Ring %d error: IOCB Data: " "x%x x%x x%x x%x x%x x%x x%x x%x\n", phba->brd_no, pring->ringno, irsp->un.ulpWord[0], irsp->un.ulpWord[1], @@ -1123,9 +1125,11 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba * phba, * resources need to be recovered. */ if (unlikely(irsp->ulpCommand == CMD_XRI_ABORTED_CX)) { - printk(KERN_INFO "%s: IOCB cmd 0x%x processed. " - "Skipping completion\n", __FUNCTION__, - irsp->ulpCommand); + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "%d:0333 IOCB cmd 0x%x" + " processed. Skipping" + " completion\n", phba->brd_no, + irsp->ulpCommand); break; } @@ -1156,7 +1160,7 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba * phba, } else { /* Unknown IOCB command */ lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "%d:0321 Unknown IOCB command " + "%d:0334 Unknown IOCB command " "Data: x%x, x%x x%x x%x x%x\n", phba->brd_no, type, irsp->ulpCommand, irsp->ulpStatus, irsp->ulpIoTag, @@ -1239,7 +1243,7 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba * phba, lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "%d:0312 Ring %d handler: portRspPut %d " + "%d:0303 Ring %d handler: portRspPut %d " "is bigger then rsp ring %d\n", phba->brd_no, pring->ringno, portRspPut, portRspMax); @@ -1384,7 +1388,7 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba * phba, lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "%d:0321 Unknown IOCB command " + "%d:0335 Unknown IOCB command " "Data: x%x x%x x%x x%x\n", phba->brd_no, irsp->ulpCommand, @@ -1759,7 +1763,7 @@ lpfc_sli_brdrestart(struct lpfc_hba * phba) /* Restart HBA */ lpfc_printf_log(phba, KERN_INFO, LOG_SLI, - "%d:0328 Restart HBA Data: x%x x%x\n", phba->brd_no, + "%d:0337 Restart HBA Data: x%x x%x\n", phba->brd_no, phba->hba_state, psli->sli_flag); word0 = 0; @@ -3016,7 +3020,7 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba * phba, if (timeleft == 0) { lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "%d:0329 IOCB wait timeout error - no " + "%d:0338 IOCB wait timeout error - no " "wake response Data x%x\n", phba->brd_no, timeout); retval = IOCB_TIMEDOUT; -- cgit v1.1 From 416780d3a7836a99568c6728830ced592a7a22e3 Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 1 Aug 2006 07:34:16 -0400 Subject: [SCSI] lpfc 8.1.7 : Change version number to 8.1.8 Change version number to 8.1.8 Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index 10e89c6..c7963f9 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -18,7 +18,7 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "8.1.7" +#define LPFC_DRIVER_VERSION "8.1.8" #define LPFC_DRIVER_NAME "lpfc" -- cgit v1.1 From b797b6de9d4d8d085169a507c54b18e74dbe4f21 Mon Sep 17 00:00:00 2001 From: Shyam Sundar Date: Tue, 1 Aug 2006 13:48:13 -0700 Subject: [SCSI] qla2xxx: Correct endianess problem while issuing a Marker IOCB on ISP24xx. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_iocb.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index 2b60a27..c5b3c61 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -471,6 +471,7 @@ __qla2x00_marker(scsi_qla_host_t *ha, uint16_t loop_id, uint16_t lun, mrk24->nport_handle = cpu_to_le16(loop_id); mrk24->lun[1] = LSB(lun); mrk24->lun[2] = MSB(lun); + host_to_fcp_swap(mrk24->lun, sizeof(mrk24->lun)); } else { SET_TARGET_ID(ha, mrk->target, loop_id); mrk->lun = cpu_to_le16(lun); -- cgit v1.1 From 45ebeb560570fd7ebae29a4105b81874063d5425 Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Tue, 1 Aug 2006 13:48:14 -0700 Subject: [SCSI] qla2xxx: Log Trace/Diagonostic asynchronous events. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_def.h | 1 + drivers/scsi/qla2xxx/qla_isr.c | 5 +++++ 2 files changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 139ea0e..0930260 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -487,6 +487,7 @@ typedef struct { #define MBA_IP_RCV_BUFFER_EMPTY 0x8026 /* IP receive buffer queue empty. */ #define MBA_IP_HDR_DATA_SPLIT 0x8027 /* IP header/data splitting feature */ /* used. */ +#define MBA_TRACE_NOTIFICATION 0x8028 /* Trace/Diagnostic notification. */ #define MBA_POINT_TO_POINT 0x8030 /* Point to point mode. */ #define MBA_CMPLT_1_16BIT 0x8031 /* Completion 1 16bit IOSB. */ #define MBA_CMPLT_2_16BIT 0x8032 /* Completion 2 16bit IOSB. */ diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 795bf15..de06131 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -587,6 +587,11 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb) DEBUG2(printk("scsi(%ld): Discard RND Frame -- %04x %04x " "%04x.\n", ha->host_no, mb[1], mb[2], mb[3])); break; + + case MBA_TRACE_NOTIFICATION: + DEBUG2(printk("scsi(%ld): Trace Notification -- %04x %04x.\n", + ha->host_no, mb[1], mb[2])); + break; } } -- cgit v1.1 From b0328beed0786b07d0102ed59cbf0b54ad8f726b Mon Sep 17 00:00:00 2001 From: Vladislav Bolkhovitin Date: Tue, 1 Aug 2006 13:48:15 -0700 Subject: [SCSI] qla2xxx: Fix to allow to reset devices using sg interface (sg_reset). Currently it is impossible to reset provided by Qlogic QLA2xxx driver SCSI devices externally using corresponding sg devices, particularly via sg_reset utility, because qla2xxx driver in qla2xxx_eh_device_reset() function checks if the input scsi_cmnd has its private data (CMD_SP()) attached. Then the found pointer isn't used anywhere inside of qla2xxx_eh_device_reset(). If the RESET request comes from sg device, it doesn't have such private data. The attached patch removes check for non-NULL CMD_SP() from qla2xxx_eh_device_reset(), hence allows to reset QLA2xxx's devices using corresponding sg devices. AV: change applies to bus/host reset handlers as well. Signed-off-by: Vladislav Bolkhovitin Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_os.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index ec7ebb6..1e2b95b 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -744,7 +744,6 @@ qla2xxx_eh_device_reset(struct scsi_cmnd *cmd) { scsi_qla_host_t *ha = to_qla_host(cmd->device->host); fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata; - srb_t *sp; int ret; unsigned int id, lun; unsigned long serial; @@ -755,8 +754,7 @@ qla2xxx_eh_device_reset(struct scsi_cmnd *cmd) lun = cmd->device->lun; serial = cmd->serial_number; - sp = (srb_t *) CMD_SP(cmd); - if (!sp || !fcport) + if (!fcport) return ret; qla_printk(KERN_INFO, ha, @@ -875,7 +873,6 @@ qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd) { scsi_qla_host_t *ha = to_qla_host(cmd->device->host); fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata; - srb_t *sp; int ret; unsigned int id, lun; unsigned long serial; @@ -886,8 +883,7 @@ qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd) lun = cmd->device->lun; serial = cmd->serial_number; - sp = (srb_t *) CMD_SP(cmd); - if (!sp || !fcport) + if (!fcport) return ret; qla_printk(KERN_INFO, ha, @@ -936,7 +932,6 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd) { scsi_qla_host_t *ha = to_qla_host(cmd->device->host); fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata; - srb_t *sp; int ret; unsigned int id, lun; unsigned long serial; @@ -947,8 +942,7 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd) lun = cmd->device->lun; serial = cmd->serial_number; - sp = (srb_t *) CMD_SP(cmd); - if (!sp || !fcport) + if (!fcport) return ret; qla_printk(KERN_INFO, ha, -- cgit v1.1 From c2602c48b5ebde55b418ba252737bf60caa4bab0 Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Tue, 1 Aug 2006 13:48:16 -0700 Subject: [SCSI] qla2xxx: Update version number to 8.01.05-k4. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index d2d6834..f5826bf 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -7,7 +7,7 @@ /* * Driver version */ -#define QLA2XXX_VERSION "8.01.05-k3" +#define QLA2XXX_VERSION "8.01.05-k4" #define QLA_DRIVER_MAJOR_VER 8 #define QLA_DRIVER_MINOR_VER 1 -- cgit v1.1 From fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3 Mon Sep 17 00:00:00 2001 From: Volker Sameske Date: Wed, 2 Aug 2006 11:05:16 +0200 Subject: [SCSI] zfcp: improve management of request IDs Improve request handling. Use hash table to manage request IDs. Signed-off-by: Volker Sameske Signed-off-by: Andreas Herrmann Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_aux.c | 120 +++++++++++++++++++++++++++++++++++++---- drivers/s390/scsi/zfcp_ccw.c | 5 ++ drivers/s390/scsi/zfcp_def.h | 11 ++-- drivers/s390/scsi/zfcp_erp.c | 16 +++--- drivers/s390/scsi/zfcp_ext.h | 6 ++- drivers/s390/scsi/zfcp_fsf.c | 122 ++++++++++++++++++++++-------------------- drivers/s390/scsi/zfcp_qdio.c | 79 +++++++++++---------------- 7 files changed, 231 insertions(+), 128 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 9cd789b..adc9d8f 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -112,6 +112,105 @@ _zfcp_hex_dump(char *addr, int count) printk("\n"); } + +/****************************************************************/ +/****** Functions to handle the request ID hash table ********/ +/****************************************************************/ + +#define ZFCP_LOG_AREA ZFCP_LOG_AREA_FSF + +static int zfcp_reqlist_init(struct zfcp_adapter *adapter) +{ + int i; + + adapter->req_list = kcalloc(REQUEST_LIST_SIZE, sizeof(struct list_head), + GFP_KERNEL); + + if (!adapter->req_list) + return -ENOMEM; + + for (i=0; ireq_list[i]); + + return 0; +} + +static void zfcp_reqlist_free(struct zfcp_adapter *adapter) +{ + struct zfcp_fsf_req *request, *tmp; + unsigned int i; + + for (i=0; ireq_list[i])) + continue; + + list_for_each_entry_safe(request, tmp, + &adapter->req_list[i], list) + list_del(&request->list); + } + + kfree(adapter->req_list); +} + +void zfcp_reqlist_add(struct zfcp_adapter *adapter, + struct zfcp_fsf_req *fsf_req) +{ + unsigned int i; + + i = fsf_req->req_id % REQUEST_LIST_SIZE; + list_add_tail(&fsf_req->list, &adapter->req_list[i]); +} + +void zfcp_reqlist_remove(struct zfcp_adapter *adapter, unsigned long req_id) +{ + struct zfcp_fsf_req *request, *tmp; + unsigned int i, counter; + u64 dbg_tmp[2]; + + i = req_id % REQUEST_LIST_SIZE; + BUG_ON(list_empty(&adapter->req_list[i])); + + counter = 0; + list_for_each_entry_safe(request, tmp, &adapter->req_list[i], list) { + if (request->req_id == req_id) { + dbg_tmp[0] = (u64) atomic_read(&adapter->reqs_active); + dbg_tmp[1] = (u64) counter; + debug_event(adapter->erp_dbf, 4, (void *) dbg_tmp, 16); + list_del(&request->list); + break; + } + counter++; + } +} + +struct zfcp_fsf_req *zfcp_reqlist_ismember(struct zfcp_adapter *adapter, + unsigned long req_id) +{ + struct zfcp_fsf_req *request, *tmp; + unsigned int i; + + i = req_id % REQUEST_LIST_SIZE; + + list_for_each_entry_safe(request, tmp, &adapter->req_list[i], list) + if (request->req_id == req_id) + return request; + + return NULL; +} + +int zfcp_reqlist_isempty(struct zfcp_adapter *adapter) +{ + unsigned int i; + + for (i=0; ireq_list[i])) + return 0; + + return 1; +} + +#undef ZFCP_LOG_AREA + /****************************************************************/ /************** Uncategorised Functions *************************/ /****************************************************************/ @@ -961,8 +1060,12 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device) INIT_LIST_HEAD(&adapter->port_remove_lh); /* initialize list of fsf requests */ - spin_lock_init(&adapter->fsf_req_list_lock); - INIT_LIST_HEAD(&adapter->fsf_req_list_head); + spin_lock_init(&adapter->req_list_lock); + retval = zfcp_reqlist_init(adapter); + if (retval) { + ZFCP_LOG_INFO("request list initialization failed\n"); + goto failed_low_mem_buffers; + } /* initialize debug locks */ @@ -1041,8 +1144,6 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device) * !0 - struct zfcp_adapter data structure could not be removed * (e.g. still used) * locks: adapter list write lock is assumed to be held by caller - * adapter->fsf_req_list_lock is taken and released within this - * function and must not be held on entry */ void zfcp_adapter_dequeue(struct zfcp_adapter *adapter) @@ -1054,14 +1155,14 @@ zfcp_adapter_dequeue(struct zfcp_adapter *adapter) zfcp_sysfs_adapter_remove_files(&adapter->ccw_device->dev); dev_set_drvdata(&adapter->ccw_device->dev, NULL); /* sanity check: no pending FSF requests */ - spin_lock_irqsave(&adapter->fsf_req_list_lock, flags); - retval = !list_empty(&adapter->fsf_req_list_head); - spin_unlock_irqrestore(&adapter->fsf_req_list_lock, flags); - if (retval) { + spin_lock_irqsave(&adapter->req_list_lock, flags); + retval = zfcp_reqlist_isempty(adapter); + spin_unlock_irqrestore(&adapter->req_list_lock, flags); + if (!retval) { ZFCP_LOG_NORMAL("bug: adapter %s (%p) still in use, " "%i requests outstanding\n", zfcp_get_busid_by_adapter(adapter), adapter, - atomic_read(&adapter->fsf_reqs_active)); + atomic_read(&adapter->reqs_active)); retval = -EBUSY; goto out; } @@ -1087,6 +1188,7 @@ zfcp_adapter_dequeue(struct zfcp_adapter *adapter) zfcp_free_low_mem_buffers(adapter); /* free memory of adapter data structure and queues */ zfcp_qdio_free_queues(adapter); + zfcp_reqlist_free(adapter); kfree(adapter->fc_stats); kfree(adapter->stats_reset_data); ZFCP_LOG_TRACE("freeing adapter structure\n"); diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c index 57d8e4b..fdabade 100644 --- a/drivers/s390/scsi/zfcp_ccw.c +++ b/drivers/s390/scsi/zfcp_ccw.c @@ -164,6 +164,11 @@ zfcp_ccw_set_online(struct ccw_device *ccw_device) retval = zfcp_adapter_scsi_register(adapter); if (retval) goto out_scsi_register; + + /* initialize request counter */ + BUG_ON(!zfcp_reqlist_isempty(adapter)); + adapter->req_no = 0; + zfcp_erp_modify_adapter_status(adapter, ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET); zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED); diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index 2df512a..72293f3 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -886,11 +886,11 @@ struct zfcp_adapter { struct list_head port_remove_lh; /* head of ports to be removed */ u32 ports; /* number of remote ports */ - struct timer_list scsi_er_timer; /* SCSI err recovery watch */ - struct list_head fsf_req_list_head; /* head of FSF req list */ - spinlock_t fsf_req_list_lock; /* lock for ops on list of - FSF requests */ - atomic_t fsf_reqs_active; /* # active FSF reqs */ + struct timer_list scsi_er_timer; /* SCSI err recovery watch */ + atomic_t reqs_active; /* # active FSF reqs */ + unsigned long req_no; /* unique FSF req number */ + struct list_head *req_list; /* list of pending reqs */ + spinlock_t req_list_lock; /* request list lock */ struct zfcp_qdio_queue request_queue; /* request queue */ u32 fsf_req_seq_no; /* FSF cmnd seq number */ wait_queue_head_t request_wq; /* can be used to wait for @@ -986,6 +986,7 @@ struct zfcp_unit { /* FSF request */ struct zfcp_fsf_req { struct list_head list; /* list of FSF requests */ + unsigned long req_id; /* unique request ID */ struct zfcp_adapter *adapter; /* adapter request belongs to */ u8 sbal_number; /* nr of SBALs free for use */ u8 sbal_first; /* first SBAL for this request */ diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index 8ec8da0..f74412b 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -848,18 +848,16 @@ zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *erp_action) struct zfcp_adapter *adapter = erp_action->adapter; if (erp_action->fsf_req) { - /* take lock to ensure that request is not being deleted meanwhile */ - spin_lock(&adapter->fsf_req_list_lock); - /* check whether fsf req does still exist */ - list_for_each_entry(fsf_req, &adapter->fsf_req_list_head, list) - if (fsf_req == erp_action->fsf_req) - break; - if (fsf_req && (fsf_req->erp_action == erp_action)) { + /* take lock to ensure that request is not deleted meanwhile */ + spin_lock(&adapter->req_list_lock); + if ((!zfcp_reqlist_ismember(adapter, + erp_action->fsf_req->req_id)) && + (fsf_req->erp_action == erp_action)) { /* fsf_req still exists */ debug_text_event(adapter->erp_dbf, 3, "a_ca_req"); debug_event(adapter->erp_dbf, 3, &fsf_req, sizeof (unsigned long)); - /* dismiss fsf_req of timed out or dismissed erp_action */ + /* dismiss fsf_req of timed out/dismissed erp_action */ if (erp_action->status & (ZFCP_STATUS_ERP_DISMISSED | ZFCP_STATUS_ERP_TIMEDOUT)) { debug_text_event(adapter->erp_dbf, 3, @@ -892,7 +890,7 @@ zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *erp_action) */ erp_action->fsf_req = NULL; } - spin_unlock(&adapter->fsf_req_list_lock); + spin_unlock(&adapter->req_list_lock); } else debug_text_event(adapter->erp_dbf, 3, "a_ca_noreq"); diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index d023660..04bb3a9 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -63,7 +63,6 @@ extern int zfcp_qdio_allocate_queues(struct zfcp_adapter *); extern void zfcp_qdio_free_queues(struct zfcp_adapter *); extern int zfcp_qdio_determine_pci(struct zfcp_qdio_queue *, struct zfcp_fsf_req *); -extern int zfcp_qdio_reqid_check(struct zfcp_adapter *, void *); extern volatile struct qdio_buffer_element *zfcp_qdio_sbale_req (struct zfcp_fsf_req *, int, int); @@ -190,5 +189,10 @@ extern void zfcp_scsi_dbf_event_abort(const char *, struct zfcp_adapter *, struct zfcp_fsf_req *); extern void zfcp_scsi_dbf_event_devreset(const char *, u8, struct zfcp_unit *, struct scsi_cmnd *); +extern void zfcp_reqlist_add(struct zfcp_adapter *, struct zfcp_fsf_req *); +extern void zfcp_reqlist_remove(struct zfcp_adapter *, unsigned long); +extern struct zfcp_fsf_req *zfcp_reqlist_ismember(struct zfcp_adapter *, + unsigned long); +extern int zfcp_reqlist_isempty(struct zfcp_adapter *); #endif /* ZFCP_EXT_H */ diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 31db2b0..ff2eacf 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -49,7 +49,6 @@ static int zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *); static void zfcp_fsf_link_down_info_eval(struct zfcp_adapter *, struct fsf_link_down_info *); static int zfcp_fsf_req_dispatch(struct zfcp_fsf_req *); -static void zfcp_fsf_req_dismiss(struct zfcp_fsf_req *); /* association between FSF command and FSF QTCB type */ static u32 fsf_qtcb_type[] = { @@ -146,47 +145,48 @@ zfcp_fsf_req_free(struct zfcp_fsf_req *fsf_req) kfree(fsf_req); } -/* - * function: - * - * purpose: - * - * returns: - * - * note: qdio queues shall be down (no ongoing inbound processing) +/** + * zfcp_fsf_req_dismiss - dismiss a single fsf request */ -int -zfcp_fsf_req_dismiss_all(struct zfcp_adapter *adapter) +static void zfcp_fsf_req_dismiss(struct zfcp_adapter *adapter, + struct zfcp_fsf_req *fsf_req, + unsigned int counter) { - struct zfcp_fsf_req *fsf_req, *tmp; - unsigned long flags; - LIST_HEAD(remove_queue); + u64 dbg_tmp[2]; - spin_lock_irqsave(&adapter->fsf_req_list_lock, flags); - list_splice_init(&adapter->fsf_req_list_head, &remove_queue); - atomic_set(&adapter->fsf_reqs_active, 0); - spin_unlock_irqrestore(&adapter->fsf_req_list_lock, flags); - - list_for_each_entry_safe(fsf_req, tmp, &remove_queue, list) { - list_del(&fsf_req->list); - zfcp_fsf_req_dismiss(fsf_req); - } - - return 0; + dbg_tmp[0] = (u64) atomic_read(&adapter->reqs_active); + dbg_tmp[1] = (u64) counter; + debug_event(adapter->erp_dbf, 4, (void *) dbg_tmp, 16); + list_del(&fsf_req->list); + fsf_req->status |= ZFCP_STATUS_FSFREQ_DISMISSED; + zfcp_fsf_req_complete(fsf_req); } -/* - * function: - * - * purpose: - * - * returns: +/** + * zfcp_fsf_req_dismiss_all - dismiss all remaining fsf requests */ -static void -zfcp_fsf_req_dismiss(struct zfcp_fsf_req *fsf_req) +int zfcp_fsf_req_dismiss_all(struct zfcp_adapter *adapter) { - fsf_req->status |= ZFCP_STATUS_FSFREQ_DISMISSED; - zfcp_fsf_req_complete(fsf_req); + struct zfcp_fsf_req *request, *tmp; + unsigned long flags; + unsigned int i, counter; + + spin_lock_irqsave(&adapter->req_list_lock, flags); + atomic_set(&adapter->reqs_active, 0); + for (i=0; ireq_list[i])) + continue; + + counter = 0; + list_for_each_entry_safe(request, tmp, + &adapter->req_list[i], list) { + zfcp_fsf_req_dismiss(adapter, request, counter); + counter++; + } + } + spin_unlock_irqrestore(&adapter->req_list_lock, flags); + + return 0; } /* @@ -4592,12 +4592,14 @@ static inline void zfcp_fsf_req_qtcb_init(struct zfcp_fsf_req *fsf_req) { if (likely(fsf_req->qtcb != NULL)) { - fsf_req->qtcb->prefix.req_seq_no = fsf_req->adapter->fsf_req_seq_no; - fsf_req->qtcb->prefix.req_id = (unsigned long)fsf_req; + fsf_req->qtcb->prefix.req_seq_no = + fsf_req->adapter->fsf_req_seq_no; + fsf_req->qtcb->prefix.req_id = fsf_req->req_id; fsf_req->qtcb->prefix.ulp_info = ZFCP_ULP_INFO_VERSION; - fsf_req->qtcb->prefix.qtcb_type = fsf_qtcb_type[fsf_req->fsf_command]; + fsf_req->qtcb->prefix.qtcb_type = + fsf_qtcb_type[fsf_req->fsf_command]; fsf_req->qtcb->prefix.qtcb_version = ZFCP_QTCB_VERSION; - fsf_req->qtcb->header.req_handle = (unsigned long)fsf_req; + fsf_req->qtcb->header.req_handle = fsf_req->req_id; fsf_req->qtcb->header.fsf_command = fsf_req->fsf_command; } } @@ -4654,6 +4656,7 @@ zfcp_fsf_req_create(struct zfcp_adapter *adapter, u32 fsf_cmd, int req_flags, { volatile struct qdio_buffer_element *sbale; struct zfcp_fsf_req *fsf_req = NULL; + unsigned long flags; int ret = 0; struct zfcp_qdio_queue *req_queue = &adapter->request_queue; @@ -4668,6 +4671,12 @@ zfcp_fsf_req_create(struct zfcp_adapter *adapter, u32 fsf_cmd, int req_flags, fsf_req->adapter = adapter; fsf_req->fsf_command = fsf_cmd; + INIT_LIST_HEAD(&fsf_req->list); + + /* unique request id */ + spin_lock_irqsave(&adapter->req_list_lock, flags); + fsf_req->req_id = adapter->req_no++; + spin_unlock_irqrestore(&adapter->req_list_lock, flags); zfcp_fsf_req_qtcb_init(fsf_req); @@ -4707,7 +4716,7 @@ zfcp_fsf_req_create(struct zfcp_adapter *adapter, u32 fsf_cmd, int req_flags, sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); /* setup common SBALE fields */ - sbale[0].addr = fsf_req; + sbale[0].addr = (void *) fsf_req->req_id; sbale[0].flags |= SBAL_FLAGS0_COMMAND; if (likely(fsf_req->qtcb != NULL)) { sbale[1].addr = (void *) fsf_req->qtcb; @@ -4747,7 +4756,7 @@ zfcp_fsf_req_send(struct zfcp_fsf_req *fsf_req, struct timer_list *timer) volatile struct qdio_buffer_element *sbale; int inc_seq_no; int new_distance_from_int; - unsigned long flags; + u64 dbg_tmp[2]; int retval = 0; adapter = fsf_req->adapter; @@ -4761,10 +4770,10 @@ zfcp_fsf_req_send(struct zfcp_fsf_req *fsf_req, struct timer_list *timer) ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE, (char *) sbale[1].addr, sbale[1].length); - /* put allocated FSF request at list tail */ - spin_lock_irqsave(&adapter->fsf_req_list_lock, flags); - list_add_tail(&fsf_req->list, &adapter->fsf_req_list_head); - spin_unlock_irqrestore(&adapter->fsf_req_list_lock, flags); + /* put allocated FSF request into hash table */ + spin_lock(&adapter->req_list_lock); + zfcp_reqlist_add(adapter, fsf_req); + spin_unlock(&adapter->req_list_lock); inc_seq_no = (fsf_req->qtcb != NULL); @@ -4803,6 +4812,10 @@ zfcp_fsf_req_send(struct zfcp_fsf_req *fsf_req, struct timer_list *timer) QDIO_FLAG_SYNC_OUTPUT, 0, fsf_req->sbal_first, fsf_req->sbal_number, NULL); + dbg_tmp[0] = (unsigned long) sbale[0].addr; + dbg_tmp[1] = (u64) retval; + debug_event(adapter->erp_dbf, 4, (void *) dbg_tmp, 16); + if (unlikely(retval)) { /* Queues are down..... */ retval = -EIO; @@ -4812,22 +4825,17 @@ zfcp_fsf_req_send(struct zfcp_fsf_req *fsf_req, struct timer_list *timer) */ if (timer) del_timer(timer); - spin_lock_irqsave(&adapter->fsf_req_list_lock, flags); - list_del(&fsf_req->list); - spin_unlock_irqrestore(&adapter->fsf_req_list_lock, flags); - /* - * adjust the number of free SBALs in request queue as well as - * position of first one - */ + spin_lock(&adapter->req_list_lock); + zfcp_reqlist_remove(adapter, fsf_req->req_id); + spin_unlock(&adapter->req_list_lock); + /* undo changes in request queue made for this request */ zfcp_qdio_zero_sbals(req_queue->buffer, fsf_req->sbal_first, fsf_req->sbal_number); atomic_add(fsf_req->sbal_number, &req_queue->free_count); - req_queue->free_index -= fsf_req->sbal_number; /* increase */ + req_queue->free_index -= fsf_req->sbal_number; req_queue->free_index += QDIO_MAX_BUFFERS_PER_Q; req_queue->free_index %= QDIO_MAX_BUFFERS_PER_Q; /* wrap */ - ZFCP_LOG_DEBUG - ("error: do_QDIO failed. Buffers could not be enqueued " - "to request queue.\n"); + zfcp_erp_adapter_reopen(adapter, 0); } else { req_queue->distance_from_int = new_distance_from_int; /* @@ -4843,7 +4851,7 @@ zfcp_fsf_req_send(struct zfcp_fsf_req *fsf_req, struct timer_list *timer) adapter->fsf_req_seq_no++; /* count FSF requests pending */ - atomic_inc(&adapter->fsf_reqs_active); + atomic_inc(&adapter->reqs_active); } return retval; } diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index 49ea5ad..dbd9f48 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c @@ -282,6 +282,37 @@ zfcp_qdio_request_handler(struct ccw_device *ccw_device, return; } +/** + * zfcp_qdio_reqid_check - checks for valid reqids or unsolicited status + */ +static int zfcp_qdio_reqid_check(struct zfcp_adapter *adapter, + unsigned long req_id) +{ + struct zfcp_fsf_req *fsf_req; + unsigned long flags; + + debug_long_event(adapter->erp_dbf, 4, req_id); + + spin_lock_irqsave(&adapter->req_list_lock, flags); + fsf_req = zfcp_reqlist_ismember(adapter, req_id); + + if (!fsf_req) { + spin_unlock_irqrestore(&adapter->req_list_lock, flags); + ZFCP_LOG_NORMAL("error: unknown request id (%ld).\n", req_id); + zfcp_erp_adapter_reopen(adapter, 0); + return -EINVAL; + } + + zfcp_reqlist_remove(adapter, req_id); + atomic_dec(&adapter->reqs_active); + spin_unlock_irqrestore(&adapter->req_list_lock, flags); + + /* finish the FSF request */ + zfcp_fsf_req_complete(fsf_req); + + return 0; +} + /* * function: zfcp_qdio_response_handler * @@ -344,7 +375,7 @@ zfcp_qdio_response_handler(struct ccw_device *ccw_device, /* look for QDIO request identifiers in SB */ buffere = &buffer->element[buffere_index]; retval = zfcp_qdio_reqid_check(adapter, - (void *) buffere->addr); + (unsigned long) buffere->addr); if (retval) { ZFCP_LOG_NORMAL("bug: unexpected inbound " @@ -415,52 +446,6 @@ zfcp_qdio_response_handler(struct ccw_device *ccw_device, return; } -/* - * function: zfcp_qdio_reqid_check - * - * purpose: checks for valid reqids or unsolicited status - * - * returns: 0 - valid request id or unsolicited status - * !0 - otherwise - */ -int -zfcp_qdio_reqid_check(struct zfcp_adapter *adapter, void *sbale_addr) -{ - struct zfcp_fsf_req *fsf_req; - unsigned long flags; - - /* invalid (per convention used in this driver) */ - if (unlikely(!sbale_addr)) { - ZFCP_LOG_NORMAL("bug: invalid reqid\n"); - return -EINVAL; - } - - /* valid request id and thus (hopefully :) valid fsf_req address */ - fsf_req = (struct zfcp_fsf_req *) sbale_addr; - - /* serialize with zfcp_fsf_req_dismiss_all */ - spin_lock_irqsave(&adapter->fsf_req_list_lock, flags); - if (list_empty(&adapter->fsf_req_list_head)) { - spin_unlock_irqrestore(&adapter->fsf_req_list_lock, flags); - return 0; - } - list_del(&fsf_req->list); - atomic_dec(&adapter->fsf_reqs_active); - spin_unlock_irqrestore(&adapter->fsf_req_list_lock, flags); - - if (unlikely(adapter != fsf_req->adapter)) { - ZFCP_LOG_NORMAL("bug: invalid reqid (fsf_req=%p, " - "fsf_req->adapter=%p, adapter=%p)\n", - fsf_req, fsf_req->adapter, adapter); - return -EINVAL; - } - - /* finish the FSF request */ - zfcp_fsf_req_complete(fsf_req); - - return 0; -} - /** * zfcp_qdio_sbale_get - return pointer to SBALE of qdio_queue * @queue: queue from which SBALE should be returned -- cgit v1.1 From f6c0e7a7b3b6db15146877c0cef43b413af5b76e Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Wed, 2 Aug 2006 11:05:52 +0200 Subject: [SCSI] zfcp: minor erp bug fixes Bug fixes for zfcp's erp: - trigger adapter reopen if do_QDIO fails - avoid erp deadlock if registration of scsi target or remote port hang - do not treat as error if exchange port data fails - decrease timeout for target reset and aborts - mark unit failed if slave_destroy is called Additionally some code cleanup was done: - made some functions void when retval is not of interest - shortened initialization of zfcp's host_template - corrected some comments Signed-off-by: Andreas Herrmann Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_def.h | 2 +- drivers/s390/scsi/zfcp_erp.c | 196 +++++++++++++++--------------------------- drivers/s390/scsi/zfcp_ext.h | 3 +- drivers/s390/scsi/zfcp_scsi.c | 73 ++++++++-------- 4 files changed, 107 insertions(+), 167 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index 72293f3..904d6a7 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -80,7 +80,7 @@ zfcp_address_to_sg(void *address, struct scatterlist *list) #define REQUEST_LIST_SIZE 128 /********************* SCSI SPECIFIC DEFINES *********************************/ -#define ZFCP_SCSI_ER_TIMEOUT (100*HZ) +#define ZFCP_SCSI_ER_TIMEOUT (10*HZ) /********************* CIO/QDIO SPECIFIC DEFINES *****************************/ diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index f74412b..7f60b6f 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -64,8 +64,8 @@ static int zfcp_erp_strategy_check_action(struct zfcp_erp_action *, int); static int zfcp_erp_adapter_strategy(struct zfcp_erp_action *); static int zfcp_erp_adapter_strategy_generic(struct zfcp_erp_action *, int); static int zfcp_erp_adapter_strategy_close(struct zfcp_erp_action *); -static int zfcp_erp_adapter_strategy_close_qdio(struct zfcp_erp_action *); -static int zfcp_erp_adapter_strategy_close_fsf(struct zfcp_erp_action *); +static void zfcp_erp_adapter_strategy_close_qdio(struct zfcp_erp_action *); +static void zfcp_erp_adapter_strategy_close_fsf(struct zfcp_erp_action *); static int zfcp_erp_adapter_strategy_open(struct zfcp_erp_action *); static int zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *); static int zfcp_erp_adapter_strategy_open_fsf(struct zfcp_erp_action *); @@ -93,10 +93,9 @@ static int zfcp_erp_unit_strategy_clearstati(struct zfcp_unit *); static int zfcp_erp_unit_strategy_close(struct zfcp_erp_action *); static int zfcp_erp_unit_strategy_open(struct zfcp_erp_action *); -static int zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *); -static int zfcp_erp_action_dismiss_port(struct zfcp_port *); -static int zfcp_erp_action_dismiss_unit(struct zfcp_unit *); -static int zfcp_erp_action_dismiss(struct zfcp_erp_action *); +static void zfcp_erp_action_dismiss_port(struct zfcp_port *); +static void zfcp_erp_action_dismiss_unit(struct zfcp_unit *); +static void zfcp_erp_action_dismiss(struct zfcp_erp_action *); static int zfcp_erp_action_enqueue(int, struct zfcp_adapter *, struct zfcp_port *, struct zfcp_unit *); @@ -135,29 +134,39 @@ zfcp_fsf_request_timeout_handler(unsigned long data) zfcp_erp_adapter_reopen(adapter, 0); } -/* - * function: zfcp_fsf_scsi_er_timeout_handler - * - * purpose: This function needs to be called whenever a SCSI error recovery - * action (abort/reset) does not return. - * Re-opening the adapter means that the command can be returned - * by zfcp (it is guarranteed that it does not return via the - * adapter anymore). The buffer can then be used again. - * - * returns: sod all +/** + * zfcp_fsf_scsi_er_timeout_handler - timeout handler for scsi eh tasks + * + * This function needs to be called whenever a SCSI error recovery + * action (abort/reset) does not return. Re-opening the adapter means + * that the abort/reset command can be returned by zfcp. It won't complete + * via the adapter anymore (because qdio queues are closed). If ERP is + * already running on this adapter it will be stopped. */ -void -zfcp_fsf_scsi_er_timeout_handler(unsigned long data) +void zfcp_fsf_scsi_er_timeout_handler(unsigned long data) { struct zfcp_adapter *adapter = (struct zfcp_adapter *) data; + unsigned long flags; ZFCP_LOG_NORMAL("warning: SCSI error recovery timed out. " "Restarting all operations on the adapter %s\n", zfcp_get_busid_by_adapter(adapter)); debug_text_event(adapter->erp_dbf, 1, "eh_lmem_tout"); - zfcp_erp_adapter_reopen(adapter, 0); - return; + write_lock_irqsave(&adapter->erp_lock, flags); + if (atomic_test_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING, + &adapter->status)) { + zfcp_erp_modify_adapter_status(adapter, + ZFCP_STATUS_COMMON_UNBLOCKED|ZFCP_STATUS_COMMON_OPEN, + ZFCP_CLEAR); + zfcp_erp_action_dismiss_adapter(adapter); + write_unlock_irqrestore(&adapter->erp_lock, flags); + /* dismiss all pending requests including requests for ERP */ + zfcp_fsf_req_dismiss_all(adapter); + adapter->fsf_req_seq_no = 0; + } else + write_unlock_irqrestore(&adapter->erp_lock, flags); + zfcp_erp_adapter_reopen(adapter, 0); } /* @@ -670,17 +679,10 @@ zfcp_erp_unit_reopen(struct zfcp_unit *unit, int clear_mask) return retval; } -/* - * function: - * - * purpose: disable I/O, - * return any open requests and clean them up, - * aim: no pending and incoming I/O - * - * returns: +/** + * zfcp_erp_adapter_block - mark adapter as blocked, block scsi requests */ -static void -zfcp_erp_adapter_block(struct zfcp_adapter *adapter, int clear_mask) +static void zfcp_erp_adapter_block(struct zfcp_adapter *adapter, int clear_mask) { debug_text_event(adapter->erp_dbf, 6, "a_bl"); zfcp_erp_modify_adapter_status(adapter, @@ -688,15 +690,10 @@ zfcp_erp_adapter_block(struct zfcp_adapter *adapter, int clear_mask) clear_mask, ZFCP_CLEAR); } -/* - * function: - * - * purpose: enable I/O - * - * returns: +/** + * zfcp_erp_adapter_unblock - mark adapter as unblocked, allow scsi requests */ -static void -zfcp_erp_adapter_unblock(struct zfcp_adapter *adapter) +static void zfcp_erp_adapter_unblock(struct zfcp_adapter *adapter) { debug_text_event(adapter->erp_dbf, 6, "a_ubl"); atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status); @@ -897,23 +894,15 @@ zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *erp_action) return retval; } -/* - * purpose: generic handler for asynchronous events related to erp_action events - * (normal completion, time-out, dismissing, retry after - * low memory condition) - * - * note: deletion of timer is not required (e.g. in case of a time-out), - * but a second try does no harm, - * we leave it in here to allow for greater simplification +/** + * zfcp_erp_async_handler_nolock - complete erp_action * - * returns: 0 - there was an action to handle - * !0 - otherwise + * Used for normal completion, time-out, dismissal and failure after + * low memory condition. */ -static int -zfcp_erp_async_handler_nolock(struct zfcp_erp_action *erp_action, - unsigned long set_mask) +static void zfcp_erp_async_handler_nolock(struct zfcp_erp_action *erp_action, + unsigned long set_mask) { - int retval; struct zfcp_adapter *adapter = erp_action->adapter; if (zfcp_erp_action_exists(erp_action) == ZFCP_ERP_ACTION_RUNNING) { @@ -924,43 +913,26 @@ zfcp_erp_async_handler_nolock(struct zfcp_erp_action *erp_action, del_timer(&erp_action->timer); erp_action->status |= set_mask; zfcp_erp_action_ready(erp_action); - retval = 0; } else { /* action is ready or gone - nothing to do */ debug_text_event(adapter->erp_dbf, 3, "a_asyh_gone"); debug_event(adapter->erp_dbf, 3, &erp_action->action, sizeof (int)); - retval = 1; } - - return retval; } -/* - * purpose: generic handler for asynchronous events related to erp_action - * events (normal completion, time-out, dismissing, retry after - * low memory condition) - * - * note: deletion of timer is not required (e.g. in case of a time-out), - * but a second try does no harm, - * we leave it in here to allow for greater simplification - * - * returns: 0 - there was an action to handle - * !0 - otherwise +/** + * zfcp_erp_async_handler - wrapper for erp_async_handler_nolock w/ locking */ -int -zfcp_erp_async_handler(struct zfcp_erp_action *erp_action, - unsigned long set_mask) +void zfcp_erp_async_handler(struct zfcp_erp_action *erp_action, + unsigned long set_mask) { struct zfcp_adapter *adapter = erp_action->adapter; unsigned long flags; - int retval; write_lock_irqsave(&adapter->erp_lock, flags); - retval = zfcp_erp_async_handler_nolock(erp_action, set_mask); + zfcp_erp_async_handler_nolock(erp_action, set_mask); write_unlock_irqrestore(&adapter->erp_lock, flags); - - return retval; } /* @@ -997,17 +969,15 @@ zfcp_erp_timeout_handler(unsigned long data) zfcp_erp_async_handler(erp_action, ZFCP_STATUS_ERP_TIMEDOUT); } -/* - * purpose: is called for an erp_action which needs to be ended - * though not being done, - * this is usually required if an higher is generated, - * action gets an appropriate flag and will be processed - * accordingly +/** + * zfcp_erp_action_dismiss - dismiss an erp_action * - * locks: erp_lock held (thus we need to call another handler variant) + * adapter->erp_lock must be held + * + * Dismissal of an erp_action is usually required if an erp_action of + * higher priority is generated. */ -static int -zfcp_erp_action_dismiss(struct zfcp_erp_action *erp_action) +static void zfcp_erp_action_dismiss(struct zfcp_erp_action *erp_action) { struct zfcp_adapter *adapter = erp_action->adapter; @@ -1015,8 +985,6 @@ zfcp_erp_action_dismiss(struct zfcp_erp_action *erp_action) debug_event(adapter->erp_dbf, 2, &erp_action->action, sizeof (int)); zfcp_erp_async_handler_nolock(erp_action, ZFCP_STATUS_ERP_DISMISSED); - - return 0; } int @@ -2072,18 +2040,12 @@ zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *erp_action) return retval; } -/* - * function: zfcp_qdio_cleanup - * - * purpose: cleans up QDIO operation for the specified adapter - * - * returns: 0 - successful cleanup - * !0 - failed cleanup +/** + * zfcp_erp_adapter_strategy_close_qdio - close qdio queues for an adapter */ -int +static void zfcp_erp_adapter_strategy_close_qdio(struct zfcp_erp_action *erp_action) { - int retval = ZFCP_ERP_SUCCEEDED; int first_used; int used_count; struct zfcp_adapter *adapter = erp_action->adapter; @@ -2092,15 +2054,13 @@ zfcp_erp_adapter_strategy_close_qdio(struct zfcp_erp_action *erp_action) ZFCP_LOG_DEBUG("error: attempt to shut down inactive QDIO " "queues on adapter %s\n", zfcp_get_busid_by_adapter(adapter)); - retval = ZFCP_ERP_FAILED; - goto out; + return; } /* * Get queue_lock and clear QDIOUP flag. Thus it's guaranteed that * do_QDIO won't be called while qdio_shutdown is in progress. */ - write_lock_irq(&adapter->request_queue.queue_lock); atomic_clear_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status); write_unlock_irq(&adapter->request_queue.queue_lock); @@ -2132,8 +2092,6 @@ zfcp_erp_adapter_strategy_close_qdio(struct zfcp_erp_action *erp_action) adapter->request_queue.free_index = 0; atomic_set(&adapter->request_queue.free_count, 0); adapter->request_queue.distance_from_int = 0; - out: - return retval; } static int @@ -2256,11 +2214,11 @@ zfcp_erp_adapter_strategy_open_fsf_xport(struct zfcp_erp_action *erp_action) "%s)\n", zfcp_get_busid_by_adapter(adapter)); ret = ZFCP_ERP_FAILED; } - if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_XPORT_OK, &adapter->status)) { - ZFCP_LOG_INFO("error: exchange port data failed (adapter " + + /* don't treat as error for the sake of compatibility */ + if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_XPORT_OK, &adapter->status)) + ZFCP_LOG_INFO("warning: exchange port data failed (adapter " "%s\n", zfcp_get_busid_by_adapter(adapter)); - ret = ZFCP_ERP_FAILED; - } return ret; } @@ -2290,18 +2248,12 @@ zfcp_erp_adapter_strategy_open_fsf_statusread(struct zfcp_erp_action return retval; } -/* - * function: zfcp_fsf_cleanup - * - * purpose: cleanup FSF operation for specified adapter - * - * returns: 0 - FSF operation successfully cleaned up - * !0 - failed to cleanup FSF operation for this adapter +/** + * zfcp_erp_adapter_strategy_close_fsf - stop FSF operations for an adapter */ -static int +static void zfcp_erp_adapter_strategy_close_fsf(struct zfcp_erp_action *erp_action) { - int retval = ZFCP_ERP_SUCCEEDED; struct zfcp_adapter *adapter = erp_action->adapter; /* @@ -2315,8 +2267,6 @@ zfcp_erp_adapter_strategy_close_fsf(struct zfcp_erp_action *erp_action) /* all ports and units are closed */ zfcp_erp_modify_adapter_status(adapter, ZFCP_STATUS_COMMON_OPEN, ZFCP_CLEAR); - - return retval; } /* @@ -3291,10 +3241,8 @@ zfcp_erp_action_cleanup(int action, struct zfcp_adapter *adapter, } -static int -zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *adapter) +void zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *adapter) { - int retval = 0; struct zfcp_port *port; debug_text_event(adapter->erp_dbf, 5, "a_actab"); @@ -3303,14 +3251,10 @@ zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *adapter) else list_for_each_entry(port, &adapter->port_list_head, list) zfcp_erp_action_dismiss_port(port); - - return retval; } -static int -zfcp_erp_action_dismiss_port(struct zfcp_port *port) +static void zfcp_erp_action_dismiss_port(struct zfcp_port *port) { - int retval = 0; struct zfcp_unit *unit; struct zfcp_adapter *adapter = port->adapter; @@ -3321,22 +3265,16 @@ zfcp_erp_action_dismiss_port(struct zfcp_port *port) else list_for_each_entry(unit, &port->unit_list_head, list) zfcp_erp_action_dismiss_unit(unit); - - return retval; } -static int -zfcp_erp_action_dismiss_unit(struct zfcp_unit *unit) +static void zfcp_erp_action_dismiss_unit(struct zfcp_unit *unit) { - int retval = 0; struct zfcp_adapter *adapter = unit->port->adapter; debug_text_event(adapter->erp_dbf, 5, "u_actab"); debug_event(adapter->erp_dbf, 5, &unit->fcp_lun, sizeof (fcp_lun_t)); if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &unit->status)) zfcp_erp_action_dismiss(&unit->erp_action); - - return retval; } static inline void diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 04bb3a9..146d7a2 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -139,6 +139,7 @@ extern void zfcp_erp_modify_adapter_status(struct zfcp_adapter *, u32, int); extern int zfcp_erp_adapter_reopen(struct zfcp_adapter *, int); extern int zfcp_erp_adapter_shutdown(struct zfcp_adapter *, int); extern void zfcp_erp_adapter_failed(struct zfcp_adapter *); +extern void zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *); extern void zfcp_erp_modify_port_status(struct zfcp_port *, u32, int); extern int zfcp_erp_port_reopen(struct zfcp_port *, int); @@ -155,7 +156,7 @@ extern void zfcp_erp_unit_failed(struct zfcp_unit *); extern int zfcp_erp_thread_setup(struct zfcp_adapter *); extern int zfcp_erp_thread_kill(struct zfcp_adapter *); extern int zfcp_erp_wait(struct zfcp_adapter *); -extern int zfcp_erp_async_handler(struct zfcp_erp_action *, unsigned long); +extern void zfcp_erp_async_handler(struct zfcp_erp_action *, unsigned long); extern int zfcp_test_link(struct zfcp_port *); diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 671f4a6..1bb5508 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -30,7 +30,6 @@ static int zfcp_scsi_queuecommand(struct scsi_cmnd *, void (*done) (struct scsi_cmnd *)); static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *); static int zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *); -static int zfcp_scsi_eh_bus_reset_handler(struct scsi_cmnd *); static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *); static int zfcp_task_management_function(struct zfcp_unit *, u8, struct scsi_cmnd *); @@ -46,30 +45,22 @@ struct zfcp_data zfcp_data = { .scsi_host_template = { .name = ZFCP_NAME, .proc_name = "zfcp", - .proc_info = NULL, - .detect = NULL, .slave_alloc = zfcp_scsi_slave_alloc, .slave_configure = zfcp_scsi_slave_configure, .slave_destroy = zfcp_scsi_slave_destroy, .queuecommand = zfcp_scsi_queuecommand, .eh_abort_handler = zfcp_scsi_eh_abort_handler, .eh_device_reset_handler = zfcp_scsi_eh_device_reset_handler, - .eh_bus_reset_handler = zfcp_scsi_eh_bus_reset_handler, + .eh_bus_reset_handler = zfcp_scsi_eh_host_reset_handler, .eh_host_reset_handler = zfcp_scsi_eh_host_reset_handler, .can_queue = 4096, .this_id = -1, - /* - * FIXME: - * one less? can zfcp_create_sbale cope with it? - */ .sg_tablesize = ZFCP_MAX_SBALES_PER_REQ, .cmd_per_lun = 1, - .unchecked_isa_dma = 0, .use_clustering = 1, .sdev_attrs = zfcp_sysfs_sdev_attrs, }, .driver_version = ZFCP_VERSION, - /* rest initialised with zeros */ }; /* Find start of Response Information in FCP response unit*/ @@ -176,8 +167,14 @@ zfcp_scsi_slave_alloc(struct scsi_device *sdp) return retval; } -static void -zfcp_scsi_slave_destroy(struct scsi_device *sdpnt) +/** + * zfcp_scsi_slave_destroy - called when scsi device is removed + * + * Remove reference to associated scsi device for an zfcp_unit. + * Mark zfcp_unit as failed. The scsi device might be deleted via sysfs + * or a scan for this device might have failed. + */ +static void zfcp_scsi_slave_destroy(struct scsi_device *sdpnt) { struct zfcp_unit *unit = (struct zfcp_unit *) sdpnt->hostdata; @@ -185,6 +182,7 @@ zfcp_scsi_slave_destroy(struct scsi_device *sdpnt) atomic_clear_mask(ZFCP_STATUS_UNIT_REGISTERED, &unit->status); sdpnt->hostdata = NULL; unit->device = NULL; + zfcp_erp_unit_failed(unit); zfcp_unit_put(unit); } else { ZFCP_LOG_NORMAL("bug: no unit associated with SCSI device at " @@ -549,35 +547,38 @@ zfcp_task_management_function(struct zfcp_unit *unit, u8 tm_flags, } /** - * zfcp_scsi_eh_bus_reset_handler - reset bus (reopen adapter) + * zfcp_scsi_eh_host_reset_handler - handler for host and bus reset + * + * If ERP is already running it will be stopped. */ -int -zfcp_scsi_eh_bus_reset_handler(struct scsi_cmnd *scpnt) +int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt) { - struct zfcp_unit *unit = (struct zfcp_unit*) scpnt->device->hostdata; - struct zfcp_adapter *adapter = unit->port->adapter; - - ZFCP_LOG_NORMAL("bus reset because of problems with " - "unit 0x%016Lx\n", unit->fcp_lun); - zfcp_erp_adapter_reopen(adapter, 0); - zfcp_erp_wait(adapter); - - return SUCCESS; -} + struct zfcp_unit *unit; + struct zfcp_adapter *adapter; + unsigned long flags; -/** - * zfcp_scsi_eh_host_reset_handler - reset host (reopen adapter) - */ -int -zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt) -{ - struct zfcp_unit *unit = (struct zfcp_unit*) scpnt->device->hostdata; - struct zfcp_adapter *adapter = unit->port->adapter; + unit = (struct zfcp_unit*) scpnt->device->hostdata; + adapter = unit->port->adapter; - ZFCP_LOG_NORMAL("host reset because of problems with " + ZFCP_LOG_NORMAL("host/bus reset because of problems with " "unit 0x%016Lx\n", unit->fcp_lun); - zfcp_erp_adapter_reopen(adapter, 0); - zfcp_erp_wait(adapter); + + write_lock_irqsave(&adapter->erp_lock, flags); + if (atomic_test_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING, + &adapter->status)) { + zfcp_erp_modify_adapter_status(adapter, + ZFCP_STATUS_COMMON_UNBLOCKED|ZFCP_STATUS_COMMON_OPEN, + ZFCP_CLEAR); + zfcp_erp_action_dismiss_adapter(adapter); + write_unlock_irqrestore(&adapter->erp_lock, flags); + zfcp_fsf_req_dismiss_all(adapter); + adapter->fsf_req_seq_no = 0; + zfcp_erp_adapter_reopen(adapter, 0); + } else { + write_unlock_irqrestore(&adapter->erp_lock, flags); + zfcp_erp_adapter_reopen(adapter, 0); + zfcp_erp_wait(adapter); + } return SUCCESS; } -- cgit v1.1 From 58b3ac07fed31ffc1349380b78305af6522fe1f4 Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Wed, 2 Aug 2006 11:06:21 +0200 Subject: [SCSI] zfcp: bump version number New version number fo zfcp driver. Signed-off-by: Andreas Herrmann Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_def.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index 904d6a7..94d1b74d 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -52,7 +52,7 @@ /********************* GENERAL DEFINES *********************************/ /* zfcp version number, it consists of major, minor, and patch-level number */ -#define ZFCP_VERSION "4.7.0" +#define ZFCP_VERSION "4.8.0" /** * zfcp_sg_to_address - determine kernel address from struct scatterlist -- cgit v1.1 From 3e74051bc7b780c5ba28939f9d5c4cd3280a5ff7 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 30 Jul 2006 19:13:36 +0200 Subject: [SCSI] hptiop: backout ioctl mess The hptiop just got merged with a horrible amount of really bad ioctl code that is against the standards for new scsi drivers. This patch backs it out (and fixes a small bug where scsi_add_host is called to early). We can re-add proper APIs once we agree on them. Signed-off-by: Christoph Hellwig Signed-off-by: James Bottomley --- drivers/scsi/hptiop.c | 566 +------------------------------------------------- 1 file changed, 8 insertions(+), 558 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/hptiop.c b/drivers/scsi/hptiop.c index 74d4d22..bcb3444 100644 --- a/drivers/scsi/hptiop.c +++ b/drivers/scsi/hptiop.c @@ -45,10 +45,6 @@ static char driver_name[] = "hptiop"; static const char driver_name_long[] = "RocketRAID 3xxx SATA Controller driver"; static const char driver_ver[] = "v1.0 (060426)"; -static DEFINE_SPINLOCK(hptiop_hba_list_lock); -static LIST_HEAD(hptiop_hba_list); -static int hptiop_cdev_major = -1; - static void hptiop_host_request_callback(struct hptiop_hba *hba, u32 tag); static void hptiop_iop_request_callback(struct hptiop_hba *hba, u32 tag); static void hptiop_message_callback(struct hptiop_hba *hba, u32 msg); @@ -620,532 +616,11 @@ static int hptiop_adjust_disk_queue_depth(struct scsi_device *sdev, return queue_depth; } -struct hptiop_getinfo { - char __user *buffer; - loff_t buflength; - loff_t bufoffset; - loff_t buffillen; - loff_t filpos; -}; - -static void hptiop_copy_mem_info(struct hptiop_getinfo *pinfo, - char *data, int datalen) -{ - if (pinfo->filpos < pinfo->bufoffset) { - if (pinfo->filpos + datalen <= pinfo->bufoffset) { - pinfo->filpos += datalen; - return; - } else { - data += (pinfo->bufoffset - pinfo->filpos); - datalen -= (pinfo->bufoffset - pinfo->filpos); - pinfo->filpos = pinfo->bufoffset; - } - } - - pinfo->filpos += datalen; - if (pinfo->buffillen == pinfo->buflength) - return; - - if (pinfo->buflength - pinfo->buffillen < datalen) - datalen = pinfo->buflength - pinfo->buffillen; - - if (copy_to_user(pinfo->buffer + pinfo->buffillen, data, datalen)) - return; - - pinfo->buffillen += datalen; -} - -static int hptiop_copy_info(struct hptiop_getinfo *pinfo, char *fmt, ...) -{ - va_list args; - char buf[128]; - int len; - - va_start(args, fmt); - len = vsnprintf(buf, sizeof(buf), fmt, args); - va_end(args); - hptiop_copy_mem_info(pinfo, buf, len); - return len; -} - -static void hptiop_ioctl_done(struct hpt_ioctl_k *arg) -{ - arg->done = NULL; - wake_up(&arg->hba->ioctl_wq); -} - -static void hptiop_do_ioctl(struct hpt_ioctl_k *arg) -{ - struct hptiop_hba *hba = arg->hba; - u32 val; - struct hpt_iop_request_ioctl_command __iomem *req; - int ioctl_retry = 0; - - dprintk("scsi%d: hptiop_do_ioctl\n", hba->host->host_no); - - /* - * check (in + out) buff size from application. - * outbuf must be dword aligned. - */ - if (((arg->inbuf_size + 3) & ~3) + arg->outbuf_size > - hba->max_request_size - - sizeof(struct hpt_iop_request_header) - - 4 * sizeof(u32)) { - dprintk("scsi%d: ioctl buf size (%d/%d) is too large\n", - hba->host->host_no, - arg->inbuf_size, arg->outbuf_size); - arg->result = HPT_IOCTL_RESULT_FAILED; - return; - } - -retry: - spin_lock_irq(hba->host->host_lock); - - val = readl(&hba->iop->inbound_queue); - if (val == IOPMU_QUEUE_EMPTY) { - spin_unlock_irq(hba->host->host_lock); - dprintk("scsi%d: no free req for ioctl\n", hba->host->host_no); - arg->result = -1; - return; - } - - req = (struct hpt_iop_request_ioctl_command __iomem *) - ((unsigned long)hba->iop + val); - - writel(HPT_CTL_CODE_LINUX_TO_IOP(arg->ioctl_code), - &req->ioctl_code); - writel(arg->inbuf_size, &req->inbuf_size); - writel(arg->outbuf_size, &req->outbuf_size); - - /* - * use the buffer on the IOP local memory first, then copy it - * back to host. - * the caller's request buffer shoudl be little-endian. - */ - if (arg->inbuf_size) - memcpy_toio(req->buf, arg->inbuf, arg->inbuf_size); - - /* correct the controller ID for IOP */ - if ((arg->ioctl_code == HPT_IOCTL_GET_CHANNEL_INFO || - arg->ioctl_code == HPT_IOCTL_GET_CONTROLLER_INFO_V2 || - arg->ioctl_code == HPT_IOCTL_GET_CONTROLLER_INFO) - && arg->inbuf_size >= sizeof(u32)) - writel(0, req->buf); - - writel(IOP_REQUEST_TYPE_IOCTL_COMMAND, &req->header.type); - writel(0, &req->header.flags); - writel(offsetof(struct hpt_iop_request_ioctl_command, buf) - + arg->inbuf_size, &req->header.size); - writel((u32)(unsigned long)arg, &req->header.context); - writel(BITS_PER_LONG > 32 ? (u32)((unsigned long)arg>>32) : 0, - &req->header.context_hi32); - writel(IOP_RESULT_PENDING, &req->header.result); - - arg->result = HPT_IOCTL_RESULT_FAILED; - arg->done = hptiop_ioctl_done; - - writel(val, &hba->iop->inbound_queue); - hptiop_pci_posting_flush(hba->iop); - - spin_unlock_irq(hba->host->host_lock); - - wait_event_timeout(hba->ioctl_wq, arg->done == NULL, 60 * HZ); - - if (arg->done != NULL) { - hptiop_reset_hba(hba); - if (ioctl_retry++ < 3) - goto retry; - } - - dprintk("hpt_iop_ioctl %x result %d\n", - arg->ioctl_code, arg->result); -} - -static int __hpt_do_ioctl(struct hptiop_hba *hba, u32 code, void *inbuf, - u32 insize, void *outbuf, u32 outsize) -{ - struct hpt_ioctl_k arg; - arg.hba = hba; - arg.ioctl_code = code; - arg.inbuf = inbuf; - arg.outbuf = outbuf; - arg.inbuf_size = insize; - arg.outbuf_size = outsize; - arg.bytes_returned = NULL; - hptiop_do_ioctl(&arg); - return arg.result; -} - -static inline int hpt_id_valid(__le32 id) -{ - return id != 0 && id != cpu_to_le32(0xffffffff); -} - -static int hptiop_get_controller_info(struct hptiop_hba *hba, - struct hpt_controller_info *pinfo) -{ - int id = 0; - - return __hpt_do_ioctl(hba, HPT_IOCTL_GET_CONTROLLER_INFO, - &id, sizeof(int), pinfo, sizeof(*pinfo)); -} - - -static int hptiop_get_channel_info(struct hptiop_hba *hba, int bus, - struct hpt_channel_info *pinfo) -{ - u32 ids[2]; - - ids[0] = 0; - ids[1] = bus; - return __hpt_do_ioctl(hba, HPT_IOCTL_GET_CHANNEL_INFO, - ids, sizeof(ids), pinfo, sizeof(*pinfo)); - -} - -static int hptiop_get_logical_devices(struct hptiop_hba *hba, - __le32 *pids, int maxcount) -{ - int i; - u32 count = maxcount - 1; - - if (__hpt_do_ioctl(hba, HPT_IOCTL_GET_LOGICAL_DEVICES, - &count, sizeof(u32), - pids, sizeof(u32) * maxcount)) - return -1; - - maxcount = le32_to_cpu(pids[0]); - for (i = 0; i < maxcount; i++) - pids[i] = pids[i+1]; - - return maxcount; -} - -static int hptiop_get_device_info_v3(struct hptiop_hba *hba, __le32 id, - struct hpt_logical_device_info_v3 *pinfo) -{ - return __hpt_do_ioctl(hba, HPT_IOCTL_GET_DEVICE_INFO_V3, - &id, sizeof(u32), - pinfo, sizeof(*pinfo)); -} - -static const char *get_array_status(struct hpt_logical_device_info_v3 *devinfo) -{ - static char s[64]; - u32 flags = le32_to_cpu(devinfo->u.array.flags); - u32 trans_prog = le32_to_cpu(devinfo->u.array.transforming_progress); - u32 reb_prog = le32_to_cpu(devinfo->u.array.rebuilding_progress); - - if (flags & ARRAY_FLAG_DISABLED) - return "Disabled"; - else if (flags & ARRAY_FLAG_TRANSFORMING) - sprintf(s, "Expanding/Migrating %d.%d%%%s%s", - trans_prog / 100, - trans_prog % 100, - (flags & (ARRAY_FLAG_NEEDBUILDING|ARRAY_FLAG_BROKEN))? - ", Critical" : "", - ((flags & ARRAY_FLAG_NEEDINITIALIZING) && - !(flags & ARRAY_FLAG_REBUILDING) && - !(flags & ARRAY_FLAG_INITIALIZING))? - ", Unintialized" : ""); - else if ((flags & ARRAY_FLAG_BROKEN) && - devinfo->u.array.array_type != AT_RAID6) - return "Critical"; - else if (flags & ARRAY_FLAG_REBUILDING) - sprintf(s, - (flags & ARRAY_FLAG_NEEDINITIALIZING)? - "%sBackground initializing %d.%d%%" : - "%sRebuilding %d.%d%%", - (flags & ARRAY_FLAG_BROKEN)? "Critical, " : "", - reb_prog / 100, - reb_prog % 100); - else if (flags & ARRAY_FLAG_VERIFYING) - sprintf(s, "%sVerifying %d.%d%%", - (flags & ARRAY_FLAG_BROKEN)? "Critical, " : "", - reb_prog / 100, - reb_prog % 100); - else if (flags & ARRAY_FLAG_INITIALIZING) - sprintf(s, "%sForground initializing %d.%d%%", - (flags & ARRAY_FLAG_BROKEN)? "Critical, " : "", - reb_prog / 100, - reb_prog % 100); - else if (flags & ARRAY_FLAG_NEEDTRANSFORM) - sprintf(s,"%s%s%s", "Need Expanding/Migrating", - (flags & ARRAY_FLAG_BROKEN)? "Critical, " : "", - ((flags & ARRAY_FLAG_NEEDINITIALIZING) && - !(flags & ARRAY_FLAG_REBUILDING) && - !(flags & ARRAY_FLAG_INITIALIZING))? - ", Unintialized" : ""); - else if (flags & ARRAY_FLAG_NEEDINITIALIZING && - !(flags & ARRAY_FLAG_REBUILDING) && - !(flags & ARRAY_FLAG_INITIALIZING)) - sprintf(s,"%sUninitialized", - (flags & ARRAY_FLAG_BROKEN)? "Critical, " : ""); - else if ((flags & ARRAY_FLAG_NEEDBUILDING) || - (flags & ARRAY_FLAG_BROKEN)) - return "Critical"; - else - return "Normal"; - return s; -} - -static void hptiop_dump_devinfo(struct hptiop_hba *hba, - struct hptiop_getinfo *pinfo, __le32 id, int indent) -{ - struct hpt_logical_device_info_v3 devinfo; - int i; - u64 capacity; - - for (i = 0; i < indent; i++) - hptiop_copy_info(pinfo, "\t"); - - if (hptiop_get_device_info_v3(hba, id, &devinfo)) { - hptiop_copy_info(pinfo, "unknown\n"); - return; - } - - switch (devinfo.type) { - - case LDT_DEVICE: { - struct hd_driveid *driveid; - u32 flags = le32_to_cpu(devinfo.u.device.flags); - - driveid = (struct hd_driveid *)devinfo.u.device.ident; - /* model[] is 40 chars long, but we just want 20 chars here */ - driveid->model[20] = 0; - - if (indent) - if (flags & DEVICE_FLAG_DISABLED) - hptiop_copy_info(pinfo,"Missing\n"); - else - hptiop_copy_info(pinfo, "CH%d %s\n", - devinfo.u.device.path_id + 1, - driveid->model); - else { - capacity = le64_to_cpu(devinfo.capacity) * 512; - do_div(capacity, 1000000); - hptiop_copy_info(pinfo, - "CH%d %s, %lluMB, %s %s%s%s%s\n", - devinfo.u.device.path_id + 1, - driveid->model, - capacity, - (flags & DEVICE_FLAG_DISABLED)? - "Disabled" : "Normal", - devinfo.u.device.read_ahead_enabled? - "[RA]" : "", - devinfo.u.device.write_cache_enabled? - "[WC]" : "", - devinfo.u.device.TCQ_enabled? - "[TCQ]" : "", - devinfo.u.device.NCQ_enabled? - "[NCQ]" : "" - ); - } - break; - } - - case LDT_ARRAY: - if (devinfo.target_id != INVALID_TARGET_ID) - hptiop_copy_info(pinfo, "[DISK %d_%d] ", - devinfo.vbus_id, devinfo.target_id); - - capacity = le64_to_cpu(devinfo.capacity) * 512; - do_div(capacity, 1000000); - hptiop_copy_info(pinfo, "%s (%s), %lluMB, %s\n", - devinfo.u.array.name, - devinfo.u.array.array_type==AT_RAID0? "RAID0" : - devinfo.u.array.array_type==AT_RAID1? "RAID1" : - devinfo.u.array.array_type==AT_RAID5? "RAID5" : - devinfo.u.array.array_type==AT_RAID6? "RAID6" : - devinfo.u.array.array_type==AT_JBOD? "JBOD" : - "unknown", - capacity, - get_array_status(&devinfo)); - for (i = 0; i < devinfo.u.array.ndisk; i++) { - if (hpt_id_valid(devinfo.u.array.members[i])) { - if (cpu_to_le16(1<private_data; - struct hptiop_getinfo info; - int i, j, ndev; - struct hpt_controller_info con_info; - struct hpt_channel_info chan_info; - __le32 ids[32]; - - info.buffer = buf; - info.buflength = count; - info.bufoffset = ppos ? *ppos : 0; - info.filpos = 0; - info.buffillen = 0; - - if (hptiop_get_controller_info(hba, &con_info)) - return -EIO; - - for (i = 0; i < con_info.num_buses; i++) { - if (hptiop_get_channel_info(hba, i, &chan_info) == 0) { - if (hpt_id_valid(chan_info.devices[0])) - hptiop_dump_devinfo(hba, &info, - chan_info.devices[0], 0); - if (hpt_id_valid(chan_info.devices[1])) - hptiop_dump_devinfo(hba, &info, - chan_info.devices[1], 0); - } - } - - ndev = hptiop_get_logical_devices(hba, ids, - sizeof(ids) / sizeof(ids[0])); - - /* - * if hptiop_get_logical_devices fails, ndev==-1 and it just - * output nothing here - */ - for (j = 0; j < ndev; j++) - hptiop_dump_devinfo(hba, &info, ids[j], 0); - - if (ppos) - *ppos += info.buffillen; - - return info.buffillen; -} - -static int hptiop_cdev_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct hptiop_hba *hba = file->private_data; - struct hpt_ioctl_u ioctl_u; - struct hpt_ioctl_k ioctl_k; - u32 bytes_returned; - int err = -EINVAL; - - if (copy_from_user(&ioctl_u, - (void __user *)arg, sizeof(struct hpt_ioctl_u))) - return -EINVAL; - - if (ioctl_u.magic != HPT_IOCTL_MAGIC) - return -EINVAL; - - ioctl_k.ioctl_code = ioctl_u.ioctl_code; - ioctl_k.inbuf = NULL; - ioctl_k.inbuf_size = ioctl_u.inbuf_size; - ioctl_k.outbuf = NULL; - ioctl_k.outbuf_size = ioctl_u.outbuf_size; - ioctl_k.hba = hba; - ioctl_k.bytes_returned = &bytes_returned; - - /* verify user buffer */ - if ((ioctl_k.inbuf_size && !access_ok(VERIFY_READ, - ioctl_u.inbuf, ioctl_k.inbuf_size)) || - (ioctl_k.outbuf_size && !access_ok(VERIFY_WRITE, - ioctl_u.outbuf, ioctl_k.outbuf_size)) || - (ioctl_u.bytes_returned && !access_ok(VERIFY_WRITE, - ioctl_u.bytes_returned, sizeof(u32))) || - ioctl_k.inbuf_size + ioctl_k.outbuf_size > 0x10000) { - - dprintk("scsi%d: got bad user address\n", hba->host->host_no); - return -EINVAL; - } - - /* map buffer to kernel. */ - if (ioctl_k.inbuf_size) { - ioctl_k.inbuf = kmalloc(ioctl_k.inbuf_size, GFP_KERNEL); - if (!ioctl_k.inbuf) { - dprintk("scsi%d: fail to alloc inbuf\n", - hba->host->host_no); - err = -ENOMEM; - goto err_exit; - } - - if (copy_from_user(ioctl_k.inbuf, - ioctl_u.inbuf, ioctl_k.inbuf_size)) { - goto err_exit; - } - } - - if (ioctl_k.outbuf_size) { - ioctl_k.outbuf = kmalloc(ioctl_k.outbuf_size, GFP_KERNEL); - if (!ioctl_k.outbuf) { - dprintk("scsi%d: fail to alloc outbuf\n", - hba->host->host_no); - err = -ENOMEM; - goto err_exit; - } - } - - hptiop_do_ioctl(&ioctl_k); - - if (ioctl_k.result == HPT_IOCTL_RESULT_OK) { - if (ioctl_k.outbuf_size && - copy_to_user(ioctl_u.outbuf, - ioctl_k.outbuf, ioctl_k.outbuf_size)) - goto err_exit; - - if (ioctl_u.bytes_returned && - copy_to_user(ioctl_u.bytes_returned, - &bytes_returned, sizeof(u32))) - goto err_exit; - - err = 0; - } - -err_exit: - kfree(ioctl_k.inbuf); - kfree(ioctl_k.outbuf); - - return err; -} - -static int hptiop_cdev_open(struct inode *inode, struct file *file) -{ - struct hptiop_hba *hba; - unsigned i = 0, minor = iminor(inode); - int ret = -ENODEV; - - spin_lock(&hptiop_hba_list_lock); - list_for_each_entry(hba, &hptiop_hba_list, link) { - if (i == minor) { - file->private_data = hba; - ret = 0; - goto out; - } - i++; - } - -out: - spin_unlock(&hptiop_hba_list_lock); - return ret; -} - -static struct file_operations hptiop_cdev_fops = { - .owner = THIS_MODULE, - .read = hptiop_cdev_read, - .ioctl = hptiop_cdev_ioctl, - .open = hptiop_cdev_open, -}; - static ssize_t hptiop_show_fw_version(struct class_device *class_dev, char *buf) { struct Scsi_Host *host = class_to_shost(class_dev); @@ -1296,19 +771,13 @@ static int __devinit hptiop_probe(struct pci_dev *pcidev, goto unmap_pci_bar; } - if (scsi_add_host(host, &pcidev->dev)) { - printk(KERN_ERR "scsi%d: scsi_add_host failed\n", - hba->host->host_no); - goto unmap_pci_bar; - } - pci_set_drvdata(pcidev, host); if (request_irq(pcidev->irq, hptiop_intr, IRQF_SHARED, driver_name, hba)) { printk(KERN_ERR "scsi%d: request irq %d failed\n", hba->host->host_no, pcidev->irq); - goto remove_scsi_host; + goto unmap_pci_bar; } /* Allocate request mem */ @@ -1355,9 +824,12 @@ static int __devinit hptiop_probe(struct pci_dev *pcidev, if (hptiop_initialize_iop(hba)) goto free_request_mem; - spin_lock(&hptiop_hba_list_lock); - list_add_tail(&hba->link, &hptiop_hba_list); - spin_unlock(&hptiop_hba_list_lock); + if (scsi_add_host(host, &pcidev->dev)) { + printk(KERN_ERR "scsi%d: scsi_add_host failed\n", + hba->host->host_no); + goto free_request_mem; + } + scsi_scan_host(host); @@ -1372,9 +844,6 @@ free_request_mem: free_request_irq: free_irq(hba->pcidev->irq, hba); -remove_scsi_host: - scsi_remove_host(host); - unmap_pci_bar: iounmap(hba->iop); @@ -1422,10 +891,6 @@ static void hptiop_remove(struct pci_dev *pcidev) scsi_remove_host(host); - spin_lock(&hptiop_hba_list_lock); - list_del_init(&hba->link); - spin_unlock(&hptiop_hba_list_lock); - hptiop_shutdown(pcidev); free_irq(hba->pcidev->irq, hba); @@ -1462,27 +927,12 @@ static struct pci_driver hptiop_pci_driver = { static int __init hptiop_module_init(void) { - int error; - printk(KERN_INFO "%s %s\n", driver_name_long, driver_ver); - - error = pci_register_driver(&hptiop_pci_driver); - if (error < 0) - return error; - - hptiop_cdev_major = register_chrdev(0, "hptiop", &hptiop_cdev_fops); - if (hptiop_cdev_major < 0) { - printk(KERN_WARNING "unable to register hptiop device.\n"); - return hptiop_cdev_major; - } - - return 0; + return pci_register_driver(&hptiop_pci_driver); } static void __exit hptiop_module_exit(void) { - dprintk("hptiop_module_exit\n"); - unregister_chrdev(hptiop_cdev_major, "hptiop"); pci_unregister_driver(&hptiop_pci_driver); } -- cgit v1.1 From ca8c100a00e91cf93782008441a2e159c4b49a25 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 6 Aug 2006 20:53:40 +0100 Subject: [ARM] Fix NCR5380-based SCSI card build The NCR5380-based SCSI cards need the SCSI SPI transport selected to build correctly. Signed-off-by: Russell King --- drivers/scsi/arm/Kconfig | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/arm/Kconfig b/drivers/scsi/arm/Kconfig index 06d7601..d006a8c 100644 --- a/drivers/scsi/arm/Kconfig +++ b/drivers/scsi/arm/Kconfig @@ -69,6 +69,7 @@ comment "The following drivers are not fully supported" config SCSI_CUMANA_1 tristate "CumanaSCSI I support (EXPERIMENTAL)" depends on ARCH_ACORN && EXPERIMENTAL && SCSI + select SCSI_SPI_ATTRS help This enables support for the Cumana SCSI I card. If you have an Acorn system with one of these, say Y. If unsure, say N. @@ -76,6 +77,7 @@ config SCSI_CUMANA_1 config SCSI_ECOSCSI tristate "EcoScsi support (EXPERIMENTAL)" depends on ARCH_ACORN && EXPERIMENTAL && (ARCH_ARC || ARCH_A5K) && SCSI + select SCSI_SPI_ATTRS help This enables support for the EcoSCSI card -- a small card that sits in the Econet socket. If you have an Acorn system with one of these, @@ -84,6 +86,7 @@ config SCSI_ECOSCSI config SCSI_OAK1 tristate "Oak SCSI support (EXPERIMENTAL)" depends on ARCH_ACORN && EXPERIMENTAL && SCSI + select SCSI_SPI_ATTRS help This enables support for the Oak SCSI card. If you have an Acorn system with one of these, say Y. If unsure, say N. -- cgit v1.1 From 574dc0abab6650c5371df15ac708e48fa25bed89 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 6 Aug 2006 20:55:33 +0100 Subject: [ARM] Fix Acorn platform SCSI driver build failures SCSI folk forgot to fix up all the uses of 'buffer' before deleting this struct member. Do it for them to rescue the resulting build failures. Signed-off-by: Russell King --- drivers/scsi/arm/scsi.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/arm/scsi.h b/drivers/scsi/arm/scsi.h index 6dd544a..8c2600f 100644 --- a/drivers/scsi/arm/scsi.h +++ b/drivers/scsi/arm/scsi.h @@ -74,7 +74,7 @@ static inline void init_SCp(Scsi_Cmnd *SCpnt) unsigned long len = 0; int buf; - SCpnt->SCp.buffer = (struct scatterlist *) SCpnt->buffer; + SCpnt->SCp.buffer = (struct scatterlist *) SCpnt->request_buffer; SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1; SCpnt->SCp.ptr = (char *) (page_address(SCpnt->SCp.buffer->page) + -- cgit v1.1 From 916f3ac680fcc4c142e9acd46161f55533b11760 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sun, 6 Aug 2006 22:22:23 +0200 Subject: [MMC] Fix base address configuration in wbsd There were some confusion about base I/O variables in the wbsd driver. Seems like things have been working on shear luck so far. The global 'io' variable (used when manually configuring the resources) was used instead of the local 'base' variable. Signed-off-by: Pierre Ossman Signed-off-by: Russell King --- drivers/mmc/wbsd.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c index 8a30ef3..ce86887 100644 --- a/drivers/mmc/wbsd.c +++ b/drivers/mmc/wbsd.c @@ -41,7 +41,7 @@ #include "wbsd.h" #define DRIVER_NAME "wbsd" -#define DRIVER_VERSION "1.5" +#define DRIVER_VERSION "1.6" #define DBG(x...) \ pr_debug(DRIVER_NAME ": " x) @@ -1439,13 +1439,13 @@ static int __devinit wbsd_scan(struct wbsd_host *host) static int __devinit wbsd_request_region(struct wbsd_host *host, int base) { - if (io & 0x7) + if (base & 0x7) return -EINVAL; if (!request_region(base, 8, DRIVER_NAME)) return -EIO; - host->base = io; + host->base = base; return 0; } -- cgit v1.1 From 77d88ee275aeba5da447987f30401bbd4c901ca9 Mon Sep 17 00:00:00 2001 From: Michael Reed Date: Mon, 31 Jul 2006 12:19:40 -0500 Subject: [SCSI] mptfc: properly wait for firmware target discovery to complete Based upon a conversation I had with LSI's fibre channel firmware guru, this patch adds another condition under which the driver waits for the firmware link initialization / target discovery to complete. Signed-off-by: Michael Reed Acked-by: Moore, Eric Signed-off-by: James Bottomley --- drivers/message/fusion/mptfc.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c index 90da7d6..2144554 100644 --- a/drivers/message/fusion/mptfc.c +++ b/drivers/message/fusion/mptfc.c @@ -669,7 +669,10 @@ mptfc_GetFcPortPage0(MPT_ADAPTER *ioc, int portnum) * if still doing discovery, * hang loose a while until finished */ - if (pp0dest->PortState == MPI_FCPORTPAGE0_PORTSTATE_UNKNOWN) { + if ((pp0dest->PortState == MPI_FCPORTPAGE0_PORTSTATE_UNKNOWN) || + (pp0dest->PortState == MPI_FCPORTPAGE0_PORTSTATE_ONLINE && + (pp0dest->Flags & MPI_FCPORTPAGE0_FLAGS_ATTACH_TYPE_MASK) + == MPI_FCPORTPAGE0_FLAGS_ATTACH_NO_INIT)) { if (count-- > 0) { msleep(100); goto try_again; -- cgit v1.1 From 3a0c56d801df6785b30e36c19e89d7e971c151da Mon Sep 17 00:00:00 2001 From: Michael Reed Date: Mon, 31 Jul 2006 12:19:50 -0500 Subject: [SCSI] mptfc: correct out of order event processing This patch corrects a problem in mptfc which can result in targets being removed after executing an "lsiutil 99" reset of the fibre channel ports. The last rescan event was being processed before the setup reset work due to an inappropriate optimization in the event processing logic. Every rescan event is now queued for execution and the setup reset work now executes in the proper sequence. Signed-off-by: Michael Reed Acked-by: Moore, Eric Signed-off-by: James Bottomley --- drivers/message/fusion/mptbase.h | 1 - drivers/message/fusion/mptfc.c | 87 ++++++++++++++++------------------------ 2 files changed, 34 insertions(+), 54 deletions(-) (limited to 'drivers') diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h index d4cb144..c537d71 100644 --- a/drivers/message/fusion/mptbase.h +++ b/drivers/message/fusion/mptbase.h @@ -640,7 +640,6 @@ typedef struct _MPT_ADAPTER struct work_struct fc_setup_reset_work; struct list_head fc_rports; spinlock_t fc_rescan_work_lock; - int fc_rescan_work_count; struct work_struct fc_rescan_work; char fc_rescan_work_q_name[KOBJ_NAME_LEN]; struct workqueue_struct *fc_rescan_work_q; diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c index 2144554..85696f3 100644 --- a/drivers/message/fusion/mptfc.c +++ b/drivers/message/fusion/mptfc.c @@ -898,59 +898,45 @@ mptfc_rescan_devices(void *arg) { MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg; int ii; - int work_to_do; u64 pn; - unsigned long flags; struct mptfc_rport_info *ri; - do { - /* start by tagging all ports as missing */ - list_for_each_entry(ri, &ioc->fc_rports, list) { - if (ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED) { - ri->flags |= MPT_RPORT_INFO_FLAGS_MISSING; - } + /* start by tagging all ports as missing */ + list_for_each_entry(ri, &ioc->fc_rports, list) { + if (ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED) { + ri->flags |= MPT_RPORT_INFO_FLAGS_MISSING; } + } - /* - * now rescan devices known to adapter, - * will reregister existing rports - */ - for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) { - (void) mptfc_GetFcPortPage0(ioc, ii); - mptfc_init_host_attr(ioc,ii); /* refresh */ - mptfc_GetFcDevPage0(ioc,ii,mptfc_register_dev); - } + /* + * now rescan devices known to adapter, + * will reregister existing rports + */ + for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) { + (void) mptfc_GetFcPortPage0(ioc, ii); + mptfc_init_host_attr(ioc, ii); /* refresh */ + mptfc_GetFcDevPage0(ioc, ii, mptfc_register_dev); + } - /* delete devices still missing */ - list_for_each_entry(ri, &ioc->fc_rports, list) { - /* if newly missing, delete it */ - if (ri->flags & MPT_RPORT_INFO_FLAGS_MISSING) { + /* delete devices still missing */ + list_for_each_entry(ri, &ioc->fc_rports, list) { + /* if newly missing, delete it */ + if (ri->flags & MPT_RPORT_INFO_FLAGS_MISSING) { - ri->flags &= ~(MPT_RPORT_INFO_FLAGS_REGISTERED| - MPT_RPORT_INFO_FLAGS_MISSING); - fc_remote_port_delete(ri->rport); /* won't sleep */ - ri->rport = NULL; + ri->flags &= ~(MPT_RPORT_INFO_FLAGS_REGISTERED| + MPT_RPORT_INFO_FLAGS_MISSING); + fc_remote_port_delete(ri->rport); /* won't sleep */ + ri->rport = NULL; - pn = (u64)ri->pg0.WWPN.High << 32 | - (u64)ri->pg0.WWPN.Low; - dfcprintk ((MYIOC_s_INFO_FMT - "mptfc_rescan.%d: %llx deleted\n", - ioc->name, - ioc->sh->host_no, - (unsigned long long)pn)); - } + pn = (u64)ri->pg0.WWPN.High << 32 | + (u64)ri->pg0.WWPN.Low; + dfcprintk ((MYIOC_s_INFO_FMT + "mptfc_rescan.%d: %llx deleted\n", + ioc->name, + ioc->sh->host_no, + (unsigned long long)pn)); } - - /* - * allow multiple passes as target state - * might have changed during scan - */ - spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags); - if (ioc->fc_rescan_work_count > 2) /* only need one more */ - ioc->fc_rescan_work_count = 2; - work_to_do = --ioc->fc_rescan_work_count; - spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags); - } while (work_to_do); + } } static int @@ -1162,7 +1148,6 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id) * by doing it via the workqueue, some locking is eliminated */ - ioc->fc_rescan_work_count = 1; queue_work(ioc->fc_rescan_work_q, &ioc->fc_rescan_work); flush_workqueue(ioc->fc_rescan_work_q); @@ -1205,10 +1190,8 @@ mptfc_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply) case MPI_EVENT_RESCAN: spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags); if (ioc->fc_rescan_work_q) { - if (ioc->fc_rescan_work_count++ == 0) { - queue_work(ioc->fc_rescan_work_q, - &ioc->fc_rescan_work); - } + queue_work(ioc->fc_rescan_work_q, + &ioc->fc_rescan_work); } spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags); break; @@ -1251,10 +1234,8 @@ mptfc_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) mptfc_SetFcPortPage1_defaults(ioc); spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags); if (ioc->fc_rescan_work_q) { - if (ioc->fc_rescan_work_count++ == 0) { - queue_work(ioc->fc_rescan_work_q, - &ioc->fc_rescan_work); - } + queue_work(ioc->fc_rescan_work_q, + &ioc->fc_rescan_work); } spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags); } -- cgit v1.1 From dd2c609c59cd9daeb90d58f3d1bc3813e8987df1 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 7 Aug 2006 01:40:04 +0200 Subject: [MMC] Another stray 'io' reference Another misuse of the global 'io' variable instead of the local 'base'. Signed-off-by: Pierre Ossman Signed-off-by: Russell King --- drivers/mmc/wbsd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c index ce86887..c351c6d 100644 --- a/drivers/mmc/wbsd.c +++ b/drivers/mmc/wbsd.c @@ -1773,7 +1773,7 @@ static int __devinit wbsd_init(struct device *dev, int base, int irq, int dma, /* * Request resources. */ - ret = wbsd_request_resources(host, io, irq, dma); + ret = wbsd_request_resources(host, base, irq, dma); if (ret) { wbsd_release_resources(host); wbsd_free_mmc(dev); @@ -1861,6 +1861,7 @@ static void __devexit wbsd_shutdown(struct device *dev, int pnp) static int __devinit wbsd_probe(struct platform_device *dev) { + /* Use the module parameters for resources */ return wbsd_init(&dev->dev, io, irq, dma, 0); } -- cgit v1.1 From 25a2001a285e187d99ea347693bedd73b3e0722a Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 7 Aug 2006 17:00:28 +0200 Subject: [S390] tape class return value handling. Without this patch register_tape_dev() will always fail, but might return a value that is not an error number. This will lead to accesses to already freed memory areas... Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- drivers/s390/char/tape_class.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/s390/char/tape_class.c b/drivers/s390/char/tape_class.c index 643b6d0..56b8761 100644 --- a/drivers/s390/char/tape_class.c +++ b/drivers/s390/char/tape_class.c @@ -76,7 +76,7 @@ struct tape_class_device *register_tape_dev( device, "%s", tcd->device_name ); - rc = PTR_ERR(tcd->class_device); + rc = IS_ERR(tcd->class_device) ? PTR_ERR(tcd->class_device) : 0; if (rc) goto fail_with_cdev; rc = sysfs_create_link( -- cgit v1.1 From 4bc0c4f9e74e7a5d62ef4db923b377f2aa474a8f Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Mon, 7 Aug 2006 17:00:30 +0200 Subject: [S390] retry after deferred condition code. Do a retry of read device characteristics / read configuration data when a deferred condition code 1 is encountered in ccw_device_wake_up(). Signed-off-by: Cornelia Huck Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/device_ops.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c index a601242..9e3de0bd 100644 --- a/drivers/s390/cio/device_ops.c +++ b/drivers/s390/cio/device_ops.c @@ -263,6 +263,9 @@ ccw_device_wake_up(struct ccw_device *cdev, unsigned long ip, struct irb *irb) /* Abuse intparm for error reporting. */ if (IS_ERR(irb)) cdev->private->intparm = -EIO; + else if (irb->scsw.cc == 1) + /* Retry for deferred condition code. */ + cdev->private->intparm = -EAGAIN; else if ((irb->scsw.dstat != (DEV_STAT_CHN_END|DEV_STAT_DEV_END)) || (irb->scsw.cstat != 0)) { -- cgit v1.1 From 65200c291c4ce397835d8232eaa0878b765a9bce Mon Sep 17 00:00:00 2001 From: Peter Oberparleiter Date: Mon, 7 Aug 2006 17:00:33 +0200 Subject: [S390] lost interrupt after chpid vary off/on cycle. I/O on a CCW device may stall if a channel path to that device is logicaly varied off/on. A user I/O interrupt can get misinterpreted as interrupt for an internal path verification operation due to a missing check and is therefore never reported to the device driver. Correct check for pending interruptions before starting path verification. Signed-off-by: Peter Oberparleiter Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/device_fsm.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index 7a39e0b..6d91c2e 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c @@ -772,6 +772,7 @@ ccw_device_online_verify(struct ccw_device *cdev, enum dev_event dev_event) stsch(sch->schid, &sch->schib); if (sch->schib.scsw.actl != 0 || + (sch->schib.scsw.stctl & SCSW_STCTL_STATUS_PEND) || (cdev->private->irb.scsw.stctl & SCSW_STCTL_STATUS_PEND)) { /* * No final status yet or final status not yet delivered -- cgit v1.1 From 37ab46a3f4983c32d5b5ab6a0366ec482e38ba47 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Mon, 7 Aug 2006 18:13:06 +0200 Subject: [S390] xpram system device class. Remove system device class for xpram. It creates the directory hierarchy under /sys/devices/system/xpram/xpram0. The xpram0 directory is empty and it is always created while xpram1 and following devices are always missing, independent if the devices exist or not. Since the xpram devices are listed in /proc/partitions and /sys/block/ as slram the system device class for xpram is meaningless. Signed-off-by: Martin Schwidefsky --- drivers/s390/block/xpram.c | 25 +------------------------ 1 file changed, 1 insertion(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c index 1140302..ca7d51f 100644 --- a/drivers/s390/block/xpram.c +++ b/drivers/s390/block/xpram.c @@ -48,15 +48,6 @@ #define PRINT_ERR(x...) printk(KERN_ERR XPRAM_NAME " error:" x) -static struct sysdev_class xpram_sysclass = { - set_kset_name("xpram"), -}; - -static struct sys_device xpram_sys_device = { - .id = 0, - .cls = &xpram_sysclass, -}; - typedef struct { unsigned int size; /* size of xpram segment in pages */ unsigned int offset; /* start page of xpram segment */ @@ -451,8 +442,6 @@ static void __exit xpram_exit(void) } unregister_blkdev(XPRAM_MAJOR, XPRAM_NAME); blk_cleanup_queue(xpram_queue); - sysdev_unregister(&xpram_sys_device); - sysdev_class_unregister(&xpram_sysclass); } static int __init xpram_init(void) @@ -470,19 +459,7 @@ static int __init xpram_init(void) rc = xpram_setup_sizes(xpram_pages); if (rc) return rc; - rc = sysdev_class_register(&xpram_sysclass); - if (rc) - return rc; - - rc = sysdev_register(&xpram_sys_device); - if (rc) { - sysdev_class_unregister(&xpram_sysclass); - return rc; - } - rc = xpram_setup_blkdev(); - if (rc) - sysdev_unregister(&xpram_sys_device); - return rc; + return xpram_setup_blkdev(); } module_init(xpram_init); -- cgit v1.1 From d14cc9a342a8004b0ecfe66f1f12120962b61d8c Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 7 Aug 2006 16:11:48 -0700 Subject: [TG3]: skb->dev assignment is done by netdev_alloc_skb All caller of netdev_alloc_skb need to assign skb->dev shortly afterwards. Move it into common code. Signed-off-by: Christoph Hellwig Signed-off-by: David S. Miller --- drivers/net/tg3.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 6f97962..0afbed6 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -3101,7 +3101,6 @@ static int tg3_alloc_rx_skb(struct tg3 *tp, u32 opaque_key, if (skb == NULL) return -ENOMEM; - skb->dev = tp->dev; skb_reserve(skb, tp->rx_offset); mapping = pci_map_single(tp->pdev, skb->data, @@ -3274,7 +3273,6 @@ static int tg3_rx(struct tg3 *tp, int budget) if (copy_skb == NULL) goto drop_it_no_recycle; - copy_skb->dev = tp->dev; skb_reserve(copy_skb, 2); skb_put(copy_skb, len); pci_dma_sync_single_for_cpu(tp->pdev, dma_addr, len, PCI_DMA_FROMDEVICE); -- cgit v1.1 From 1b2a720506ccf7c30baaeda5d990c29b31e21726 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 7 Aug 2006 21:46:02 -0700 Subject: [TG3]: Fix tx race condition Fix a subtle race condition between tg3_start_xmit() and tg3_tx() discovered by Herbert Xu : CPU0 CPU1 tg3_start_xmit() if (tx_ring_full) { tx_lock tg3_tx() if (!netif_queue_stopped) netif_stop_queue() if (!tx_ring_full) update_tx_ring netif_wake_queue() tx_unlock } Even though tx_ring is updated before the if statement in tg3_tx() in program order, it can be re-ordered by the CPU as shown above. This scenario can cause the tx queue to be stopped forever if tg3_tx() has just freed up the entire tx_ring. The possibility of this happening should be very rare though. The following changes are made: 1. Add memory barrier to fix the above race condition. 2. Eliminate the private tx_lock altogether and rely solely on netif_tx_lock. This eliminates one spinlock in tg3_start_xmit() when the ring is full. 3. Because of 2, use netif_tx_lock in tg3_tx() before calling netif_wake_queue(). 4. Change TX_BUFFS_AVAIL to an inline function with a memory barrier. Herbert and David suggested using the memory barrier instead of volatile. 5. Check for the full wake queue condition before getting netif_tx_lock in tg3_tx(). This reduces the number of unnecessary spinlocks when the tx ring is full in a steady-state condition. 6. Update version to 3.65. Signed-off-by: Michael Chan Acked-by: Herbert Xu Signed-off-by: David S. Miller --- drivers/net/tg3.c | 49 ++++++++++++++++++++++++++++--------------------- drivers/net/tg3.h | 8 +++----- 2 files changed, 31 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 0afbed6..eafabb2 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -68,8 +68,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.64" -#define DRV_MODULE_RELDATE "July 31, 2006" +#define DRV_MODULE_VERSION "3.65" +#define DRV_MODULE_RELDATE "August 07, 2006" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 @@ -123,9 +123,6 @@ TG3_RX_RCB_RING_SIZE(tp)) #define TG3_TX_RING_BYTES (sizeof(struct tg3_tx_buffer_desc) * \ TG3_TX_RING_SIZE) -#define TX_BUFFS_AVAIL(TP) \ - ((TP)->tx_pending - \ - (((TP)->tx_prod - (TP)->tx_cons) & (TG3_TX_RING_SIZE - 1))) #define NEXT_TX(N) (((N) + 1) & (TG3_TX_RING_SIZE - 1)) #define RX_PKT_BUF_SZ (1536 + tp->rx_offset + 64) @@ -2987,6 +2984,13 @@ static void tg3_tx_recover(struct tg3 *tp) spin_unlock(&tp->lock); } +static inline u32 tg3_tx_avail(struct tg3 *tp) +{ + smp_mb(); + return (tp->tx_pending - + ((tp->tx_prod - tp->tx_cons) & (TG3_TX_RING_SIZE - 1))); +} + /* Tigon3 never reports partial packet sends. So we do not * need special logic to handle SKBs that have not had all * of their frags sent yet, like SunGEM does. @@ -3038,12 +3042,20 @@ static void tg3_tx(struct tg3 *tp) tp->tx_cons = sw_idx; - if (unlikely(netif_queue_stopped(tp->dev))) { - spin_lock(&tp->tx_lock); + /* Need to make the tx_cons update visible to tg3_start_xmit() + * before checking for netif_queue_stopped(). Without the + * memory barrier, there is a small possibility that tg3_start_xmit() + * will miss it and cause the queue to be stopped forever. + */ + smp_mb(); + + if (unlikely(netif_queue_stopped(tp->dev) && + (tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH))) { + netif_tx_lock(tp->dev); if (netif_queue_stopped(tp->dev) && - (TX_BUFFS_AVAIL(tp) > TG3_TX_WAKEUP_THRESH)) + (tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH)) netif_wake_queue(tp->dev); - spin_unlock(&tp->tx_lock); + netif_tx_unlock(tp->dev); } } @@ -3795,7 +3807,7 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) * interrupt. Furthermore, IRQ processing runs lockless so we have * no IRQ context deadlocks to worry about either. Rejoice! */ - if (unlikely(TX_BUFFS_AVAIL(tp) <= (skb_shinfo(skb)->nr_frags + 1))) { + if (unlikely(tg3_tx_avail(tp) <= (skb_shinfo(skb)->nr_frags + 1))) { if (!netif_queue_stopped(dev)) { netif_stop_queue(dev); @@ -3891,12 +3903,10 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) tw32_tx_mbox((MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW), entry); tp->tx_prod = entry; - if (unlikely(TX_BUFFS_AVAIL(tp) <= (MAX_SKB_FRAGS + 1))) { - spin_lock(&tp->tx_lock); + if (unlikely(tg3_tx_avail(tp) <= (MAX_SKB_FRAGS + 1))) { netif_stop_queue(dev); - if (TX_BUFFS_AVAIL(tp) > TG3_TX_WAKEUP_THRESH) + if (tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH) netif_wake_queue(tp->dev); - spin_unlock(&tp->tx_lock); } out_unlock: @@ -3918,7 +3928,7 @@ static int tg3_tso_bug(struct tg3 *tp, struct sk_buff *skb) struct sk_buff *segs, *nskb; /* Estimate the number of fragments in the worst case */ - if (unlikely(TX_BUFFS_AVAIL(tp) <= (skb_shinfo(skb)->gso_segs * 3))) { + if (unlikely(tg3_tx_avail(tp) <= (skb_shinfo(skb)->gso_segs * 3))) { netif_stop_queue(tp->dev); return NETDEV_TX_BUSY; } @@ -3958,7 +3968,7 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev) * interrupt. Furthermore, IRQ processing runs lockless so we have * no IRQ context deadlocks to worry about either. Rejoice! */ - if (unlikely(TX_BUFFS_AVAIL(tp) <= (skb_shinfo(skb)->nr_frags + 1))) { + if (unlikely(tg3_tx_avail(tp) <= (skb_shinfo(skb)->nr_frags + 1))) { if (!netif_queue_stopped(dev)) { netif_stop_queue(dev); @@ -4108,12 +4118,10 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev) tw32_tx_mbox((MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW), entry); tp->tx_prod = entry; - if (unlikely(TX_BUFFS_AVAIL(tp) <= (MAX_SKB_FRAGS + 1))) { - spin_lock(&tp->tx_lock); + if (unlikely(tg3_tx_avail(tp) <= (MAX_SKB_FRAGS + 1))) { netif_stop_queue(dev); - if (TX_BUFFS_AVAIL(tp) > TG3_TX_WAKEUP_THRESH) + if (tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH) netif_wake_queue(tp->dev); - spin_unlock(&tp->tx_lock); } out_unlock: @@ -11472,7 +11480,6 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, tp->grc_mode |= GRC_MODE_BSWAP_NONFRM_DATA; #endif spin_lock_init(&tp->lock); - spin_lock_init(&tp->tx_lock); spin_lock_init(&tp->indirect_lock); INIT_WORK(&tp->reset_task, tg3_reset_task, tp); diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index ba2c987..3ecf356 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2079,9 +2079,9 @@ struct tg3 { * lock: Held during reset, PHY access, timer, and when * updating tg3_flags and tg3_flags2. * - * tx_lock: Held during tg3_start_xmit and tg3_tx only - * when calling netif_[start|stop]_queue. - * tg3_start_xmit is protected by netif_tx_lock. + * netif_tx_lock: Held during tg3_start_xmit. tg3_tx holds + * netif_tx_lock when it needs to call + * netif_wake_queue. * * Both of these locks are to be held with BH safety. * @@ -2118,8 +2118,6 @@ struct tg3 { u32 tx_cons; u32 tx_pending; - spinlock_t tx_lock; - struct tg3_tx_buffer_desc *tx_ring; struct tx_ring_info *tx_buffers; dma_addr_t tx_desc_mapping; -- cgit v1.1 From 5bdd6cc3300be534f2a2cf826e3fb926b5695698 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 25 Jul 2006 16:17:54 -0300 Subject: V4L/DVB (4371a): Fix V4L1 dependencies on compat_ioctl32 Compat32 should be able to handle V4L1 ioctls if the old API support were selected. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/compat_ioctl32.c | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/compat_ioctl32.c b/drivers/media/video/compat_ioctl32.c index 9dddff4..b69ee11 100644 --- a/drivers/media/video/compat_ioctl32.c +++ b/drivers/media/video/compat_ioctl32.c @@ -21,7 +21,7 @@ #ifdef CONFIG_COMPAT - +#ifdef CONFIG_VIDEO_V4L1_COMPAT struct video_tuner32 { compat_int_t tuner; char name[32]; @@ -107,6 +107,7 @@ struct video_window32 { compat_caddr_t clips; compat_int_t clipcount; }; +#endif static int native_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { @@ -124,6 +125,7 @@ static int native_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } +#ifdef CONFIG_VIDEO_V4L1_COMPAT /* You get back everything except the clips... */ static int put_video_window32(struct video_window *kp, struct video_window32 __user *up) { @@ -138,6 +140,7 @@ static int put_video_window32(struct video_window *kp, struct video_window32 __u return -EFAULT; return 0; } +#endif struct v4l2_clip32 { @@ -490,6 +493,7 @@ static inline int put_v4l2_input(struct v4l2_input *kp, struct v4l2_input __user return 0; } +#ifdef CONFIG_VIDEO_V4L1_COMPAT struct video_code32 { char loadwhat[16]; /* name or tag of file being passed */ @@ -517,6 +521,8 @@ static inline int microcode32(struct video_code *kp, struct video_code32 __user #define VIDIOCSFREQ32 _IOW('v',15, u32) #define VIDIOCSMICROCODE32 _IOW('v',27, struct video_code32) +#endif + /* VIDIOC_ENUMINPUT32 is VIDIOC_ENUMINPUT minus 4 bytes of padding alignement */ #define VIDIOC_ENUMINPUT32 VIDIOC_ENUMINPUT - _IOC(0, 0, 0, 4) #define VIDIOC_G_FMT32 _IOWR ('V', 4, struct v4l2_format32) @@ -537,6 +543,7 @@ static inline int microcode32(struct video_code *kp, struct video_code32 __user #define VIDIOC_S_INPUT32 _IOWR ('V', 39, compat_int_t) #define VIDIOC_TRY_FMT32 _IOWR ('V', 64, struct v4l2_format32) +#ifdef CONFIG_VIDEO_V4L1_COMPAT enum { MaxClips = (~0U-sizeof(struct video_window))/sizeof(struct video_clip) }; @@ -601,14 +608,17 @@ static int do_set_window(struct file *file, unsigned int cmd, unsigned long arg) return native_ioctl(file, VIDIOCSWIN, (unsigned long)vw); } +#endif static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { union { +#ifdef CONFIG_VIDEO_V4L1_COMPAT struct video_tuner vt; struct video_buffer vb; struct video_window vw; struct video_code vc; +#endif struct v4l2_format v2f; struct v4l2_buffer v2b; struct v4l2_framebuffer v2fb; @@ -624,6 +634,7 @@ static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg /* First, convert the command. */ switch(cmd) { +#ifdef CONFIG_VIDEO_V4L1_COMPAT case VIDIOCGTUNER32: cmd = VIDIOCGTUNER; break; case VIDIOCSTUNER32: cmd = VIDIOCSTUNER; break; case VIDIOCGWIN32: cmd = VIDIOCGWIN; break; @@ -631,6 +642,8 @@ static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg case VIDIOCSFBUF32: cmd = VIDIOCSFBUF; break; case VIDIOCGFREQ32: cmd = VIDIOCGFREQ; break; case VIDIOCSFREQ32: cmd = VIDIOCSFREQ; break; + case VIDIOCSMICROCODE32: cmd = VIDIOCSMICROCODE; break; +#endif case VIDIOC_G_FMT32: cmd = VIDIOC_G_FMT; break; case VIDIOC_S_FMT32: cmd = VIDIOC_S_FMT; break; case VIDIOC_QUERYBUF32: cmd = VIDIOC_QUERYBUF; break; @@ -647,10 +660,10 @@ static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg case VIDIOC_G_INPUT32: cmd = VIDIOC_G_INPUT; break; case VIDIOC_S_INPUT32: cmd = VIDIOC_S_INPUT; break; case VIDIOC_TRY_FMT32: cmd = VIDIOC_TRY_FMT; break; - case VIDIOCSMICROCODE32: cmd = VIDIOCSMICROCODE; break; }; switch(cmd) { +#ifdef CONFIG_VIDEO_V4L1_COMPAT case VIDIOCSTUNER: case VIDIOCGTUNER: err = get_video_tuner32(&karg.vt, up); @@ -664,6 +677,7 @@ static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg break; case VIDIOCSFREQ: +#endif case VIDIOC_S_INPUT: case VIDIOC_OVERLAY: case VIDIOC_STREAMON: @@ -717,18 +731,21 @@ static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg compatible_arg = 0; break; +#ifdef CONFIG_VIDEO_V4L1_COMPAT case VIDIOCGWIN: case VIDIOCGFBUF: case VIDIOCGFREQ: +#endif case VIDIOC_G_FBUF: case VIDIOC_G_INPUT: compatible_arg = 0; +#ifdef CONFIG_VIDEO_V4L1_COMPAT case VIDIOCSMICROCODE: err = microcode32(&karg.vc, up); compatible_arg = 0; break; +#endif }; - if(err) goto out; @@ -743,6 +760,7 @@ static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg } if(err == 0) { switch(cmd) { +#ifdef CONFIG_VIDEO_V4L1_COMPAT case VIDIOCGTUNER: err = put_video_tuner32(&karg.vt, up); break; @@ -754,7 +772,7 @@ static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg case VIDIOCGFBUF: err = put_video_buffer32(&karg.vb, up); break; - +#endif case VIDIOC_G_FBUF: err = put_v4l2_framebuffer32(&karg.v2fb, up); break; @@ -792,7 +810,9 @@ static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg err = put_v4l2_input32(&karg.v2i, up); break; +#ifdef CONFIG_VIDEO_V4L1_COMPAT case VIDIOCGFREQ: +#endif case VIDIOC_G_INPUT: err = put_user(((u32)karg.vx), (u32 __user *)up); break; @@ -810,6 +830,7 @@ long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg) return ret; switch (cmd) { +#ifdef CONFIG_VIDEO_V4L1_COMPAT case VIDIOCSWIN32: ret = do_set_window(file, cmd, arg); break; @@ -820,6 +841,7 @@ long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg) case VIDIOCSFBUF32: case VIDIOCGFREQ32: case VIDIOCSFREQ32: +#endif case VIDIOC_QUERYCAP: case VIDIOC_ENUM_FMT: case VIDIOC_G_FMT32: @@ -851,6 +873,7 @@ long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg) ret = do_video_ioctl(file, cmd, arg); break; +#ifdef CONFIG_VIDEO_V4L1_COMPAT /* Little v, the video4linux ioctls (conflict?) */ case VIDIOCGCAP: case VIDIOCGCHAN: @@ -879,6 +902,7 @@ long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg) case _IOR('v' , BASE_VIDIOCPRIVATE+7, int): ret = native_ioctl(file, cmd, (unsigned long)compat_ptr(arg)); break; +#endif default: v4l_print_ioctl("compat_ioctl32", cmd); } -- cgit v1.1 From 3cdc0f263b9fe99f7dfcef49df7a148b458e9d11 Mon Sep 17 00:00:00 2001 From: Luc Van Oostenryck Date: Tue, 8 Aug 2006 09:10:10 -0300 Subject: V4L/DVB (4395): Restore compat_ioctl in pwc driver The compat_ioctl support of the pwc driver was dropped during the last update of the driver. I suppose it was by mistake. If yes here is the patch to restore the support. Signed-off-by: Luc Van Oostenryck Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pwc/pwc-if.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c index 47d0d83..d470394 100644 --- a/drivers/media/video/pwc/pwc-if.c +++ b/drivers/media/video/pwc/pwc-if.c @@ -160,6 +160,7 @@ static struct file_operations pwc_fops = { .poll = pwc_video_poll, .mmap = pwc_video_mmap, .ioctl = pwc_video_ioctl, + .compat_ioctl = v4l_compat_ioctl32, .llseek = no_llseek, }; static struct video_device pwc_template = { -- cgit v1.1 From 0dfa9abd6bd153364da8cb131db0d0404ab15ad1 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 8 Aug 2006 09:10:10 -0300 Subject: V4L/DVB (4399): Fix a typo that caused some compat stuff to not work Config option typo: -#ifdef CONFIG_V4L1_COMPAT +#ifdef CONFIG_VIDEO_V4L1_COMPAT Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-video.c | 4 ++-- drivers/media/video/saa7134/saa7134-video.c | 2 +- drivers/media/video/v4l2-common.c | 6 +++--- drivers/media/video/videodev.c | 2 +- drivers/media/video/vivi.c | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index 547cdbd..94c92ba 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -1225,7 +1225,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file, struct v4l2_format *f = arg; return cx8800_try_fmt(dev,fh,f); } -#ifdef CONFIG_V4L1_COMPAT +#ifdef CONFIG_VIDEO_V4L1_COMPAT /* --- streaming capture ------------------------------------- */ case VIDIOCGMBUF: { @@ -1584,7 +1584,7 @@ static int radio_do_ioctl(struct inode *inode, struct file *file, *id = 0; return 0; } -#ifdef CONFIG_V4L1_COMPAT +#ifdef CONFIG_VIDEO_V4L1_COMPAT case VIDIOCSTUNER: { struct video_tuner *v = arg; diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index 8656f24..2c171af 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -2087,7 +2087,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file, struct v4l2_format *f = arg; return saa7134_try_fmt(dev,fh,f); } -#ifdef CONFIG_V4L1_COMPAT +#ifdef CONFIG_VIDEO_V4L1_COMPAT case VIDIOCGMBUF: { struct video_mbuf *mbuf = arg; diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c index 2ecbeff..8d972ffd 100644 --- a/drivers/media/video/v4l2-common.c +++ b/drivers/media/video/v4l2-common.c @@ -202,7 +202,7 @@ static char *v4l2_memory_names[] = { /* ------------------------------------------------------------------ */ /* debug help functions */ -#ifdef CONFIG_V4L1_COMPAT +#ifdef CONFIG_VIDEO_V4L1_COMPAT static const char *v4l1_ioctls[] = { [_IOC_NR(VIDIOCGCAP)] = "VIDIOCGCAP", [_IOC_NR(VIDIOCGCHAN)] = "VIDIOCGCHAN", @@ -301,7 +301,7 @@ static const char *v4l2_ioctls[] = { #define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls) static const char *v4l2_int_ioctls[] = { -#ifdef CONFIG_V4L1_COMPAT +#ifdef CONFIG_VIDEO_V4L1_COMPAT [_IOC_NR(DECODER_GET_CAPABILITIES)] = "DECODER_GET_CAPABILITIES", [_IOC_NR(DECODER_GET_STATUS)] = "DECODER_GET_STATUS", [_IOC_NR(DECODER_SET_NORM)] = "DECODER_SET_NORM", @@ -367,7 +367,7 @@ void v4l_printk_ioctl(unsigned int cmd) (_IOC_NR(cmd) < V4L2_INT_IOCTLS) ? v4l2_int_ioctls[_IOC_NR(cmd)] : "UNKNOWN", dir, cmd); break; -#ifdef CONFIG_V4L1_COMPAT +#ifdef CONFIG_VIDEO_V4L1_COMPAT case 'v': printk("v4l1 ioctl %s, dir=%s (0x%08x)\n", (_IOC_NR(cmd) < V4L1_IOCTLS) ? diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c index 0fc90cd..88bf2af 100644 --- a/drivers/media/video/videodev.c +++ b/drivers/media/video/videodev.c @@ -760,7 +760,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, ret=vfd->vidioc_overlay(file, fh, *i); break; } -#ifdef CONFIG_V4L1_COMPAT +#ifdef CONFIG_VIDEO_V4L1_COMPAT /* --- streaming capture ------------------------------------- */ case VIDIOCGMBUF: { diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index 38bd0c1..841884a 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -986,7 +986,7 @@ static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *p) file->f_flags & O_NONBLOCK)); } -#ifdef CONFIG_V4L1_COMPAT +#ifdef CONFIG_VIDEO_V4L1_COMPAT static int vidiocgmbuf (struct file *file, void *priv, struct video_mbuf *mbuf) { struct vivi_fh *fh=priv; @@ -1328,7 +1328,7 @@ static struct video_device vivi = { .vidioc_s_ctrl = vidioc_s_ctrl, .vidioc_streamon = vidioc_streamon, .vidioc_streamoff = vidioc_streamoff, -#ifdef CONFIG_V4L1_COMPAT +#ifdef CONFIG_VIDEO_V4L1_COMPAT .vidiocgmbuf = vidiocgmbuf, #endif .tvnorms = tvnorms, -- cgit v1.1 From 7fb6529762f8185f792ad74adcf211713f973c80 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 8 Aug 2006 15:47:31 -0300 Subject: V4L/DVB (4407): Driver dsbr100 is a radio device, not a video one! Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/Kconfig | 12 +- drivers/media/radio/Makefile | 1 + drivers/media/radio/dsbr100.c | 430 ++++++++++++++++++++++++++++++++++++++++++ drivers/media/video/Kconfig | 12 -- drivers/media/video/Makefile | 1 - drivers/media/video/dsbr100.c | 430 ------------------------------------------ 6 files changed, 442 insertions(+), 444 deletions(-) create mode 100644 drivers/media/radio/dsbr100.c delete mode 100644 drivers/media/video/dsbr100.c (limited to 'drivers') diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig index de3128a..220076b 100644 --- a/drivers/media/radio/Kconfig +++ b/drivers/media/radio/Kconfig @@ -350,5 +350,15 @@ config RADIO_ZOLTRIX_PORT help Enter the I/O port of your Zoltrix radio card. -endmenu +config USB_DSBR + tristate "D-Link USB FM radio support (EXPERIMENTAL)" + depends on USB && VIDEO_V4L1 && EXPERIMENTAL + ---help--- + Say Y here if you want to connect this type of radio to your + computer's USB port. Note that the audio is not digital, and + you must connect the line out connector to a sound card or a + set of speakers. + To compile this driver as a module, choose M here: the + module will be called dsbr100. +endmenu diff --git a/drivers/media/radio/Makefile b/drivers/media/radio/Makefile index e95b680..cf55a18 100644 --- a/drivers/media/radio/Makefile +++ b/drivers/media/radio/Makefile @@ -20,5 +20,6 @@ obj-$(CONFIG_RADIO_GEMTEK) += radio-gemtek.o obj-$(CONFIG_RADIO_GEMTEK_PCI) += radio-gemtek-pci.o obj-$(CONFIG_RADIO_TRUST) += radio-trust.o obj-$(CONFIG_RADIO_MAESTRO) += radio-maestro.o +obj-$(CONFIG_USB_DSBR) += dsbr100.o EXTRA_CFLAGS += -Isound diff --git a/drivers/media/radio/dsbr100.c b/drivers/media/radio/dsbr100.c new file mode 100644 index 0000000..f7e33f9 --- /dev/null +++ b/drivers/media/radio/dsbr100.c @@ -0,0 +1,430 @@ +/* A driver for the D-Link DSB-R100 USB radio. The R100 plugs + into both the USB and an analog audio input, so this thing + only deals with initialisation and frequency setting, the + audio data has to be handled by a sound driver. + + Major issue: I can't find out where the device reports the signal + strength, and indeed the windows software appearantly just looks + at the stereo indicator as well. So, scanning will only find + stereo stations. Sad, but I can't help it. + + Also, the windows program sends oodles of messages over to the + device, and I couldn't figure out their meaning. My suspicion + is that they don't have any:-) + + You might find some interesting stuff about this module at + http://unimut.fsk.uni-heidelberg.de/unimut/demi/dsbr + + Copyright (c) 2000 Markus Demleitner + + 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 + + History: + + Version 0.40: + Markus: Updates for 2.6.x kernels, code layout changes, name sanitizing + + Version 0.30: + Markus: Updates for 2.5.x kernel and more ISO compliant source + + Version 0.25: + PSL and Markus: Cleanup, radio now doesn't stop on device close + + Version 0.24: + Markus: Hope I got these silly VIDEO_TUNER_LOW issues finally + right. Some minor cleanup, improved standalone compilation + + Version 0.23: + Markus: Sign extension bug fixed by declaring transfer_buffer unsigned + + Version 0.22: + Markus: Some (brown bag) cleanup in what VIDIOCSTUNER returns, + thanks to Mike Cox for pointing the problem out. + + Version 0.21: + Markus: Minor cleanup, warnings if something goes wrong, lame attempt + to adhere to Documentation/CodingStyle + + Version 0.2: + Brad Hards : Fixes to make it work as non-module + Markus: Copyright clarification + + Version 0.01: Markus: initial release + +*/ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Version Information + */ +#define DRIVER_VERSION "v0.40" +#define DRIVER_AUTHOR "Markus Demleitner " +#define DRIVER_DESC "D-Link DSB-R100 USB FM radio driver" + +#define DSB100_VENDOR 0x04b4 +#define DSB100_PRODUCT 0x1002 + +/* Commands the device appears to understand */ +#define DSB100_TUNE 1 +#define DSB100_ONOFF 2 + +#define TB_LEN 16 + +/* Frequency limits in MHz -- these are European values. For Japanese +devices, that would be 76 and 91. */ +#define FREQ_MIN 87.5 +#define FREQ_MAX 108.0 +#define FREQ_MUL 16000 + + +static int usb_dsbr100_probe(struct usb_interface *intf, + const struct usb_device_id *id); +static void usb_dsbr100_disconnect(struct usb_interface *intf); +static int usb_dsbr100_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg); +static int usb_dsbr100_open(struct inode *inode, struct file *file); +static int usb_dsbr100_close(struct inode *inode, struct file *file); + +static int radio_nr = -1; +module_param(radio_nr, int, 0); + +/* Data for one (physical) device */ +typedef struct { + struct usb_device *usbdev; + struct video_device *videodev; + unsigned char transfer_buffer[TB_LEN]; + int curfreq; + int stereo; + int users; + int removed; +} dsbr100_device; + + +/* File system interface */ +static struct file_operations usb_dsbr100_fops = { + .owner = THIS_MODULE, + .open = usb_dsbr100_open, + .release = usb_dsbr100_close, + .ioctl = usb_dsbr100_ioctl, + .compat_ioctl = v4l_compat_ioctl32, + .llseek = no_llseek, +}; + +/* V4L interface */ +static struct video_device dsbr100_videodev_template= +{ + .owner = THIS_MODULE, + .name = "D-Link DSB-R 100", + .type = VID_TYPE_TUNER, + .hardware = VID_HARDWARE_AZTECH, + .fops = &usb_dsbr100_fops, + .release = video_device_release, +}; + +static struct usb_device_id usb_dsbr100_device_table [] = { + { USB_DEVICE(DSB100_VENDOR, DSB100_PRODUCT) }, + { } /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE (usb, usb_dsbr100_device_table); + +/* USB subsystem interface */ +static struct usb_driver usb_dsbr100_driver = { + .name = "dsbr100", + .probe = usb_dsbr100_probe, + .disconnect = usb_dsbr100_disconnect, + .id_table = usb_dsbr100_device_table, +}; + +/* Low-level device interface begins here */ + +/* switch on radio */ +static int dsbr100_start(dsbr100_device *radio) +{ + if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), + USB_REQ_GET_STATUS, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, + 0x00, 0xC7, radio->transfer_buffer, 8, 300)<0 || + usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), + DSB100_ONOFF, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, + 0x01, 0x00, radio->transfer_buffer, 8, 300)<0) + return -1; + return (radio->transfer_buffer)[0]; +} + + +/* switch off radio */ +static int dsbr100_stop(dsbr100_device *radio) +{ + if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), + USB_REQ_GET_STATUS, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, + 0x16, 0x1C, radio->transfer_buffer, 8, 300)<0 || + usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), + DSB100_ONOFF, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, + 0x00, 0x00, radio->transfer_buffer, 8, 300)<0) + return -1; + return (radio->transfer_buffer)[0]; +} + +/* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */ +static int dsbr100_setfreq(dsbr100_device *radio, int freq) +{ + freq = (freq/16*80)/1000+856; + if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), + DSB100_TUNE, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, + (freq>>8)&0x00ff, freq&0xff, + radio->transfer_buffer, 8, 300)<0 || + usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), + USB_REQ_GET_STATUS, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, + 0x96, 0xB7, radio->transfer_buffer, 8, 300)<0 || + usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), + USB_REQ_GET_STATUS, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, + 0x00, 0x24, radio->transfer_buffer, 8, 300)<0) { + radio->stereo = -1; + return -1; + } + radio->stereo = ! ((radio->transfer_buffer)[0]&0x01); + return (radio->transfer_buffer)[0]; +} + +/* return the device status. This is, in effect, just whether it +sees a stereo signal or not. Pity. */ +static void dsbr100_getstat(dsbr100_device *radio) +{ + if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), + USB_REQ_GET_STATUS, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, + 0x00 , 0x24, radio->transfer_buffer, 8, 300)<0) + radio->stereo = -1; + else + radio->stereo = ! (radio->transfer_buffer[0]&0x01); +} + + +/* USB subsystem interface begins here */ + +/* check if the device is present and register with v4l and +usb if it is */ +static int usb_dsbr100_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + dsbr100_device *radio; + + if (!(radio = kmalloc(sizeof(dsbr100_device), GFP_KERNEL))) + return -ENOMEM; + if (!(radio->videodev = video_device_alloc())) { + kfree(radio); + return -ENOMEM; + } + memcpy(radio->videodev, &dsbr100_videodev_template, + sizeof(dsbr100_videodev_template)); + radio->removed = 0; + radio->users = 0; + radio->usbdev = interface_to_usbdev(intf); + radio->curfreq = FREQ_MIN*FREQ_MUL; + video_set_drvdata(radio->videodev, radio); + if (video_register_device(radio->videodev, VFL_TYPE_RADIO, + radio_nr)) { + warn("Could not register video device"); + video_device_release(radio->videodev); + kfree(radio); + return -EIO; + } + usb_set_intfdata(intf, radio); + return 0; +} + +/* handle unplugging of the device, release data structures +if nothing keeps us from doing it. If something is still +keeping us busy, the release callback of v4l will take care +of releasing it. stv680.c does not relase its private +data, so I don't do this here either. Checking out the +code I'd expect I better did that, but if there's a memory +leak here it's tiny (~50 bytes per disconnect) */ +static void usb_dsbr100_disconnect(struct usb_interface *intf) +{ + dsbr100_device *radio = usb_get_intfdata(intf); + + usb_set_intfdata (intf, NULL); + if (radio) { + video_unregister_device(radio->videodev); + radio->videodev = NULL; + if (radio->users) { + kfree(radio); + } else { + radio->removed = 1; + } + } +} + + +/* Video for Linux interface */ + +static int usb_dsbr100_do_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, void *arg) +{ + dsbr100_device *radio=video_get_drvdata(video_devdata(file)); + + if (!radio) + return -EIO; + + switch(cmd) { + case VIDIOCGCAP: { + struct video_capability *v = arg; + + memset(v, 0, sizeof(*v)); + v->type = VID_TYPE_TUNER; + v->channels = 1; + v->audios = 1; + strcpy(v->name, "D-Link R-100 USB FM Radio"); + return 0; + } + case VIDIOCGTUNER: { + struct video_tuner *v = arg; + + dsbr100_getstat(radio); + if(v->tuner) /* Only 1 tuner */ + return -EINVAL; + v->rangelow = FREQ_MIN*FREQ_MUL; + v->rangehigh = FREQ_MAX*FREQ_MUL; + v->flags = VIDEO_TUNER_LOW; + v->mode = VIDEO_MODE_AUTO; + v->signal = radio->stereo*0x7000; + /* Don't know how to get signal strength */ + v->flags |= VIDEO_TUNER_STEREO_ON*radio->stereo; + strcpy(v->name, "DSB R-100"); + return 0; + } + case VIDIOCSTUNER: { + struct video_tuner *v = arg; + + if(v->tuner!=0) + return -EINVAL; + /* Only 1 tuner so no setting needed ! */ + return 0; + } + case VIDIOCGFREQ: { + int *freq = arg; + + if (radio->curfreq==-1) + return -EINVAL; + *freq = radio->curfreq; + return 0; + } + case VIDIOCSFREQ: { + int *freq = arg; + + radio->curfreq = *freq; + if (dsbr100_setfreq(radio, radio->curfreq)==-1) + warn("Set frequency failed"); + return 0; + } + case VIDIOCGAUDIO: { + struct video_audio *v = arg; + + memset(v, 0, sizeof(*v)); + v->flags |= VIDEO_AUDIO_MUTABLE; + v->mode = VIDEO_SOUND_STEREO; + v->volume = 1; + v->step = 1; + strcpy(v->name, "Radio"); + return 0; + } + case VIDIOCSAUDIO: { + struct video_audio *v = arg; + + if (v->audio) + return -EINVAL; + if (v->flags&VIDEO_AUDIO_MUTE) { + if (dsbr100_stop(radio)==-1) + warn("Radio did not respond properly"); + } + else + if (dsbr100_start(radio)==-1) + warn("Radio did not respond properly"); + return 0; + } + default: + return -ENOIOCTLCMD; + } +} + +static int usb_dsbr100_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + return video_usercopy(inode, file, cmd, arg, usb_dsbr100_do_ioctl); +} + +static int usb_dsbr100_open(struct inode *inode, struct file *file) +{ + dsbr100_device *radio=video_get_drvdata(video_devdata(file)); + + radio->users = 1; + if (dsbr100_start(radio)<0) { + warn("Radio did not start up properly"); + radio->users = 0; + return -EIO; + } + dsbr100_setfreq(radio, radio->curfreq); + return 0; +} + +static int usb_dsbr100_close(struct inode *inode, struct file *file) +{ + dsbr100_device *radio=video_get_drvdata(video_devdata(file)); + + if (!radio) + return -ENODEV; + radio->users = 0; + if (radio->removed) { + kfree(radio); + } + return 0; +} + +static int __init dsbr100_init(void) +{ + int retval = usb_register(&usb_dsbr100_driver); + info(DRIVER_VERSION ":" DRIVER_DESC); + return retval; +} + +static void __exit dsbr100_exit(void) +{ + usb_deregister(&usb_dsbr100_driver); +} + +module_init (dsbr100_init); +module_exit (dsbr100_exit); + +MODULE_AUTHOR( DRIVER_AUTHOR ); +MODULE_DESCRIPTION( DRIVER_DESC ); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index fe56862..732bf1e 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -449,18 +449,6 @@ source "drivers/media/video/pvrusb2/Kconfig" source "drivers/media/video/em28xx/Kconfig" -config USB_DSBR - tristate "D-Link USB FM radio support (EXPERIMENTAL)" - depends on USB && VIDEO_V4L1 && EXPERIMENTAL - ---help--- - Say Y here if you want to connect this type of radio to your - computer's USB port. Note that the audio is not digital, and - you must connect the line out connector to a sound card or a - set of speakers. - - To compile this driver as a module, choose M here: the - module will be called dsbr100. - source "drivers/media/video/usbvideo/Kconfig" source "drivers/media/video/et61x251/Kconfig" diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 353d61c..010833d 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -77,7 +77,6 @@ obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o obj-$(CONFIG_USB_DABUSB) += dabusb.o -obj-$(CONFIG_USB_DSBR) += dsbr100.o obj-$(CONFIG_USB_OV511) += ov511.o obj-$(CONFIG_USB_SE401) += se401.o obj-$(CONFIG_USB_STV680) += stv680.o diff --git a/drivers/media/video/dsbr100.c b/drivers/media/video/dsbr100.c deleted file mode 100644 index f7e33f9..0000000 --- a/drivers/media/video/dsbr100.c +++ /dev/null @@ -1,430 +0,0 @@ -/* A driver for the D-Link DSB-R100 USB radio. The R100 plugs - into both the USB and an analog audio input, so this thing - only deals with initialisation and frequency setting, the - audio data has to be handled by a sound driver. - - Major issue: I can't find out where the device reports the signal - strength, and indeed the windows software appearantly just looks - at the stereo indicator as well. So, scanning will only find - stereo stations. Sad, but I can't help it. - - Also, the windows program sends oodles of messages over to the - device, and I couldn't figure out their meaning. My suspicion - is that they don't have any:-) - - You might find some interesting stuff about this module at - http://unimut.fsk.uni-heidelberg.de/unimut/demi/dsbr - - Copyright (c) 2000 Markus Demleitner - - 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 - - History: - - Version 0.40: - Markus: Updates for 2.6.x kernels, code layout changes, name sanitizing - - Version 0.30: - Markus: Updates for 2.5.x kernel and more ISO compliant source - - Version 0.25: - PSL and Markus: Cleanup, radio now doesn't stop on device close - - Version 0.24: - Markus: Hope I got these silly VIDEO_TUNER_LOW issues finally - right. Some minor cleanup, improved standalone compilation - - Version 0.23: - Markus: Sign extension bug fixed by declaring transfer_buffer unsigned - - Version 0.22: - Markus: Some (brown bag) cleanup in what VIDIOCSTUNER returns, - thanks to Mike Cox for pointing the problem out. - - Version 0.21: - Markus: Minor cleanup, warnings if something goes wrong, lame attempt - to adhere to Documentation/CodingStyle - - Version 0.2: - Brad Hards : Fixes to make it work as non-module - Markus: Copyright clarification - - Version 0.01: Markus: initial release - -*/ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Version Information - */ -#define DRIVER_VERSION "v0.40" -#define DRIVER_AUTHOR "Markus Demleitner " -#define DRIVER_DESC "D-Link DSB-R100 USB FM radio driver" - -#define DSB100_VENDOR 0x04b4 -#define DSB100_PRODUCT 0x1002 - -/* Commands the device appears to understand */ -#define DSB100_TUNE 1 -#define DSB100_ONOFF 2 - -#define TB_LEN 16 - -/* Frequency limits in MHz -- these are European values. For Japanese -devices, that would be 76 and 91. */ -#define FREQ_MIN 87.5 -#define FREQ_MAX 108.0 -#define FREQ_MUL 16000 - - -static int usb_dsbr100_probe(struct usb_interface *intf, - const struct usb_device_id *id); -static void usb_dsbr100_disconnect(struct usb_interface *intf); -static int usb_dsbr100_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg); -static int usb_dsbr100_open(struct inode *inode, struct file *file); -static int usb_dsbr100_close(struct inode *inode, struct file *file); - -static int radio_nr = -1; -module_param(radio_nr, int, 0); - -/* Data for one (physical) device */ -typedef struct { - struct usb_device *usbdev; - struct video_device *videodev; - unsigned char transfer_buffer[TB_LEN]; - int curfreq; - int stereo; - int users; - int removed; -} dsbr100_device; - - -/* File system interface */ -static struct file_operations usb_dsbr100_fops = { - .owner = THIS_MODULE, - .open = usb_dsbr100_open, - .release = usb_dsbr100_close, - .ioctl = usb_dsbr100_ioctl, - .compat_ioctl = v4l_compat_ioctl32, - .llseek = no_llseek, -}; - -/* V4L interface */ -static struct video_device dsbr100_videodev_template= -{ - .owner = THIS_MODULE, - .name = "D-Link DSB-R 100", - .type = VID_TYPE_TUNER, - .hardware = VID_HARDWARE_AZTECH, - .fops = &usb_dsbr100_fops, - .release = video_device_release, -}; - -static struct usb_device_id usb_dsbr100_device_table [] = { - { USB_DEVICE(DSB100_VENDOR, DSB100_PRODUCT) }, - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE (usb, usb_dsbr100_device_table); - -/* USB subsystem interface */ -static struct usb_driver usb_dsbr100_driver = { - .name = "dsbr100", - .probe = usb_dsbr100_probe, - .disconnect = usb_dsbr100_disconnect, - .id_table = usb_dsbr100_device_table, -}; - -/* Low-level device interface begins here */ - -/* switch on radio */ -static int dsbr100_start(dsbr100_device *radio) -{ - if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), - USB_REQ_GET_STATUS, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, - 0x00, 0xC7, radio->transfer_buffer, 8, 300)<0 || - usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), - DSB100_ONOFF, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, - 0x01, 0x00, radio->transfer_buffer, 8, 300)<0) - return -1; - return (radio->transfer_buffer)[0]; -} - - -/* switch off radio */ -static int dsbr100_stop(dsbr100_device *radio) -{ - if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), - USB_REQ_GET_STATUS, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, - 0x16, 0x1C, radio->transfer_buffer, 8, 300)<0 || - usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), - DSB100_ONOFF, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, - 0x00, 0x00, radio->transfer_buffer, 8, 300)<0) - return -1; - return (radio->transfer_buffer)[0]; -} - -/* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */ -static int dsbr100_setfreq(dsbr100_device *radio, int freq) -{ - freq = (freq/16*80)/1000+856; - if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), - DSB100_TUNE, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, - (freq>>8)&0x00ff, freq&0xff, - radio->transfer_buffer, 8, 300)<0 || - usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), - USB_REQ_GET_STATUS, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, - 0x96, 0xB7, radio->transfer_buffer, 8, 300)<0 || - usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), - USB_REQ_GET_STATUS, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, - 0x00, 0x24, radio->transfer_buffer, 8, 300)<0) { - radio->stereo = -1; - return -1; - } - radio->stereo = ! ((radio->transfer_buffer)[0]&0x01); - return (radio->transfer_buffer)[0]; -} - -/* return the device status. This is, in effect, just whether it -sees a stereo signal or not. Pity. */ -static void dsbr100_getstat(dsbr100_device *radio) -{ - if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), - USB_REQ_GET_STATUS, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, - 0x00 , 0x24, radio->transfer_buffer, 8, 300)<0) - radio->stereo = -1; - else - radio->stereo = ! (radio->transfer_buffer[0]&0x01); -} - - -/* USB subsystem interface begins here */ - -/* check if the device is present and register with v4l and -usb if it is */ -static int usb_dsbr100_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - dsbr100_device *radio; - - if (!(radio = kmalloc(sizeof(dsbr100_device), GFP_KERNEL))) - return -ENOMEM; - if (!(radio->videodev = video_device_alloc())) { - kfree(radio); - return -ENOMEM; - } - memcpy(radio->videodev, &dsbr100_videodev_template, - sizeof(dsbr100_videodev_template)); - radio->removed = 0; - radio->users = 0; - radio->usbdev = interface_to_usbdev(intf); - radio->curfreq = FREQ_MIN*FREQ_MUL; - video_set_drvdata(radio->videodev, radio); - if (video_register_device(radio->videodev, VFL_TYPE_RADIO, - radio_nr)) { - warn("Could not register video device"); - video_device_release(radio->videodev); - kfree(radio); - return -EIO; - } - usb_set_intfdata(intf, radio); - return 0; -} - -/* handle unplugging of the device, release data structures -if nothing keeps us from doing it. If something is still -keeping us busy, the release callback of v4l will take care -of releasing it. stv680.c does not relase its private -data, so I don't do this here either. Checking out the -code I'd expect I better did that, but if there's a memory -leak here it's tiny (~50 bytes per disconnect) */ -static void usb_dsbr100_disconnect(struct usb_interface *intf) -{ - dsbr100_device *radio = usb_get_intfdata(intf); - - usb_set_intfdata (intf, NULL); - if (radio) { - video_unregister_device(radio->videodev); - radio->videodev = NULL; - if (radio->users) { - kfree(radio); - } else { - radio->removed = 1; - } - } -} - - -/* Video for Linux interface */ - -static int usb_dsbr100_do_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, void *arg) -{ - dsbr100_device *radio=video_get_drvdata(video_devdata(file)); - - if (!radio) - return -EIO; - - switch(cmd) { - case VIDIOCGCAP: { - struct video_capability *v = arg; - - memset(v, 0, sizeof(*v)); - v->type = VID_TYPE_TUNER; - v->channels = 1; - v->audios = 1; - strcpy(v->name, "D-Link R-100 USB FM Radio"); - return 0; - } - case VIDIOCGTUNER: { - struct video_tuner *v = arg; - - dsbr100_getstat(radio); - if(v->tuner) /* Only 1 tuner */ - return -EINVAL; - v->rangelow = FREQ_MIN*FREQ_MUL; - v->rangehigh = FREQ_MAX*FREQ_MUL; - v->flags = VIDEO_TUNER_LOW; - v->mode = VIDEO_MODE_AUTO; - v->signal = radio->stereo*0x7000; - /* Don't know how to get signal strength */ - v->flags |= VIDEO_TUNER_STEREO_ON*radio->stereo; - strcpy(v->name, "DSB R-100"); - return 0; - } - case VIDIOCSTUNER: { - struct video_tuner *v = arg; - - if(v->tuner!=0) - return -EINVAL; - /* Only 1 tuner so no setting needed ! */ - return 0; - } - case VIDIOCGFREQ: { - int *freq = arg; - - if (radio->curfreq==-1) - return -EINVAL; - *freq = radio->curfreq; - return 0; - } - case VIDIOCSFREQ: { - int *freq = arg; - - radio->curfreq = *freq; - if (dsbr100_setfreq(radio, radio->curfreq)==-1) - warn("Set frequency failed"); - return 0; - } - case VIDIOCGAUDIO: { - struct video_audio *v = arg; - - memset(v, 0, sizeof(*v)); - v->flags |= VIDEO_AUDIO_MUTABLE; - v->mode = VIDEO_SOUND_STEREO; - v->volume = 1; - v->step = 1; - strcpy(v->name, "Radio"); - return 0; - } - case VIDIOCSAUDIO: { - struct video_audio *v = arg; - - if (v->audio) - return -EINVAL; - if (v->flags&VIDEO_AUDIO_MUTE) { - if (dsbr100_stop(radio)==-1) - warn("Radio did not respond properly"); - } - else - if (dsbr100_start(radio)==-1) - warn("Radio did not respond properly"); - return 0; - } - default: - return -ENOIOCTLCMD; - } -} - -static int usb_dsbr100_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - return video_usercopy(inode, file, cmd, arg, usb_dsbr100_do_ioctl); -} - -static int usb_dsbr100_open(struct inode *inode, struct file *file) -{ - dsbr100_device *radio=video_get_drvdata(video_devdata(file)); - - radio->users = 1; - if (dsbr100_start(radio)<0) { - warn("Radio did not start up properly"); - radio->users = 0; - return -EIO; - } - dsbr100_setfreq(radio, radio->curfreq); - return 0; -} - -static int usb_dsbr100_close(struct inode *inode, struct file *file) -{ - dsbr100_device *radio=video_get_drvdata(video_devdata(file)); - - if (!radio) - return -ENODEV; - radio->users = 0; - if (radio->removed) { - kfree(radio); - } - return 0; -} - -static int __init dsbr100_init(void) -{ - int retval = usb_register(&usb_dsbr100_driver); - info(DRIVER_VERSION ":" DRIVER_DESC); - return retval; -} - -static void __exit dsbr100_exit(void) -{ - usb_deregister(&usb_dsbr100_driver); -} - -module_init (dsbr100_init); -module_exit (dsbr100_exit); - -MODULE_AUTHOR( DRIVER_AUTHOR ); -MODULE_DESCRIPTION( DRIVER_DESC ); -MODULE_LICENSE("GPL"); -- cgit v1.1 From b02dc515914bc37f5e406cc6f622fc06991eb779 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Tue, 8 Aug 2006 09:10:12 -0300 Subject: V4L/DVB (4411): Fix minor errors in build files In pwc Kconfig, change 'depends' to 'depends on' In dvb-core Makefile, change '=' to ':=' Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/Makefile | 6 +++--- drivers/media/video/pwc/Kconfig | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-core/Makefile b/drivers/media/dvb/dvb-core/Makefile index 1105465..0b51828 100644 --- a/drivers/media/dvb/dvb-core/Makefile +++ b/drivers/media/dvb/dvb-core/Makefile @@ -2,8 +2,8 @@ # Makefile for the kernel DVB device drivers. # -dvb-core-objs = dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o \ - dvb_ca_en50221.o dvb_frontend.o \ - dvb_net.o dvb_ringbuffer.o dvb_math.o +dvb-core-objs := dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o \ + dvb_ca_en50221.o dvb_frontend.o \ + dvb_net.o dvb_ringbuffer.o dvb_math.o obj-$(CONFIG_DVB_CORE) += dvb-core.o diff --git a/drivers/media/video/pwc/Kconfig b/drivers/media/video/pwc/Kconfig index 697145e..8fdf710 100644 --- a/drivers/media/video/pwc/Kconfig +++ b/drivers/media/video/pwc/Kconfig @@ -30,7 +30,7 @@ config USB_PWC config USB_PWC_DEBUG bool "USB Philips Cameras verbose debug" - depends USB_PWC + depends on USB_PWC help Say Y here in order to have the pwc driver generate verbose debugging messages. -- cgit v1.1 From 17531c168c7b8138b5379a85de788798fc6696e1 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 8 Aug 2006 09:10:12 -0300 Subject: V4L/DVB (4416): Cx25840_read4 has wrong endianness. cx25840_read4 assembled the bytes in the wrong order. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx25840/cx25840-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index 5c2036b..7bb7589 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -104,8 +104,8 @@ u32 cx25840_read4(struct i2c_client * client, u16 addr) if (i2c_master_recv(client, buffer, 4) < 4) return 0; - return (buffer[0] << 24) | (buffer[1] << 16) | - (buffer[2] << 8) | buffer[3]; + return (buffer[3] << 24) | (buffer[2] << 16) | + (buffer[1] << 8) | buffer[0]; } int cx25840_and_or(struct i2c_client *client, u16 addr, unsigned and_mask, -- cgit v1.1 From e335fada5afef0658038b6bec432d37f332da9fc Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 8 Aug 2006 09:10:15 -0300 Subject: V4L/DVB (4418): Fix broken msp3400 module option 'standard' Due to a wrong statement order the 'standard' module option didn't work for 'G' model chips. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/msp3400-kthreads.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/msp3400-kthreads.c b/drivers/media/video/msp3400-kthreads.c index f2fd919..ed02ff8 100644 --- a/drivers/media/video/msp3400-kthreads.c +++ b/drivers/media/video/msp3400-kthreads.c @@ -961,10 +961,10 @@ int msp34xxg_thread(void *data) /* setup the chip*/ msp34xxg_reset(client); state->std = state->radio ? 0x40 : msp_standard; - if (state->std != 1) - goto unmute; /* start autodetect */ msp_write_dem(client, 0x20, state->std); + if (state->std != 1) + goto unmute; /* watch autodetect */ v4l_dbg(1, msp_debug, client, "started autodetect, waiting for result\n"); -- cgit v1.1 From 43c560fa59ef2688d891f6431e972b7763b73a00 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 8 Aug 2006 09:10:15 -0300 Subject: V4L/DVB (4419): Turn on the Low Noise Amplifier of the Samsung tuners. Without the LNA these tuners perform very poorly (read 'unwatchable') when the signal is weak. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-types.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/tuner-types.c b/drivers/media/video/tuner-types.c index a167e17..d7eadc2 100644 --- a/drivers/media/video/tuner-types.c +++ b/drivers/media/video/tuner-types.c @@ -1027,10 +1027,11 @@ static struct tuner_params tuner_tnf_5335mf_params[] = { /* 70-79 */ /* ------------ TUNER_SAMSUNG_TCPN_2121P30A - Samsung NTSC ------------ */ +/* '+ 4' turns on the Low Noise Amplifier */ static struct tuner_range tuner_samsung_tcpn_2121p30a_ntsc_ranges[] = { - { 16 * 130.00 /*MHz*/, 0xce, 0x01, }, - { 16 * 364.50 /*MHz*/, 0xce, 0x02, }, - { 16 * 999.99 , 0xce, 0x08, }, + { 16 * 130.00 /*MHz*/, 0xce, 0x01 + 4, }, + { 16 * 364.50 /*MHz*/, 0xce, 0x02 + 4, }, + { 16 * 999.99 , 0xce, 0x08 + 4, }, }; static struct tuner_params tuner_samsung_tcpn_2121p30a_params[] = { @@ -1060,10 +1061,11 @@ static struct tuner_params tuner_thomson_fe6600_params[] = { /* ------------ TUNER_SAMSUNG_TCPG_6121P30A - Samsung PAL ------------ */ +/* '+ 4' turns on the Low Noise Amplifier */ static struct tuner_range tuner_samsung_tcpg_6121p30a_pal_ranges[] = { - { 16 * 146.25 /*MHz*/, 0xce, 0x01, }, - { 16 * 428.50 /*MHz*/, 0xce, 0x02, }, - { 16 * 999.99 , 0xce, 0x08, }, + { 16 * 146.25 /*MHz*/, 0xce, 0x01 + 4, }, + { 16 * 428.50 /*MHz*/, 0xce, 0x02 + 4, }, + { 16 * 999.99 , 0xce, 0x08 + 4, }, }; static struct tuner_params tuner_samsung_tcpg_6121p30a_params[] = { -- cgit v1.1 From 8a016dcc8383bedc731bca9fdedae77ff52a6ad7 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 8 Aug 2006 09:10:16 -0300 Subject: V4L/DVB (4427): Fix V4L1 Compat for VIDIOCGPICT ioctl Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l1-compat.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/v4l1-compat.c b/drivers/media/video/v4l1-compat.c index d83a2c8..d7c3fcb 100644 --- a/drivers/media/video/v4l1-compat.c +++ b/drivers/media/video/v4l1-compat.c @@ -599,6 +599,10 @@ v4l_compat_translate_ioctl(struct inode *inode, dprintk("VIDIOCGPICT / VIDIOC_G_FMT: %d\n",err); break; } + + pict->depth = ((fmt2->fmt.pix.bytesperline<<3) + + (fmt2->fmt.pix.width-1) ) + /fmt2->fmt.pix.width; pict->palette = pixelformat_to_palette( fmt2->fmt.pix.pixelformat); break; -- cgit v1.1 From eafa98177a388700d613c187c7716e11869b7171 Mon Sep 17 00:00:00 2001 From: Diego Calleja Date: Tue, 8 Aug 2006 09:10:17 -0300 Subject: V4L/DVB (4430): Quickcam_messenger compilation fix In bugzilla #6943, Maxim Britov reported: "I can enable Logitech quickcam support in .config, but it want be compile. I have to add into drivers/media/video/Makefile: obj-$(CONFIG_USB_QUICKCAM_MESSENGER) += usbvideo/" He's right, just enable that driver as module while disabling every other driver that gets into that directory, nothing will get compiled. This patch fixes the Makefile. Signed-off-by: Diego Calleja Acked-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Makefile | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 010833d..e82e511 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -90,6 +90,7 @@ obj-$(CONFIG_USB_ZC0301) += zc0301/ obj-$(CONFIG_USB_IBMCAM) += usbvideo/ obj-$(CONFIG_USB_KONICAWC) += usbvideo/ obj-$(CONFIG_USB_VICAM) += usbvideo/ +obj-$(CONFIG_USB_QUICKCAM_MESSENGER) += usbvideo/ obj-$(CONFIG_VIDEO_VIVI) += vivi.o -- cgit v1.1 From 0851fb48486c044476b019029245cb9b348fca33 Mon Sep 17 00:00:00 2001 From: Yeasah Pell Date: Tue, 8 Aug 2006 09:10:18 -0300 Subject: V4L/DVB (4431): Add several error checks to dst Signed-off-by: Yeasah Pell Signed-off-by: Manu Abraham Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/bt8xx/dst.c | 58 ++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c index d687a14..06ac899 100644 --- a/drivers/media/dvb/bt8xx/dst.c +++ b/drivers/media/dvb/bt8xx/dst.c @@ -393,7 +393,7 @@ static int dst_set_bandwidth(struct dst_state *state, fe_bandwidth_t bandwidth) state->bandwidth = bandwidth; if (state->dst_type != DST_TYPE_IS_TERR) - return 0; + return -EOPNOTSUPP; switch (bandwidth) { case BANDWIDTH_6_MHZ: @@ -462,7 +462,7 @@ static int dst_set_symbolrate(struct dst_state *state, u32 srate) state->symbol_rate = srate; if (state->dst_type == DST_TYPE_IS_TERR) { - return 0; + return -EOPNOTSUPP; } dprintk(verbose, DST_INFO, 1, "set symrate %u", srate); srate /= 1000; @@ -504,7 +504,7 @@ static int dst_set_symbolrate(struct dst_state *state, u32 srate) static int dst_set_modulation(struct dst_state *state, fe_modulation_t modulation) { if (state->dst_type != DST_TYPE_IS_CABLE) - return 0; + return -EOPNOTSUPP; state->modulation = modulation; switch (modulation) { @@ -1234,7 +1234,7 @@ int dst_command(struct dst_state *state, u8 *data, u8 len) goto error; } if (write_dst(state, data, len)) { - dprintk(verbose, DST_INFO, 1, "Tring to recover.. "); + dprintk(verbose, DST_INFO, 1, "Trying to recover.. "); if ((dst_error_recovery(state)) < 0) { dprintk(verbose, DST_ERROR, 1, "Recovery Failed."); goto error; @@ -1328,15 +1328,13 @@ static int dst_tone_power_cmd(struct dst_state *state) { u8 paket[8] = { 0x00, 0x09, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00 }; - if (state->dst_type == DST_TYPE_IS_TERR) - return 0; + if (state->dst_type != DST_TYPE_IS_SAT) + return -EOPNOTSUPP; paket[4] = state->tx_tuna[4]; paket[2] = state->tx_tuna[2]; paket[3] = state->tx_tuna[3]; paket[7] = dst_check_sum (paket, 7); - dst_command(state, paket, 8); - - return 0; + return dst_command(state, paket, 8); } static int dst_get_tuna(struct dst_state *state) @@ -1465,7 +1463,7 @@ static int dst_set_diseqc(struct dvb_frontend *fe, struct dvb_diseqc_master_cmd u8 paket[8] = { 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf0, 0xec }; if (state->dst_type != DST_TYPE_IS_SAT) - return 0; + return -EOPNOTSUPP; if (cmd->msg_len > 0 && cmd->msg_len < 5) memcpy(&paket[3], cmd->msg, cmd->msg_len); else if (cmd->msg_len == 5 && state->dst_hw_cap & DST_TYPE_HAS_DISEQC5) @@ -1473,18 +1471,17 @@ static int dst_set_diseqc(struct dvb_frontend *fe, struct dvb_diseqc_master_cmd else return -EINVAL; paket[7] = dst_check_sum(&paket[0], 7); - dst_command(state, paket, 8); - return 0; + return dst_command(state, paket, 8); } static int dst_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) { - int need_cmd; + int need_cmd, retval = 0; struct dst_state *state = fe->demodulator_priv; state->voltage = voltage; if (state->dst_type != DST_TYPE_IS_SAT) - return 0; + return -EOPNOTSUPP; need_cmd = 0; @@ -1506,9 +1503,9 @@ static int dst_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) } if (need_cmd) - dst_tone_power_cmd(state); + retval = dst_tone_power_cmd(state); - return 0; + return retval; } static int dst_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) @@ -1517,7 +1514,7 @@ static int dst_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) state->tone = tone; if (state->dst_type != DST_TYPE_IS_SAT) - return 0; + return -EOPNOTSUPP; switch (tone) { case SEC_TONE_OFF: @@ -1533,9 +1530,7 @@ static int dst_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) default: return -EINVAL; } - dst_tone_power_cmd(state); - - return 0; + return dst_tone_power_cmd(state); } static int dst_send_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t minicmd) @@ -1543,7 +1538,7 @@ static int dst_send_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t minicmd) struct dst_state *state = fe->demodulator_priv; if (state->dst_type != DST_TYPE_IS_SAT) - return 0; + return -EOPNOTSUPP; state->minicmd = minicmd; switch (minicmd) { case SEC_MINI_A: @@ -1553,9 +1548,7 @@ static int dst_send_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t minicmd) state->tx_tuna[3] = 0xff; break; } - dst_tone_power_cmd(state); - - return 0; + return dst_tone_power_cmd(state); } @@ -1608,28 +1601,31 @@ static int dst_read_signal_strength(struct dvb_frontend *fe, u16 *strength) { struct dst_state *state = fe->demodulator_priv; - dst_get_signal(state); + int retval = dst_get_signal(state); *strength = state->decode_strength; - return 0; + return retval; } static int dst_read_snr(struct dvb_frontend *fe, u16 *snr) { struct dst_state *state = fe->demodulator_priv; - dst_get_signal(state); + int retval = dst_get_signal(state); *snr = state->decode_snr; - return 0; + return retval; } static int dst_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) { + int retval = -EINVAL; struct dst_state *state = fe->demodulator_priv; if (p != NULL) { - dst_set_freq(state, p->frequency); + retval = dst_set_freq(state, p->frequency); + if(retval != 0) + return retval; dprintk(verbose, DST_DEBUG, 1, "Set Frequency=[%d]", p->frequency); if (state->dst_type == DST_TYPE_IS_SAT) { @@ -1647,10 +1643,10 @@ static int dst_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_paramet dst_set_symbolrate(state, p->u.qam.symbol_rate); dst_set_modulation(state, p->u.qam.modulation); } - dst_write_tuna(fe); + retval = dst_write_tuna(fe); } - return 0; + return retval; } static int dst_tune_frontend(struct dvb_frontend* fe, -- cgit v1.1 From 013b68bf7cb4edfb8753aac9bde3cb60c84bc067 Mon Sep 17 00:00:00 2001 From: Brice Goglin Date: Wed, 9 Aug 2006 00:07:53 -0400 Subject: [PATCH] myri10ge: always re-enable dummy rdmas in myri10ge_resume Dummy RDMA are always enabled on device startup since commit 9a71db721a2cbb9921b929b2699ab181f5a3c6c0 (to work around buggy PCIe chipsets which do not implement resending properly). But, we also need to always re-enable them when resuming the device. Signed-off-by: Brice Goglin Signed-off-by: Jeff Garzik --- drivers/net/myri10ge/myri10ge.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index 06440a8..9bdd43a 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -2425,7 +2425,7 @@ static int myri10ge_resume(struct pci_dev *pdev) } myri10ge_reset(mgp); - myri10ge_dummy_rdma(mgp, mgp->tx.boundary != 4096); + myri10ge_dummy_rdma(mgp, 1); /* Save configuration space to be restored if the * nic resets due to a parity error */ -- cgit v1.1 From 85455dd34219376dcc7dce94bea67058f0b7d731 Mon Sep 17 00:00:00 2001 From: Keith Owens Date: Tue, 8 Aug 2006 13:51:02 +1000 Subject: [PATCH] Fix compile problem when sata debugging is on Fix a sata debug print statement that still uses an old variable name. Signed-off-by: Keith Owens Signed-off-by: Jeff Garzik --- drivers/scsi/ata_piix.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c index 298e464..5e8afc8 100644 --- a/drivers/scsi/ata_piix.c +++ b/drivers/scsi/ata_piix.c @@ -567,8 +567,8 @@ static int piix_sata_prereset(struct ata_port *ap) present = 1; } - DPRINTK("ata%u: LEAVE, pcs=0x%x present_mask=0x%x\n", - ap->id, pcs, present_mask); + DPRINTK("ata%u: LEAVE, pcs=0x%x present=0x%x\n", + ap->id, pcs, present); if (!present) { ata_port_printk(ap, KERN_INFO, "SATA port has no device.\n"); -- cgit v1.1 From 22aac0896b1b0b8cabaf00714c55dd12f25d5738 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 8 Aug 2006 14:08:59 +0900 Subject: [PATCH] libata: clear sdev->locked on door lock failure SCSI EH locks door if sdev->locked is set. Sometimes door lock command fails continuously (e.g. when medium is not present) and as libata uses EH to acquire sense data, this easily creates a loop where a failed lock door invokes EH and EH issues lock door on completion. This patch clears sdev->locked on door lock failure to break this loop. This problem has been spotted and diagnosed by Unicorn Chang . Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/scsi/libata-scsi.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index 7ced41e..e92c31d 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -2353,6 +2353,19 @@ static void atapi_qc_complete(struct ata_queued_cmd *qc) ata_gen_ata_desc_sense(qc); } + /* SCSI EH automatically locks door if sdev->locked is + * set. Sometimes door lock request continues to + * fail, for example, when no media is present. This + * creates a loop - SCSI EH issues door lock which + * fails and gets invoked again to acquire sense data + * for the failed command. + * + * If door lock fails, always clear sdev->locked to + * avoid this infinite loop. + */ + if (qc->cdb[0] == ALLOW_MEDIUM_REMOVAL) + qc->dev->sdev->locked = 0; + qc->scsicmd->result = SAM_STAT_CHECK_CONDITION; qc->scsidone(cmd); ata_qc_free(qc); -- cgit v1.1 From ebc4599990898ecaaace7ed40dfad6d8d9f2a24a Mon Sep 17 00:00:00 2001 From: Horst Hummel Date: Wed, 9 Aug 2006 10:30:22 +0200 Subject: [S390] dasd set offline kernel bug. The request queue flush function of the dasd driver has to dequeue the requests first and then call the end request function. Otherwise a kernel bug in ll_rw_block.c might get triggered. Signed-off-by: Horst Hummel Signed-off-by: Martin Schwidefsky --- drivers/s390/block/dasd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 4bf03fb..d8e9b95 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -1730,8 +1730,8 @@ dasd_flush_request_queue(struct dasd_device * device) req = elv_next_request(device->request_queue); if (req == NULL) break; - dasd_end_request(req, 0); blkdev_dequeue_request(req); + dasd_end_request(req, 0); } spin_unlock_irq(&device->request_queue_lock); } -- cgit v1.1 From 79860a9a79a17f1bed0713680a3995467405ba49 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 9 Aug 2006 15:04:58 +0100 Subject: [PATCH] PATCH: 2.6.18 oops on boot fix for IDE When the IDE fix for Jmicron went in one piece went walking somewhere (send log shows my end somehow). Without this sometimes you get an oops on boot. Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/ide/pci/generic.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'drivers') diff --git a/drivers/ide/pci/generic.c b/drivers/ide/pci/generic.c index 2f962cf..78810ba 100644 --- a/drivers/ide/pci/generic.c +++ b/drivers/ide/pci/generic.c @@ -180,6 +180,36 @@ static ide_pci_device_t generic_chipsets[] __devinitdata = { .channels = 2, .autodma = AUTODMA, .bootable = OFF_BOARD, + },{ /* 15 */ + .name = "JMB361", + .init_hwif = init_hwif_generic, + .channels = 2, + .autodma = AUTODMA, + .bootable = OFF_BOARD, + },{ /* 16 */ + .name = "JMB363", + .init_hwif = init_hwif_generic, + .channels = 2, + .autodma = AUTODMA, + .bootable = OFF_BOARD, + },{ /* 17 */ + .name = "JMB365", + .init_hwif = init_hwif_generic, + .channels = 2, + .autodma = AUTODMA, + .bootable = OFF_BOARD, + },{ /* 18 */ + .name = "JMB366", + .init_hwif = init_hwif_generic, + .channels = 2, + .autodma = AUTODMA, + .bootable = OFF_BOARD, + },{ /* 19 */ + .name = "JMB368", + .init_hwif = init_hwif_generic, + .channels = 2, + .autodma = AUTODMA, + .bootable = OFF_BOARD, } }; -- cgit v1.1 From 51704c609fcf256dacfcfae3622eb6ef53ac5b48 Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Wed, 9 Aug 2006 18:36:22 +0800 Subject: [PATCH] libata: Use ATA_FLAG_PIO_POLLING for pdc_adma pdc_adma was overlooked and broken by the irq-pio patch: Only HSM_ST_LAST interrupts should be delivered to this LLDD. Adding ATA_FLAG_PIO_POLLING to pdc_adma fixes the problem (temporarily), before we convert the irq handler of pdc_adma to handle all interrupts. Signed-off-by: Albert Lee Signed-off-by: Jeff Garzik --- drivers/scsi/pdc_adma.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/pdc_adma.c b/drivers/scsi/pdc_adma.c index d1f38c3..efc8fff 100644 --- a/drivers/scsi/pdc_adma.c +++ b/drivers/scsi/pdc_adma.c @@ -183,7 +183,8 @@ static struct ata_port_info adma_port_info[] = { { .sht = &adma_ata_sht, .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST | - ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO, + ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO | + ATA_FLAG_PIO_POLLING, .pio_mask = 0x10, /* pio4 */ .udma_mask = 0x1f, /* udma0-4 */ .port_ops = &adma_ata_ops, -- cgit v1.1 From a34b6fc04d58ad72fe0cc74cd448f4551bd2ebaf Mon Sep 17 00:00:00 2001 From: Martin Hicks Date: Wed, 5 Jul 2006 15:06:13 -0400 Subject: [PATCH] libata: PHY reset requires writing 0x4 to SControl Hi, Reading the Intel VSC and AHCI it seems like writing 0x302 is incorrect. The only valid values are 4, 1 and 0. Writing 4 disables the PHY. Signed-off-by: Martin Hicks Signed-off-by: Jeff Garzik --- drivers/scsi/libata-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 16fc2dd..73dd6c8 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -2746,7 +2746,7 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class) if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol))) return rc; - scontrol = (scontrol & 0x0f0) | 0x302; + scontrol = (scontrol & 0x0f0) | 0x304; if ((rc = sata_scr_write(ap, SCR_CONTROL, scontrol))) return rc; -- cgit v1.1 From 8d3d35b4e20dc2e678fc7cb51165905b5a32fb76 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 9 Aug 2006 14:14:50 -0700 Subject: [PATCH] sky2: phy power problems on 88e805X chips On the 88E805X chipsets (used in laptops), the PHY was not getting powered out of shutdown properly. The variable reg1 was getting reused incorrectly. This is probably the cause of the bug. http://bugzilla.kernel.org/show_bug.cgi?id=6471 Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/sky2.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index de91609..933e87f 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -233,6 +233,8 @@ static void sky2_set_power_state(struct sky2_hw *hw, pci_power_t state) if (hw->ports > 1) reg1 |= PCI_Y2_PHY2_COMA; } + sky2_pci_write32(hw, PCI_DEV_REG1, reg1); + udelay(100); if (hw->chip_id == CHIP_ID_YUKON_EC_U) { sky2_pci_write32(hw, PCI_DEV_REG3, 0); @@ -242,9 +244,6 @@ static void sky2_set_power_state(struct sky2_hw *hw, pci_power_t state) sky2_pci_write32(hw, PCI_DEV_REG5, 0); } - sky2_pci_write32(hw, PCI_DEV_REG1, reg1); - udelay(100); - break; case PCI_D3hot: -- cgit v1.1 From d0710c7c9eea2145a0614f39dbe9dc8cb4ae14da Mon Sep 17 00:00:00 2001 From: Horst Hummel Date: Thu, 10 Aug 2006 15:45:16 +0200 Subject: [S390] dasd calls kzalloc while holding a spinlock. The dasd function dasd_set_uid calls kzalloc while holding the dasd_devmap_lock. Rearrange the code to do the memory allocation outside the lock. Signed-off-by: Horst Hummel Signed-off-by: Martin Schwidefsky --- drivers/s390/block/dasd_devmap.c | 65 +++++++++++++++++----------------------- drivers/s390/block/dasd_eckd.c | 8 ++--- 2 files changed, 32 insertions(+), 41 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index 7f6fdac..6fcb28d 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c @@ -89,7 +89,7 @@ static char *dasd[256]; module_param_array(dasd, charp, NULL, 0); /* - * Single spinlock to protect devmap structures and lists. + * Single spinlock to protect devmap and servermap structures and lists. */ static DEFINE_SPINLOCK(dasd_devmap_lock); @@ -859,39 +859,6 @@ static struct attribute_group dasd_attr_group = { }; /* - * Check if the related storage server is already contained in the - * dasd_serverlist. If server is not contained, create new entry. - * Return 0 if server was already in serverlist, - * 1 if the server was added successfully - * <0 in case of error. - */ -static int -dasd_add_server(struct dasd_uid *uid) -{ - struct dasd_servermap *new, *tmp; - - /* check if server is already contained */ - list_for_each_entry(tmp, &dasd_serverlist, list) - // normale cmp? - if (strncmp(tmp->sid.vendor, uid->vendor, - sizeof(tmp->sid.vendor)) == 0 - && strncmp(tmp->sid.serial, uid->serial, - sizeof(tmp->sid.serial)) == 0) - return 0; - - new = (struct dasd_servermap *) - kzalloc(sizeof(struct dasd_servermap), GFP_KERNEL); - if (!new) - return -ENOMEM; - - strncpy(new->sid.vendor, uid->vendor, sizeof(new->sid.vendor)); - strncpy(new->sid.serial, uid->serial, sizeof(new->sid.serial)); - list_add(&new->list, &dasd_serverlist); - return 1; -} - - -/* * Return copy of the device unique identifier. */ int @@ -910,6 +877,8 @@ dasd_get_uid(struct ccw_device *cdev, struct dasd_uid *uid) /* * Register the given device unique identifier into devmap struct. + * In addition check if the related storage server is already contained in the + * dasd_serverlist. If server is not contained, create new entry. * Return 0 if server was already in serverlist, * 1 if the server was added successful * <0 in case of error. @@ -918,16 +887,38 @@ int dasd_set_uid(struct ccw_device *cdev, struct dasd_uid *uid) { struct dasd_devmap *devmap; - int rc; + struct dasd_servermap *srv, *tmp; devmap = dasd_find_busid(cdev->dev.bus_id); if (IS_ERR(devmap)) return PTR_ERR(devmap); + + /* generate entry for servermap */ + srv = (struct dasd_servermap *) + kzalloc(sizeof(struct dasd_servermap), GFP_KERNEL); + if (!srv) + return -ENOMEM; + strncpy(srv->sid.vendor, uid->vendor, sizeof(srv->sid.vendor) - 1); + strncpy(srv->sid.serial, uid->serial, sizeof(srv->sid.serial) - 1); + + /* server is already contained ? */ spin_lock(&dasd_devmap_lock); devmap->uid = *uid; - rc = dasd_add_server(uid); + list_for_each_entry(tmp, &dasd_serverlist, list) { + if (!memcmp(&srv->sid, &tmp->sid, + sizeof(struct dasd_servermap))) { + kfree(srv); + srv = NULL; + break; + } + } + + /* add servermap to serverlist */ + if (srv) + list_add(&srv->list, &dasd_serverlist); spin_unlock(&dasd_devmap_lock); - return rc; + + return (srv ? 1 : 0); } EXPORT_SYMBOL_GPL(dasd_set_uid); diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 39c2281..957ed5d 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -468,11 +468,11 @@ dasd_eckd_generate_uid(struct dasd_device *device, struct dasd_uid *uid) return -ENODEV; memset(uid, 0, sizeof(struct dasd_uid)); - strncpy(uid->vendor, confdata->ned1.HDA_manufacturer, - sizeof(uid->vendor) - 1); + memcpy(uid->vendor, confdata->ned1.HDA_manufacturer, + sizeof(uid->vendor) - 1); EBCASC(uid->vendor, sizeof(uid->vendor) - 1); - strncpy(uid->serial, confdata->ned1.HDA_location, - sizeof(uid->serial) - 1); + memcpy(uid->serial, confdata->ned1.HDA_location, + sizeof(uid->serial) - 1); EBCASC(uid->serial, sizeof(uid->serial) - 1); uid->ssid = confdata->neq.subsystemID; if (confdata->ned2.sneq.flags == 0x40) { -- cgit v1.1 From e54b82d739d4a2ef992976c8c0692cdf89286420 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Thu, 10 Aug 2006 10:46:56 -0700 Subject: IB/mthca: Make fence flag work for send work requests The fence bit needs to be set in the doorbell too, not just the WQE. Signed-off-by: Michael S. Tsirkin Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_qp.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c index cd8b672..157b4f8 100644 --- a/drivers/infiniband/hw/mthca/mthca_qp.c +++ b/drivers/infiniband/hw/mthca/mthca_qp.c @@ -99,6 +99,10 @@ enum { MTHCA_QP_BIT_RSC = 1 << 3 }; +enum { + MTHCA_SEND_DOORBELL_FENCE = 1 << 5 +}; + struct mthca_qp_path { __be32 port_pkey; u8 rnr_retry; @@ -1502,7 +1506,7 @@ int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, int i; int size; int size0 = 0; - u32 f0 = 0; + u32 f0; int ind; u8 op0 = 0; @@ -1686,6 +1690,8 @@ int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, if (!size0) { size0 = size; op0 = mthca_opcode[wr->opcode]; + f0 = wr->send_flags & IB_SEND_FENCE ? + MTHCA_SEND_DOORBELL_FENCE : 0; } ++ind; @@ -1843,7 +1849,7 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, int i; int size; int size0 = 0; - u32 f0 = 0; + u32 f0; int ind; u8 op0 = 0; @@ -2051,6 +2057,8 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, if (!size0) { size0 = size; op0 = mthca_opcode[wr->opcode]; + f0 = wr->send_flags & IB_SEND_FENCE ? + MTHCA_SEND_DOORBELL_FENCE : 0; } ++ind; -- cgit v1.1 From a19aa5c5fdda8b556ab238177ee27c5ef7873c94 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Fri, 11 Aug 2006 08:56:57 -0700 Subject: IB/mthca: Fix potential AB-BA deadlock with CQ locks When destroying a QP, mthca locks both the QP's send CQ and receive CQ. However, the following scenario is perfectly valid: QP_a: send_cq == CQ_x, recv_cq == CQ_y QP_b: send_cq == CQ_y, recv_cq == CQ_x The old mthca code simply locked send_cq and then recv_cq, which in this case could lead to an AB-BA deadlock if QP_a and QP_b were destroyed simultaneously. We can fix this by changing the locking code to lock the CQ with the lower CQ number first, which will create a consistent lock ordering. Also, the second CQ is locked with spin_lock_nested() to tell lockdep that we know what we're doing with the lock nesting. This bug was found by lockdep. Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_provider.h | 4 +-- drivers/infiniband/hw/mthca/mthca_qp.c | 42 ++++++++++++++++++++-------- 2 files changed, 32 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mthca/mthca_provider.h b/drivers/infiniband/hw/mthca/mthca_provider.h index 8de2887..9a5bece 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.h +++ b/drivers/infiniband/hw/mthca/mthca_provider.h @@ -136,8 +136,8 @@ struct mthca_ah { * We have one global lock that protects dev->cq/qp_table. Each * struct mthca_cq/qp also has its own lock. An individual qp lock * may be taken inside of an individual cq lock. Both cqs attached to - * a qp may be locked, with the send cq locked first. No other - * nesting should be done. + * a qp may be locked, with the cq with the lower cqn locked first. + * No other nesting should be done. * * Each struct mthca_cq/qp also has an ref count, protected by the * corresponding table lock. The pointer from the cq/qp_table to the diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c index 157b4f8..2e8f6f3 100644 --- a/drivers/infiniband/hw/mthca/mthca_qp.c +++ b/drivers/infiniband/hw/mthca/mthca_qp.c @@ -1263,6 +1263,32 @@ int mthca_alloc_qp(struct mthca_dev *dev, return 0; } +static void mthca_lock_cqs(struct mthca_cq *send_cq, struct mthca_cq *recv_cq) +{ + if (send_cq == recv_cq) + spin_lock_irq(&send_cq->lock); + else if (send_cq->cqn < recv_cq->cqn) { + spin_lock_irq(&send_cq->lock); + spin_lock_nested(&recv_cq->lock, SINGLE_DEPTH_NESTING); + } else { + spin_lock_irq(&recv_cq->lock); + spin_lock_nested(&send_cq->lock, SINGLE_DEPTH_NESTING); + } +} + +static void mthca_unlock_cqs(struct mthca_cq *send_cq, struct mthca_cq *recv_cq) +{ + if (send_cq == recv_cq) + spin_unlock_irq(&send_cq->lock); + else if (send_cq->cqn < recv_cq->cqn) { + spin_unlock(&recv_cq->lock); + spin_unlock_irq(&send_cq->lock); + } else { + spin_unlock(&send_cq->lock); + spin_unlock_irq(&recv_cq->lock); + } +} + int mthca_alloc_sqp(struct mthca_dev *dev, struct mthca_pd *pd, struct mthca_cq *send_cq, @@ -1315,17 +1341,13 @@ int mthca_alloc_sqp(struct mthca_dev *dev, * Lock CQs here, so that CQ polling code can do QP lookup * without taking a lock. */ - spin_lock_irq(&send_cq->lock); - if (send_cq != recv_cq) - spin_lock(&recv_cq->lock); + mthca_lock_cqs(send_cq, recv_cq); spin_lock(&dev->qp_table.lock); mthca_array_clear(&dev->qp_table.qp, mqpn); spin_unlock(&dev->qp_table.lock); - if (send_cq != recv_cq) - spin_unlock(&recv_cq->lock); - spin_unlock_irq(&send_cq->lock); + mthca_unlock_cqs(send_cq, recv_cq); err_out: dma_free_coherent(&dev->pdev->dev, sqp->header_buf_size, @@ -1359,9 +1381,7 @@ void mthca_free_qp(struct mthca_dev *dev, * Lock CQs here, so that CQ polling code can do QP lookup * without taking a lock. */ - spin_lock_irq(&send_cq->lock); - if (send_cq != recv_cq) - spin_lock(&recv_cq->lock); + mthca_lock_cqs(send_cq, recv_cq); spin_lock(&dev->qp_table.lock); mthca_array_clear(&dev->qp_table.qp, @@ -1369,9 +1389,7 @@ void mthca_free_qp(struct mthca_dev *dev, --qp->refcount; spin_unlock(&dev->qp_table.lock); - if (send_cq != recv_cq) - spin_unlock(&recv_cq->lock); - spin_unlock_irq(&send_cq->lock); + mthca_unlock_cqs(send_cq, recv_cq); wait_event(qp->wait, !get_qp_refcount(dev, qp)); -- cgit v1.1 From 0ee6a17389ceef65f1a86c38872fa98f08489022 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 11 Aug 2006 08:30:31 +0200 Subject: ACPI: fix kfree in i2c_ec error path Signed-off-by: Jean Delvare Signed-off-by: Len Brown --- drivers/acpi/i2c_ec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/acpi/i2c_ec.c b/drivers/acpi/i2c_ec.c index 84239d5..6809c28 100644 --- a/drivers/acpi/i2c_ec.c +++ b/drivers/acpi/i2c_ec.c @@ -330,7 +330,7 @@ static int acpi_ec_hc_add(struct acpi_device *device) status = acpi_evaluate_integer(ec_hc->handle, "_EC", NULL, &val); if (ACPI_FAILURE(status)) { ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Error obtaining _EC\n")); - kfree(ec_hc->smbus); + kfree(ec_hc); kfree(smbus); return -EIO; } -- cgit v1.1 From e50d1088bf2e5a68068c5f602be1dcc3e52dc873 Mon Sep 17 00:00:00 2001 From: Kristen Carlson Accardi Date: Tue, 8 Aug 2006 09:44:26 -0400 Subject: pciehp: make pciehp build for powerpc Make pciehp build on powerpc Signed-off-by: Kristen Carlson Accardi Acked-by: Randy Dunlap Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/pciehp.h | 5 +++++ drivers/pci/hotplug/pciehp_hpc.c | 4 ---- 2 files changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index ce89f58..eaea9d3 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -279,6 +279,11 @@ struct hpc_ops { #ifdef CONFIG_ACPI +#include +#include +#include +#include + #define pciehp_get_hp_hw_control_from_firmware(dev) \ pciehp_acpi_get_hp_hw_control_from_firmware(dev) static inline int pciehp_get_hp_params_from_firmware(struct pci_dev *dev, diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 0d8fb6e..6ab3b6c 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -38,10 +38,6 @@ #include "../pci.h" #include "pciehp.h" -#include -#include -#include -#include #ifdef DEBUG #define DBG_K_TRACE_ENTRY ((unsigned int)0x00000001) /* On function entry */ #define DBG_K_TRACE_EXIT ((unsigned int)0x00000002) /* On function exit */ -- cgit v1.1 From f0c1dc07309f0fe3409b92eb170b648a487b1e81 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Wed, 9 Aug 2006 15:25:09 -0400 Subject: PCI: remove dead HOTPLUG_PCI_SHPC_PHPRM_LEGACY option. Nothing in the tree references this config option. Signed-off-by: Dave Jones Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/Kconfig | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/hotplug/Kconfig b/drivers/pci/hotplug/Kconfig index 3fae77f..3c148ea 100644 --- a/drivers/pci/hotplug/Kconfig +++ b/drivers/pci/hotplug/Kconfig @@ -153,13 +153,6 @@ config HOTPLUG_PCI_SHPC_POLL_EVENT_MODE When in doubt, say N. -config HOTPLUG_PCI_SHPC_PHPRM_LEGACY - bool "For AMD SHPC only: Use $HRT for resource/configuration" - depends on HOTPLUG_PCI_SHPC && !ACPI - help - Say Y here for AMD SHPC. You have to select this option if you are - using this driver on platform with AMD SHPC. - config HOTPLUG_PCI_RPA tristate "RPA PCI Hotplug driver" depends on HOTPLUG_PCI && PPC_PSERIES && PPC64 && !HOTPLUG_PCI_FAKE -- cgit v1.1 From b41ee5d62211825cbe5e583cafc2255c91385aee Mon Sep 17 00:00:00 2001 From: David Kuehling Date: Mon, 7 Aug 2006 10:18:48 -0400 Subject: USB: unusual_devs entry for A-VOX WSX-300ER MP3 player This patch (as763) adds an unusual_devs entry for the A-VOX WSX-300ER MP3 player. From: David Kuehling Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/unusual_devs.h | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 2793f9a..fd158e0 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -1240,6 +1240,16 @@ UNUSUAL_DEV( 0x0ed1, 0x7636, 0x0103, 0x0103, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_IGNORE_RESIDUE | US_FL_GO_SLOW | US_FL_MAX_SECTORS_64), +/* David Kuehling : + * for MP3-Player AVOX WSX-300ER (bought in Japan). Reports lots of SCSI + * errors when trying to write. + */ +UNUSUAL_DEV( 0x0f19, 0x0105, 0x0100, 0x0100, + "C-MEX", + "A-VOX", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_IGNORE_RESIDUE ), + /* Reported by Michael Stattmann */ UNUSUAL_DEV( 0x0fce, 0xd008, 0x0000, 0x0000, "Sony Ericsson", -- cgit v1.1 From 919aeadcfa8e72ec2d6bf7bd405a16c40b8d8ecf Mon Sep 17 00:00:00 2001 From: Yoichi Yuasa Date: Thu, 3 Aug 2006 09:54:24 +0900 Subject: USB: removed a unbalanced #endif from ohci-au1xxx.c This patch has removed a unbalanced #endif from ohci-au1xxx.c . Please apply before 2.6.18 release. Error message was: In file included from drivers/usb/host/ohci-hcd.c:909: drivers/usb/host/ohci-au1xxx.c:113:2: #endif without #if Signed-off-by: Yoichi Yuasa Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-au1xxx.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/host/ohci-au1xxx.c b/drivers/usb/host/ohci-au1xxx.c index 822914e..f7a975d 100644 --- a/drivers/usb/host/ohci-au1xxx.c +++ b/drivers/usb/host/ohci-au1xxx.c @@ -110,7 +110,6 @@ static void au1xxx_start_ohc(struct platform_device *dev) printk(KERN_DEBUG __FILE__ ": Clock to USB host has been enabled \n"); -#endif } static void au1xxx_stop_ohc(struct platform_device *dev) -- cgit v1.1 From 7af569abc33ce09d3cb93e9b2160efff2531c59f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 19 Jul 2006 15:39:46 +0200 Subject: USB: appletouch: fix atp_disconnect appletouch uses urb->transfer_dma after having freed the urb, this shows up only if the system is compiled with slab debugging. This patch fixes it by reordering the free calls. Signed-off-by: Johannes Berg Signed-off-by: Vojtech Pavlik Signed-off-by: Greg Kroah-Hartman --- drivers/usb/input/appletouch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/input/appletouch.c b/drivers/usb/input/appletouch.c index 9e3f139..044faa0 100644 --- a/drivers/usb/input/appletouch.c +++ b/drivers/usb/input/appletouch.c @@ -597,9 +597,9 @@ static void atp_disconnect(struct usb_interface *iface) if (dev) { usb_kill_urb(dev->urb); input_unregister_device(dev->input); - usb_free_urb(dev->urb); usb_buffer_free(dev->udev, dev->datalen, dev->data, dev->urb->transfer_dma); + usb_free_urb(dev->urb); kfree(dev); } printk(KERN_INFO "input: appletouch disconnected\n"); -- cgit v1.1 From 922fdaa692e23bf57a10c16047d993c181991579 Mon Sep 17 00:00:00 2001 From: Norihiko Tomiyama Date: Tue, 8 Aug 2006 14:31:25 +0900 Subject: USB: Additional PID for SHARP W-ZERO3 I write a patch for ipaq.c. Would you like to add upstream tree ? This patch enables a support of "SHARP W-ZERO3(WS004SH)" and "SHARP W-ZERO3[es](WS007SH)". From: Norihiko Tomiyama Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ipaq.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c index 7e1bd5d..9840bad 100644 --- a/drivers/usb/serial/ipaq.c +++ b/drivers/usb/serial/ipaq.c @@ -251,6 +251,8 @@ static struct usb_device_id ipaq_id_table [] = { { USB_DEVICE(0x04C5, 0x1079) }, /* FUJITSU USB Sync */ { USB_DEVICE(0x04DA, 0x2500) }, /* Panasonic USB Sync */ { USB_DEVICE(0x04DD, 0x9102) }, /* SHARP WS003SH USB Modem */ + { USB_DEVICE(0x04DD, 0x9121) }, /* SHARP WS004SH USB Modem */ + { USB_DEVICE(0x04DD, 0x9123) }, /* SHARP WS007SH USB Modem */ { USB_DEVICE(0x04E8, 0x5F00) }, /* Samsung NEXiO USB Sync */ { USB_DEVICE(0x04E8, 0x5F01) }, /* Samsung NEXiO USB Sync */ { USB_DEVICE(0x04E8, 0x5F02) }, /* Samsung NEXiO USB Sync */ -- cgit v1.1 From 2011e9249a252e0655807fbe6841f6cfe6b6c197 Mon Sep 17 00:00:00 2001 From: Jonathan Davies Date: Wed, 9 Aug 2006 10:48:03 +0100 Subject: USB: ftdi_sio driver - new PIDs Signed-off-by: Jonathan Davies Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 2 ++ drivers/usb/serial/ftdi_sio.h | 6 ++++++ 2 files changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index a20da85..15945e8 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -306,6 +306,8 @@ static struct ftdi_sio_quirk ftdi_HE_TIRA1_quirk = { static struct usb_device_id id_table_combined [] = { + { USB_DEVICE(FTDI_VID, FTDI_AMC232_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CANUSB_PID) }, { USB_DEVICE(FTDI_VID, FTDI_ACTZWAVE_PID) }, { USB_DEVICE(FTDI_VID, FTDI_IRTRANS_PID) }, { USB_DEVICE(FTDI_VID, FTDI_IPLUS_PID) }, diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index 9f7343a..8888cd8 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h @@ -32,6 +32,12 @@ #define FTDI_NF_RIC_PID 0x0001 /* Product Id */ +/* www.canusb.com Lawicel CANUSB device */ +#define FTDI_CANUSB_PID 0xFFA8 /* Product Id */ + +/* AlphaMicro Components AMC-232USB01 device */ +#define FTDI_AMC232_PID 0xFF00 /* Product Id */ + /* ACT Solutions HomePro ZWave interface (http://www.act-solutions.com/HomePro.htm) */ #define FTDI_ACTZWAVE_PID 0xF2D0 -- cgit v1.1 From f54fa84dda211f68f65002efa44142207c886c79 Mon Sep 17 00:00:00 2001 From: Orjan Friberg Date: Tue, 8 Aug 2006 23:31:40 -0700 Subject: USB: usbtest.c: unsigned retval makes ctrl_out return 0 in case of error In my quest to try and figure out why test 14 (control write) doesn't work with my EZ-USB board, I noticed that sometimes testusb reported no error even though the kernel log complained "byte 0 is 0 not 2" etc. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/usbtest.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c index 786e1db..983e104 100644 --- a/drivers/usb/misc/usbtest.c +++ b/drivers/usb/misc/usbtest.c @@ -1242,11 +1242,12 @@ done: static int ctrl_out (struct usbtest_dev *dev, unsigned count, unsigned length, unsigned vary) { - unsigned i, j, len, retval; + unsigned i, j, len; + int retval; u8 *buf; char *what = "?"; struct usb_device *udev; - + if (length < 1 || length > 0xffff || vary >= length) return -EINVAL; -- cgit v1.1 From 09e590e5d5a93f2eaa748a89c623258e6bad1648 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Sat, 12 Aug 2006 10:55:07 +0200 Subject: [PATCH] smc91x: disable DMA mode on the logicpd pxa270 Enabling PXA DMA for the smc91x on the logicpd pxa270 produces unacceptable interference with the TFT panel, so disable it. Also delete the lpd270 versions of the SMC_{in,out}[bl]() macros, as they aren't used, since the board only supports 16bit accesses. Signed-off-by: Lennert Buytenhek Signed-off-by: Jeff Garzik --- drivers/net/smc91x.h | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h index 4ec4b4d..9f9f8f2 100644 --- a/drivers/net/smc91x.h +++ b/drivers/net/smc91x.h @@ -136,14 +136,9 @@ #define SMC_CAN_USE_32BIT 0 #define SMC_IO_SHIFT 0 #define SMC_NOWAIT 1 -#define SMC_USE_PXA_DMA 1 -#define SMC_inb(a, r) readb((a) + (r)) #define SMC_inw(a, r) readw((a) + (r)) -#define SMC_inl(a, r) readl((a) + (r)) -#define SMC_outb(v, a, r) writeb(v, (a) + (r)) #define SMC_outw(v, a, r) writew(v, (a) + (r)) -#define SMC_outl(v, a, r) writel(v, (a) + (r)) #define SMC_insw(a, r, p, l) readsw((a) + (r), p, l) #define SMC_outsw(a, r, p, l) writesw((a) + (r), p, l) -- cgit v1.1 From b64ef8afa58f397e1eaba2bd9ecaa6812064d464 Mon Sep 17 00:00:00 2001 From: Edgar Hucek Date: Sun, 13 Aug 2006 23:24:16 -0700 Subject: [PATCH] add imacfb documentation and detection Add basic Machine detection to imacfb and some Ducumentation bits for imacfb. Signed-off-by: Edgar Hucek Cc: "Antonino A. Daplas" Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/video/Kconfig | 2 +- drivers/video/imacfb.c | 49 ++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 45 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index c40b9b8..702eb93 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -554,7 +554,7 @@ config FB_VESA config FB_IMAC bool "Intel-based Macintosh Framebuffer Support" - depends on (FB = y) && X86 + depends on (FB = y) && X86 && EFI select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT diff --git a/drivers/video/imacfb.c b/drivers/video/imacfb.c index ff233b8..b485bece 100644 --- a/drivers/video/imacfb.c +++ b/drivers/video/imacfb.c @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include @@ -28,7 +30,7 @@ typedef enum _MAC_TYPE { M_I20, M_MINI, M_MACBOOK, - M_NEW + M_UNKNOWN } MAC_TYPE; /* --------------------------------------------------------------------- */ @@ -52,10 +54,36 @@ static struct fb_fix_screeninfo imacfb_fix __initdata = { }; static int inverse; -static int model = M_NEW; +static int model = M_UNKNOWN; static int manual_height; static int manual_width; +static int set_system(struct dmi_system_id *id) +{ + printk(KERN_INFO "imacfb: %s detected - set system to %ld\n", + id->ident, (long)id->driver_data); + + model = (long)id->driver_data; + + return 0; +} + +static struct dmi_system_id __initdata dmi_system_table[] = { + { set_system, "iMac4,1", { + DMI_MATCH(DMI_BIOS_VENDOR,"Apple Computer, Inc."), + DMI_MATCH(DMI_BIOS_VERSION,"iMac4,1") }, (void*)M_I17}, + { set_system, "MacBookPro1,1", { + DMI_MATCH(DMI_BIOS_VENDOR,"Apple Computer, Inc."), + DMI_MATCH(DMI_BIOS_VERSION,"MacBookPro1,1") }, (void*)M_I17}, + { set_system, "MacBook1,1", { + DMI_MATCH(DMI_BIOS_VENDOR,"Apple Computer, Inc."), + DMI_MATCH(DMI_PRODUCT_NAME,"MacBook1,1")}, (void *)M_MACBOOK}, + { set_system, "Macmini1,1", { + DMI_MATCH(DMI_BIOS_VENDOR,"Apple Computer, Inc."), + DMI_MATCH(DMI_PRODUCT_NAME,"Macmini1,1")}, (void *)M_MINI}, + {}, +}; + #define DEFAULT_FB_MEM 1024*1024*16 /* --------------------------------------------------------------------- */ @@ -149,7 +177,6 @@ static int __init imacfb_probe(struct platform_device *dev) screen_info.lfb_linelength = 1472 * 4; screen_info.lfb_base = 0x80010000; break; - case M_NEW: case M_I20: screen_info.lfb_width = 1680; screen_info.lfb_height = 1050; @@ -207,6 +234,10 @@ static int __init imacfb_probe(struct platform_device *dev) size_remap = size_total; imacfb_fix.smem_len = size_remap; +#ifndef __i386__ + screen_info.imacpm_seg = 0; +#endif + if (!request_mem_region(imacfb_fix.smem_start, size_total, "imacfb")) { printk(KERN_WARNING "imacfb: cannot reserve video memory at 0x%lx\n", @@ -324,8 +355,16 @@ static int __init imacfb_init(void) int ret; char *option = NULL; - /* ignore error return of fb_get_options */ - fb_get_options("imacfb", &option); + if (!efi_enabled) + return -ENODEV; + if (!dmi_check_system(dmi_system_table)) + return -ENODEV; + if (model == M_UNKNOWN) + return -ENODEV; + + if (fb_get_options("imacfb", &option)) + return -ENODEV; + imacfb_setup(option); ret = platform_driver_register(&imacfb_driver); -- cgit v1.1 From 485311a23c72c87332f9a55ce25e650e40ae3fc7 Mon Sep 17 00:00:00 2001 From: Michal Miroslaw Date: Sun, 13 Aug 2006 23:24:20 -0700 Subject: [PATCH] dm: BUG/OOPS fix Fix BUG I tripped on while testing failover and multipathing. BUG shows up on error path in multipath_ctr() when parse_priority_group() fails after returning at least once without error. The fix is to initialize m->ti early - just after alloc()ing it. BUG: unable to handle kernel NULL pointer dereference at virtual address 00000000 printing eip: c027c3d2 *pde = 00000000 Oops: 0000 [#3] Modules linked in: qla2xxx ext3 jbd mbcache sg ide_cd cdrom floppy CPU: 0 EIP: 0060:[] Not tainted VLI EFLAGS: 00010202 (2.6.17.3 #1) EIP is at dm_put_device+0xf/0x3b eax: 00000001 ebx: ee4fcac0 ecx: 00000000 edx: ee4fcac0 esi: ee4fc4e0 edi: ee4fc4e0 ebp: 00000000 esp: c5db3e78 ds: 007b es: 007b ss: 0068 Process multipathd (pid: 15912, threadinfo=c5db2000 task=ef485a90) Stack: ec4eda40 c02816bd ee4fc4c0 00000000 f7e89498 f883e0bc c02816f6 f7e89480 f7e8948c c0281801 ffffffea f7e89480 f883e080 c0281ffe 00000001 00000000 00000004 dfe9cab8 f7a693c0 f883e080 f883e0c0 ca4b99c0 c027c6ee 01400000 Call Trace: free_pgpaths+0x31/0x45 free_priority_group+0x25/0x2e free_multipath+0x35/0x67 multipath_ctr+0x123/0x12d dm_table_add_target+0x11e/0x18b populate_table+0x8a/0xaf table_load+0x52/0xf9 ctl_ioctl+0xca/0xfc table_load+0x0/0xf9 do_ioctl+0x3e/0x43 vfs_ioctl+0x16c/0x178 sys_ioctl+0x48/0x60 syscall_call+0x7/0xb Code: 97 f0 00 00 00 89 c1 83 c9 01 80 e2 01 0f 44 c1 88 43 14 8b 04 24 59 5b 5e 5f 5d c3 53 89 c1 89 d3 ff 4a 08 0f 94 c0 84 c0 74 2a <8b> 01 8b 10 89 d8 e8 f6 fb ff ff 8b 03 8b 53 04 89 50 04 89 02 EIP: [] dm_put_device+0xf/0x3b SS:ESP 0068:c5db3e78 Signed-off-by: Michal Miroslaw Acked-by: Alasdair G Kergon Cc: Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/md/dm-mpath.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index 217615b..93f701e 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c @@ -710,6 +710,8 @@ static int multipath_ctr(struct dm_target *ti, unsigned int argc, return -EINVAL; } + m->ti = ti; + r = parse_features(&as, m, ti); if (r) goto bad; @@ -751,7 +753,6 @@ static int multipath_ctr(struct dm_target *ti, unsigned int argc, } ti->private = m; - m->ti = ti; return 0; -- cgit v1.1 From 2621e2a155140b01c6ff57b3863cda2922c2c8bd Mon Sep 17 00:00:00 2001 From: Matt LaPlante Date: Wed, 5 Jul 2006 01:20:51 +0000 Subject: [WATCHDOG] Kconfig typos fix. Three typos in drivers/char/watchdog/Kconfig... Signed-off-by: Matt LaPlante Signed-off-by: Wim Van Sebroeck --- drivers/char/watchdog/Kconfig | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig index d53f664..fff89c2 100644 --- a/drivers/char/watchdog/Kconfig +++ b/drivers/char/watchdog/Kconfig @@ -45,7 +45,7 @@ config WATCHDOG_NOWAYOUT comment "Watchdog Device Drivers" depends on WATCHDOG -# Architecture Independant +# Architecture Independent config SOFT_WATCHDOG tristate "Software watchdog" @@ -127,7 +127,7 @@ config S3C2410_WATCHDOG enabled. The driver is limited by the speed of the system's PCLK - signal, so with reasonbaly fast systems (PCLK around 50-66MHz) + signal, so with reasonably fast systems (PCLK around 50-66MHz) then watchdog intervals of over approximately 20seconds are unavailable. @@ -423,7 +423,7 @@ config SBC_EPX_C3_WATCHDOG is no way to know if writing to its IO address will corrupt your system or have any real effect. The only way to be sure that this driver does what you want is to make sure you - are runnning it on an EPX-C3 from Winsystems with the watchdog + are running it on an EPX-C3 from Winsystems with the watchdog timer at IO address 0x1ee and 0x1ef. It will write to both those IO ports. Basically, the assumption is made that if you compile this driver into your kernel and/or load it as a module, that you @@ -472,7 +472,7 @@ config INDYDOG tristate "Indy/I2 Hardware Watchdog" depends on WATCHDOG && SGI_IP22 help - Hardwaredriver for the Indy's/I2's watchdog. This is a + Hardware driver for the Indy's/I2's watchdog. This is a watchdog timer that will reboot the machine after a 60 second timer expired and no process has written to /dev/watchdog during that time. -- cgit v1.1 From 4d8316d5ea4dcf0bf15d8a06d539ed7c99e9cfbe Mon Sep 17 00:00:00 2001 From: Pavel Machek Date: Mon, 14 Aug 2006 22:37:22 -0700 Subject: ACPI: fix boot with acpi=off Fix acpi_ac/battery boot with acpi=off Signed-off-by: Pavel Machek Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- drivers/acpi/ac.c | 2 ++ drivers/acpi/battery.c | 3 +++ 2 files changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c index 96309b9..11abc7b 100644 --- a/drivers/acpi/ac.c +++ b/drivers/acpi/ac.c @@ -285,6 +285,8 @@ static int __init acpi_ac_init(void) { int result; + if (acpi_disabled) + return -ENODEV; acpi_ac_dir = acpi_lock_ac_dir(); if (!acpi_ac_dir) diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 6e52217..9810e2a 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -757,6 +757,9 @@ static int __init acpi_battery_init(void) { int result; + if (acpi_disabled) + return -ENODEV; + acpi_battery_dir = acpi_lock_battery_dir(); if (!acpi_battery_dir) return -ENODEV; -- cgit v1.1 From b20d2aeb0ad322cbe7fd9120acae6118231b17a3 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Tue, 15 Aug 2006 23:21:37 -0400 Subject: ACPI: skip smart battery init when acpi=off Signed-off-by: Len Brown --- drivers/acpi/sbs.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c index db7b350..62bef0b 100644 --- a/drivers/acpi/sbs.c +++ b/drivers/acpi/sbs.c @@ -1714,6 +1714,9 @@ static int __init acpi_sbs_init(void) { int result = 0; + if (acpi_disabled) + return -ENODEV; + init_MUTEX(&sbs_sem); if (capacity_mode != DEF_CAPACITY_UNIT -- cgit v1.1 From 7daef60721e03809c7e5f8aa8491df4190f6b56f Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Mon, 14 Aug 2006 22:37:24 -0700 Subject: ACPI: add message if firmware_register() init fails Signed-off-by: Randy Dunlap Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- drivers/acpi/bus.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index b297769..7b77ee1 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -738,7 +739,10 @@ static int __init acpi_init(void) return -ENODEV; } - firmware_register(&acpi_subsys); + result = firmware_register(&acpi_subsys); + if (result < 0) + printk(KERN_WARNING "%s: firmware_register error: %d\n", + __FUNCTION__, result); result = acpi_bus_init(); -- cgit v1.1 From e9a315bcae3b9e0c54fb68ef90d0095956314480 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Mon, 14 Aug 2006 22:37:24 -0700 Subject: ACPI: verbose on kset/kobject_register errors Signed-off-by: Randy Dunlap Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- drivers/acpi/scan.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 5fcb50c..698a154 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -113,6 +114,8 @@ static struct kset acpi_namespace_kset = { static void acpi_device_register(struct acpi_device *device, struct acpi_device *parent) { + int err; + /* * Linkage * ------- @@ -138,7 +141,10 @@ static void acpi_device_register(struct acpi_device *device, device->kobj.parent = &parent->kobj; device->kobj.ktype = &ktype_acpi_ns; device->kobj.kset = &acpi_namespace_kset; - kobject_register(&device->kobj); + err = kobject_register(&device->kobj); + if (err < 0) + printk(KERN_WARNING "%s: kobject_register error: %d\n", + __FUNCTION__, err); create_sysfs_device_files(device); } @@ -1450,7 +1456,9 @@ static int __init acpi_scan_init(void) if (acpi_disabled) return 0; - kset_register(&acpi_namespace_kset); + result = kset_register(&acpi_namespace_kset); + if (result < 0) + printk(KERN_ERR PREFIX "kset_register error: %d\n", result); result = bus_register(&acpi_bus_type); if (result) { -- cgit v1.1 From 07dd4855e7fffeb50565826e5e736509ee8f6129 Mon Sep 17 00:00:00 2001 From: Yasunori Goto Date: Mon, 14 Aug 2006 22:37:32 -0700 Subject: ACPI: memory hotplug: remove useless message at boot time This is to remove noisy useless message at boot. The message is a ton of "ACPI Exception (acpi_memory-0492): AE_ERROR, handle is no memory device" In my emulation, number of memory devices are not so many (only 6), but, this messages are displayed 114 times. It is showed by acpi_memory_register_notify_handler() which is called by acpi_walk_namespace(). acpi_walk_namespace() parses all of ACPI's namespace and execute acpi_memory_register_notify_handler(). So, it is called for all of the device which is defined in namespace. If the parsing device is not memory, acpi_memhotplug ignores it due to "no match" and will parse next device. This is normal route, not an exception. Signed-off-by: Yasunori Goto Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- drivers/acpi/acpi_memhotplug.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c index b0d4b14..1dda370 100644 --- a/drivers/acpi/acpi_memhotplug.c +++ b/drivers/acpi/acpi_memhotplug.c @@ -484,10 +484,8 @@ acpi_memory_register_notify_handler(acpi_handle handle, status = is_memory_device(handle); - if (ACPI_FAILURE(status)){ - ACPI_EXCEPTION((AE_INFO, status, "handle is no memory device")); + if (ACPI_FAILURE(status)) return AE_OK; /* continue */ - } status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, acpi_memory_device_notify, NULL); @@ -503,10 +501,8 @@ acpi_memory_deregister_notify_handler(acpi_handle handle, status = is_memory_device(handle); - if (ACPI_FAILURE(status)){ - ACPI_EXCEPTION((AE_INFO, status, "handle is no memory device")); + if (ACPI_FAILURE(status)) return AE_OK; /* continue */ - } status = acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, -- cgit v1.1 From b5240b32b9b2b75917c478d768191862a2b190cc Mon Sep 17 00:00:00 2001 From: Kristen Carlson Accardi Date: Wed, 26 Jul 2006 13:32:00 -0400 Subject: ACPIPHP: allow acpiphp to build without ACPI_DOCK Change the build options for acpiphp so that it may build without being dependent on the ACPI_DOCK option, but yet does not allow the option of acpiphp being built-in when dock is built as a module. This does not change the previous patch for ACPI_IBM_DOCK Kconfig. For the following matrix of config options, I built an i386 kernel. Dock acpiphp should it build? confirmed y y y y y n y y y m y y m y no - acpiphp should acpiphp was convert to m converted to m m n y y m m y y n y y y n n y y n m y y Signed-off-by: Anil S Keshavamurthy Signed-off-by: Kristen Carlson Accardi Signed-off-by: Len Brown --- drivers/pci/hotplug/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/hotplug/Kconfig b/drivers/pci/hotplug/Kconfig index 3fae77f..1c363d8 100644 --- a/drivers/pci/hotplug/Kconfig +++ b/drivers/pci/hotplug/Kconfig @@ -76,7 +76,7 @@ config HOTPLUG_PCI_IBM config HOTPLUG_PCI_ACPI tristate "ACPI PCI Hotplug driver" - depends on ACPI_DOCK && HOTPLUG_PCI + depends on (!ACPI_DOCK && ACPI && HOTPLUG_PCI) || (ACPI_DOCK && HOTPLUG_PCI) help Say Y here if you have a system that supports PCI Hotplug using ACPI. -- cgit v1.1 From 2f6c55fc3109bcfa1bb1a112c825e07212c20f37 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Wed, 16 Aug 2006 13:49:27 +0200 Subject: [S390] dasd slab cache alignment. The dasd_page_cache should return page addresses and therefore the cache must be created with an alignment of PAGE_SIZE. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- drivers/s390/block/dasd_devmap.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index 6fcb28d..29e48b2 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c @@ -264,8 +264,9 @@ dasd_parse_keyword( char *parsestring ) { if (dasd_page_cache) return residual_str; dasd_page_cache = - kmem_cache_create("dasd_page_cache", PAGE_SIZE, 0, - SLAB_CACHE_DMA, NULL, NULL ); + kmem_cache_create("dasd_page_cache", PAGE_SIZE, + PAGE_SIZE, SLAB_CACHE_DMA, + NULL, NULL ); if (!dasd_page_cache) MESSAGE(KERN_WARNING, "%s", "Failed to create slab, " "fixed buffer mode disabled."); -- cgit v1.1 From b18a60e7c2a7f2a17dbd57885621a42d546e2f7d Mon Sep 17 00:00:00 2001 From: Peter Oberparleiter Date: Wed, 16 Aug 2006 13:49:33 +0200 Subject: [S390] inaccessible PAV alias devices on LPAR. In some situations PAV alias devices on LPAR are not accessible. The initialization procedure required to enable access to PAV alias devices has to be performed per storage server subsystem and not only once per storage server. Signed-off-by: Peter Oberparleiter Signed-off-by: Martin Schwidefsky --- drivers/s390/block/dasd_devmap.c | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index 29e48b2..9d0c6e1 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c @@ -48,18 +48,20 @@ struct dasd_devmap { }; /* - * dasd_servermap is used to store the server_id of all storage servers - * accessed by DASD device driver. + * dasd_server_ssid_map contains a globally unique storage server subsystem ID. + * dasd_server_ssid_list contains the list of all subsystem IDs accessed by + * the DASD device driver. */ -struct dasd_servermap { +struct dasd_server_ssid_map { struct list_head list; struct server_id { char vendor[4]; char serial[15]; } sid; + __u16 ssid; }; -static struct list_head dasd_serverlist; +static struct list_head dasd_server_ssid_list; /* * Parameter parsing functions for dasd= parameter. The syntax is: @@ -878,8 +880,9 @@ dasd_get_uid(struct ccw_device *cdev, struct dasd_uid *uid) /* * Register the given device unique identifier into devmap struct. - * In addition check if the related storage server is already contained in the - * dasd_serverlist. If server is not contained, create new entry. + * In addition check if the related storage server subsystem ID is already + * contained in the dasd_server_ssid_list. If subsystem ID is not contained, + * create new entry. * Return 0 if server was already in serverlist, * 1 if the server was added successful * <0 in case of error. @@ -888,26 +891,27 @@ int dasd_set_uid(struct ccw_device *cdev, struct dasd_uid *uid) { struct dasd_devmap *devmap; - struct dasd_servermap *srv, *tmp; + struct dasd_server_ssid_map *srv, *tmp; devmap = dasd_find_busid(cdev->dev.bus_id); if (IS_ERR(devmap)) return PTR_ERR(devmap); - /* generate entry for servermap */ - srv = (struct dasd_servermap *) - kzalloc(sizeof(struct dasd_servermap), GFP_KERNEL); + /* generate entry for server_ssid_map */ + srv = (struct dasd_server_ssid_map *) + kzalloc(sizeof(struct dasd_server_ssid_map), GFP_KERNEL); if (!srv) return -ENOMEM; strncpy(srv->sid.vendor, uid->vendor, sizeof(srv->sid.vendor) - 1); strncpy(srv->sid.serial, uid->serial, sizeof(srv->sid.serial) - 1); + srv->ssid = uid->ssid; /* server is already contained ? */ spin_lock(&dasd_devmap_lock); devmap->uid = *uid; - list_for_each_entry(tmp, &dasd_serverlist, list) { + list_for_each_entry(tmp, &dasd_server_ssid_list, list) { if (!memcmp(&srv->sid, &tmp->sid, - sizeof(struct dasd_servermap))) { + sizeof(struct dasd_server_ssid_map))) { kfree(srv); srv = NULL; break; @@ -916,7 +920,7 @@ dasd_set_uid(struct ccw_device *cdev, struct dasd_uid *uid) /* add servermap to serverlist */ if (srv) - list_add(&srv->list, &dasd_serverlist); + list_add(&srv->list, &dasd_server_ssid_list); spin_unlock(&dasd_devmap_lock); return (srv ? 1 : 0); @@ -987,7 +991,7 @@ dasd_devmap_init(void) INIT_LIST_HEAD(&dasd_hashlists[i]); /* Initialize servermap structure. */ - INIT_LIST_HEAD(&dasd_serverlist); + INIT_LIST_HEAD(&dasd_server_ssid_list); return 0; } -- cgit v1.1 From acaea9ee460d0ba5a14f0066ba26cfa43dd5fdf3 Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Tue, 15 Aug 2006 17:20:50 +0300 Subject: IB/core: Fix SM LID/LID change with client reregister set After commit 12bbb2b7be7f5564952ebe0196623e97464b8ac5, when SM LID change or LID change MAD also has a client reregistration bit set, only CLIENT_REREGISTER event is generated. As a result, the sa_query module and the cache module don't update the port information, and ULPs (e.g. IPoIB) stop working. This is the regression we observe as compared to 2.6.17. Rather than generate multiple events (which would have negative performance impact), let us simply let cache and SA query respond to reregister event in the same way as to LID and SM change events. Signed-off-by: Jack Morgenstein Signed-off-by: Michael S. Tsirkin Signed-off-by: Roland Dreier --- drivers/infiniband/core/cache.c | 3 ++- drivers/infiniband/core/sa_query.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/cache.c b/drivers/infiniband/core/cache.c index e05ca2c..75313ad 100644 --- a/drivers/infiniband/core/cache.c +++ b/drivers/infiniband/core/cache.c @@ -301,7 +301,8 @@ static void ib_cache_event(struct ib_event_handler *handler, event->event == IB_EVENT_PORT_ACTIVE || event->event == IB_EVENT_LID_CHANGE || event->event == IB_EVENT_PKEY_CHANGE || - event->event == IB_EVENT_SM_CHANGE) { + event->event == IB_EVENT_SM_CHANGE || + event->event == IB_EVENT_CLIENT_REREGISTER) { work = kmalloc(sizeof *work, GFP_ATOMIC); if (work) { INIT_WORK(&work->work, ib_cache_task, work); diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c index aeda484..d6b8422 100644 --- a/drivers/infiniband/core/sa_query.c +++ b/drivers/infiniband/core/sa_query.c @@ -405,7 +405,8 @@ static void ib_sa_event(struct ib_event_handler *handler, struct ib_event *event event->event == IB_EVENT_PORT_ACTIVE || event->event == IB_EVENT_LID_CHANGE || event->event == IB_EVENT_PKEY_CHANGE || - event->event == IB_EVENT_SM_CHANGE) { + event->event == IB_EVENT_SM_CHANGE || + event->event == IB_EVENT_CLIENT_REREGISTER) { struct ib_sa_device *sa_dev; sa_dev = container_of(handler, typeof(*sa_dev), event_handler); -- cgit v1.1 From 5672bde6355f2d12c49df1eec083d25afe489063 Mon Sep 17 00:00:00 2001 From: Handle X Date: Mon, 14 Aug 2006 22:37:27 -0700 Subject: ACPI: hotkey.c fixes, fix for potential crash of hotkey.c While going through the code, I found out some memory leaks and potential crashes in drivers/acpi/hotkey.c Please find the patch to fix them. This patch does the following, 1. Fixes memory leaks in error paths of hotkey_write_config 2. Fixes freeing unallocated pointers in the error paths of hotkey_write_config 3. Uses a loop instead of linear searching for parsing the userspace input in get_params 4. Uses array of char * instead of passing 4 pointer parameters explicitly into the init_{poll_}hotkey_* static functions Signed-off-by: Andrew Morton Acked-by: Luming Yu Signed-off-by: Len Brown --- drivers/acpi/hotkey.c | 281 +++++++++++++++++++++----------------------------- 1 file changed, 119 insertions(+), 162 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/hotkey.c b/drivers/acpi/hotkey.c index 32c9d88..1ba2db6 100644 --- a/drivers/acpi/hotkey.c +++ b/drivers/acpi/hotkey.c @@ -91,6 +91,14 @@ enum { HK_EVENT_ENTERRING_S5, }; +enum conf_entry_enum { + bus_handle = 0, + bus_method = 1, + action_handle = 2, + method = 3, + LAST_CONF_ENTRY +}; + /* procdir we use */ static struct proc_dir_entry *hotkey_proc_dir; static struct proc_dir_entry *hotkey_config; @@ -244,19 +252,15 @@ static int hotkey_info_open_fs(struct inode *inode, struct file *file) static char *format_result(union acpi_object *object) { - char *buf = NULL; - - buf = (char *)kmalloc(RESULT_STR_LEN, GFP_KERNEL); - if (buf) - memset(buf, 0, RESULT_STR_LEN); - else - goto do_fail; + char *buf; + buf = kzalloc(RESULT_STR_LEN, GFP_KERNEL); + if (!buf) + return NULL; /* Now, just support integer type */ if (object->type == ACPI_TYPE_INTEGER) sprintf(buf, "%d\n", (u32) object->integer.value); - do_fail: - return (buf); + return buf; } static int hotkey_polling_seq_show(struct seq_file *seq, void *offset) @@ -486,98 +490,102 @@ static void free_hotkey_device(union acpi_hotkey *key) static void free_hotkey_buffer(union acpi_hotkey *key) { + /* key would never be null, action method could be */ kfree(key->event_hotkey.action_method); } static void free_poll_hotkey_buffer(union acpi_hotkey *key) { + /* key would never be null, others could be*/ kfree(key->poll_hotkey.action_method); kfree(key->poll_hotkey.poll_method); kfree(key->poll_hotkey.poll_result); } static int -init_hotkey_device(union acpi_hotkey *key, char *bus_str, char *action_str, - char *method, int std_num, int external_num) +init_hotkey_device(union acpi_hotkey *key, char **config_entry, + int std_num, int external_num) { acpi_handle tmp_handle; acpi_status status = AE_OK; - if (std_num < 0 || IS_POLL(std_num) || !key) goto do_fail; - if (!bus_str || !action_str || !method) + if (!config_entry[bus_handle] || !config_entry[action_handle] + || !config_entry[method]) goto do_fail; key->link.hotkey_type = ACPI_HOTKEY_EVENT; key->link.hotkey_standard_num = std_num; key->event_hotkey.flag = 0; - key->event_hotkey.action_method = method; + key->event_hotkey.action_method = config_entry[method]; - status = - acpi_get_handle(NULL, bus_str, &(key->event_hotkey.bus_handle)); + status = acpi_get_handle(NULL, config_entry[bus_handle], + &(key->event_hotkey.bus_handle)); if (ACPI_FAILURE(status)) - goto do_fail; + goto do_fail_zero; key->event_hotkey.external_hotkey_num = external_num; - status = - acpi_get_handle(NULL, action_str, + status = acpi_get_handle(NULL, config_entry[action_handle], &(key->event_hotkey.action_handle)); if (ACPI_FAILURE(status)) - goto do_fail; + goto do_fail_zero; status = acpi_get_handle(key->event_hotkey.action_handle, - method, &tmp_handle); + config_entry[method], &tmp_handle); if (ACPI_FAILURE(status)) - goto do_fail; + goto do_fail_zero; return AE_OK; - do_fail: +do_fail_zero: + key->event_hotkey.action_method = NULL; +do_fail: return -ENODEV; } static int -init_poll_hotkey_device(union acpi_hotkey *key, - char *poll_str, - char *poll_method, - char *action_str, char *action_method, int std_num) +init_poll_hotkey_device(union acpi_hotkey *key, char **config_entry, + int std_num) { acpi_status status = AE_OK; acpi_handle tmp_handle; - if (std_num < 0 || IS_EVENT(std_num) || !key) goto do_fail; - - if (!poll_str || !poll_method || !action_str || !action_method) + if (!config_entry[bus_handle] ||!config_entry[bus_method] || + !config_entry[action_handle] || !config_entry[method]) goto do_fail; key->link.hotkey_type = ACPI_HOTKEY_POLLING; key->link.hotkey_standard_num = std_num; key->poll_hotkey.flag = 0; - key->poll_hotkey.poll_method = poll_method; - key->poll_hotkey.action_method = action_method; + key->poll_hotkey.poll_method = config_entry[bus_method]; + key->poll_hotkey.action_method = config_entry[method]; - status = - acpi_get_handle(NULL, poll_str, &(key->poll_hotkey.poll_handle)); + status = acpi_get_handle(NULL, config_entry[bus_handle], + &(key->poll_hotkey.poll_handle)); if (ACPI_FAILURE(status)) - goto do_fail; + goto do_fail_zero; status = acpi_get_handle(key->poll_hotkey.poll_handle, - poll_method, &tmp_handle); + config_entry[bus_method], &tmp_handle); if (ACPI_FAILURE(status)) - goto do_fail; + goto do_fail_zero; status = - acpi_get_handle(NULL, action_str, + acpi_get_handle(NULL, config_entry[action_handle], &(key->poll_hotkey.action_handle)); if (ACPI_FAILURE(status)) - goto do_fail; + goto do_fail_zero; status = acpi_get_handle(key->poll_hotkey.action_handle, - action_method, &tmp_handle); + config_entry[method], &tmp_handle); if (ACPI_FAILURE(status)) - goto do_fail; + goto do_fail_zero; key->poll_hotkey.poll_result = (union acpi_object *)kmalloc(sizeof(union acpi_object), GFP_KERNEL); if (!key->poll_hotkey.poll_result) - goto do_fail; + goto do_fail_zero; return AE_OK; - do_fail: + +do_fail_zero: + key->poll_hotkey.poll_method = NULL; + key->poll_hotkey.action_method = NULL; +do_fail: return -ENODEV; } @@ -652,17 +660,18 @@ static int hotkey_poll_config_seq_show(struct seq_file *seq, void *offset) } static int -get_parms(char *config_record, - int *cmd, - char **bus_handle, - char **bus_method, - char **action_handle, - char **method, int *internal_event_num, int *external_event_num) +get_parms(char *config_record, int *cmd, char **config_entry, + int *internal_event_num, int *external_event_num) { +/* the format of *config_record = + * "1:\d+:*" : "cmd:internal_event_num" + * "\d+:\w+:\w+:\w+:\w+:\d+:\d+" : + * "cmd:bus_handle:bus_method:action_handle:method:internal_event_num:external_event_num" + */ char *tmp, *tmp1, count; + int i; sscanf(config_record, "%d", cmd); - if (*cmd == 1) { if (sscanf(config_record, "%d:%d", cmd, internal_event_num) != 2) @@ -674,59 +683,27 @@ get_parms(char *config_record, if (!tmp) goto do_fail; tmp++; - tmp1 = strchr(tmp, ':'); - if (!tmp1) - goto do_fail; - - count = tmp1 - tmp; - *bus_handle = (char *)kmalloc(count + 1, GFP_KERNEL); - if (!*bus_handle) - goto do_fail; - strncpy(*bus_handle, tmp, count); - *(*bus_handle + count) = 0; - - tmp = tmp1; - tmp++; - tmp1 = strchr(tmp, ':'); - if (!tmp1) - goto do_fail; - count = tmp1 - tmp; - *bus_method = (char *)kmalloc(count + 1, GFP_KERNEL); - if (!*bus_method) - goto do_fail; - strncpy(*bus_method, tmp, count); - *(*bus_method + count) = 0; - - tmp = tmp1; - tmp++; - tmp1 = strchr(tmp, ':'); - if (!tmp1) - goto do_fail; - count = tmp1 - tmp; - *action_handle = (char *)kmalloc(count + 1, GFP_KERNEL); - if (!*action_handle) - goto do_fail; - strncpy(*action_handle, tmp, count); - *(*action_handle + count) = 0; - - tmp = tmp1; - tmp++; - tmp1 = strchr(tmp, ':'); - if (!tmp1) - goto do_fail; - count = tmp1 - tmp; - *method = (char *)kmalloc(count + 1, GFP_KERNEL); - if (!*method) - goto do_fail; - strncpy(*method, tmp, count); - *(*method + count) = 0; - - if (sscanf(tmp1 + 1, "%d:%d", internal_event_num, external_event_num) <= - 0) - goto do_fail; - - return 6; - do_fail: + for (i = 0; i < LAST_CONF_ENTRY; i++) { + tmp1 = strchr(tmp, ':'); + if (!tmp1) { + goto do_fail; + } + count = tmp1 - tmp; + config_entry[i] = kzalloc(count + 1, GFP_KERNEL); + if (!config_entry[i]) + goto handle_failure; + strncpy(config_entry[i], tmp, count); + tmp = tmp1 + 1; + } + if (sscanf(tmp, "%d:%d", internal_event_num, external_event_num) <= 0) + goto handle_failure; + if (!IS_OTHERS(*internal_event_num)) { + return 6; + } +handle_failure: + while (i-- > 0) + kfree(config_entry[i]); +do_fail: return -1; } @@ -736,50 +713,34 @@ static ssize_t hotkey_write_config(struct file *file, size_t count, loff_t * data) { char *config_record = NULL; - char *bus_handle = NULL; - char *bus_method = NULL; - char *action_handle = NULL; - char *method = NULL; + char *config_entry[LAST_CONF_ENTRY]; int cmd, internal_event_num, external_event_num; int ret = 0; - union acpi_hotkey *key = NULL; + union acpi_hotkey *key = kzalloc(sizeof(union acpi_hotkey), GFP_KERNEL); + if (!key) + return -ENOMEM; - config_record = (char *)kmalloc(count + 1, GFP_KERNEL); - if (!config_record) + config_record = kzalloc(count + 1, GFP_KERNEL); + if (!config_record) { + kfree(key); return -ENOMEM; + } if (copy_from_user(config_record, buffer, count)) { kfree(config_record); + kfree(key); printk(KERN_ERR PREFIX "Invalid data\n"); return -EINVAL; } - config_record[count] = 0; - - ret = get_parms(config_record, - &cmd, - &bus_handle, - &bus_method, - &action_handle, - &method, &internal_event_num, &external_event_num); - + ret = get_parms(config_record, &cmd, config_entry, + &internal_event_num, &external_event_num); kfree(config_record); - if (IS_OTHERS(internal_event_num)) - goto do_fail; if (ret != 6) { - do_fail: - kfree(bus_handle); - kfree(bus_method); - kfree(action_handle); - kfree(method); printk(KERN_ERR PREFIX "Invalid data format ret=%d\n", ret); return -EINVAL; } - key = kmalloc(sizeof(union acpi_hotkey), GFP_KERNEL); - if (!key) - goto do_fail; - memset(key, 0, sizeof(union acpi_hotkey)); if (cmd == 1) { union acpi_hotkey *tmp = NULL; tmp = get_hotkey_by_event(&global_hotkey_list, @@ -791,34 +752,19 @@ static ssize_t hotkey_write_config(struct file *file, goto cont_cmd; } if (IS_EVENT(internal_event_num)) { - kfree(bus_method); - ret = init_hotkey_device(key, bus_handle, action_handle, method, - internal_event_num, - external_event_num); - } else - ret = init_poll_hotkey_device(key, bus_handle, bus_method, - action_handle, method, - internal_event_num); - if (ret) { - kfree(bus_handle); - kfree(action_handle); - if (IS_EVENT(internal_event_num)) - free_hotkey_buffer(key); - else - free_poll_hotkey_buffer(key); - kfree(key); - printk(KERN_ERR PREFIX "Invalid hotkey\n"); - return -EINVAL; + if (init_hotkey_device(key, config_entry, + internal_event_num, external_event_num)) + goto init_hotkey_fail; + } else { + if (init_poll_hotkey_device(key, config_entry, + internal_event_num)) + goto init_poll_hotkey_fail; } - - cont_cmd: - kfree(bus_handle); - kfree(action_handle); - +cont_cmd: switch (cmd) { case 0: - if (get_hotkey_by_event - (&global_hotkey_list, key->link.hotkey_standard_num)) + if (get_hotkey_by_event(&global_hotkey_list, + key->link.hotkey_standard_num)) goto fail_out; else hotkey_add(key); @@ -827,6 +773,7 @@ static ssize_t hotkey_write_config(struct file *file, hotkey_remove(key); break; case 2: + /* key is kfree()ed if matched*/ if (hotkey_update(key)) goto fail_out; break; @@ -835,11 +782,22 @@ static ssize_t hotkey_write_config(struct file *file, break; } return count; - fail_out: - if (IS_EVENT(internal_event_num)) - free_hotkey_buffer(key); - else - free_poll_hotkey_buffer(key); + +init_poll_hotkey_fail: /* failed init_poll_hotkey_device */ + kfree(config_entry[bus_method]); + config_entry[bus_method] = NULL; +init_hotkey_fail: /* failed init_hotkey_device */ + kfree(config_entry[method]); +fail_out: + kfree(config_entry[bus_handle]); + kfree(config_entry[action_handle]); + /* No double free since elements =NULL for error cases */ + if (IS_EVENT(internal_event_num)) { + if (config_entry[bus_method]) + kfree(config_entry[bus_method]); + free_hotkey_buffer(key); /* frees [method] */ + } else + free_poll_hotkey_buffer(key); /* frees [bus_method]+[method] */ kfree(key); printk(KERN_ERR PREFIX "invalid key\n"); return -EINVAL; @@ -923,10 +881,9 @@ static ssize_t hotkey_execute_aml_method(struct file *file, union acpi_hotkey *key; - arg = (char *)kmalloc(count + 1, GFP_KERNEL); + arg = kzalloc(count + 1, GFP_KERNEL); if (!arg) return -ENOMEM; - arg[count] = 0; if (copy_from_user(arg, buffer, count)) { kfree(arg); -- cgit v1.1 From d68909f4c3eee09c13d4e5c86512c6c075553dbd Mon Sep 17 00:00:00 2001 From: Len Brown Date: Wed, 16 Aug 2006 19:16:58 -0400 Subject: ACPI: avoid irqrouter_resume might_sleep oops on resume from S4 __might_sleep+0x8e/0x93 acpi_os_wait_semaphore+0x50/0xa3 acpi_ut_acquire_mutex+0x28/0x6a acpi_ns_get_node+0x46/0x88 acpi_ns_evaluate+0x2d/0xfc acpi_rs_set_srs_method_data+0xc5/0xe1 acpi_set_current_resources+0x31/0x3f acpi_pci_link_set+0xfc/0x1a5 irqrouter_resume+0x48/0x5f and __might_sleep+0x8e/0x93 kmem_cache_alloc+0x2a/0x8f acpi_evaluate_integer+0x32/0x96 acpi_bus_get_status+0x30/0x84 acpi_pci_link_set+0x12a/0x1a5 irqrouter_resume+0x48/0x5f http://bugzilla.kernel.org/show_bug.cgi?id=6810 Signed-off-by: Len Brown --- drivers/acpi/osl.c | 10 ++++++++++ drivers/acpi/utils.c | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index b7d1514..507f051 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -746,6 +746,16 @@ acpi_status acpi_os_wait_semaphore(acpi_handle handle, u32 units, u16 timeout) ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Waiting for semaphore[%p|%d|%d]\n", handle, units, timeout)); + /* + * This can be called during resume with interrupts off. + * Like boot-time, we should be single threaded and will + * always get the lock if we try -- timeout or not. + * If this doesn't succeed, then we will oops courtesy of + * might_sleep() in down(). + */ + if (!down_trylock(sem)) + return AE_OK; + switch (timeout) { /* * No Wait: diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index f48227f..d0d84c4 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -262,7 +262,7 @@ acpi_evaluate_integer(acpi_handle handle, if (!data) return AE_BAD_PARAMETER; - element = kmalloc(sizeof(union acpi_object), GFP_KERNEL); + element = kmalloc(sizeof(union acpi_object), irqs_disabled() ? GFP_ATOMIC: GFP_KERNEL); if (!element) return AE_NO_MEMORY; -- cgit v1.1 From 2f8af120a159a843948749ea88bcacda9779b132 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Tue, 15 Aug 2006 01:39:10 -0700 Subject: [BNX2]: Fix tx race condition. Fix a subtle race condition between bnx2_start_xmit() and bnx2_tx_int() similar to the one in tg3 discovered by Herbert Xu: CPU0 CPU1 bnx2_start_xmit() if (tx_ring_full) { tx_lock bnx2_tx() if (!netif_queue_stopped) netif_stop_queue() if (!tx_ring_full) update_tx_ring netif_wake_queue() tx_unlock } Even though tx_ring is updated before the if statement in bnx2_tx_int() in program order, it can be re-ordered by the CPU as shown above. This scenario can cause the tx queue to be stopped forever if bnx2_tx_int() has just freed up the entire tx_ring. The possibility of this happening should be very rare though. The following changes are made, very much identical to the tg3 fix: 1. Add memory barrier to fix the above race condition. 2. Eliminate the private tx_lock altogether and rely solely on netif_tx_lock. This eliminates one spinlock in bnx2_start_xmit() when the ring is full. 3. Because of 2, use netif_tx_lock in bnx2_tx_int() before calling netif_wake_queue(). 4. Add memory barrier to bnx2_tx_avail(). 5. Add bp->tx_wake_thresh which is set to half the tx ring size. 6. Check for the full wake queue condition before getting netif_tx_lock in tg3_tx(). This reduces the number of unnecessary spinlocks when the tx ring is full in a steady-state condition. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 35 +++++++++++++++++++---------------- drivers/net/bnx2.h | 12 +++++------- 2 files changed, 24 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index db73de0..2099edb 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -209,8 +209,10 @@ MODULE_DEVICE_TABLE(pci, bnx2_pci_tbl); static inline u32 bnx2_tx_avail(struct bnx2 *bp) { - u32 diff = TX_RING_IDX(bp->tx_prod) - TX_RING_IDX(bp->tx_cons); + u32 diff; + smp_mb(); + diff = TX_RING_IDX(bp->tx_prod) - TX_RING_IDX(bp->tx_cons); if (diff > MAX_TX_DESC_CNT) diff = (diff & MAX_TX_DESC_CNT) - 1; return (bp->tx_ring_size - diff); @@ -1686,15 +1688,20 @@ bnx2_tx_int(struct bnx2 *bp) } bp->tx_cons = sw_cons; + /* Need to make the tx_cons update visible to bnx2_start_xmit() + * before checking for netif_queue_stopped(). Without the + * memory barrier, there is a small possibility that bnx2_start_xmit() + * will miss it and cause the queue to be stopped forever. + */ + smp_mb(); - if (unlikely(netif_queue_stopped(bp->dev))) { - spin_lock(&bp->tx_lock); + if (unlikely(netif_queue_stopped(bp->dev)) && + (bnx2_tx_avail(bp) > bp->tx_wake_thresh)) { + netif_tx_lock(bp->dev); if ((netif_queue_stopped(bp->dev)) && - (bnx2_tx_avail(bp) > MAX_SKB_FRAGS)) { - + (bnx2_tx_avail(bp) > bp->tx_wake_thresh)) netif_wake_queue(bp->dev); - } - spin_unlock(&bp->tx_lock); + netif_tx_unlock(bp->dev); } } @@ -3503,6 +3510,8 @@ bnx2_init_tx_ring(struct bnx2 *bp) struct tx_bd *txbd; u32 val; + bp->tx_wake_thresh = bp->tx_ring_size / 2; + txbd = &bp->tx_desc_ring[MAX_TX_DESC_CNT]; txbd->tx_bd_haddr_hi = (u64) bp->tx_desc_mapping >> 32; @@ -4390,10 +4399,8 @@ bnx2_vlan_rx_kill_vid(struct net_device *dev, uint16_t vid) #endif /* Called with netif_tx_lock. - * hard_start_xmit is pseudo-lockless - a lock is only required when - * the tx queue is full. This way, we get the benefit of lockless - * operations most of the time without the complexities to handle - * netif_stop_queue/wake_queue race conditions. + * bnx2_tx_int() runs without netif_tx_lock unless it needs to call + * netif_wake_queue(). */ static int bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev) @@ -4512,12 +4519,9 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; if (unlikely(bnx2_tx_avail(bp) <= MAX_SKB_FRAGS)) { - spin_lock(&bp->tx_lock); netif_stop_queue(dev); - - if (bnx2_tx_avail(bp) > MAX_SKB_FRAGS) + if (bnx2_tx_avail(bp) > bp->tx_wake_thresh) netif_wake_queue(dev); - spin_unlock(&bp->tx_lock); } return NETDEV_TX_OK; @@ -5628,7 +5632,6 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) bp->pdev = pdev; spin_lock_init(&bp->phy_lock); - spin_lock_init(&bp->tx_lock); INIT_WORK(&bp->reset_task, bnx2_reset_task, bp); dev->base_addr = dev->mem_start = pci_resource_start(pdev, 0); diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h index 658c5ee..fe80476 100644 --- a/drivers/net/bnx2.h +++ b/drivers/net/bnx2.h @@ -3890,10 +3890,6 @@ struct bnx2 { u32 tx_prod_bseq __attribute__((aligned(L1_CACHE_BYTES))); u16 tx_prod; - struct tx_bd *tx_desc_ring; - struct sw_bd *tx_buf_ring; - int tx_ring_size; - u16 tx_cons __attribute__((aligned(L1_CACHE_BYTES))); u16 hw_tx_cons; @@ -3916,9 +3912,11 @@ struct bnx2 { struct sw_bd *rx_buf_ring; struct rx_bd *rx_desc_ring[MAX_RX_RINGS]; - /* Only used to synchronize netif_stop_queue/wake_queue when tx */ - /* ring is full */ - spinlock_t tx_lock; + /* TX constants */ + struct tx_bd *tx_desc_ring; + struct sw_bd *tx_buf_ring; + int tx_ring_size; + u32 tx_wake_thresh; /* End of fields used in the performance code paths. */ -- cgit v1.1 From 932f3772cf76cc1b1fd1538ceee3edba9bf2164f Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Tue, 15 Aug 2006 01:39:36 -0700 Subject: [BNX2]: Convert to netdev_alloc_skb() Convert dev_alloc_skb() to netdev_alloc_skb() and increase default rx ring size to 255. The old ring size of 100 was too small. Update version to 1.4.44. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 2099edb..652eb05 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -56,8 +56,8 @@ #define DRV_MODULE_NAME "bnx2" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "1.4.43" -#define DRV_MODULE_RELDATE "June 28, 2006" +#define DRV_MODULE_VERSION "1.4.44" +#define DRV_MODULE_RELDATE "August 10, 2006" #define RUN_AT(x) (jiffies + (x)) @@ -1571,7 +1571,7 @@ bnx2_alloc_rx_skb(struct bnx2 *bp, u16 index) struct rx_bd *rxbd = &bp->rx_desc_ring[RX_RING(index)][RX_IDX(index)]; unsigned long align; - skb = dev_alloc_skb(bp->rx_buf_size); + skb = netdev_alloc_skb(bp->dev, bp->rx_buf_size); if (skb == NULL) { return -ENOMEM; } @@ -1580,7 +1580,6 @@ bnx2_alloc_rx_skb(struct bnx2 *bp, u16 index) skb_reserve(skb, 8 - align); } - skb->dev = bp->dev; mapping = pci_map_single(bp->pdev, skb->data, bp->rx_buf_use_size, PCI_DMA_FROMDEVICE); @@ -1793,7 +1792,7 @@ bnx2_rx_int(struct bnx2 *bp, int budget) if ((bp->dev->mtu > 1500) && (len <= RX_COPY_THRESH)) { struct sk_buff *new_skb; - new_skb = dev_alloc_skb(len + 2); + new_skb = netdev_alloc_skb(bp->dev, len + 2); if (new_skb == NULL) goto reuse_rx; @@ -1804,7 +1803,6 @@ bnx2_rx_int(struct bnx2 *bp, int budget) skb_reserve(new_skb, 2); skb_put(new_skb, len); - new_skb->dev = bp->dev; bnx2_reuse_rx_skb(bp, skb, sw_ring_cons, sw_ring_prod); @@ -3961,7 +3959,7 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode) return -EINVAL; pkt_size = 1514; - skb = dev_alloc_skb(pkt_size); + skb = netdev_alloc_skb(bp->dev, pkt_size); if (!skb) return -ENOMEM; packet = skb_put(skb, pkt_size); @@ -5754,7 +5752,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) bp->mac_addr[5] = (u8) reg; bp->tx_ring_size = MAX_TX_DESC_CNT; - bnx2_set_rx_ring_size(bp, 100); + bnx2_set_rx_ring_size(bp, 255); bp->rx_csum = 1; -- cgit v1.1 From d4274b51a5c8147b5341e15927368e75b632d297 Mon Sep 17 00:00:00 2001 From: Panagiotis Issaris Date: Tue, 15 Aug 2006 16:01:07 -0700 Subject: [PPP]: handle kmalloc failures and convert to using kzalloc The PPP code contains two kmalloc()s followed by memset()s without handling a possible memory allocation failure. (Suggested by Joe Perches). And furthermore, conversions from kmalloc+memset to kzalloc. [akpm@osdl.org: fix error-path leak] [akpm@osdl.org: cleanups] [paulus@samba.org: don't add useless printk and cardmap_destroy calls] Signed-off-by: Panagiotis Issaris Signed-off-by: Andrew Morton Signed-off-by: Paul Mackerras Signed-off-by: David S. Miller --- drivers/net/ppp_generic.c | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index 0ec6e9d..c872f7c 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c @@ -192,7 +192,7 @@ struct cardmap { void *ptr[CARDMAP_WIDTH]; }; static void *cardmap_get(struct cardmap *map, unsigned int nr); -static void cardmap_set(struct cardmap **map, unsigned int nr, void *ptr); +static int cardmap_set(struct cardmap **map, unsigned int nr, void *ptr); static unsigned int cardmap_find_first_free(struct cardmap *map); static void cardmap_destroy(struct cardmap **map); @@ -1995,10 +1995,9 @@ ppp_register_channel(struct ppp_channel *chan) { struct channel *pch; - pch = kmalloc(sizeof(struct channel), GFP_KERNEL); + pch = kzalloc(sizeof(struct channel), GFP_KERNEL); if (pch == 0) return -ENOMEM; - memset(pch, 0, sizeof(struct channel)); pch->ppp = NULL; pch->chan = chan; chan->ppp = pch; @@ -2408,13 +2407,12 @@ ppp_create_interface(int unit, int *retp) int ret = -ENOMEM; int i; - ppp = kmalloc(sizeof(struct ppp), GFP_KERNEL); + ppp = kzalloc(sizeof(struct ppp), GFP_KERNEL); if (!ppp) goto out; dev = alloc_netdev(0, "", ppp_setup); if (!dev) goto out1; - memset(ppp, 0, sizeof(struct ppp)); ppp->mru = PPP_MRU; init_ppp_file(&ppp->file, INTERFACE); @@ -2454,11 +2452,16 @@ ppp_create_interface(int unit, int *retp) } atomic_inc(&ppp_unit_count); - cardmap_set(&all_ppp_units, unit, ppp); + ret = cardmap_set(&all_ppp_units, unit, ppp); + if (ret != 0) + goto out3; + mutex_unlock(&all_ppp_mutex); *retp = 0; return ppp; +out3: + atomic_dec(&ppp_unit_count); out2: mutex_unlock(&all_ppp_mutex); free_netdev(dev); @@ -2695,7 +2698,7 @@ static void *cardmap_get(struct cardmap *map, unsigned int nr) return NULL; } -static void cardmap_set(struct cardmap **pmap, unsigned int nr, void *ptr) +static int cardmap_set(struct cardmap **pmap, unsigned int nr, void *ptr) { struct cardmap *p; int i; @@ -2704,8 +2707,9 @@ static void cardmap_set(struct cardmap **pmap, unsigned int nr, void *ptr) if (p == NULL || (nr >> p->shift) >= CARDMAP_WIDTH) { do { /* need a new top level */ - struct cardmap *np = kmalloc(sizeof(*np), GFP_KERNEL); - memset(np, 0, sizeof(*np)); + struct cardmap *np = kzalloc(sizeof(*np), GFP_KERNEL); + if (!np) + goto enomem; np->ptr[0] = p; if (p != NULL) { np->shift = p->shift + CARDMAP_ORDER; @@ -2719,8 +2723,9 @@ static void cardmap_set(struct cardmap **pmap, unsigned int nr, void *ptr) while (p->shift > 0) { i = (nr >> p->shift) & CARDMAP_MASK; if (p->ptr[i] == NULL) { - struct cardmap *np = kmalloc(sizeof(*np), GFP_KERNEL); - memset(np, 0, sizeof(*np)); + struct cardmap *np = kzalloc(sizeof(*np), GFP_KERNEL); + if (!np) + goto enomem; np->shift = p->shift - CARDMAP_ORDER; np->parent = p; p->ptr[i] = np; @@ -2735,6 +2740,9 @@ static void cardmap_set(struct cardmap **pmap, unsigned int nr, void *ptr) set_bit(i, &p->inuse); else clear_bit(i, &p->inuse); + return 0; + enomem: + return -ENOMEM; } static unsigned int cardmap_find_first_free(struct cardmap *map) -- cgit v1.1 From 5beba53230351b2d77c317c22e66c415f2ebaf02 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Fri, 18 Aug 2006 10:41:46 -0700 Subject: IB/mthca: No userspace SRQs if HCA doesn't have SRQ support Leave all SRQ methods out of the device's uverbs_cmd_mask if the device doesn't have SRQ support (because of ancient firmware) so that we don't allow userspace to call the driver's create_srq method. This fixes a userspace-triggerable oops caused by ib_uverbs_create_srq() following the device's ->create_srq function pointer, which will be NULL if the device doesn't support SRQs. Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_provider.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c index 230ae21..265b1d1 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.c +++ b/drivers/infiniband/hw/mthca/mthca_provider.c @@ -1287,11 +1287,7 @@ int mthca_register_device(struct mthca_dev *dev) (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_QUERY_SRQ) | - (1ull << IB_USER_VERBS_CMD_DESTROY_SRQ); + (1ull << IB_USER_VERBS_CMD_DETACH_MCAST); 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; @@ -1316,6 +1312,11 @@ int mthca_register_device(struct mthca_dev *dev) dev->ib_dev.modify_srq = mthca_modify_srq; dev->ib_dev.query_srq = mthca_query_srq; dev->ib_dev.destroy_srq = mthca_destroy_srq; + dev->ib_dev.uverbs_cmd_mask |= + (1ull << IB_USER_VERBS_CMD_CREATE_SRQ) | + (1ull << IB_USER_VERBS_CMD_MODIFY_SRQ) | + (1ull << IB_USER_VERBS_CMD_QUERY_SRQ) | + (1ull << IB_USER_VERBS_CMD_DESTROY_SRQ); if (mthca_is_memfree(dev)) dev->ib_dev.post_srq_recv = mthca_arbel_post_srq_recv; -- cgit v1.1 From 33ccf8d1080bdccb4751a92f6da361a6e01b7cc0 Mon Sep 17 00:00:00 2001 From: James Smart Date: Thu, 17 Aug 2006 11:57:58 -0400 Subject: [SCSI] lpfc 8.1.9 : Misc Bug Fixes Misc Bug Fixes: - Cap MBX_DOWN_LINK command timeout to 60 seconds - Fix double free of ndlp object - Don't free mbox structures on error. The completion handlers expect to do so. - Clear host attention work items when going offline - Fixed discovery issues in multi-initiator environments. Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_attr.c | 2 +- drivers/scsi/lpfc/lpfc_els.c | 15 ++++++++++++--- drivers/scsi/lpfc/lpfc_hbadisc.c | 3 +++ drivers/scsi/lpfc/lpfc_init.c | 1 + drivers/scsi/lpfc/lpfc_nportdisc.c | 22 +++++++++++++++++++++- 5 files changed, 38 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 76f8bd5..d384c16 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -222,7 +222,7 @@ lpfc_issue_lip(struct Scsi_Host *host) pmboxq->mb.mbxCommand = MBX_DOWN_LINK; pmboxq->mb.mbxOwner = OWN_HOST; - mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2); + mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, LPFC_MBOX_TMO * 2); if ((mbxstatus == MBX_SUCCESS) && (pmboxq->mb.mbxStatus == 0)) { memset((void *)pmboxq, 0, sizeof (LPFC_MBOXQ_t)); diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 60f5cca..3567de61 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -1848,9 +1848,12 @@ static void lpfc_cmpl_els_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, struct lpfc_iocbq * rspiocb) { + IOCB_t *irsp; struct lpfc_nodelist *ndlp; LPFC_MBOXQ_t *mbox = NULL; + irsp = &rspiocb->iocb; + ndlp = (struct lpfc_nodelist *) cmdiocb->context1; if (cmdiocb->context_un.mbox) mbox = cmdiocb->context_un.mbox; @@ -1893,9 +1896,15 @@ lpfc_cmpl_els_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, mempool_free( mbox, phba->mbox_mem_pool); } else { mempool_free( mbox, phba->mbox_mem_pool); - if (ndlp->nlp_flag & NLP_ACC_REGLOGIN) { - lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); - ndlp = NULL; + /* Do not call NO_LIST for lpfc_els_abort'ed ELS cmds */ + if (!((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) && + ((irsp->un.ulpWord[4] == IOERR_SLI_ABORTED) || + (irsp->un.ulpWord[4] == IOERR_LINK_DOWN) || + (irsp->un.ulpWord[4] == IOERR_SLI_DOWN)))) { + if (ndlp->nlp_flag & NLP_ACC_REGLOGIN) { + lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); + ndlp = NULL; + } } } } diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 1c3f268..b2f1552 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -1557,6 +1557,8 @@ lpfc_freenode(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; } } + + spin_lock_irq(phba->host->host_lock); list_for_each_entry_safe(mb, nextmb, &phba->sli.mboxq, list) { if ((mb->mb.mbxCommand == MBX_REG_LOGIN64) && (ndlp == (struct lpfc_nodelist *) mb->context2)) { @@ -1569,6 +1571,7 @@ lpfc_freenode(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) mempool_free(mb, phba->mbox_mem_pool); } } + spin_unlock_irq(phba->host->host_lock); lpfc_els_abort(phba,ndlp,0); spin_lock_irq(phba->host->host_lock); diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 16dc8c8..f6948ff 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -1379,6 +1379,7 @@ lpfc_offline(struct lpfc_hba * phba) /* stop all timers associated with this hba */ lpfc_stop_timer(phba); phba->work_hba_events = 0; + phba->work_ha = 0; lpfc_printf_log(phba, KERN_WARNING, diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index b38021a..20449a8 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -393,6 +393,20 @@ lpfc_rcv_plogi(struct lpfc_hba * phba, mbox->context2 = ndlp; ndlp->nlp_flag |= (NLP_ACC_REGLOGIN | NLP_RCV_PLOGI); + /* + * If there is an outstanding PLOGI issued, abort it before + * sending ACC rsp for received PLOGI. If pending plogi + * is not canceled here, the plogi will be rejected by + * remote port and will be retried. On a configuration with + * single discovery thread, this will cause a huge delay in + * discovery. Also this will cause multiple state machines + * running in parallel for this node. + */ + if (ndlp->nlp_state == NLP_STE_PLOGI_ISSUE) { + /* software abort outstanding PLOGI */ + lpfc_els_abort(phba, ndlp, 1); + } + lpfc_els_rsp_acc(phba, ELS_CMD_PLOGI, cmdiocb, ndlp, mbox, 0); return 1; @@ -1601,7 +1615,13 @@ lpfc_rcv_padisc_npr_node(struct lpfc_hba * phba, lpfc_rcv_padisc(phba, ndlp, cmdiocb); - if (!(ndlp->nlp_flag & NLP_DELAY_TMO)) { + /* + * Do not start discovery if discovery is about to start + * or discovery in progress for this node. Starting discovery + * here will affect the counting of discovery threads. + */ + if ((!(ndlp->nlp_flag & NLP_DELAY_TMO)) && + (ndlp->nlp_flag & NLP_NPR_2B_DISC)){ if (ndlp->nlp_flag & NLP_NPR_ADISC) { ndlp->nlp_prev_state = NLP_STE_NPR_NODE; ndlp->nlp_state = NLP_STE_ADISC_ISSUE; -- cgit v1.1 From a90f56847e8df9034c1c05d1157e1b0cd96987fb Mon Sep 17 00:00:00 2001 From: James Smart Date: Thu, 17 Aug 2006 11:58:04 -0400 Subject: [SCSI] lpfc 8.1.9 : Stall eh handlers if resetting while rport blocked Stall error handler if attempting resets/aborts while an rport is blocked. This avoids device offline scenarios due to errors in the error handler. Background: Although the transport is using the scsi_timed_out functionality to restart the timeout if the rport is blocked, if the timeout has already fired before the block occurs, the eh handler still runs and can take the device offline. Ultimately, this window cannot be resolved without significant work in the error handler thread. Christoph noted the first level of these issues when he noted the poor error response handling by the error thread. We found, under heavy load and error testing, that time window from when the scsi_times_out() adds the io to the queue to when the scsi_error_handler gets around to servicing it, can be in the several seconds range. In most cases, these test conditions are highly unusual, but possible. As a result, we're stalling the error handler in this race window so that we can avoid the device_offline transitions. Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_scsi.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 0811c82..a8816a8 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -841,6 +842,21 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)) return 0; } +static void +lpfc_block_error_handler(struct scsi_cmnd *cmnd) +{ + struct Scsi_Host *shost = cmnd->device->host; + struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device)); + + spin_lock_irq(shost->host_lock); + while (rport->port_state == FC_PORTSTATE_BLOCKED) { + spin_unlock_irq(shost->host_lock); + msleep(1000); + spin_lock_irq(shost->host_lock); + } + spin_unlock_irq(shost->host_lock); + return; +} static int lpfc_abort_handler(struct scsi_cmnd *cmnd) @@ -855,6 +871,7 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) unsigned int loop_count = 0; int ret = SUCCESS; + lpfc_block_error_handler(cmnd); spin_lock_irq(shost->host_lock); lpfc_cmd = (struct lpfc_scsi_buf *)cmnd->host_scribble; @@ -957,6 +974,7 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd) int ret = FAILED; int cnt, loopcnt; + lpfc_block_error_handler(cmnd); spin_lock_irq(shost->host_lock); /* * If target is not in a MAPPED state, delay the reset until @@ -1073,6 +1091,7 @@ lpfc_reset_bus_handler(struct scsi_cmnd *cmnd) int cnt, loopcnt; struct lpfc_scsi_buf * lpfc_cmd; + lpfc_block_error_handler(cmnd); spin_lock_irq(shost->host_lock); lpfc_cmd = lpfc_get_scsi_buf(phba); -- cgit v1.1 From 48e2691f9c3bd6719e773f0b883449f4cef39585 Mon Sep 17 00:00:00 2001 From: James Smart Date: Thu, 17 Aug 2006 11:58:11 -0400 Subject: [SCSI] lpfc 8.1.9 : Change version number to 8.1.9 Change version number to 8.1.9 Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index c7963f9..c7091ea 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -18,7 +18,7 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "8.1.8" +#define LPFC_DRIVER_VERSION "8.1.9" #define LPFC_DRIVER_NAME "lpfc" -- cgit v1.1 From 864fe05dfa4ff3e230acf3b4ccf878b6f22603c4 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 14 Aug 2006 22:59:57 -0700 Subject: [PATCH] 82596 section fixes WARNING: drivers/net/82596.o - Section mismatch: reference to .init.text:i82596_probe from .text between 'init_module' (at offset 0x141) and 'i596_add_cmd' Also nail a couple of crazy inlines. Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/82596.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/82596.c b/drivers/net/82596.c index 7e2ca95..257d3bc 100644 --- a/drivers/net/82596.c +++ b/drivers/net/82596.c @@ -899,7 +899,7 @@ memory_squeeze: } -static inline void i596_cleanup_cmd(struct net_device *dev, struct i596_private *lp) +static void i596_cleanup_cmd(struct net_device *dev, struct i596_private *lp) { struct i596_cmd *ptr; @@ -932,7 +932,8 @@ static inline void i596_cleanup_cmd(struct net_device *dev, struct i596_private lp->scb.cmd = I596_NULL; } -static inline void i596_reset(struct net_device *dev, struct i596_private *lp, int ioaddr) +static void i596_reset(struct net_device *dev, struct i596_private *lp, + int ioaddr) { unsigned long flags; @@ -1578,7 +1579,7 @@ static int debug = -1; module_param(debug, int, 0); MODULE_PARM_DESC(debug, "i82596 debug mask"); -int init_module(void) +int __init init_module(void) { if (debug >= 0) i596_debug = debug; @@ -1588,7 +1589,7 @@ int init_module(void) return 0; } -void cleanup_module(void) +void __exit cleanup_module(void) { unregister_netdev(dev_82596); #ifdef __mc68000__ -- cgit v1.1 From 62a87b8051ded3d1fcb89773c9febd1bb34d3cbd Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 14 Aug 2006 22:59:57 -0700 Subject: [PATCH] ac3200 section fixes WARNING: drivers/net/ac3200.o - Section mismatch: reference to .init.text: from .text between 'init_module' (at offset 0xf9) and 'ac_close_card' Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/ac3200.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ac3200.c b/drivers/net/ac3200.c index 7952dc6..0fbbcb7 100644 --- a/drivers/net/ac3200.c +++ b/drivers/net/ac3200.c @@ -370,8 +370,7 @@ MODULE_PARM_DESC(mem, "Memory base address(es)"); MODULE_DESCRIPTION("Ansel AC3200 EISA ethernet driver"); MODULE_LICENSE("GPL"); -int -init_module(void) +int __init init_module(void) { struct net_device *dev; int this_dev, found = 0; -- cgit v1.1 From 5f3bc456ce190a963a8816be5a318df9998f3bc5 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 14 Aug 2006 22:59:58 -0700 Subject: [PATCH] cops section fix WARNING: drivers/net/appletalk/cops.o - Section mismatch: reference to .init.text:cops_probe from .text between 'init_module' (at offset 0xae) and 'cops_rx' Cc: "David S. Miller" Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/appletalk/cops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/appletalk/cops.c b/drivers/net/appletalk/cops.c index 1d01ac0..ae7f828 100644 --- a/drivers/net/appletalk/cops.c +++ b/drivers/net/appletalk/cops.c @@ -1030,7 +1030,7 @@ module_param(io, int, 0); module_param(irq, int, 0); module_param(board_type, int, 0); -int init_module(void) +int __init init_module(void) { if (io == 0) printk(KERN_WARNING "%s: You shouldn't autoprobe with insmod\n", -- cgit v1.1 From e26c129a49a7a4990f362a9cdb3084198b4d9d7b Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 14 Aug 2006 22:59:59 -0700 Subject: [PATCH] cs89x0 section fix WARNING: drivers/net/cs89x0.o - Section mismatch: reference to .init.data:version from .text between 'init_module' (at offset 0x13d8) and 'net_get_stats' WARNING: drivers/net/cs89x0.o - Section mismatch: reference to .init.text: from .text between 'init_module' (at offset 0x1634) and 'net_get_stats' WARNING: drivers/net/cs89x0.o - Section mismatch: reference to .init.text: from .text between 'init_module' (at offset 0x1a1f) and 'net_get_stats' Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/cs89x0.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c index 47eecce..2dcca79b 100644 --- a/drivers/net/cs89x0.c +++ b/drivers/net/cs89x0.c @@ -1905,8 +1905,7 @@ MODULE_LICENSE("GPL"); */ -int -init_module(void) +int __init init_module(void) { struct net_device *dev = alloc_etherdev(sizeof(struct net_local)); struct net_local *lp; -- cgit v1.1 From 5d930108c914c04fbb0bfbb059d23a5fcaf0d1e7 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 14 Aug 2006 22:59:59 -0700 Subject: [PATCH] at1700 section fix WARNING: drivers/net/at1700.o - Section mismatch: reference to .init.text:at1700_probe from .text between 'init_module' (at offset 0x75) and 'net_get_stats' Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/at1700.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c index 5d7929c7..4ca061c 100644 --- a/drivers/net/at1700.c +++ b/drivers/net/at1700.c @@ -901,7 +901,7 @@ MODULE_PARM_DESC(io, "AT1700/FMV18X I/O base address"); MODULE_PARM_DESC(irq, "AT1700/FMV18X IRQ number"); MODULE_PARM_DESC(net_debug, "AT1700/FMV18X debug level (0-6)"); -int init_module(void) +int __init init_module(void) { if (io == 0) printk("at1700: You should not use auto-probing with insmod!\n"); -- cgit v1.1 From d543cbb6d192313d9027ed09c7a1e085b1234082 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 14 Aug 2006 23:00:00 -0700 Subject: [PATCH] e2100 section fix WARNING: drivers/net/e2100.o - Section mismatch: reference to .init.text: from .text between 'init_module' (at offset 0xd9) and 'e21_reset_8390' Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/e2100.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/e2100.c b/drivers/net/e2100.c index e5c5cd2..e4e733a 100644 --- a/drivers/net/e2100.c +++ b/drivers/net/e2100.c @@ -425,8 +425,8 @@ MODULE_LICENSE("GPL"); /* This is set up so that only a single autoprobe takes place per call. ISA device autoprobes on a running machine are not recommended. */ -int -init_module(void) + +int __init init_module(void) { struct net_device *dev; int this_dev, found = 0; -- cgit v1.1 From 02a3245fcf0911ff92100aa54823dc1c5950fba9 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 14 Aug 2006 23:00:01 -0700 Subject: [PATCH] eepro section fix WARNING: drivers/net/eepro.o - Section mismatch: reference to .init.text: from .text between 'init_module' (at offset 0x284) and 'eepro_ethtool_get_drvinfo' WARNING: drivers/net/eepro.o - Section mismatch: reference to .init.text: from .text between 'init_module' (at offset 0x2a7) and 'eepro_ethtool_get_drvinfo' WARNING: drivers/net/eepro.o - Section mismatch: reference to .init.data:eepro_portlist from .text between 'init_module' (at offset 0x2b3) and 'eepro_ethtool_get_drvinfo' Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/eepro.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c index 20d3143..8dc61d6 100644 --- a/drivers/net/eepro.c +++ b/drivers/net/eepro.c @@ -1807,8 +1807,7 @@ MODULE_PARM_DESC(irq, "EtherExpress Pro/10 IRQ number(s)"); MODULE_PARM_DESC(mem, "EtherExpress Pro/10 Rx buffer size(es) in kB (3-29)"); MODULE_PARM_DESC(autodetect, "EtherExpress Pro/10 force board(s) detection (0-1)"); -int -init_module(void) +int __init init_module(void) { struct net_device *dev; int i; -- cgit v1.1 From b1176b95b4b851b05a2f541ef54e7ce3ed358d19 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 14 Aug 2006 23:00:01 -0700 Subject: [PATCH] eexpress section fix WARNING: drivers/net/eexpress.o - Section mismatch: reference to .init.text: from .text between 'init_module' (at offset 0x6c3) and 'eexp_hw_lasttxstat' WARNING: drivers/net/eexpress.o - Section mismatch: reference to .init.text: from .text between 'init_module' (at offset 0x74f) and 'eexp_hw_lasttxstat' Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/eexpress.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c index 33291bc..0701c1d 100644 --- a/drivers/net/eexpress.c +++ b/drivers/net/eexpress.c @@ -1698,7 +1698,7 @@ MODULE_LICENSE("GPL"); * are specified, we verify and then use them. If no parameters are given, we * autoprobe for one card only. */ -int init_module(void) +int __init init_module(void) { struct net_device *dev; int this_dev, found = 0; -- cgit v1.1 From 5757f5c6d7d9cbe4bf6a464f1842a767f505d440 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 14 Aug 2006 23:00:02 -0700 Subject: [PATCH] es3210 section fix WARNING: drivers/net/es3210.o - Section mismatch: reference to .init.text: from .text between 'init_module' (at offset 0xdf) and 'es_close' WARNING: drivers/net/es3210.o - Section mismatch: reference to .init.text: from .text between 'init_module' (at offset 0x100) and 'es_close' Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/es3210.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/es3210.c b/drivers/net/es3210.c index 6b0ab1e..fd7b32a 100644 --- a/drivers/net/es3210.c +++ b/drivers/net/es3210.c @@ -421,8 +421,7 @@ MODULE_PARM_DESC(mem, "memory base address(es)"); MODULE_DESCRIPTION("Racal-Interlan ES3210 EISA ethernet driver"); MODULE_LICENSE("GPL"); -int -init_module(void) +int __init init_module(void) { struct net_device *dev; int this_dev, found = 0; -- cgit v1.1 From 58f149fc65ebced1148789cfb37457a8c7aaca75 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 14 Aug 2006 23:00:03 -0700 Subject: [PATCH] eth16i section fix WARNING: drivers/net/eth16i.o - Section mismatch: reference to .init.data:cardname from .text between 'init_module' (at offset 0x6d2) and 'eth16i_multicast' WARNING: drivers/net/eth16i.o - Section mismatch: reference to .init.text: from .text between 'init_module' (at offset 0x6ef) and 'eth16i_multicast' WARNING: drivers/net/eth16i.o - Section mismatch: reference to .init.text: from .text between 'init_module' (at offset 0x702) and 'eth16i_multicast' WARNING: drivers/net/eth16i.o - Section mismatch: reference to .init.data:cardname from .text between 'init_module' (at offset 0x70e) and 'eth16i_multicast' WARNING: drivers/net/eth16i.o - Section mismatch: reference to .init.text: from .text between 'init_module' (at offset 0x71d) and 'eth16i_multicast' WARNING: drivers/net/eth16i.o - Section mismatch: reference to .init.data:cardname from .text between 'init_module' (at offset 0x729) and 'eth16i_multicast' Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/eth16i.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/eth16i.c b/drivers/net/eth16i.c index 4bf76f8..ca42efa 100644 --- a/drivers/net/eth16i.c +++ b/drivers/net/eth16i.c @@ -1434,7 +1434,7 @@ MODULE_PARM_DESC(mediatype, "eth16i media type of interface(s) (bnc,tp,dix,auto, module_param(debug, int, 0); MODULE_PARM_DESC(debug, "eth16i debug level (0-6)"); -int init_module(void) +int __init init_module(void) { int this_dev, found = 0; struct net_device *dev; -- cgit v1.1 From 3805f0e28ca313893b87e881201561d5c1857dd8 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 14 Aug 2006 23:00:03 -0700 Subject: [PATCH] lance section fix WARNING: drivers/net/lance.o - Section mismatch: reference to .init.data:lance_portlist from .text between 'init_module' (at offset 0x8d3) and 'lance_purge_ring' Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/lance.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/lance.c b/drivers/net/lance.c index c1c3452..5b4dbfe5 100644 --- a/drivers/net/lance.c +++ b/drivers/net/lance.c @@ -326,7 +326,7 @@ MODULE_PARM_DESC(dma, "LANCE/PCnet ISA DMA channel (ignored for some devices)"); MODULE_PARM_DESC(irq, "LANCE/PCnet IRQ number (ignored for some devices)"); MODULE_PARM_DESC(lance_debug, "LANCE/PCnet debug level (0-7)"); -int init_module(void) +int __init init_module(void) { struct net_device *dev; int this_dev, found = 0; -- cgit v1.1 From dab3d02ec05d16aab680de471cb5d20c5d4852e8 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 14 Aug 2006 23:00:04 -0700 Subject: [PATCH] lne390 section fix WARNING: drivers/net/lne390.o - Section mismatch: reference to .init.text: from .text between 'init_module' (at offset 0x100) and 'lne390_close' Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/lne390.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/lne390.c b/drivers/net/lne390.c index 646e89f..c0ec7f6 100644 --- a/drivers/net/lne390.c +++ b/drivers/net/lne390.c @@ -406,7 +406,7 @@ MODULE_PARM_DESC(mem, "memory base address(es)"); MODULE_DESCRIPTION("Mylex LNE390A/B EISA Ethernet driver"); MODULE_LICENSE("GPL"); -int init_module(void) +int __init init_module(void) { struct net_device *dev; int this_dev, found = 0; -- cgit v1.1 From 19a8664d8a05f75cab3cd4eb8022d22d3f0c53c3 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 14 Aug 2006 23:00:05 -0700 Subject: [PATCH] ni52 section fix WARNING: drivers/net/ni52.o - Section mismatch: reference to .init.text:ni52_probe from .text between 'init_module' (at offset 0x997) and 'ni52_close' WARNING: drivers/net/ni65.o - Section mismatch: reference to .init.text:ni65_probe from .text between 'init_module' (at offset 0x54a) and 'ni65_stop_start' Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/ni52.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ni52.c b/drivers/net/ni52.c index fa854c8..4d52ecf 100644 --- a/drivers/net/ni52.c +++ b/drivers/net/ni52.c @@ -1323,7 +1323,7 @@ MODULE_PARM_DESC(irq, "NI5210 IRQ number,required"); MODULE_PARM_DESC(memstart, "NI5210 memory base address,required"); MODULE_PARM_DESC(memend, "NI5210 memory end address,required"); -int init_module(void) +int __init init_module(void) { if(io <= 0x0 || !memend || !memstart || irq < 2) { printk("ni52: Autoprobing not allowed for modules.\nni52: Set symbols 'io' 'irq' 'memstart' and 'memend'\n"); -- cgit v1.1 From 6d2cdb4fd1cc1b15ad070a57c9b2bc40bb1565e7 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 14 Aug 2006 23:00:05 -0700 Subject: [PATCH] ibmtr section fix WARNING: drivers/net/tokenring/ibmtr.o - Section mismatch: reference to .init.data:ibmtr_mem_base from .text between 'ibmtr_probe1' (at offset 0x6e6) and 'ibmtr_probe_card' WARNING: drivers/net/tokenring/ibmtr.o - Section mismatch: reference to .init.data:ibmtr_mem_base from .text between 'ibmtr_probe1' (at offset 0x74a) and 'ibmtr_probe_card' WARNING: drivers/net/tokenring/ibmtr.o - Section mismatch: reference to .init.data:ibmtr_mem_base from .text between 'ibmtr_probe1' (at offset 0x7fd) and 'ibmtr_probe_card' Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/tokenring/ibmtr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tokenring/ibmtr.c b/drivers/net/tokenring/ibmtr.c index 9f49156..4470025 100644 --- a/drivers/net/tokenring/ibmtr.c +++ b/drivers/net/tokenring/ibmtr.c @@ -140,7 +140,7 @@ in the event that chatty debug messages are desired - jjs 12/30/98 */ /* version and credits */ #ifndef PCMCIA -static char version[] __initdata = +static char version[] __devinitdata = "\nibmtr.c: v1.3.57 8/ 7/94 Peter De Schrijver and Mark Swanson\n" " v2.1.125 10/20/98 Paul Norton \n" " v2.2.0 12/30/98 Joel Sloan \n" @@ -216,7 +216,7 @@ static int __devinitdata turbo_irq[IBMTR_MAX_ADAPTERS] = {0}; static int __devinitdata turbo_searched = 0; #ifndef PCMCIA -static __u32 ibmtr_mem_base __initdata = 0xd0000; +static __u32 ibmtr_mem_base __devinitdata = 0xd0000; #endif static void __devinit PrtChanID(char *pcid, short stride) -- cgit v1.1 From daca7cd7612639848c39744e02dab537755b31a1 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 14 Aug 2006 23:00:06 -0700 Subject: [PATCH] smctr section fix WARNING: drivers/net/tokenring/smctr.o - Section mismatch: reference to .init.text: from .text between 'init_module' (at offset 0x2ba0) and 'smctr_reset_adapter' WARNING: drivers/net/tokenring/smctr.o - Section mismatch: reference to .init.text:smctr_probe from .text between 'init_module' (at offset 0x2bf4) and 'smctr_reset_adapter' Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/tokenring/smctr.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tokenring/smctr.c b/drivers/net/tokenring/smctr.c index cd2e025..85a7f79 100644 --- a/drivers/net/tokenring/smctr.c +++ b/drivers/net/tokenring/smctr.c @@ -5666,7 +5666,7 @@ module_param_array(io, int, NULL, 0); module_param_array(irq, int, NULL, 0); module_param(ringspeed, int, 0); -static struct net_device *setup_card(int n) +static struct net_device * __init setup_card(int n) { struct net_device *dev = alloc_trdev(sizeof(struct net_local)); int err; @@ -5696,9 +5696,8 @@ out: free_netdev(dev); return ERR_PTR(err); } - -int init_module(void) +int __init init_module(void) { int i, found = 0; struct net_device *dev; -- cgit v1.1 From 5e5fa01d55e9949660a89b23f4a43884eaf49097 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 14 Aug 2006 23:00:06 -0700 Subject: [PATCH] wd section fix WARNING: drivers/net/wd.o - Section mismatch: reference to .init.text: from .text between 'init_module' (at offset 0xfd) and 'wd_open' WARNING: drivers/net/wd.o - Section mismatch: reference to .init.text: from .text between 'init_module' (at offset 0x14b) and 'wd_open' WARNING: drivers/net/wd.o - Section mismatch: reference to .init.data:wd_portlist from .text between 'init_module' (at offset 0x17f) and 'wd_open' Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/wd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wd.c b/drivers/net/wd.c index 7caa8dc..b1ba187 100644 --- a/drivers/net/wd.c +++ b/drivers/net/wd.c @@ -500,8 +500,8 @@ MODULE_LICENSE("GPL"); /* This is set up so that only a single autoprobe takes place per call. ISA device autoprobes on a running machine are not recommended. */ -int -init_module(void) + +int __init init_module(void) { struct net_device *dev; int this_dev, found = 0; -- cgit v1.1 From 1e13b0d82d24ac3c8b2f16a09dd9ce537cad134c Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 14 Aug 2006 23:00:07 -0700 Subject: [PATCH] ni65 section fix WARNING: drivers/net/ni65.o - Section mismatch: reference to .init.text:ni65_probe from .text between 'init_module' (at offset 0x54a) and 'ni65_stop_start' Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/ni65.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ni65.c b/drivers/net/ni65.c index bb42ff2..810cc57 100644 --- a/drivers/net/ni65.c +++ b/drivers/net/ni65.c @@ -1253,7 +1253,7 @@ MODULE_PARM_DESC(irq, "ni6510 IRQ number (ignored for some cards)"); MODULE_PARM_DESC(io, "ni6510 I/O base address"); MODULE_PARM_DESC(dma, "ni6510 ISA DMA channel (ignored for some cards)"); -int init_module(void) +int __init init_module(void) { dev_ni65 = ni65_probe(-1); return IS_ERR(dev_ni65) ? PTR_ERR(dev_ni65) : 0; -- cgit v1.1 From c971ef46cb94b8bb4a12555fa757e5f67934fcd9 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 14 Aug 2006 23:00:08 -0700 Subject: [PATCH] seeq8005 section fix WARNING: drivers/net/seeq8005.o - Section mismatch: reference to .init.text:seeq8005_probe from .text between 'init_module' (at offset 0x106) and 'seeq8005_open' Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/seeq8005.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/seeq8005.c b/drivers/net/seeq8005.c index efd0f23..01392bc 100644 --- a/drivers/net/seeq8005.c +++ b/drivers/net/seeq8005.c @@ -742,7 +742,7 @@ module_param(irq, int, 0); MODULE_PARM_DESC(io, "SEEQ 8005 I/O base address"); MODULE_PARM_DESC(irq, "SEEQ 8005 IRQ number"); -int init_module(void) +int __init init_module(void) { dev_seeq = seeq8005_probe(-1); if (IS_ERR(dev_seeq)) -- cgit v1.1 From c9d26c9785d900d8547b268f0c0507f252879c48 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 14 Aug 2006 23:00:08 -0700 Subject: [PATCH] winbond-840 section fix With CONFIG_HOTPLUG=n it won't compile: drivers/net/tulip/winbond-840.c:141: error: version causes a section type conflict (For some reason it gets the same error if marked __initdata. Give up.) Cc: Valerie Henson Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/tulip/winbond-840.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c index 7f41481..eba9083 100644 --- a/drivers/net/tulip/winbond-840.c +++ b/drivers/net/tulip/winbond-840.c @@ -138,7 +138,7 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; #include /* These identify the driver base version and may not be removed. */ -static char version[] __devinitdata = +static char version[] = KERN_INFO DRV_NAME ".c:v" DRV_VERSION " (2.4 port) " DRV_RELDATE " Donald Becker \n" KERN_INFO " http://www.scyld.com/network/drivers.html\n"; -- cgit v1.1 From 90d5aed2d9c7d2f3915b75342988114fd7b6c13d Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 14 Aug 2006 23:00:09 -0700 Subject: [PATCH] fealnx section fix With CONFIG_HOTPLUG=n it won't compile: distcc[25607] ERROR: compile drivers/net/fealnx.c on g5/64 failed version[] is referred to from both __init code and from __devinit code, so move it out of __init altogether. Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/fealnx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/fealnx.c b/drivers/net/fealnx.c index 97d34fe..567e274 100644 --- a/drivers/net/fealnx.c +++ b/drivers/net/fealnx.c @@ -92,7 +92,7 @@ static int full_duplex[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1 }; #include /* These identify the driver base version and may not be removed. */ -static char version[] __devinitdata = +static char version[] = KERN_INFO DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE "\n"; -- cgit v1.1 From 3418e469ebaebec16f7df83074087eb901fb76b9 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 14 Aug 2006 23:00:10 -0700 Subject: [PATCH] sundance section fix drivers/net/sundance.c:110: error: version causes a section type conflict I don't understand this error. It's referred to from both __init and __devinit code. With CONFIG_HOTPLUG=n, version[] is placed in .init.data and is referred to from .init.text. Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/sundance.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c index ac17377..698568e 100644 --- a/drivers/net/sundance.c +++ b/drivers/net/sundance.c @@ -107,7 +107,7 @@ static char *media[MAX_UNITS]; #endif /* These identify the driver base version and may not be removed. */ -static char version[] __devinitdata = +static char version[] = KERN_INFO DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " Written by Donald Becker\n" KERN_INFO " http://www.scyld.com/network/sundance.html\n"; -- cgit v1.1 From e4c780b1ffc7d7bc27b7dc57fcf17ebb8d3006bc Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Mon, 14 Aug 2006 23:00:10 -0700 Subject: [PATCH] drivers/net/e1000/: possible cleanups - make needlessly global functions static - #if 0 the following unused global functions: - e1000_hw.c: e1000_mc_addr_list_update() - e1000_hw.c: e1000_read_reg_io() - e1000_hw.c: e1000_enable_pciex_master() - e1000_hw.c: e1000_ife_disable_dynamic_power_down() - e1000_hw.c: e1000_ife_enable_dynamic_power_down() - e1000_hw.c: e1000_write_ich8_word() - e1000_hw.c: e1000_duplex_reversal() - e1000_main.c: e1000_io_read() Signed-off-by: Adrian Bunk Cc: John Ronciak Cc: Jesse Brandeburg Cc: Jeff Kirsher Cc: Auke Kok Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/e1000/e1000_hw.c | 89 ++++++++++++++++++++++++++++++------------ drivers/net/e1000/e1000_hw.h | 32 --------------- drivers/net/e1000/e1000_main.c | 2 + 3 files changed, 67 insertions(+), 56 deletions(-) (limited to 'drivers') diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c index 583518a..b3b9191 100644 --- a/drivers/net/e1000/e1000_hw.c +++ b/drivers/net/e1000/e1000_hw.c @@ -105,6 +105,33 @@ static int32_t e1000_configure_kmrn_for_10_100(struct e1000_hw *hw, uint16_t duplex); static int32_t e1000_configure_kmrn_for_1000(struct e1000_hw *hw); +static int32_t e1000_erase_ich8_4k_segment(struct e1000_hw *hw, + uint32_t segment); +static int32_t e1000_get_software_flag(struct e1000_hw *hw); +static int32_t e1000_get_software_semaphore(struct e1000_hw *hw); +static int32_t e1000_init_lcd_from_nvm(struct e1000_hw *hw); +static int32_t e1000_kumeran_lock_loss_workaround(struct e1000_hw *hw); +static int32_t e1000_read_eeprom_ich8(struct e1000_hw *hw, uint16_t offset, + uint16_t words, uint16_t *data); +static int32_t e1000_read_ich8_byte(struct e1000_hw *hw, uint32_t index, + uint8_t* data); +static int32_t e1000_read_ich8_word(struct e1000_hw *hw, uint32_t index, + uint16_t *data); +static int32_t e1000_read_kmrn_reg(struct e1000_hw *hw, uint32_t reg_addr, + uint16_t *data); +static void e1000_release_software_flag(struct e1000_hw *hw); +static void e1000_release_software_semaphore(struct e1000_hw *hw); +static int32_t e1000_set_pci_ex_no_snoop(struct e1000_hw *hw, + uint32_t no_snoop); +static int32_t e1000_verify_write_ich8_byte(struct e1000_hw *hw, + uint32_t index, uint8_t byte); +static int32_t e1000_write_eeprom_ich8(struct e1000_hw *hw, uint16_t offset, + uint16_t words, uint16_t *data); +static int32_t e1000_write_ich8_byte(struct e1000_hw *hw, uint32_t index, + uint8_t data); +static int32_t e1000_write_kmrn_reg(struct e1000_hw *hw, uint32_t reg_addr, + uint16_t data); + /* IGP cable length table */ static const uint16_t e1000_igp_cable_length_table[IGP01E1000_AGC_LENGTH_TABLE_SIZE] = @@ -3233,7 +3260,7 @@ e1000_shift_in_mdi_bits(struct e1000_hw *hw) return data; } -int32_t +static int32_t e1000_swfw_sync_acquire(struct e1000_hw *hw, uint16_t mask) { uint32_t swfw_sync = 0; @@ -3277,7 +3304,7 @@ e1000_swfw_sync_acquire(struct e1000_hw *hw, uint16_t mask) return E1000_SUCCESS; } -void +static void e1000_swfw_sync_release(struct e1000_hw *hw, uint16_t mask) { uint32_t swfw_sync; @@ -3575,7 +3602,7 @@ e1000_write_phy_reg_ex(struct e1000_hw *hw, return E1000_SUCCESS; } -int32_t +static int32_t e1000_read_kmrn_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t *data) @@ -3608,7 +3635,7 @@ e1000_read_kmrn_reg(struct e1000_hw *hw, return E1000_SUCCESS; } -int32_t +static int32_t e1000_write_kmrn_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t data) @@ -3839,7 +3866,7 @@ e1000_phy_powerdown_workaround(struct e1000_hw *hw) * * hw - struct containing variables accessed by shared code ******************************************************************************/ -int32_t +static int32_t e1000_kumeran_lock_loss_workaround(struct e1000_hw *hw) { int32_t ret_val; @@ -4086,7 +4113,7 @@ e1000_phy_igp_get_info(struct e1000_hw *hw, * hw - Struct containing variables accessed by shared code * phy_info - PHY information structure ******************************************************************************/ -int32_t +static int32_t e1000_phy_ife_get_info(struct e1000_hw *hw, struct e1000_phy_info *phy_info) { @@ -5643,6 +5670,7 @@ e1000_init_rx_addrs(struct e1000_hw *hw) * for the first 15 multicast addresses, and hashes the rest into the * multicast table. *****************************************************************************/ +#if 0 void e1000_mc_addr_list_update(struct e1000_hw *hw, uint8_t *mc_addr_list, @@ -5719,6 +5747,7 @@ e1000_mc_addr_list_update(struct e1000_hw *hw, } DEBUGOUT("MC Update Complete\n"); } +#endif /* 0 */ /****************************************************************************** * Hashes an address to determine its location in the multicast table @@ -6587,6 +6616,7 @@ e1000_get_bus_info(struct e1000_hw *hw) * hw - Struct containing variables accessed by shared code * offset - offset to read from *****************************************************************************/ +#if 0 uint32_t e1000_read_reg_io(struct e1000_hw *hw, uint32_t offset) @@ -6597,6 +6627,7 @@ e1000_read_reg_io(struct e1000_hw *hw, e1000_io_write(hw, io_addr, offset); return e1000_io_read(hw, io_data); } +#endif /* 0 */ /****************************************************************************** * Writes a value to one of the devices registers using port I/O (as opposed to @@ -7909,6 +7940,7 @@ e1000_set_pci_express_master_disable(struct e1000_hw *hw) * returns: - none. * ***************************************************************************/ +#if 0 void e1000_enable_pciex_master(struct e1000_hw *hw) { @@ -7923,6 +7955,7 @@ e1000_enable_pciex_master(struct e1000_hw *hw) ctrl &= ~E1000_CTRL_GIO_MASTER_DISABLE; E1000_WRITE_REG(hw, CTRL, ctrl); } +#endif /* 0 */ /******************************************************************************* * @@ -8148,7 +8181,7 @@ e1000_put_hw_eeprom_semaphore(struct e1000_hw *hw) * E1000_SUCCESS at any other case. * ***************************************************************************/ -int32_t +static int32_t e1000_get_software_semaphore(struct e1000_hw *hw) { int32_t timeout = hw->eeprom.word_size + 1; @@ -8183,7 +8216,7 @@ e1000_get_software_semaphore(struct e1000_hw *hw) * hw: Struct containing variables accessed by shared code * ***************************************************************************/ -void +static void e1000_release_software_semaphore(struct e1000_hw *hw) { uint32_t swsm; @@ -8265,7 +8298,7 @@ e1000_arc_subsystem_valid(struct e1000_hw *hw) * returns: E1000_SUCCESS * *****************************************************************************/ -int32_t +static int32_t e1000_set_pci_ex_no_snoop(struct e1000_hw *hw, uint32_t no_snoop) { uint32_t gcr_reg = 0; @@ -8306,7 +8339,7 @@ e1000_set_pci_ex_no_snoop(struct e1000_hw *hw, uint32_t no_snoop) * hw: Struct containing variables accessed by shared code * ***************************************************************************/ -int32_t +static int32_t e1000_get_software_flag(struct e1000_hw *hw) { int32_t timeout = PHY_CFG_TIMEOUT; @@ -8345,7 +8378,7 @@ e1000_get_software_flag(struct e1000_hw *hw) * hw: Struct containing variables accessed by shared code * ***************************************************************************/ -void +static void e1000_release_software_flag(struct e1000_hw *hw) { uint32_t extcnf_ctrl; @@ -8369,6 +8402,7 @@ e1000_release_software_flag(struct e1000_hw *hw) * hw: Struct containing variables accessed by shared code * ***************************************************************************/ +#if 0 int32_t e1000_ife_disable_dynamic_power_down(struct e1000_hw *hw) { @@ -8388,6 +8422,7 @@ e1000_ife_disable_dynamic_power_down(struct e1000_hw *hw) return ret_val; } +#endif /* 0 */ /*************************************************************************** * @@ -8397,6 +8432,7 @@ e1000_ife_disable_dynamic_power_down(struct e1000_hw *hw) * hw: Struct containing variables accessed by shared code * ***************************************************************************/ +#if 0 int32_t e1000_ife_enable_dynamic_power_down(struct e1000_hw *hw) { @@ -8416,6 +8452,7 @@ e1000_ife_enable_dynamic_power_down(struct e1000_hw *hw) return ret_val; } +#endif /* 0 */ /****************************************************************************** * Reads a 16 bit word or words from the EEPROM using the ICH8's flash access @@ -8426,7 +8463,7 @@ e1000_ife_enable_dynamic_power_down(struct e1000_hw *hw) * data - word read from the EEPROM * words - number of words to read *****************************************************************************/ -int32_t +static int32_t e1000_read_eeprom_ich8(struct e1000_hw *hw, uint16_t offset, uint16_t words, uint16_t *data) { @@ -8482,7 +8519,7 @@ e1000_read_eeprom_ich8(struct e1000_hw *hw, uint16_t offset, uint16_t words, * words - number of words to write * data - words to write to the EEPROM *****************************************************************************/ -int32_t +static int32_t e1000_write_eeprom_ich8(struct e1000_hw *hw, uint16_t offset, uint16_t words, uint16_t *data) { @@ -8529,7 +8566,7 @@ e1000_write_eeprom_ich8(struct e1000_hw *hw, uint16_t offset, uint16_t words, * * hw - The pointer to the hw structure ****************************************************************************/ -int32_t +static int32_t e1000_ich8_cycle_init(struct e1000_hw *hw) { union ich8_hws_flash_status hsfsts; @@ -8596,7 +8633,7 @@ e1000_ich8_cycle_init(struct e1000_hw *hw) * * hw - The pointer to the hw structure ****************************************************************************/ -int32_t +static int32_t e1000_ich8_flash_cycle(struct e1000_hw *hw, uint32_t timeout) { union ich8_hws_flash_ctrl hsflctl; @@ -8631,7 +8668,7 @@ e1000_ich8_flash_cycle(struct e1000_hw *hw, uint32_t timeout) * size - Size of data to read, 1=byte 2=word * data - Pointer to the word to store the value read. *****************************************************************************/ -int32_t +static int32_t e1000_read_ich8_data(struct e1000_hw *hw, uint32_t index, uint32_t size, uint16_t* data) { @@ -8710,7 +8747,7 @@ e1000_read_ich8_data(struct e1000_hw *hw, uint32_t index, * size - Size of data to read, 1=byte 2=word * data - The byte(s) to write to the NVM. *****************************************************************************/ -int32_t +static int32_t e1000_write_ich8_data(struct e1000_hw *hw, uint32_t index, uint32_t size, uint16_t data) { @@ -8785,7 +8822,7 @@ e1000_write_ich8_data(struct e1000_hw *hw, uint32_t index, uint32_t size, * index - The index of the byte to read. * data - Pointer to a byte to store the value read. *****************************************************************************/ -int32_t +static int32_t e1000_read_ich8_byte(struct e1000_hw *hw, uint32_t index, uint8_t* data) { int32_t status = E1000_SUCCESS; @@ -8808,7 +8845,7 @@ e1000_read_ich8_byte(struct e1000_hw *hw, uint32_t index, uint8_t* data) * index - The index of the byte to write. * byte - The byte to write to the NVM. *****************************************************************************/ -int32_t +static int32_t e1000_verify_write_ich8_byte(struct e1000_hw *hw, uint32_t index, uint8_t byte) { int32_t error = E1000_SUCCESS; @@ -8839,7 +8876,7 @@ e1000_verify_write_ich8_byte(struct e1000_hw *hw, uint32_t index, uint8_t byte) * index - The index of the byte to read. * data - The byte to write to the NVM. *****************************************************************************/ -int32_t +static int32_t e1000_write_ich8_byte(struct e1000_hw *hw, uint32_t index, uint8_t data) { int32_t status = E1000_SUCCESS; @@ -8857,7 +8894,7 @@ e1000_write_ich8_byte(struct e1000_hw *hw, uint32_t index, uint8_t data) * index - The starting byte index of the word to read. * data - Pointer to a word to store the value read. *****************************************************************************/ -int32_t +static int32_t e1000_read_ich8_word(struct e1000_hw *hw, uint32_t index, uint16_t *data) { int32_t status = E1000_SUCCESS; @@ -8872,6 +8909,7 @@ e1000_read_ich8_word(struct e1000_hw *hw, uint32_t index, uint16_t *data) * index - The starting byte index of the word to read. * data - The word to write to the NVM. *****************************************************************************/ +#if 0 int32_t e1000_write_ich8_word(struct e1000_hw *hw, uint32_t index, uint16_t data) { @@ -8879,6 +8917,7 @@ e1000_write_ich8_word(struct e1000_hw *hw, uint32_t index, uint16_t data) status = e1000_write_ich8_data(hw, index, 2, data); return status; } +#endif /* 0 */ /****************************************************************************** * Erases the bank specified. Each bank is a 4k block. Segments are 0 based. @@ -8887,7 +8926,7 @@ e1000_write_ich8_word(struct e1000_hw *hw, uint32_t index, uint16_t data) * hw - pointer to e1000_hw structure * segment - 0 for first segment, 1 for second segment, etc. *****************************************************************************/ -int32_t +static int32_t e1000_erase_ich8_4k_segment(struct e1000_hw *hw, uint32_t segment) { union ich8_hws_flash_status hsfsts; @@ -8984,6 +9023,7 @@ e1000_erase_ich8_4k_segment(struct e1000_hw *hw, uint32_t segment) * hw: Struct containing variables accessed by shared code * *****************************************************************************/ +#if 0 int32_t e1000_duplex_reversal(struct e1000_hw *hw) { @@ -9012,8 +9052,9 @@ e1000_duplex_reversal(struct e1000_hw *hw) return ret_val; } +#endif /* 0 */ -int32_t +static int32_t e1000_init_lcd_from_nvm_config_region(struct e1000_hw *hw, uint32_t cnf_base_addr, uint32_t cnf_size) { @@ -9047,7 +9088,7 @@ e1000_init_lcd_from_nvm_config_region(struct e1000_hw *hw, } -int32_t +static int32_t e1000_init_lcd_from_nvm(struct e1000_hw *hw) { uint32_t reg_data, cnf_base_addr, cnf_size, ret_val, loop; diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h index f9341e3..375b955 100644 --- a/drivers/net/e1000/e1000_hw.h +++ b/drivers/net/e1000/e1000_hw.h @@ -323,13 +323,8 @@ int32_t e1000_write_phy_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t dat int32_t e1000_phy_hw_reset(struct e1000_hw *hw); int32_t e1000_phy_reset(struct e1000_hw *hw); void e1000_phy_powerdown_workaround(struct e1000_hw *hw); -int32_t e1000_kumeran_lock_loss_workaround(struct e1000_hw *hw); -int32_t e1000_init_lcd_from_nvm_config_region(struct e1000_hw *hw, uint32_t cnf_base_addr, uint32_t cnf_size); -int32_t e1000_init_lcd_from_nvm(struct e1000_hw *hw); int32_t e1000_phy_get_info(struct e1000_hw *hw, struct e1000_phy_info *phy_info); int32_t e1000_validate_mdi_setting(struct e1000_hw *hw); -int32_t e1000_read_kmrn_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t *data); -int32_t e1000_write_kmrn_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t data); /* EEPROM Functions */ int32_t e1000_init_eeprom_params(struct e1000_hw *hw); @@ -400,13 +395,8 @@ int32_t e1000_update_eeprom_checksum(struct e1000_hw *hw); int32_t e1000_write_eeprom(struct e1000_hw *hw, uint16_t reg, uint16_t words, uint16_t *data); int32_t e1000_read_part_num(struct e1000_hw *hw, uint32_t * part_num); int32_t e1000_read_mac_addr(struct e1000_hw * hw); -int32_t e1000_swfw_sync_acquire(struct e1000_hw *hw, uint16_t mask); -void e1000_swfw_sync_release(struct e1000_hw *hw, uint16_t mask); -void e1000_release_software_flag(struct e1000_hw *hw); -int32_t e1000_get_software_flag(struct e1000_hw *hw); /* Filters (multicast, vlan, receive) */ -void e1000_mc_addr_list_update(struct e1000_hw *hw, uint8_t * mc_addr_list, uint32_t mc_addr_count, uint32_t pad, uint32_t rar_used_count); uint32_t e1000_hash_mc_addr(struct e1000_hw *hw, uint8_t * mc_addr); void e1000_mta_set(struct e1000_hw *hw, uint32_t hash_value); void e1000_rar_set(struct e1000_hw *hw, uint8_t * mc_addr, uint32_t rar_index); @@ -431,31 +421,9 @@ void e1000_pci_clear_mwi(struct e1000_hw *hw); void e1000_read_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t * value); void e1000_write_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t * value); /* Port I/O is only supported on 82544 and newer */ -uint32_t e1000_io_read(struct e1000_hw *hw, unsigned long port); -uint32_t e1000_read_reg_io(struct e1000_hw *hw, uint32_t offset); void e1000_io_write(struct e1000_hw *hw, unsigned long port, uint32_t value); -void e1000_enable_pciex_master(struct e1000_hw *hw); int32_t e1000_disable_pciex_master(struct e1000_hw *hw); -int32_t e1000_get_software_semaphore(struct e1000_hw *hw); -void e1000_release_software_semaphore(struct e1000_hw *hw); int32_t e1000_check_phy_reset_block(struct e1000_hw *hw); -int32_t e1000_set_pci_ex_no_snoop(struct e1000_hw *hw, uint32_t no_snoop); - -int32_t e1000_read_ich8_byte(struct e1000_hw *hw, uint32_t index, - uint8_t *data); -int32_t e1000_verify_write_ich8_byte(struct e1000_hw *hw, uint32_t index, - uint8_t byte); -int32_t e1000_write_ich8_byte(struct e1000_hw *hw, uint32_t index, - uint8_t byte); -int32_t e1000_read_ich8_word(struct e1000_hw *hw, uint32_t index, - uint16_t *data); -int32_t e1000_read_ich8_data(struct e1000_hw *hw, uint32_t index, - uint32_t size, uint16_t *data); -int32_t e1000_read_eeprom_ich8(struct e1000_hw *hw, uint16_t offset, - uint16_t words, uint16_t *data); -int32_t e1000_write_eeprom_ich8(struct e1000_hw *hw, uint16_t offset, - uint16_t words, uint16_t *data); -int32_t e1000_erase_ich8_4k_segment(struct e1000_hw *hw, uint32_t segment); #define E1000_READ_REG_IO(a, reg) \ diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 627f224..726f43d 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -4386,11 +4386,13 @@ e1000_write_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t *value) pci_write_config_word(adapter->pdev, reg, *value); } +#if 0 uint32_t e1000_io_read(struct e1000_hw *hw, unsigned long port) { return inl(port); } +#endif /* 0 */ void e1000_io_write(struct e1000_hw *hw, unsigned long port, uint32_t value) -- cgit v1.1 From ce973b141dfac4a0f160c7435d65e3ea47753ce8 Mon Sep 17 00:00:00 2001 From: Li Yang Date: Mon, 14 Aug 2006 23:00:11 -0700 Subject: [PATCH] Freescale QE UCC gigabit ethernet driver QE(QUICC Engine) is a new generation communication coprocessor, which can be found on some of the latest Freescale PowerQUICC CPUs(e.g. MPC8360). The UCC(Unified Communications Controller) module of QE can work as gigabit Ethernet device. This patch provides driver for the device. Signed-off-by: Shlomi Gridish Signed-off-by: Li Yang Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/Kconfig | 27 + drivers/net/Makefile | 3 + drivers/net/ucc_geth.c | 4278 ++++++++++++++++++++++++++++++++++++++++++++ drivers/net/ucc_geth.h | 1339 ++++++++++++++ drivers/net/ucc_geth_phy.c | 801 +++++++++ drivers/net/ucc_geth_phy.h | 217 +++ 6 files changed, 6665 insertions(+) create mode 100644 drivers/net/ucc_geth.c create mode 100644 drivers/net/ucc_geth.h create mode 100644 drivers/net/ucc_geth_phy.c create mode 100644 drivers/net/ucc_geth_phy.h (limited to 'drivers') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 3918990..ea1796e 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2219,6 +2219,33 @@ config GFAR_NAPI bool "NAPI Support" depends on GIANFAR +config UCC_GETH + tristate "Freescale QE UCC GETH" + depends on QUICC_ENGINE && UCC_FAST + help + This driver supports the Gigabit Ethernet mode of QE UCC. + QE can be found on MPC836x CPUs. + +config UGETH_NAPI + bool "NAPI Support" + depends on UCC_GETH + +config UGETH_MAGIC_PACKET + bool "Magic Packet detection support" + depends on UCC_GETH + +config UGETH_FILTERING + bool "Mac address filtering support" + depends on UCC_GETH + +config UGETH_TX_ON_DEMOND + bool "Transmit on Demond support" + depends on UCC_GETH + +config UGETH_HAS_GIGA + bool + depends on UCC_GETH && MPC836x + config MV643XX_ETH tristate "MV-643XX Ethernet support" depends on MOMENCO_OCELOT_C || MOMENCO_JAGUAR_ATX || MV64360 || MOMENCO_OCELOT_3 || PPC_MULTIPLATFORM diff --git a/drivers/net/Makefile b/drivers/net/Makefile index c91e951..8427bf9 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -18,6 +18,9 @@ gianfar_driver-objs := gianfar.o \ gianfar_mii.o \ gianfar_sysfs.o +obj-$(CONFIG_UCC_GETH) += ucc_geth_driver.o +ucc_geth_driver-objs := ucc_geth.o ucc_geth_phy.o + # # link order important here # diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c new file mode 100644 index 0000000..47f49ef --- /dev/null +++ b/drivers/net/ucc_geth.c @@ -0,0 +1,4278 @@ +/* + * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved. + * + * Author: Shlomi Gridish + * + * Description: + * QE UCC Gigabit Ethernet Driver + * + * Changelog: + * Jul 6, 2006 Li Yang + * - Rearrange code and style fixes + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "ucc_geth.h" +#include "ucc_geth_phy.h" + +#undef DEBUG + +#define DRV_DESC "QE UCC Gigabit Ethernet Controller version:June 20, 2006" +#define DRV_NAME "ucc_geth" + +#define ugeth_printk(level, format, arg...) \ + printk(level format "\n", ## arg) + +#define ugeth_dbg(format, arg...) \ + ugeth_printk(KERN_DEBUG , format , ## arg) +#define ugeth_err(format, arg...) \ + ugeth_printk(KERN_ERR , format , ## arg) +#define ugeth_info(format, arg...) \ + ugeth_printk(KERN_INFO , format , ## arg) +#define ugeth_warn(format, arg...) \ + ugeth_printk(KERN_WARNING , format , ## arg) + +#ifdef UGETH_VERBOSE_DEBUG +#define ugeth_vdbg ugeth_dbg +#else +#define ugeth_vdbg(fmt, args...) do { } while (0) +#endif /* UGETH_VERBOSE_DEBUG */ + +static DEFINE_SPINLOCK(ugeth_lock); + +static ucc_geth_info_t ugeth_primary_info = { + .uf_info = { + .bd_mem_part = MEM_PART_SYSTEM, + .rtsm = UCC_FAST_SEND_IDLES_BETWEEN_FRAMES, + .max_rx_buf_length = 1536, +/* FIXME: should be changed in run time for 1G and 100M */ +#ifdef CONFIG_UGETH_HAS_GIGA + .urfs = UCC_GETH_URFS_GIGA_INIT, + .urfet = UCC_GETH_URFET_GIGA_INIT, + .urfset = UCC_GETH_URFSET_GIGA_INIT, + .utfs = UCC_GETH_UTFS_GIGA_INIT, + .utfet = UCC_GETH_UTFET_GIGA_INIT, + .utftt = UCC_GETH_UTFTT_GIGA_INIT, +#else + .urfs = UCC_GETH_URFS_INIT, + .urfet = UCC_GETH_URFET_INIT, + .urfset = UCC_GETH_URFSET_INIT, + .utfs = UCC_GETH_UTFS_INIT, + .utfet = UCC_GETH_UTFET_INIT, + .utftt = UCC_GETH_UTFTT_INIT, +#endif + .ufpt = 256, + .mode = UCC_FAST_PROTOCOL_MODE_ETHERNET, + .ttx_trx = UCC_FAST_GUMR_TRANSPARENT_TTX_TRX_NORMAL, + .tenc = UCC_FAST_TX_ENCODING_NRZ, + .renc = UCC_FAST_RX_ENCODING_NRZ, + .tcrc = UCC_FAST_16_BIT_CRC, + .synl = UCC_FAST_SYNC_LEN_NOT_USED, + }, + .numQueuesTx = 1, + .numQueuesRx = 1, + .extendedFilteringChainPointer = ((uint32_t) NULL), + .typeorlen = 3072 /*1536 */ , + .nonBackToBackIfgPart1 = 0x40, + .nonBackToBackIfgPart2 = 0x60, + .miminumInterFrameGapEnforcement = 0x50, + .backToBackInterFrameGap = 0x60, + .mblinterval = 128, + .nortsrbytetime = 5, + .fracsiz = 1, + .strictpriorityq = 0xff, + .altBebTruncation = 0xa, + .excessDefer = 1, + .maxRetransmission = 0xf, + .collisionWindow = 0x37, + .receiveFlowControl = 1, + .maxGroupAddrInHash = 4, + .maxIndAddrInHash = 4, + .prel = 7, + .maxFrameLength = 1518, + .minFrameLength = 64, + .maxD1Length = 1520, + .maxD2Length = 1520, + .vlantype = 0x8100, + .ecamptr = ((uint32_t) NULL), + .eventRegMask = UCCE_OTHER, + .pausePeriod = 0xf000, + .interruptcoalescingmaxvalue = {1, 1, 1, 1, 1, 1, 1, 1}, + .bdRingLenTx = { + TX_BD_RING_LEN, + TX_BD_RING_LEN, + TX_BD_RING_LEN, + TX_BD_RING_LEN, + TX_BD_RING_LEN, + TX_BD_RING_LEN, + TX_BD_RING_LEN, + TX_BD_RING_LEN}, + + .bdRingLenRx = { + RX_BD_RING_LEN, + RX_BD_RING_LEN, + RX_BD_RING_LEN, + RX_BD_RING_LEN, + RX_BD_RING_LEN, + RX_BD_RING_LEN, + RX_BD_RING_LEN, + RX_BD_RING_LEN}, + + .numStationAddresses = UCC_GETH_NUM_OF_STATION_ADDRESSES_1, + .largestexternallookupkeysize = + QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_NONE, + .statisticsMode = UCC_GETH_STATISTICS_GATHERING_MODE_NONE, + .vlanOperationTagged = UCC_GETH_VLAN_OPERATION_TAGGED_NOP, + .vlanOperationNonTagged = UCC_GETH_VLAN_OPERATION_NON_TAGGED_NOP, + .rxQoSMode = UCC_GETH_QOS_MODE_DEFAULT, + .aufc = UPSMR_AUTOMATIC_FLOW_CONTROL_MODE_NONE, + .padAndCrc = MACCFG2_PAD_AND_CRC_MODE_PAD_AND_CRC, + .numThreadsTx = UCC_GETH_NUM_OF_THREADS_4, + .numThreadsRx = UCC_GETH_NUM_OF_THREADS_4, + .riscTx = QE_RISC_ALLOCATION_RISC1_AND_RISC2, + .riscRx = QE_RISC_ALLOCATION_RISC1_AND_RISC2, +}; + +static ucc_geth_info_t ugeth_info[8]; + +#ifdef DEBUG +static void mem_disp(u8 *addr, int size) +{ + u8 *i; + int size16Aling = (size >> 4) << 4; + int size4Aling = (size >> 2) << 2; + int notAlign = 0; + if (size % 16) + notAlign = 1; + + for (i = addr; (u32) i < (u32) addr + size16Aling; i += 16) + printk("0x%08x: %08x %08x %08x %08x\r\n", + (u32) i, + *((u32 *) (i)), + *((u32 *) (i + 4)), + *((u32 *) (i + 8)), *((u32 *) (i + 12))); + if (notAlign == 1) + printk("0x%08x: ", (u32) i); + for (; (u32) i < (u32) addr + size4Aling; i += 4) + printk("%08x ", *((u32 *) (i))); + for (; (u32) i < (u32) addr + size; i++) + printk("%02x", *((u8 *) (i))); + if (notAlign == 1) + printk("\r\n"); +} +#endif /* DEBUG */ + +#ifdef CONFIG_UGETH_FILTERING +static void enqueue(struct list_head *node, struct list_head *lh) +{ + unsigned long flags; + + spin_lock_irqsave(ugeth_lock, flags); + list_add_tail(node, lh); + spin_unlock_irqrestore(ugeth_lock, flags); +} +#endif /* CONFIG_UGETH_FILTERING */ + +static struct list_head *dequeue(struct list_head *lh) +{ + unsigned long flags; + + spin_lock_irqsave(ugeth_lock, flags); + if (!list_empty(lh)) { + struct list_head *node = lh->next; + list_del(node); + spin_unlock_irqrestore(ugeth_lock, flags); + return node; + } else { + spin_unlock_irqrestore(ugeth_lock, flags); + return NULL; + } +} + +static int get_interface_details(enet_interface_e enet_interface, + enet_speed_e *speed, + int *r10m, + int *rmm, + int *rpm, + int *tbi, int *limited_to_full_duplex) +{ + /* Analyze enet_interface according to Interface Mode + Configuration table */ + switch (enet_interface) { + case ENET_10_MII: + *speed = ENET_SPEED_10BT; + break; + case ENET_10_RMII: + *speed = ENET_SPEED_10BT; + *r10m = 1; + *rmm = 1; + break; + case ENET_10_RGMII: + *speed = ENET_SPEED_10BT; + *rpm = 1; + *r10m = 1; + *limited_to_full_duplex = 1; + break; + case ENET_100_MII: + *speed = ENET_SPEED_100BT; + break; + case ENET_100_RMII: + *speed = ENET_SPEED_100BT; + *rmm = 1; + break; + case ENET_100_RGMII: + *speed = ENET_SPEED_100BT; + *rpm = 1; + *limited_to_full_duplex = 1; + break; + case ENET_1000_GMII: + *speed = ENET_SPEED_1000BT; + *limited_to_full_duplex = 1; + break; + case ENET_1000_RGMII: + *speed = ENET_SPEED_1000BT; + *rpm = 1; + *limited_to_full_duplex = 1; + break; + case ENET_1000_TBI: + *speed = ENET_SPEED_1000BT; + *tbi = 1; + *limited_to_full_duplex = 1; + break; + case ENET_1000_RTBI: + *speed = ENET_SPEED_1000BT; + *rpm = 1; + *tbi = 1; + *limited_to_full_duplex = 1; + break; + default: + return -EINVAL; + break; + } + + return 0; +} + +static struct sk_buff *get_new_skb(ucc_geth_private_t *ugeth, u8 *bd) +{ + struct sk_buff *skb = NULL; + + skb = dev_alloc_skb(ugeth->ug_info->uf_info.max_rx_buf_length + + UCC_GETH_RX_DATA_BUF_ALIGNMENT); + + if (skb == NULL) + return NULL; + + /* We need the data buffer to be aligned properly. We will reserve + * as many bytes as needed to align the data properly + */ + skb_reserve(skb, + UCC_GETH_RX_DATA_BUF_ALIGNMENT - + (((unsigned)skb->data) & (UCC_GETH_RX_DATA_BUF_ALIGNMENT - + 1))); + + skb->dev = ugeth->dev; + + BD_BUFFER_SET(bd, + dma_map_single(NULL, + skb->data, + ugeth->ug_info->uf_info.max_rx_buf_length + + UCC_GETH_RX_DATA_BUF_ALIGNMENT, + DMA_FROM_DEVICE)); + + BD_STATUS_AND_LENGTH_SET(bd, + (R_E | R_I | + (BD_STATUS_AND_LENGTH(bd) & R_W))); + + return skb; +} + +static int rx_bd_buffer_set(ucc_geth_private_t *ugeth, u8 rxQ) +{ + u8 *bd; + u32 bd_status; + struct sk_buff *skb; + int i; + + bd = ugeth->p_rx_bd_ring[rxQ]; + i = 0; + + do { + bd_status = BD_STATUS_AND_LENGTH(bd); + skb = get_new_skb(ugeth, bd); + + if (!skb) /* If can not allocate data buffer, + abort. Cleanup will be elsewhere */ + return -ENOMEM; + + ugeth->rx_skbuff[rxQ][i] = skb; + + /* advance the BD pointer */ + bd += UCC_GETH_SIZE_OF_BD; + i++; + } while (!(bd_status & R_W)); + + return 0; +} + +static int fill_init_enet_entries(ucc_geth_private_t *ugeth, + volatile u32 *p_start, + u8 num_entries, + u32 thread_size, + u32 thread_alignment, + qe_risc_allocation_e risc, + int skip_page_for_first_entry) +{ + u32 init_enet_offset; + u8 i; + int snum; + + for (i = 0; i < num_entries; i++) { + if ((snum = qe_get_snum()) < 0) { + ugeth_err("fill_init_enet_entries: Can not get SNUM."); + return snum; + } + if ((i == 0) && skip_page_for_first_entry) + /* First entry of Rx does not have page */ + init_enet_offset = 0; + else { + init_enet_offset = + qe_muram_alloc(thread_size, thread_alignment); + if (IS_MURAM_ERR(init_enet_offset)) { + ugeth_err + ("fill_init_enet_entries: Can not allocate DPRAM memory."); + qe_put_snum((u8) snum); + return -ENOMEM; + } + } + *(p_start++) = + ((u8) snum << ENET_INIT_PARAM_SNUM_SHIFT) | init_enet_offset + | risc; + } + + return 0; +} + +static int return_init_enet_entries(ucc_geth_private_t *ugeth, + volatile u32 *p_start, + u8 num_entries, + qe_risc_allocation_e risc, + int skip_page_for_first_entry) +{ + u32 init_enet_offset; + u8 i; + int snum; + + for (i = 0; i < num_entries; i++) { + /* Check that this entry was actually valid -- + needed in case failed in allocations */ + if ((*p_start & ENET_INIT_PARAM_RISC_MASK) == risc) { + snum = + (u32) (*p_start & ENET_INIT_PARAM_SNUM_MASK) >> + ENET_INIT_PARAM_SNUM_SHIFT; + qe_put_snum((u8) snum); + if (!((i == 0) && skip_page_for_first_entry)) { + /* First entry of Rx does not have page */ + init_enet_offset = + (in_be32(p_start) & + ENET_INIT_PARAM_PTR_MASK); + qe_muram_free(init_enet_offset); + } + *(p_start++) = 0; /* Just for cosmetics */ + } + } + + return 0; +} + +#ifdef DEBUG +static int dump_init_enet_entries(ucc_geth_private_t *ugeth, + volatile u32 *p_start, + u8 num_entries, + u32 thread_size, + qe_risc_allocation_e risc, + int skip_page_for_first_entry) +{ + u32 init_enet_offset; + u8 i; + int snum; + + for (i = 0; i < num_entries; i++) { + /* Check that this entry was actually valid -- + needed in case failed in allocations */ + if ((*p_start & ENET_INIT_PARAM_RISC_MASK) == risc) { + snum = + (u32) (*p_start & ENET_INIT_PARAM_SNUM_MASK) >> + ENET_INIT_PARAM_SNUM_SHIFT; + qe_put_snum((u8) snum); + if (!((i == 0) && skip_page_for_first_entry)) { + /* First entry of Rx does not have page */ + init_enet_offset = + (in_be32(p_start) & + ENET_INIT_PARAM_PTR_MASK); + ugeth_info("Init enet entry %d:", i); + ugeth_info("Base address: 0x%08x", + (u32) + qe_muram_addr(init_enet_offset)); + mem_disp(qe_muram_addr(init_enet_offset), + thread_size); + } + p_start++; + } + } + + return 0; +} +#endif + +#ifdef CONFIG_UGETH_FILTERING +static enet_addr_container_t *get_enet_addr_container(void) +{ + enet_addr_container_t *enet_addr_cont; + + /* allocate memory */ + enet_addr_cont = kmalloc(sizeof(enet_addr_container_t), GFP_KERNEL); + if (!enet_addr_cont) { + ugeth_err("%s: No memory for enet_addr_container_t object.", + __FUNCTION__); + return NULL; + } + + return enet_addr_cont; +} +#endif /* CONFIG_UGETH_FILTERING */ + +static void put_enet_addr_container(enet_addr_container_t *enet_addr_cont) +{ + kfree(enet_addr_cont); +} + +#ifdef CONFIG_UGETH_FILTERING +static int hw_add_addr_in_paddr(ucc_geth_private_t *ugeth, + enet_addr_t *p_enet_addr, u8 paddr_num) +{ + ucc_geth_82xx_address_filtering_pram_t *p_82xx_addr_filt; + + if (!(paddr_num < NUM_OF_PADDRS)) { + ugeth_warn("%s: Illagel paddr_num.", __FUNCTION__); + return -EINVAL; + } + + p_82xx_addr_filt = + (ucc_geth_82xx_address_filtering_pram_t *) ugeth->p_rx_glbl_pram-> + addressfiltering; + + /* Ethernet frames are defined in Little Endian mode, */ + /* therefore to insert the address we reverse the bytes. */ + out_be16(&p_82xx_addr_filt->paddr[paddr_num].h, + (u16) (((u16) (((u16) ((*p_enet_addr)[5])) << 8)) | + (u16) (*p_enet_addr)[4])); + out_be16(&p_82xx_addr_filt->paddr[paddr_num].m, + (u16) (((u16) (((u16) ((*p_enet_addr)[3])) << 8)) | + (u16) (*p_enet_addr)[2])); + out_be16(&p_82xx_addr_filt->paddr[paddr_num].l, + (u16) (((u16) (((u16) ((*p_enet_addr)[1])) << 8)) | + (u16) (*p_enet_addr)[0])); + + return 0; +} +#endif /* CONFIG_UGETH_FILTERING */ + +static int hw_clear_addr_in_paddr(ucc_geth_private_t *ugeth, u8 paddr_num) +{ + ucc_geth_82xx_address_filtering_pram_t *p_82xx_addr_filt; + + if (!(paddr_num < NUM_OF_PADDRS)) { + ugeth_warn("%s: Illagel paddr_num.", __FUNCTION__); + return -EINVAL; + } + + p_82xx_addr_filt = + (ucc_geth_82xx_address_filtering_pram_t *) ugeth->p_rx_glbl_pram-> + addressfiltering; + + /* Writing address ff.ff.ff.ff.ff.ff disables address + recognition for this register */ + out_be16(&p_82xx_addr_filt->paddr[paddr_num].h, 0xffff); + out_be16(&p_82xx_addr_filt->paddr[paddr_num].m, 0xffff); + out_be16(&p_82xx_addr_filt->paddr[paddr_num].l, 0xffff); + + return 0; +} + +static void hw_add_addr_in_hash(ucc_geth_private_t *ugeth, + enet_addr_t *p_enet_addr) +{ + ucc_geth_82xx_address_filtering_pram_t *p_82xx_addr_filt; + u32 cecr_subblock; + + p_82xx_addr_filt = + (ucc_geth_82xx_address_filtering_pram_t *) ugeth->p_rx_glbl_pram-> + addressfiltering; + + cecr_subblock = + ucc_fast_get_qe_cr_subblock(ugeth->ug_info->uf_info.ucc_num); + + /* Ethernet frames are defined in Little Endian mode, + therefor to insert */ + /* the address to the hash (Big Endian mode), we reverse the bytes.*/ + out_be16(&p_82xx_addr_filt->taddr.h, + (u16) (((u16) (((u16) ((*p_enet_addr)[5])) << 8)) | + (u16) (*p_enet_addr)[4])); + out_be16(&p_82xx_addr_filt->taddr.m, + (u16) (((u16) (((u16) ((*p_enet_addr)[3])) << 8)) | + (u16) (*p_enet_addr)[2])); + out_be16(&p_82xx_addr_filt->taddr.l, + (u16) (((u16) (((u16) ((*p_enet_addr)[1])) << 8)) | + (u16) (*p_enet_addr)[0])); + + qe_issue_cmd(QE_SET_GROUP_ADDRESS, cecr_subblock, + (u8) QE_CR_PROTOCOL_ETHERNET, 0); +} + +#ifdef CONFIG_UGETH_MAGIC_PACKET +static void magic_packet_detection_enable(ucc_geth_private_t *ugeth) +{ + ucc_fast_private_t *uccf; + ucc_geth_t *ug_regs; + u32 maccfg2, uccm; + + uccf = ugeth->uccf; + ug_regs = ugeth->ug_regs; + + /* Enable interrupts for magic packet detection */ + uccm = in_be32(uccf->p_uccm); + uccm |= UCCE_MPD; + out_be32(uccf->p_uccm, uccm); + + /* Enable magic packet detection */ + maccfg2 = in_be32(&ug_regs->maccfg2); + maccfg2 |= MACCFG2_MPE; + out_be32(&ug_regs->maccfg2, maccfg2); +} + +static void magic_packet_detection_disable(ucc_geth_private_t *ugeth) +{ + ucc_fast_private_t *uccf; + ucc_geth_t *ug_regs; + u32 maccfg2, uccm; + + uccf = ugeth->uccf; + ug_regs = ugeth->ug_regs; + + /* Disable interrupts for magic packet detection */ + uccm = in_be32(uccf->p_uccm); + uccm &= ~UCCE_MPD; + out_be32(uccf->p_uccm, uccm); + + /* Disable magic packet detection */ + maccfg2 = in_be32(&ug_regs->maccfg2); + maccfg2 &= ~MACCFG2_MPE; + out_be32(&ug_regs->maccfg2, maccfg2); +} +#endif /* MAGIC_PACKET */ + +static inline int compare_addr(enet_addr_t *addr1, enet_addr_t *addr2) +{ + return memcmp(addr1, addr2, ENET_NUM_OCTETS_PER_ADDRESS); +} + +#ifdef DEBUG +static void get_statistics(ucc_geth_private_t *ugeth, + ucc_geth_tx_firmware_statistics_t * + tx_firmware_statistics, + ucc_geth_rx_firmware_statistics_t * + rx_firmware_statistics, + ucc_geth_hardware_statistics_t *hardware_statistics) +{ + ucc_fast_t *uf_regs; + ucc_geth_t *ug_regs; + ucc_geth_tx_firmware_statistics_pram_t *p_tx_fw_statistics_pram; + ucc_geth_rx_firmware_statistics_pram_t *p_rx_fw_statistics_pram; + + ug_regs = ugeth->ug_regs; + uf_regs = (ucc_fast_t *) ug_regs; + p_tx_fw_statistics_pram = ugeth->p_tx_fw_statistics_pram; + p_rx_fw_statistics_pram = ugeth->p_rx_fw_statistics_pram; + + /* Tx firmware only if user handed pointer and driver actually + gathers Tx firmware statistics */ + if (tx_firmware_statistics && p_tx_fw_statistics_pram) { + tx_firmware_statistics->sicoltx = + in_be32(&p_tx_fw_statistics_pram->sicoltx); + tx_firmware_statistics->mulcoltx = + in_be32(&p_tx_fw_statistics_pram->mulcoltx); + tx_firmware_statistics->latecoltxfr = + in_be32(&p_tx_fw_statistics_pram->latecoltxfr); + tx_firmware_statistics->frabortduecol = + in_be32(&p_tx_fw_statistics_pram->frabortduecol); + tx_firmware_statistics->frlostinmactxer = + in_be32(&p_tx_fw_statistics_pram->frlostinmactxer); + tx_firmware_statistics->carriersenseertx = + in_be32(&p_tx_fw_statistics_pram->carriersenseertx); + tx_firmware_statistics->frtxok = + in_be32(&p_tx_fw_statistics_pram->frtxok); + tx_firmware_statistics->txfrexcessivedefer = + in_be32(&p_tx_fw_statistics_pram->txfrexcessivedefer); + tx_firmware_statistics->txpkts256 = + in_be32(&p_tx_fw_statistics_pram->txpkts256); + tx_firmware_statistics->txpkts512 = + in_be32(&p_tx_fw_statistics_pram->txpkts512); + tx_firmware_statistics->txpkts1024 = + in_be32(&p_tx_fw_statistics_pram->txpkts1024); + tx_firmware_statistics->txpktsjumbo = + in_be32(&p_tx_fw_statistics_pram->txpktsjumbo); + } + + /* Rx firmware only if user handed pointer and driver actually + * gathers Rx firmware statistics */ + if (rx_firmware_statistics && p_rx_fw_statistics_pram) { + int i; + rx_firmware_statistics->frrxfcser = + in_be32(&p_rx_fw_statistics_pram->frrxfcser); + rx_firmware_statistics->fraligner = + in_be32(&p_rx_fw_statistics_pram->fraligner); + rx_firmware_statistics->inrangelenrxer = + in_be32(&p_rx_fw_statistics_pram->inrangelenrxer); + rx_firmware_statistics->outrangelenrxer = + in_be32(&p_rx_fw_statistics_pram->outrangelenrxer); + rx_firmware_statistics->frtoolong = + in_be32(&p_rx_fw_statistics_pram->frtoolong); + rx_firmware_statistics->runt = + in_be32(&p_rx_fw_statistics_pram->runt); + rx_firmware_statistics->verylongevent = + in_be32(&p_rx_fw_statistics_pram->verylongevent); + rx_firmware_statistics->symbolerror = + in_be32(&p_rx_fw_statistics_pram->symbolerror); + rx_firmware_statistics->dropbsy = + in_be32(&p_rx_fw_statistics_pram->dropbsy); + for (i = 0; i < 0x8; i++) + rx_firmware_statistics->res0[i] = + p_rx_fw_statistics_pram->res0[i]; + rx_firmware_statistics->mismatchdrop = + in_be32(&p_rx_fw_statistics_pram->mismatchdrop); + rx_firmware_statistics->underpkts = + in_be32(&p_rx_fw_statistics_pram->underpkts); + rx_firmware_statistics->pkts256 = + in_be32(&p_rx_fw_statistics_pram->pkts256); + rx_firmware_statistics->pkts512 = + in_be32(&p_rx_fw_statistics_pram->pkts512); + rx_firmware_statistics->pkts1024 = + in_be32(&p_rx_fw_statistics_pram->pkts1024); + rx_firmware_statistics->pktsjumbo = + in_be32(&p_rx_fw_statistics_pram->pktsjumbo); + rx_firmware_statistics->frlossinmacer = + in_be32(&p_rx_fw_statistics_pram->frlossinmacer); + rx_firmware_statistics->pausefr = + in_be32(&p_rx_fw_statistics_pram->pausefr); + for (i = 0; i < 0x4; i++) + rx_firmware_statistics->res1[i] = + p_rx_fw_statistics_pram->res1[i]; + rx_firmware_statistics->removevlan = + in_be32(&p_rx_fw_statistics_pram->removevlan); + rx_firmware_statistics->replacevlan = + in_be32(&p_rx_fw_statistics_pram->replacevlan); + rx_firmware_statistics->insertvlan = + in_be32(&p_rx_fw_statistics_pram->insertvlan); + } + + /* Hardware only if user handed pointer and driver actually + gathers hardware statistics */ + if (hardware_statistics && (in_be32(&uf_regs->upsmr) & UPSMR_HSE)) { + hardware_statistics->tx64 = in_be32(&ug_regs->tx64); + hardware_statistics->tx127 = in_be32(&ug_regs->tx127); + hardware_statistics->tx255 = in_be32(&ug_regs->tx255); + hardware_statistics->rx64 = in_be32(&ug_regs->rx64); + hardware_statistics->rx127 = in_be32(&ug_regs->rx127); + hardware_statistics->rx255 = in_be32(&ug_regs->rx255); + hardware_statistics->txok = in_be32(&ug_regs->txok); + hardware_statistics->txcf = in_be16(&ug_regs->txcf); + hardware_statistics->tmca = in_be32(&ug_regs->tmca); + hardware_statistics->tbca = in_be32(&ug_regs->tbca); + hardware_statistics->rxfok = in_be32(&ug_regs->rxfok); + hardware_statistics->rxbok = in_be32(&ug_regs->rxbok); + hardware_statistics->rbyt = in_be32(&ug_regs->rbyt); + hardware_statistics->rmca = in_be32(&ug_regs->rmca); + hardware_statistics->rbca = in_be32(&ug_regs->rbca); + } +} + +static void dump_bds(ucc_geth_private_t *ugeth) +{ + int i; + int length; + + for (i = 0; i < ugeth->ug_info->numQueuesTx; i++) { + if (ugeth->p_tx_bd_ring[i]) { + length = + (ugeth->ug_info->bdRingLenTx[i] * + UCC_GETH_SIZE_OF_BD); + ugeth_info("TX BDs[%d]", i); + mem_disp(ugeth->p_tx_bd_ring[i], length); + } + } + for (i = 0; i < ugeth->ug_info->numQueuesRx; i++) { + if (ugeth->p_rx_bd_ring[i]) { + length = + (ugeth->ug_info->bdRingLenRx[i] * + UCC_GETH_SIZE_OF_BD); + ugeth_info("RX BDs[%d]", i); + mem_disp(ugeth->p_rx_bd_ring[i], length); + } + } +} + +static void dump_regs(ucc_geth_private_t *ugeth) +{ + int i; + + ugeth_info("UCC%d Geth registers:", ugeth->ug_info->uf_info.ucc_num); + ugeth_info("Base address: 0x%08x", (u32) ugeth->ug_regs); + + ugeth_info("maccfg1 : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->maccfg1, + in_be32(&ugeth->ug_regs->maccfg1)); + ugeth_info("maccfg2 : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->maccfg2, + in_be32(&ugeth->ug_regs->maccfg2)); + ugeth_info("ipgifg : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->ipgifg, + in_be32(&ugeth->ug_regs->ipgifg)); + ugeth_info("hafdup : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->hafdup, + in_be32(&ugeth->ug_regs->hafdup)); + ugeth_info("miimcfg : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->miimng.miimcfg, + in_be32(&ugeth->ug_regs->miimng.miimcfg)); + ugeth_info("miimcom : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->miimng.miimcom, + in_be32(&ugeth->ug_regs->miimng.miimcom)); + ugeth_info("miimadd : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->miimng.miimadd, + in_be32(&ugeth->ug_regs->miimng.miimadd)); + ugeth_info("miimcon : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->miimng.miimcon, + in_be32(&ugeth->ug_regs->miimng.miimcon)); + ugeth_info("miimstat : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->miimng.miimstat, + in_be32(&ugeth->ug_regs->miimng.miimstat)); + ugeth_info("miimmind : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->miimng.miimind, + in_be32(&ugeth->ug_regs->miimng.miimind)); + ugeth_info("ifctl : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->ifctl, + in_be32(&ugeth->ug_regs->ifctl)); + ugeth_info("ifstat : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->ifstat, + in_be32(&ugeth->ug_regs->ifstat)); + ugeth_info("macstnaddr1: addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->macstnaddr1, + in_be32(&ugeth->ug_regs->macstnaddr1)); + ugeth_info("macstnaddr2: addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->macstnaddr2, + in_be32(&ugeth->ug_regs->macstnaddr2)); + ugeth_info("uempr : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->uempr, + in_be32(&ugeth->ug_regs->uempr)); + ugeth_info("utbipar : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->utbipar, + in_be32(&ugeth->ug_regs->utbipar)); + ugeth_info("uescr : addr - 0x%08x, val - 0x%04x", + (u32) & ugeth->ug_regs->uescr, + in_be16(&ugeth->ug_regs->uescr)); + ugeth_info("tx64 : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->tx64, + in_be32(&ugeth->ug_regs->tx64)); + ugeth_info("tx127 : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->tx127, + in_be32(&ugeth->ug_regs->tx127)); + ugeth_info("tx255 : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->tx255, + in_be32(&ugeth->ug_regs->tx255)); + ugeth_info("rx64 : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->rx64, + in_be32(&ugeth->ug_regs->rx64)); + ugeth_info("rx127 : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->rx127, + in_be32(&ugeth->ug_regs->rx127)); + ugeth_info("rx255 : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->rx255, + in_be32(&ugeth->ug_regs->rx255)); + ugeth_info("txok : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->txok, + in_be32(&ugeth->ug_regs->txok)); + ugeth_info("txcf : addr - 0x%08x, val - 0x%04x", + (u32) & ugeth->ug_regs->txcf, + in_be16(&ugeth->ug_regs->txcf)); + ugeth_info("tmca : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->tmca, + in_be32(&ugeth->ug_regs->tmca)); + ugeth_info("tbca : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->tbca, + in_be32(&ugeth->ug_regs->tbca)); + ugeth_info("rxfok : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->rxfok, + in_be32(&ugeth->ug_regs->rxfok)); + ugeth_info("rxbok : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->rxbok, + in_be32(&ugeth->ug_regs->rxbok)); + ugeth_info("rbyt : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->rbyt, + in_be32(&ugeth->ug_regs->rbyt)); + ugeth_info("rmca : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->rmca, + in_be32(&ugeth->ug_regs->rmca)); + ugeth_info("rbca : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->rbca, + in_be32(&ugeth->ug_regs->rbca)); + ugeth_info("scar : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->scar, + in_be32(&ugeth->ug_regs->scar)); + ugeth_info("scam : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->scam, + in_be32(&ugeth->ug_regs->scam)); + + if (ugeth->p_thread_data_tx) { + int numThreadsTxNumerical; + switch (ugeth->ug_info->numThreadsTx) { + case UCC_GETH_NUM_OF_THREADS_1: + numThreadsTxNumerical = 1; + break; + case UCC_GETH_NUM_OF_THREADS_2: + numThreadsTxNumerical = 2; + break; + case UCC_GETH_NUM_OF_THREADS_4: + numThreadsTxNumerical = 4; + break; + case UCC_GETH_NUM_OF_THREADS_6: + numThreadsTxNumerical = 6; + break; + case UCC_GETH_NUM_OF_THREADS_8: + numThreadsTxNumerical = 8; + break; + default: + numThreadsTxNumerical = 0; + break; + } + + ugeth_info("Thread data TXs:"); + ugeth_info("Base address: 0x%08x", + (u32) ugeth->p_thread_data_tx); + for (i = 0; i < numThreadsTxNumerical; i++) { + ugeth_info("Thread data TX[%d]:", i); + ugeth_info("Base address: 0x%08x", + (u32) & ugeth->p_thread_data_tx[i]); + mem_disp((u8 *) & ugeth->p_thread_data_tx[i], + sizeof(ucc_geth_thread_data_tx_t)); + } + } + if (ugeth->p_thread_data_rx) { + int numThreadsRxNumerical; + switch (ugeth->ug_info->numThreadsRx) { + case UCC_GETH_NUM_OF_THREADS_1: + numThreadsRxNumerical = 1; + break; + case UCC_GETH_NUM_OF_THREADS_2: + numThreadsRxNumerical = 2; + break; + case UCC_GETH_NUM_OF_THREADS_4: + numThreadsRxNumerical = 4; + break; + case UCC_GETH_NUM_OF_THREADS_6: + numThreadsRxNumerical = 6; + break; + case UCC_GETH_NUM_OF_THREADS_8: + numThreadsRxNumerical = 8; + break; + default: + numThreadsRxNumerical = 0; + break; + } + + ugeth_info("Thread data RX:"); + ugeth_info("Base address: 0x%08x", + (u32) ugeth->p_thread_data_rx); + for (i = 0; i < numThreadsRxNumerical; i++) { + ugeth_info("Thread data RX[%d]:", i); + ugeth_info("Base address: 0x%08x", + (u32) & ugeth->p_thread_data_rx[i]); + mem_disp((u8 *) & ugeth->p_thread_data_rx[i], + sizeof(ucc_geth_thread_data_rx_t)); + } + } + if (ugeth->p_exf_glbl_param) { + ugeth_info("EXF global param:"); + ugeth_info("Base address: 0x%08x", + (u32) ugeth->p_exf_glbl_param); + mem_disp((u8 *) ugeth->p_exf_glbl_param, + sizeof(*ugeth->p_exf_glbl_param)); + } + if (ugeth->p_tx_glbl_pram) { + ugeth_info("TX global param:"); + ugeth_info("Base address: 0x%08x", (u32) ugeth->p_tx_glbl_pram); + ugeth_info("temoder : addr - 0x%08x, val - 0x%04x", + (u32) & ugeth->p_tx_glbl_pram->temoder, + in_be16(&ugeth->p_tx_glbl_pram->temoder)); + ugeth_info("sqptr : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_tx_glbl_pram->sqptr, + in_be32(&ugeth->p_tx_glbl_pram->sqptr)); + ugeth_info("schedulerbasepointer: addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_tx_glbl_pram->schedulerbasepointer, + in_be32(&ugeth->p_tx_glbl_pram-> + schedulerbasepointer)); + ugeth_info("txrmonbaseptr: addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_tx_glbl_pram->txrmonbaseptr, + in_be32(&ugeth->p_tx_glbl_pram->txrmonbaseptr)); + ugeth_info("tstate : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_tx_glbl_pram->tstate, + in_be32(&ugeth->p_tx_glbl_pram->tstate)); + ugeth_info("iphoffset[0] : addr - 0x%08x, val - 0x%02x", + (u32) & ugeth->p_tx_glbl_pram->iphoffset[0], + ugeth->p_tx_glbl_pram->iphoffset[0]); + ugeth_info("iphoffset[1] : addr - 0x%08x, val - 0x%02x", + (u32) & ugeth->p_tx_glbl_pram->iphoffset[1], + ugeth->p_tx_glbl_pram->iphoffset[1]); + ugeth_info("iphoffset[2] : addr - 0x%08x, val - 0x%02x", + (u32) & ugeth->p_tx_glbl_pram->iphoffset[2], + ugeth->p_tx_glbl_pram->iphoffset[2]); + ugeth_info("iphoffset[3] : addr - 0x%08x, val - 0x%02x", + (u32) & ugeth->p_tx_glbl_pram->iphoffset[3], + ugeth->p_tx_glbl_pram->iphoffset[3]); + ugeth_info("iphoffset[4] : addr - 0x%08x, val - 0x%02x", + (u32) & ugeth->p_tx_glbl_pram->iphoffset[4], + ugeth->p_tx_glbl_pram->iphoffset[4]); + ugeth_info("iphoffset[5] : addr - 0x%08x, val - 0x%02x", + (u32) & ugeth->p_tx_glbl_pram->iphoffset[5], + ugeth->p_tx_glbl_pram->iphoffset[5]); + ugeth_info("iphoffset[6] : addr - 0x%08x, val - 0x%02x", + (u32) & ugeth->p_tx_glbl_pram->iphoffset[6], + ugeth->p_tx_glbl_pram->iphoffset[6]); + ugeth_info("iphoffset[7] : addr - 0x%08x, val - 0x%02x", + (u32) & ugeth->p_tx_glbl_pram->iphoffset[7], + ugeth->p_tx_glbl_pram->iphoffset[7]); + ugeth_info("vtagtable[0] : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_tx_glbl_pram->vtagtable[0], + in_be32(&ugeth->p_tx_glbl_pram->vtagtable[0])); + ugeth_info("vtagtable[1] : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_tx_glbl_pram->vtagtable[1], + in_be32(&ugeth->p_tx_glbl_pram->vtagtable[1])); + ugeth_info("vtagtable[2] : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_tx_glbl_pram->vtagtable[2], + in_be32(&ugeth->p_tx_glbl_pram->vtagtable[2])); + ugeth_info("vtagtable[3] : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_tx_glbl_pram->vtagtable[3], + in_be32(&ugeth->p_tx_glbl_pram->vtagtable[3])); + ugeth_info("vtagtable[4] : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_tx_glbl_pram->vtagtable[4], + in_be32(&ugeth->p_tx_glbl_pram->vtagtable[4])); + ugeth_info("vtagtable[5] : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_tx_glbl_pram->vtagtable[5], + in_be32(&ugeth->p_tx_glbl_pram->vtagtable[5])); + ugeth_info("vtagtable[6] : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_tx_glbl_pram->vtagtable[6], + in_be32(&ugeth->p_tx_glbl_pram->vtagtable[6])); + ugeth_info("vtagtable[7] : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_tx_glbl_pram->vtagtable[7], + in_be32(&ugeth->p_tx_glbl_pram->vtagtable[7])); + ugeth_info("tqptr : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_tx_glbl_pram->tqptr, + in_be32(&ugeth->p_tx_glbl_pram->tqptr)); + } + if (ugeth->p_rx_glbl_pram) { + ugeth_info("RX global param:"); + ugeth_info("Base address: 0x%08x", (u32) ugeth->p_rx_glbl_pram); + ugeth_info("remoder : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_rx_glbl_pram->remoder, + in_be32(&ugeth->p_rx_glbl_pram->remoder)); + ugeth_info("rqptr : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_rx_glbl_pram->rqptr, + in_be32(&ugeth->p_rx_glbl_pram->rqptr)); + ugeth_info("typeorlen : addr - 0x%08x, val - 0x%04x", + (u32) & ugeth->p_rx_glbl_pram->typeorlen, + in_be16(&ugeth->p_rx_glbl_pram->typeorlen)); + ugeth_info("rxgstpack : addr - 0x%08x, val - 0x%02x", + (u32) & ugeth->p_rx_glbl_pram->rxgstpack, + ugeth->p_rx_glbl_pram->rxgstpack); + ugeth_info("rxrmonbaseptr : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_rx_glbl_pram->rxrmonbaseptr, + in_be32(&ugeth->p_rx_glbl_pram->rxrmonbaseptr)); + ugeth_info("intcoalescingptr: addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_rx_glbl_pram->intcoalescingptr, + in_be32(&ugeth->p_rx_glbl_pram->intcoalescingptr)); + ugeth_info("rstate : addr - 0x%08x, val - 0x%02x", + (u32) & ugeth->p_rx_glbl_pram->rstate, + ugeth->p_rx_glbl_pram->rstate); + ugeth_info("mrblr : addr - 0x%08x, val - 0x%04x", + (u32) & ugeth->p_rx_glbl_pram->mrblr, + in_be16(&ugeth->p_rx_glbl_pram->mrblr)); + ugeth_info("rbdqptr : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_rx_glbl_pram->rbdqptr, + in_be32(&ugeth->p_rx_glbl_pram->rbdqptr)); + ugeth_info("mflr : addr - 0x%08x, val - 0x%04x", + (u32) & ugeth->p_rx_glbl_pram->mflr, + in_be16(&ugeth->p_rx_glbl_pram->mflr)); + ugeth_info("minflr : addr - 0x%08x, val - 0x%04x", + (u32) & ugeth->p_rx_glbl_pram->minflr, + in_be16(&ugeth->p_rx_glbl_pram->minflr)); + ugeth_info("maxd1 : addr - 0x%08x, val - 0x%04x", + (u32) & ugeth->p_rx_glbl_pram->maxd1, + in_be16(&ugeth->p_rx_glbl_pram->maxd1)); + ugeth_info("maxd2 : addr - 0x%08x, val - 0x%04x", + (u32) & ugeth->p_rx_glbl_pram->maxd2, + in_be16(&ugeth->p_rx_glbl_pram->maxd2)); + ugeth_info("ecamptr : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_rx_glbl_pram->ecamptr, + in_be32(&ugeth->p_rx_glbl_pram->ecamptr)); + ugeth_info("l2qt : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_rx_glbl_pram->l2qt, + in_be32(&ugeth->p_rx_glbl_pram->l2qt)); + ugeth_info("l3qt[0] : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_rx_glbl_pram->l3qt[0], + in_be32(&ugeth->p_rx_glbl_pram->l3qt[0])); + ugeth_info("l3qt[1] : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_rx_glbl_pram->l3qt[1], + in_be32(&ugeth->p_rx_glbl_pram->l3qt[1])); + ugeth_info("l3qt[2] : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_rx_glbl_pram->l3qt[2], + in_be32(&ugeth->p_rx_glbl_pram->l3qt[2])); + ugeth_info("l3qt[3] : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_rx_glbl_pram->l3qt[3], + in_be32(&ugeth->p_rx_glbl_pram->l3qt[3])); + ugeth_info("l3qt[4] : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_rx_glbl_pram->l3qt[4], + in_be32(&ugeth->p_rx_glbl_pram->l3qt[4])); + ugeth_info("l3qt[5] : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_rx_glbl_pram->l3qt[5], + in_be32(&ugeth->p_rx_glbl_pram->l3qt[5])); + ugeth_info("l3qt[6] : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_rx_glbl_pram->l3qt[6], + in_be32(&ugeth->p_rx_glbl_pram->l3qt[6])); + ugeth_info("l3qt[7] : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_rx_glbl_pram->l3qt[7], + in_be32(&ugeth->p_rx_glbl_pram->l3qt[7])); + ugeth_info("vlantype : addr - 0x%08x, val - 0x%04x", + (u32) & ugeth->p_rx_glbl_pram->vlantype, + in_be16(&ugeth->p_rx_glbl_pram->vlantype)); + ugeth_info("vlantci : addr - 0x%08x, val - 0x%04x", + (u32) & ugeth->p_rx_glbl_pram->vlantci, + in_be16(&ugeth->p_rx_glbl_pram->vlantci)); + for (i = 0; i < 64; i++) + ugeth_info + ("addressfiltering[%d]: addr - 0x%08x, val - 0x%02x", + i, + (u32) & ugeth->p_rx_glbl_pram->addressfiltering[i], + ugeth->p_rx_glbl_pram->addressfiltering[i]); + ugeth_info("exfGlobalParam : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_rx_glbl_pram->exfGlobalParam, + in_be32(&ugeth->p_rx_glbl_pram->exfGlobalParam)); + } + if (ugeth->p_send_q_mem_reg) { + ugeth_info("Send Q memory registers:"); + ugeth_info("Base address: 0x%08x", + (u32) ugeth->p_send_q_mem_reg); + for (i = 0; i < ugeth->ug_info->numQueuesTx; i++) { + ugeth_info("SQQD[%d]:", i); + ugeth_info("Base address: 0x%08x", + (u32) & ugeth->p_send_q_mem_reg->sqqd[i]); + mem_disp((u8 *) & ugeth->p_send_q_mem_reg->sqqd[i], + sizeof(ucc_geth_send_queue_qd_t)); + } + } + if (ugeth->p_scheduler) { + ugeth_info("Scheduler:"); + ugeth_info("Base address: 0x%08x", (u32) ugeth->p_scheduler); + mem_disp((u8 *) ugeth->p_scheduler, + sizeof(*ugeth->p_scheduler)); + } + if (ugeth->p_tx_fw_statistics_pram) { + ugeth_info("TX FW statistics pram:"); + ugeth_info("Base address: 0x%08x", + (u32) ugeth->p_tx_fw_statistics_pram); + mem_disp((u8 *) ugeth->p_tx_fw_statistics_pram, + sizeof(*ugeth->p_tx_fw_statistics_pram)); + } + if (ugeth->p_rx_fw_statistics_pram) { + ugeth_info("RX FW statistics pram:"); + ugeth_info("Base address: 0x%08x", + (u32) ugeth->p_rx_fw_statistics_pram); + mem_disp((u8 *) ugeth->p_rx_fw_statistics_pram, + sizeof(*ugeth->p_rx_fw_statistics_pram)); + } + if (ugeth->p_rx_irq_coalescing_tbl) { + ugeth_info("RX IRQ coalescing tables:"); + ugeth_info("Base address: 0x%08x", + (u32) ugeth->p_rx_irq_coalescing_tbl); + for (i = 0; i < ugeth->ug_info->numQueuesRx; i++) { + ugeth_info("RX IRQ coalescing table entry[%d]:", i); + ugeth_info("Base address: 0x%08x", + (u32) & ugeth->p_rx_irq_coalescing_tbl-> + coalescingentry[i]); + ugeth_info + ("interruptcoalescingmaxvalue: addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_rx_irq_coalescing_tbl-> + coalescingentry[i].interruptcoalescingmaxvalue, + in_be32(&ugeth->p_rx_irq_coalescing_tbl-> + coalescingentry[i]. + interruptcoalescingmaxvalue)); + ugeth_info + ("interruptcoalescingcounter : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_rx_irq_coalescing_tbl-> + coalescingentry[i].interruptcoalescingcounter, + in_be32(&ugeth->p_rx_irq_coalescing_tbl-> + coalescingentry[i]. + interruptcoalescingcounter)); + } + } + if (ugeth->p_rx_bd_qs_tbl) { + ugeth_info("RX BD QS tables:"); + ugeth_info("Base address: 0x%08x", (u32) ugeth->p_rx_bd_qs_tbl); + for (i = 0; i < ugeth->ug_info->numQueuesRx; i++) { + ugeth_info("RX BD QS table[%d]:", i); + ugeth_info("Base address: 0x%08x", + (u32) & ugeth->p_rx_bd_qs_tbl[i]); + ugeth_info + ("bdbaseptr : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_rx_bd_qs_tbl[i].bdbaseptr, + in_be32(&ugeth->p_rx_bd_qs_tbl[i].bdbaseptr)); + ugeth_info + ("bdptr : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_rx_bd_qs_tbl[i].bdptr, + in_be32(&ugeth->p_rx_bd_qs_tbl[i].bdptr)); + ugeth_info + ("externalbdbaseptr: addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_rx_bd_qs_tbl[i].externalbdbaseptr, + in_be32(&ugeth->p_rx_bd_qs_tbl[i]. + externalbdbaseptr)); + ugeth_info + ("externalbdptr : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_rx_bd_qs_tbl[i].externalbdptr, + in_be32(&ugeth->p_rx_bd_qs_tbl[i].externalbdptr)); + ugeth_info("ucode RX Prefetched BDs:"); + ugeth_info("Base address: 0x%08x", + (u32) + qe_muram_addr(in_be32 + (&ugeth->p_rx_bd_qs_tbl[i]. + bdbaseptr))); + mem_disp((u8 *) + qe_muram_addr(in_be32 + (&ugeth->p_rx_bd_qs_tbl[i]. + bdbaseptr)), + sizeof(ucc_geth_rx_prefetched_bds_t)); + } + } + if (ugeth->p_init_enet_param_shadow) { + int size; + ugeth_info("Init enet param shadow:"); + ugeth_info("Base address: 0x%08x", + (u32) ugeth->p_init_enet_param_shadow); + mem_disp((u8 *) ugeth->p_init_enet_param_shadow, + sizeof(*ugeth->p_init_enet_param_shadow)); + + size = sizeof(ucc_geth_thread_rx_pram_t); + if (ugeth->ug_info->rxExtendedFiltering) { + size += + THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING; + if (ugeth->ug_info->largestexternallookupkeysize == + QE_FLTR_TABLE_LOOKUP_KEY_SIZE_8_BYTES) + size += + THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING_8; + if (ugeth->ug_info->largestexternallookupkeysize == + QE_FLTR_TABLE_LOOKUP_KEY_SIZE_16_BYTES) + size += + THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING_16; + } + + dump_init_enet_entries(ugeth, + &(ugeth->p_init_enet_param_shadow-> + txthread[0]), + ENET_INIT_PARAM_MAX_ENTRIES_TX, + sizeof(ucc_geth_thread_tx_pram_t), + ugeth->ug_info->riscTx, 0); + dump_init_enet_entries(ugeth, + &(ugeth->p_init_enet_param_shadow-> + rxthread[0]), + ENET_INIT_PARAM_MAX_ENTRIES_RX, size, + ugeth->ug_info->riscRx, 1); + } +} +#endif /* DEBUG */ + +static void init_default_reg_vals(volatile u32 *upsmr_register, + volatile u32 *maccfg1_register, + volatile u32 *maccfg2_register) +{ + out_be32(upsmr_register, UCC_GETH_UPSMR_INIT); + out_be32(maccfg1_register, UCC_GETH_MACCFG1_INIT); + out_be32(maccfg2_register, UCC_GETH_MACCFG2_INIT); +} + +static int init_half_duplex_params(int alt_beb, + int back_pressure_no_backoff, + int no_backoff, + int excess_defer, + u8 alt_beb_truncation, + u8 max_retransmissions, + u8 collision_window, + volatile u32 *hafdup_register) +{ + u32 value = 0; + + if ((alt_beb_truncation > HALFDUP_ALT_BEB_TRUNCATION_MAX) || + (max_retransmissions > HALFDUP_MAX_RETRANSMISSION_MAX) || + (collision_window > HALFDUP_COLLISION_WINDOW_MAX)) + return -EINVAL; + + value = (u32) (alt_beb_truncation << HALFDUP_ALT_BEB_TRUNCATION_SHIFT); + + if (alt_beb) + value |= HALFDUP_ALT_BEB; + if (back_pressure_no_backoff) + value |= HALFDUP_BACK_PRESSURE_NO_BACKOFF; + if (no_backoff) + value |= HALFDUP_NO_BACKOFF; + if (excess_defer) + value |= HALFDUP_EXCESSIVE_DEFER; + + value |= (max_retransmissions << HALFDUP_MAX_RETRANSMISSION_SHIFT); + + value |= collision_window; + + out_be32(hafdup_register, value); + return 0; +} + +static int init_inter_frame_gap_params(u8 non_btb_cs_ipg, + u8 non_btb_ipg, + u8 min_ifg, + u8 btb_ipg, + volatile u32 *ipgifg_register) +{ + u32 value = 0; + + /* Non-Back-to-back IPG part 1 should be <= Non-Back-to-back + IPG part 2 */ + if (non_btb_cs_ipg > non_btb_ipg) + return -EINVAL; + + if ((non_btb_cs_ipg > IPGIFG_NON_BACK_TO_BACK_IFG_PART1_MAX) || + (non_btb_ipg > IPGIFG_NON_BACK_TO_BACK_IFG_PART2_MAX) || + /*(min_ifg > IPGIFG_MINIMUM_IFG_ENFORCEMENT_MAX) || */ + (btb_ipg > IPGIFG_BACK_TO_BACK_IFG_MAX)) + return -EINVAL; + + value |= + ((non_btb_cs_ipg << IPGIFG_NON_BACK_TO_BACK_IFG_PART1_SHIFT) & + IPGIFG_NBTB_CS_IPG_MASK); + value |= + ((non_btb_ipg << IPGIFG_NON_BACK_TO_BACK_IFG_PART2_SHIFT) & + IPGIFG_NBTB_IPG_MASK); + value |= + ((min_ifg << IPGIFG_MINIMUM_IFG_ENFORCEMENT_SHIFT) & + IPGIFG_MIN_IFG_MASK); + value |= (btb_ipg & IPGIFG_BTB_IPG_MASK); + + out_be32(ipgifg_register, value); + return 0; +} + +static int init_flow_control_params(u32 automatic_flow_control_mode, + int rx_flow_control_enable, + int tx_flow_control_enable, + u16 pause_period, + u16 extension_field, + volatile u32 *upsmr_register, + volatile u32 *uempr_register, + volatile u32 *maccfg1_register) +{ + u32 value = 0; + + /* Set UEMPR register */ + value = (u32) pause_period << UEMPR_PAUSE_TIME_VALUE_SHIFT; + value |= (u32) extension_field << UEMPR_EXTENDED_PAUSE_TIME_VALUE_SHIFT; + out_be32(uempr_register, value); + + /* Set UPSMR register */ + value = in_be32(upsmr_register); + value |= automatic_flow_control_mode; + out_be32(upsmr_register, value); + + value = in_be32(maccfg1_register); + if (rx_flow_control_enable) + value |= MACCFG1_FLOW_RX; + if (tx_flow_control_enable) + value |= MACCFG1_FLOW_TX; + out_be32(maccfg1_register, value); + + return 0; +} + +static int init_hw_statistics_gathering_mode(int enable_hardware_statistics, + int auto_zero_hardware_statistics, + volatile u32 *upsmr_register, + volatile u16 *uescr_register) +{ + u32 upsmr_value = 0; + u16 uescr_value = 0; + /* Enable hardware statistics gathering if requested */ + if (enable_hardware_statistics) { + upsmr_value = in_be32(upsmr_register); + upsmr_value |= UPSMR_HSE; + out_be32(upsmr_register, upsmr_value); + } + + /* Clear hardware statistics counters */ + uescr_value = in_be16(uescr_register); + uescr_value |= UESCR_CLRCNT; + /* Automatically zero hardware statistics counters on read, + if requested */ + if (auto_zero_hardware_statistics) + uescr_value |= UESCR_AUTOZ; + out_be16(uescr_register, uescr_value); + + return 0; +} + +static int init_firmware_statistics_gathering_mode(int + enable_tx_firmware_statistics, + int enable_rx_firmware_statistics, + volatile u32 *tx_rmon_base_ptr, + u32 tx_firmware_statistics_structure_address, + volatile u32 *rx_rmon_base_ptr, + u32 rx_firmware_statistics_structure_address, + volatile u16 *temoder_register, + volatile u32 *remoder_register) +{ + /* Note: this function does not check if */ + /* the parameters it receives are NULL */ + u16 temoder_value; + u32 remoder_value; + + if (enable_tx_firmware_statistics) { + out_be32(tx_rmon_base_ptr, + tx_firmware_statistics_structure_address); + temoder_value = in_be16(temoder_register); + temoder_value |= TEMODER_TX_RMON_STATISTICS_ENABLE; + out_be16(temoder_register, temoder_value); + } + + if (enable_rx_firmware_statistics) { + out_be32(rx_rmon_base_ptr, + rx_firmware_statistics_structure_address); + remoder_value = in_be32(remoder_register); + remoder_value |= REMODER_RX_RMON_STATISTICS_ENABLE; + out_be32(remoder_register, remoder_value); + } + + return 0; +} + +static int init_mac_station_addr_regs(u8 address_byte_0, + u8 address_byte_1, + u8 address_byte_2, + u8 address_byte_3, + u8 address_byte_4, + u8 address_byte_5, + volatile u32 *macstnaddr1_register, + volatile u32 *macstnaddr2_register) +{ + u32 value = 0; + + /* Example: for a station address of 0x12345678ABCD, */ + /* 0x12 is byte 0, 0x34 is byte 1 and so on and 0xCD is byte 5 */ + + /* MACSTNADDR1 Register: */ + + /* 0 7 8 15 */ + /* station address byte 5 station address byte 4 */ + /* 16 23 24 31 */ + /* station address byte 3 station address byte 2 */ + value |= (u32) ((address_byte_2 << 0) & 0x000000FF); + value |= (u32) ((address_byte_3 << 8) & 0x0000FF00); + value |= (u32) ((address_byte_4 << 16) & 0x00FF0000); + value |= (u32) ((address_byte_5 << 24) & 0xFF000000); + + out_be32(macstnaddr1_register, value); + + /* MACSTNADDR2 Register: */ + + /* 0 7 8 15 */ + /* station address byte 1 station address byte 0 */ + /* 16 23 24 31 */ + /* reserved reserved */ + value = 0; + value |= (u32) ((address_byte_0 << 16) & 0x00FF0000); + value |= (u32) ((address_byte_1 << 24) & 0xFF000000); + + out_be32(macstnaddr2_register, value); + + return 0; +} + +static int init_mac_duplex_mode(int full_duplex, + int limited_to_full_duplex, + volatile u32 *maccfg2_register) +{ + u32 value = 0; + + /* some interfaces must work in full duplex mode */ + if ((full_duplex == 0) && (limited_to_full_duplex == 1)) + return -EINVAL; + + value = in_be32(maccfg2_register); + + if (full_duplex) + value |= MACCFG2_FDX; + else + value &= ~MACCFG2_FDX; + + out_be32(maccfg2_register, value); + return 0; +} + +static int init_check_frame_length_mode(int length_check, + volatile u32 *maccfg2_register) +{ + u32 value = 0; + + value = in_be32(maccfg2_register); + + if (length_check) + value |= MACCFG2_LC; + else + value &= ~MACCFG2_LC; + + out_be32(maccfg2_register, value); + return 0; +} + +static int init_preamble_length(u8 preamble_length, + volatile u32 *maccfg2_register) +{ + u32 value = 0; + + if ((preamble_length < 3) || (preamble_length > 7)) + return -EINVAL; + + value = in_be32(maccfg2_register); + value &= ~MACCFG2_PREL_MASK; + value |= (preamble_length << MACCFG2_PREL_SHIFT); + out_be32(maccfg2_register, value); + return 0; +} + +static int init_mii_management_configuration(int reset_mgmt, + int preamble_supress, + volatile u32 *miimcfg_register, + volatile u32 *miimind_register) +{ + unsigned int timeout = PHY_INIT_TIMEOUT; + u32 value = 0; + + value = in_be32(miimcfg_register); + if (reset_mgmt) { + value |= MIIMCFG_RESET_MANAGEMENT; + out_be32(miimcfg_register, value); + } + + value = 0; + + if (preamble_supress) + value |= MIIMCFG_NO_PREAMBLE; + + value |= UCC_GETH_MIIMCFG_MNGMNT_CLC_DIV_INIT; + out_be32(miimcfg_register, value); + + /* Wait until the bus is free */ + while ((in_be32(miimind_register) & MIIMIND_BUSY) && timeout--) + cpu_relax(); + + if (timeout <= 0) { + ugeth_err("%s: The MII Bus is stuck!", __FUNCTION__); + return -ETIMEDOUT; + } + + return 0; +} + +static int init_rx_parameters(int reject_broadcast, + int receive_short_frames, + int promiscuous, volatile u32 *upsmr_register) +{ + u32 value = 0; + + value = in_be32(upsmr_register); + + if (reject_broadcast) + value |= UPSMR_BRO; + else + value &= ~UPSMR_BRO; + + if (receive_short_frames) + value |= UPSMR_RSH; + else + value &= ~UPSMR_RSH; + + if (promiscuous) + value |= UPSMR_PRO; + else + value &= ~UPSMR_PRO; + + out_be32(upsmr_register, value); + + return 0; +} + +static int init_max_rx_buff_len(u16 max_rx_buf_len, + volatile u16 *mrblr_register) +{ + /* max_rx_buf_len value must be a multiple of 128 */ + if ((max_rx_buf_len == 0) + || (max_rx_buf_len % UCC_GETH_MRBLR_ALIGNMENT)) + return -EINVAL; + + out_be16(mrblr_register, max_rx_buf_len); + return 0; +} + +static int init_min_frame_len(u16 min_frame_length, + volatile u16 *minflr_register, + volatile u16 *mrblr_register) +{ + u16 mrblr_value = 0; + + mrblr_value = in_be16(mrblr_register); + if (min_frame_length >= (mrblr_value - 4)) + return -EINVAL; + + out_be16(minflr_register, min_frame_length); + return 0; +} + +static int adjust_enet_interface(ucc_geth_private_t *ugeth) +{ + ucc_geth_info_t *ug_info; + ucc_geth_t *ug_regs; + ucc_fast_t *uf_regs; + enet_speed_e speed; + int ret_val, rpm = 0, tbi = 0, r10m = 0, rmm = + 0, limited_to_full_duplex = 0; + u32 upsmr, maccfg2, utbipar, tbiBaseAddress; + u16 value; + + ugeth_vdbg("%s: IN", __FUNCTION__); + + ug_info = ugeth->ug_info; + ug_regs = ugeth->ug_regs; + uf_regs = ugeth->uccf->uf_regs; + + /* Analyze enet_interface according to Interface Mode Configuration + table */ + ret_val = + get_interface_details(ug_info->enet_interface, &speed, &r10m, &rmm, + &rpm, &tbi, &limited_to_full_duplex); + if (ret_val != 0) { + ugeth_err + ("%s: half duplex not supported in requested configuration.", + __FUNCTION__); + return ret_val; + } + + /* Set MACCFG2 */ + maccfg2 = in_be32(&ug_regs->maccfg2); + maccfg2 &= ~MACCFG2_INTERFACE_MODE_MASK; + if ((speed == ENET_SPEED_10BT) || (speed == ENET_SPEED_100BT)) + maccfg2 |= MACCFG2_INTERFACE_MODE_NIBBLE; + else if (speed == ENET_SPEED_1000BT) + maccfg2 |= MACCFG2_INTERFACE_MODE_BYTE; + maccfg2 |= ug_info->padAndCrc; + out_be32(&ug_regs->maccfg2, maccfg2); + + /* Set UPSMR */ + upsmr = in_be32(&uf_regs->upsmr); + upsmr &= ~(UPSMR_RPM | UPSMR_R10M | UPSMR_TBIM | UPSMR_RMM); + if (rpm) + upsmr |= UPSMR_RPM; + if (r10m) + upsmr |= UPSMR_R10M; + if (tbi) + upsmr |= UPSMR_TBIM; + if (rmm) + upsmr |= UPSMR_RMM; + out_be32(&uf_regs->upsmr, upsmr); + + /* Set UTBIPAR */ + utbipar = in_be32(&ug_regs->utbipar); + utbipar &= ~UTBIPAR_PHY_ADDRESS_MASK; + if (tbi) + utbipar |= + (ug_info->phy_address + + ugeth->ug_info->uf_info. + ucc_num) << UTBIPAR_PHY_ADDRESS_SHIFT; + else + utbipar |= + (0x10 + + ugeth->ug_info->uf_info. + ucc_num) << UTBIPAR_PHY_ADDRESS_SHIFT; + out_be32(&ug_regs->utbipar, utbipar); + + /* Disable autonegotiation in tbi mode, because by default it + comes up in autonegotiation mode. */ + /* Note that this depends on proper setting in utbipar register. */ + if (tbi) { + tbiBaseAddress = in_be32(&ug_regs->utbipar); + tbiBaseAddress &= UTBIPAR_PHY_ADDRESS_MASK; + tbiBaseAddress >>= UTBIPAR_PHY_ADDRESS_SHIFT; + value = + ugeth->mii_info->mdio_read(ugeth->dev, (u8) tbiBaseAddress, + ENET_TBI_MII_CR); + value &= ~0x1000; /* Turn off autonegotiation */ + ugeth->mii_info->mdio_write(ugeth->dev, (u8) tbiBaseAddress, + ENET_TBI_MII_CR, value); + } + + ret_val = init_mac_duplex_mode(1, + limited_to_full_duplex, + &ug_regs->maccfg2); + if (ret_val != 0) { + ugeth_err + ("%s: half duplex not supported in requested configuration.", + __FUNCTION__); + return ret_val; + } + + init_check_frame_length_mode(ug_info->lengthCheckRx, &ug_regs->maccfg2); + + ret_val = init_preamble_length(ug_info->prel, &ug_regs->maccfg2); + if (ret_val != 0) { + ugeth_err + ("%s: Preamble length must be between 3 and 7 inclusive.", + __FUNCTION__); + return ret_val; + } + + return 0; +} + +/* 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 ugeth structure, and this + * function converts those variables into the appropriate + * register values, and can bring down the device if needed. + */ +static void adjust_link(struct net_device *dev) +{ + ucc_geth_private_t *ugeth = netdev_priv(dev); + ucc_geth_t *ug_regs; + u32 tempval; + struct ugeth_mii_info *mii_info = ugeth->mii_info; + + ug_regs = ugeth->ug_regs; + + 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 != ugeth->oldduplex) { + if (!(mii_info->duplex)) { + tempval = in_be32(&ug_regs->maccfg2); + tempval &= ~(MACCFG2_FDX); + out_be32(&ug_regs->maccfg2, tempval); + + ugeth_info("%s: Half Duplex", dev->name); + } else { + tempval = in_be32(&ug_regs->maccfg2); + tempval |= MACCFG2_FDX; + out_be32(&ug_regs->maccfg2, tempval); + + ugeth_info("%s: Full Duplex", dev->name); + } + + ugeth->oldduplex = mii_info->duplex; + } + + if (mii_info->speed != ugeth->oldspeed) { + switch (mii_info->speed) { + case 1000: +#ifdef CONFIG_MPC836x +/* FIXME: This code is for 100Mbs BUG fixing, +remove this when it is fixed!!! */ + if (ugeth->ug_info->enet_interface == + ENET_1000_GMII) + /* Run the commands which initialize the PHY */ + { + tempval = + (u32) mii_info->mdio_read(ugeth-> + dev, mii_info->mii_id, 0x1b); + tempval |= 0x000f; + mii_info->mdio_write(ugeth->dev, + mii_info->mii_id, 0x1b, + (u16) tempval); + tempval = + (u32) mii_info->mdio_read(ugeth-> + dev, mii_info->mii_id, + MII_BMCR); + mii_info->mdio_write(ugeth->dev, + mii_info->mii_id, MII_BMCR, + (u16) (tempval | BMCR_RESET)); + } else if (ugeth->ug_info->enet_interface == + ENET_1000_RGMII) + /* Run the commands which initialize the PHY */ + { + tempval = + (u32) mii_info->mdio_read(ugeth-> + dev, mii_info->mii_id, 0x1b); + tempval = (tempval & ~0x000f) | 0x000b; + mii_info->mdio_write(ugeth->dev, + mii_info->mii_id, 0x1b, + (u16) tempval); + tempval = + (u32) mii_info->mdio_read(ugeth-> + dev, mii_info->mii_id, + MII_BMCR); + mii_info->mdio_write(ugeth->dev, + mii_info->mii_id, MII_BMCR, + (u16) (tempval | BMCR_RESET)); + } + msleep(4000); +#endif /* CONFIG_MPC8360 */ + adjust_enet_interface(ugeth); + break; + case 100: + case 10: +#ifdef CONFIG_MPC836x +/* FIXME: This code is for 100Mbs BUG fixing, +remove this lines when it will be fixed!!! */ + ugeth->ug_info->enet_interface = ENET_100_RGMII; + tempval = + (u32) mii_info->mdio_read(ugeth->dev, + mii_info->mii_id, + 0x1b); + tempval = (tempval & ~0x000f) | 0x000b; + mii_info->mdio_write(ugeth->dev, + mii_info->mii_id, 0x1b, + (u16) tempval); + tempval = + (u32) mii_info->mdio_read(ugeth->dev, + mii_info->mii_id, + MII_BMCR); + mii_info->mdio_write(ugeth->dev, + mii_info->mii_id, MII_BMCR, + (u16) (tempval | + BMCR_RESET)); + msleep(4000); +#endif /* CONFIG_MPC8360 */ + adjust_enet_interface(ugeth); + break; + default: + ugeth_warn + ("%s: Ack! Speed (%d) is not 10/100/1000!", + dev->name, mii_info->speed); + break; + } + + ugeth_info("%s: Speed %dBT", dev->name, + mii_info->speed); + + ugeth->oldspeed = mii_info->speed; + } + + if (!ugeth->oldlink) { + ugeth_info("%s: Link is up", dev->name); + ugeth->oldlink = 1; + netif_carrier_on(dev); + netif_schedule(dev); + } + } else { + if (ugeth->oldlink) { + ugeth_info("%s: Link is down", dev->name); + ugeth->oldlink = 0; + ugeth->oldspeed = 0; + ugeth->oldduplex = -1; + netif_carrier_off(dev); + } + } +} + +/* Configure the PHY for dev. + * returns 0 if success. -1 if failure + */ +static int init_phy(struct net_device *dev) +{ + ucc_geth_private_t *ugeth = netdev_priv(dev); + struct phy_info *curphy; + ucc_mii_mng_t *mii_regs; + struct ugeth_mii_info *mii_info; + int err; + + mii_regs = &ugeth->ug_regs->miimng; + + ugeth->oldlink = 0; + ugeth->oldspeed = 0; + ugeth->oldduplex = -1; + + mii_info = kmalloc(sizeof(struct ugeth_mii_info), GFP_KERNEL); + + if (NULL == mii_info) { + ugeth_err("%s: Could not allocate mii_info", dev->name); + return -ENOMEM; + } + + mii_info->mii_regs = mii_regs; + mii_info->speed = SPEED_1000; + mii_info->duplex = DUPLEX_FULL; + mii_info->pause = 0; + mii_info->link = 0; + + mii_info->advertising = (ADVERTISED_10baseT_Half | + ADVERTISED_10baseT_Full | + ADVERTISED_100baseT_Half | + ADVERTISED_100baseT_Full | + ADVERTISED_1000baseT_Full); + mii_info->autoneg = 1; + + mii_info->mii_id = ugeth->ug_info->phy_address; + + mii_info->dev = dev; + + mii_info->mdio_read = &read_phy_reg; + mii_info->mdio_write = &write_phy_reg; + + ugeth->mii_info = mii_info; + + spin_lock_irq(&ugeth->lock); + + /* Set this UCC to be the master of the MII managment */ + ucc_set_qe_mux_mii_mng(ugeth->ug_info->uf_info.ucc_num); + + if (init_mii_management_configuration(1, + ugeth->ug_info-> + miiPreambleSupress, + &mii_regs->miimcfg, + &mii_regs->miimind)) { + ugeth_err("%s: The MII Bus is stuck!", dev->name); + err = -1; + goto bus_fail; + } + + spin_unlock_irq(&ugeth->lock); + + /* get info for this PHY */ + curphy = get_phy_info(ugeth->mii_info); + + if (curphy == NULL) { + ugeth_err("%s: No PHY found", dev->name); + err = -1; + goto no_phy; + } + + mii_info->phyinfo = curphy; + + /* Run the commands which initialize the PHY */ + if (curphy->init) { + err = curphy->init(ugeth->mii_info); + if (err) + goto phy_init_fail; + } + + return 0; + + phy_init_fail: + no_phy: + bus_fail: + kfree(mii_info); + + return err; +} + +#ifdef CONFIG_UGETH_TX_ON_DEMOND +static int ugeth_transmit_on_demand(ucc_geth_private_t *ugeth) +{ + ucc_fast_transmit_on_demand(ugeth->uccf); + + return 0; +} +#endif + +static int ugeth_graceful_stop_tx(ucc_geth_private_t *ugeth) +{ + ucc_fast_private_t *uccf; + u32 cecr_subblock; + u32 temp; + + uccf = ugeth->uccf; + + /* Mask GRACEFUL STOP TX interrupt bit and clear it */ + temp = in_be32(uccf->p_uccm); + temp &= ~UCCE_GRA; + out_be32(uccf->p_uccm, temp); + out_be32(uccf->p_ucce, UCCE_GRA); /* clear by writing 1 */ + + /* Issue host command */ + cecr_subblock = + ucc_fast_get_qe_cr_subblock(ugeth->ug_info->uf_info.ucc_num); + qe_issue_cmd(QE_GRACEFUL_STOP_TX, cecr_subblock, + (u8) QE_CR_PROTOCOL_ETHERNET, 0); + + /* Wait for command to complete */ + do { + temp = in_be32(uccf->p_ucce); + } while (!(temp & UCCE_GRA)); + + uccf->stopped_tx = 1; + + return 0; +} + +static int ugeth_graceful_stop_rx(ucc_geth_private_t * ugeth) +{ + ucc_fast_private_t *uccf; + u32 cecr_subblock; + u8 temp; + + uccf = ugeth->uccf; + + /* Clear acknowledge bit */ + temp = ugeth->p_rx_glbl_pram->rxgstpack; + temp &= ~GRACEFUL_STOP_ACKNOWLEDGE_RX; + ugeth->p_rx_glbl_pram->rxgstpack = temp; + + /* Keep issuing command and checking acknowledge bit until + it is asserted, according to spec */ + do { + /* Issue host command */ + cecr_subblock = + ucc_fast_get_qe_cr_subblock(ugeth->ug_info->uf_info. + ucc_num); + qe_issue_cmd(QE_GRACEFUL_STOP_RX, cecr_subblock, + (u8) QE_CR_PROTOCOL_ETHERNET, 0); + + temp = ugeth->p_rx_glbl_pram->rxgstpack; + } while (!(temp & GRACEFUL_STOP_ACKNOWLEDGE_RX)); + + uccf->stopped_rx = 1; + + return 0; +} + +static int ugeth_restart_tx(ucc_geth_private_t *ugeth) +{ + ucc_fast_private_t *uccf; + u32 cecr_subblock; + + uccf = ugeth->uccf; + + cecr_subblock = + ucc_fast_get_qe_cr_subblock(ugeth->ug_info->uf_info.ucc_num); + qe_issue_cmd(QE_RESTART_TX, cecr_subblock, (u8) QE_CR_PROTOCOL_ETHERNET, + 0); + uccf->stopped_tx = 0; + + return 0; +} + +static int ugeth_restart_rx(ucc_geth_private_t *ugeth) +{ + ucc_fast_private_t *uccf; + u32 cecr_subblock; + + uccf = ugeth->uccf; + + cecr_subblock = + ucc_fast_get_qe_cr_subblock(ugeth->ug_info->uf_info.ucc_num); + qe_issue_cmd(QE_RESTART_RX, cecr_subblock, (u8) QE_CR_PROTOCOL_ETHERNET, + 0); + uccf->stopped_rx = 0; + + return 0; +} + +static int ugeth_enable(ucc_geth_private_t *ugeth, comm_dir_e mode) +{ + ucc_fast_private_t *uccf; + int enabled_tx, enabled_rx; + + uccf = ugeth->uccf; + + /* check if the UCC number is in range. */ + if (ugeth->ug_info->uf_info.ucc_num >= UCC_MAX_NUM) { + ugeth_err("%s: ucc_num out of range.", __FUNCTION__); + return -EINVAL; + } + + enabled_tx = uccf->enabled_tx; + enabled_rx = uccf->enabled_rx; + + /* Get Tx and Rx going again, in case this channel was actively + disabled. */ + if ((mode & COMM_DIR_TX) && (!enabled_tx) && uccf->stopped_tx) + ugeth_restart_tx(ugeth); + if ((mode & COMM_DIR_RX) && (!enabled_rx) && uccf->stopped_rx) + ugeth_restart_rx(ugeth); + + ucc_fast_enable(uccf, mode); /* OK to do even if not disabled */ + + return 0; + +} + +static int ugeth_disable(ucc_geth_private_t * ugeth, comm_dir_e mode) +{ + ucc_fast_private_t *uccf; + + uccf = ugeth->uccf; + + /* check if the UCC number is in range. */ + if (ugeth->ug_info->uf_info.ucc_num >= UCC_MAX_NUM) { + ugeth_err("%s: ucc_num out of range.", __FUNCTION__); + return -EINVAL; + } + + /* Stop any transmissions */ + if ((mode & COMM_DIR_TX) && uccf->enabled_tx && !uccf->stopped_tx) + ugeth_graceful_stop_tx(ugeth); + + /* Stop any receptions */ + if ((mode & COMM_DIR_RX) && uccf->enabled_rx && !uccf->stopped_rx) + ugeth_graceful_stop_rx(ugeth); + + ucc_fast_disable(ugeth->uccf, mode); /* OK to do even if not enabled */ + + return 0; +} + +static void ugeth_dump_regs(ucc_geth_private_t *ugeth) +{ +#ifdef DEBUG + ucc_fast_dump_regs(ugeth->uccf); + dump_regs(ugeth); + dump_bds(ugeth); +#endif +} + +#ifdef CONFIG_UGETH_FILTERING +static int ugeth_ext_filtering_serialize_tad(ucc_geth_tad_params_t * + p_UccGethTadParams, + qe_fltr_tad_t *qe_fltr_tad) +{ + u16 temp; + + /* Zero serialized TAD */ + memset(qe_fltr_tad, 0, QE_FLTR_TAD_SIZE); + + qe_fltr_tad->serialized[0] |= UCC_GETH_TAD_V; /* Must have this */ + if (p_UccGethTadParams->rx_non_dynamic_extended_features_mode || + (p_UccGethTadParams->vtag_op != UCC_GETH_VLAN_OPERATION_TAGGED_NOP) + || (p_UccGethTadParams->vnontag_op != + UCC_GETH_VLAN_OPERATION_NON_TAGGED_NOP) + ) + qe_fltr_tad->serialized[0] |= UCC_GETH_TAD_EF; + if (p_UccGethTadParams->reject_frame) + qe_fltr_tad->serialized[0] |= UCC_GETH_TAD_REJ; + temp = + (u16) (((u16) p_UccGethTadParams-> + vtag_op) << UCC_GETH_TAD_VTAG_OP_SHIFT); + qe_fltr_tad->serialized[0] |= (u8) (temp >> 8); /* upper bits */ + + qe_fltr_tad->serialized[1] |= (u8) (temp & 0x00ff); /* lower bits */ + if (p_UccGethTadParams->vnontag_op == + UCC_GETH_VLAN_OPERATION_NON_TAGGED_Q_TAG_INSERT) + qe_fltr_tad->serialized[1] |= UCC_GETH_TAD_V_NON_VTAG_OP; + qe_fltr_tad->serialized[1] |= + p_UccGethTadParams->rqos << UCC_GETH_TAD_RQOS_SHIFT; + + qe_fltr_tad->serialized[2] |= + p_UccGethTadParams->vpri << UCC_GETH_TAD_V_PRIORITY_SHIFT; + /* upper bits */ + qe_fltr_tad->serialized[2] |= (u8) (p_UccGethTadParams->vid >> 8); + /* lower bits */ + qe_fltr_tad->serialized[3] |= (u8) (p_UccGethTadParams->vid & 0x00ff); + + return 0; +} + +static enet_addr_container_t + *ugeth_82xx_filtering_get_match_addr_in_hash(ucc_geth_private_t *ugeth, + enet_addr_t *p_enet_addr) +{ + enet_addr_container_t *enet_addr_cont; + struct list_head *p_lh; + u16 i, num; + int32_t j; + u8 *p_counter; + + if ((*p_enet_addr)[0] & ENET_GROUP_ADDR) { + p_lh = &ugeth->group_hash_q; + p_counter = &(ugeth->numGroupAddrInHash); + } else { + p_lh = &ugeth->ind_hash_q; + p_counter = &(ugeth->numIndAddrInHash); + } + + if (!p_lh) + return NULL; + + num = *p_counter; + + for (i = 0; i < num; i++) { + enet_addr_cont = + (enet_addr_container_t *) + ENET_ADDR_CONT_ENTRY(dequeue(p_lh)); + for (j = ENET_NUM_OCTETS_PER_ADDRESS - 1; j >= 0; j--) { + if ((*p_enet_addr)[j] != (enet_addr_cont->address)[j]) + break; + if (j == 0) + return enet_addr_cont; /* Found */ + } + enqueue(p_lh, &enet_addr_cont->node); /* Put it back */ + } + return NULL; +} + +static int ugeth_82xx_filtering_add_addr_in_hash(ucc_geth_private_t *ugeth, + enet_addr_t *p_enet_addr) +{ + ucc_geth_enet_address_recognition_location_e location; + enet_addr_container_t *enet_addr_cont; + struct list_head *p_lh; + u8 i; + u32 limit; + u8 *p_counter; + + if ((*p_enet_addr)[0] & ENET_GROUP_ADDR) { + p_lh = &ugeth->group_hash_q; + limit = ugeth->ug_info->maxGroupAddrInHash; + location = + UCC_GETH_ENET_ADDRESS_RECOGNITION_LOCATION_GROUP_HASH; + p_counter = &(ugeth->numGroupAddrInHash); + } else { + p_lh = &ugeth->ind_hash_q; + limit = ugeth->ug_info->maxIndAddrInHash; + location = + UCC_GETH_ENET_ADDRESS_RECOGNITION_LOCATION_INDIVIDUAL_HASH; + p_counter = &(ugeth->numIndAddrInHash); + } + + if ((enet_addr_cont = + ugeth_82xx_filtering_get_match_addr_in_hash(ugeth, p_enet_addr))) { + list_add(p_lh, &enet_addr_cont->node); /* Put it back */ + return 0; + } + if ((!p_lh) || (!(*p_counter < limit))) + return -EBUSY; + if (!(enet_addr_cont = get_enet_addr_container())) + return -ENOMEM; + for (i = 0; i < ENET_NUM_OCTETS_PER_ADDRESS; i++) + (enet_addr_cont->address)[i] = (*p_enet_addr)[i]; + enet_addr_cont->location = location; + enqueue(p_lh, &enet_addr_cont->node); /* Put it back */ + ++(*p_counter); + + hw_add_addr_in_hash(ugeth, &(enet_addr_cont->address)); + + return 0; +} + +static int ugeth_82xx_filtering_clear_addr_in_hash(ucc_geth_private_t *ugeth, + enet_addr_t *p_enet_addr) +{ + ucc_geth_82xx_address_filtering_pram_t *p_82xx_addr_filt; + enet_addr_container_t *enet_addr_cont; + ucc_fast_private_t *uccf; + comm_dir_e comm_dir; + u16 i, num; + struct list_head *p_lh; + u32 *addr_h, *addr_l; + u8 *p_counter; + + uccf = ugeth->uccf; + + p_82xx_addr_filt = + (ucc_geth_82xx_address_filtering_pram_t *) ugeth->p_rx_glbl_pram-> + addressfiltering; + + if (! + (enet_addr_cont = + ugeth_82xx_filtering_get_match_addr_in_hash(ugeth, p_enet_addr))) + return -ENOENT; + + /* It's been found and removed from the CQ. */ + /* Now destroy its container */ + put_enet_addr_container(enet_addr_cont); + + if ((*p_enet_addr)[0] & ENET_GROUP_ADDR) { + addr_h = &(p_82xx_addr_filt->gaddr_h); + addr_l = &(p_82xx_addr_filt->gaddr_l); + p_lh = &ugeth->group_hash_q; + p_counter = &(ugeth->numGroupAddrInHash); + } else { + addr_h = &(p_82xx_addr_filt->iaddr_h); + addr_l = &(p_82xx_addr_filt->iaddr_l); + p_lh = &ugeth->ind_hash_q; + p_counter = &(ugeth->numIndAddrInHash); + } + + comm_dir = 0; + if (uccf->enabled_tx) + comm_dir |= COMM_DIR_TX; + if (uccf->enabled_rx) + comm_dir |= COMM_DIR_RX; + if (comm_dir) + ugeth_disable(ugeth, comm_dir); + + /* Clear the hash table. */ + out_be32(addr_h, 0x00000000); + out_be32(addr_l, 0x00000000); + + /* Add all remaining CQ elements back into hash */ + num = --(*p_counter); + for (i = 0; i < num; i++) { + enet_addr_cont = + (enet_addr_container_t *) + ENET_ADDR_CONT_ENTRY(dequeue(p_lh)); + hw_add_addr_in_hash(ugeth, &(enet_addr_cont->address)); + enqueue(p_lh, &enet_addr_cont->node); /* Put it back */ + } + + if (comm_dir) + ugeth_enable(ugeth, comm_dir); + + return 0; +} +#endif /* CONFIG_UGETH_FILTERING */ + +static int ugeth_82xx_filtering_clear_all_addr_in_hash(ucc_geth_private_t * + ugeth, + enet_addr_type_e + enet_addr_type) +{ + ucc_geth_82xx_address_filtering_pram_t *p_82xx_addr_filt; + ucc_fast_private_t *uccf; + comm_dir_e comm_dir; + struct list_head *p_lh; + u16 i, num; + u32 *addr_h, *addr_l; + u8 *p_counter; + + uccf = ugeth->uccf; + + p_82xx_addr_filt = + (ucc_geth_82xx_address_filtering_pram_t *) ugeth->p_rx_glbl_pram-> + addressfiltering; + + if (enet_addr_type == ENET_ADDR_TYPE_GROUP) { + addr_h = &(p_82xx_addr_filt->gaddr_h); + addr_l = &(p_82xx_addr_filt->gaddr_l); + p_lh = &ugeth->group_hash_q; + p_counter = &(ugeth->numGroupAddrInHash); + } else if (enet_addr_type == ENET_ADDR_TYPE_INDIVIDUAL) { + addr_h = &(p_82xx_addr_filt->iaddr_h); + addr_l = &(p_82xx_addr_filt->iaddr_l); + p_lh = &ugeth->ind_hash_q; + p_counter = &(ugeth->numIndAddrInHash); + } else + return -EINVAL; + + comm_dir = 0; + if (uccf->enabled_tx) + comm_dir |= COMM_DIR_TX; + if (uccf->enabled_rx) + comm_dir |= COMM_DIR_RX; + if (comm_dir) + ugeth_disable(ugeth, comm_dir); + + /* Clear the hash table. */ + out_be32(addr_h, 0x00000000); + out_be32(addr_l, 0x00000000); + + if (!p_lh) + return 0; + + num = *p_counter; + + /* Delete all remaining CQ elements */ + for (i = 0; i < num; i++) + put_enet_addr_container(ENET_ADDR_CONT_ENTRY(dequeue(p_lh))); + + *p_counter = 0; + + if (comm_dir) + ugeth_enable(ugeth, comm_dir); + + return 0; +} + +#ifdef CONFIG_UGETH_FILTERING +static int ugeth_82xx_filtering_add_addr_in_paddr(ucc_geth_private_t *ugeth, + enet_addr_t *p_enet_addr, + u8 paddr_num) +{ + int i; + + if ((*p_enet_addr)[0] & ENET_GROUP_ADDR) + ugeth_warn + ("%s: multicast address added to paddr will have no " + "effect - is this what you wanted?", + __FUNCTION__); + + ugeth->indAddrRegUsed[paddr_num] = 1; /* mark this paddr as used */ + /* store address in our database */ + for (i = 0; i < ENET_NUM_OCTETS_PER_ADDRESS; i++) + ugeth->paddr[paddr_num][i] = (*p_enet_addr)[i]; + /* put in hardware */ + return hw_add_addr_in_paddr(ugeth, p_enet_addr, paddr_num); +} +#endif /* CONFIG_UGETH_FILTERING */ + +static int ugeth_82xx_filtering_clear_addr_in_paddr(ucc_geth_private_t *ugeth, + u8 paddr_num) +{ + ugeth->indAddrRegUsed[paddr_num] = 0; /* mark this paddr as not used */ + return hw_clear_addr_in_paddr(ugeth, paddr_num);/* clear in hardware */ +} + +static void ucc_geth_memclean(ucc_geth_private_t *ugeth) +{ + u16 i, j; + u8 *bd; + + if (!ugeth) + return; + + if (ugeth->uccf) + ucc_fast_free(ugeth->uccf); + + if (ugeth->p_thread_data_tx) { + qe_muram_free(ugeth->thread_dat_tx_offset); + ugeth->p_thread_data_tx = NULL; + } + if (ugeth->p_thread_data_rx) { + qe_muram_free(ugeth->thread_dat_rx_offset); + ugeth->p_thread_data_rx = NULL; + } + if (ugeth->p_exf_glbl_param) { + qe_muram_free(ugeth->exf_glbl_param_offset); + ugeth->p_exf_glbl_param = NULL; + } + if (ugeth->p_rx_glbl_pram) { + qe_muram_free(ugeth->rx_glbl_pram_offset); + ugeth->p_rx_glbl_pram = NULL; + } + if (ugeth->p_tx_glbl_pram) { + qe_muram_free(ugeth->tx_glbl_pram_offset); + ugeth->p_tx_glbl_pram = NULL; + } + if (ugeth->p_send_q_mem_reg) { + qe_muram_free(ugeth->send_q_mem_reg_offset); + ugeth->p_send_q_mem_reg = NULL; + } + if (ugeth->p_scheduler) { + qe_muram_free(ugeth->scheduler_offset); + ugeth->p_scheduler = NULL; + } + if (ugeth->p_tx_fw_statistics_pram) { + qe_muram_free(ugeth->tx_fw_statistics_pram_offset); + ugeth->p_tx_fw_statistics_pram = NULL; + } + if (ugeth->p_rx_fw_statistics_pram) { + qe_muram_free(ugeth->rx_fw_statistics_pram_offset); + ugeth->p_rx_fw_statistics_pram = NULL; + } + if (ugeth->p_rx_irq_coalescing_tbl) { + qe_muram_free(ugeth->rx_irq_coalescing_tbl_offset); + ugeth->p_rx_irq_coalescing_tbl = NULL; + } + if (ugeth->p_rx_bd_qs_tbl) { + qe_muram_free(ugeth->rx_bd_qs_tbl_offset); + ugeth->p_rx_bd_qs_tbl = NULL; + } + if (ugeth->p_init_enet_param_shadow) { + return_init_enet_entries(ugeth, + &(ugeth->p_init_enet_param_shadow-> + rxthread[0]), + ENET_INIT_PARAM_MAX_ENTRIES_RX, + ugeth->ug_info->riscRx, 1); + return_init_enet_entries(ugeth, + &(ugeth->p_init_enet_param_shadow-> + txthread[0]), + ENET_INIT_PARAM_MAX_ENTRIES_TX, + ugeth->ug_info->riscTx, 0); + kfree(ugeth->p_init_enet_param_shadow); + ugeth->p_init_enet_param_shadow = NULL; + } + for (i = 0; i < ugeth->ug_info->numQueuesTx; i++) { + bd = ugeth->p_tx_bd_ring[i]; + for (j = 0; j < ugeth->ug_info->bdRingLenTx[i]; j++) { + if (ugeth->tx_skbuff[i][j]) { + dma_unmap_single(NULL, + BD_BUFFER_ARG(bd), + (BD_STATUS_AND_LENGTH(bd) & + BD_LENGTH_MASK), + DMA_TO_DEVICE); + dev_kfree_skb_any(ugeth->tx_skbuff[i][j]); + ugeth->tx_skbuff[i][j] = NULL; + } + } + + kfree(ugeth->tx_skbuff[i]); + + if (ugeth->p_tx_bd_ring[i]) { + if (ugeth->ug_info->uf_info.bd_mem_part == + MEM_PART_SYSTEM) + kfree((void *)ugeth->tx_bd_ring_offset[i]); + else if (ugeth->ug_info->uf_info.bd_mem_part == + MEM_PART_MURAM) + qe_muram_free(ugeth->tx_bd_ring_offset[i]); + ugeth->p_tx_bd_ring[i] = NULL; + } + } + for (i = 0; i < ugeth->ug_info->numQueuesRx; i++) { + if (ugeth->p_rx_bd_ring[i]) { + /* Return existing data buffers in ring */ + bd = ugeth->p_rx_bd_ring[i]; + for (j = 0; j < ugeth->ug_info->bdRingLenRx[i]; j++) { + if (ugeth->rx_skbuff[i][j]) { + dma_unmap_single(NULL, BD_BUFFER(bd), + ugeth->ug_info-> + uf_info. + max_rx_buf_length + + UCC_GETH_RX_DATA_BUF_ALIGNMENT, + DMA_FROM_DEVICE); + + dev_kfree_skb_any(ugeth-> + rx_skbuff[i][j]); + ugeth->rx_skbuff[i][j] = NULL; + } + bd += UCC_GETH_SIZE_OF_BD; + } + + kfree(ugeth->rx_skbuff[i]); + + if (ugeth->ug_info->uf_info.bd_mem_part == + MEM_PART_SYSTEM) + kfree((void *)ugeth->rx_bd_ring_offset[i]); + else if (ugeth->ug_info->uf_info.bd_mem_part == + MEM_PART_MURAM) + qe_muram_free(ugeth->rx_bd_ring_offset[i]); + ugeth->p_rx_bd_ring[i] = NULL; + } + } + while (!list_empty(&ugeth->group_hash_q)) + put_enet_addr_container(ENET_ADDR_CONT_ENTRY + (dequeue(&ugeth->group_hash_q))); + while (!list_empty(&ugeth->ind_hash_q)) + put_enet_addr_container(ENET_ADDR_CONT_ENTRY + (dequeue(&ugeth->ind_hash_q))); + +} + +static void ucc_geth_set_multi(struct net_device *dev) +{ + ucc_geth_private_t *ugeth; + struct dev_mc_list *dmi; + ucc_fast_t *uf_regs; + ucc_geth_82xx_address_filtering_pram_t *p_82xx_addr_filt; + enet_addr_t tempaddr; + u8 *mcptr, *tdptr; + int i, j; + + ugeth = netdev_priv(dev); + + uf_regs = ugeth->uccf->uf_regs; + + if (dev->flags & IFF_PROMISC) { + + /* Log any net taps. */ + printk("%s: Promiscuous mode enabled.\n", dev->name); + uf_regs->upsmr |= UPSMR_PRO; + + } else { + + uf_regs->upsmr &= ~UPSMR_PRO; + + p_82xx_addr_filt = + (ucc_geth_82xx_address_filtering_pram_t *) ugeth-> + p_rx_glbl_pram->addressfiltering; + + if (dev->flags & IFF_ALLMULTI) { + /* Catch all multicast addresses, so set the + * filter to all 1's. + */ + out_be32(&p_82xx_addr_filt->gaddr_h, 0xffffffff); + out_be32(&p_82xx_addr_filt->gaddr_l, 0xffffffff); + } else { + /* Clear filter and add the addresses in the list. + */ + out_be32(&p_82xx_addr_filt->gaddr_h, 0x0); + out_be32(&p_82xx_addr_filt->gaddr_l, 0x0); + + dmi = dev->mc_list; + + for (i = 0; i < dev->mc_count; i++, dmi = dmi->next) { + + /* Only support group multicast for now. + */ + if (!(dmi->dmi_addr[0] & 1)) + continue; + + /* The address in dmi_addr is LSB first, + * and taddr is MSB first. We have to + * copy bytes MSB first from dmi_addr. + */ + mcptr = (u8 *) dmi->dmi_addr + 5; + tdptr = (u8 *) & tempaddr; + for (j = 0; j < 6; j++) + *tdptr++ = *mcptr--; + + /* Ask CPM to run CRC and set bit in + * filter mask. + */ + hw_add_addr_in_hash(ugeth, &tempaddr); + + } + } + } +} + +static void ucc_geth_stop(ucc_geth_private_t *ugeth) +{ + ucc_geth_t *ug_regs = ugeth->ug_regs; + u32 tempval; + + ugeth_vdbg("%s: IN", __FUNCTION__); + + /* Disable the controller */ + ugeth_disable(ugeth, COMM_DIR_RX_AND_TX); + + /* Tell the kernel the link is down */ + ugeth->mii_info->link = 0; + adjust_link(ugeth->dev); + + /* Mask all interrupts */ + out_be32(ugeth->uccf->p_ucce, 0x00000000); + + /* Clear all interrupts */ + out_be32(ugeth->uccf->p_ucce, 0xffffffff); + + /* Disable Rx and Tx */ + tempval = in_be32(&ug_regs->maccfg1); + tempval &= ~(MACCFG1_ENABLE_RX | MACCFG1_ENABLE_TX); + out_be32(&ug_regs->maccfg1, tempval); + + if (ugeth->ug_info->board_flags & FSL_UGETH_BRD_HAS_PHY_INTR) { + /* Clear any pending interrupts */ + mii_clear_phy_interrupt(ugeth->mii_info); + + /* Disable PHY Interrupts */ + mii_configure_phy_interrupt(ugeth->mii_info, + MII_INTERRUPT_DISABLED); + } + + free_irq(ugeth->ug_info->uf_info.irq, ugeth->dev); + + if (ugeth->ug_info->board_flags & FSL_UGETH_BRD_HAS_PHY_INTR) { + free_irq(ugeth->ug_info->phy_interrupt, ugeth->dev); + } else { + del_timer_sync(&ugeth->phy_info_timer); + } + + ucc_geth_memclean(ugeth); +} + +static int ucc_geth_startup(ucc_geth_private_t *ugeth) +{ + ucc_geth_82xx_address_filtering_pram_t *p_82xx_addr_filt; + ucc_geth_init_pram_t *p_init_enet_pram; + ucc_fast_private_t *uccf; + ucc_geth_info_t *ug_info; + ucc_fast_info_t *uf_info; + ucc_fast_t *uf_regs; + ucc_geth_t *ug_regs; + int ret_val = -EINVAL; + u32 remoder = UCC_GETH_REMODER_INIT; + u32 init_enet_pram_offset, cecr_subblock, command, maccfg1; + u32 ifstat, i, j, size, l2qt, l3qt, length; + u16 temoder = UCC_GETH_TEMODER_INIT; + u16 test; + u8 function_code = 0; + u8 *bd, *endOfRing; + u8 numThreadsRxNumerical, numThreadsTxNumerical; + + ugeth_vdbg("%s: IN", __FUNCTION__); + + ug_info = ugeth->ug_info; + uf_info = &ug_info->uf_info; + + if (!((uf_info->bd_mem_part == MEM_PART_SYSTEM) || + (uf_info->bd_mem_part == MEM_PART_MURAM))) { + ugeth_err("%s: Bad memory partition value.", __FUNCTION__); + return -EINVAL; + } + + /* Rx BD lengths */ + for (i = 0; i < ug_info->numQueuesRx; i++) { + if ((ug_info->bdRingLenRx[i] < UCC_GETH_RX_BD_RING_SIZE_MIN) || + (ug_info->bdRingLenRx[i] % + UCC_GETH_RX_BD_RING_SIZE_ALIGNMENT)) { + ugeth_err + ("%s: Rx BD ring length must be multiple of 4," + " no smaller than 8.", __FUNCTION__); + return -EINVAL; + } + } + + /* Tx BD lengths */ + for (i = 0; i < ug_info->numQueuesTx; i++) { + if (ug_info->bdRingLenTx[i] < UCC_GETH_TX_BD_RING_SIZE_MIN) { + ugeth_err + ("%s: Tx BD ring length must be no smaller than 2.", + __FUNCTION__); + return -EINVAL; + } + } + + /* mrblr */ + if ((uf_info->max_rx_buf_length == 0) || + (uf_info->max_rx_buf_length % UCC_GETH_MRBLR_ALIGNMENT)) { + ugeth_err + ("%s: max_rx_buf_length must be non-zero multiple of 128.", + __FUNCTION__); + return -EINVAL; + } + + /* num Tx queues */ + if (ug_info->numQueuesTx > NUM_TX_QUEUES) { + ugeth_err("%s: number of tx queues too large.", __FUNCTION__); + return -EINVAL; + } + + /* num Rx queues */ + if (ug_info->numQueuesRx > NUM_RX_QUEUES) { + ugeth_err("%s: number of rx queues too large.", __FUNCTION__); + return -EINVAL; + } + + /* l2qt */ + for (i = 0; i < UCC_GETH_VLAN_PRIORITY_MAX; i++) { + if (ug_info->l2qt[i] >= ug_info->numQueuesRx) { + ugeth_err + ("%s: VLAN priority table entry must not be" + " larger than number of Rx queues.", + __FUNCTION__); + return -EINVAL; + } + } + + /* l3qt */ + for (i = 0; i < UCC_GETH_IP_PRIORITY_MAX; i++) { + if (ug_info->l3qt[i] >= ug_info->numQueuesRx) { + ugeth_err + ("%s: IP priority table entry must not be" + " larger than number of Rx queues.", + __FUNCTION__); + return -EINVAL; + } + } + + if (ug_info->cam && !ug_info->ecamptr) { + ugeth_err("%s: If cam mode is chosen, must supply cam ptr.", + __FUNCTION__); + return -EINVAL; + } + + if ((ug_info->numStationAddresses != + UCC_GETH_NUM_OF_STATION_ADDRESSES_1) + && ug_info->rxExtendedFiltering) { + ugeth_err("%s: Number of station addresses greater than 1 " + "not allowed in extended parsing mode.", + __FUNCTION__); + return -EINVAL; + } + + /* Generate uccm_mask for receive */ + uf_info->uccm_mask = ug_info->eventRegMask & UCCE_OTHER;/* Errors */ + for (i = 0; i < ug_info->numQueuesRx; i++) + uf_info->uccm_mask |= (UCCE_RXBF_SINGLE_MASK << i); + + for (i = 0; i < ug_info->numQueuesTx; i++) + uf_info->uccm_mask |= (UCCE_TXBF_SINGLE_MASK << i); + /* Initialize the general fast UCC block. */ + if (ucc_fast_init(uf_info, &uccf)) { + ugeth_err("%s: Failed to init uccf.", __FUNCTION__); + ucc_geth_memclean(ugeth); + return -ENOMEM; + } + ugeth->uccf = uccf; + + switch (ug_info->numThreadsRx) { + case UCC_GETH_NUM_OF_THREADS_1: + numThreadsRxNumerical = 1; + break; + case UCC_GETH_NUM_OF_THREADS_2: + numThreadsRxNumerical = 2; + break; + case UCC_GETH_NUM_OF_THREADS_4: + numThreadsRxNumerical = 4; + break; + case UCC_GETH_NUM_OF_THREADS_6: + numThreadsRxNumerical = 6; + break; + case UCC_GETH_NUM_OF_THREADS_8: + numThreadsRxNumerical = 8; + break; + default: + ugeth_err("%s: Bad number of Rx threads value.", __FUNCTION__); + ucc_geth_memclean(ugeth); + return -EINVAL; + break; + } + + switch (ug_info->numThreadsTx) { + case UCC_GETH_NUM_OF_THREADS_1: + numThreadsTxNumerical = 1; + break; + case UCC_GETH_NUM_OF_THREADS_2: + numThreadsTxNumerical = 2; + break; + case UCC_GETH_NUM_OF_THREADS_4: + numThreadsTxNumerical = 4; + break; + case UCC_GETH_NUM_OF_THREADS_6: + numThreadsTxNumerical = 6; + break; + case UCC_GETH_NUM_OF_THREADS_8: + numThreadsTxNumerical = 8; + break; + default: + ugeth_err("%s: Bad number of Tx threads value.", __FUNCTION__); + ucc_geth_memclean(ugeth); + return -EINVAL; + break; + } + + /* Calculate rx_extended_features */ + ugeth->rx_non_dynamic_extended_features = ug_info->ipCheckSumCheck || + ug_info->ipAddressAlignment || + (ug_info->numStationAddresses != + UCC_GETH_NUM_OF_STATION_ADDRESSES_1); + + ugeth->rx_extended_features = ugeth->rx_non_dynamic_extended_features || + (ug_info->vlanOperationTagged != UCC_GETH_VLAN_OPERATION_TAGGED_NOP) + || (ug_info->vlanOperationNonTagged != + UCC_GETH_VLAN_OPERATION_NON_TAGGED_NOP); + + uf_regs = uccf->uf_regs; + ug_regs = (ucc_geth_t *) (uccf->uf_regs); + ugeth->ug_regs = ug_regs; + + init_default_reg_vals(&uf_regs->upsmr, + &ug_regs->maccfg1, &ug_regs->maccfg2); + + /* Set UPSMR */ + /* For more details see the hardware spec. */ + init_rx_parameters(ug_info->bro, + ug_info->rsh, ug_info->pro, &uf_regs->upsmr); + + /* We're going to ignore other registers for now, */ + /* except as needed to get up and running */ + + /* Set MACCFG1 */ + /* For more details see the hardware spec. */ + init_flow_control_params(ug_info->aufc, + ug_info->receiveFlowControl, + 1, + ug_info->pausePeriod, + ug_info->extensionField, + &uf_regs->upsmr, + &ug_regs->uempr, &ug_regs->maccfg1); + + maccfg1 = in_be32(&ug_regs->maccfg1); + maccfg1 |= MACCFG1_ENABLE_RX; + maccfg1 |= MACCFG1_ENABLE_TX; + out_be32(&ug_regs->maccfg1, maccfg1); + + /* Set IPGIFG */ + /* For more details see the hardware spec. */ + ret_val = init_inter_frame_gap_params(ug_info->nonBackToBackIfgPart1, + ug_info->nonBackToBackIfgPart2, + ug_info-> + miminumInterFrameGapEnforcement, + ug_info->backToBackInterFrameGap, + &ug_regs->ipgifg); + if (ret_val != 0) { + ugeth_err("%s: IPGIFG initialization parameter too large.", + __FUNCTION__); + ucc_geth_memclean(ugeth); + return ret_val; + } + + /* Set HAFDUP */ + /* For more details see the hardware spec. */ + ret_val = init_half_duplex_params(ug_info->altBeb, + ug_info->backPressureNoBackoff, + ug_info->noBackoff, + ug_info->excessDefer, + ug_info->altBebTruncation, + ug_info->maxRetransmission, + ug_info->collisionWindow, + &ug_regs->hafdup); + if (ret_val != 0) { + ugeth_err("%s: Half Duplex initialization parameter too large.", + __FUNCTION__); + ucc_geth_memclean(ugeth); + return ret_val; + } + + /* Set IFSTAT */ + /* For more details see the hardware spec. */ + /* Read only - resets upon read */ + ifstat = in_be32(&ug_regs->ifstat); + + /* Clear UEMPR */ + /* For more details see the hardware spec. */ + out_be32(&ug_regs->uempr, 0); + + /* Set UESCR */ + /* For more details see the hardware spec. */ + init_hw_statistics_gathering_mode((ug_info->statisticsMode & + UCC_GETH_STATISTICS_GATHERING_MODE_HARDWARE), + 0, &uf_regs->upsmr, &ug_regs->uescr); + + /* Allocate Tx bds */ + for (j = 0; j < ug_info->numQueuesTx; j++) { + /* Allocate in multiple of + UCC_GETH_TX_BD_RING_SIZE_MEMORY_ALIGNMENT, + according to spec */ + length = ((ug_info->bdRingLenTx[j] * UCC_GETH_SIZE_OF_BD) + / UCC_GETH_TX_BD_RING_SIZE_MEMORY_ALIGNMENT) + * UCC_GETH_TX_BD_RING_SIZE_MEMORY_ALIGNMENT; + if ((ug_info->bdRingLenTx[j] * UCC_GETH_SIZE_OF_BD) % + UCC_GETH_TX_BD_RING_SIZE_MEMORY_ALIGNMENT) + length += UCC_GETH_TX_BD_RING_SIZE_MEMORY_ALIGNMENT; + if (uf_info->bd_mem_part == MEM_PART_SYSTEM) { + u32 align = 4; + if (UCC_GETH_TX_BD_RING_ALIGNMENT > 4) + align = UCC_GETH_TX_BD_RING_ALIGNMENT; + ugeth->tx_bd_ring_offset[j] = + (u32) (kmalloc((u32) (length + align), + GFP_KERNEL)); + if (ugeth->tx_bd_ring_offset[j] != 0) + ugeth->p_tx_bd_ring[j] = + (void*)((ugeth->tx_bd_ring_offset[j] + + align) & ~(align - 1)); + } else if (uf_info->bd_mem_part == MEM_PART_MURAM) { + ugeth->tx_bd_ring_offset[j] = + qe_muram_alloc(length, + UCC_GETH_TX_BD_RING_ALIGNMENT); + if (!IS_MURAM_ERR(ugeth->tx_bd_ring_offset[j])) + ugeth->p_tx_bd_ring[j] = + (u8 *) qe_muram_addr(ugeth-> + tx_bd_ring_offset[j]); + } + if (!ugeth->p_tx_bd_ring[j]) { + ugeth_err + ("%s: Can not allocate memory for Tx bd rings.", + __FUNCTION__); + ucc_geth_memclean(ugeth); + return -ENOMEM; + } + /* Zero unused end of bd ring, according to spec */ + memset(ugeth->p_tx_bd_ring[j] + + ug_info->bdRingLenTx[j] * UCC_GETH_SIZE_OF_BD, 0, + length - ug_info->bdRingLenTx[j] * UCC_GETH_SIZE_OF_BD); + } + + /* Allocate Rx bds */ + for (j = 0; j < ug_info->numQueuesRx; j++) { + length = ug_info->bdRingLenRx[j] * UCC_GETH_SIZE_OF_BD; + if (uf_info->bd_mem_part == MEM_PART_SYSTEM) { + u32 align = 4; + if (UCC_GETH_RX_BD_RING_ALIGNMENT > 4) + align = UCC_GETH_RX_BD_RING_ALIGNMENT; + ugeth->rx_bd_ring_offset[j] = + (u32) (kmalloc((u32) (length + align), GFP_KERNEL)); + if (ugeth->rx_bd_ring_offset[j] != 0) + ugeth->p_rx_bd_ring[j] = + (void*)((ugeth->rx_bd_ring_offset[j] + + align) & ~(align - 1)); + } else if (uf_info->bd_mem_part == MEM_PART_MURAM) { + ugeth->rx_bd_ring_offset[j] = + qe_muram_alloc(length, + UCC_GETH_RX_BD_RING_ALIGNMENT); + if (!IS_MURAM_ERR(ugeth->rx_bd_ring_offset[j])) + ugeth->p_rx_bd_ring[j] = + (u8 *) qe_muram_addr(ugeth-> + rx_bd_ring_offset[j]); + } + if (!ugeth->p_rx_bd_ring[j]) { + ugeth_err + ("%s: Can not allocate memory for Rx bd rings.", + __FUNCTION__); + ucc_geth_memclean(ugeth); + return -ENOMEM; + } + } + + /* Init Tx bds */ + for (j = 0; j < ug_info->numQueuesTx; j++) { + /* Setup the skbuff rings */ + ugeth->tx_skbuff[j] = + (struct sk_buff **)kmalloc(sizeof(struct sk_buff *) * + ugeth->ug_info->bdRingLenTx[j], + GFP_KERNEL); + + if (ugeth->tx_skbuff[j] == NULL) { + ugeth_err("%s: Could not allocate tx_skbuff", + __FUNCTION__); + ucc_geth_memclean(ugeth); + return -ENOMEM; + } + + for (i = 0; i < ugeth->ug_info->bdRingLenTx[j]; i++) + ugeth->tx_skbuff[j][i] = NULL; + + ugeth->skb_curtx[j] = ugeth->skb_dirtytx[j] = 0; + bd = ugeth->confBd[j] = ugeth->txBd[j] = ugeth->p_tx_bd_ring[j]; + for (i = 0; i < ug_info->bdRingLenTx[j]; i++) { + BD_BUFFER_CLEAR(bd); + BD_STATUS_AND_LENGTH_SET(bd, 0); + bd += UCC_GETH_SIZE_OF_BD; + } + bd -= UCC_GETH_SIZE_OF_BD; + BD_STATUS_AND_LENGTH_SET(bd, T_W);/* for last BD set Wrap bit */ + } + + /* Init Rx bds */ + for (j = 0; j < ug_info->numQueuesRx; j++) { + /* Setup the skbuff rings */ + ugeth->rx_skbuff[j] = + (struct sk_buff **)kmalloc(sizeof(struct sk_buff *) * + ugeth->ug_info->bdRingLenRx[j], + GFP_KERNEL); + + if (ugeth->rx_skbuff[j] == NULL) { + ugeth_err("%s: Could not allocate rx_skbuff", + __FUNCTION__); + ucc_geth_memclean(ugeth); + return -ENOMEM; + } + + for (i = 0; i < ugeth->ug_info->bdRingLenRx[j]; i++) + ugeth->rx_skbuff[j][i] = NULL; + + ugeth->skb_currx[j] = 0; + bd = ugeth->rxBd[j] = ugeth->p_rx_bd_ring[j]; + for (i = 0; i < ug_info->bdRingLenRx[j]; i++) { + BD_STATUS_AND_LENGTH_SET(bd, R_I); + BD_BUFFER_CLEAR(bd); + bd += UCC_GETH_SIZE_OF_BD; + } + bd -= UCC_GETH_SIZE_OF_BD; + BD_STATUS_AND_LENGTH_SET(bd, R_W);/* for last BD set Wrap bit */ + } + + /* + * Global PRAM + */ + /* Tx global PRAM */ + /* Allocate global tx parameter RAM page */ + ugeth->tx_glbl_pram_offset = + qe_muram_alloc(sizeof(ucc_geth_tx_global_pram_t), + UCC_GETH_TX_GLOBAL_PRAM_ALIGNMENT); + if (IS_MURAM_ERR(ugeth->tx_glbl_pram_offset)) { + ugeth_err + ("%s: Can not allocate DPRAM memory for p_tx_glbl_pram.", + __FUNCTION__); + ucc_geth_memclean(ugeth); + return -ENOMEM; + } + ugeth->p_tx_glbl_pram = + (ucc_geth_tx_global_pram_t *) qe_muram_addr(ugeth-> + tx_glbl_pram_offset); + /* Zero out p_tx_glbl_pram */ + memset(ugeth->p_tx_glbl_pram, 0, sizeof(ucc_geth_tx_global_pram_t)); + + /* Fill global PRAM */ + + /* TQPTR */ + /* Size varies with number of Tx threads */ + ugeth->thread_dat_tx_offset = + qe_muram_alloc(numThreadsTxNumerical * + sizeof(ucc_geth_thread_data_tx_t) + + 32 * (numThreadsTxNumerical == 1), + UCC_GETH_THREAD_DATA_ALIGNMENT); + if (IS_MURAM_ERR(ugeth->thread_dat_tx_offset)) { + ugeth_err + ("%s: Can not allocate DPRAM memory for p_thread_data_tx.", + __FUNCTION__); + ucc_geth_memclean(ugeth); + return -ENOMEM; + } + + ugeth->p_thread_data_tx = + (ucc_geth_thread_data_tx_t *) qe_muram_addr(ugeth-> + thread_dat_tx_offset); + out_be32(&ugeth->p_tx_glbl_pram->tqptr, ugeth->thread_dat_tx_offset); + + /* vtagtable */ + for (i = 0; i < UCC_GETH_TX_VTAG_TABLE_ENTRY_MAX; i++) + out_be32(&ugeth->p_tx_glbl_pram->vtagtable[i], + ug_info->vtagtable[i]); + + /* iphoffset */ + for (i = 0; i < TX_IP_OFFSET_ENTRY_MAX; i++) + ugeth->p_tx_glbl_pram->iphoffset[i] = ug_info->iphoffset[i]; + + /* SQPTR */ + /* Size varies with number of Tx queues */ + ugeth->send_q_mem_reg_offset = + qe_muram_alloc(ug_info->numQueuesTx * + sizeof(ucc_geth_send_queue_qd_t), + UCC_GETH_SEND_QUEUE_QUEUE_DESCRIPTOR_ALIGNMENT); + if (IS_MURAM_ERR(ugeth->send_q_mem_reg_offset)) { + ugeth_err + ("%s: Can not allocate DPRAM memory for p_send_q_mem_reg.", + __FUNCTION__); + ucc_geth_memclean(ugeth); + return -ENOMEM; + } + + ugeth->p_send_q_mem_reg = + (ucc_geth_send_queue_mem_region_t *) qe_muram_addr(ugeth-> + send_q_mem_reg_offset); + out_be32(&ugeth->p_tx_glbl_pram->sqptr, ugeth->send_q_mem_reg_offset); + + /* Setup the table */ + /* Assume BD rings are already established */ + for (i = 0; i < ug_info->numQueuesTx; i++) { + endOfRing = + ugeth->p_tx_bd_ring[i] + (ug_info->bdRingLenTx[i] - + 1) * UCC_GETH_SIZE_OF_BD; + if (ugeth->ug_info->uf_info.bd_mem_part == MEM_PART_SYSTEM) { + out_be32(&ugeth->p_send_q_mem_reg->sqqd[i].bd_ring_base, + (u32) virt_to_phys(ugeth->p_tx_bd_ring[i])); + out_be32(&ugeth->p_send_q_mem_reg->sqqd[i]. + last_bd_completed_address, + (u32) virt_to_phys(endOfRing)); + } else if (ugeth->ug_info->uf_info.bd_mem_part == + MEM_PART_MURAM) { + out_be32(&ugeth->p_send_q_mem_reg->sqqd[i].bd_ring_base, + (u32) immrbar_virt_to_phys(ugeth-> + p_tx_bd_ring[i])); + out_be32(&ugeth->p_send_q_mem_reg->sqqd[i]. + last_bd_completed_address, + (u32) immrbar_virt_to_phys(endOfRing)); + } + } + + /* schedulerbasepointer */ + + if (ug_info->numQueuesTx > 1) { + /* scheduler exists only if more than 1 tx queue */ + ugeth->scheduler_offset = + qe_muram_alloc(sizeof(ucc_geth_scheduler_t), + UCC_GETH_SCHEDULER_ALIGNMENT); + if (IS_MURAM_ERR(ugeth->scheduler_offset)) { + ugeth_err + ("%s: Can not allocate DPRAM memory for p_scheduler.", + __FUNCTION__); + ucc_geth_memclean(ugeth); + return -ENOMEM; + } + + ugeth->p_scheduler = + (ucc_geth_scheduler_t *) qe_muram_addr(ugeth-> + scheduler_offset); + out_be32(&ugeth->p_tx_glbl_pram->schedulerbasepointer, + ugeth->scheduler_offset); + /* Zero out p_scheduler */ + memset(ugeth->p_scheduler, 0, sizeof(ucc_geth_scheduler_t)); + + /* Set values in scheduler */ + out_be32(&ugeth->p_scheduler->mblinterval, + ug_info->mblinterval); + out_be16(&ugeth->p_scheduler->nortsrbytetime, + ug_info->nortsrbytetime); + ugeth->p_scheduler->fracsiz = ug_info->fracsiz; + ugeth->p_scheduler->strictpriorityq = ug_info->strictpriorityq; + ugeth->p_scheduler->txasap = ug_info->txasap; + ugeth->p_scheduler->extrabw = ug_info->extrabw; + for (i = 0; i < NUM_TX_QUEUES; i++) + ugeth->p_scheduler->weightfactor[i] = + ug_info->weightfactor[i]; + + /* Set pointers to cpucount registers in scheduler */ + ugeth->p_cpucount[0] = &(ugeth->p_scheduler->cpucount0); + ugeth->p_cpucount[1] = &(ugeth->p_scheduler->cpucount1); + ugeth->p_cpucount[2] = &(ugeth->p_scheduler->cpucount2); + ugeth->p_cpucount[3] = &(ugeth->p_scheduler->cpucount3); + ugeth->p_cpucount[4] = &(ugeth->p_scheduler->cpucount4); + ugeth->p_cpucount[5] = &(ugeth->p_scheduler->cpucount5); + ugeth->p_cpucount[6] = &(ugeth->p_scheduler->cpucount6); + ugeth->p_cpucount[7] = &(ugeth->p_scheduler->cpucount7); + } + + /* schedulerbasepointer */ + /* TxRMON_PTR (statistics) */ + if (ug_info-> + statisticsMode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_TX) { + ugeth->tx_fw_statistics_pram_offset = + qe_muram_alloc(sizeof + (ucc_geth_tx_firmware_statistics_pram_t), + UCC_GETH_TX_STATISTICS_ALIGNMENT); + if (IS_MURAM_ERR(ugeth->tx_fw_statistics_pram_offset)) { + ugeth_err + ("%s: Can not allocate DPRAM memory for" + " p_tx_fw_statistics_pram.", __FUNCTION__); + ucc_geth_memclean(ugeth); + return -ENOMEM; + } + ugeth->p_tx_fw_statistics_pram = + (ucc_geth_tx_firmware_statistics_pram_t *) + qe_muram_addr(ugeth->tx_fw_statistics_pram_offset); + /* Zero out p_tx_fw_statistics_pram */ + memset(ugeth->p_tx_fw_statistics_pram, + 0, sizeof(ucc_geth_tx_firmware_statistics_pram_t)); + } + + /* temoder */ + /* Already has speed set */ + + if (ug_info->numQueuesTx > 1) + temoder |= TEMODER_SCHEDULER_ENABLE; + if (ug_info->ipCheckSumGenerate) + temoder |= TEMODER_IP_CHECKSUM_GENERATE; + temoder |= ((ug_info->numQueuesTx - 1) << TEMODER_NUM_OF_QUEUES_SHIFT); + out_be16(&ugeth->p_tx_glbl_pram->temoder, temoder); + + test = in_be16(&ugeth->p_tx_glbl_pram->temoder); + + /* Function code register value to be used later */ + function_code = QE_BMR_BYTE_ORDER_BO_MOT | UCC_FAST_FUNCTION_CODE_GBL; + /* Required for QE */ + + /* function code register */ + out_be32(&ugeth->p_tx_glbl_pram->tstate, ((u32) function_code) << 24); + + /* Rx global PRAM */ + /* Allocate global rx parameter RAM page */ + ugeth->rx_glbl_pram_offset = + qe_muram_alloc(sizeof(ucc_geth_rx_global_pram_t), + UCC_GETH_RX_GLOBAL_PRAM_ALIGNMENT); + if (IS_MURAM_ERR(ugeth->rx_glbl_pram_offset)) { + ugeth_err + ("%s: Can not allocate DPRAM memory for p_rx_glbl_pram.", + __FUNCTION__); + ucc_geth_memclean(ugeth); + return -ENOMEM; + } + ugeth->p_rx_glbl_pram = + (ucc_geth_rx_global_pram_t *) qe_muram_addr(ugeth-> + rx_glbl_pram_offset); + /* Zero out p_rx_glbl_pram */ + memset(ugeth->p_rx_glbl_pram, 0, sizeof(ucc_geth_rx_global_pram_t)); + + /* Fill global PRAM */ + + /* RQPTR */ + /* Size varies with number of Rx threads */ + ugeth->thread_dat_rx_offset = + qe_muram_alloc(numThreadsRxNumerical * + sizeof(ucc_geth_thread_data_rx_t), + UCC_GETH_THREAD_DATA_ALIGNMENT); + if (IS_MURAM_ERR(ugeth->thread_dat_rx_offset)) { + ugeth_err + ("%s: Can not allocate DPRAM memory for p_thread_data_rx.", + __FUNCTION__); + ucc_geth_memclean(ugeth); + return -ENOMEM; + } + + ugeth->p_thread_data_rx = + (ucc_geth_thread_data_rx_t *) qe_muram_addr(ugeth-> + thread_dat_rx_offset); + out_be32(&ugeth->p_rx_glbl_pram->rqptr, ugeth->thread_dat_rx_offset); + + /* typeorlen */ + out_be16(&ugeth->p_rx_glbl_pram->typeorlen, ug_info->typeorlen); + + /* rxrmonbaseptr (statistics) */ + if (ug_info-> + statisticsMode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_RX) { + ugeth->rx_fw_statistics_pram_offset = + qe_muram_alloc(sizeof + (ucc_geth_rx_firmware_statistics_pram_t), + UCC_GETH_RX_STATISTICS_ALIGNMENT); + if (IS_MURAM_ERR(ugeth->rx_fw_statistics_pram_offset)) { + ugeth_err + ("%s: Can not allocate DPRAM memory for" + " p_rx_fw_statistics_pram.", __FUNCTION__); + ucc_geth_memclean(ugeth); + return -ENOMEM; + } + ugeth->p_rx_fw_statistics_pram = + (ucc_geth_rx_firmware_statistics_pram_t *) + qe_muram_addr(ugeth->rx_fw_statistics_pram_offset); + /* Zero out p_rx_fw_statistics_pram */ + memset(ugeth->p_rx_fw_statistics_pram, 0, + sizeof(ucc_geth_rx_firmware_statistics_pram_t)); + } + + /* intCoalescingPtr */ + + /* Size varies with number of Rx queues */ + ugeth->rx_irq_coalescing_tbl_offset = + qe_muram_alloc(ug_info->numQueuesRx * + sizeof(ucc_geth_rx_interrupt_coalescing_entry_t), + UCC_GETH_RX_INTERRUPT_COALESCING_ALIGNMENT); + if (IS_MURAM_ERR(ugeth->rx_irq_coalescing_tbl_offset)) { + ugeth_err + ("%s: Can not allocate DPRAM memory for" + " p_rx_irq_coalescing_tbl.", __FUNCTION__); + ucc_geth_memclean(ugeth); + return -ENOMEM; + } + + ugeth->p_rx_irq_coalescing_tbl = + (ucc_geth_rx_interrupt_coalescing_table_t *) + qe_muram_addr(ugeth->rx_irq_coalescing_tbl_offset); + out_be32(&ugeth->p_rx_glbl_pram->intcoalescingptr, + ugeth->rx_irq_coalescing_tbl_offset); + + /* Fill interrupt coalescing table */ + for (i = 0; i < ug_info->numQueuesRx; i++) { + out_be32(&ugeth->p_rx_irq_coalescing_tbl->coalescingentry[i]. + interruptcoalescingmaxvalue, + ug_info->interruptcoalescingmaxvalue[i]); + out_be32(&ugeth->p_rx_irq_coalescing_tbl->coalescingentry[i]. + interruptcoalescingcounter, + ug_info->interruptcoalescingmaxvalue[i]); + } + + /* MRBLR */ + init_max_rx_buff_len(uf_info->max_rx_buf_length, + &ugeth->p_rx_glbl_pram->mrblr); + /* MFLR */ + out_be16(&ugeth->p_rx_glbl_pram->mflr, ug_info->maxFrameLength); + /* MINFLR */ + init_min_frame_len(ug_info->minFrameLength, + &ugeth->p_rx_glbl_pram->minflr, + &ugeth->p_rx_glbl_pram->mrblr); + /* MAXD1 */ + out_be16(&ugeth->p_rx_glbl_pram->maxd1, ug_info->maxD1Length); + /* MAXD2 */ + out_be16(&ugeth->p_rx_glbl_pram->maxd2, ug_info->maxD2Length); + + /* l2qt */ + l2qt = 0; + for (i = 0; i < UCC_GETH_VLAN_PRIORITY_MAX; i++) + l2qt |= (ug_info->l2qt[i] << (28 - 4 * i)); + out_be32(&ugeth->p_rx_glbl_pram->l2qt, l2qt); + + /* l3qt */ + for (j = 0; j < UCC_GETH_IP_PRIORITY_MAX; j += 8) { + l3qt = 0; + for (i = 0; i < 8; i++) + l3qt |= (ug_info->l3qt[j + i] << (28 - 4 * i)); + out_be32(&ugeth->p_rx_glbl_pram->l3qt[j], l3qt); + } + + /* vlantype */ + out_be16(&ugeth->p_rx_glbl_pram->vlantype, ug_info->vlantype); + + /* vlantci */ + out_be16(&ugeth->p_rx_glbl_pram->vlantci, ug_info->vlantci); + + /* ecamptr */ + out_be32(&ugeth->p_rx_glbl_pram->ecamptr, ug_info->ecamptr); + + /* RBDQPTR */ + /* Size varies with number of Rx queues */ + ugeth->rx_bd_qs_tbl_offset = + qe_muram_alloc(ug_info->numQueuesRx * + (sizeof(ucc_geth_rx_bd_queues_entry_t) + + sizeof(ucc_geth_rx_prefetched_bds_t)), + UCC_GETH_RX_BD_QUEUES_ALIGNMENT); + if (IS_MURAM_ERR(ugeth->rx_bd_qs_tbl_offset)) { + ugeth_err + ("%s: Can not allocate DPRAM memory for p_rx_bd_qs_tbl.", + __FUNCTION__); + ucc_geth_memclean(ugeth); + return -ENOMEM; + } + + ugeth->p_rx_bd_qs_tbl = + (ucc_geth_rx_bd_queues_entry_t *) qe_muram_addr(ugeth-> + rx_bd_qs_tbl_offset); + out_be32(&ugeth->p_rx_glbl_pram->rbdqptr, ugeth->rx_bd_qs_tbl_offset); + /* Zero out p_rx_bd_qs_tbl */ + memset(ugeth->p_rx_bd_qs_tbl, + 0, + ug_info->numQueuesRx * (sizeof(ucc_geth_rx_bd_queues_entry_t) + + sizeof(ucc_geth_rx_prefetched_bds_t))); + + /* Setup the table */ + /* Assume BD rings are already established */ + for (i = 0; i < ug_info->numQueuesRx; i++) { + if (ugeth->ug_info->uf_info.bd_mem_part == MEM_PART_SYSTEM) { + out_be32(&ugeth->p_rx_bd_qs_tbl[i].externalbdbaseptr, + (u32) virt_to_phys(ugeth->p_rx_bd_ring[i])); + } else if (ugeth->ug_info->uf_info.bd_mem_part == + MEM_PART_MURAM) { + out_be32(&ugeth->p_rx_bd_qs_tbl[i].externalbdbaseptr, + (u32) immrbar_virt_to_phys(ugeth-> + p_rx_bd_ring[i])); + } + /* rest of fields handled by QE */ + } + + /* remoder */ + /* Already has speed set */ + + if (ugeth->rx_extended_features) + remoder |= REMODER_RX_EXTENDED_FEATURES; + if (ug_info->rxExtendedFiltering) + remoder |= REMODER_RX_EXTENDED_FILTERING; + if (ug_info->dynamicMaxFrameLength) + remoder |= REMODER_DYNAMIC_MAX_FRAME_LENGTH; + if (ug_info->dynamicMinFrameLength) + remoder |= REMODER_DYNAMIC_MIN_FRAME_LENGTH; + remoder |= + ug_info->vlanOperationTagged << REMODER_VLAN_OPERATION_TAGGED_SHIFT; + remoder |= + ug_info-> + vlanOperationNonTagged << REMODER_VLAN_OPERATION_NON_TAGGED_SHIFT; + remoder |= ug_info->rxQoSMode << REMODER_RX_QOS_MODE_SHIFT; + remoder |= ((ug_info->numQueuesRx - 1) << REMODER_NUM_OF_QUEUES_SHIFT); + if (ug_info->ipCheckSumCheck) + remoder |= REMODER_IP_CHECKSUM_CHECK; + if (ug_info->ipAddressAlignment) + remoder |= REMODER_IP_ADDRESS_ALIGNMENT; + out_be32(&ugeth->p_rx_glbl_pram->remoder, remoder); + + /* Note that this function must be called */ + /* ONLY AFTER p_tx_fw_statistics_pram */ + /* andp_UccGethRxFirmwareStatisticsPram are allocated ! */ + init_firmware_statistics_gathering_mode((ug_info-> + statisticsMode & + UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_TX), + (ug_info->statisticsMode & + UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_RX), + &ugeth->p_tx_glbl_pram->txrmonbaseptr, + ugeth->tx_fw_statistics_pram_offset, + &ugeth->p_rx_glbl_pram->rxrmonbaseptr, + ugeth->rx_fw_statistics_pram_offset, + &ugeth->p_tx_glbl_pram->temoder, + &ugeth->p_rx_glbl_pram->remoder); + + /* function code register */ + ugeth->p_rx_glbl_pram->rstate = function_code; + + /* initialize extended filtering */ + if (ug_info->rxExtendedFiltering) { + if (!ug_info->extendedFilteringChainPointer) { + ugeth_err("%s: Null Extended Filtering Chain Pointer.", + __FUNCTION__); + ucc_geth_memclean(ugeth); + return -EINVAL; + } + + /* Allocate memory for extended filtering Mode Global + Parameters */ + ugeth->exf_glbl_param_offset = + qe_muram_alloc(sizeof(ucc_geth_exf_global_pram_t), + UCC_GETH_RX_EXTENDED_FILTERING_GLOBAL_PARAMETERS_ALIGNMENT); + if (IS_MURAM_ERR(ugeth->exf_glbl_param_offset)) { + ugeth_err + ("%s: Can not allocate DPRAM memory for" + " p_exf_glbl_param.", __FUNCTION__); + ucc_geth_memclean(ugeth); + return -ENOMEM; + } + + ugeth->p_exf_glbl_param = + (ucc_geth_exf_global_pram_t *) qe_muram_addr(ugeth-> + exf_glbl_param_offset); + out_be32(&ugeth->p_rx_glbl_pram->exfGlobalParam, + ugeth->exf_glbl_param_offset); + out_be32(&ugeth->p_exf_glbl_param->l2pcdptr, + (u32) ug_info->extendedFilteringChainPointer); + + } else { /* initialize 82xx style address filtering */ + + /* Init individual address recognition registers to disabled */ + + for (j = 0; j < NUM_OF_PADDRS; j++) + ugeth_82xx_filtering_clear_addr_in_paddr(ugeth, (u8) j); + + /* Create CQs for hash tables */ + if (ug_info->maxGroupAddrInHash > 0) { + INIT_LIST_HEAD(&ugeth->group_hash_q); + } + if (ug_info->maxIndAddrInHash > 0) { + INIT_LIST_HEAD(&ugeth->ind_hash_q); + } + p_82xx_addr_filt = + (ucc_geth_82xx_address_filtering_pram_t *) ugeth-> + p_rx_glbl_pram->addressfiltering; + + ugeth_82xx_filtering_clear_all_addr_in_hash(ugeth, + ENET_ADDR_TYPE_GROUP); + ugeth_82xx_filtering_clear_all_addr_in_hash(ugeth, + ENET_ADDR_TYPE_INDIVIDUAL); + } + + /* + * Initialize UCC at QE level + */ + + command = QE_INIT_TX_RX; + + /* Allocate shadow InitEnet command parameter structure. + * This is needed because after the InitEnet command is executed, + * the structure in DPRAM is released, because DPRAM is a premium + * resource. + * This shadow structure keeps a copy of what was done so that the + * allocated resources can be released when the channel is freed. + */ + if (!(ugeth->p_init_enet_param_shadow = + (ucc_geth_init_pram_t *) kmalloc(sizeof(ucc_geth_init_pram_t), + GFP_KERNEL))) { + ugeth_err + ("%s: Can not allocate memory for" + " p_UccInitEnetParamShadows.", __FUNCTION__); + ucc_geth_memclean(ugeth); + return -ENOMEM; + } + /* Zero out *p_init_enet_param_shadow */ + memset((char *)ugeth->p_init_enet_param_shadow, + 0, sizeof(ucc_geth_init_pram_t)); + + /* Fill shadow InitEnet command parameter structure */ + + ugeth->p_init_enet_param_shadow->resinit1 = + ENET_INIT_PARAM_MAGIC_RES_INIT1; + ugeth->p_init_enet_param_shadow->resinit2 = + ENET_INIT_PARAM_MAGIC_RES_INIT2; + ugeth->p_init_enet_param_shadow->resinit3 = + ENET_INIT_PARAM_MAGIC_RES_INIT3; + ugeth->p_init_enet_param_shadow->resinit4 = + ENET_INIT_PARAM_MAGIC_RES_INIT4; + ugeth->p_init_enet_param_shadow->resinit5 = + ENET_INIT_PARAM_MAGIC_RES_INIT5; + ugeth->p_init_enet_param_shadow->rgftgfrxglobal |= + ((u32) ug_info->numThreadsRx) << ENET_INIT_PARAM_RGF_SHIFT; + ugeth->p_init_enet_param_shadow->rgftgfrxglobal |= + ((u32) ug_info->numThreadsTx) << ENET_INIT_PARAM_TGF_SHIFT; + + ugeth->p_init_enet_param_shadow->rgftgfrxglobal |= + ugeth->rx_glbl_pram_offset | ug_info->riscRx; + if ((ug_info->largestexternallookupkeysize != + QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_NONE) + && (ug_info->largestexternallookupkeysize != + QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_8_BYTES) + && (ug_info->largestexternallookupkeysize != + QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_16_BYTES)) { + ugeth_err("%s: Invalid largest External Lookup Key Size.", + __FUNCTION__); + ucc_geth_memclean(ugeth); + return -EINVAL; + } + ugeth->p_init_enet_param_shadow->largestexternallookupkeysize = + ug_info->largestexternallookupkeysize; + size = sizeof(ucc_geth_thread_rx_pram_t); + if (ug_info->rxExtendedFiltering) { + size += THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING; + if (ug_info->largestexternallookupkeysize == + QE_FLTR_TABLE_LOOKUP_KEY_SIZE_8_BYTES) + size += + THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING_8; + if (ug_info->largestexternallookupkeysize == + QE_FLTR_TABLE_LOOKUP_KEY_SIZE_16_BYTES) + size += + THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING_16; + } + + if ((ret_val = fill_init_enet_entries(ugeth, &(ugeth-> + p_init_enet_param_shadow->rxthread[0]), + (u8) (numThreadsRxNumerical + 1) + /* Rx needs one extra for terminator */ + , size, UCC_GETH_THREAD_RX_PRAM_ALIGNMENT, + ug_info->riscRx, 1)) != 0) { + ugeth_err("%s: Can not fill p_init_enet_param_shadow.", + __FUNCTION__); + ucc_geth_memclean(ugeth); + return ret_val; + } + + ugeth->p_init_enet_param_shadow->txglobal = + ugeth->tx_glbl_pram_offset | ug_info->riscTx; + if ((ret_val = + fill_init_enet_entries(ugeth, + &(ugeth->p_init_enet_param_shadow-> + txthread[0]), numThreadsTxNumerical, + sizeof(ucc_geth_thread_tx_pram_t), + UCC_GETH_THREAD_TX_PRAM_ALIGNMENT, + ug_info->riscTx, 0)) != 0) { + ugeth_err("%s: Can not fill p_init_enet_param_shadow.", + __FUNCTION__); + ucc_geth_memclean(ugeth); + return ret_val; + } + + /* Load Rx bds with buffers */ + for (i = 0; i < ug_info->numQueuesRx; i++) { + if ((ret_val = rx_bd_buffer_set(ugeth, (u8) i)) != 0) { + ugeth_err("%s: Can not fill Rx bds with buffers.", + __FUNCTION__); + ucc_geth_memclean(ugeth); + return ret_val; + } + } + + /* Allocate InitEnet command parameter structure */ + init_enet_pram_offset = qe_muram_alloc(sizeof(ucc_geth_init_pram_t), 4); + if (IS_MURAM_ERR(init_enet_pram_offset)) { + ugeth_err + ("%s: Can not allocate DPRAM memory for p_init_enet_pram.", + __FUNCTION__); + ucc_geth_memclean(ugeth); + return -ENOMEM; + } + p_init_enet_pram = + (ucc_geth_init_pram_t *) qe_muram_addr(init_enet_pram_offset); + + /* Copy shadow InitEnet command parameter structure into PRAM */ + p_init_enet_pram->resinit1 = ugeth->p_init_enet_param_shadow->resinit1; + p_init_enet_pram->resinit2 = ugeth->p_init_enet_param_shadow->resinit2; + p_init_enet_pram->resinit3 = ugeth->p_init_enet_param_shadow->resinit3; + p_init_enet_pram->resinit4 = ugeth->p_init_enet_param_shadow->resinit4; + out_be16(&p_init_enet_pram->resinit5, + ugeth->p_init_enet_param_shadow->resinit5); + p_init_enet_pram->largestexternallookupkeysize = + ugeth->p_init_enet_param_shadow->largestexternallookupkeysize; + out_be32(&p_init_enet_pram->rgftgfrxglobal, + ugeth->p_init_enet_param_shadow->rgftgfrxglobal); + for (i = 0; i < ENET_INIT_PARAM_MAX_ENTRIES_RX; i++) + out_be32(&p_init_enet_pram->rxthread[i], + ugeth->p_init_enet_param_shadow->rxthread[i]); + out_be32(&p_init_enet_pram->txglobal, + ugeth->p_init_enet_param_shadow->txglobal); + for (i = 0; i < ENET_INIT_PARAM_MAX_ENTRIES_TX; i++) + out_be32(&p_init_enet_pram->txthread[i], + ugeth->p_init_enet_param_shadow->txthread[i]); + + /* Issue QE command */ + cecr_subblock = + ucc_fast_get_qe_cr_subblock(ugeth->ug_info->uf_info.ucc_num); + qe_issue_cmd(command, cecr_subblock, (u8) QE_CR_PROTOCOL_ETHERNET, + init_enet_pram_offset); + + /* Free InitEnet command parameter */ + qe_muram_free(init_enet_pram_offset); + + return 0; +} + +/* returns a net_device_stats structure pointer */ +static struct net_device_stats *ucc_geth_get_stats(struct net_device *dev) +{ + ucc_geth_private_t *ugeth = netdev_priv(dev); + + return &(ugeth->stats); +} + +/* ucc_geth_timeout gets called when a packet has not been + * transmitted after a set amount of time. + * For now, assume that clearing out all the structures, and + * starting over will fix the problem. */ +static void ucc_geth_timeout(struct net_device *dev) +{ + ucc_geth_private_t *ugeth = netdev_priv(dev); + + ugeth_vdbg("%s: IN", __FUNCTION__); + + ugeth->stats.tx_errors++; + + ugeth_dump_regs(ugeth); + + if (dev->flags & IFF_UP) { + ucc_geth_stop(ugeth); + ucc_geth_startup(ugeth); + } + + netif_schedule(dev); +} + +/* This is called by the kernel when a frame is ready for transmission. */ +/* It is pointed to by the dev->hard_start_xmit function pointer */ +static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + ucc_geth_private_t *ugeth = netdev_priv(dev); + u8 *bd; /* BD pointer */ + u32 bd_status; + u8 txQ = 0; + + ugeth_vdbg("%s: IN", __FUNCTION__); + + spin_lock_irq(&ugeth->lock); + + ugeth->stats.tx_bytes += skb->len; + + /* Start from the next BD that should be filled */ + bd = ugeth->txBd[txQ]; + bd_status = BD_STATUS_AND_LENGTH(bd); + /* Save the skb pointer so we can free it later */ + ugeth->tx_skbuff[txQ][ugeth->skb_curtx[txQ]] = skb; + + /* Update the current skb pointer (wrapping if this was the last) */ + ugeth->skb_curtx[txQ] = + (ugeth->skb_curtx[txQ] + + 1) & TX_RING_MOD_MASK(ugeth->ug_info->bdRingLenTx[txQ]); + + /* set up the buffer descriptor */ + BD_BUFFER_SET(bd, + dma_map_single(NULL, skb->data, skb->len, DMA_TO_DEVICE)); + + //printk(KERN_DEBUG"skb->data is 0x%x\n",skb->data); + + bd_status = (bd_status & T_W) | T_R | T_I | T_L | skb->len; + + BD_STATUS_AND_LENGTH_SET(bd, bd_status); + + dev->trans_start = jiffies; + + /* Move to next BD in the ring */ + if (!(bd_status & T_W)) + ugeth->txBd[txQ] = bd + UCC_GETH_SIZE_OF_BD; + else + ugeth->txBd[txQ] = ugeth->p_tx_bd_ring[txQ]; + + /* If the next BD still needs to be cleaned up, then the bds + are full. We need to tell the kernel to stop sending us stuff. */ + if (bd == ugeth->confBd[txQ]) { + if (!netif_queue_stopped(dev)) + netif_stop_queue(dev); + } + + if (ugeth->p_scheduler) { + ugeth->cpucount[txQ]++; + /* Indicate to QE that there are more Tx bds ready for + transmission */ + /* This is done by writing a running counter of the bd + count to the scheduler PRAM. */ + out_be16(ugeth->p_cpucount[txQ], ugeth->cpucount[txQ]); + } + + spin_unlock_irq(&ugeth->lock); + + return 0; +} + +static int ucc_geth_rx(ucc_geth_private_t *ugeth, u8 rxQ, int rx_work_limit) +{ + struct sk_buff *skb; + u8 *bd; + u16 length, howmany = 0; + u32 bd_status; + u8 *bdBuffer; + + ugeth_vdbg("%s: IN", __FUNCTION__); + + spin_lock(&ugeth->lock); + /* collect received buffers */ + bd = ugeth->rxBd[rxQ]; + + bd_status = BD_STATUS_AND_LENGTH(bd); + + /* while there are received buffers and BD is full (~R_E) */ + while (!((bd_status & (R_E)) || (--rx_work_limit < 0))) { + bdBuffer = (u8 *) BD_BUFFER(bd); + length = (u16) ((bd_status & BD_LENGTH_MASK) - 4); + skb = ugeth->rx_skbuff[rxQ][ugeth->skb_currx[rxQ]]; + + /* determine whether buffer is first, last, first and last + (single buffer frame) or middle (not first and not last) */ + if (!skb || + (!(bd_status & (R_F | R_L))) || + (bd_status & R_ERRORS_FATAL)) { + ugeth_vdbg("%s, %d: ERROR!!! skb - 0x%08x", + __FUNCTION__, __LINE__, (u32) skb); + if (skb) + dev_kfree_skb_any(skb); + + ugeth->rx_skbuff[rxQ][ugeth->skb_currx[rxQ]] = NULL; + ugeth->stats.rx_dropped++; + } else { + ugeth->stats.rx_packets++; + howmany++; + + /* Prep the skb for the packet */ + skb_put(skb, length); + + /* Tell the skb what kind of packet this is */ + skb->protocol = eth_type_trans(skb, ugeth->dev); + + ugeth->stats.rx_bytes += length; + /* Send the packet up the stack */ +#ifdef CONFIG_UGETH_NAPI + netif_receive_skb(skb); +#else + netif_rx(skb); +#endif /* CONFIG_UGETH_NAPI */ + } + + ugeth->dev->last_rx = jiffies; + + skb = get_new_skb(ugeth, bd); + if (!skb) { + ugeth_warn("%s: No Rx Data Buffer", __FUNCTION__); + spin_unlock(&ugeth->lock); + ugeth->stats.rx_dropped++; + break; + } + + ugeth->rx_skbuff[rxQ][ugeth->skb_currx[rxQ]] = skb; + + /* update to point at the next skb */ + ugeth->skb_currx[rxQ] = + (ugeth->skb_currx[rxQ] + + 1) & RX_RING_MOD_MASK(ugeth->ug_info->bdRingLenRx[rxQ]); + + if (bd_status & R_W) + bd = ugeth->p_rx_bd_ring[rxQ]; + else + bd += UCC_GETH_SIZE_OF_BD; + + bd_status = BD_STATUS_AND_LENGTH(bd); + } + + ugeth->rxBd[rxQ] = bd; + spin_unlock(&ugeth->lock); + return howmany; +} + +static int ucc_geth_tx(struct net_device *dev, u8 txQ) +{ + /* Start from the next BD that should be filled */ + ucc_geth_private_t *ugeth = netdev_priv(dev); + u8 *bd; /* BD pointer */ + u32 bd_status; + + bd = ugeth->confBd[txQ]; + bd_status = BD_STATUS_AND_LENGTH(bd); + + /* Normal processing. */ + while ((bd_status & T_R) == 0) { + /* BD contains already transmitted buffer. */ + /* Handle the transmitted buffer and release */ + /* the BD to be used with the current frame */ + + if ((bd = ugeth->txBd[txQ]) && (netif_queue_stopped(dev) == 0)) + break; + + ugeth->stats.tx_packets++; + + /* Free the sk buffer associated with this TxBD */ + dev_kfree_skb_irq(ugeth-> + tx_skbuff[txQ][ugeth->skb_dirtytx[txQ]]); + ugeth->tx_skbuff[txQ][ugeth->skb_dirtytx[txQ]] = NULL; + ugeth->skb_dirtytx[txQ] = + (ugeth->skb_dirtytx[txQ] + + 1) & TX_RING_MOD_MASK(ugeth->ug_info->bdRingLenTx[txQ]); + + /* We freed a buffer, so now we can restart transmission */ + if (netif_queue_stopped(dev)) + netif_wake_queue(dev); + + /* Advance the confirmation BD pointer */ + if (!(bd_status & T_W)) + ugeth->confBd[txQ] += UCC_GETH_SIZE_OF_BD; + else + ugeth->confBd[txQ] = ugeth->p_tx_bd_ring[txQ]; + } + return 0; +} + +#ifdef CONFIG_UGETH_NAPI +static int ucc_geth_poll(struct net_device *dev, int *budget) +{ + ucc_geth_private_t *ugeth = netdev_priv(dev); + int howmany; + int rx_work_limit = *budget; + u8 rxQ = 0; + + if (rx_work_limit > dev->quota) + rx_work_limit = dev->quota; + + howmany = ucc_geth_rx(ugeth, rxQ, rx_work_limit); + + dev->quota -= howmany; + rx_work_limit -= howmany; + *budget -= howmany; + + if (rx_work_limit >= 0) + netif_rx_complete(dev); + + return (rx_work_limit < 0) ? 1 : 0; +} +#endif /* CONFIG_UGETH_NAPI */ + +static irqreturn_t ucc_geth_irq_handler(int irq, void *info, + struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *)info; + ucc_geth_private_t *ugeth = netdev_priv(dev); + ucc_fast_private_t *uccf; + ucc_geth_info_t *ug_info; + register u32 ucce = 0; + register u32 bit_mask = UCCE_RXBF_SINGLE_MASK; + register u32 tx_mask = UCCE_TXBF_SINGLE_MASK; + register u8 i; + + ugeth_vdbg("%s: IN", __FUNCTION__); + + if (!ugeth) + return IRQ_NONE; + + uccf = ugeth->uccf; + ug_info = ugeth->ug_info; + + do { + ucce |= (u32) (in_be32(uccf->p_ucce) & in_be32(uccf->p_uccm)); + + /* clear event bits for next time */ + /* Side effect here is to mask ucce variable + for future processing below. */ + out_be32(uccf->p_ucce, ucce); /* Clear with ones, + but only bits in UCCM */ + + /* We ignore Tx interrupts because Tx confirmation is + done inside Tx routine */ + + for (i = 0; i < ug_info->numQueuesRx; i++) { + if (ucce & bit_mask) + ucc_geth_rx(ugeth, i, + (int)ugeth->ug_info-> + bdRingLenRx[i]); + ucce &= ~bit_mask; + bit_mask <<= 1; + } + + for (i = 0; i < ug_info->numQueuesTx; i++) { + if (ucce & tx_mask) + ucc_geth_tx(dev, i); + ucce &= ~tx_mask; + tx_mask <<= 1; + } + + /* Exceptions */ + if (ucce & UCCE_BSY) { + ugeth_vdbg("Got BUSY irq!!!!"); + ugeth->stats.rx_errors++; + ucce &= ~UCCE_BSY; + } + if (ucce & UCCE_OTHER) { + ugeth_vdbg("Got frame with error (ucce - 0x%08x)!!!!", + ucce); + ugeth->stats.rx_errors++; + ucce &= ~ucce; + } + } + while (ucce); + + 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; + ucc_geth_private_t *ugeth = netdev_priv(dev); + + ugeth_vdbg("%s: IN", __FUNCTION__); + + /* Clear the interrupt */ + mii_clear_phy_interrupt(ugeth->mii_info); + + /* Disable PHY interrupts */ + mii_configure_phy_interrupt(ugeth->mii_info, MII_INTERRUPT_DISABLED); + + /* Schedule the phy change */ + schedule_work(&ugeth->tq); + + return IRQ_HANDLED; +} + +/* Scheduled by the phy_interrupt/timer to handle PHY changes */ +static void ugeth_phy_change(void *data) +{ + struct net_device *dev = (struct net_device *)data; + ucc_geth_private_t *ugeth = netdev_priv(dev); + ucc_geth_t *ug_regs; + int result = 0; + + ugeth_vdbg("%s: IN", __FUNCTION__); + + ug_regs = ugeth->ug_regs; + + /* Delay to give the PHY a chance to change the + * register state */ + msleep(1); + + /* Update the link, speed, duplex */ + result = ugeth->mii_info->phyinfo->read_status(ugeth->mii_info); + + /* Adjust the known status as long as the link + * isn't still coming up */ + if ((0 == result) || (ugeth->mii_info->link == 0)) + adjust_link(dev); + + /* Reenable interrupts, if needed */ + if (ugeth->ug_info->board_flags & FSL_UGETH_BRD_HAS_PHY_INTR) + mii_configure_phy_interrupt(ugeth->mii_info, + MII_INTERRUPT_ENABLED); +} + +/* Called every so often on systems that don't interrupt + * the core for PHY changes */ +static void ugeth_phy_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + ucc_geth_private_t *ugeth = netdev_priv(dev); + + schedule_work(&ugeth->tq); + + mod_timer(&ugeth->phy_info_timer, jiffies + 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 ugeth_phy_timer to check status */ +static void ugeth_phy_startup_timer(unsigned long data) +{ + struct ugeth_mii_info *mii_info = (struct ugeth_mii_info *)data; + ucc_geth_private_t *ugeth = netdev_priv(mii_info->dev); + static int secondary = UGETH_AN_TIMEOUT; + int result; + + /* 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(&ugeth->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) { + ugeth_err("%s: Forcing failed!", mii_info->dev->name); + return; + } + } + + /* Kill the timer so it can be restarted */ + del_timer_sync(&ugeth->phy_info_timer); + + /* Grab the PHY interrupt, if necessary/possible */ + if (ugeth->ug_info->board_flags & FSL_UGETH_BRD_HAS_PHY_INTR) { + if (request_irq(ugeth->ug_info->phy_interrupt, + phy_interrupt, + SA_SHIRQ, "phy_interrupt", mii_info->dev) < 0) { + ugeth_err("%s: Can't get IRQ %d (PHY)", + mii_info->dev->name, + ugeth->ug_info->phy_interrupt); + } else { + mii_configure_phy_interrupt(ugeth->mii_info, + MII_INTERRUPT_ENABLED); + return; + } + } + + /* Start the timer again, this time in order to + * handle a change in status */ + init_timer(&ugeth->phy_info_timer); + ugeth->phy_info_timer.function = &ugeth_phy_timer; + ugeth->phy_info_timer.data = (unsigned long)mii_info->dev; + mod_timer(&ugeth->phy_info_timer, jiffies + PHY_CHANGE_TIME * HZ); +} + +/* Called when something needs to use the ethernet device */ +/* Returns 0 for success. */ +static int ucc_geth_open(struct net_device *dev) +{ + ucc_geth_private_t *ugeth = netdev_priv(dev); + int err; + + ugeth_vdbg("%s: IN", __FUNCTION__); + + /* Test station address */ + if (dev->dev_addr[0] & ENET_GROUP_ADDR) { + ugeth_err("%s: Multicast address used for station address" + " - is this what you wanted?", __FUNCTION__); + return -EINVAL; + } + + err = ucc_geth_startup(ugeth); + if (err) { + ugeth_err("%s: Cannot configure net device, aborting.", + dev->name); + return err; + } + + err = adjust_enet_interface(ugeth); + if (err) { + ugeth_err("%s: Cannot configure net device, aborting.", + dev->name); + return err; + } + + /* Set MACSTNADDR1, MACSTNADDR2 */ + /* For more details see the hardware spec. */ + init_mac_station_addr_regs(dev->dev_addr[0], + dev->dev_addr[1], + dev->dev_addr[2], + dev->dev_addr[3], + dev->dev_addr[4], + dev->dev_addr[5], + &ugeth->ug_regs->macstnaddr1, + &ugeth->ug_regs->macstnaddr2); + + err = init_phy(dev); + if (err) { + ugeth_err("%s: Cannot initialzie PHY, aborting.", dev->name); + return err; + } +#ifndef CONFIG_UGETH_NAPI + err = + request_irq(ugeth->ug_info->uf_info.irq, ucc_geth_irq_handler, 0, + "UCC Geth", dev); + if (err) { + ugeth_err("%s: Cannot get IRQ for net device, aborting.", + dev->name); + ucc_geth_stop(ugeth); + return err; + } +#endif /* CONFIG_UGETH_NAPI */ + + /* Set up the PHY change work queue */ + INIT_WORK(&ugeth->tq, ugeth_phy_change, dev); + + init_timer(&ugeth->phy_info_timer); + ugeth->phy_info_timer.function = &ugeth_phy_startup_timer; + ugeth->phy_info_timer.data = (unsigned long)ugeth->mii_info; + mod_timer(&ugeth->phy_info_timer, jiffies + HZ); + + err = ugeth_enable(ugeth, COMM_DIR_RX_AND_TX); + if (err) { + ugeth_err("%s: Cannot enable net device, aborting.", dev->name); + ucc_geth_stop(ugeth); + return err; + } + + netif_start_queue(dev); + + return err; +} + +/* Stops the kernel queue, and halts the controller */ +static int ucc_geth_close(struct net_device *dev) +{ + ucc_geth_private_t *ugeth = netdev_priv(dev); + + ugeth_vdbg("%s: IN", __FUNCTION__); + + ucc_geth_stop(ugeth); + + /* Shutdown the PHY */ + if (ugeth->mii_info->phyinfo->close) + ugeth->mii_info->phyinfo->close(ugeth->mii_info); + + kfree(ugeth->mii_info); + + netif_stop_queue(dev); + + return 0; +} + +struct ethtool_ops ucc_geth_ethtool_ops = { + .get_settings = NULL, + .get_drvinfo = NULL, + .get_regs_len = NULL, + .get_regs = NULL, + .get_link = NULL, + .get_coalesce = NULL, + .set_coalesce = NULL, + .get_ringparam = NULL, + .set_ringparam = NULL, + .get_strings = NULL, + .get_stats_count = NULL, + .get_ethtool_stats = NULL, +}; + +static int ucc_geth_probe(struct device *device) +{ + struct platform_device *pdev = to_platform_device(device); + struct ucc_geth_platform_data *ugeth_pdata; + struct net_device *dev = NULL; + struct ucc_geth_private *ugeth = NULL; + struct ucc_geth_info *ug_info; + int err; + static int mii_mng_configured = 0; + + ugeth_vdbg("%s: IN", __FUNCTION__); + + ugeth_pdata = (struct ucc_geth_platform_data *)pdev->dev.platform_data; + + ug_info = &ugeth_info[pdev->id]; + ug_info->uf_info.ucc_num = pdev->id; + ug_info->uf_info.rx_clock = ugeth_pdata->rx_clock; + ug_info->uf_info.tx_clock = ugeth_pdata->tx_clock; + ug_info->uf_info.regs = ugeth_pdata->phy_reg_addr; + ug_info->uf_info.irq = platform_get_irq(pdev, 0); + ug_info->phy_address = ugeth_pdata->phy_id; + ug_info->enet_interface = ugeth_pdata->phy_interface; + ug_info->board_flags = ugeth_pdata->board_flags; + ug_info->phy_interrupt = ugeth_pdata->phy_interrupt; + + printk(KERN_INFO "ucc_geth: UCC%1d at 0x%8x (irq = %d) \n", + ug_info->uf_info.ucc_num + 1, ug_info->uf_info.regs, + ug_info->uf_info.irq); + + if (ug_info == NULL) { + ugeth_err("%s: [%d] Missing additional data!", __FUNCTION__, + pdev->id); + return -ENODEV; + } + + if (!mii_mng_configured) { + ucc_set_qe_mux_mii_mng(ug_info->uf_info.ucc_num); + mii_mng_configured = 1; + } + + /* Create an ethernet device instance */ + dev = alloc_etherdev(sizeof(*ugeth)); + + if (dev == NULL) + return -ENOMEM; + + ugeth = netdev_priv(dev); + spin_lock_init(&ugeth->lock); + + dev_set_drvdata(device, dev); + + /* Set the dev->base_addr to the gfar reg region */ + dev->base_addr = (unsigned long)(ug_info->uf_info.regs); + + SET_MODULE_OWNER(dev); + SET_NETDEV_DEV(dev, device); + + /* Fill in the dev structure */ + dev->open = ucc_geth_open; + dev->hard_start_xmit = ucc_geth_start_xmit; + dev->tx_timeout = ucc_geth_timeout; + dev->watchdog_timeo = TX_TIMEOUT; +#ifdef CONFIG_UGETH_NAPI + dev->poll = ucc_geth_poll; + dev->weight = UCC_GETH_DEV_WEIGHT; +#endif /* CONFIG_UGETH_NAPI */ + dev->stop = ucc_geth_close; + dev->get_stats = ucc_geth_get_stats; +// dev->change_mtu = ucc_geth_change_mtu; + dev->mtu = 1500; + dev->set_multicast_list = ucc_geth_set_multi; + dev->ethtool_ops = &ucc_geth_ethtool_ops; + + err = register_netdev(dev); + if (err) { + ugeth_err("%s: Cannot register net device, aborting.", + dev->name); + free_netdev(dev); + return err; + } + + ugeth->ug_info = ug_info; + ugeth->dev = dev; + memcpy(dev->dev_addr, ugeth_pdata->mac_addr, 6); + + return 0; +} + +static int ucc_geth_remove(struct device *device) +{ + struct net_device *dev = dev_get_drvdata(device); + struct ucc_geth_private *ugeth = netdev_priv(dev); + + dev_set_drvdata(device, NULL); + ucc_geth_memclean(ugeth); + free_netdev(dev); + + return 0; +} + +/* Structure for a device driver */ +static struct device_driver ucc_geth_driver = { + .name = DRV_NAME, + .bus = &platform_bus_type, + .probe = ucc_geth_probe, + .remove = ucc_geth_remove, +}; + +static int __init ucc_geth_init(void) +{ + int i; + printk(KERN_INFO "ucc_geth: " DRV_DESC "\n"); + for (i = 0; i < 8; i++) + memcpy(&(ugeth_info[i]), &ugeth_primary_info, + sizeof(ugeth_primary_info)); + + return driver_register(&ucc_geth_driver); +} + +static void __exit ucc_geth_exit(void) +{ + driver_unregister(&ucc_geth_driver); +} + +module_init(ucc_geth_init); +module_exit(ucc_geth_exit); + +MODULE_AUTHOR("Freescale Semiconductor, Inc"); +MODULE_DESCRIPTION(DRV_DESC); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/ucc_geth.h b/drivers/net/ucc_geth.h new file mode 100644 index 0000000..005965f --- /dev/null +++ b/drivers/net/ucc_geth.h @@ -0,0 +1,1339 @@ +/* + * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved. + * + * Author: Shlomi Gridish + * + * Description: + * Internal header file for UCC Gigabit Ethernet unit routines. + * + * Changelog: + * Jun 28, 2006 Li Yang + * - Rearrange code and style fixes + * + * 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 __UCC_GETH_H__ +#define __UCC_GETH_H__ + +#include +#include +#include + +#include +#include + +#include +#include + +#define NUM_TX_QUEUES 8 +#define NUM_RX_QUEUES 8 +#define NUM_BDS_IN_PREFETCHED_BDS 4 +#define TX_IP_OFFSET_ENTRY_MAX 8 +#define NUM_OF_PADDRS 4 +#define ENET_INIT_PARAM_MAX_ENTRIES_RX 9 +#define ENET_INIT_PARAM_MAX_ENTRIES_TX 8 + +typedef struct ucc_mii_mng { + u32 miimcfg; /* MII management configuration reg */ + u32 miimcom; /* MII management command reg */ + u32 miimadd; /* MII management address reg */ + u32 miimcon; /* MII management control reg */ + u32 miimstat; /* MII management status reg */ + u32 miimind; /* MII management indication reg */ +} __attribute__ ((packed)) ucc_mii_mng_t; + +typedef struct ucc_geth { + ucc_fast_t uccf; + + u32 maccfg1; /* mac configuration reg. 1 */ + u32 maccfg2; /* mac configuration reg. 2 */ + u32 ipgifg; /* interframe gap reg. */ + u32 hafdup; /* half-duplex reg. */ + u8 res1[0x10]; + ucc_mii_mng_t miimng; /* MII management structure */ + u32 ifctl; /* interface control reg */ + u32 ifstat; /* interface statux reg */ + u32 macstnaddr1; /* mac station address part 1 reg */ + u32 macstnaddr2; /* mac station address part 2 reg */ + u8 res2[0x8]; + u32 uempr; /* UCC Ethernet Mac parameter reg */ + u32 utbipar; /* UCC tbi address reg */ + u16 uescr; /* UCC Ethernet statistics control reg */ + u8 res3[0x180 - 0x15A]; + u32 tx64; /* Total number of frames (including bad + frames) transmitted that were exactly of the + minimal length (64 for un tagged, 68 for + tagged, or with length exactly equal to the + parameter MINLength */ + u32 tx127; /* Total number of frames (including bad + frames) transmitted that were between + MINLength (Including FCS length==4) and 127 + octets */ + u32 tx255; /* Total number of frames (including bad + frames) transmitted that were between 128 + (Including FCS length==4) and 255 octets */ + u32 rx64; /* Total number of frames received including + bad frames that were exactly of the mninimal + length (64 bytes) */ + u32 rx127; /* Total number of frames (including bad + frames) received that were between MINLength + (Including FCS length==4) and 127 octets */ + u32 rx255; /* Total number of frames (including bad + frames) received that were between 128 + (Including FCS length==4) and 255 octets */ + u32 txok; /* Total number of octets residing in frames + that where involved in succesfull + transmission */ + u16 txcf; /* Total number of PAUSE control frames + transmitted by this MAC */ + u8 res4[0x2]; + u32 tmca; /* Total number of frames that were transmitted + succesfully with the group address bit set + that are not broadcast frames */ + u32 tbca; /* Total number of frames transmitted + succesfully that had destination address + field equal to the broadcast address */ + u32 rxfok; /* Total number of frames received OK */ + u32 rxbok; /* Total number of octets received OK */ + u32 rbyt; /* Total number of octets received including + octets in bad frames. Must be implemented in + HW because it includes octets in frames that + never even reach the UCC */ + u32 rmca; /* Total number of frames that were received + succesfully with the group address bit set + that are not broadcast frames */ + u32 rbca; /* Total number of frames received succesfully + that had destination address equal to the + broadcast address */ + u32 scar; /* Statistics carry register */ + u32 scam; /* Statistics caryy mask register */ + u8 res5[0x200 - 0x1c4]; +} __attribute__ ((packed)) ucc_geth_t; + +/* UCC GETH TEMODR Register */ +#define TEMODER_TX_RMON_STATISTICS_ENABLE 0x0100 /* enable Tx statistics + */ +#define TEMODER_SCHEDULER_ENABLE 0x2000 /* enable scheduler */ +#define TEMODER_IP_CHECKSUM_GENERATE 0x0400 /* generate IPv4 + checksums */ +#define TEMODER_PERFORMANCE_OPTIMIZATION_MODE1 0x0200 /* enable performance + optimization + enhancement (mode1) */ +#define TEMODER_RMON_STATISTICS 0x0100 /* enable tx statistics + */ +#define TEMODER_NUM_OF_QUEUES_SHIFT (15-15) /* Number of queues << + shift */ + +/* UCC GETH TEMODR Register */ +#define REMODER_RX_RMON_STATISTICS_ENABLE 0x00001000 /* enable Rx + statistics */ +#define REMODER_RX_EXTENDED_FEATURES 0x80000000 /* enable + extended + features */ +#define REMODER_VLAN_OPERATION_TAGGED_SHIFT (31-9 ) /* vlan operation + tagged << shift */ +#define REMODER_VLAN_OPERATION_NON_TAGGED_SHIFT (31-10) /* vlan operation non + tagged << shift */ +#define REMODER_RX_QOS_MODE_SHIFT (31-15) /* rx QoS mode << shift + */ +#define REMODER_RMON_STATISTICS 0x00001000 /* enable rx + statistics */ +#define REMODER_RX_EXTENDED_FILTERING 0x00000800 /* extended + filtering + vs. + mpc82xx-like + filtering */ +#define REMODER_NUM_OF_QUEUES_SHIFT (31-23) /* Number of queues << + shift */ +#define REMODER_DYNAMIC_MAX_FRAME_LENGTH 0x00000008 /* enable + dynamic max + frame length + */ +#define REMODER_DYNAMIC_MIN_FRAME_LENGTH 0x00000004 /* enable + dynamic min + frame length + */ +#define REMODER_IP_CHECKSUM_CHECK 0x00000002 /* check IPv4 + checksums */ +#define REMODER_IP_ADDRESS_ALIGNMENT 0x00000001 /* align ip + address to + 4-byte + boundary */ + +/* UCC GETH Event Register */ +#define UCCE_MPD 0x80000000 /* Magic packet + detection */ +#define UCCE_SCAR 0x40000000 +#define UCCE_GRA 0x20000000 /* Tx graceful + stop + complete */ +#define UCCE_CBPR 0x10000000 +#define UCCE_BSY 0x08000000 +#define UCCE_RXC 0x04000000 +#define UCCE_TXC 0x02000000 +#define UCCE_TXE 0x01000000 +#define UCCE_TXB7 0x00800000 +#define UCCE_TXB6 0x00400000 +#define UCCE_TXB5 0x00200000 +#define UCCE_TXB4 0x00100000 +#define UCCE_TXB3 0x00080000 +#define UCCE_TXB2 0x00040000 +#define UCCE_TXB1 0x00020000 +#define UCCE_TXB0 0x00010000 +#define UCCE_RXB7 0x00008000 +#define UCCE_RXB6 0x00004000 +#define UCCE_RXB5 0x00002000 +#define UCCE_RXB4 0x00001000 +#define UCCE_RXB3 0x00000800 +#define UCCE_RXB2 0x00000400 +#define UCCE_RXB1 0x00000200 +#define UCCE_RXB0 0x00000100 +#define UCCE_RXF7 0x00000080 +#define UCCE_RXF6 0x00000040 +#define UCCE_RXF5 0x00000020 +#define UCCE_RXF4 0x00000010 +#define UCCE_RXF3 0x00000008 +#define UCCE_RXF2 0x00000004 +#define UCCE_RXF1 0x00000002 +#define UCCE_RXF0 0x00000001 + +#define UCCE_RXBF_SINGLE_MASK (UCCE_RXF0) +#define UCCE_TXBF_SINGLE_MASK (UCCE_TXB0) + +#define UCCE_TXB (UCCE_TXB7 | UCCE_TXB6 | UCCE_TXB5 | UCCE_TXB4 |\ + UCCE_TXB3 | UCCE_TXB2 | UCCE_TXB1 | UCCE_TXB0) +#define UCCE_RXB (UCCE_RXB7 | UCCE_RXB6 | UCCE_RXB5 | UCCE_RXB4 |\ + UCCE_RXB3 | UCCE_RXB2 | UCCE_RXB1 | UCCE_RXB0) +#define UCCE_RXF (UCCE_RXF7 | UCCE_RXF6 | UCCE_RXF5 | UCCE_RXF4 |\ + UCCE_RXF3 | UCCE_RXF2 | UCCE_RXF1 | UCCE_RXF0) +#define UCCE_OTHER (UCCE_SCAR | UCCE_GRA | UCCE_CBPR | UCCE_BSY |\ + UCCE_RXC | UCCE_TXC | UCCE_TXE) + +/* UCC GETH UPSMR (Protocol Specific Mode Register) */ +#define UPSMR_ECM 0x04000000 /* Enable CAM + Miss or + Enable + Filtering + Miss */ +#define UPSMR_HSE 0x02000000 /* Hardware + Statistics + Enable */ +#define UPSMR_PRO 0x00400000 /* Promiscuous*/ +#define UPSMR_CAP 0x00200000 /* CAM polarity + */ +#define UPSMR_RSH 0x00100000 /* Receive + Short Frames + */ +#define UPSMR_RPM 0x00080000 /* Reduced Pin + Mode + interfaces */ +#define UPSMR_R10M 0x00040000 /* RGMII/RMII + 10 Mode */ +#define UPSMR_RLPB 0x00020000 /* RMII + Loopback + Mode */ +#define UPSMR_TBIM 0x00010000 /* Ten-bit + Interface + Mode */ +#define UPSMR_RMM 0x00001000 /* RMII/RGMII + Mode */ +#define UPSMR_CAM 0x00000400 /* CAM Address + Matching */ +#define UPSMR_BRO 0x00000200 /* Broadcast + Address */ +#define UPSMR_RES1 0x00002000 /* Reserved + feild - must + be 1 */ + +/* UCC GETH MACCFG1 (MAC Configuration 1 Register) */ +#define MACCFG1_FLOW_RX 0x00000020 /* Flow Control + Rx */ +#define MACCFG1_FLOW_TX 0x00000010 /* Flow Control + Tx */ +#define MACCFG1_ENABLE_SYNCHED_RX 0x00000008 /* Rx Enable + synchronized + to Rx stream + */ +#define MACCFG1_ENABLE_RX 0x00000004 /* Enable Rx */ +#define MACCFG1_ENABLE_SYNCHED_TX 0x00000002 /* Tx Enable + synchronized + to Tx stream + */ +#define MACCFG1_ENABLE_TX 0x00000001 /* Enable Tx */ + +/* UCC GETH MACCFG2 (MAC Configuration 2 Register) */ +#define MACCFG2_PREL_SHIFT (31 - 19) /* Preamble + Length << + shift */ +#define MACCFG2_PREL_MASK 0x0000f000 /* Preamble + Length mask */ +#define MACCFG2_SRP 0x00000080 /* Soft Receive + Preamble */ +#define MACCFG2_STP 0x00000040 /* Soft + Transmit + Preamble */ +#define MACCFG2_RESERVED_1 0x00000020 /* Reserved - + must be set + to 1 */ +#define MACCFG2_LC 0x00000010 /* Length Check + */ +#define MACCFG2_MPE 0x00000008 /* Magic packet + detect */ +#define MACCFG2_FDX 0x00000001 /* Full Duplex */ +#define MACCFG2_FDX_MASK 0x00000001 /* Full Duplex + mask */ +#define MACCFG2_PAD_CRC 0x00000004 +#define MACCFG2_CRC_EN 0x00000002 +#define MACCFG2_PAD_AND_CRC_MODE_NONE 0x00000000 /* Neither + Padding + short frames + nor CRC */ +#define MACCFG2_PAD_AND_CRC_MODE_CRC_ONLY 0x00000002 /* Append CRC + only */ +#define MACCFG2_PAD_AND_CRC_MODE_PAD_AND_CRC 0x00000004 +#define MACCFG2_INTERFACE_MODE_NIBBLE 0x00000100 /* nibble mode + (MII/RMII/RGMII + 10/100bps) */ +#define MACCFG2_INTERFACE_MODE_BYTE 0x00000200 /* byte mode + (GMII/TBI/RTB/RGMII + 1000bps ) */ +#define MACCFG2_INTERFACE_MODE_MASK 0x00000300 /* mask + covering all + relevant + bits */ + +/* UCC GETH IPGIFG (Inter-frame Gap / Inter-Frame Gap Register) */ +#define IPGIFG_NON_BACK_TO_BACK_IFG_PART1_SHIFT (31 - 7) /* Non + back-to-back + inter frame + gap part 1. + << shift */ +#define IPGIFG_NON_BACK_TO_BACK_IFG_PART2_SHIFT (31 - 15) /* Non + back-to-back + inter frame + gap part 2. + << shift */ +#define IPGIFG_MINIMUM_IFG_ENFORCEMENT_SHIFT (31 - 23) /* Mimimum IFG + Enforcement + << shift */ +#define IPGIFG_BACK_TO_BACK_IFG_SHIFT (31 - 31) /* back-to-back + inter frame + gap << shift + */ +#define IPGIFG_NON_BACK_TO_BACK_IFG_PART1_MAX 127 /* Non back-to-back + inter frame gap part + 1. max val */ +#define IPGIFG_NON_BACK_TO_BACK_IFG_PART2_MAX 127 /* Non back-to-back + inter frame gap part + 2. max val */ +#define IPGIFG_MINIMUM_IFG_ENFORCEMENT_MAX 255 /* Mimimum IFG + Enforcement max val */ +#define IPGIFG_BACK_TO_BACK_IFG_MAX 127 /* back-to-back inter + frame gap max val */ +#define IPGIFG_NBTB_CS_IPG_MASK 0x7F000000 +#define IPGIFG_NBTB_IPG_MASK 0x007F0000 +#define IPGIFG_MIN_IFG_MASK 0x0000FF00 +#define IPGIFG_BTB_IPG_MASK 0x0000007F + +/* UCC GETH HAFDUP (Half Duplex Register) */ +#define HALFDUP_ALT_BEB_TRUNCATION_SHIFT (31 - 11) /* Alternate + Binary + Exponential + Backoff + Truncation + << shift */ +#define HALFDUP_ALT_BEB_TRUNCATION_MAX 0xf /* Alternate Binary + Exponential Backoff + Truncation max val */ +#define HALFDUP_ALT_BEB 0x00080000 /* Alternate + Binary + Exponential + Backoff */ +#define HALFDUP_BACK_PRESSURE_NO_BACKOFF 0x00040000 /* Back + pressure no + backoff */ +#define HALFDUP_NO_BACKOFF 0x00020000 /* No Backoff */ +#define HALFDUP_EXCESSIVE_DEFER 0x00010000 /* Excessive + Defer */ +#define HALFDUP_MAX_RETRANSMISSION_SHIFT (31 - 19) /* Maximum + Retransmission + << shift */ +#define HALFDUP_MAX_RETRANSMISSION_MAX 0xf /* Maximum + Retransmission max + val */ +#define HALFDUP_COLLISION_WINDOW_SHIFT (31 - 31) /* Collision + Window << + shift */ +#define HALFDUP_COLLISION_WINDOW_MAX 0x3f /* Collision Window max + val */ +#define HALFDUP_ALT_BEB_TR_MASK 0x00F00000 +#define HALFDUP_RETRANS_MASK 0x0000F000 +#define HALFDUP_COL_WINDOW_MASK 0x0000003F + +/* UCC GETH UCCS (Ethernet Status Register) */ +#define UCCS_BPR 0x02 /* Back pressure (in + half duplex mode) */ +#define UCCS_PAU 0x02 /* Pause state (in full + duplex mode) */ +#define UCCS_MPD 0x01 /* Magic Packet + Detected */ + +/* UCC GETH MIIMCFG (MII Management Configuration Register) */ +#define MIIMCFG_RESET_MANAGEMENT 0x80000000 /* Reset + management */ +#define MIIMCFG_NO_PREAMBLE 0x00000010 /* Preamble + suppress */ +#define MIIMCFG_CLOCK_DIVIDE_SHIFT (31 - 31) /* clock divide + << shift */ +#define MIIMCFG_CLOCK_DIVIDE_MAX 0xf /* clock divide max val + */ +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_2 0x00000000 /* divide by 2 */ +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_4 0x00000001 /* divide by 4 */ +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_6 0x00000002 /* divide by 6 */ +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_8 0x00000003 /* divide by 8 */ +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_10 0x00000004 /* divide by 10 + */ +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_14 0x00000005 /* divide by 14 + */ +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_16 0x00000008 /* divide by 16 + */ +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_20 0x00000006 /* divide by 20 + */ +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_28 0x00000007 /* divide by 28 + */ +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_32 0x00000009 /* divide by 32 + */ +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_48 0x0000000a /* divide by 48 + */ +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_64 0x0000000b /* divide by 64 + */ +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_80 0x0000000c /* divide by 80 + */ +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_112 0x0000000d /* divide by + 112 */ +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_160 0x0000000e /* divide by + 160 */ +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_224 0x0000000f /* divide by + 224 */ + +/* UCC GETH MIIMCOM (MII Management Command Register) */ +#define MIIMCOM_SCAN_CYCLE 0x00000002 /* Scan cycle */ +#define MIIMCOM_READ_CYCLE 0x00000001 /* Read cycle */ + +/* UCC GETH MIIMADD (MII Management Address Register) */ +#define MIIMADD_PHY_ADDRESS_SHIFT (31 - 23) /* PHY Address + << shift */ +#define MIIMADD_PHY_REGISTER_SHIFT (31 - 31) /* PHY Register + << shift */ + +/* UCC GETH MIIMCON (MII Management Control Register) */ +#define MIIMCON_PHY_CONTROL_SHIFT (31 - 31) /* PHY Control + << shift */ +#define MIIMCON_PHY_STATUS_SHIFT (31 - 31) /* PHY Status + << shift */ + +/* UCC GETH MIIMIND (MII Management Indicator Register) */ +#define MIIMIND_NOT_VALID 0x00000004 /* Not valid */ +#define MIIMIND_SCAN 0x00000002 /* Scan in + progress */ +#define MIIMIND_BUSY 0x00000001 + +/* UCC GETH IFSTAT (Interface Status Register) */ +#define IFSTAT_EXCESS_DEFER 0x00000200 /* Excessive + transmission + defer */ + +/* UCC GETH MACSTNADDR1 (Station Address Part 1 Register) */ +#define MACSTNADDR1_OCTET_6_SHIFT (31 - 7) /* Station + address 6th + octet << + shift */ +#define MACSTNADDR1_OCTET_5_SHIFT (31 - 15) /* Station + address 5th + octet << + shift */ +#define MACSTNADDR1_OCTET_4_SHIFT (31 - 23) /* Station + address 4th + octet << + shift */ +#define MACSTNADDR1_OCTET_3_SHIFT (31 - 31) /* Station + address 3rd + octet << + shift */ + +/* UCC GETH MACSTNADDR2 (Station Address Part 2 Register) */ +#define MACSTNADDR2_OCTET_2_SHIFT (31 - 7) /* Station + address 2nd + octet << + shift */ +#define MACSTNADDR2_OCTET_1_SHIFT (31 - 15) /* Station + address 1st + octet << + shift */ + +/* UCC GETH UEMPR (Ethernet Mac Parameter Register) */ +#define UEMPR_PAUSE_TIME_VALUE_SHIFT (31 - 15) /* Pause time + value << + shift */ +#define UEMPR_EXTENDED_PAUSE_TIME_VALUE_SHIFT (31 - 31) /* Extended + pause time + value << + shift */ + +/* UCC GETH UTBIPAR (Ten Bit Interface Physical Address Register) */ +#define UTBIPAR_PHY_ADDRESS_SHIFT (31 - 31) /* Phy address + << shift */ +#define UTBIPAR_PHY_ADDRESS_MASK 0x0000001f /* Phy address + mask */ + +/* UCC GETH UESCR (Ethernet Statistics Control Register) */ +#define UESCR_AUTOZ 0x8000 /* Automatically zero + addressed + statistical counter + values */ +#define UESCR_CLRCNT 0x4000 /* Clear all statistics + counters */ +#define UESCR_MAXCOV_SHIFT (15 - 7) /* Max + Coalescing + Value << + shift */ +#define UESCR_SCOV_SHIFT (15 - 15) /* Status + Coalescing + Value << + shift */ + +/* UCC GETH UDSR (Data Synchronization Register) */ +#define UDSR_MAGIC 0x067E + +typedef struct ucc_geth_thread_data_tx { + u8 res0[104]; +} __attribute__ ((packed)) ucc_geth_thread_data_tx_t; + +typedef struct ucc_geth_thread_data_rx { + u8 res0[40]; +} __attribute__ ((packed)) ucc_geth_thread_data_rx_t; + +/* Send Queue Queue-Descriptor */ +typedef struct ucc_geth_send_queue_qd { + u32 bd_ring_base; /* pointer to BD ring base address */ + u8 res0[0x8]; + u32 last_bd_completed_address;/* initialize to last entry in BD ring */ + u8 res1[0x30]; +} __attribute__ ((packed)) ucc_geth_send_queue_qd_t; + +typedef struct ucc_geth_send_queue_mem_region { + ucc_geth_send_queue_qd_t sqqd[NUM_TX_QUEUES]; +} __attribute__ ((packed)) ucc_geth_send_queue_mem_region_t; + +typedef struct ucc_geth_thread_tx_pram { + u8 res0[64]; +} __attribute__ ((packed)) ucc_geth_thread_tx_pram_t; + +typedef struct ucc_geth_thread_rx_pram { + u8 res0[128]; +} __attribute__ ((packed)) ucc_geth_thread_rx_pram_t; + +#define THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING 64 +#define THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING_8 64 +#define THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING_16 96 + +typedef struct ucc_geth_scheduler { + u16 cpucount0; /* CPU packet counter */ + u16 cpucount1; /* CPU packet counter */ + u16 cecount0; /* QE packet counter */ + u16 cecount1; /* QE packet counter */ + u16 cpucount2; /* CPU packet counter */ + u16 cpucount3; /* CPU packet counter */ + u16 cecount2; /* QE packet counter */ + u16 cecount3; /* QE packet counter */ + u16 cpucount4; /* CPU packet counter */ + u16 cpucount5; /* CPU packet counter */ + u16 cecount4; /* QE packet counter */ + u16 cecount5; /* QE packet counter */ + u16 cpucount6; /* CPU packet counter */ + u16 cpucount7; /* CPU packet counter */ + u16 cecount6; /* QE packet counter */ + u16 cecount7; /* QE packet counter */ + u32 weightstatus[NUM_TX_QUEUES]; /* accumulated weight factor */ + u32 rtsrshadow; /* temporary variable handled by QE */ + u32 time; /* temporary variable handled by QE */ + u32 ttl; /* temporary variable handled by QE */ + u32 mblinterval; /* max burst length interval */ + u16 nortsrbytetime; /* normalized value of byte time in tsr units */ + u8 fracsiz; /* radix 2 log value of denom. of + NorTSRByteTime */ + u8 res0[1]; + u8 strictpriorityq; /* Strict Priority Mask register */ + u8 txasap; /* Transmit ASAP register */ + u8 extrabw; /* Extra BandWidth register */ + u8 oldwfqmask; /* temporary variable handled by QE */ + u8 weightfactor[NUM_TX_QUEUES]; + /**< weight factor for queues */ + u32 minw; /* temporary variable handled by QE */ + u8 res1[0x70 - 0x64]; +} __attribute__ ((packed)) ucc_geth_scheduler_t; + +typedef struct ucc_geth_tx_firmware_statistics_pram { + u32 sicoltx; /* single collision */ + u32 mulcoltx; /* multiple collision */ + u32 latecoltxfr; /* late collision */ + u32 frabortduecol; /* frames aborted due to transmit collision */ + u32 frlostinmactxer; /* frames lost due to internal MAC error + transmission that are not counted on any + other counter */ + u32 carriersenseertx; /* carrier sense error */ + u32 frtxok; /* frames transmitted OK */ + u32 txfrexcessivedefer; /* frames with defferal time greater than + specified threshold */ + u32 txpkts256; /* total packets (including bad) between 256 + and 511 octets */ + u32 txpkts512; /* total packets (including bad) between 512 + and 1023 octets */ + u32 txpkts1024; /* total packets (including bad) between 1024 + and 1518 octets */ + u32 txpktsjumbo; /* total packets (including bad) between 1024 + and MAXLength octets */ +} __attribute__ ((packed)) ucc_geth_tx_firmware_statistics_pram_t; + +typedef struct ucc_geth_rx_firmware_statistics_pram { + u32 frrxfcser; /* frames with crc error */ + u32 fraligner; /* frames with alignment error */ + u32 inrangelenrxer; /* in range length error */ + u32 outrangelenrxer; /* out of range length error */ + u32 frtoolong; /* frame too long */ + u32 runt; /* runt */ + u32 verylongevent; /* very long event */ + u32 symbolerror; /* symbol error */ + u32 dropbsy; /* drop because of BD not ready */ + u8 res0[0x8]; + u32 mismatchdrop; /* drop because of MAC filtering (e.g. address + or type mismatch) */ + u32 underpkts; /* total frames less than 64 octets */ + u32 pkts256; /* total frames (including bad) between 256 and + 511 octets */ + u32 pkts512; /* total frames (including bad) between 512 and + 1023 octets */ + u32 pkts1024; /* total frames (including bad) between 1024 + and 1518 octets */ + u32 pktsjumbo; /* total frames (including bad) between 1024 + and MAXLength octets */ + u32 frlossinmacer; /* frames lost because of internal MAC error + that is not counted in any other counter */ + u32 pausefr; /* pause frames */ + u8 res1[0x4]; + u32 removevlan; /* total frames that had their VLAN tag removed + */ + u32 replacevlan; /* total frames that had their VLAN tag + replaced */ + u32 insertvlan; /* total frames that had their VLAN tag + inserted */ +} __attribute__ ((packed)) ucc_geth_rx_firmware_statistics_pram_t; + +typedef struct ucc_geth_rx_interrupt_coalescing_entry { + u32 interruptcoalescingmaxvalue; /* interrupt coalescing max + value */ + u32 interruptcoalescingcounter; /* interrupt coalescing counter, + initialize to + interruptcoalescingmaxvalue */ +} __attribute__ ((packed)) ucc_geth_rx_interrupt_coalescing_entry_t; + +typedef struct ucc_geth_rx_interrupt_coalescing_table { + ucc_geth_rx_interrupt_coalescing_entry_t coalescingentry[NUM_RX_QUEUES]; + /**< interrupt coalescing entry */ +} __attribute__ ((packed)) ucc_geth_rx_interrupt_coalescing_table_t; + +typedef struct ucc_geth_rx_prefetched_bds { + qe_bd_t bd[NUM_BDS_IN_PREFETCHED_BDS]; /* prefetched bd */ +} __attribute__ ((packed)) ucc_geth_rx_prefetched_bds_t; + +typedef struct ucc_geth_rx_bd_queues_entry { + u32 bdbaseptr; /* BD base pointer */ + u32 bdptr; /* BD pointer */ + u32 externalbdbaseptr; /* external BD base pointer */ + u32 externalbdptr; /* external BD pointer */ +} __attribute__ ((packed)) ucc_geth_rx_bd_queues_entry_t; + +typedef struct ucc_geth_tx_global_pram { + u16 temoder; + u8 res0[0x38 - 0x02]; + u32 sqptr; /* a base pointer to send queue memory region */ + u32 schedulerbasepointer; /* a base pointer to scheduler memory + region */ + u32 txrmonbaseptr; /* base pointer to Tx RMON statistics counter */ + u32 tstate; /* tx internal state. High byte contains + function code */ + u8 iphoffset[TX_IP_OFFSET_ENTRY_MAX]; + u32 vtagtable[0x8]; /* 8 4-byte VLAN tags */ + u32 tqptr; /* a base pointer to the Tx Queues Memory + Region */ + u8 res2[0x80 - 0x74]; +} __attribute__ ((packed)) ucc_geth_tx_global_pram_t; + +/* structure representing Extended Filtering Global Parameters in PRAM */ +typedef struct ucc_geth_exf_global_pram { + u32 l2pcdptr; /* individual address filter, high */ + u8 res0[0x10 - 0x04]; +} __attribute__ ((packed)) ucc_geth_exf_global_pram_t; + +typedef struct ucc_geth_rx_global_pram { + u32 remoder; /* ethernet mode reg. */ + u32 rqptr; /* base pointer to the Rx Queues Memory Region*/ + u32 res0[0x1]; + u8 res1[0x20 - 0xC]; + u16 typeorlen; /* cutoff point less than which, type/len field + is considered length */ + u8 res2[0x1]; + u8 rxgstpack; /* acknowledgement on GRACEFUL STOP RX command*/ + u32 rxrmonbaseptr; /* base pointer to Rx RMON statistics counter */ + u8 res3[0x30 - 0x28]; + u32 intcoalescingptr; /* Interrupt coalescing table pointer */ + u8 res4[0x36 - 0x34]; + u8 rstate; /* rx internal state. High byte contains + function code */ + u8 res5[0x46 - 0x37]; + u16 mrblr; /* max receive buffer length reg. */ + u32 rbdqptr; /* base pointer to RxBD parameter table + description */ + u16 mflr; /* max frame length reg. */ + u16 minflr; /* min frame length reg. */ + u16 maxd1; /* max dma1 length reg. */ + u16 maxd2; /* max dma2 length reg. */ + u32 ecamptr; /* external CAM address */ + u32 l2qt; /* VLAN priority mapping table. */ + u32 l3qt[0x8]; /* IP priority mapping table. */ + u16 vlantype; /* vlan type */ + u16 vlantci; /* default vlan tci */ + u8 addressfiltering[64]; /* address filtering data structure */ + u32 exfGlobalParam; /* base address for extended filtering global + parameters */ + u8 res6[0x100 - 0xC4]; /* Initialize to zero */ +} __attribute__ ((packed)) ucc_geth_rx_global_pram_t; + +#define GRACEFUL_STOP_ACKNOWLEDGE_RX 0x01 + +/* structure representing InitEnet command */ +typedef struct ucc_geth_init_pram { + u8 resinit1; + u8 resinit2; + u8 resinit3; + u8 resinit4; + u16 resinit5; + u8 res1[0x1]; + u8 largestexternallookupkeysize; + u32 rgftgfrxglobal; + u32 rxthread[ENET_INIT_PARAM_MAX_ENTRIES_RX]; /* rx threads */ + u8 res2[0x38 - 0x30]; + u32 txglobal; /* tx global */ + u32 txthread[ENET_INIT_PARAM_MAX_ENTRIES_TX]; /* tx threads */ + u8 res3[0x1]; +} __attribute__ ((packed)) ucc_geth_init_pram_t; + +#define ENET_INIT_PARAM_RGF_SHIFT (32 - 4) +#define ENET_INIT_PARAM_TGF_SHIFT (32 - 8) + +#define ENET_INIT_PARAM_RISC_MASK 0x0000003f +#define ENET_INIT_PARAM_PTR_MASK 0x00ffffc0 +#define ENET_INIT_PARAM_SNUM_MASK 0xff000000 +#define ENET_INIT_PARAM_SNUM_SHIFT 24 + +#define ENET_INIT_PARAM_MAGIC_RES_INIT1 0x06 +#define ENET_INIT_PARAM_MAGIC_RES_INIT2 0x30 +#define ENET_INIT_PARAM_MAGIC_RES_INIT3 0xff +#define ENET_INIT_PARAM_MAGIC_RES_INIT4 0x00 +#define ENET_INIT_PARAM_MAGIC_RES_INIT5 0x0400 + +/* structure representing 82xx Address Filtering Enet Address in PRAM */ +typedef struct ucc_geth_82xx_enet_address { + u8 res1[0x2]; + u16 h; /* address (MSB) */ + u16 m; /* address */ + u16 l; /* address (LSB) */ +} __attribute__ ((packed)) ucc_geth_82xx_enet_address_t; + +/* structure representing 82xx Address Filtering PRAM */ +typedef struct ucc_geth_82xx_address_filtering_pram { + u32 iaddr_h; /* individual address filter, high */ + u32 iaddr_l; /* individual address filter, low */ + u32 gaddr_h; /* group address filter, high */ + u32 gaddr_l; /* group address filter, low */ + ucc_geth_82xx_enet_address_t taddr; + ucc_geth_82xx_enet_address_t paddr[NUM_OF_PADDRS]; + u8 res0[0x40 - 0x38]; +} __attribute__ ((packed)) ucc_geth_82xx_address_filtering_pram_t; + +/* GETH Tx firmware statistics structure, used when calling + UCC_GETH_GetStatistics. */ +typedef struct ucc_geth_tx_firmware_statistics { + u32 sicoltx; /* single collision */ + u32 mulcoltx; /* multiple collision */ + u32 latecoltxfr; /* late collision */ + u32 frabortduecol; /* frames aborted due to transmit collision */ + u32 frlostinmactxer; /* frames lost due to internal MAC error + transmission that are not counted on any + other counter */ + u32 carriersenseertx; /* carrier sense error */ + u32 frtxok; /* frames transmitted OK */ + u32 txfrexcessivedefer; /* frames with defferal time greater than + specified threshold */ + u32 txpkts256; /* total packets (including bad) between 256 + and 511 octets */ + u32 txpkts512; /* total packets (including bad) between 512 + and 1023 octets */ + u32 txpkts1024; /* total packets (including bad) between 1024 + and 1518 octets */ + u32 txpktsjumbo; /* total packets (including bad) between 1024 + and MAXLength octets */ +} __attribute__ ((packed)) ucc_geth_tx_firmware_statistics_t; + +/* GETH Rx firmware statistics structure, used when calling + UCC_GETH_GetStatistics. */ +typedef struct ucc_geth_rx_firmware_statistics { + u32 frrxfcser; /* frames with crc error */ + u32 fraligner; /* frames with alignment error */ + u32 inrangelenrxer; /* in range length error */ + u32 outrangelenrxer; /* out of range length error */ + u32 frtoolong; /* frame too long */ + u32 runt; /* runt */ + u32 verylongevent; /* very long event */ + u32 symbolerror; /* symbol error */ + u32 dropbsy; /* drop because of BD not ready */ + u8 res0[0x8]; + u32 mismatchdrop; /* drop because of MAC filtering (e.g. address + or type mismatch) */ + u32 underpkts; /* total frames less than 64 octets */ + u32 pkts256; /* total frames (including bad) between 256 and + 511 octets */ + u32 pkts512; /* total frames (including bad) between 512 and + 1023 octets */ + u32 pkts1024; /* total frames (including bad) between 1024 + and 1518 octets */ + u32 pktsjumbo; /* total frames (including bad) between 1024 + and MAXLength octets */ + u32 frlossinmacer; /* frames lost because of internal MAC error + that is not counted in any other counter */ + u32 pausefr; /* pause frames */ + u8 res1[0x4]; + u32 removevlan; /* total frames that had their VLAN tag removed + */ + u32 replacevlan; /* total frames that had their VLAN tag + replaced */ + u32 insertvlan; /* total frames that had their VLAN tag + inserted */ +} __attribute__ ((packed)) ucc_geth_rx_firmware_statistics_t; + +/* GETH hardware statistics structure, used when calling + UCC_GETH_GetStatistics. */ +typedef struct ucc_geth_hardware_statistics { + u32 tx64; /* Total number of frames (including bad + frames) transmitted that were exactly of the + minimal length (64 for un tagged, 68 for + tagged, or with length exactly equal to the + parameter MINLength */ + u32 tx127; /* Total number of frames (including bad + frames) transmitted that were between + MINLength (Including FCS length==4) and 127 + octets */ + u32 tx255; /* Total number of frames (including bad + frames) transmitted that were between 128 + (Including FCS length==4) and 255 octets */ + u32 rx64; /* Total number of frames received including + bad frames that were exactly of the mninimal + length (64 bytes) */ + u32 rx127; /* Total number of frames (including bad + frames) received that were between MINLength + (Including FCS length==4) and 127 octets */ + u32 rx255; /* Total number of frames (including bad + frames) received that were between 128 + (Including FCS length==4) and 255 octets */ + u32 txok; /* Total number of octets residing in frames + that where involved in succesfull + transmission */ + u16 txcf; /* Total number of PAUSE control frames + transmitted by this MAC */ + u32 tmca; /* Total number of frames that were transmitted + succesfully with the group address bit set + that are not broadcast frames */ + u32 tbca; /* Total number of frames transmitted + succesfully that had destination address + field equal to the broadcast address */ + u32 rxfok; /* Total number of frames received OK */ + u32 rxbok; /* Total number of octets received OK */ + u32 rbyt; /* Total number of octets received including + octets in bad frames. Must be implemented in + HW because it includes octets in frames that + never even reach the UCC */ + u32 rmca; /* Total number of frames that were received + succesfully with the group address bit set + that are not broadcast frames */ + u32 rbca; /* Total number of frames received succesfully + that had destination address equal to the + broadcast address */ +} __attribute__ ((packed)) ucc_geth_hardware_statistics_t; + +/* UCC GETH Tx errors returned via TxConf callback */ +#define TX_ERRORS_DEF 0x0200 +#define TX_ERRORS_EXDEF 0x0100 +#define TX_ERRORS_LC 0x0080 +#define TX_ERRORS_RL 0x0040 +#define TX_ERRORS_RC_MASK 0x003C +#define TX_ERRORS_RC_SHIFT 2 +#define TX_ERRORS_UN 0x0002 +#define TX_ERRORS_CSL 0x0001 + +/* UCC GETH Rx errors returned via RxStore callback */ +#define RX_ERRORS_CMR 0x0200 +#define RX_ERRORS_M 0x0100 +#define RX_ERRORS_BC 0x0080 +#define RX_ERRORS_MC 0x0040 + +/* Transmit BD. These are in addition to values defined in uccf. */ +#define T_VID 0x003c0000 /* insert VLAN id index mask. */ +#define T_DEF (((u32) TX_ERRORS_DEF ) << 16) +#define T_EXDEF (((u32) TX_ERRORS_EXDEF ) << 16) +#define T_LC (((u32) TX_ERRORS_LC ) << 16) +#define T_RL (((u32) TX_ERRORS_RL ) << 16) +#define T_RC_MASK (((u32) TX_ERRORS_RC_MASK ) << 16) +#define T_UN (((u32) TX_ERRORS_UN ) << 16) +#define T_CSL (((u32) TX_ERRORS_CSL ) << 16) +#define T_ERRORS_REPORT (T_DEF | T_EXDEF | T_LC | T_RL | T_RC_MASK \ + | T_UN | T_CSL) /* transmit errors to report */ + +/* Receive BD. These are in addition to values defined in uccf. */ +#define R_LG 0x00200000 /* Frame length violation. */ +#define R_NO 0x00100000 /* Non-octet aligned frame. */ +#define R_SH 0x00080000 /* Short frame. */ +#define R_CR 0x00040000 /* CRC error. */ +#define R_OV 0x00020000 /* Overrun. */ +#define R_IPCH 0x00010000 /* IP checksum check failed. */ +#define R_CMR (((u32) RX_ERRORS_CMR ) << 16) +#define R_M (((u32) RX_ERRORS_M ) << 16) +#define R_BC (((u32) RX_ERRORS_BC ) << 16) +#define R_MC (((u32) RX_ERRORS_MC ) << 16) +#define R_ERRORS_REPORT (R_CMR | R_M | R_BC | R_MC) /* receive errors to + report */ +#define R_ERRORS_FATAL (R_LG | R_NO | R_SH | R_CR | \ + R_OV | R_IPCH) /* receive errors to discard */ + +/* Alignments */ +#define UCC_GETH_RX_GLOBAL_PRAM_ALIGNMENT 256 +#define UCC_GETH_TX_GLOBAL_PRAM_ALIGNMENT 128 +#define UCC_GETH_THREAD_RX_PRAM_ALIGNMENT 128 +#define UCC_GETH_THREAD_TX_PRAM_ALIGNMENT 64 +#define UCC_GETH_THREAD_DATA_ALIGNMENT 256 /* spec gives values + based on num of + threads, but always + using the maximum is + easier */ +#define UCC_GETH_SEND_QUEUE_QUEUE_DESCRIPTOR_ALIGNMENT 32 +#define UCC_GETH_SCHEDULER_ALIGNMENT 4 /* This is a guess */ +#define UCC_GETH_TX_STATISTICS_ALIGNMENT 4 /* This is a guess */ +#define UCC_GETH_RX_STATISTICS_ALIGNMENT 4 /* This is a guess */ +#define UCC_GETH_RX_INTERRUPT_COALESCING_ALIGNMENT 4 /* This is a + guess */ +#define UCC_GETH_RX_BD_QUEUES_ALIGNMENT 8 /* This is a guess */ +#define UCC_GETH_RX_PREFETCHED_BDS_ALIGNMENT 128 /* This is a guess */ +#define UCC_GETH_RX_EXTENDED_FILTERING_GLOBAL_PARAMETERS_ALIGNMENT 4 /* This + is a + guess + */ +#define UCC_GETH_RX_BD_RING_ALIGNMENT 32 +#define UCC_GETH_TX_BD_RING_ALIGNMENT 32 +#define UCC_GETH_MRBLR_ALIGNMENT 128 +#define UCC_GETH_RX_BD_RING_SIZE_ALIGNMENT 4 +#define UCC_GETH_TX_BD_RING_SIZE_MEMORY_ALIGNMENT 32 +#define UCC_GETH_RX_DATA_BUF_ALIGNMENT 64 + +#define UCC_GETH_TAD_EF 0x80 +#define UCC_GETH_TAD_V 0x40 +#define UCC_GETH_TAD_REJ 0x20 +#define UCC_GETH_TAD_VTAG_OP_RIGHT_SHIFT 2 +#define UCC_GETH_TAD_VTAG_OP_SHIFT 6 +#define UCC_GETH_TAD_V_NON_VTAG_OP 0x20 +#define UCC_GETH_TAD_RQOS_SHIFT 0 +#define UCC_GETH_TAD_V_PRIORITY_SHIFT 5 +#define UCC_GETH_TAD_CFI 0x10 + +#define UCC_GETH_VLAN_PRIORITY_MAX 8 +#define UCC_GETH_IP_PRIORITY_MAX 64 +#define UCC_GETH_TX_VTAG_TABLE_ENTRY_MAX 8 +#define UCC_GETH_RX_BD_RING_SIZE_MIN 8 +#define UCC_GETH_TX_BD_RING_SIZE_MIN 2 + +#define UCC_GETH_SIZE_OF_BD QE_SIZEOF_BD + +/* Driver definitions */ +#define TX_BD_RING_LEN 0x10 +#define RX_BD_RING_LEN 0x10 +#define UCC_GETH_DEV_WEIGHT TX_BD_RING_LEN + +#define TX_RING_MOD_MASK(size) (size-1) +#define RX_RING_MOD_MASK(size) (size-1) + +#define ENET_NUM_OCTETS_PER_ADDRESS 6 +#define ENET_GROUP_ADDR 0x01 /* Group address mask + for ethernet + addresses */ + +#define TX_TIMEOUT (1*HZ) +#define SKB_ALLOC_TIMEOUT 100000 +#define PHY_INIT_TIMEOUT 100000 +#define PHY_CHANGE_TIME 2 + +/* Fast Ethernet (10/100 Mbps) */ +#define UCC_GETH_URFS_INIT 512 /* Rx virtual FIFO size + */ +#define UCC_GETH_URFET_INIT 256 /* 1/2 urfs */ +#define UCC_GETH_URFSET_INIT 384 /* 3/4 urfs */ +#define UCC_GETH_UTFS_INIT 512 /* Tx virtual FIFO size + */ +#define UCC_GETH_UTFET_INIT 256 /* 1/2 utfs */ +#define UCC_GETH_UTFTT_INIT 128 +/* Gigabit Ethernet (1000 Mbps) */ +#define UCC_GETH_URFS_GIGA_INIT 4096/*2048*/ /* Rx virtual + FIFO size */ +#define UCC_GETH_URFET_GIGA_INIT 2048/*1024*/ /* 1/2 urfs */ +#define UCC_GETH_URFSET_GIGA_INIT 3072/*1536*/ /* 3/4 urfs */ +#define UCC_GETH_UTFS_GIGA_INIT 8192/*2048*/ /* Tx virtual + FIFO size */ +#define UCC_GETH_UTFET_GIGA_INIT 4096/*1024*/ /* 1/2 utfs */ +#define UCC_GETH_UTFTT_GIGA_INIT 0x400/*0x40*/ /* */ + +#define UCC_GETH_REMODER_INIT 0 /* bits that must be + set */ +#define UCC_GETH_TEMODER_INIT 0xC000 /* bits that must */ +#define UCC_GETH_UPSMR_INIT (UPSMR_RES1) /* Start value + for this + register */ +#define UCC_GETH_MACCFG1_INIT 0 +#define UCC_GETH_MACCFG2_INIT (MACCFG2_RESERVED_1) +#define UCC_GETH_MIIMCFG_MNGMNT_CLC_DIV_INIT \ + (MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_112) + +/* Ethernet speed */ +typedef enum enet_speed { + ENET_SPEED_10BT, /* 10 Base T */ + ENET_SPEED_100BT, /* 100 Base T */ + ENET_SPEED_1000BT /* 1000 Base T */ +} enet_speed_e; + +/* Ethernet Address Type. */ +typedef enum enet_addr_type { + ENET_ADDR_TYPE_INDIVIDUAL, + ENET_ADDR_TYPE_GROUP, + ENET_ADDR_TYPE_BROADCAST +} enet_addr_type_e; + +/* TBI / MII Set Register */ +typedef enum enet_tbi_mii_reg { + ENET_TBI_MII_CR = 0x00, /* Control (CR ) */ + ENET_TBI_MII_SR = 0x01, /* Status (SR ) */ + ENET_TBI_MII_ANA = 0x04, /* AN advertisement (ANA ) */ + ENET_TBI_MII_ANLPBPA = 0x05, /* AN link partner base page ability + (ANLPBPA) */ + ENET_TBI_MII_ANEX = 0x06, /* AN expansion (ANEX ) */ + ENET_TBI_MII_ANNPT = 0x07, /* AN next page transmit (ANNPT ) */ + ENET_TBI_MII_ANLPANP = 0x08, /* AN link partner ability next page + (ANLPANP) */ + ENET_TBI_MII_EXST = 0x0F, /* Extended status (EXST ) */ + ENET_TBI_MII_JD = 0x10, /* Jitter diagnostics (JD ) */ + ENET_TBI_MII_TBICON = 0x11 /* TBI control (TBICON ) */ +} enet_tbi_mii_reg_e; + +/* UCC GETH 82xx Ethernet Address Recognition Location */ +typedef enum ucc_geth_enet_address_recognition_location { + UCC_GETH_ENET_ADDRESS_RECOGNITION_LOCATION_STATION_ADDRESS,/* station + address */ + UCC_GETH_ENET_ADDRESS_RECOGNITION_LOCATION_PADDR_FIRST, /* additional + station + address + paddr1 */ + UCC_GETH_ENET_ADDRESS_RECOGNITION_LOCATION_PADDR2, /* additional + station + address + paddr2 */ + UCC_GETH_ENET_ADDRESS_RECOGNITION_LOCATION_PADDR3, /* additional + station + address + paddr3 */ + UCC_GETH_ENET_ADDRESS_RECOGNITION_LOCATION_PADDR_LAST, /* additional + station + address + paddr4 */ + UCC_GETH_ENET_ADDRESS_RECOGNITION_LOCATION_GROUP_HASH, /* group hash */ + UCC_GETH_ENET_ADDRESS_RECOGNITION_LOCATION_INDIVIDUAL_HASH /* individual + hash */ +} ucc_geth_enet_address_recognition_location_e; + +/* UCC GETH vlan operation tagged */ +typedef enum ucc_geth_vlan_operation_tagged { + UCC_GETH_VLAN_OPERATION_TAGGED_NOP = 0x0, /* Tagged - nop */ + UCC_GETH_VLAN_OPERATION_TAGGED_REPLACE_VID_PORTION_OF_Q_TAG + = 0x1, /* Tagged - replace vid portion of q tag */ + UCC_GETH_VLAN_OPERATION_TAGGED_IF_VID0_REPLACE_VID_WITH_DEFAULT_VALUE + = 0x2, /* Tagged - if vid0 replace vid with default value */ + UCC_GETH_VLAN_OPERATION_TAGGED_EXTRACT_Q_TAG_FROM_FRAME + = 0x3 /* Tagged - extract q tag from frame */ +} ucc_geth_vlan_operation_tagged_e; + +/* UCC GETH vlan operation non-tagged */ +typedef enum ucc_geth_vlan_operation_non_tagged { + UCC_GETH_VLAN_OPERATION_NON_TAGGED_NOP = 0x0, /* Non tagged - nop */ + UCC_GETH_VLAN_OPERATION_NON_TAGGED_Q_TAG_INSERT = 0x1 /* Non tagged - + q tag insert + */ +} ucc_geth_vlan_operation_non_tagged_e; + +/* UCC GETH Rx Quality of Service Mode */ +typedef enum ucc_geth_qos_mode { + UCC_GETH_QOS_MODE_DEFAULT = 0x0, /* default queue */ + UCC_GETH_QOS_MODE_QUEUE_NUM_FROM_L2_CRITERIA = 0x1, /* queue + determined + by L2 + criteria */ + UCC_GETH_QOS_MODE_QUEUE_NUM_FROM_L3_CRITERIA = 0x2 /* queue + determined + by L3 + criteria */ +} ucc_geth_qos_mode_e; + +/* UCC GETH Statistics Gathering Mode - These are bit flags, 'or' them together + for combined functionality */ +typedef enum ucc_geth_statistics_gathering_mode { + UCC_GETH_STATISTICS_GATHERING_MODE_NONE = 0x00000000, /* No + statistics + gathering */ + UCC_GETH_STATISTICS_GATHERING_MODE_HARDWARE = 0x00000001,/* Enable + hardware + statistics + gathering + */ + UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_TX = 0x00000004,/*Enable + firmware + tx + statistics + gathering + */ + UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_RX = 0x00000008/* Enable + firmware + rx + statistics + gathering + */ +} ucc_geth_statistics_gathering_mode_e; + +/* UCC GETH Pad and CRC Mode - Note, Padding without CRC is not possible */ +typedef enum ucc_geth_maccfg2_pad_and_crc_mode { + UCC_GETH_PAD_AND_CRC_MODE_NONE + = MACCFG2_PAD_AND_CRC_MODE_NONE, /* Neither Padding + short frames + nor CRC */ + UCC_GETH_PAD_AND_CRC_MODE_CRC_ONLY + = MACCFG2_PAD_AND_CRC_MODE_CRC_ONLY, /* Append + CRC only */ + UCC_GETH_PAD_AND_CRC_MODE_PAD_AND_CRC = + MACCFG2_PAD_AND_CRC_MODE_PAD_AND_CRC +} ucc_geth_maccfg2_pad_and_crc_mode_e; + +/* UCC GETH upsmr Flow Control Mode */ +typedef enum ucc_geth_flow_control_mode { + UPSMR_AUTOMATIC_FLOW_CONTROL_MODE_NONE = 0x00000000, /* No automatic + flow control + */ + UPSMR_AUTOMATIC_FLOW_CONTROL_MODE_PAUSE_WHEN_EMERGENCY + = 0x00004000 /* Send pause frame when RxFIFO reaches its + emergency threshold */ +} ucc_geth_flow_control_mode_e; + +/* UCC GETH number of threads */ +typedef enum ucc_geth_num_of_threads { + UCC_GETH_NUM_OF_THREADS_1 = 0x1, /* 1 */ + UCC_GETH_NUM_OF_THREADS_2 = 0x2, /* 2 */ + UCC_GETH_NUM_OF_THREADS_4 = 0x0, /* 4 */ + UCC_GETH_NUM_OF_THREADS_6 = 0x3, /* 6 */ + UCC_GETH_NUM_OF_THREADS_8 = 0x4 /* 8 */ +} ucc_geth_num_of_threads_e; + +/* UCC GETH number of station addresses */ +typedef enum ucc_geth_num_of_station_addresses { + UCC_GETH_NUM_OF_STATION_ADDRESSES_1, /* 1 */ + UCC_GETH_NUM_OF_STATION_ADDRESSES_5 /* 5 */ +} ucc_geth_num_of_station_addresses_e; + +typedef u8 enet_addr_t[ENET_NUM_OCTETS_PER_ADDRESS]; + +/* UCC GETH 82xx Ethernet Address Container */ +typedef struct enet_addr_container { + enet_addr_t address; /* ethernet address */ + ucc_geth_enet_address_recognition_location_e location; /* location in + 82xx address + recognition + hardware */ + struct list_head node; +} enet_addr_container_t; + +#define ENET_ADDR_CONT_ENTRY(ptr) list_entry(ptr, enet_addr_container_t, node) + +/* UCC GETH Termination Action Descriptor (TAD) structure. */ +typedef struct ucc_geth_tad_params { + int rx_non_dynamic_extended_features_mode; + int reject_frame; + ucc_geth_vlan_operation_tagged_e vtag_op; + ucc_geth_vlan_operation_non_tagged_e vnontag_op; + ucc_geth_qos_mode_e rqos; + u8 vpri; + u16 vid; +} ucc_geth_tad_params_t; + +/* GETH protocol initialization structure */ +typedef struct ucc_geth_info { + ucc_fast_info_t uf_info; + u8 numQueuesTx; + u8 numQueuesRx; + int ipCheckSumCheck; + int ipCheckSumGenerate; + int rxExtendedFiltering; + u32 extendedFilteringChainPointer; + u16 typeorlen; + int dynamicMaxFrameLength; + int dynamicMinFrameLength; + u8 nonBackToBackIfgPart1; + u8 nonBackToBackIfgPart2; + u8 miminumInterFrameGapEnforcement; + u8 backToBackInterFrameGap; + int ipAddressAlignment; + int lengthCheckRx; + u32 mblinterval; + u16 nortsrbytetime; + u8 fracsiz; + u8 strictpriorityq; + u8 txasap; + u8 extrabw; + int miiPreambleSupress; + u8 altBebTruncation; + int altBeb; + int backPressureNoBackoff; + int noBackoff; + int excessDefer; + u8 maxRetransmission; + u8 collisionWindow; + int pro; + int cap; + int rsh; + int rlpb; + int cam; + int bro; + int ecm; + int receiveFlowControl; + u8 maxGroupAddrInHash; + u8 maxIndAddrInHash; + u8 prel; + u16 maxFrameLength; + u16 minFrameLength; + u16 maxD1Length; + u16 maxD2Length; + u16 vlantype; + u16 vlantci; + u32 ecamptr; + u32 eventRegMask; + u16 pausePeriod; + u16 extensionField; + u8 phy_address; + u32 board_flags; + u32 phy_interrupt; + u8 weightfactor[NUM_TX_QUEUES]; + u8 interruptcoalescingmaxvalue[NUM_RX_QUEUES]; + u8 l2qt[UCC_GETH_VLAN_PRIORITY_MAX]; + u8 l3qt[UCC_GETH_IP_PRIORITY_MAX]; + u32 vtagtable[UCC_GETH_TX_VTAG_TABLE_ENTRY_MAX]; + u8 iphoffset[TX_IP_OFFSET_ENTRY_MAX]; + u16 bdRingLenTx[NUM_TX_QUEUES]; + u16 bdRingLenRx[NUM_RX_QUEUES]; + enet_interface_e enet_interface; + ucc_geth_num_of_station_addresses_e numStationAddresses; + qe_fltr_largest_external_tbl_lookup_key_size_e + largestexternallookupkeysize; + ucc_geth_statistics_gathering_mode_e statisticsMode; + ucc_geth_vlan_operation_tagged_e vlanOperationTagged; + ucc_geth_vlan_operation_non_tagged_e vlanOperationNonTagged; + ucc_geth_qos_mode_e rxQoSMode; + ucc_geth_flow_control_mode_e aufc; + ucc_geth_maccfg2_pad_and_crc_mode_e padAndCrc; + ucc_geth_num_of_threads_e numThreadsTx; + ucc_geth_num_of_threads_e numThreadsRx; + qe_risc_allocation_e riscTx; + qe_risc_allocation_e riscRx; +} ucc_geth_info_t; + +/* structure representing UCC GETH */ +typedef struct ucc_geth_private { + ucc_geth_info_t *ug_info; + ucc_fast_private_t *uccf; + struct net_device *dev; + struct net_device_stats stats; /* linux network statistics */ + ucc_geth_t *ug_regs; + ucc_geth_init_pram_t *p_init_enet_param_shadow; + ucc_geth_exf_global_pram_t *p_exf_glbl_param; + u32 exf_glbl_param_offset; + ucc_geth_rx_global_pram_t *p_rx_glbl_pram; + u32 rx_glbl_pram_offset; + ucc_geth_tx_global_pram_t *p_tx_glbl_pram; + u32 tx_glbl_pram_offset; + ucc_geth_send_queue_mem_region_t *p_send_q_mem_reg; + u32 send_q_mem_reg_offset; + ucc_geth_thread_data_tx_t *p_thread_data_tx; + u32 thread_dat_tx_offset; + ucc_geth_thread_data_rx_t *p_thread_data_rx; + u32 thread_dat_rx_offset; + ucc_geth_scheduler_t *p_scheduler; + u32 scheduler_offset; + ucc_geth_tx_firmware_statistics_pram_t *p_tx_fw_statistics_pram; + u32 tx_fw_statistics_pram_offset; + ucc_geth_rx_firmware_statistics_pram_t *p_rx_fw_statistics_pram; + u32 rx_fw_statistics_pram_offset; + ucc_geth_rx_interrupt_coalescing_table_t *p_rx_irq_coalescing_tbl; + u32 rx_irq_coalescing_tbl_offset; + ucc_geth_rx_bd_queues_entry_t *p_rx_bd_qs_tbl; + u32 rx_bd_qs_tbl_offset; + u8 *p_tx_bd_ring[NUM_TX_QUEUES]; + u32 tx_bd_ring_offset[NUM_TX_QUEUES]; + u8 *p_rx_bd_ring[NUM_RX_QUEUES]; + u32 rx_bd_ring_offset[NUM_RX_QUEUES]; + u8 *confBd[NUM_TX_QUEUES]; + u8 *txBd[NUM_TX_QUEUES]; + u8 *rxBd[NUM_RX_QUEUES]; + int badFrame[NUM_RX_QUEUES]; + u16 cpucount[NUM_TX_QUEUES]; + volatile u16 *p_cpucount[NUM_TX_QUEUES]; + int indAddrRegUsed[NUM_OF_PADDRS]; + enet_addr_t paddr[NUM_OF_PADDRS]; + u8 numGroupAddrInHash; + u8 numIndAddrInHash; + u8 numIndAddrInReg; + int rx_extended_features; + int rx_non_dynamic_extended_features; + struct list_head conf_skbs; + struct list_head group_hash_q; + struct list_head ind_hash_q; + u32 saved_uccm; + spinlock_t lock; + /* pointers to arrays of skbuffs for tx and rx */ + struct sk_buff **tx_skbuff[NUM_TX_QUEUES]; + struct sk_buff **rx_skbuff[NUM_RX_QUEUES]; + /* indices pointing to the next free sbk in skb arrays */ + u16 skb_curtx[NUM_TX_QUEUES]; + u16 skb_currx[NUM_RX_QUEUES]; + /* index of the first skb which hasn't been transmitted yet. */ + u16 skb_dirtytx[NUM_TX_QUEUES]; + + struct work_struct tq; + struct timer_list phy_info_timer; + struct ugeth_mii_info *mii_info; + int oldspeed; + int oldduplex; + int oldlink; +} ucc_geth_private_t; + +#endif /* __UCC_GETH_H__ */ diff --git a/drivers/net/ucc_geth_phy.c b/drivers/net/ucc_geth_phy.c new file mode 100644 index 0000000..f91028c --- /dev/null +++ b/drivers/net/ucc_geth_phy.c @@ -0,0 +1,801 @@ +/* + * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved. + * + * Author: Shlomi Gridish + * + * Description: + * UCC GETH Driver -- PHY handling + * + * Changelog: + * Jun 28, 2006 Li Yang + * - Rearrange code and style fixes + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "ucc_geth.h" +#include "ucc_geth_phy.h" +#include + +#define ugphy_printk(level, format, arg...) \ + printk(level format "\n", ## arg) + +#define ugphy_dbg(format, arg...) \ + ugphy_printk(KERN_DEBUG, format , ## arg) +#define ugphy_err(format, arg...) \ + ugphy_printk(KERN_ERR, format , ## arg) +#define ugphy_info(format, arg...) \ + ugphy_printk(KERN_INFO, format , ## arg) +#define ugphy_warn(format, arg...) \ + ugphy_printk(KERN_WARNING, format , ## arg) + +#ifdef UGETH_VERBOSE_DEBUG +#define ugphy_vdbg ugphy_dbg +#else +#define ugphy_vdbg(fmt, args...) do { } while (0) +#endif /* UGETH_VERBOSE_DEBUG */ + +static void config_genmii_advert(struct ugeth_mii_info *mii_info); +static void genmii_setup_forced(struct ugeth_mii_info *mii_info); +static void genmii_restart_aneg(struct ugeth_mii_info *mii_info); +static int gbit_config_aneg(struct ugeth_mii_info *mii_info); +static int genmii_config_aneg(struct ugeth_mii_info *mii_info); +static int genmii_update_link(struct ugeth_mii_info *mii_info); +static int genmii_read_status(struct ugeth_mii_info *mii_info); +u16 phy_read(struct ugeth_mii_info *mii_info, u16 regnum); +void phy_write(struct ugeth_mii_info *mii_info, u16 regnum, u16 val); + +static u8 *bcsr_regs = NULL; + +/* 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) +{ + ucc_geth_private_t *ugeth = netdev_priv(dev); + ucc_mii_mng_t *mii_regs; + enet_tbi_mii_reg_e mii_reg = (enet_tbi_mii_reg_e) regnum; + u32 tmp_reg; + + ugphy_vdbg("%s: IN", __FUNCTION__); + + spin_lock_irq(&ugeth->lock); + + mii_regs = ugeth->mii_info->mii_regs; + + /* Set this UCC to be the master of the MII managment */ + ucc_set_qe_mux_mii_mng(ugeth->ug_info->uf_info.ucc_num); + + /* Stop the MII management read cycle */ + out_be32(&mii_regs->miimcom, 0); + /* Setting up the MII Mangement Address Register */ + tmp_reg = ((u32) mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | mii_reg; + out_be32(&mii_regs->miimadd, tmp_reg); + + /* Setting up the MII Mangement Control Register with the value */ + out_be32(&mii_regs->miimcon, (u32) value); + + /* Wait till MII management write is complete */ + while ((in_be32(&mii_regs->miimind)) & MIIMIND_BUSY) + cpu_relax(); + + spin_unlock_irq(&ugeth->lock); + + udelay(10000); +} + +/* 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) +{ + ucc_geth_private_t *ugeth = netdev_priv(dev); + ucc_mii_mng_t *mii_regs; + enet_tbi_mii_reg_e mii_reg = (enet_tbi_mii_reg_e) regnum; + u32 tmp_reg; + u16 value; + + ugphy_vdbg("%s: IN", __FUNCTION__); + + spin_lock_irq(&ugeth->lock); + + mii_regs = ugeth->mii_info->mii_regs; + + /* Setting up the MII Mangement Address Register */ + tmp_reg = ((u32) mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | mii_reg; + out_be32(&mii_regs->miimadd, tmp_reg); + + /* Perform an MII management read cycle */ + out_be32(&mii_regs->miimcom, MIIMCOM_READ_CYCLE); + + /* Wait till MII management write is complete */ + while ((in_be32(&mii_regs->miimind)) & MIIMIND_BUSY) + cpu_relax(); + + udelay(10000); + + /* Read MII management status */ + value = (u16) in_be32(&mii_regs->miimstat); + out_be32(&mii_regs->miimcom, 0); + if (value == 0xffff) + ugphy_warn("read wrong value : mii_id %d,mii_reg %d, base %08x", + mii_id, mii_reg, (u32) & (mii_regs->miimcfg)); + + spin_unlock_irq(&ugeth->lock); + + return (value); +} + +void mii_clear_phy_interrupt(struct ugeth_mii_info *mii_info) +{ + ugphy_vdbg("%s: IN", __FUNCTION__); + + if (mii_info->phyinfo->ack_interrupt) + mii_info->phyinfo->ack_interrupt(mii_info); +} + +void mii_configure_phy_interrupt(struct ugeth_mii_info *mii_info, + u32 interrupts) +{ + ugphy_vdbg("%s: IN", __FUNCTION__); + + 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 ugeth_mii_info *mii_info) +{ + u32 advertise; + u16 adv; + + ugphy_vdbg("%s: IN", __FUNCTION__); + + /* 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 ugeth_mii_info *mii_info) +{ + u16 ctrl; + u32 features = mii_info->phyinfo->features; + + ugphy_vdbg("%s: IN", __FUNCTION__); + + 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! */ + ugphy_err("%s: Bad speed!", mii_info->dev->name); + break; + } + + phy_write(mii_info, MII_BMCR, ctrl); +} + +/* Enable and Restart Autonegotiation */ +static void genmii_restart_aneg(struct ugeth_mii_info *mii_info) +{ + u16 ctl; + + ugphy_vdbg("%s: IN", __FUNCTION__); + + 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 ugeth_mii_info *mii_info) +{ + u16 adv; + u32 advertise; + + ugphy_vdbg("%s: IN", __FUNCTION__); + + 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 genmii_config_aneg(struct ugeth_mii_info *mii_info) +{ + ugphy_vdbg("%s: IN", __FUNCTION__); + + 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 ugeth_mii_info *mii_info) +{ + u16 status; + + ugphy_vdbg("%s: IN", __FUNCTION__); + + /* 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 ugeth_mii_info *mii_info) +{ + u16 status; + int err; + + ugphy_vdbg("%s: IN", __FUNCTION__); + + /* 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_init(struct ugeth_mii_info *mii_info) +{ + ugphy_vdbg("%s: IN", __FUNCTION__); + + phy_write(mii_info, 0x14, 0x0cd2); + phy_write(mii_info, MII_BMCR, + phy_read(mii_info, MII_BMCR) | BMCR_RESET); + msleep(4000); + + return 0; +} + +static int marvell_config_aneg(struct ugeth_mii_info *mii_info) +{ + ugphy_vdbg("%s: IN", __FUNCTION__); + + /* 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 marvell_read_status(struct ugeth_mii_info *mii_info) +{ + u16 status; + int err; + + ugphy_vdbg("%s: IN", __FUNCTION__); + + /* 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); + + /* 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 marvell_ack_interrupt(struct ugeth_mii_info *mii_info) +{ + ugphy_vdbg("%s: IN", __FUNCTION__); + + /* Clear the interrupts by reading the reg */ + phy_read(mii_info, MII_M1011_IEVENT); + + return 0; +} + +static int marvell_config_intr(struct ugeth_mii_info *mii_info) +{ + ugphy_vdbg("%s: IN", __FUNCTION__); + + 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 ugeth_mii_info *mii_info) +{ + ugphy_vdbg("%s: IN", __FUNCTION__); + + 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_read_status(struct ugeth_mii_info *mii_info) +{ + u16 status; + int err; + + ugphy_vdbg("%s: IN", __FUNCTION__); + + /* 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 cis820x_ack_interrupt(struct ugeth_mii_info *mii_info) +{ + ugphy_vdbg("%s: IN", __FUNCTION__); + + phy_read(mii_info, MII_CIS8201_ISTAT); + + return 0; +} + +static int cis820x_config_intr(struct ugeth_mii_info *mii_info) +{ + ugphy_vdbg("%s: IN", __FUNCTION__); + + 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 ugeth_mii_info *mii_info) +{ + u16 status; + int err; + + ugphy_vdbg("%s: IN", __FUNCTION__); + + /* 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 ugeth_mii_info *mii_info) +{ + struct dm9161_private *priv = mii_info->priv; + + ugphy_vdbg("%s: IN", __FUNCTION__); + + if (0 == priv->resetdone) + return -EAGAIN; + + return 0; +} + +static void dm9161_timer(unsigned long data) +{ + struct ugeth_mii_info *mii_info = (struct ugeth_mii_info *)data; + struct dm9161_private *priv = mii_info->priv; + u16 status = phy_read(mii_info, MII_BMSR); + + ugphy_vdbg("%s: IN", __FUNCTION__); + + if (status & BMSR_ANEGCOMPLETE) { + priv->resetdone = 1; + } else + mod_timer(&priv->timer, jiffies + DM9161_DELAY * HZ); +} + +static int dm9161_init(struct ugeth_mii_info *mii_info) +{ + struct dm9161_private *priv; + + ugphy_vdbg("%s: IN", __FUNCTION__); + + /* 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; + + phy_write(mii_info, MII_BMCR, + phy_read(mii_info, MII_BMCR) | BMCR_RESET); + + phy_write(mii_info, MII_BMCR, + phy_read(mii_info, MII_BMCR) & ~BMCR_ISOLATE); + + config_genmii_advert(mii_info); + /* Start/Restart aneg */ + genmii_config_aneg(mii_info); + + /* 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 ugeth_mii_info *mii_info) +{ + struct dm9161_private *priv = mii_info->priv; + + ugphy_vdbg("%s: IN", __FUNCTION__); + + del_timer_sync(&priv->timer); + kfree(priv); +} + +static int dm9161_ack_interrupt(struct ugeth_mii_info *mii_info) +{ +/* FIXME: This lines are for BUG fixing in the mpc8325. +Remove this from here when it's fixed */ + if (bcsr_regs == NULL) + bcsr_regs = (u8 *) ioremap(BCSR_PHYS_ADDR, BCSR_SIZE); + bcsr_regs[14] |= 0x40; + ugphy_vdbg("%s: IN", __FUNCTION__); + + /* Clear the interrupts by reading the reg */ + phy_read(mii_info, MII_DM9161_INTR); + + + return 0; +} + +static int dm9161_config_intr(struct ugeth_mii_info *mii_info) +{ +/* FIXME: This lines are for BUG fixing in the mpc8325. +Remove this from here when it's fixed */ + if (bcsr_regs == NULL) { + bcsr_regs = (u8 *) ioremap(BCSR_PHYS_ADDR, BCSR_SIZE); + bcsr_regs[14] &= ~0x40; + } + ugphy_vdbg("%s: IN", __FUNCTION__); + + if (mii_info->interrupts == MII_INTERRUPT_ENABLED) + phy_write(mii_info, MII_DM9161_INTR, MII_DM9161_INTR_INIT); + else + phy_write(mii_info, MII_DM9161_INTR, MII_DM9161_INTR_STOP); + + return 0; +} + +/* Cicada 820x */ +static struct phy_info phy_info_cis820x = { + .phy_id = 0x000fc440, + .name = "Cicada Cis8204", + .phy_id_mask = 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, + .phy_id_mask = 0x0ffffff0, + .name = "Davicom DM9161E", + .init = dm9161_init, + .config_aneg = dm9161_config_aneg, + .read_status = dm9161_read_status, + .close = dm9161_close, +}; + +static struct phy_info phy_info_dm9161a = { + .phy_id = 0x0181b8a0, + .phy_id_mask = 0x0ffffff0, + .name = "Davicom DM9161A", + .features = MII_BASIC_FEATURES, + .init = dm9161_init, + .config_aneg = dm9161_config_aneg, + .read_status = dm9161_read_status, + .ack_interrupt = dm9161_ack_interrupt, + .config_intr = dm9161_config_intr, + .close = dm9161_close, +}; + +static struct phy_info phy_info_marvell = { + .phy_id = 0x01410c00, + .phy_id_mask = 0xffffff00, + .name = "Marvell 88E11x1", + .features = MII_GBIT_FEATURES, + .init = &marvell_init, + .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_dm9161a, + &phy_info_genmii, + NULL +}; + +u16 phy_read(struct ugeth_mii_info *mii_info, u16 regnum) +{ + u16 retval; + unsigned long flags; + + ugphy_vdbg("%s: IN", __FUNCTION__); + + 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 ugeth_mii_info *mii_info, u16 regnum, u16 val) +{ + unsigned long flags; + + ugphy_vdbg("%s: IN", __FUNCTION__); + + 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 ugeth_mii_info *mii_info) +{ + u16 phy_reg; + u32 phy_ID; + int i; + struct phy_info *theInfo = NULL; + struct net_device *dev = mii_info->dev; + + ugphy_vdbg("%s: IN", __FUNCTION__); + + /* 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) { + ugphy_info("%s: PHY id %x is not supported!", dev->name, + phy_ID); + return NULL; + } else { + ugphy_info("%s: PHY is %s (%x)", dev->name, theInfo->name, + phy_ID); + } + + return theInfo; +} diff --git a/drivers/net/ucc_geth_phy.h b/drivers/net/ucc_geth_phy.h new file mode 100644 index 0000000..2f98b8f --- /dev/null +++ b/drivers/net/ucc_geth_phy.h @@ -0,0 +1,217 @@ +/* + * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved. + * + * Author: Shlomi Gridish + * + * Description: + * UCC GETH Driver -- PHY handling + * + * Changelog: + * Jun 28, 2006 Li Yang + * - Rearrange code and style fixes + * + * 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 __UCC_GETH_PHY_H__ +#define __UCC_GETH_PHY_H__ + +#define MII_end ((u32)-2) +#define MII_read ((u32)-1) + +#define MIIMIND_BUSY 0x00000001 +#define MIIMIND_NOTVALID 0x00000004 + +#define UGETH_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 ugeth_mii_info { + /* Information about the PHY type */ + /* And management functions */ + struct phy_info *phyinfo; + + ucc_mii_mng_t *mii_regs; + + /* 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 ugeth_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 ugeth_mii_info * mii_info); + + /* Called to suspend the PHY for power */ + int (*suspend) (struct ugeth_mii_info * mii_info); + + /* Reconfigures autonegotiation (or disables it) */ + int (*config_aneg) (struct ugeth_mii_info * mii_info); + + /* Determines the negotiated speed and duplex */ + int (*read_status) (struct ugeth_mii_info * mii_info); + + /* Clears any pending interrupts */ + int (*ack_interrupt) (struct ugeth_mii_info * mii_info); + + /* Enables or disables interrupts */ + int (*config_intr) (struct ugeth_mii_info * mii_info); + + /* Clears up any memory if needed */ + void (*close) (struct ugeth_mii_info * mii_info); +}; + +struct phy_info *get_phy_info(struct ugeth_mii_info *mii_info); +void write_phy_reg(struct net_device *dev, int mii_id, int regnum, int value); +int read_phy_reg(struct net_device *dev, int mii_id, int regnum); +void mii_clear_phy_interrupt(struct ugeth_mii_info *mii_info); +void mii_configure_phy_interrupt(struct ugeth_mii_info *mii_info, + u32 interrupts); + +struct dm9161_private { + struct timer_list timer; + int resetdone; +}; + +#endif /* __UCC_GETH_PHY_H__ */ -- cgit v1.1 From 6fd7587bc284af61f92e547287aa5cd616a9c7ba Mon Sep 17 00:00:00 2001 From: Deepak Saxena Date: Mon, 14 Aug 2006 23:00:13 -0700 Subject: [PATCH] Update smc91x driver with ARM Versatile board info We need to specify a Versatile-specific SMC_IRQ_FLAGS value or the new generic IRQ layer will complain thusly: No IRQF_TRIGGER set_type function for IRQ 25 () Signed-off-by: Deepak Saxena Cc: Jeff Garzik Cc: Russell King Cc: Nicolas Pitre Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/smc91x.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'drivers') diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h index 9f9f8f2..95ac2dd 100644 --- a/drivers/net/smc91x.h +++ b/drivers/net/smc91x.h @@ -367,6 +367,24 @@ static inline void LPD7_SMC_outsw (unsigned char* a, int r, #define SMC_IRQ_FLAGS (0) +#elif defined(CONFIG_ARCH_VERSATILE) + +#define SMC_CAN_USE_8BIT 1 +#define SMC_CAN_USE_16BIT 1 +#define SMC_CAN_USE_32BIT 1 +#define SMC_NOWAIT 1 + +#define SMC_inb(a, r) readb((a) + (r)) +#define SMC_inw(a, r) readw((a) + (r)) +#define SMC_inl(a, r) readl((a) + (r)) +#define SMC_outb(v, a, r) writeb(v, (a) + (r)) +#define SMC_outw(v, a, r) writew(v, (a) + (r)) +#define SMC_outl(v, a, r) writel(v, (a) + (r)) +#define SMC_insl(a, r, p, l) readsl((a) + (r), p, l) +#define SMC_outsl(a, r, p, l) writesl((a) + (r), p, l) + +#define SMC_IRQ_FLAGS (0) + #else #define SMC_CAN_USE_8BIT 1 -- cgit v1.1 From 330ce0de93fd7cc0f72fa57a7ec892befe7035d2 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 14 Aug 2006 23:00:14 -0700 Subject: [PATCH] s2io build fix sparc32: drivers/net/s2io.c:2636: warning: implicit declaration of function 'disable_irq' drivers/net/s2io.c:2656: warning: implicit declaration of function 'enable_irq' Cc: Ananda Raju Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/s2io.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 132ed32..e72e0e0 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -71,6 +71,7 @@ #include #include #include +#include /* local include */ #include "s2io.h" -- cgit v1.1 From 2fd0e33f4f967022ef2f3249b6c512b309734384 Mon Sep 17 00:00:00 2001 From: Kevin Hao Date: Mon, 14 Aug 2006 23:00:15 -0700 Subject: [PATCH] net: Add netconsole support to dm9000 driver Add netconsole support to dm9000 driver. Cc: Jeff Garzik Cc: Sascha Hauer Cc: Ben Dooks Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/dm9000.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers') diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c index 1b758b7..3d76fa1 100644 --- a/drivers/net/dm9000.c +++ b/drivers/net/dm9000.c @@ -339,6 +339,17 @@ static void dm9000_timeout(struct net_device *dev) spin_unlock_irqrestore(&db->lock,flags); } +#ifdef CONFIG_NET_POLL_CONTROLLER +/* + *Used by netconsole + */ +static void dm9000_poll_controller(struct net_device *dev) +{ + disable_irq(dev->irq); + dm9000_interrupt(dev->irq,dev,NULL); + enable_irq(dev->irq); +} +#endif /* dm9000_release_board * @@ -538,6 +549,9 @@ dm9000_probe(struct platform_device *pdev) ndev->stop = &dm9000_stop; ndev->get_stats = &dm9000_get_stats; ndev->set_multicast_list = &dm9000_hash_table; +#ifdef CONFIG_NET_POLL_CONTROLLER + ndev->poll_controller = &dm9000_poll_controller; +#endif #ifdef DM9000_PROGRAM_EEPROM program_eeprom(db); -- cgit v1.1 From a4d09272480e57cd4aa1156cac7aba9b08885bf9 Mon Sep 17 00:00:00 2001 From: Peter Korsgaard Date: Mon, 14 Aug 2006 23:00:17 -0700 Subject: [PATCH] smc911x: Re-release spinlock on spurious interrupt The smc911x driver forgets to release the spinlock on spurious interrupts. This little patch fixes it. Cc: Jeff Garzik Signed-off-by: Peter Korsgaard Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/smc911x.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index d37bd86..0b15290 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -1092,6 +1092,7 @@ static irqreturn_t smc911x_interrupt(int irq, void *dev_id, struct pt_regs *regs /* Spurious interrupt check */ if ((SMC_GET_IRQ_CFG() & (INT_CFG_IRQ_INT_ | INT_CFG_IRQ_EN_)) != (INT_CFG_IRQ_INT_ | INT_CFG_IRQ_EN_)) { + spin_unlock_irqrestore(&lp->lock, flags); return IRQ_NONE; } -- cgit v1.1 From 633949a145df19d6d338b0f227f033a0a1c5562a Mon Sep 17 00:00:00 2001 From: Roger Luethi Date: Mon, 14 Aug 2006 23:00:17 -0700 Subject: [PATCH] via-rhine: NAPI support Add NAPI support to the via-rhine driver so that it can handle higher speeds and doesn't get overloaded by interrupts as easily. Signed-off-by: Stephen Hemminger Signed-off-by: Roger Luethi Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/Kconfig | 14 +++++++++ drivers/net/via-rhine.c | 77 +++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 79 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index ea1796e..30b3671 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -1724,6 +1724,20 @@ config VIA_RHINE_MMIO If unsure, say Y. +config VIA_RHINE_NAPI + bool "Use Rx Polling (NAPI)" + depends on VIA_RHINE + help + NAPI is a new driver API designed to reduce CPU and interrupt load + when the driver is receiving lots of packets from the card. + + If your estimated Rx load is 10kpps or more, or if the card will be + deployed on potentially unfriendly networks (e.g. in a firewall), + then say Y here. + + See for more + information. + config LAN_SAA9730 bool "Philips SAA9730 Ethernet support (EXPERIMENTAL)" depends on NET_PCI && EXPERIMENTAL && MIPS diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index d3d0ec9..fee8240 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -30,8 +30,8 @@ */ #define DRV_NAME "via-rhine" -#define DRV_VERSION "1.4.0" -#define DRV_RELDATE "June-27-2006" +#define DRV_VERSION "1.4.1" +#define DRV_RELDATE "July-24-2006" /* A few user-configurable values. @@ -63,7 +63,11 @@ static const int multicast_filter_limit = 32; There are no ill effects from too-large receive rings. */ #define TX_RING_SIZE 16 #define TX_QUEUE_LEN 10 /* Limit ring entries actually used. */ +#ifdef CONFIG_VIA_RHINE_NAPI +#define RX_RING_SIZE 64 +#else #define RX_RING_SIZE 16 +#endif /* Operational parameters that usually are not changed. */ @@ -396,7 +400,7 @@ static void rhine_tx_timeout(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); -static void rhine_rx(struct net_device *dev); +static int rhine_rx(struct net_device *dev, int limit); static void rhine_error(struct net_device *dev, int intr_status); static void rhine_set_rx_mode(struct net_device *dev); static struct net_device_stats *rhine_get_stats(struct net_device *dev); @@ -564,6 +568,32 @@ static void rhine_poll(struct net_device *dev) } #endif +#ifdef CONFIG_VIA_RHINE_NAPI +static int rhine_napipoll(struct net_device *dev, int *budget) +{ + struct rhine_private *rp = netdev_priv(dev); + void __iomem *ioaddr = rp->base; + int done, limit = min(dev->quota, *budget); + + done = rhine_rx(dev, limit); + *budget -= done; + dev->quota -= done; + + if (done < limit) { + netif_rx_complete(dev); + + iowrite16(IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow | + IntrRxDropped | IntrRxNoBuf | IntrTxAborted | + IntrTxDone | IntrTxError | IntrTxUnderrun | + IntrPCIErr | IntrStatsMax | IntrLinkChange, + ioaddr + IntrEnable); + return 0; + } + else + return 1; +} +#endif + static void rhine_hw_init(struct net_device *dev, long pioaddr) { struct rhine_private *rp = netdev_priv(dev); @@ -744,6 +774,10 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = rhine_poll; #endif +#ifdef CONFIG_VIA_RHINE_NAPI + dev->poll = rhine_napipoll; + dev->weight = 64; +#endif if (rp->quirks & rqRhineI) dev->features |= NETIF_F_SG|NETIF_F_HW_CSUM; @@ -1165,6 +1199,7 @@ static void rhine_tx_timeout(struct net_device *dev) dev->trans_start = jiffies; rp->stats.tx_errors++; netif_wake_queue(dev); + netif_poll_enable(dev); } static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev) @@ -1268,8 +1303,18 @@ static irqreturn_t rhine_interrupt(int irq, void *dev_instance, struct pt_regs * dev->name, intr_status); if (intr_status & (IntrRxDone | IntrRxErr | IntrRxDropped | - IntrRxWakeUp | IntrRxEmpty | IntrRxNoBuf)) - rhine_rx(dev); + IntrRxWakeUp | IntrRxEmpty | IntrRxNoBuf)) { +#ifdef CONFIG_VIA_RHINE_NAPI + iowrite16(IntrTxAborted | + IntrTxDone | IntrTxError | IntrTxUnderrun | + IntrPCIErr | IntrStatsMax | IntrLinkChange, + ioaddr + IntrEnable); + + netif_rx_schedule(dev); +#else + rhine_rx(dev, RX_RING_SIZE); +#endif + } if (intr_status & (IntrTxErrSummary | IntrTxDone)) { if (intr_status & IntrTxErrSummary) { @@ -1367,13 +1412,12 @@ static void rhine_tx(struct net_device *dev) spin_unlock(&rp->lock); } -/* This routine is logically part of the interrupt handler, but isolated - for clarity and better register allocation. */ -static void rhine_rx(struct net_device *dev) +/* Process up to limit frames from receive ring */ +static int rhine_rx(struct net_device *dev, int limit) { struct rhine_private *rp = netdev_priv(dev); + int count; int entry = rp->cur_rx % RX_RING_SIZE; - int boguscnt = rp->dirty_rx + RX_RING_SIZE - rp->cur_rx; if (debug > 4) { printk(KERN_DEBUG "%s: rhine_rx(), entry %d status %8.8x.\n", @@ -1382,16 +1426,18 @@ static void rhine_rx(struct net_device *dev) } /* If EOP is set on the next entry, it's a new packet. Send it up. */ - while (!(rp->rx_head_desc->rx_status & cpu_to_le32(DescOwn))) { + for (count = 0; count < limit; ++count) { struct rx_desc *desc = rp->rx_head_desc; u32 desc_status = le32_to_cpu(desc->rx_status); int data_size = desc_status >> 16; + if (desc_status & DescOwn) + break; + if (debug > 4) printk(KERN_DEBUG "rhine_rx() status is %8.8x.\n", desc_status); - if (--boguscnt < 0) - break; + if ((desc_status & (RxWholePkt | RxErr)) != RxWholePkt) { if ((desc_status & RxWholePkt) != RxWholePkt) { printk(KERN_WARNING "%s: Oversized Ethernet " @@ -1460,7 +1506,11 @@ static void rhine_rx(struct net_device *dev) PCI_DMA_FROMDEVICE); } skb->protocol = eth_type_trans(skb, dev); +#ifdef CONFIG_VIA_RHINE_NAPI + netif_receive_skb(skb); +#else netif_rx(skb); +#endif dev->last_rx = jiffies; rp->stats.rx_bytes += pkt_len; rp->stats.rx_packets++; @@ -1487,6 +1537,8 @@ static void rhine_rx(struct net_device *dev) } rp->rx_ring[entry].rx_status = cpu_to_le32(DescOwn); } + + return count; } /* @@ -1776,6 +1828,7 @@ static int rhine_close(struct net_device *dev) spin_lock_irq(&rp->lock); netif_stop_queue(dev); + netif_poll_disable(dev); if (debug > 1) printk(KERN_DEBUG "%s: Shutting down ethercard, " -- cgit v1.1 From ab1976682f31661a898b92593bccfeae14d0a0ae Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 14 Aug 2006 23:00:18 -0700 Subject: [PATCH] via-rhine: NAPI poll enable The poll_enable should be in init_registers before enabling interrupts, not in tx_timeout. Thanks for spotting it Roger. Signed-off-by: Stephen Hemminger Cc: Roger Luethi Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/via-rhine.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index fee8240..fda367b 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -1048,6 +1048,8 @@ static void init_registers(struct net_device *dev) rhine_set_rx_mode(dev); + netif_poll_enable(dev); + /* Enable interrupts by setting the interrupt mask. */ iowrite16(IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow | IntrRxDropped | IntrRxNoBuf | IntrTxAborted | @@ -1199,7 +1201,6 @@ static void rhine_tx_timeout(struct net_device *dev) dev->trans_start = jiffies; rp->stats.tx_errors++; netif_wake_queue(dev); - netif_poll_enable(dev); } static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev) -- cgit v1.1 From 76cb4fe7c0926c2c59f4a36ab169aa2d547c93d1 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 14 Aug 2006 23:00:20 -0700 Subject: [PATCH] lockdep: fix smc91x When booting using root-nfs, I'm seeing (independently) two lockdep dumps in the smc91x driver. The patch below fixes both. Both dumps look like real locking issues. Nico - please review and ack if you think the patch is correct. Dump 1: Sending DHCP requests . ================================= [ INFO: inconsistent lock state ] Signed-off-by: Jeff Garzik --- drivers/net/smc91x.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c index 3d8dcb6..cf62373 100644 --- a/drivers/net/smc91x.c +++ b/drivers/net/smc91x.c @@ -321,12 +321,12 @@ static void smc_reset(struct net_device *dev) DBG(2, "%s: %s\n", dev->name, __FUNCTION__); /* Disable all interrupts, block TX tasklet */ - spin_lock(&lp->lock); + spin_lock_irq(&lp->lock); SMC_SELECT_BANK(2); SMC_SET_INT_MASK(0); pending_skb = lp->pending_tx_skb; lp->pending_tx_skb = NULL; - spin_unlock(&lp->lock); + spin_unlock_irq(&lp->lock); /* free any pending tx skb */ if (pending_skb) { @@ -448,12 +448,12 @@ static void smc_shutdown(struct net_device *dev) DBG(2, "%s: %s\n", CARDNAME, __FUNCTION__); /* no more interrupts for me */ - spin_lock(&lp->lock); + spin_lock_irq(&lp->lock); SMC_SELECT_BANK(2); SMC_SET_INT_MASK(0); pending_skb = lp->pending_tx_skb; lp->pending_tx_skb = NULL; - spin_unlock(&lp->lock); + spin_unlock_irq(&lp->lock); if (pending_skb) dev_kfree_skb(pending_skb); -- cgit v1.1 From b933b4d93888b584eda826bffa68a3a1283f8411 Mon Sep 17 00:00:00 2001 From: Roger Luethi Date: Mon, 14 Aug 2006 23:00:21 -0700 Subject: [PATCH] via-rhine: add option avoid_D3 (work around broken BIOSes) It looks like broken BIOSes controlling Rhine chips will remain in use in significant numbers; such systems fail to come up via PXE after they have been put into D3 (power-saving) mode. This patch adds a module option for disabling the call that puts the chip to sleep. Signed-off-by: Roger Luethi Cc: Jeff Garzik Cc: Joerg Bashir Cc: Tim Phipps Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/via-rhine.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index fda367b..ae97108 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -44,6 +44,10 @@ static int max_interrupt_work = 20; Setting to > 1518 effectively disables this feature. */ static int rx_copybreak; +/* Work-around for broken BIOSes: they are unable to get the chip back out of + power state D3 so PXE booting fails. bootparam(7): via-rhine.avoid_D3=1 */ +static int avoid_D3; + /* * In case you are looking for 'options[]' or 'full_duplex[]', they * are gone. Use ethtool(8) instead. @@ -120,9 +124,11 @@ MODULE_LICENSE("GPL"); module_param(max_interrupt_work, int, 0); module_param(debug, int, 0); module_param(rx_copybreak, int, 0); +module_param(avoid_D3, bool, 0); MODULE_PARM_DESC(max_interrupt_work, "VIA Rhine maximum events handled per interrupt"); MODULE_PARM_DESC(debug, "VIA Rhine debug level (0-7)"); MODULE_PARM_DESC(rx_copybreak, "VIA Rhine copy breakpoint for copy-only-tiny-frames"); +MODULE_PARM_DESC(avoid_D3, "Avoid power state D3 (work-around for broken BIOSes)"); /* Theory of Operation @@ -823,6 +829,9 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, } } rp->mii_if.phy_id = phy_id; + if (debug > 1 && avoid_D3) + printk(KERN_INFO "%s: No D3 power state at shutdown.\n", + dev->name); return 0; @@ -1911,7 +1920,8 @@ static void rhine_shutdown (struct pci_dev *pdev) } /* Hit power state D3 (sleep) */ - iowrite8(ioread8(ioaddr + StickyHW) | 0x03, ioaddr + StickyHW); + if (!avoid_D3) + iowrite8(ioread8(ioaddr + StickyHW) | 0x03, ioaddr + StickyHW); /* TODO: Check use of pci_enable_wake() */ -- cgit v1.1 From 7e29f8bf39de372e3903a0b12f34285d30a8a244 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Mon, 14 Aug 2006 23:00:22 -0700 Subject: [PATCH] build fixes: smc91x Unclear how these bugs arrived, presumably from incorrect cleanup of the 16-bit-only paths, but smc91x wouldn't build for OMAP. Signed-off-by: David Brownell Cc: Nicolas Pitre Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/smc91x.h | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h index 95ac2dd..7aa7fba 100644 --- a/drivers/net/smc91x.h +++ b/drivers/net/smc91x.h @@ -184,16 +184,10 @@ SMC_outw(u16 val, void __iomem *ioaddr, int reg) #define SMC_IO_SHIFT 0 #define SMC_NOWAIT 1 -#define SMC_inb(a, r) readb((a) + (r)) -#define SMC_outb(v, a, r) writeb(v, (a) + (r)) #define SMC_inw(a, r) readw((a) + (r)) #define SMC_outw(v, a, r) writew(v, (a) + (r)) #define SMC_insw(a, r, p, l) readsw((a) + (r), p, l) #define SMC_outsw(a, r, p, l) writesw((a) + (r), p, l) -#define SMC_inl(a, r) readl((a) + (r)) -#define SMC_outl(v, a, r) writel(v, (a) + (r)) -#define SMC_insl(a, r, p, l) readsl((a) + (r), p, l) -#define SMC_outsl(a, r, p, l) writesl((a) + (r), p, l) #include #include -- cgit v1.1 From b68a60e598c0d1e738c807c47cb181e8cc52a0d8 Mon Sep 17 00:00:00 2001 From: Jim Lewis Date: Mon, 14 Aug 2006 23:00:23 -0700 Subject: [PATCH] Add ethtool -g support to Spidernet network driver Add ethtool -g (show ring sizes) support to the Spidernet network driver. Signed-off-by: James K Lewis Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/spider_net.c | 12 +++++++----- drivers/net/spider_net.h | 3 +++ drivers/net/spider_net_ethtool.c | 13 +++++++++++++ 3 files changed, 23 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index 647f62e..8890721 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -1611,13 +1611,12 @@ spider_net_open(struct net_device *netdev) int result; result = -ENOMEM; - if (spider_net_init_chain(card, &card->tx_chain, - card->descr, - PCI_DMA_TODEVICE, tx_descriptors)) + if (spider_net_init_chain(card, &card->tx_chain, card->descr, + PCI_DMA_TODEVICE, card->tx_desc)) goto alloc_tx_failed; if (spider_net_init_chain(card, &card->rx_chain, - card->descr + tx_descriptors, - PCI_DMA_FROMDEVICE, rx_descriptors)) + card->descr + card->rx_desc, + PCI_DMA_FROMDEVICE, card->rx_desc)) goto alloc_rx_failed; /* allocate rx skbs */ @@ -2005,6 +2004,9 @@ spider_net_setup_netdev(struct spider_net_card *card) card->options.rx_csum = SPIDER_NET_RX_CSUM_DEFAULT; + card->tx_desc = tx_descriptors; + card->rx_desc = rx_descriptors; + spider_net_setup_netdev_ops(netdev); netdev->features = NETIF_F_HW_CSUM | NETIF_F_LLTX; diff --git a/drivers/net/spider_net.h b/drivers/net/spider_net.h index f6dcf18..30407cd 100644 --- a/drivers/net/spider_net.h +++ b/drivers/net/spider_net.h @@ -440,6 +440,9 @@ struct spider_net_card { /* for ethtool */ int msg_enable; + int rx_desc; + int tx_desc; + struct spider_net_descr descr[0]; }; diff --git a/drivers/net/spider_net_ethtool.c b/drivers/net/spider_net_ethtool.c index a5bb0b76..0220922 100644 --- a/drivers/net/spider_net_ethtool.c +++ b/drivers/net/spider_net_ethtool.c @@ -130,6 +130,18 @@ spider_net_ethtool_set_tx_csum(struct net_device *netdev, uint32_t data) return 0; } +static void +spider_net_ethtool_get_ringparam(struct net_device *netdev, + struct ethtool_ringparam *ering) +{ + struct spider_net_card *card = netdev->priv; + + ering->tx_max_pending = SPIDER_NET_TX_DESCRIPTORS_MAX; + ering->tx_pending = card->tx_desc; + ering->rx_max_pending = SPIDER_NET_RX_DESCRIPTORS_MAX; + ering->rx_pending = card->rx_desc; +} + struct ethtool_ops spider_net_ethtool_ops = { .get_settings = spider_net_ethtool_get_settings, .get_drvinfo = spider_net_ethtool_get_drvinfo, @@ -141,5 +153,6 @@ struct ethtool_ops spider_net_ethtool_ops = { .set_rx_csum = spider_net_ethtool_set_rx_csum, .get_tx_csum = spider_net_ethtool_get_tx_csum, .set_tx_csum = spider_net_ethtool_set_tx_csum, + .get_ringparam = spider_net_ethtool_get_ringparam, }; -- cgit v1.1 From 239e44e1f05e2163ee066c07a753f9fb445979b2 Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Mon, 14 Aug 2006 23:00:24 -0700 Subject: [PATCH] skge: remember to run netif_poll_disable() Signed-off-by: Edgar E. Iglesias Cc: Stephen Hemminger Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/skge.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/skge.c b/drivers/net/skge.c index 7de9a07..ad878df 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -2211,6 +2211,7 @@ static int skge_up(struct net_device *dev) skge_write8(hw, Q_ADDR(rxqaddr[port], Q_CSR), CSR_START | CSR_IRQ_CL_F); skge_led(skge, LED_MODE_ON); + netif_poll_enable(dev); return 0; free_rx_ring: @@ -2279,6 +2280,7 @@ static int skge_down(struct net_device *dev) skge_led(skge, LED_MODE_OFF); + netif_poll_disable(dev); skge_tx_clean(skge); skge_rx_clean(skge); -- cgit v1.1 From 3d8f3f3c3697a7603a802427c9226f5dfe6d67ad Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 14 Aug 2006 23:00:27 -0700 Subject: [PATCH] s390: fix arp_tbl lock usage in qeth qeth: bhs must be disabled when accessing neighbour tables. ================================= [ INFO: inconsistent lock state ] Signed-off-by: Jeff Garzik --- drivers/s390/net/qeth_main.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c index 5fff1f9..e1327b8 100644 --- a/drivers/s390/net/qeth_main.c +++ b/drivers/s390/net/qeth_main.c @@ -8510,9 +8510,9 @@ static int qeth_ipv6_init(void) { qeth_old_arp_constructor = arp_tbl.constructor; - write_lock(&arp_tbl.lock); + write_lock_bh(&arp_tbl.lock); arp_tbl.constructor = qeth_arp_constructor; - write_unlock(&arp_tbl.lock); + write_unlock_bh(&arp_tbl.lock); arp_direct_ops = (struct neigh_ops*) kmalloc(sizeof(struct neigh_ops), GFP_KERNEL); @@ -8528,9 +8528,9 @@ qeth_ipv6_init(void) static void qeth_ipv6_uninit(void) { - write_lock(&arp_tbl.lock); + write_lock_bh(&arp_tbl.lock); arp_tbl.constructor = qeth_old_arp_constructor; - write_unlock(&arp_tbl.lock); + write_unlock_bh(&arp_tbl.lock); kfree(arp_direct_ops); } #endif /* CONFIG_QETH_IPV6 */ -- cgit v1.1 From ec42cdb624059bb9d9d1accca5ed4345bf8f5fda Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Mon, 14 Aug 2006 23:00:28 -0700 Subject: [PATCH] xircom_cb: wire up errors from pci_register_driver() Signed-off-by: Alexey Dobriyan Cc: Jeff Garzik Cc: Dominik Brodowski Cc: Valerie Henson Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/tulip/xircom_cb.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tulip/xircom_cb.c b/drivers/net/tulip/xircom_cb.c index f874e4f..cf43390 100644 --- a/drivers/net/tulip/xircom_cb.c +++ b/drivers/net/tulip/xircom_cb.c @@ -1264,8 +1264,7 @@ static void investigate_write_descriptor(struct net_device *dev, struct xircom_p static int __init xircom_init(void) { - pci_register_driver(&xircom_ops); - return 0; + return pci_register_driver(&xircom_ops); } static void __exit xircom_exit(void) -- cgit v1.1 From 11b0bacd717c285c94dbb56505a28434b34f0639 Mon Sep 17 00:00:00 2001 From: Vitaly Bordug Date: Mon, 14 Aug 2006 23:00:29 -0700 Subject: [PATCH] PAL: Support of the fixed PHY This makes it possible for HW PHY-less boards to utilize PAL goodies. Generic routines to connect to fixed PHY are provided, as well as ability to specify software callback that fills up link, speed, etc. information into PHY descriptor (the latter feature not tested so far). Signed-off-by: Vitaly Bordug Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/phy/Kconfig | 17 ++ drivers/net/phy/Makefile | 1 + drivers/net/phy/fixed.c | 358 +++++++++++++++++++++++++++++++++++++++++++ drivers/net/phy/mdio_bus.c | 1 + drivers/net/phy/phy_device.c | 51 +++--- 5 files changed, 407 insertions(+), 21 deletions(-) create mode 100644 drivers/net/phy/fixed.c (limited to 'drivers') diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 2ba6d3a..b79ec0d 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -56,5 +56,22 @@ config SMSC_PHY ---help--- Currently supports the LAN83C185 PHY +config FIXED_PHY + tristate "Drivers for PHY emulation on fixed speed/link" + depends on PHYLIB + ---help--- + Adds the driver to PHY layer to cover the boards that do not have any PHY bound, + but with the ability to manipulate with speed/link in software. The relavant MII + speed/duplex parameters could be effectively handled in user-specified fuction. + Currently tested with mpc866ads. + +config FIXED_MII_10_FDX + bool "Emulation for 10M Fdx fixed PHY behavior" + depends on FIXED_PHY + +config FIXED_MII_100_FDX + bool "Emulation for 100M Fdx fixed PHY behavior" + depends on FIXED_PHY + endmenu diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index a00e619..320f832 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -10,3 +10,4 @@ obj-$(CONFIG_LXT_PHY) += lxt.o obj-$(CONFIG_QSEMI_PHY) += qsemi.o obj-$(CONFIG_SMSC_PHY) += smsc.o obj-$(CONFIG_VITESSE_PHY) += vitesse.o +obj-$(CONFIG_FIXED_PHY) += fixed.o diff --git a/drivers/net/phy/fixed.c b/drivers/net/phy/fixed.c new file mode 100644 index 0000000..341036d --- /dev/null +++ b/drivers/net/phy/fixed.c @@ -0,0 +1,358 @@ +/* + * drivers/net/phy/fixed.c + * + * Driver for fixed PHYs, when transceiver is able to operate in one fixed mode. + * + * Author: Vitaly Bordug + * + * Copyright (c) 2006 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define MII_REGS_NUM 7 + +/* + The idea is to emulate normal phy behavior by responding with + pre-defined values to mii BMCR read, so that read_status hook could + take all the needed info. +*/ + +struct fixed_phy_status { + u8 link; + u16 speed; + u8 duplex; +}; + +/*----------------------------------------------------------------------------- + * Private information hoder for mii_bus + *-----------------------------------------------------------------------------*/ +struct fixed_info { + u16 *regs; + u8 regs_num; + struct fixed_phy_status phy_status; + struct phy_device *phydev; /* pointer to the container */ + /* link & speed cb */ + int(*link_update)(struct net_device*, struct fixed_phy_status*); + +}; + +/*----------------------------------------------------------------------------- + * If something weird is required to be done with link/speed, + * network driver is able to assign a function to implement this. + * May be useful for PHY's that need to be software-driven. + *-----------------------------------------------------------------------------*/ +int fixed_mdio_set_link_update(struct phy_device* phydev, + int(*link_update)(struct net_device*, struct fixed_phy_status*)) +{ + struct fixed_info *fixed; + + if(link_update == NULL) + return -EINVAL; + + if(phydev) { + if(phydev->bus) { + fixed = phydev->bus->priv; + fixed->link_update = link_update; + return 0; + } + } + return -EINVAL; +} +EXPORT_SYMBOL(fixed_mdio_set_link_update); + +/*----------------------------------------------------------------------------- + * This is used for updating internal mii regs from the status + *-----------------------------------------------------------------------------*/ +static int fixed_mdio_update_regs(struct fixed_info *fixed) +{ + u16 *regs = fixed->regs; + u16 bmsr = 0; + u16 bmcr = 0; + + if(!regs) { + printk(KERN_ERR "%s: regs not set up", __FUNCTION__); + return -EINVAL; + } + + if(fixed->phy_status.link) + bmsr |= BMSR_LSTATUS; + + if(fixed->phy_status.duplex) { + bmcr |= BMCR_FULLDPLX; + + switch ( fixed->phy_status.speed ) { + case 100: + bmsr |= BMSR_100FULL; + bmcr |= BMCR_SPEED100; + break; + + case 10: + bmsr |= BMSR_10FULL; + break; + } + } else { + switch ( fixed->phy_status.speed ) { + case 100: + bmsr |= BMSR_100HALF; + bmcr |= BMCR_SPEED100; + break; + + case 10: + bmsr |= BMSR_100HALF; + break; + } + } + + regs[MII_BMCR] = bmcr; + regs[MII_BMSR] = bmsr | 0x800; /*we are always capable of 10 hdx*/ + + return 0; +} + +static int fixed_mii_read(struct mii_bus *bus, int phy_id, int location) +{ + struct fixed_info *fixed = bus->priv; + + /* if user has registered link update callback, use it */ + if(fixed->phydev) + if(fixed->phydev->attached_dev) { + if(fixed->link_update) { + fixed->link_update(fixed->phydev->attached_dev, + &fixed->phy_status); + fixed_mdio_update_regs(fixed); + } + } + + if ((unsigned int)location >= fixed->regs_num) + return -1; + return fixed->regs[location]; +} + +static int fixed_mii_write(struct mii_bus *bus, int phy_id, int location, u16 val) +{ + /* do nothing for now*/ + return 0; +} + +static int fixed_mii_reset(struct mii_bus *bus) +{ + /*nothing here - no way/need to reset it*/ + return 0; +} + +static int fixed_config_aneg(struct phy_device *phydev) +{ + /* :TODO:03/13/2006 09:45:37 PM:: + The full autoneg funcionality can be emulated, + but no need to have anything here for now + */ + return 0; +} + +/*----------------------------------------------------------------------------- + * the manual bind will do the magic - with phy_id_mask == 0 + * match will never return true... + *-----------------------------------------------------------------------------*/ +static struct phy_driver fixed_mdio_driver = { + .name = "Fixed PHY", + .features = PHY_BASIC_FEATURES, + .config_aneg = fixed_config_aneg, + .read_status = genphy_read_status, + .driver = { .owner = THIS_MODULE,}, +}; + +/*----------------------------------------------------------------------------- + * This func is used to create all the necessary stuff, bind + * the fixed phy driver and register all it on the mdio_bus_type. + * speed is either 10 or 100, duplex is boolean. + * number is used to create multiple fixed PHYs, so that several devices can + * utilize them simultaneously. + *-----------------------------------------------------------------------------*/ +static int fixed_mdio_register_device(int number, int speed, int duplex) +{ + struct mii_bus *new_bus; + struct fixed_info *fixed; + struct phy_device *phydev; + int err = 0; + + struct device* dev = kzalloc(sizeof(struct device), GFP_KERNEL); + + if (NULL == dev) + return -ENOMEM; + + new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL); + + if (NULL == new_bus) { + kfree(dev); + return -ENOMEM; + } + fixed = kzalloc(sizeof(struct fixed_info), GFP_KERNEL); + + if (NULL == fixed) { + kfree(dev); + kfree(new_bus); + return -ENOMEM; + } + + fixed->regs = kzalloc(MII_REGS_NUM*sizeof(int), GFP_KERNEL); + fixed->regs_num = MII_REGS_NUM; + fixed->phy_status.speed = speed; + fixed->phy_status.duplex = duplex; + fixed->phy_status.link = 1; + + new_bus->name = "Fixed MII Bus", + new_bus->read = &fixed_mii_read, + new_bus->write = &fixed_mii_write, + new_bus->reset = &fixed_mii_reset, + + /*set up workspace*/ + fixed_mdio_update_regs(fixed); + new_bus->priv = fixed; + + new_bus->dev = dev; + dev_set_drvdata(dev, new_bus); + + /* create phy_device and register it on the mdio bus */ + phydev = phy_device_create(new_bus, 0, 0); + + /* + Put the phydev pointer into the fixed pack so that bus read/write code could + be able to access for instance attached netdev. Well it doesn't have to do + so, only in case of utilizing user-specified link-update... + */ + fixed->phydev = phydev; + + if(NULL == phydev) { + err = -ENOMEM; + goto device_create_fail; + } + + phydev->irq = -1; + phydev->dev.bus = &mdio_bus_type; + + if(number) + snprintf(phydev->dev.bus_id, BUS_ID_SIZE, + "fixed_%d@%d:%d", number, speed, duplex); + else + snprintf(phydev->dev.bus_id, BUS_ID_SIZE, + "fixed@%d:%d", speed, duplex); + phydev->bus = new_bus; + + err = device_register(&phydev->dev); + if(err) { + printk(KERN_ERR "Phy %s failed to register\n", + phydev->dev.bus_id); + goto bus_register_fail; + } + + /* + the mdio bus has phy_id match... In order not to do it + artificially, we are binding the driver here by hand; + it will be the same for all the fixed phys anyway. + */ + down_write(&phydev->dev.bus->subsys.rwsem); + + phydev->dev.driver = &fixed_mdio_driver.driver; + + err = phydev->dev.driver->probe(&phydev->dev); + if(err < 0) { + printk(KERN_ERR "Phy %s: problems with fixed driver\n",phydev->dev.bus_id); + up_write(&phydev->dev.bus->subsys.rwsem); + goto probe_fail; + } + + device_bind_driver(&phydev->dev); + up_write(&phydev->dev.bus->subsys.rwsem); + + return 0; + +probe_fail: + device_unregister(&phydev->dev); +bus_register_fail: + kfree(phydev); +device_create_fail: + kfree(dev); + kfree(new_bus); + kfree(fixed); + + return err; +} + + +MODULE_DESCRIPTION("Fixed PHY device & driver for PAL"); +MODULE_AUTHOR("Vitaly Bordug"); +MODULE_LICENSE("GPL"); + +static int __init fixed_init(void) +{ + int ret; + int duplex = 0; + + /* register on the bus... Not expected to be matched with anything there... */ + phy_driver_register(&fixed_mdio_driver); + + /* So let the fun begin... + We will create several mdio devices here, and will bound the upper + driver to them. + + Then the external software can lookup the phy bus by searching + fixed@speed:duplex, e.g. fixed@100:1, to be connected to the + virtual 100M Fdx phy. + + In case several virtual PHYs required, the bus_id will be in form + fixed_@:, which make it able even to define + driver-specific link control callback, if for instance PHY is completely + SW-driven. + + */ + +#ifdef CONFIG_FIXED_MII_DUPLEX + duplex = 1; +#endif + +#ifdef CONFIG_FIXED_MII_100_FDX + fixed_mdio_register_device(0, 100, 1); +#endif + +#ifdef CONFIX_FIXED_MII_10_FDX + fixed_mdio_register_device(0, 10, 1); +#endif + return 0; +} + +static void __exit fixed_exit(void) +{ + phy_driver_unregister(&fixed_mdio_driver); + /* :WARNING:02/18/2006 04:32:40 AM:: Cleanup all the created stuff */ +} + +module_init(fixed_init); +module_exit(fixed_exit); diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index 1dde390..cf6660c 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -159,6 +159,7 @@ struct bus_type mdio_bus_type = { .suspend = mdio_bus_suspend, .resume = mdio_bus_resume, }; +EXPORT_SYMBOL(mdio_bus_type); int __init mdio_bus_init(void) { diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 1bc1e03..2d1ecfd 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -45,6 +45,35 @@ static struct phy_driver genphy_driver; extern int mdio_bus_init(void); extern void mdio_bus_exit(void); +struct phy_device* phy_device_create(struct mii_bus *bus, int addr, int phy_id) +{ + struct phy_device *dev; + /* We allocate the device, and initialize the + * default values */ + dev = kcalloc(1, sizeof(*dev), GFP_KERNEL); + + if (NULL == dev) + return (struct phy_device*) PTR_ERR((void*)-ENOMEM); + + dev->speed = 0; + dev->duplex = -1; + dev->pause = dev->asym_pause = 0; + dev->link = 1; + + dev->autoneg = AUTONEG_ENABLE; + + dev->addr = addr; + dev->phy_id = phy_id; + dev->bus = bus; + + dev->state = PHY_DOWN; + + spin_lock_init(&dev->lock); + + return dev; +} +EXPORT_SYMBOL(phy_device_create); + /* get_phy_device * * description: Reads the ID registers of the PHY at addr on the @@ -78,27 +107,7 @@ struct phy_device * get_phy_device(struct mii_bus *bus, int addr) if (0xffffffff == phy_id) return NULL; - /* Otherwise, we allocate the device, and initialize the - * default values */ - dev = kcalloc(1, sizeof(*dev), GFP_KERNEL); - - if (NULL == dev) - return ERR_PTR(-ENOMEM); - - dev->speed = 0; - dev->duplex = -1; - dev->pause = dev->asym_pause = 0; - dev->link = 1; - - dev->autoneg = AUTONEG_ENABLE; - - dev->addr = addr; - dev->phy_id = phy_id; - dev->bus = bus; - - dev->state = PHY_DOWN; - - spin_lock_init(&dev->lock); + dev = phy_device_create(bus, addr, phy_id); return dev; } -- cgit v1.1 From 5b4b8454344a0391bb0f69fda0f4ec8e1f0d2fed Mon Sep 17 00:00:00 2001 From: Vitaly Bordug Date: Mon, 14 Aug 2006 23:00:30 -0700 Subject: [PATCH] FS_ENET: use PAL for mii management This patch should update the fs_enet infrastructure to utilize Phy Abstraction Layer subsystem. Along with the above, there are apparent bugfixes, overhaul and improvements. Signed-off-by: Vitaly Bordug Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/fs_enet/Makefile | 6 +- drivers/net/fs_enet/fec.h | 42 +++ drivers/net/fs_enet/fs_enet-main.c | 207 +++++++++------ drivers/net/fs_enet/fs_enet-mii.c | 505 ------------------------------------- drivers/net/fs_enet/fs_enet.h | 40 +-- drivers/net/fs_enet/mac-fcc.c | 32 ++- drivers/net/fs_enet/mac-fec.c | 142 ++--------- drivers/net/fs_enet/mac-scc.c | 4 +- drivers/net/fs_enet/mii-bitbang.c | 448 ++++++++++++++++---------------- drivers/net/fs_enet/mii-fec.c | 243 ++++++++++++++++++ drivers/net/fs_enet/mii-fixed.c | 91 ------- 11 files changed, 711 insertions(+), 1049 deletions(-) create mode 100644 drivers/net/fs_enet/fec.h delete mode 100644 drivers/net/fs_enet/fs_enet-mii.c create mode 100644 drivers/net/fs_enet/mii-fec.c delete mode 100644 drivers/net/fs_enet/mii-fixed.c (limited to 'drivers') diff --git a/drivers/net/fs_enet/Makefile b/drivers/net/fs_enet/Makefile index d6dd3f2..02d4dc1 100644 --- a/drivers/net/fs_enet/Makefile +++ b/drivers/net/fs_enet/Makefile @@ -4,7 +4,7 @@ obj-$(CONFIG_FS_ENET) += fs_enet.o -obj-$(CONFIG_8xx) += mac-fec.o mac-scc.o -obj-$(CONFIG_8260) += mac-fcc.o +obj-$(CONFIG_8xx) += mac-fec.o mac-scc.o mii-fec.o +obj-$(CONFIG_CPM2) += mac-fcc.o mii-bitbang.o -fs_enet-objs := fs_enet-main.o fs_enet-mii.o mii-bitbang.o mii-fixed.o +fs_enet-objs := fs_enet-main.o diff --git a/drivers/net/fs_enet/fec.h b/drivers/net/fs_enet/fec.h new file mode 100644 index 0000000..e980527 --- /dev/null +++ b/drivers/net/fs_enet/fec.h @@ -0,0 +1,42 @@ +#ifndef FS_ENET_FEC_H +#define FS_ENET_FEC_H + +/* 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 + + + +/* + * Delay to wait for FEC reset command to complete (in us) + */ +#define FEC_RESET_DELAY 50 +#endif diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c index f6abff5..df62506 100644 --- a/drivers/net/fs_enet/fs_enet-main.c +++ b/drivers/net/fs_enet/fs_enet-main.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -682,35 +683,6 @@ static void fs_free_irq(struct net_device *dev, int irq) (*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); @@ -722,10 +694,13 @@ static void fs_timeout(struct net_device *dev) spin_lock_irqsave(&fep->lock, flags); if (dev->flags & IFF_UP) { + phy_stop(fep->phydev); (*fep->ops->stop)(dev); (*fep->ops->restart)(dev); + phy_start(fep->phydev); } + phy_start(fep->phydev); wake = fep->tx_free && !(CBDR_SC(fep->cur_tx) & BD_ENET_TX_READY); spin_unlock_irqrestore(&fep->lock, flags); @@ -733,35 +708,112 @@ static void fs_timeout(struct net_device *dev) netif_wake_queue(dev); } +/*----------------------------------------------------------------------------- + * generic link-change handler - should be sufficient for most cases + *-----------------------------------------------------------------------------*/ +static void generic_adjust_link(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + struct phy_device *phydev = fep->phydev; + int new_state = 0; + + if (phydev->link) { + + /* adjust to duplex mode */ + if (phydev->duplex != fep->oldduplex){ + new_state = 1; + fep->oldduplex = phydev->duplex; + } + + if (phydev->speed != fep->oldspeed) { + new_state = 1; + fep->oldspeed = phydev->speed; + } + + if (!fep->oldlink) { + new_state = 1; + fep->oldlink = 1; + netif_schedule(dev); + netif_carrier_on(dev); + netif_start_queue(dev); + } + + if (new_state) + fep->ops->restart(dev); + + } else if (fep->oldlink) { + new_state = 1; + fep->oldlink = 0; + fep->oldspeed = 0; + fep->oldduplex = -1; + netif_carrier_off(dev); + netif_stop_queue(dev); + } + + if (new_state && netif_msg_link(fep)) + phy_print_status(phydev); +} + + +static void fs_adjust_link(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + unsigned long flags; + + spin_lock_irqsave(&fep->lock, flags); + + if(fep->ops->adjust_link) + fep->ops->adjust_link(dev); + else + generic_adjust_link(dev); + + spin_unlock_irqrestore(&fep->lock, flags); +} + +static int fs_init_phy(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + struct phy_device *phydev; + + fep->oldlink = 0; + fep->oldspeed = 0; + fep->oldduplex = -1; + if(fep->fpi->bus_id) + phydev = phy_connect(dev, fep->fpi->bus_id, &fs_adjust_link, 0); + else { + printk("No phy bus ID specified in BSP code\n"); + return -EINVAL; + } + if (IS_ERR(phydev)) { + printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name); + return PTR_ERR(phydev); + } + + fep->phydev = phydev; + + return 0; +} + + 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; + int err; /* 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); + ": %s Could not allocate FS_ENET 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; - } - } + err = fs_init_phy(dev); + if(err) + return err; - fs_mii_startup(dev); - netif_carrier_off(dev); - fs_mii_link_status_change_check(dev, 1); + phy_start(fep->phydev); return 0; } @@ -769,20 +821,19 @@ static int fs_enet_open(struct net_device *dev) 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); + phy_stop(fep->phydev); 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); + phy_disconnect(fep->phydev); + fep->phydev = NULL; fs_free_irq(dev, fep->interrupt); return 0; @@ -830,33 +881,19 @@ static void fs_get_regs(struct net_device *dev, struct ethtool_regs *regs, 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; + return phy_ethtool_gset(fep->phydev, cmd); } 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; + phy_ethtool_sset(fep->phydev, cmd); + return 0; } static int fs_nway_reset(struct net_device *dev) { - struct fs_enet_private *fep = netdev_priv(dev); - return mii_nway_restart(&fep->mii_if); + return 0; } static u32 fs_get_msglevel(struct net_device *dev) @@ -898,7 +935,7 @@ static int fs_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) return -EINVAL; spin_lock_irqsave(&fep->lock, flags); - rc = generic_mii_ioctl(&fep->mii_if, mii, cmd, NULL); + rc = phy_mii_ioctl(fep->phydev, mii, cmd); spin_unlock_irqrestore(&fep->lock, flags); return rc; } @@ -1030,12 +1067,6 @@ static struct net_device *fs_init_instance(struct device *dev, } 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; @@ -1073,8 +1104,6 @@ static int fs_cleanup_instance(struct net_device *ndev) fpi = fep->fpi; - fs_mii_disconnect(ndev); - unregister_netdev(ndev); dma_free_coherent(fep->dev, (fpi->tx_ring + fpi->rx_ring) * sizeof(cbd_t), @@ -1196,17 +1225,39 @@ static int __init fs_init(void) r = setup_immap(); if (r != 0) return r; - r = driver_register(&fs_enet_fec_driver); + +#ifdef CONFIG_FS_ENET_HAS_FCC + /* let's insert mii stuff */ + r = fs_enet_mdio_bb_init(); + + if (r != 0) { + printk(KERN_ERR DRV_MODULE_NAME + "BB PHY init failed.\n"); + return r; + } + r = driver_register(&fs_enet_fcc_driver); if (r != 0) goto err; +#endif - r = driver_register(&fs_enet_fcc_driver); +#ifdef CONFIG_FS_ENET_HAS_FEC + r = fs_enet_mdio_fec_init(); + if (r != 0) { + printk(KERN_ERR DRV_MODULE_NAME + "FEC PHY init failed.\n"); + return r; + } + + r = driver_register(&fs_enet_fec_driver); if (r != 0) goto err; +#endif +#ifdef CONFIG_FS_ENET_HAS_SCC r = driver_register(&fs_enet_scc_driver); if (r != 0) goto err; +#endif return 0; err: diff --git a/drivers/net/fs_enet/fs_enet-mii.c b/drivers/net/fs_enet/fs_enet-mii.c deleted file mode 100644 index b7e6e21..0000000 --- a/drivers/net/fs_enet/fs_enet-mii.c +++ /dev/null @@ -1,505 +0,0 @@ -/* - * Combined Ethernet driver for Motorola MPC8xx and MPC82xx. - * - * Copyright (c) 2003 Intracom S.A. - * by Pantelis Antoniou - * - * 2005 (c) MontaVista Software, Inc. - * Vitaly Bordug - * - * Heavily based on original FEC driver by Dan Malek - * and modifications by Joakim Tjernlund - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#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: - 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 index e7ec96c..95022c005 100644 --- a/drivers/net/fs_enet/fs_enet.h +++ b/drivers/net/fs_enet/fs_enet.h @@ -5,6 +5,7 @@ #include #include #include +#include #include @@ -12,12 +13,30 @@ #ifdef CONFIG_CPM1 #include + +struct fec_info { + fec_t* fecp; + u32 mii_speed; +}; #endif #ifdef CONFIG_CPM2 #include #endif +/* This is used to operate with pins. + Note that the actual port size may + be different; cpm(s) handle it OK */ +struct bb_info { + u8 mdio_dat_msk; + u8 mdio_dir_msk; + u8 *mdio_dir; + u8 *mdio_dat; + u8 mdc_msk; + u8 *mdc_dat; + int delay; +}; + /* hw driver ops */ struct fs_ops { int (*setup_data)(struct net_device *dev); @@ -25,6 +44,7 @@ struct fs_ops { void (*free_bd)(struct net_device *dev); void (*cleanup_data)(struct net_device *dev); void (*set_multicast_list)(struct net_device *dev); + void (*adjust_link)(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); @@ -100,10 +120,6 @@ struct fs_enet_mii_bus { }; }; -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 */ @@ -130,7 +146,8 @@ struct fs_enet_private { struct fs_enet_mii_bus *mii_bus; int interrupt; - int duplex, speed; /* current settings */ + struct phy_device *phydev; + int oldduplex, oldspeed, oldlink; /* current settings */ /* event masks */ u32 ev_napi_rx; /* mask of NAPI rx events */ @@ -168,15 +185,9 @@ struct fs_enet_private { }; /***************************************************************************/ - -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); +int fs_enet_mdio_bb_init(void); +int fs_mii_fixed_init(struct fs_enet_mii_bus *bus); +int fs_enet_mdio_fec_init(void); void fs_init_bds(struct net_device *dev); void fs_cleanup_bds(struct net_device *dev); @@ -194,7 +205,6 @@ int fs_enet_platform_init(void); void fs_enet_platform_cleanup(void); /***************************************************************************/ - /* buffer descriptor access macros */ /* access macros */ diff --git a/drivers/net/fs_enet/mac-fcc.c b/drivers/net/fs_enet/mac-fcc.c index 64e2098..1ff2597 100644 --- a/drivers/net/fs_enet/mac-fcc.c +++ b/drivers/net/fs_enet/mac-fcc.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -122,22 +123,32 @@ static int do_pd_setup(struct fs_enet_private *fep) /* Attach the memory for the FCC Parameter RAM */ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fcc_pram"); - fep->fcc.ep = (void *)r->start; - + fep->fcc.ep = (void *)ioremap(r->start, r->end - r->start + 1); if (fep->fcc.ep == NULL) return -EINVAL; r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fcc_regs"); - fep->fcc.fccp = (void *)r->start; - + fep->fcc.fccp = (void *)ioremap(r->start, r->end - r->start + 1); if (fep->fcc.fccp == NULL) return -EINVAL; - fep->fcc.fcccp = (void *)fep->fpi->fcc_regs_c; + if (fep->fpi->fcc_regs_c) { + + fep->fcc.fcccp = (void *)fep->fpi->fcc_regs_c; + } else { + r = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "fcc_regs_c"); + fep->fcc.fcccp = (void *)ioremap(r->start, + r->end - r->start + 1); + } if (fep->fcc.fcccp == NULL) return -EINVAL; + fep->fcc.mem = (void *)fep->fpi->mem_offset; + if (fep->fcc.mem == NULL) + return -EINVAL; + return 0; } @@ -155,8 +166,6 @@ static int setup_data(struct net_device *dev) 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; @@ -394,7 +403,7 @@ static void restart(struct net_device *dev) /* adjust to speed (for RMII mode) */ if (fpi->use_rmii) { - if (fep->speed == 100) + if (fep->phydev->speed == 100) C8(fcccp, fcc_gfemr, 0x20); else S8(fcccp, fcc_gfemr, 0x20); @@ -420,7 +429,7 @@ static void restart(struct net_device *dev) S32(fccp, fcc_fpsmr, FCC_PSMR_RMII); /* adjust to duplex mode */ - if (fep->duplex) + if (fep->phydev->duplex) S32(fccp, fcc_fpsmr, FCC_PSMR_FDE | FCC_PSMR_LPB); else C32(fccp, fcc_fpsmr, FCC_PSMR_FDE | FCC_PSMR_LPB); @@ -486,7 +495,10 @@ static void rx_bd_done(struct net_device *dev) static void tx_kickstart(struct net_device *dev) { - /* nothing */ + struct fs_enet_private *fep = netdev_priv(dev); + fcc_t *fccp = fep->fcc.fccp; + + S32(fccp, fcc_ftodr, 0x80); } static u32 get_int_events(struct net_device *dev) diff --git a/drivers/net/fs_enet/mac-fec.c b/drivers/net/fs_enet/mac-fec.c index e095470..c2c5fd4 100644 --- a/drivers/net/fs_enet/mac-fec.c +++ b/drivers/net/fs_enet/mac-fec.c @@ -46,6 +46,7 @@ #endif #include "fs_enet.h" +#include "fec.h" /*************************************************/ @@ -75,50 +76,8 @@ /* 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) + * Delay to wait for FEC reset command to complete (in us) */ #define FEC_RESET_DELAY 50 @@ -303,13 +262,15 @@ static void restart(struct net_device *dev) int r; u32 addrhi, addrlo; + struct mii_bus* mii = fep->phydev->bus; + struct fec_info* fec_inf = mii->priv; + 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. + * Set station address. */ addrhi = ((u32) dev->dev_addr[0] << 24) | ((u32) dev->dev_addr[1] << 16) | @@ -350,12 +311,12 @@ static void restart(struct net_device *dev) FW(fecp, fun_code, 0x78000000); /* - * Set MII speed. + * Set MII speed. */ - FW(fecp, mii_speed, fep->mii_bus->fec.mii_speed); + FW(fecp, mii_speed, fec_inf->mii_speed); /* - * Clear any outstanding interrupt. + * Clear any outstanding interrupt. */ FW(fecp, ievent, 0xffc0); FW(fecp, ivec, (fep->interrupt / 2) << 29); @@ -390,11 +351,12 @@ static void restart(struct net_device *dev) } #endif + FW(fecp, r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */ /* - * adjust to duplex mode + * adjust to duplex mode */ - if (fep->duplex) { + if (fep->phydev->duplex) { FC(fecp, r_cntrl, FEC_RCNTRL_DRT); FS(fecp, x_cntrl, FEC_TCNTRL_FDEN); /* FD enable */ } else { @@ -418,9 +380,11 @@ static void restart(struct net_device *dev) static void stop(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); + const struct fs_platform_info *fpi = fep->fpi; 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; + + struct fec_info* feci= fep->phydev->bus->priv; + int i; if ((FR(fecp, ecntrl) & FEC_ECNTRL_ETHER_EN) == 0) @@ -444,11 +408,11 @@ static void stop(struct net_device *dev) 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) { + if (fpi->has_phy) { 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); + FW(fecp, mii_speed, feci->mii_speed); } } @@ -583,73 +547,3 @@ const struct fs_ops fs_fec_ops = { .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 index eaa24fa..95ec587 100644 --- a/drivers/net/fs_enet/mac-scc.c +++ b/drivers/net/fs_enet/mac-scc.c @@ -369,7 +369,7 @@ static void restart(struct net_device *dev) W16(sccp, scc_psmr, SCC_PSMR_ENCRC | SCC_PSMR_NIB22); /* Set full duplex mode if needed */ - if (fep->duplex) + if (fep->phydev->duplex) S16(sccp, scc_psmr, SCC_PSMR_LPB | SCC_PSMR_FDE); S32(sccp, scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT); @@ -500,6 +500,8 @@ static void tx_restart(struct net_device *dev) scc_cr_cmd(fep, CPM_CR_RESTART_TX); } + + /*************************************************************************/ const struct fs_ops fs_scc_ops = { diff --git a/drivers/net/fs_enet/mii-bitbang.c b/drivers/net/fs_enet/mii-bitbang.c index 48f9cf8..0b9b8b5 100644 --- a/drivers/net/fs_enet/mii-bitbang.c +++ b/drivers/net/fs_enet/mii-bitbang.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -40,129 +41,25 @@ #include "fs_enet.h" -#ifdef CONFIG_8xx -static int bitbang_prep_bit(u8 **dirp, u8 **datp, u8 *mskp, int port, int bit) +static int bitbang_prep_bit(u8 **datp, u8 *mskp, + struct fs_mii_bit *mii_bit) { - immap_t *im = (immap_t *)fs_enet_immap; - void *dir, *dat, *ppar; + void *dat; 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; - } + dat = (void*) mii_bit->offset; - adv = bit >> 3; - dir = (char *)dir + adv; + adv = mii_bit->bit >> 3; 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; - } + msk = 1 << (7 - (mii_bit->bit & 7)); - *dirp = dir; *datp = dat; *mskp = msk; return 0; } -#endif static inline void bb_set(u8 *p, u8 m) { @@ -179,44 +76,44 @@ 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) +static inline void mdio_active(struct bb_info *bitbang) { - bb_set(bus->bitbang.mdio_dir, bus->bitbang.mdio_msk); + bb_set(bitbang->mdio_dir, bitbang->mdio_dir_msk); } -static inline void mdio_tristate(struct fs_enet_mii_bus *bus) +static inline void mdio_tristate(struct bb_info *bitbang ) { - bb_clr(bus->bitbang.mdio_dir, bus->bitbang.mdio_msk); + bb_clr(bitbang->mdio_dir, bitbang->mdio_dir_msk); } -static inline int mdio_read(struct fs_enet_mii_bus *bus) +static inline int mdio_read(struct bb_info *bitbang ) { - return bb_read(bus->bitbang.mdio_dat, bus->bitbang.mdio_msk); + return bb_read(bitbang->mdio_dat, bitbang->mdio_dat_msk); } -static inline void mdio(struct fs_enet_mii_bus *bus, int what) +static inline void mdio(struct bb_info *bitbang , int what) { if (what) - bb_set(bus->bitbang.mdio_dat, bus->bitbang.mdio_msk); + bb_set(bitbang->mdio_dat, bitbang->mdio_dat_msk); else - bb_clr(bus->bitbang.mdio_dat, bus->bitbang.mdio_msk); + bb_clr(bitbang->mdio_dat, bitbang->mdio_dat_msk); } -static inline void mdc(struct fs_enet_mii_bus *bus, int what) +static inline void mdc(struct bb_info *bitbang , int what) { if (what) - bb_set(bus->bitbang.mdc_dat, bus->bitbang.mdc_msk); + bb_set(bitbang->mdc_dat, bitbang->mdc_msk); else - bb_clr(bus->bitbang.mdc_dat, bus->bitbang.mdc_msk); + bb_clr(bitbang->mdc_dat, bitbang->mdc_msk); } -static inline void mii_delay(struct fs_enet_mii_bus *bus) +static inline void mii_delay(struct bb_info *bitbang ) { - udelay(bus->bus_info->i.bitbang.delay); + udelay(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) +static void bitbang_pre(struct bb_info *bitbang , int read, u8 addr, u8 reg) { int j; @@ -228,177 +125,284 @@ static void bitbang_pre(struct fs_enet_mii_bus *bus, int read, u8 addr, u8 reg) * but it is safer and will be much more robust. */ - mdio_active(bus); - mdio(bus, 1); + mdio_active(bitbang); + mdio(bitbang, 1); for (j = 0; j < 32; j++) { - mdc(bus, 0); - mii_delay(bus); - mdc(bus, 1); - mii_delay(bus); + mdc(bitbang, 0); + mii_delay(bitbang); + mdc(bitbang, 1); + mii_delay(bitbang); } /* 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); + mdc(bitbang, 0); + mdio(bitbang, 0); + mii_delay(bitbang); + mdc(bitbang, 1); + mii_delay(bitbang); + mdc(bitbang, 0); + mdio(bitbang, 1); + mii_delay(bitbang); + mdc(bitbang, 1); + mii_delay(bitbang); + mdc(bitbang, 0); + mdio(bitbang, read); + mii_delay(bitbang); + mdc(bitbang, 1); + mii_delay(bitbang); + mdc(bitbang, 0); + mdio(bitbang, !read); + mii_delay(bitbang); + mdc(bitbang, 1); + mii_delay(bitbang); /* 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); + mdc(bitbang, 0); + mdio(bitbang, (addr & 0x10) != 0); + mii_delay(bitbang); + mdc(bitbang, 1); + mii_delay(bitbang); 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); + mdc(bitbang, 0); + mdio(bitbang, (reg & 0x10) != 0); + mii_delay(bitbang); + mdc(bitbang, 1); + mii_delay(bitbang); reg <<= 1; } } -static int mii_read(struct fs_enet_mii_bus *bus, int phy_id, int location) +static int fs_enet_mii_bb_read(struct mii_bus *bus , int phy_id, int location) { u16 rdreg; int ret, j; u8 addr = phy_id & 0xff; u8 reg = location & 0xff; + struct bb_info* bitbang = bus->priv; - bitbang_pre(bus, 1, addr, reg); + bitbang_pre(bitbang, 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); + mdc(bitbang, 0); + mdio_tristate(bitbang); + mii_delay(bitbang); + mdc(bitbang, 1); + mii_delay(bitbang); /* check the turnaround bit: the PHY should be driving it to zero */ - if (mdio_read(bus) != 0) { + if (mdio_read(bitbang) != 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); + mdc(bitbang, 0); + mii_delay(bitbang); + mdc(bitbang, 1); + mii_delay(bitbang); } ret = -1; goto out; } - mdc(bus, 0); - mii_delay(bus); + mdc(bitbang, 0); + mii_delay(bitbang); /* read 16 bits of register data, MSB first */ rdreg = 0; for (j = 0; j < 16; j++) { - mdc(bus, 1); - mii_delay(bus); + mdc(bitbang, 1); + mii_delay(bitbang); rdreg <<= 1; - rdreg |= mdio_read(bus); - mdc(bus, 0); - mii_delay(bus); + rdreg |= mdio_read(bitbang); + mdc(bitbang, 0); + mii_delay(bitbang); } - mdc(bus, 1); - mii_delay(bus); - mdc(bus, 0); - mii_delay(bus); - mdc(bus, 1); - mii_delay(bus); + mdc(bitbang, 1); + mii_delay(bitbang); + mdc(bitbang, 0); + mii_delay(bitbang); + mdc(bitbang, 1); + mii_delay(bitbang); ret = rdreg; out: return ret; } -static void mii_write(struct fs_enet_mii_bus *bus, int phy_id, int location, int val) +static int fs_enet_mii_bb_write(struct mii_bus *bus, int phy_id, int location, u16 val) { int j; + struct bb_info* bitbang = bus->priv; + u8 addr = phy_id & 0xff; u8 reg = location & 0xff; u16 value = val & 0xffff; - bitbang_pre(bus, 0, addr, reg); + bitbang_pre(bitbang, 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); + mdc(bitbang, 0); + mdio(bitbang, 1); + mii_delay(bitbang); + mdc(bitbang, 1); + mii_delay(bitbang); + mdc(bitbang, 0); + mdio(bitbang, 0); + mii_delay(bitbang); + mdc(bitbang, 1); + mii_delay(bitbang); /* 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); + mdc(bitbang, 0); + mdio(bitbang, (value & 0x8000) != 0); + mii_delay(bitbang); + mdc(bitbang, 1); + mii_delay(bitbang); value <<= 1; } /* * Tri-state the MDIO line. */ - mdio_tristate(bus); - mdc(bus, 0); - mii_delay(bus); - mdc(bus, 1); - mii_delay(bus); + mdio_tristate(bitbang); + mdc(bitbang, 0); + mii_delay(bitbang); + mdc(bitbang, 1); + mii_delay(bitbang); + return 0; } -int fs_mii_bitbang_init(struct fs_enet_mii_bus *bus) +static int fs_enet_mii_bb_reset(struct mii_bus *bus) +{ + /*nothing here - dunno how to reset it*/ + return 0; +} + +static int fs_mii_bitbang_init(struct bb_info *bitbang, struct fs_mii_bb_platform_info* fmpi) { - 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); + bitbang->delay = fmpi->delay; + + r = bitbang_prep_bit(&bitbang->mdio_dir, + &bitbang->mdio_dir_msk, + &fmpi->mdio_dir); 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); + r = bitbang_prep_bit(&bitbang->mdio_dat, + &bitbang->mdio_dat_msk, + &fmpi->mdio_dat); if (r != 0) return r; - bus->mii_read = mii_read; - bus->mii_write = mii_write; + r = bitbang_prep_bit(&bitbang->mdc_dat, + &bitbang->mdc_msk, + &fmpi->mdc_dat); + if (r != 0) + return r; return 0; } + + +static int __devinit fs_enet_mdio_probe(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct fs_mii_bb_platform_info *pdata; + struct mii_bus *new_bus; + struct bb_info *bitbang; + int err = 0; + + if (NULL == dev) + return -EINVAL; + + new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL); + + if (NULL == new_bus) + return -ENOMEM; + + bitbang = kzalloc(sizeof(struct bb_info), GFP_KERNEL); + + if (NULL == bitbang) + return -ENOMEM; + + new_bus->name = "BB MII Bus", + new_bus->read = &fs_enet_mii_bb_read, + new_bus->write = &fs_enet_mii_bb_write, + new_bus->reset = &fs_enet_mii_bb_reset, + new_bus->id = pdev->id; + + new_bus->phy_mask = ~0x9; + pdata = (struct fs_mii_bb_platform_info *)pdev->dev.platform_data; + + if (NULL == pdata) { + printk(KERN_ERR "gfar mdio %d: Missing platform data!\n", pdev->id); + return -ENODEV; + } + + /*set up workspace*/ + fs_mii_bitbang_init(bitbang, pdata); + + new_bus->priv = bitbang; + + 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: + kfree(bitbang); + kfree(new_bus); + + return err; +} + + +static int fs_enet_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 fs_enet_bb_mdio_driver = { + .name = "fsl-bb-mdio", + .bus = &platform_bus_type, + .probe = fs_enet_mdio_probe, + .remove = fs_enet_mdio_remove, +}; + +int fs_enet_mdio_bb_init(void) +{ + return driver_register(&fs_enet_bb_mdio_driver); +} + +void fs_enet_mdio_bb_exit(void) +{ + driver_unregister(&fs_enet_bb_mdio_driver); +} + diff --git a/drivers/net/fs_enet/mii-fec.c b/drivers/net/fs_enet/mii-fec.c new file mode 100644 index 0000000..1328e10 --- /dev/null +++ b/drivers/net/fs_enet/mii-fec.c @@ -0,0 +1,243 @@ +/* + * Combined Ethernet driver for Motorola MPC8xx and MPC82xx. + * + * Copyright (c) 2003 Intracom S.A. + * by Pantelis Antoniou + * + * 2005 (c) MontaVista Software, Inc. + * Vitaly Bordug + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "fs_enet.h" +#include "fec.h" + +/* 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 + +static int match_has_phy (struct device *dev, void* data) +{ + struct platform_device* pdev = container_of(dev, struct platform_device, dev); + struct fs_platform_info* fpi; + if(strcmp(pdev->name, (char*)data)) + { + return 0; + } + + fpi = pdev->dev.platform_data; + if((fpi)&&(fpi->has_phy)) + return 1; + return 0; +} + +static int fs_mii_fec_init(struct fec_info* fec, struct fs_mii_fec_platform_info *fmpi) +{ + struct resource *r; + fec_t *fecp; + char* name = "fsl-cpm-fec"; + + /* we need fec in order to be useful */ + struct platform_device *fec_pdev = + container_of(bus_find_device(&platform_bus_type, NULL, name, match_has_phy), + struct platform_device, dev); + + if(fec_pdev == NULL) { + printk(KERN_ERR"Unable to find PHY for %s", name); + return -ENODEV; + } + + r = platform_get_resource_byname(fec_pdev, IORESOURCE_MEM, "regs"); + + fec->fecp = fecp = (fec_t*)ioremap(r->start,sizeof(fec_t)); + fec->mii_speed = fmpi->mii_speed; + + setbits32(&fecp->fec_r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */ + setbits32(&fecp->fec_ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN); + out_be32(&fecp->fec_ievent, FEC_ENET_MII); + out_be32(&fecp->fec_mii_speed, fec->mii_speed); + + return 0; +} + +static int fs_enet_fec_mii_read(struct mii_bus *bus , int phy_id, int location) +{ + struct fec_info* fec = bus->priv; + fec_t *fecp = fec->fecp; + int i, ret = -1; + + if ((in_be32(&fecp->fec_r_cntrl) & FEC_RCNTRL_MII_MODE) == 0) + BUG(); + + /* Add PHY address to register command. */ + out_be32(&fecp->fec_mii_data, (phy_id << 23) | mk_mii_read(location)); + + for (i = 0; i < FEC_MII_LOOPS; i++) + if ((in_be32(&fecp->fec_ievent) & FEC_ENET_MII) != 0) + break; + + if (i < FEC_MII_LOOPS) { + out_be32(&fecp->fec_ievent, FEC_ENET_MII); + ret = in_be32(&fecp->fec_mii_data) & 0xffff; + } + + return ret; + +} + +static int fs_enet_fec_mii_write(struct mii_bus *bus, int phy_id, int location, u16 val) +{ + struct fec_info* fec = bus->priv; + fec_t *fecp = fec->fecp; + int i; + + /* this must never happen */ + if ((in_be32(&fecp->fec_r_cntrl) & FEC_RCNTRL_MII_MODE) == 0) + BUG(); + + /* Add PHY address to register command. */ + out_be32(&fecp->fec_mii_data, (phy_id << 23) | mk_mii_write(location, val)); + + for (i = 0; i < FEC_MII_LOOPS; i++) + if ((in_be32(&fecp->fec_ievent) & FEC_ENET_MII) != 0) + break; + + if (i < FEC_MII_LOOPS) + out_be32(&fecp->fec_ievent, FEC_ENET_MII); + + return 0; + +} + +static int fs_enet_fec_mii_reset(struct mii_bus *bus) +{ + /* nothing here - for now */ + return 0; +} + +static int __devinit fs_enet_fec_mdio_probe(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct fs_mii_fec_platform_info *pdata; + struct mii_bus *new_bus; + struct fec_info *fec; + int err = 0; + if (NULL == dev) + return -EINVAL; + new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL); + + if (NULL == new_bus) + return -ENOMEM; + + fec = kzalloc(sizeof(struct fec_info), GFP_KERNEL); + + if (NULL == fec) + return -ENOMEM; + + new_bus->name = "FEC MII Bus", + new_bus->read = &fs_enet_fec_mii_read, + new_bus->write = &fs_enet_fec_mii_write, + new_bus->reset = &fs_enet_fec_mii_reset, + new_bus->id = pdev->id; + + pdata = (struct fs_mii_fec_platform_info *)pdev->dev.platform_data; + + if (NULL == pdata) { + printk(KERN_ERR "fs_enet FEC mdio %d: Missing platform data!\n", pdev->id); + return -ENODEV; + } + + /*set up workspace*/ + + fs_mii_fec_init(fec, pdata); + new_bus->priv = fec; + + 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: + kfree(new_bus); + + return err; +} + + +static int fs_enet_fec_mdio_remove(struct device *dev) +{ + struct mii_bus *bus = dev_get_drvdata(dev); + + mdiobus_unregister(bus); + + dev_set_drvdata(dev, NULL); + kfree(bus->priv); + + bus->priv = NULL; + kfree(bus); + + return 0; +} + +static struct device_driver fs_enet_fec_mdio_driver = { + .name = "fsl-cpm-fec-mdio", + .bus = &platform_bus_type, + .probe = fs_enet_fec_mdio_probe, + .remove = fs_enet_fec_mdio_remove, +}; + +int fs_enet_mdio_fec_init(void) +{ + return driver_register(&fs_enet_fec_mdio_driver); +} + +void fs_enet_mdio_fec_exit(void) +{ + driver_unregister(&fs_enet_fec_mdio_driver); +} + diff --git a/drivers/net/fs_enet/mii-fixed.c b/drivers/net/fs_enet/mii-fixed.c deleted file mode 100644 index ae4a9c3..0000000 --- a/drivers/net/fs_enet/mii-fixed.c +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Combined Ethernet driver for Motorola MPC8xx and MPC82xx. - * - * Copyright (c) 2003 Intracom S.A. - * by Pantelis Antoniou - * - * 2005 (c) MontaVista Software, Inc. - * Vitaly Bordug - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#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; -} -- cgit v1.1 From a76b044af147135b5fb7570aba35d4908f143cc9 Mon Sep 17 00:00:00 2001 From: Krzysztof Halasa Date: Wed, 16 Aug 2006 01:52:23 +0200 Subject: [PATCH] WAN: fix C101 card carrier handling Hi, One of my recent changes broke C101 carrier handling, this patch fixes it. Also fixes an old TX underrun checking bug. 2.6.18 material. Please apply. Thanks. Signed-off-by: Krzysztof Halasa Signed-off-by: Jeff Garzik --- drivers/net/wan/c101.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wan/c101.c b/drivers/net/wan/c101.c index 435e91e..6b63b35 100644 --- a/drivers/net/wan/c101.c +++ b/drivers/net/wan/c101.c @@ -118,7 +118,7 @@ static inline void openwin(card_t *card, u8 page) static inline void set_carrier(port_t *port) { - if (!sca_in(MSCI1_OFFSET + ST3, port) & ST3_DCD) + if (!(sca_in(MSCI1_OFFSET + ST3, port) & ST3_DCD)) netif_carrier_on(port_to_dev(port)); else netif_carrier_off(port_to_dev(port)); @@ -127,10 +127,10 @@ static inline void set_carrier(port_t *port) static void sca_msci_intr(port_t *port) { - u8 stat = sca_in(MSCI1_OFFSET + ST1, port); /* read MSCI ST1 status */ + u8 stat = sca_in(MSCI0_OFFSET + ST1, port); /* read MSCI ST1 status */ - /* Reset MSCI TX underrun status bit */ - sca_out(stat & ST1_UDRN, MSCI0_OFFSET + ST1, port); + /* Reset MSCI TX underrun and CDCD (ignored) status bit */ + sca_out(stat & (ST1_UDRN | ST1_CDCD), MSCI0_OFFSET + ST1, port); if (stat & ST1_UDRN) { struct net_device_stats *stats = hdlc_stats(port_to_dev(port)); @@ -138,6 +138,7 @@ static void sca_msci_intr(port_t *port) stats->tx_fifo_errors++; } + stat = sca_in(MSCI1_OFFSET + ST1, port); /* read MSCI1 ST1 status */ /* Reset MSCI CDCD status bit - uses ch#2 DCD input */ sca_out(stat & ST1_CDCD, MSCI1_OFFSET + ST1, port); -- cgit v1.1 From f1a58ecae527fc67c87ce4dcb9e73894f64aadfe Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 20 Aug 2006 17:56:38 +0900 Subject: [PATCH] ata_piix: fix ghost device probing by honoring PCS present bits Move out PCS handling from piix_sata_prereset() into piix_sata_present_mask() and use it from newly implemented piix_sata_softreset(). Class codes for devices which are indicated to be absent by PCS are cleared to ATA_DEV_NONE. This fixes ghost device problem reported on ICH6 and 7. This patch moves PCS handling from prereset to softreset, which makes two behavior changes. * perform softreset even when PCS indicates no device * PCS handling is repeated before retrying softresets due to reset failures. Both behavior changes are intended and more consistent with how other drivers behave. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/scsi/ata_piix.c | 60 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 43 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c index 5e8afc8..01b3530 100644 --- a/drivers/scsi/ata_piix.c +++ b/drivers/scsi/ata_piix.c @@ -531,27 +531,25 @@ static void piix_pata_error_handler(struct ata_port *ap) } /** - * piix_sata_prereset - prereset for SATA host controller + * piix_sata_present_mask - determine present mask for SATA host controller * @ap: Target port * - * Reads and configures SATA PCI device's PCI config register - * Port Configuration and Status (PCS) to determine port and - * device availability. Return -ENODEV to skip reset if no - * device is present. + * Reads SATA PCI device's PCI config register Port Configuration + * and Status (PCS) to determine port and device availability. * * LOCKING: * None (inherited from caller). * * RETURNS: - * 0 if device is present, -ENODEV otherwise. + * determined present_mask */ -static int piix_sata_prereset(struct ata_port *ap) +static unsigned int piix_sata_present_mask(struct ata_port *ap) { struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); struct piix_host_priv *hpriv = ap->host_set->private_data; const unsigned int *map = hpriv->map; int base = 2 * ap->hard_port_no; - unsigned int present = 0; + unsigned int present_mask = 0; int port, i; u16 pcs; @@ -564,24 +562,52 @@ static int piix_sata_prereset(struct ata_port *ap) continue; if ((ap->flags & PIIX_FLAG_IGNORE_PCS) || (pcs & 1 << (hpriv->map_db->present_shift + port))) - present = 1; + present_mask |= 1 << i; } - DPRINTK("ata%u: LEAVE, pcs=0x%x present=0x%x\n", - ap->id, pcs, present); + DPRINTK("ata%u: LEAVE, pcs=0x%x present_mask=0x%x\n", + ap->id, pcs, present_mask); - if (!present) { - ata_port_printk(ap, KERN_INFO, "SATA port has no device.\n"); - ap->eh_context.i.action &= ~ATA_EH_RESET_MASK; - return 0; + return present_mask; +} + +/** + * piix_sata_softreset - reset SATA host port via ATA SRST + * @ap: port to reset + * @classes: resulting classes of attached devices + * + * Reset SATA host port via ATA SRST. On controllers with + * reliable PCS present bits, the bits are used to determine + * device presence. + * + * LOCKING: + * Kernel thread context (may sleep) + * + * RETURNS: + * 0 on success, -errno otherwise. + */ +static int piix_sata_softreset(struct ata_port *ap, unsigned int *classes) +{ + unsigned int present_mask; + int i, rc; + + present_mask = piix_sata_present_mask(ap); + + rc = ata_std_softreset(ap, classes); + if (rc) + return rc; + + for (i = 0; i < ATA_MAX_DEVICES; i++) { + if (!(present_mask & (1 << i))) + classes[i] = ATA_DEV_NONE; } - return ata_std_prereset(ap); + return 0; } static void piix_sata_error_handler(struct ata_port *ap) { - ata_bmdma_drive_eh(ap, piix_sata_prereset, ata_std_softreset, NULL, + ata_bmdma_drive_eh(ap, ata_std_prereset, piix_sata_softreset, NULL, ata_std_postreset); } -- cgit v1.1 From 8ea371fb6df5a6e8056265e0089fd578e87797fc Mon Sep 17 00:00:00 2001 From: Florin Malita Date: Wed, 23 Aug 2006 00:45:33 -0400 Subject: Input: atkbd - fix overrun in atkbd_set_repeat_rate() This was introduced in commit 3d0f0fa0cb554541e10cb8cb84104e4b10828468: bounds checking is performed against period[32] while indexing delay[4]. Spotted by Coverity, CID 1376. Signed-off-by: Florin Malita Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/atkbd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index 6bfa0cf..a86afd0 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c @@ -498,7 +498,7 @@ static int atkbd_set_repeat_rate(struct atkbd *atkbd) i++; dev->rep[REP_PERIOD] = period[i]; - while (j < ARRAY_SIZE(period) - 1 && delay[j] < dev->rep[REP_DELAY]) + while (j < ARRAY_SIZE(delay) - 1 && delay[j] < dev->rep[REP_DELAY]) j++; dev->rep[REP_DELAY] = delay[j]; -- cgit v1.1 From 72a623be00fa3d77724c1b0cac07c1bac60e70a5 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 23 Aug 2006 00:47:39 -0400 Subject: Input: wistron - fix crash due to referencing __initdata Remove __initdata markings from keymaps as they are used during normal driver operations. Signed-off-by: Dmitry Torokhov --- drivers/input/misc/wistron_btns.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c index a8efc1a..de0f46d 100644 --- a/drivers/input/misc/wistron_btns.c +++ b/drivers/input/misc/wistron_btns.c @@ -259,11 +259,11 @@ static int __init dmi_matched(struct dmi_system_id *dmi) return 1; } -static struct key_entry keymap_empty[] __initdata = { +static struct key_entry keymap_empty[] = { { KE_END, 0 } }; -static struct key_entry keymap_fs_amilo_pro_v2000[] __initdata = { +static struct key_entry keymap_fs_amilo_pro_v2000[] = { { KE_KEY, 0x01, KEY_HELP }, { KE_KEY, 0x11, KEY_PROG1 }, { KE_KEY, 0x12, KEY_PROG2 }, @@ -273,7 +273,7 @@ static struct key_entry keymap_fs_amilo_pro_v2000[] __initdata = { { KE_END, 0 } }; -static struct key_entry keymap_fujitsu_n3510[] __initdata = { +static struct key_entry keymap_fujitsu_n3510[] = { { KE_KEY, 0x11, KEY_PROG1 }, { KE_KEY, 0x12, KEY_PROG2 }, { KE_KEY, 0x36, KEY_WWW }, @@ -285,7 +285,7 @@ static struct key_entry keymap_fujitsu_n3510[] __initdata = { { KE_END, 0 } }; -static struct key_entry keymap_wistron_ms2111[] __initdata = { +static struct key_entry keymap_wistron_ms2111[] = { { KE_KEY, 0x11, KEY_PROG1 }, { KE_KEY, 0x12, KEY_PROG2 }, { KE_KEY, 0x13, KEY_PROG3 }, @@ -294,7 +294,7 @@ static struct key_entry keymap_wistron_ms2111[] __initdata = { { KE_END, 0 } }; -static struct key_entry keymap_wistron_ms2141[] __initdata = { +static struct key_entry keymap_wistron_ms2141[] = { { KE_KEY, 0x11, KEY_PROG1 }, { KE_KEY, 0x12, KEY_PROG2 }, { KE_WIFI, 0x30, 0 }, @@ -307,7 +307,7 @@ static struct key_entry keymap_wistron_ms2141[] __initdata = { { KE_END, 0 } }; -static struct key_entry keymap_acer_aspire_1500[] __initdata = { +static struct key_entry keymap_acer_aspire_1500[] = { { KE_KEY, 0x11, KEY_PROG1 }, { KE_KEY, 0x12, KEY_PROG2 }, { KE_WIFI, 0x30, 0 }, @@ -317,7 +317,7 @@ static struct key_entry keymap_acer_aspire_1500[] __initdata = { { KE_END, 0 } }; -static struct key_entry keymap_acer_travelmate_240[] __initdata = { +static struct key_entry keymap_acer_travelmate_240[] = { { KE_KEY, 0x31, KEY_MAIL }, { KE_KEY, 0x36, KEY_WWW }, { KE_KEY, 0x11, KEY_PROG1 }, @@ -327,7 +327,7 @@ static struct key_entry keymap_acer_travelmate_240[] __initdata = { { KE_END, 0 } }; -static struct key_entry keymap_aopen_1559as[] __initdata = { +static struct key_entry keymap_aopen_1559as[] = { { KE_KEY, 0x01, KEY_HELP }, { KE_KEY, 0x06, KEY_PROG3 }, { KE_KEY, 0x11, KEY_PROG1 }, -- cgit v1.1 From 90414be9523208f0b667fd58c22e26b8db0594de Mon Sep 17 00:00:00 2001 From: Pozsar Balazs Date: Wed, 23 Aug 2006 00:48:03 -0400 Subject: Input: psmouse - fix Intellimouse 4.0 initialization Revert the superfluous initilization causing some mice become jumpy. Signed-off-by: Pozsar Balazs Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/psmouse-base.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers') diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index 8bc9f51..343afa3 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -485,13 +485,6 @@ static int im_explorer_detect(struct psmouse *psmouse, int set_properties) param[0] = 40; ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE); - param[0] = 200; - ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE); - param[0] = 200; - ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE); - param[0] = 60; - ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE); - if (set_properties) { set_bit(BTN_MIDDLE, psmouse->dev->keybit); set_bit(REL_WHEEL, psmouse->dev->relbit); -- cgit v1.1 From 794ccda61c7dc2aa6c66e8ef18a44d865d3c3a7d Mon Sep 17 00:00:00 2001 From: Pavel Roskin Date: Tue, 15 Aug 2006 20:42:20 -0400 Subject: [PATCH] spectrum_cs: Fix incorrect use of pcmcia_dev_present() This bug was introduced during the PCMCIA API conversion and broke spectrum_cs completely. Tracked down by Fredrik Tolf Signed-off-by: Pavel Roskin Signed-off-by: John W. Linville --- drivers/net/wireless/spectrum_cs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/spectrum_cs.c b/drivers/net/wireless/spectrum_cs.c index 7f78b78..bcc7038 100644 --- a/drivers/net/wireless/spectrum_cs.c +++ b/drivers/net/wireless/spectrum_cs.c @@ -242,7 +242,7 @@ spectrum_reset(struct pcmcia_device *link, int idle) u_int save_cor; /* Doing it if hardware is gone is guaranteed crash */ - if (pcmcia_dev_present(link)) + if (!pcmcia_dev_present(link)) return -ENODEV; /* Save original COR value */ -- cgit v1.1 From 9b5cce07648d059a013444116bd0140b047b25a1 Mon Sep 17 00:00:00 2001 From: Pavel Roskin Date: Tue, 15 Aug 2006 21:41:39 -0400 Subject: [PATCH] hostap: Restore antenna selection settings after port reset Intersil firmware 1.7.4 (and possibly others) loses the antenna selection settings when the port is reset. Signed-off-by: David Acker Signed-off-by: Pavel Roskin Signed-off-by: John W. Linville --- drivers/net/wireless/hostap/hostap_hw.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c index dafaa5f..d500012 100644 --- a/drivers/net/wireless/hostap/hostap_hw.c +++ b/drivers/net/wireless/hostap/hostap_hw.c @@ -1042,6 +1042,9 @@ static int prism2_reset_port(struct net_device *dev) dev->name, local->fragm_threshold); } + /* Some firmwares lose antenna selection settings on reset */ + (void) hostap_set_antsel(local); + return res; } -- cgit v1.1 From 834ac73d4bc804db8ccb3f2a517e36db5f6bc4bd Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Tue, 22 Aug 2006 22:45:06 +0300 Subject: IB/mthca: Update HCA firmware revisions Update the driver's list of HCA firmware revisions to make sure people running Sinai firmware older than 1.1.0 get a message suggesting a firmware upgrade. Update the Arbel versions as well while we are at it. Signed-off-by: Michael S. Tsirkin Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mthca/mthca_main.c b/drivers/infiniband/hw/mthca/mthca_main.c index 557cde3..7b82c19 100644 --- a/drivers/infiniband/hw/mthca/mthca_main.c +++ b/drivers/infiniband/hw/mthca/mthca_main.c @@ -967,12 +967,12 @@ static struct { } mthca_hca_table[] = { [TAVOR] = { .latest_fw = MTHCA_FW_VER(3, 4, 0), .flags = 0 }, - [ARBEL_COMPAT] = { .latest_fw = MTHCA_FW_VER(4, 7, 400), + [ARBEL_COMPAT] = { .latest_fw = MTHCA_FW_VER(4, 7, 600), .flags = MTHCA_FLAG_PCIE }, - [ARBEL_NATIVE] = { .latest_fw = MTHCA_FW_VER(5, 1, 0), + [ARBEL_NATIVE] = { .latest_fw = MTHCA_FW_VER(5, 1, 400), .flags = MTHCA_FLAG_MEMFREE | MTHCA_FLAG_PCIE }, - [SINAI] = { .latest_fw = MTHCA_FW_VER(1, 0, 800), + [SINAI] = { .latest_fw = MTHCA_FW_VER(1, 1, 0), .flags = MTHCA_FLAG_MEMFREE | MTHCA_FLAG_PCIE | MTHCA_FLAG_SINAI_OPT } -- cgit v1.1 From 25848c4e502ec2bb94ee1f3c82709311059d0857 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 23 Aug 2006 15:33:07 -0700 Subject: [SCSI] esp: Fix build on SUN4. Noted by Alexey Dobriyan. Signed-off-by: David S. Miller --- drivers/scsi/esp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/esp.c b/drivers/scsi/esp.c index 98bd227..5630868 100644 --- a/drivers/scsi/esp.c +++ b/drivers/scsi/esp.c @@ -1146,7 +1146,7 @@ static struct sbus_dev sun4_esp_dev; static int __init esp_sun4_probe(struct scsi_host_template *tpnt) { if (sun4_esp_physaddr) { - memset(&sun4_esp_dev, 0, sizeof(esp_dev)); + memset(&sun4_esp_dev, 0, sizeof(sun4_esp_dev)); sun4_esp_dev.reg_addrs[0].phys_addr = sun4_esp_physaddr; sun4_esp_dev.irqs[0] = 4; sun4_esp_dev.resource[0].start = sun4_esp_physaddr; @@ -1162,6 +1162,7 @@ static int __init esp_sun4_probe(struct scsi_host_template *tpnt) static int __devexit esp_sun4_remove(void) { + struct of_device *dev = &sun4_esp_dev.ofdev; struct esp *esp = dev_get_drvdata(&dev->dev); return esp_remove_common(esp); -- cgit v1.1 From 0f4184f73d5233214d3225a94fcf1bd4d6678d74 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 23 Aug 2006 15:50:57 -0700 Subject: [SERIAL] sunsab: Fix E250 console with RSC. This fixes yet another sunsab problem, when console is set to anything but the first port. The console framework calls sunsab_console_setup for each port, and we end up setting up a console on a not yet discovered port, which leads to an Oops. Instead, defer console setup until the requested port is properly initialized. Tested on an E250 through an RSC console. Reported by Daniel Smolik Signed-off-by: Marc Zyngier Signed-off-by: David S. Miller --- drivers/serial/sunsab.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c index dc673e1..cfe20f7 100644 --- a/drivers/serial/sunsab.c +++ b/drivers/serial/sunsab.c @@ -886,6 +886,15 @@ static int sunsab_console_setup(struct console *con, char *options) unsigned long flags; unsigned int baud, quot; + /* + * The console framework calls us for each and every port + * registered. Defer the console setup until the requested + * port has been properly discovered. A bit of a hack, + * though... + */ + if (up->port.type != PORT_SUNSAB) + return -1; + printk("Console: ttyS%d (SAB82532)\n", (sunsab_reg.minor - 64) + con->index); -- cgit v1.1 From b8b99e857d0e258b0da17e55466e5142465d35fd Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 23 Aug 2006 15:53:39 -0700 Subject: [SERIAL] sunzilog: Mirror the sunsab serial setup bug fix. Signed-off-by: David S. Miller --- drivers/serial/sunzilog.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c index 47bc3d5..d34f336 100644 --- a/drivers/serial/sunzilog.c +++ b/drivers/serial/sunzilog.c @@ -1146,6 +1146,9 @@ static int __init sunzilog_console_setup(struct console *con, char *options) unsigned long flags; int baud, brg; + if (up->port.type != PORT_SUNZILOG) + return -1; + printk(KERN_INFO "Console: ttyS%d (SunZilog zs%d)\n", (sunzilog_reg.minor - 64) + con->index, con->index); -- cgit v1.1 From cb958186ed543d1a4f074ceb1c783fe8b0908437 Mon Sep 17 00:00:00 2001 From: Eric Sesterhenn Date: Sat, 19 Aug 2006 19:37:57 +0200 Subject: [PATCH] Signedness issue in drivers/net/3c515.c while playing with gcc 4.1 -Wextra warnings, I came across this one: drivers/net/3c515.c:1027: warning: comparison of unsigned expression >= 0 is always true Since i is unsigned the >= 0 check in the for loop is always true, so we might spin there forever unless the if condition triggers. Since i is only used in this loop, this patch changes it to an integer. Signed-off-by: Eric Sesterhenn Signed-off-by: Jeff Garzik --- drivers/net/3c515.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c index 4532b17..aedfddf 100644 --- a/drivers/net/3c515.c +++ b/drivers/net/3c515.c @@ -1003,7 +1003,8 @@ static int corkscrew_start_xmit(struct sk_buff *skb, /* Calculate the next Tx descriptor entry. */ int entry = vp->cur_tx % TX_RING_SIZE; struct boom_tx_desc *prev_entry; - unsigned long flags, i; + unsigned long flags; + int i; if (vp->tx_full) /* No room to transmit with */ return 1; -- cgit v1.1 From 9a469abe9c6bab3ce237ee433541931bbd827faf Mon Sep 17 00:00:00 2001 From: Joerg Ahrens Date: Sun, 20 Aug 2006 21:51:57 +0100 Subject: [PATCH] xirc2ps_cs: Cannot reset card in atomic context I am using a Xircom CEM33 pcmcia NIC which has occasional hardware problems. If the netdev watchdog detects a transmit timeout, do_reset is called which msleeps - this is illegal in atomic context. This patch schedules the timeout handling as a workqueue item. Signed-off-by: Daniel Drake Signed-off-by: Jeff Garzik --- drivers/net/pcmcia/xirc2ps_cs.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c index 9bae77c..4122bb4 100644 --- a/drivers/net/pcmcia/xirc2ps_cs.c +++ b/drivers/net/pcmcia/xirc2ps_cs.c @@ -345,6 +345,7 @@ typedef struct local_info_t { void __iomem *dingo_ccr; /* only used for CEM56 cards */ unsigned last_ptr_value; /* last packets transmitted value */ const char *manf_str; + struct work_struct tx_timeout_task; } local_info_t; /**************** @@ -352,6 +353,7 @@ typedef struct local_info_t { */ static int do_start_xmit(struct sk_buff *skb, struct net_device *dev); static void do_tx_timeout(struct net_device *dev); +static void xirc2ps_tx_timeout_task(void *data); static struct net_device_stats *do_get_stats(struct net_device *dev); static void set_addresses(struct net_device *dev); static void set_multicast_list(struct net_device *dev); @@ -589,6 +591,7 @@ xirc2ps_probe(struct pcmcia_device *link) #ifdef HAVE_TX_TIMEOUT dev->tx_timeout = do_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; + INIT_WORK(&local->tx_timeout_task, xirc2ps_tx_timeout_task, dev); #endif return xirc2ps_config(link); @@ -1341,17 +1344,24 @@ xirc2ps_interrupt(int irq, void *dev_id, struct pt_regs *regs) /*====================================================================*/ static void -do_tx_timeout(struct net_device *dev) +xirc2ps_tx_timeout_task(void *data) { - local_info_t *lp = netdev_priv(dev); - printk(KERN_NOTICE "%s: transmit timed out\n", dev->name); - lp->stats.tx_errors++; + struct net_device *dev = data; /* reset the card */ do_reset(dev,1); dev->trans_start = jiffies; netif_wake_queue(dev); } +static void +do_tx_timeout(struct net_device *dev) +{ + local_info_t *lp = netdev_priv(dev); + lp->stats.tx_errors++; + printk(KERN_NOTICE "%s: transmit timed out\n", dev->name); + schedule_work(&lp->tx_timeout_task); +} + static int do_start_xmit(struct sk_buff *skb, struct net_device *dev) { -- cgit v1.1 From 8d91626636ed9ce8b742edb52ae48f2faefd5864 Mon Sep 17 00:00:00 2001 From: Don Fry Date: Tue, 22 Aug 2006 10:22:37 -0700 Subject: [PATCH] pcnet32: break in 2.6.18-rc1 identified A change I made for 2.6.17 and another for 2.6.18 do not work on older pcnet32 chips which I do not have access to. If the chip is a 79C970 or 79C965, do not try and suspend or check the link status. I have tested with a 79C970A, 79C971, 79C972, 79C973, 79C975, 79C976, and 79C978. Signed-off-by: Don Fry Signed-off-by: Jeff Garzik --- drivers/net/pcnet32.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index 4daafe3..d50bcb8 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -202,6 +202,8 @@ static int homepna[MAX_UNITS]; #define CSR15 15 #define PCNET32_MC_FILTER 8 +#define PCNET32_79C970A 0x2621 + /* The PCNET32 Rx and Tx ring descriptors. */ struct pcnet32_rx_head { u32 base; @@ -289,6 +291,7 @@ struct pcnet32_private { /* each bit indicates an available PHY */ u32 phymask; + unsigned short chip_version; /* which variant this is */ }; static int pcnet32_probe_pci(struct pci_dev *, const struct pci_device_id *); @@ -724,9 +727,11 @@ static u32 pcnet32_get_link(struct net_device *dev) spin_lock_irqsave(&lp->lock, flags); if (lp->mii) { r = mii_link_ok(&lp->mii_if); - } else { + } else if (lp->chip_version >= PCNET32_79C970A) { ulong ioaddr = dev->base_addr; /* card base I/O address */ r = (lp->a.read_bcr(ioaddr, 4) != 0xc0); + } else { /* can not detect link on really old chips */ + r = 1; } spin_unlock_irqrestore(&lp->lock, flags); @@ -1091,6 +1096,10 @@ static int pcnet32_suspend(struct net_device *dev, unsigned long *flags, ulong ioaddr = dev->base_addr; int ticks; + /* really old chips have to be stopped. */ + if (lp->chip_version < PCNET32_79C970A) + return 0; + /* set SUSPEND (SPND) - CSR5 bit 0 */ csr5 = a->read_csr(ioaddr, CSR5); a->write_csr(ioaddr, CSR5, csr5 | CSR5_SUSPEND); @@ -1529,6 +1538,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) lp->mii_if.reg_num_mask = 0x1f; lp->dxsuflo = dxsuflo; lp->mii = mii; + lp->chip_version = chip_version; lp->msg_enable = pcnet32_debug; if ((cards_found >= MAX_UNITS) || (options[cards_found] > sizeof(options_mapping))) @@ -1839,10 +1849,7 @@ static int pcnet32_open(struct net_device *dev) val |= 2; } else if (lp->options & PCNET32_PORT_ASEL) { /* workaround of xSeries250, turn on for 79C975 only */ - i = ((lp->a.read_csr(ioaddr, 88) | - (lp->a. - read_csr(ioaddr, 89) << 16)) >> 12) & 0xffff; - if (i == 0x2627) + if (lp->chip_version == 0x2627) val |= 3; } lp->a.write_bcr(ioaddr, 9, val); @@ -1986,9 +1993,11 @@ static int pcnet32_open(struct net_device *dev) netif_start_queue(dev); - /* Print the link status and start the watchdog */ - pcnet32_check_media(dev, 1); - mod_timer(&(lp->watchdog_timer), PCNET32_WATCHDOG_TIMEOUT); + if (lp->chip_version >= PCNET32_79C970A) { + /* Print the link status and start the watchdog */ + pcnet32_check_media(dev, 1); + mod_timer(&(lp->watchdog_timer), PCNET32_WATCHDOG_TIMEOUT); + } i = 0; while (i++ < 100) -- cgit v1.1 From c5ab964debe92d0ec7af330f350a3433c1b5b61e Mon Sep 17 00:00:00 2001 From: Richard Purdie Date: Tue, 22 Aug 2006 18:55:44 +0100 Subject: [PATCH] spectrum_cs: Fix firmware uploading errors spectrum_cs: Fix the logic so we error when the device is *not* present! This fixes firmware upload failures which prevent the driver from working (the bug is also present in 2.6.17). Signed-off-by: Richard Purdie Signed-off-by: Jeff Garzik --- drivers/net/wireless/spectrum_cs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/spectrum_cs.c b/drivers/net/wireless/spectrum_cs.c index 7f78b78..bcc7038 100644 --- a/drivers/net/wireless/spectrum_cs.c +++ b/drivers/net/wireless/spectrum_cs.c @@ -242,7 +242,7 @@ spectrum_reset(struct pcmcia_device *link, int idle) u_int save_cor; /* Doing it if hardware is gone is guaranteed crash */ - if (pcmcia_dev_present(link)) + if (!pcmcia_dev_present(link)) return -ENODEV; /* Save original COR value */ -- cgit v1.1 From f3745a3f9fa39fa3c62f7d5b8549ee787d2c6848 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 22 Aug 2006 21:06:46 +0900 Subject: [PATCH] ata_piix: ignore PCS on ICH5 There have been a number of reports regarding some ICH5s failing to detect devices since the PCS handling update. Analysis shows that these problems are caused by bogus PCS values from those controllers. Before the PCS update, the driver didn't honor PCS regs exactly and probed them in many cases PCS reports no device. Now that PCS is honored exactly, these hardware problems are visible. This patch makes ICH5 ignore PCS. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/scsi/ata_piix.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c index 01b3530..3b98f18 100644 --- a/drivers/scsi/ata_piix.c +++ b/drivers/scsi/ata_piix.c @@ -390,7 +390,8 @@ static struct ata_port_info piix_port_info[] = { /* ich5_sata */ { .sht = &piix_sht, - .host_flags = ATA_FLAG_SATA | PIIX_FLAG_CHECKINTR, + .host_flags = ATA_FLAG_SATA | PIIX_FLAG_CHECKINTR | + PIIX_FLAG_IGNORE_PCS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x7f, /* udma0-6 */ -- cgit v1.1 From 9dd9c16465c82d1385f97d2a245641464fcb7894 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 22 Aug 2006 21:15:58 +0900 Subject: [PATCH] ata_piix: implement force_pcs module parameter This patch implements force_pcs module parameter for ata_piix. If 1, PCS is ignored, 2 honored. As there seem to be quite a few ICHs w/ impaired PCS, this option will be useful for cases where the default setting doesn't work. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/scsi/ata_piix.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c index 3b98f18..2d20caf 100644 --- a/drivers/scsi/ata_piix.c +++ b/drivers/scsi/ata_piix.c @@ -468,6 +468,11 @@ MODULE_LICENSE("GPL"); MODULE_DEVICE_TABLE(pci, piix_pci_tbl); MODULE_VERSION(DRV_VERSION); +static int force_pcs = 0; +module_param(force_pcs, int, 0444); +MODULE_PARM_DESC(force_pcs, "force honoring or ignoring PCS to work around " + "device mis-detection (0=default, 1=ignore PCS, 2=honor PCS)"); + /** * piix_pata_cbl_detect - Probe host controller cable detect info * @ap: Port for which cable detect info is desired @@ -812,6 +817,7 @@ static int __devinit piix_check_450nx_errata(struct pci_dev *ata_dev) } static void __devinit piix_init_pcs(struct pci_dev *pdev, + struct ata_port_info *pinfo, const struct piix_map_db *map_db) { u16 pcs, new_pcs; @@ -825,6 +831,18 @@ static void __devinit piix_init_pcs(struct pci_dev *pdev, pci_write_config_word(pdev, ICH5_PCS, new_pcs); msleep(150); } + + if (force_pcs == 1) { + dev_printk(KERN_INFO, &pdev->dev, + "force ignoring PCS (0x%x)\n", new_pcs); + pinfo[0].host_flags |= PIIX_FLAG_IGNORE_PCS; + pinfo[1].host_flags |= PIIX_FLAG_IGNORE_PCS; + } else if (force_pcs == 2) { + dev_printk(KERN_INFO, &pdev->dev, + "force honoring PCS (0x%x)\n", new_pcs); + pinfo[0].host_flags &= ~PIIX_FLAG_IGNORE_PCS; + pinfo[1].host_flags &= ~PIIX_FLAG_IGNORE_PCS; + } } static void __devinit piix_init_sata_map(struct pci_dev *pdev, @@ -933,7 +951,8 @@ static int piix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) if (host_flags & ATA_FLAG_SATA) { piix_init_sata_map(pdev, port_info, piix_map_db_table[ent->driver_data]); - piix_init_pcs(pdev, piix_map_db_table[ent->driver_data]); + piix_init_pcs(pdev, port_info, + piix_map_db_table[ent->driver_data]); } /* On ICH5, some BIOSen disable the interrupt using the -- cgit v1.1 From ac2164d5e425fa4755bdbab9641d8dab7239b6f5 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 23 Aug 2006 01:00:27 +0900 Subject: [PATCH] sata_via: use old SCR access pattern on vt6420 vt6420 has super-fragile SCR registers which can hang the whole machine if accessed with the wrong timings. This patch makes sata_via use SCR registers only during probing and with the same timings as before (pre new EH), which is proven to work. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/scsi/sata_via.c | 117 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 112 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/sata_via.c b/drivers/scsi/sata_via.c index 03baec2..01d4036 100644 --- a/drivers/scsi/sata_via.c +++ b/drivers/scsi/sata_via.c @@ -74,6 +74,7 @@ enum { static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); static u32 svia_scr_read (struct ata_port *ap, unsigned int sc_reg); static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); +static void vt6420_error_handler(struct ata_port *ap); static const struct pci_device_id svia_pci_tbl[] = { { 0x1106, 0x3149, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt6420 }, @@ -107,7 +108,38 @@ static struct scsi_host_template svia_sht = { .bios_param = ata_std_bios_param, }; -static const struct ata_port_operations svia_sata_ops = { +static const struct ata_port_operations vt6420_sata_ops = { + .port_disable = ata_port_disable, + + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .check_status = ata_check_status, + .exec_command = ata_exec_command, + .dev_select = ata_std_dev_select, + + .bmdma_setup = ata_bmdma_setup, + .bmdma_start = ata_bmdma_start, + .bmdma_stop = ata_bmdma_stop, + .bmdma_status = ata_bmdma_status, + + .qc_prep = ata_qc_prep, + .qc_issue = ata_qc_issue_prot, + .data_xfer = ata_pio_data_xfer, + + .freeze = ata_bmdma_freeze, + .thaw = ata_bmdma_thaw, + .error_handler = vt6420_error_handler, + .post_internal_cmd = ata_bmdma_post_internal_cmd, + + .irq_handler = ata_interrupt, + .irq_clear = ata_bmdma_irq_clear, + + .port_start = ata_port_start, + .port_stop = ata_port_stop, + .host_stop = ata_host_stop, +}; + +static const struct ata_port_operations vt6421_sata_ops = { .port_disable = ata_port_disable, .tf_load = ata_tf_load, @@ -141,13 +173,13 @@ static const struct ata_port_operations svia_sata_ops = { .host_stop = ata_host_stop, }; -static struct ata_port_info svia_port_info = { +static struct ata_port_info vt6420_port_info = { .sht = &svia_sht, .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY, .pio_mask = 0x1f, .mwdma_mask = 0x07, .udma_mask = 0x7f, - .port_ops = &svia_sata_ops, + .port_ops = &vt6420_sata_ops, }; MODULE_AUTHOR("Jeff Garzik"); @@ -170,6 +202,81 @@ static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) outl(val, ap->ioaddr.scr_addr + (4 * sc_reg)); } +/** + * vt6420_prereset - prereset for vt6420 + * @ap: target ATA port + * + * SCR registers on vt6420 are pieces of shit and may hang the + * whole machine completely if accessed with the wrong timing. + * To avoid such catastrophe, vt6420 doesn't provide generic SCR + * access operations, but uses SStatus and SControl only during + * boot probing in controlled way. + * + * As the old (pre EH update) probing code is proven to work, we + * strictly follow the access pattern. + * + * LOCKING: + * Kernel thread context (may sleep) + * + * RETURNS: + * 0 on success, -errno otherwise. + */ +static int vt6420_prereset(struct ata_port *ap) +{ + struct ata_eh_context *ehc = &ap->eh_context; + unsigned long timeout = jiffies + (HZ * 5); + u32 sstatus, scontrol; + int online; + + /* don't do any SCR stuff if we're not loading */ + if (!ATA_PFLAG_LOADING) + goto skip_scr; + + /* Resume phy. This is the old resume sequence from + * __sata_phy_reset(). + */ + svia_scr_write(ap, SCR_CONTROL, 0x300); + svia_scr_read(ap, SCR_CONTROL); /* flush */ + + /* wait for phy to become ready, if necessary */ + do { + msleep(200); + if ((svia_scr_read(ap, SCR_STATUS) & 0xf) != 1) + break; + } while (time_before(jiffies, timeout)); + + /* open code sata_print_link_status() */ + sstatus = svia_scr_read(ap, SCR_STATUS); + scontrol = svia_scr_read(ap, SCR_CONTROL); + + online = (sstatus & 0xf) == 0x3; + + ata_port_printk(ap, KERN_INFO, + "SATA link %s 1.5 Gbps (SStatus %X SControl %X)\n", + online ? "up" : "down", sstatus, scontrol); + + /* SStatus is read one more time */ + svia_scr_read(ap, SCR_STATUS); + + if (!online) { + /* tell EH to bail */ + ehc->i.action &= ~ATA_EH_RESET_MASK; + return 0; + } + + skip_scr: + /* wait for !BSY */ + ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT); + + return 0; +} + +static void vt6420_error_handler(struct ata_port *ap) +{ + return ata_bmdma_drive_eh(ap, vt6420_prereset, ata_std_softreset, + NULL, ata_std_postreset); +} + static const unsigned int svia_bar_sizes[] = { 8, 4, 8, 4, 16, 256 }; @@ -210,7 +317,7 @@ static void vt6421_init_addrs(struct ata_probe_ent *probe_ent, 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; + struct ata_port_info *ppi = &vt6420_port_info; probe_ent = ata_pci_init_native_mode(pdev, &ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY); if (!probe_ent) @@ -239,7 +346,7 @@ static struct ata_probe_ent *vt6421_init_probe_ent(struct pci_dev *pdev) probe_ent->sht = &svia_sht; probe_ent->host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY; - probe_ent->port_ops = &svia_sata_ops; + probe_ent->port_ops = &vt6421_sata_ops; probe_ent->n_ports = N_PORTS; probe_ent->irq = pdev->irq; probe_ent->irq_flags = IRQF_SHARED; -- cgit v1.1 From 8e79a441a4d8a34d64efe93add49b3eefca5cd1c Mon Sep 17 00:00:00 2001 From: Horst Hummel Date: Thu, 24 Aug 2006 13:22:36 +0200 Subject: [S390] dasd PAV enabling. The subsystem check in the PAV code is incorrect, it enables PAV per device instead of per subsystem. Signed-off-by: Horst Hummel Signed-off-by: Martin Schwidefsky --- drivers/s390/block/dasd_devmap.c | 8 ++++---- drivers/s390/block/dasd_eckd.c | 14 +++++++------- 2 files changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index 9d0c6e1..9af02c7 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c @@ -54,11 +54,11 @@ struct dasd_devmap { */ struct dasd_server_ssid_map { struct list_head list; - struct server_id { + struct system_id { char vendor[4]; char serial[15]; + __u16 ssid; } sid; - __u16 ssid; }; static struct list_head dasd_server_ssid_list; @@ -904,14 +904,14 @@ dasd_set_uid(struct ccw_device *cdev, struct dasd_uid *uid) return -ENOMEM; strncpy(srv->sid.vendor, uid->vendor, sizeof(srv->sid.vendor) - 1); strncpy(srv->sid.serial, uid->serial, sizeof(srv->sid.serial) - 1); - srv->ssid = uid->ssid; + srv->sid.ssid = uid->ssid; /* server is already contained ? */ spin_lock(&dasd_devmap_lock); devmap->uid = *uid; list_for_each_entry(tmp, &dasd_server_ssid_list, list) { if (!memcmp(&srv->sid, &tmp->sid, - sizeof(struct dasd_server_ssid_map))) { + sizeof(struct system_id))) { kfree(srv); srv = NULL; break; diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 957ed5d..b7a7fac 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -607,7 +607,7 @@ dasd_eckd_psf_ssc(struct dasd_device *device) * Valide storage server of current device. */ static int -dasd_eckd_validate_server(struct dasd_device *device) +dasd_eckd_validate_server(struct dasd_device *device, struct dasd_uid *uid) { int rc; @@ -616,11 +616,11 @@ dasd_eckd_validate_server(struct dasd_device *device) return 0; rc = dasd_eckd_psf_ssc(device); - if (rc) - /* may be requested feature is not available on server, - * therefore just report error and go ahead */ - DEV_MESSAGE(KERN_INFO, device, - "Perform Subsystem Function returned rc=%d", rc); + /* may be requested feature is not available on server, + * therefore just report error and go ahead */ + DEV_MESSAGE(KERN_INFO, device, + "PSF-SSC on storage subsystem %s.%s.%04x returned rc=%d", + uid->vendor, uid->serial, uid->ssid, rc); /* RE-Read Configuration Data */ return dasd_eckd_read_conf(device); } @@ -666,7 +666,7 @@ dasd_eckd_check_characteristics(struct dasd_device *device) return rc; rc = dasd_set_uid(device->cdev, &uid); if (rc == 1) /* new server found */ - rc = dasd_eckd_validate_server(device); + rc = dasd_eckd_validate_server(device, &uid); if (rc) return rc; -- cgit v1.1 From b2155d0417df9f2b4c0d396b6530b864d9f08623 Mon Sep 17 00:00:00 2001 From: Douglas Gilbert Date: Sat, 19 Aug 2006 00:11:34 -0400 Subject: [SCSI] sg: fix incorrect page problem There's a problem where sg is executing a ->nopage operation on a compound page, it actually calls get_page() on the first page in the compound rather than the page which is being mapped. The fix is to select the correct page by indexing into the compound. Signed-off-by: James Bottomley --- drivers/scsi/sg.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 65eef338..34f9343e 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -18,8 +18,8 @@ * */ -static int sg_version_num = 30533; /* 2 digits for each component */ -#define SG_VERSION_STR "3.5.33" +static int sg_version_num = 30534; /* 2 digits for each component */ +#define SG_VERSION_STR "3.5.34" /* * D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au), notes: @@ -60,7 +60,7 @@ static int sg_version_num = 30533; /* 2 digits for each component */ #ifdef CONFIG_SCSI_PROC_FS #include -static char *sg_version_date = "20050908"; +static char *sg_version_date = "20060818"; static int sg_proc_init(void); static void sg_proc_cleanup(void); @@ -1164,7 +1164,7 @@ sg_vma_nopage(struct vm_area_struct *vma, unsigned long addr, int *type) len = vma->vm_end - sa; len = (len < sg->length) ? len : sg->length; if (offset < len) { - page = sg->page; + page = virt_to_page(page_address(sg->page) + offset); get_page(page); /* increment page count */ break; } -- cgit v1.1 From 9c06938aa458843fb71fa35371f23a3b89317252 Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Wed, 23 Aug 2006 14:54:54 -0700 Subject: [SCSI] qla2xxx: Correct PLOGI retry logic. Original code attempts to retry PLOGIs to fcports that are FCP_TARGETs only. If the driver never performed a successful PLOGI/PRLI, the port-type would never be assigned, and the relogin logic would silently drop the request (and thus the port would not be recognized and registered). The fix is relatively straightforward, drop the FCP_TARGET-only check. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_os.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 1e2b95b..65cbe2f 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -2238,9 +2238,6 @@ qla2x00_do_dpc(void *data) next_loopid = 0; list_for_each_entry(fcport, &ha->fcports, list) { - if (fcport->port_type != FCT_TARGET) - continue; - /* * If the port is not ONLINE then try to login * to it if we haven't run out of retries. -- cgit v1.1 From 476e8978d9ccacfc911bd42e083dd784ad1465b1 Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Wed, 23 Aug 2006 14:54:55 -0700 Subject: [SCSI] qla2xxx: Properly re-enable EFT support after an ISP abort. Software must explicitely re-enable extended firmware tracing after any ISP abort condition. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_init.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 9758dba..8596491 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -3063,6 +3063,7 @@ qla2x00_update_fcports(scsi_qla_host_t *ha) int qla2x00_abort_isp(scsi_qla_host_t *ha) { + int rval; unsigned long flags = 0; uint16_t cnt; srb_t *sp; @@ -3119,6 +3120,16 @@ qla2x00_abort_isp(scsi_qla_host_t *ha) ha->isp_abort_cnt = 0; clear_bit(ISP_ABORT_RETRY, &ha->dpc_flags); + + if (ha->eft) { + rval = qla2x00_trace_control(ha, TC_ENABLE, + ha->eft_dma, EFT_NUM_BUFFERS); + if (rval) { + qla_printk(KERN_WARNING, ha, + "Unable to reinitialize EFT " + "(%d).\n", rval); + } + } } else { /* failed the ISP abort */ ha->flags.online = 1; if (test_bit(ISP_ABORT_RETRY, &ha->dpc_flags)) { -- cgit v1.1 From 15a3758dc9e1c9d862e46acdf607de70c302fa6a Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Wed, 23 Aug 2006 14:54:56 -0700 Subject: [SCSI] qla2xxx: Update version number to 8.01.07-k1. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_version.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index f5826bf..9712590 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -7,9 +7,9 @@ /* * Driver version */ -#define QLA2XXX_VERSION "8.01.05-k4" +#define QLA2XXX_VERSION "8.01.07-k1" #define QLA_DRIVER_MAJOR_VER 8 #define QLA_DRIVER_MINOR_VER 1 -#define QLA_DRIVER_PATCH_VER 5 +#define QLA_DRIVER_PATCH_VER 7 #define QLA_DRIVER_BETA_VER 0 -- cgit v1.1 From 0db99e3359234be181590463184b9959059a9ea9 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Sat, 26 Aug 2006 03:00:22 -0400 Subject: [SCSI] fix scsi_send_eh_cmnd regression The callers of scsi_send_eh_cmnd are setting the cmnd buffer, and then scsi_send_eh_cmnd is copying that updated buffer to the old_cmnd variable. Then after the command runs, we end up copying that old_cmnd var which has the new cmnd to the scsi command buffer. When this command gets recent, all types of fun things happen like getting TUR or START_STOP commands with data and scatterlists. This patch made against scsi-rc-fixes, has the callers of scsi_send_eh_cmnd pass in the command so scsi_send_eh_cmnd can do the right thing. This should go into 2.6.18 since this fixes a regression added when we removed some of the scsi_cmnd fields and replaced them with local variables. Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/scsi_error.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 6a5b731..a8ed5a2 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -460,7 +460,8 @@ static void scsi_eh_done(struct scsi_cmnd *scmd) * Return value: * SUCCESS or FAILED or NEEDS_RETRY **/ -static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, int timeout, int copy_sense) +static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd, + int cmnd_size, int timeout, int copy_sense) { struct scsi_device *sdev = scmd->device; struct Scsi_Host *shost = sdev->host; @@ -490,6 +491,9 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, int timeout, int copy_sense old_cmd_len = scmd->cmd_len; old_use_sg = scmd->use_sg; + memset(scmd->cmnd, 0, sizeof(scmd->cmnd)); + memcpy(scmd->cmnd, cmnd, cmnd_size); + if (copy_sense) { int gfp_mask = GFP_ATOMIC; @@ -610,8 +614,7 @@ static int scsi_request_sense(struct scsi_cmnd *scmd) static unsigned char generic_sense[6] = {REQUEST_SENSE, 0, 0, 0, 252, 0}; - memcpy(scmd->cmnd, generic_sense, sizeof(generic_sense)); - return scsi_send_eh_cmnd(scmd, SENSE_TIMEOUT, 1); + return scsi_send_eh_cmnd(scmd, generic_sense, 6, SENSE_TIMEOUT, 1); } /** @@ -736,10 +739,7 @@ static int scsi_eh_tur(struct scsi_cmnd *scmd) int retry_cnt = 1, rtn; retry_tur: - memcpy(scmd->cmnd, tur_command, sizeof(tur_command)); - - - rtn = scsi_send_eh_cmnd(scmd, SENSE_TIMEOUT, 0); + rtn = scsi_send_eh_cmnd(scmd, tur_command, 6, SENSE_TIMEOUT, 0); SCSI_LOG_ERROR_RECOVERY(3, printk("%s: scmd %p rtn %x\n", __FUNCTION__, scmd, rtn)); @@ -839,8 +839,8 @@ static int scsi_eh_try_stu(struct scsi_cmnd *scmd) if (scmd->device->allow_restart) { int rtn; - memcpy(scmd->cmnd, stu_command, sizeof(stu_command)); - rtn = scsi_send_eh_cmnd(scmd, START_UNIT_TIMEOUT, 0); + rtn = scsi_send_eh_cmnd(scmd, stu_command, 6, + START_UNIT_TIMEOUT, 0); if (rtn == SUCCESS) return 0; } -- cgit v1.1 From 4801bc25f37a969ea773c24d12fd4738541848a1 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Fri, 11 Aug 2006 22:53:08 +0200 Subject: [PATCH] i2c: tps65010 build fixes The tps65010.c driver in the main tree never got updated with build fixes since the last batch of I2C driver changes; and the genirq trigger flags were updated wierdly too. This also includes a minor tweak to reduce the frequency used to poll for unplug-the-AC-power on the TPS chips that don't provide relevant IRQs. It _would_ be nice to sense whether there's even a battery, but that'd normally be an HDQ/1-wire interface to a smart battery, and such APIs aren't standardized. Signed-off-by: David Brownell Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/chips/tps65010.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/chips/tps65010.c b/drivers/i2c/chips/tps65010.c index e7e2704..0be6fd6 100644 --- a/drivers/i2c/chips/tps65010.c +++ b/drivers/i2c/chips/tps65010.c @@ -43,13 +43,12 @@ /*-------------------------------------------------------------------------*/ #define DRIVER_VERSION "2 May 2005" -#define DRIVER_NAME (tps65010_driver.name) +#define DRIVER_NAME (tps65010_driver.driver.name) MODULE_DESCRIPTION("TPS6501x Power Management Driver"); MODULE_LICENSE("GPL"); static unsigned short normal_i2c[] = { 0x48, /* 0x49, */ I2C_CLIENT_END }; -static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; I2C_CLIENT_INSMOD; @@ -100,7 +99,7 @@ struct tps65010 { /* not currently tracking GPIO state */ }; -#define POWER_POLL_DELAY msecs_to_jiffies(800) +#define POWER_POLL_DELAY msecs_to_jiffies(5000) /*-------------------------------------------------------------------------*/ @@ -520,8 +519,11 @@ tps65010_probe(struct i2c_adapter *bus, int address, int kind) goto fail1; } + /* the IRQ is active low, but many gpio lines can't support that + * so this driver can use falling-edge triggers instead. + */ + irqflags = IRQF_SAMPLE_RANDOM; #ifdef CONFIG_ARM - irqflags = IRQF_SAMPLE_RANDOM | IRQF_TRIGGER_LOW; if (machine_is_omap_h2()) { tps->model = TPS65010; omap_cfg_reg(W4_GPIO58); @@ -543,8 +545,6 @@ tps65010_probe(struct i2c_adapter *bus, int address, int kind) // FIXME set up this board's IRQ ... } -#else - irqflags = IRQF_SAMPLE_RANDOM; #endif if (tps->irq > 0) { -- cgit v1.1 From faf9b616325430422fa13fead88ca7843eb249d6 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 25 Aug 2006 10:24:20 +0200 Subject: [PATCH] hwmon: abituguru timeout fixes This patch contains 2 sets of fixes for the abituguru: 1) Much improved timeout handling, drasticly reducing the amount of timeout errors on some motherboards 2) Fix the exit paths in the bank1 sensor type detect code to always restore the original settings even on an error. Without this our special test settings could remain seriously confusing the system BIOS's setup menu. Both are very much related and are must haves, to avoid messing up the uguru CMOS settings. Detailed changes: - Much improved timeout / wait for status handling. Many thanks to Sunil Kumar, for all his testing, ideas and patches! The code now first busy waits, polling the uguru for the expected status as this usually succeeds pretty quickly (within 90 reads). To avoid unnecessary CPU burn in timeout conditions, the amount of busy waiting has been halved from previous versions (120 tries instead of 250). This is not a problem, because this version goes to sleep after 120 attemps for 1 jiffy and then tries again, it does this sleep and try again 5 times before finally giving up. This (almost?) completly removes the timeout errors some people have seen regulary. Apparently some older uguru versions sometimes are distracted for a (relatively) long time. This solves this. - These timeout errors not only occur in the sending address part of reading the uguru but also in the wait for read state, so errors in this state are now handled as retryable just like send address state errors and are only logged and reported to userspace if 3 executive tries fail. - Fix a very nasty bug in the bank1 sensor type detection code, where it would not restore the original settings in any of the error paths! - Since not successfully restoring the original settings can seriously confuse the system BIOS (hang when entering the relevant setup menu), we now try restoring them 3 times before giving up. Signed-off-by: Hans de Goede Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/abituguru.c | 99 +++++++++++++++++++++++++++++------------------ 1 file changed, 61 insertions(+), 38 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/abituguru.c b/drivers/hwmon/abituguru.c index cc15c4f..35ad1b0 100644 --- a/drivers/hwmon/abituguru.c +++ b/drivers/hwmon/abituguru.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -64,17 +65,17 @@ #define ABIT_UGURU_IN_SENSOR 0 #define ABIT_UGURU_TEMP_SENSOR 1 #define ABIT_UGURU_NC 2 -/* Timeouts / Retries, if these turn out to need a lot of fiddling we could - convert them to params. */ -/* 250 was determined by trial and error, 200 works most of the time, but not - always. I assume this is cpu-speed independent, since the ISA-bus and not - the CPU should be the bottleneck. Note that 250 sometimes is still not - enough (only reported on AN7 mb) this is handled by a higher layer. */ -#define ABIT_UGURU_WAIT_TIMEOUT 250 +/* In many cases we need to wait for the uGuru to reach a certain status, most + of the time it will reach this status within 30 - 90 ISA reads, and thus we + can best busy wait. This define gives the total amount of reads to try. */ +#define ABIT_UGURU_WAIT_TIMEOUT 125 +/* However sometimes older versions of the uGuru seem to be distracted and they + do not respond for a long time. To handle this we sleep before each of the + last ABIT_UGURU_WAIT_TIMEOUT_SLEEP tries. */ +#define ABIT_UGURU_WAIT_TIMEOUT_SLEEP 5 /* Normally all expected status in abituguru_ready, are reported after the - first read, but sometimes not and we need to poll, 5 polls was not enough - 50 sofar is. */ -#define ABIT_UGURU_READY_TIMEOUT 50 + first read, but sometimes not and we need to poll. */ +#define ABIT_UGURU_READY_TIMEOUT 5 /* Maximum 3 retries on timedout reads/writes, delay 200 ms before retrying */ #define ABIT_UGURU_MAX_RETRIES 3 #define ABIT_UGURU_RETRY_DELAY (HZ/5) @@ -226,6 +227,10 @@ static int abituguru_wait(struct abituguru_data *data, u8 state) timeout--; if (timeout == 0) return -EBUSY; + /* sleep a bit before our last few tries, see the comment on + this where ABIT_UGURU_WAIT_TIMEOUT_SLEEP is defined. */ + if (timeout <= ABIT_UGURU_WAIT_TIMEOUT_SLEEP) + msleep(0); } return 0; } @@ -256,6 +261,7 @@ static int abituguru_ready(struct abituguru_data *data) "CMD reg does not hold 0xAC after ready command\n"); return -EIO; } + msleep(0); } /* After this the ABIT_UGURU_DATA port should contain @@ -268,6 +274,7 @@ static int abituguru_ready(struct abituguru_data *data) "state != more input after ready command\n"); return -EIO; } + msleep(0); } data->uguru_ready = 1; @@ -331,7 +338,8 @@ static int abituguru_read(struct abituguru_data *data, /* And read the data */ for (i = 0; i < count; i++) { if (abituguru_wait(data, ABIT_UGURU_STATUS_READ)) { - ABIT_UGURU_DEBUG(1, "timeout exceeded waiting for " + ABIT_UGURU_DEBUG(retries ? 1 : 3, + "timeout exceeded waiting for " "read state (bank: %d, sensor: %d)\n", (int)bank_addr, (int)sensor_addr); break; @@ -350,7 +358,9 @@ static int abituguru_read(struct abituguru_data *data, static int abituguru_write(struct abituguru_data *data, u8 bank_addr, u8 sensor_addr, u8 *buf, int count) { - int i; + /* We use the ready timeout as we have to wait for 0xAC just like the + ready function */ + int i, timeout = ABIT_UGURU_READY_TIMEOUT; /* Send the address */ i = abituguru_send_address(data, bank_addr, sensor_addr, @@ -370,7 +380,8 @@ static int abituguru_write(struct abituguru_data *data, } /* Now we need to wait till the chip is ready to be read again, - don't ask why */ + so that we can read 0xAC as confirmation that our write has + succeeded. */ if (abituguru_wait(data, ABIT_UGURU_STATUS_READ)) { ABIT_UGURU_DEBUG(1, "timeout exceeded waiting for read state " "after write (bank: %d, sensor: %d)\n", (int)bank_addr, @@ -379,11 +390,15 @@ static int abituguru_write(struct abituguru_data *data, } /* Cmd port MUST be read now and should contain 0xAC */ - if (inb_p(data->addr + ABIT_UGURU_CMD) != 0xAC) { - ABIT_UGURU_DEBUG(1, "CMD reg does not hold 0xAC after write " - "(bank: %d, sensor: %d)\n", (int)bank_addr, - (int)sensor_addr); - return -EIO; + while (inb_p(data->addr + ABIT_UGURU_CMD) != 0xAC) { + timeout--; + if (timeout == 0) { + ABIT_UGURU_DEBUG(1, "CMD reg does not hold 0xAC after " + "write (bank: %d, sensor: %d)\n", + (int)bank_addr, (int)sensor_addr); + return -EIO; + } + msleep(0); } /* Last put the chip back in ready state */ @@ -403,7 +418,7 @@ abituguru_detect_bank1_sensor_type(struct abituguru_data *data, u8 sensor_addr) { u8 val, buf[3]; - int ret = ABIT_UGURU_NC; + int i, ret = -ENODEV; /* error is the most common used retval :| */ /* If overriden by the user return the user selected type */ if (bank1_types[sensor_addr] >= ABIT_UGURU_IN_SENSOR && @@ -439,7 +454,7 @@ abituguru_detect_bank1_sensor_type(struct abituguru_data *data, buf[2] = 250; if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK1 + 2, sensor_addr, buf, 3) != 3) - return -ENODEV; + goto abituguru_detect_bank1_sensor_type_exit; /* Now we need 20 ms to give the uguru time to read the sensors and raise a voltage alarm */ set_current_state(TASK_UNINTERRUPTIBLE); @@ -447,21 +462,16 @@ abituguru_detect_bank1_sensor_type(struct abituguru_data *data, /* Check for alarm and check the alarm is a volt low alarm. */ if (abituguru_read(data, ABIT_UGURU_ALARM_BANK, 0, buf, 3, ABIT_UGURU_MAX_RETRIES) != 3) - return -ENODEV; + goto abituguru_detect_bank1_sensor_type_exit; if (buf[sensor_addr/8] & (0x01 << (sensor_addr % 8))) { if (abituguru_read(data, ABIT_UGURU_SENSOR_BANK1 + 1, sensor_addr, buf, 3, ABIT_UGURU_MAX_RETRIES) != 3) - return -ENODEV; + goto abituguru_detect_bank1_sensor_type_exit; if (buf[0] & ABIT_UGURU_VOLT_LOW_ALARM_FLAG) { - /* Restore original settings */ - if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK1 + 2, - sensor_addr, - data->bank1_settings[sensor_addr], - 3) != 3) - return -ENODEV; ABIT_UGURU_DEBUG(2, " found volt sensor\n"); - return ABIT_UGURU_IN_SENSOR; + ret = ABIT_UGURU_IN_SENSOR; + goto abituguru_detect_bank1_sensor_type_exit; } else ABIT_UGURU_DEBUG(2, " alarm raised during volt " "sensor test, but volt low flag not set\n"); @@ -477,7 +487,7 @@ abituguru_detect_bank1_sensor_type(struct abituguru_data *data, buf[2] = 10; if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK1 + 2, sensor_addr, buf, 3) != 3) - return -ENODEV; + goto abituguru_detect_bank1_sensor_type_exit; /* Now we need 50 ms to give the uguru time to read the sensors and raise a temp alarm */ set_current_state(TASK_UNINTERRUPTIBLE); @@ -485,15 +495,16 @@ abituguru_detect_bank1_sensor_type(struct abituguru_data *data, /* Check for alarm and check the alarm is a temp high alarm. */ if (abituguru_read(data, ABIT_UGURU_ALARM_BANK, 0, buf, 3, ABIT_UGURU_MAX_RETRIES) != 3) - return -ENODEV; + goto abituguru_detect_bank1_sensor_type_exit; if (buf[sensor_addr/8] & (0x01 << (sensor_addr % 8))) { if (abituguru_read(data, ABIT_UGURU_SENSOR_BANK1 + 1, sensor_addr, buf, 3, ABIT_UGURU_MAX_RETRIES) != 3) - return -ENODEV; + goto abituguru_detect_bank1_sensor_type_exit; if (buf[0] & ABIT_UGURU_TEMP_HIGH_ALARM_FLAG) { - ret = ABIT_UGURU_TEMP_SENSOR; ABIT_UGURU_DEBUG(2, " found temp sensor\n"); + ret = ABIT_UGURU_TEMP_SENSOR; + goto abituguru_detect_bank1_sensor_type_exit; } else ABIT_UGURU_DEBUG(2, " alarm raised during temp " "sensor test, but temp high flag not set\n"); @@ -501,11 +512,23 @@ abituguru_detect_bank1_sensor_type(struct abituguru_data *data, ABIT_UGURU_DEBUG(2, " alarm not raised during temp sensor " "test\n"); - /* Restore original settings */ - if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK1 + 2, sensor_addr, - data->bank1_settings[sensor_addr], 3) != 3) + ret = ABIT_UGURU_NC; +abituguru_detect_bank1_sensor_type_exit: + /* Restore original settings, failing here is really BAD, it has been + reported that some BIOS-es hang when entering the uGuru menu with + invalid settings present in the uGuru, so we try this 3 times. */ + for (i = 0; i < 3; i++) + if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK1 + 2, + sensor_addr, data->bank1_settings[sensor_addr], + 3) == 3) + break; + if (i == 3) { + printk(KERN_ERR ABIT_UGURU_NAME + ": Fatal error could not restore original settings. " + "This should never happen please report this to the " + "abituguru maintainer (see MAINTAINERS)\n"); return -ENODEV; - + } return ret; } @@ -1305,7 +1328,7 @@ static struct abituguru_data *abituguru_update_device(struct device *dev) data->update_timeouts = 0; LEAVE_UPDATE: /* handle timeout condition */ - if (err == -EBUSY) { + if (!success && (err == -EBUSY || err >= 0)) { /* No overflow please */ if (data->update_timeouts < 255u) data->update_timeouts++; -- cgit v1.1 From 65ae4dddbb56c7415c31e9aae0b3811cb583bbea Mon Sep 17 00:00:00 2001 From: Daniel Ritz Date: Tue, 22 Aug 2006 07:29:10 -0700 Subject: [PATCH] PCI: fix ICH6 quirks - add the ICH6(R) LPC to the ICH6 ACPI quirks. currently only the ICH6-M is handled. [ PCI_DEVICE_ID_INTEL_ICH6_1 is the ICH6-M LPC, ICH6_0 is the ICH6(R) ] - remove the wrong quirk calling asus_hides_smbus_lpc() for ICH6. the register modified in asus_hides_smbus_lpc() has a different meaning in ICH6. Signed-off-by: Daniel Ritz Acked-by: Jean Delvare Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/pci/quirks.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 04618d4..7317742 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -438,6 +438,7 @@ static void __devinit quirk_ich6_lpc_acpi(struct pci_dev *dev) 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_0, quirk_ich6_lpc_acpi ); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, quirk_ich6_lpc_acpi ); /* @@ -1091,7 +1092,6 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, asu DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, asus_hides_smbus_lpc ); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, asus_hides_smbus_lpc ); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, asus_hides_smbus_lpc ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, asus_hides_smbus_lpc ); static void __init asus_hides_smbus_lpc_ich6(struct pci_dev *dev) { -- cgit v1.1 From cc702c2c5e5ab51e1b0d3386d447e7b1772879ee Mon Sep 17 00:00:00 2001 From: Scott Murray Date: Tue, 22 Aug 2006 19:55:57 -0400 Subject: [PATCH] CPCI hotplug: fix resource assignment Here is a patch against the CPCI hotplug core to fix up PCI resource assignment such that things will actually work when a hot inserted device is enabled. I mentioned this patch to you way back in April at ELC, but am only now out from under things enough to clean it up and submit it. I've basically cribbed the corresponding code from shpchp_pci.c, so there are no big surprises. If it's still possible, I wouldn't mind this going into 2.6.18, but it wouldn't be the end of the world if it went into 2.6.19. Signed-off-by: Scott Murray Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/cpci_hotplug_pci.c | 54 ++++++++++++++++++++++++++-------- 1 file changed, 42 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/hotplug/cpci_hotplug_pci.c b/drivers/pci/hotplug/cpci_hotplug_pci.c index 02be74c..4afcaff 100644 --- a/drivers/pci/hotplug/cpci_hotplug_pci.c +++ b/drivers/pci/hotplug/cpci_hotplug_pci.c @@ -254,8 +254,8 @@ int cpci_led_off(struct slot* slot) int cpci_configure_slot(struct slot* slot) { - unsigned char busnr; - struct pci_bus *child; + struct pci_bus *parent; + int fn; dbg("%s - enter", __FUNCTION__); @@ -276,23 +276,53 @@ int cpci_configure_slot(struct slot* slot) */ n = pci_scan_slot(slot->bus, slot->devfn); dbg("%s: pci_scan_slot returned %d", __FUNCTION__, n); - if (n > 0) - pci_bus_add_devices(slot->bus); slot->dev = pci_get_slot(slot->bus, slot->devfn); if (slot->dev == NULL) { err("Could not find PCI device for slot %02x", slot->number); - return 1; + return -ENODEV; } } - - if (slot->dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { - pci_read_config_byte(slot->dev, PCI_SECONDARY_BUS, &busnr); - child = pci_add_new_bus(slot->dev->bus, slot->dev, busnr); - pci_do_scan_bus(child); - pci_bus_size_bridges(child); + parent = slot->dev->bus; + + for (fn = 0; fn < 8; fn++) { + struct pci_dev *dev; + + dev = pci_get_slot(parent, PCI_DEVFN(PCI_SLOT(slot->devfn), fn)); + if (!dev) + continue; + 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; + } + if (busnr >= end) { + err("No free bus for hot-added bridge\n"); + pci_dev_put(dev); + continue; + } + child = pci_add_new_bus(parent, dev, busnr); + if (!child) { + err("Cannot add new bus for %s\n", + pci_name(dev)); + pci_dev_put(dev); + continue; + } + child->subordinate = pci_do_scan_bus(child); + pci_bus_size_bridges(child); + } + pci_dev_put(dev); } - pci_bus_assign_resources(slot->dev->bus); + pci_bus_assign_resources(parent); + pci_bus_add_devices(parent); + pci_enable_bridges(parent); dbg("%s - exit", __FUNCTION__); return 0; -- cgit v1.1 From 39ba487fe22a63b3df7c543c82d01db0f0fed700 Mon Sep 17 00:00:00 2001 From: Henrik Kretzschmar Date: Tue, 15 Aug 2006 10:57:16 +0200 Subject: [PATCH] PCI: kerneldoc correction in pci-driver Removes an unused kerneldoc entry from pci_match_device and put the others into correct order. Signed-off-by: Henrik Kretzschmar Signed-off-by: Greg Kroah-Hartman --- drivers/pci/pci-driver.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 10e1a90..474e9cd 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -139,9 +139,8 @@ const struct pci_device_id *pci_match_id(const struct pci_device_id *ids, /** * pci_match_device - 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 PCI driver to match against + * @dev: the PCI device structure to match against * * Used by a driver to check whether a PCI device present in the * system is in its list of supported devices. Returns the matching -- cgit v1.1 From b93b58eea81beacac55770dd39e34fbffdc36000 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 14 Aug 2006 17:32:51 -0700 Subject: [PATCH] USB: fix bug in cypress_cy7c63.c driver This was pointed out by Adrian Bunk , as found by the Coverity Checker. Cc: Adrian Bunk Cc: Oliver Bock Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/cypress_cy7c63.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/misc/cypress_cy7c63.c b/drivers/usb/misc/cypress_cy7c63.c index a4062a6..9c46746 100644 --- a/drivers/usb/misc/cypress_cy7c63.c +++ b/drivers/usb/misc/cypress_cy7c63.c @@ -208,7 +208,7 @@ static int cypress_probe(struct usb_interface *interface, /* allocate memory for our device state and initialize it */ dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (dev == NULL) { - dev_err(&dev->udev->dev, "Out of memory!\n"); + dev_err(&interface->dev, "Out of memory!\n"); goto error; } -- cgit v1.1 From be729523369ec7825bde4a0e774ee7932e9d3dff Mon Sep 17 00:00:00 2001 From: Tomasz Kazmierczak Date: Fri, 18 Aug 2006 23:43:29 +0200 Subject: [PATCH] USB: pl2303: removed support for OTi's DKU-5 clone cable This patch removes support for a clone of Nokia DKU-5 cable made by Ours Technology Inc, as it turned out that the cable does not use the pl2303 chip, but OTI-6858 chip which is not compatible with the pl2303. Signed-off-by: Tomasz Kazmierczak Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/pl2303.c | 1 - drivers/usb/serial/pl2303.h | 4 ---- 2 files changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index efbbc0a..65e4d04 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -79,7 +79,6 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(SAGEM_VENDOR_ID, SAGEM_PRODUCT_ID) }, { USB_DEVICE(LEADTEK_VENDOR_ID, LEADTEK_9531_PRODUCT_ID) }, { USB_DEVICE(SPEEDDRAGON_VENDOR_ID, SPEEDDRAGON_PRODUCT_ID) }, - { USB_DEVICE(OTI_VENDOR_ID, OTI_PRODUCT_ID) }, { USB_DEVICE(DATAPILOT_U2_VENDOR_ID, DATAPILOT_U2_PRODUCT_ID) }, { USB_DEVICE(BELKIN_VENDOR_ID, BELKIN_PRODUCT_ID) }, { } /* Terminating entry */ diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h index a692ac6..55195e7 100644 --- a/drivers/usb/serial/pl2303.h +++ b/drivers/usb/serial/pl2303.h @@ -82,10 +82,6 @@ #define SPEEDDRAGON_VENDOR_ID 0x0e55 #define SPEEDDRAGON_PRODUCT_ID 0x110b -/* Ours Technology Inc DKU-5 clone, chipset: Prolific Technology Inc */ -#define OTI_VENDOR_ID 0x0ea0 -#define OTI_PRODUCT_ID 0x6858 - /* DATAPILOT Universal-2 Phone Cable */ #define DATAPILOT_U2_VENDOR_ID 0x0731 #define DATAPILOT_U2_PRODUCT_ID 0x2003 -- cgit v1.1 From 94918ff68a7c78fdd3241d13e18444ef80b8ff4a Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 14 Aug 2006 11:40:46 -0400 Subject: [PATCH] unusual_devs update for UCR-61S2B The existing unusual_devs entry for the UCR-61S2B appears to have too wide a revision range. It matches at least one device that doesn't respond to the initialization sequence. Perhaps the sequence needs to be updated, or perhaps something else can be done. For now, this patch (as764) restricts the range to include only the revision mentioned in the original comment. This resolves (for now!) Bugzilla entry #6950. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/unusual_devs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index fd158e0..4a803d6 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -1261,7 +1261,7 @@ UNUSUAL_DEV( 0x0fce, 0xd008, 0x0000, 0x0000, * Tested on hardware version 1.10. * Entry is needed only for the initializer function override. */ -UNUSUAL_DEV( 0x1019, 0x0c55, 0x0000, 0x9999, +UNUSUAL_DEV( 0x1019, 0x0c55, 0x0110, 0x0110, "Desknote", "UCR-61S2B", US_SC_DEVICE, US_PR_DEVICE, usb_stor_ucr61s2b_init, -- cgit v1.1 From 9a654518e1b774b8e8f74a819fd12a931e7672c9 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Sun, 27 Aug 2006 01:23:22 -0700 Subject: [PATCH] drivers/rtc: fix rtc-s3c.c In the cleanups of drivers/rtc/s3c-rtc.c, the base address for the registers got broken. This patch fixes that by ensuring the readb/writeb are all prefixed with the base returned from ioremap()ing the registers. Also fix check for valid year range, which was the wrong way around. Signed-off-by: Ben Dooks Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-s3c.c | 121 ++++++++++++++++++++++++++++---------------------- 1 file changed, 67 insertions(+), 54 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index d6d1bff..aacbfea 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -69,12 +69,12 @@ static void s3c_rtc_setaie(int to) pr_debug("%s: aie=%d\n", __FUNCTION__, to); - tmp = readb(S3C2410_RTCALM) & ~S3C2410_RTCALM_ALMEN; + tmp = readb(s3c_rtc_base + S3C2410_RTCALM) & ~S3C2410_RTCALM_ALMEN; if (to) tmp |= S3C2410_RTCALM_ALMEN; - writeb(tmp, S3C2410_RTCALM); + writeb(tmp, s3c_rtc_base + S3C2410_RTCALM); } static void s3c_rtc_setpie(int to) @@ -84,12 +84,12 @@ static void s3c_rtc_setpie(int to) pr_debug("%s: pie=%d\n", __FUNCTION__, to); spin_lock_irq(&s3c_rtc_pie_lock); - tmp = readb(S3C2410_TICNT) & ~S3C2410_TICNT_ENABLE; + tmp = readb(s3c_rtc_base + S3C2410_TICNT) & ~S3C2410_TICNT_ENABLE; if (to) tmp |= S3C2410_TICNT_ENABLE; - writeb(tmp, S3C2410_TICNT); + writeb(tmp, s3c_rtc_base + S3C2410_TICNT); spin_unlock_irq(&s3c_rtc_pie_lock); } @@ -98,13 +98,13 @@ static void s3c_rtc_setfreq(int freq) unsigned int tmp; spin_lock_irq(&s3c_rtc_pie_lock); - tmp = readb(S3C2410_TICNT) & S3C2410_TICNT_ENABLE; + tmp = readb(s3c_rtc_base + S3C2410_TICNT) & S3C2410_TICNT_ENABLE; s3c_rtc_freq = freq; tmp |= (128 / freq)-1; - writeb(tmp, S3C2410_TICNT); + writeb(tmp, s3c_rtc_base + S3C2410_TICNT); spin_unlock_irq(&s3c_rtc_pie_lock); } @@ -113,14 +113,15 @@ static void s3c_rtc_setfreq(int freq) static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm) { unsigned int have_retried = 0; + void __iomem *base = s3c_rtc_base; retry_get_time: - rtc_tm->tm_min = readb(S3C2410_RTCMIN); - rtc_tm->tm_hour = readb(S3C2410_RTCHOUR); - rtc_tm->tm_mday = readb(S3C2410_RTCDATE); - rtc_tm->tm_mon = readb(S3C2410_RTCMON); - rtc_tm->tm_year = readb(S3C2410_RTCYEAR); - rtc_tm->tm_sec = readb(S3C2410_RTCSEC); + rtc_tm->tm_min = readb(base + S3C2410_RTCMIN); + rtc_tm->tm_hour = readb(base + S3C2410_RTCHOUR); + rtc_tm->tm_mday = readb(base + S3C2410_RTCDATE); + rtc_tm->tm_mon = readb(base + S3C2410_RTCMON); + rtc_tm->tm_year = readb(base + S3C2410_RTCYEAR); + rtc_tm->tm_sec = readb(base + S3C2410_RTCSEC); /* the only way to work out wether the system was mid-update * when we read it is to check the second counter, and if it @@ -151,17 +152,25 @@ static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm) static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm) { + void __iomem *base = s3c_rtc_base; + /* the rtc gets round the y2k problem by just not supporting it */ - if (tm->tm_year < 100) + if (tm->tm_year > 100) { + dev_err(dev, "rtc only supports 100 years\n"); return -EINVAL; + } + + pr_debug("set time %02d.%02d.%02d %02d/%02d/%02d\n", + tm->tm_year, tm->tm_mon, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec); - writeb(BIN2BCD(tm->tm_sec), S3C2410_RTCSEC); - writeb(BIN2BCD(tm->tm_min), S3C2410_RTCMIN); - writeb(BIN2BCD(tm->tm_hour), S3C2410_RTCHOUR); - writeb(BIN2BCD(tm->tm_mday), S3C2410_RTCDATE); - writeb(BIN2BCD(tm->tm_mon + 1), S3C2410_RTCMON); - writeb(BIN2BCD(tm->tm_year - 100), S3C2410_RTCYEAR); + writeb(BIN2BCD(tm->tm_sec), base + S3C2410_RTCSEC); + writeb(BIN2BCD(tm->tm_min), base + S3C2410_RTCMIN); + writeb(BIN2BCD(tm->tm_hour), base + S3C2410_RTCHOUR); + writeb(BIN2BCD(tm->tm_mday), base + S3C2410_RTCDATE); + writeb(BIN2BCD(tm->tm_mon + 1), base + S3C2410_RTCMON); + writeb(BIN2BCD(tm->tm_year - 100), base + S3C2410_RTCYEAR); return 0; } @@ -169,16 +178,17 @@ static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm) static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm) { struct rtc_time *alm_tm = &alrm->time; + void __iomem *base = s3c_rtc_base; unsigned int alm_en; - alm_tm->tm_sec = readb(S3C2410_ALMSEC); - alm_tm->tm_min = readb(S3C2410_ALMMIN); - alm_tm->tm_hour = readb(S3C2410_ALMHOUR); - alm_tm->tm_mon = readb(S3C2410_ALMMON); - alm_tm->tm_mday = readb(S3C2410_ALMDATE); - alm_tm->tm_year = readb(S3C2410_ALMYEAR); + alm_tm->tm_sec = readb(base + S3C2410_ALMSEC); + alm_tm->tm_min = readb(base + S3C2410_ALMMIN); + alm_tm->tm_hour = readb(base + S3C2410_ALMHOUR); + alm_tm->tm_mon = readb(base + S3C2410_ALMMON); + alm_tm->tm_mday = readb(base + S3C2410_ALMDATE); + alm_tm->tm_year = readb(base + S3C2410_ALMYEAR); - alm_en = readb(S3C2410_RTCALM); + alm_en = readb(base + S3C2410_RTCALM); pr_debug("read alarm %02x %02x.%02x.%02x %02x/%02x/%02x\n", alm_en, @@ -226,6 +236,7 @@ static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm) static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) { struct rtc_time *tm = &alrm->time; + void __iomem *base = s3c_rtc_base; unsigned int alrm_en; pr_debug("s3c_rtc_setalarm: %d, %02x/%02x/%02x %02x.%02x.%02x\n", @@ -234,32 +245,32 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) tm->tm_hour & 0xff, tm->tm_min & 0xff, tm->tm_sec); - alrm_en = readb(S3C2410_RTCALM) & S3C2410_RTCALM_ALMEN; - writeb(0x00, S3C2410_RTCALM); + alrm_en = readb(base + S3C2410_RTCALM) & S3C2410_RTCALM_ALMEN; + writeb(0x00, base + S3C2410_RTCALM); if (tm->tm_sec < 60 && tm->tm_sec >= 0) { alrm_en |= S3C2410_RTCALM_SECEN; - writeb(BIN2BCD(tm->tm_sec), S3C2410_ALMSEC); + writeb(BIN2BCD(tm->tm_sec), base + S3C2410_ALMSEC); } if (tm->tm_min < 60 && tm->tm_min >= 0) { alrm_en |= S3C2410_RTCALM_MINEN; - writeb(BIN2BCD(tm->tm_min), S3C2410_ALMMIN); + writeb(BIN2BCD(tm->tm_min), base + S3C2410_ALMMIN); } if (tm->tm_hour < 24 && tm->tm_hour >= 0) { alrm_en |= S3C2410_RTCALM_HOUREN; - writeb(BIN2BCD(tm->tm_hour), S3C2410_ALMHOUR); + writeb(BIN2BCD(tm->tm_hour), base + S3C2410_ALMHOUR); } pr_debug("setting S3C2410_RTCALM to %08x\n", alrm_en); - writeb(alrm_en, S3C2410_RTCALM); + writeb(alrm_en, base + S3C2410_RTCALM); if (0) { - alrm_en = readb(S3C2410_RTCALM); + alrm_en = readb(base + S3C2410_RTCALM); alrm_en &= ~S3C2410_RTCALM_ALMEN; - writeb(alrm_en, S3C2410_RTCALM); + writeb(alrm_en, base + S3C2410_RTCALM); disable_irq_wake(s3c_rtc_alarmno); } @@ -319,8 +330,8 @@ static int s3c_rtc_ioctl(struct device *dev, static int s3c_rtc_proc(struct device *dev, struct seq_file *seq) { - unsigned int rtcalm = readb(S3C2410_RTCALM); - unsigned int ticnt = readb (S3C2410_TICNT); + unsigned int rtcalm = readb(s3c_rtc_base + S3C2410_RTCALM); + unsigned int ticnt = readb(s3c_rtc_base + S3C2410_TICNT); seq_printf(seq, "alarm_IRQ\t: %s\n", (rtcalm & S3C2410_RTCALM_ALMEN) ? "yes" : "no" ); @@ -387,39 +398,40 @@ static struct rtc_class_ops s3c_rtcops = { static void s3c_rtc_enable(struct platform_device *pdev, int en) { + void __iomem *base = s3c_rtc_base; unsigned int tmp; if (s3c_rtc_base == NULL) return; if (!en) { - tmp = readb(S3C2410_RTCCON); - writeb(tmp & ~S3C2410_RTCCON_RTCEN, S3C2410_RTCCON); + tmp = readb(base + S3C2410_RTCCON); + writeb(tmp & ~S3C2410_RTCCON_RTCEN, base + S3C2410_RTCCON); - tmp = readb(S3C2410_TICNT); - writeb(tmp & ~S3C2410_TICNT_ENABLE, S3C2410_TICNT); + tmp = readb(base + S3C2410_TICNT); + writeb(tmp & ~S3C2410_TICNT_ENABLE, base + S3C2410_TICNT); } else { /* re-enable the device, and check it is ok */ - if ((readb(S3C2410_RTCCON) & S3C2410_RTCCON_RTCEN) == 0){ + if ((readb(base+S3C2410_RTCCON) & S3C2410_RTCCON_RTCEN) == 0){ dev_info(&pdev->dev, "rtc disabled, re-enabling\n"); - tmp = readb(S3C2410_RTCCON); - writeb(tmp | S3C2410_RTCCON_RTCEN , S3C2410_RTCCON); + tmp = readb(base + S3C2410_RTCCON); + writeb(tmp|S3C2410_RTCCON_RTCEN, base+S3C2410_RTCCON); } - if ((readb(S3C2410_RTCCON) & S3C2410_RTCCON_CNTSEL)){ + if ((readb(base + S3C2410_RTCCON) & S3C2410_RTCCON_CNTSEL)){ dev_info(&pdev->dev, "removing RTCCON_CNTSEL\n"); - tmp = readb(S3C2410_RTCCON); - writeb(tmp& ~S3C2410_RTCCON_CNTSEL , S3C2410_RTCCON); + tmp = readb(base + S3C2410_RTCCON); + writeb(tmp& ~S3C2410_RTCCON_CNTSEL, base+S3C2410_RTCCON); } - if ((readb(S3C2410_RTCCON) & S3C2410_RTCCON_CLKRST)){ + if ((readb(base + S3C2410_RTCCON) & S3C2410_RTCCON_CLKRST)){ dev_info(&pdev->dev, "removing RTCCON_CLKRST\n"); - tmp = readb(S3C2410_RTCCON); - writeb(tmp & ~S3C2410_RTCCON_CLKRST, S3C2410_RTCCON); + tmp = readb(base + S3C2410_RTCCON); + writeb(tmp & ~S3C2410_RTCCON_CLKRST, base+S3C2410_RTCCON); } } } @@ -475,8 +487,8 @@ static int s3c_rtc_probe(struct platform_device *pdev) } s3c_rtc_mem = request_mem_region(res->start, - res->end-res->start+1, - pdev->name); + res->end-res->start+1, + pdev->name); if (s3c_rtc_mem == NULL) { dev_err(&pdev->dev, "failed to reserve memory region\n"); @@ -495,7 +507,8 @@ static int s3c_rtc_probe(struct platform_device *pdev) s3c_rtc_enable(pdev, 1); - pr_debug("s3c2410_rtc: RTCCON=%02x\n", readb(S3C2410_RTCCON)); + pr_debug("s3c2410_rtc: RTCCON=%02x\n", + readb(s3c_rtc_base + S3C2410_RTCCON)); s3c_rtc_setfreq(s3c_rtc_freq); @@ -543,7 +556,7 @@ static int s3c_rtc_suspend(struct platform_device *pdev, pm_message_t state) /* save TICNT for anyone using periodic interrupts */ - ticnt_save = readb(S3C2410_TICNT); + ticnt_save = readb(s3c_rtc_base + S3C2410_TICNT); /* calculate time delta for suspend */ @@ -567,7 +580,7 @@ static int s3c_rtc_resume(struct platform_device *pdev) rtc_tm_to_time(&tm, &time.tv_sec); restore_time_delta(&s3c_rtc_delta, &time); - writeb(ticnt_save, S3C2410_TICNT); + writeb(ticnt_save, s3c_rtc_base + S3C2410_TICNT); return 0; } #else -- cgit v1.1 From c06aad854fdb9da38fcc22dccfe9d72919453e43 Mon Sep 17 00:00:00 2001 From: Daniel Kobras Date: Sun, 27 Aug 2006 01:23:24 -0700 Subject: [PATCH] dm: Fix deadlock under high i/o load in raid1 setup. On an nForce4-equipped machine with two SATA disk in raid1 setup using dmraid, we experienced frequent deadlock of the system under high i/o load. 'cat /dev/zero > ~/zero' was the most reliable way to reproduce them: Randomly after a few GB, 'cp' would be left in 'D' state along with kjournald and kmirrord. The functions cp and kjournald were blocked in did vary, but kmirrord's wchan always pointed to 'mempool_alloc()'. We've seen this pattern on 2.6.15 and 2.6.17 kernels. http://lkml.org/lkml/2005/4/20/142 indicates that this problem has been around even before. So much for the facts, here's my interpretation: mempool_alloc() first tries to atomically allocate the requested memory, or falls back to hand out preallocated chunks from the mempool. If both fail, it puts the calling process (kmirrord in this case) on a private waitqueue until somebody refills the pool. Where the only 'somebody' is kmirrord itself, so we have a deadlock. I worked around this problem by falling back to a (blocking) kmalloc when before kmirrord would have ended up on the waitqueue. This defeats part of the benefits of using the mempool, but at least keeps the system running. And it could be done with a two-line change. Note that mempool_alloc() clears the GFP_NOIO flag internally, and only uses it to decide whether to wait or return an error if immediate allocation fails, so the attached patch doesn't change behaviour in the non-deadlocking case. Path is against current git (2.6.18-rc4), but should apply to earlier versions as well. I've tested on 2.6.15, where this patch makes the difference between random lockup and a stable system. Signed-off-by: Daniel Kobras Acked-by: Alasdair G Kergon Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/md/dm-raid1.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c index be48ced..c54de98 100644 --- a/drivers/md/dm-raid1.c +++ b/drivers/md/dm-raid1.c @@ -255,7 +255,9 @@ static struct region *__rh_alloc(struct region_hash *rh, region_t region) struct region *reg, *nreg; read_unlock(&rh->hash_lock); - nreg = mempool_alloc(rh->region_pool, GFP_NOIO); + nreg = mempool_alloc(rh->region_pool, GFP_ATOMIC); + if (unlikely(!nreg)) + nreg = kmalloc(sizeof(struct region), GFP_NOIO); nreg->state = rh->log->type->in_sync(rh->log, region, 1) ? RH_CLEAN : RH_NOSYNC; nreg->rh = rh; -- cgit v1.1 From 641741e010b615bae417c876a21d17dbd616241f Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Sun, 27 Aug 2006 01:23:27 -0700 Subject: [PATCH] rtc-s3c.c: fix time setting checks Fix the year check on setting the time with the S3C24XX RTC driver. Also move the debug to before the set to see what is going on if it does fail. Signed-off-by: Ben Dooks Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-s3c.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index aacbfea..2c7de79 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -153,24 +153,25 @@ static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm) static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm) { void __iomem *base = s3c_rtc_base; + int year = tm->tm_year - 100; - /* the rtc gets round the y2k problem by just not supporting it */ + pr_debug("set time %02d.%02d.%02d %02d/%02d/%02d\n", + tm->tm_year, tm->tm_mon, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec); + + /* we get around y2k by simply not supporting it */ - if (tm->tm_year > 100) { + if (year < 0 || year >= 100) { dev_err(dev, "rtc only supports 100 years\n"); return -EINVAL; } - pr_debug("set time %02d.%02d.%02d %02d/%02d/%02d\n", - tm->tm_year, tm->tm_mon, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec); - writeb(BIN2BCD(tm->tm_sec), base + S3C2410_RTCSEC); writeb(BIN2BCD(tm->tm_min), base + S3C2410_RTCMIN); writeb(BIN2BCD(tm->tm_hour), base + S3C2410_RTCHOUR); writeb(BIN2BCD(tm->tm_mday), base + S3C2410_RTCDATE); writeb(BIN2BCD(tm->tm_mon + 1), base + S3C2410_RTCMON); - writeb(BIN2BCD(tm->tm_year - 100), base + S3C2410_RTCYEAR); + writeb(BIN2BCD(year), base + S3C2410_RTCYEAR); return 0; } -- cgit v1.1 From cc36e7f124da139a819ad316c39d9dbcb5ba1897 Mon Sep 17 00:00:00 2001 From: Rolf Eike Beer Date: Sun, 27 Aug 2006 01:23:27 -0700 Subject: [PATCH] tty: remove bogus call to cdev_del() When cdev_add() failed there is no reason to call cdev_del(). Signed-off-by: Rolf Eike Beer Cc: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tty_io.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index bfdb902..d6e4eaa 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -3094,7 +3094,6 @@ int tty_register_driver(struct tty_driver *driver) driver->cdev.owner = driver->owner; error = cdev_add(&driver->cdev, dev, driver->num); if (error) { - cdev_del(&driver->cdev); unregister_chrdev_region(dev, driver->num); driver->ttys = NULL; driver->termios = driver->termios_locked = NULL; -- cgit v1.1 From 7334bb4ae931159384acf168eacb0d5d6e0d083c Mon Sep 17 00:00:00 2001 From: Danny Tholen Date: Sun, 27 Aug 2006 01:23:29 -0700 Subject: [PATCH] 1394: fix for recently added firewire patch that breaks things on ppc Recently a patch was added for preliminary suspend/resume handling on !PPC_PMAC. However, this broke both suspend and firewire on powerpc because it saves the pci state after the device has already been disabled. This moves the save state to before the pmac specific code. Signed-off-by: Danny Tholen Cc: Stefan Richter Acked-by: Benjamin Herrenschmidt Cc: Ben Collins Cc: Jody McIntyre Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/ieee1394/ohci1394.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c index d4bad67..448df27 100644 --- a/drivers/ieee1394/ohci1394.c +++ b/drivers/ieee1394/ohci1394.c @@ -3552,6 +3552,8 @@ static int ohci1394_pci_resume (struct pci_dev *pdev) static int ohci1394_pci_suspend (struct pci_dev *pdev, pm_message_t state) { + pci_save_state(pdev); + #ifdef CONFIG_PPC_PMAC if (machine_is(powermac)) { struct device_node *of_node; @@ -3563,8 +3565,6 @@ static int ohci1394_pci_suspend (struct pci_dev *pdev, pm_message_t state) } #endif - pci_save_state(pdev); - return 0; } -- cgit v1.1 From 7fd5aecc5d32882f8e29b14370e9ce2520e7e56f Mon Sep 17 00:00:00 2001 From: Richard Purdie Date: Sun, 27 Aug 2006 01:23:33 -0700 Subject: [PATCH] mtd corruption fix Read the return value before we release the nand device otherwise the value can become corrupted by another user of chip->ops, ultimately resulting in filesystem corruption. Signed-off-by: Richard Purdie Cc: David Woodhouse Acked-by: Josh Boyer Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/mtd/nand/nand_base.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 62b8613..c8cbc00 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -1093,9 +1093,10 @@ static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, ret = nand_do_read_ops(mtd, from, &chip->ops); + *retlen = chip->ops.retlen; + nand_release_device(mtd); - *retlen = chip->ops.retlen; return ret; } @@ -1691,9 +1692,10 @@ static int nand_write(struct mtd_info *mtd, loff_t to, size_t len, ret = nand_do_write_ops(mtd, to, &chip->ops); + *retlen = chip->ops.retlen; + nand_release_device(mtd); - *retlen = chip->ops.retlen; return ret; } -- cgit v1.1 From cb3e0fe3a5dabdc5eda50b825acb23bdfa2d1d55 Mon Sep 17 00:00:00 2001 From: Thomas Meyer Date: Sun, 27 Aug 2006 01:23:33 -0700 Subject: [PATCH] x86: Fix dmi detection of MacBookPro and iMac Commit b64ef8afa58f397e1eaba2bd9ecaa6812064d464 ("[PATCH] add imacfb documentation and detection") contained a wrong DMI_MATCH. Signed-off-by: Thomas Meyer Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/imacfb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/video/imacfb.c b/drivers/video/imacfb.c index b485bece..18ea4a5 100644 --- a/drivers/video/imacfb.c +++ b/drivers/video/imacfb.c @@ -71,10 +71,10 @@ static int set_system(struct dmi_system_id *id) static struct dmi_system_id __initdata dmi_system_table[] = { { set_system, "iMac4,1", { DMI_MATCH(DMI_BIOS_VENDOR,"Apple Computer, Inc."), - DMI_MATCH(DMI_BIOS_VERSION,"iMac4,1") }, (void*)M_I17}, + DMI_MATCH(DMI_PRODUCT_NAME,"iMac4,1") }, (void*)M_I17}, { set_system, "MacBookPro1,1", { DMI_MATCH(DMI_BIOS_VENDOR,"Apple Computer, Inc."), - DMI_MATCH(DMI_BIOS_VERSION,"MacBookPro1,1") }, (void*)M_I17}, + DMI_MATCH(DMI_PRODUCT_NAME,"MacBookPro1,1") }, (void*)M_I17}, { set_system, "MacBook1,1", { DMI_MATCH(DMI_BIOS_VENDOR,"Apple Computer, Inc."), DMI_MATCH(DMI_PRODUCT_NAME,"MacBook1,1")}, (void *)M_MACBOOK}, -- cgit v1.1 From 01cfaf0d12ae5fa092cc916ca4066ee1598e857d Mon Sep 17 00:00:00 2001 From: Dirk Eibach Date: Sun, 27 Aug 2006 01:23:36 -0700 Subject: [PATCH] char/moxa.c: fix endianess and multiple-card issues While testing Moxa C218T/PCI on PowerPC 405EP I found that loading firmware using the linux kernel driver fails because calculation of the checksum is not endianess independent in the original code. After I fixed this I found that uploading firmware in a system with multiple cards causes a kernel oops. I had a look in the recent moxa sources and found that they do some kind of locking there. Applying this lock fixed the problem. Alan sayeth: Checksum changes are clearly correct. Other changes is an improvement but not I think enough to handle malicious firmware attacks. That said such an attacker has CAP_SYS_RAWIO anyway so that part is irrelevant except for neatness. [akpm@osdl.org: cleanups] Signed-off-by: Dirk Eibach Acked-by: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/moxa.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c index 4ea7bd5..a369dd6 100644 --- a/drivers/char/moxa.c +++ b/drivers/char/moxa.c @@ -142,6 +142,7 @@ typedef struct _moxa_board_conf { static moxa_board_conf moxa_boards[MAX_BOARDS]; static void __iomem *moxaBaseAddr[MAX_BOARDS]; +static int loadstat[MAX_BOARDS]; struct moxa_str { int type; @@ -1688,6 +1689,8 @@ int MoxaDriverPoll(void) if (moxaCard == 0) return (-1); for (card = 0; card < MAX_BOARDS; card++) { + if (loadstat[card] == 0) + continue; if ((ports = moxa_boards[card].numPorts) == 0) continue; if (readb(moxaIntPend[card]) == 0xff) { @@ -2903,6 +2906,7 @@ static int moxaloadcode(int cardno, unsigned char __user *tmp, int len) } break; } + loadstat[cardno] = 1; return (0); } @@ -2920,7 +2924,7 @@ static int moxaloadc218(int cardno, void __iomem *baseAddr, int len) len1 = len >> 1; ptr = (ushort *) moxaBuff; for (i = 0; i < len1; i++) - usum += *(ptr + i); + usum += le16_to_cpu(*(ptr + i)); retry = 0; do { len1 = len >> 1; @@ -2992,7 +2996,7 @@ static int moxaloadc320(int cardno, void __iomem *baseAddr, int len, int *numPor wlen = len >> 1; uptr = (ushort *) moxaBuff; for (i = 0; i < wlen; i++) - usum += uptr[i]; + usum += le16_to_cpu(uptr[i]); retry = 0; j = 0; do { -- cgit v1.1 From b8cf368944807e29b16b24588a2a35c829bc9d9a Mon Sep 17 00:00:00 2001 From: "Paul A. Clarke" Date: Sun, 27 Aug 2006 01:23:37 -0700 Subject: [PATCH] matroxfb: fix jittery display on non-ppc systems I wish I was happier about this patch. It'll serve as a placeholder for the moment. I'm still trying to get a G550 working in order to even reproduce the problem this patch introduces. I find that the G450 has jitter even without this patch, so it won't show me what the patch changed. At this point, I'll continue trying to get the G550 to work, and in parallel work with the G450 to work out the kinks. The patch is below. Set XDVICLKCTRL only on PPC, as doing this apparently introduces jitter on the G550, at least on x86 architectures. Signed-off-by: Paul A. Clarke Signed-off-by: Petr Vandrovec Cc: "Antonino A. Daplas" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/matrox/g450_pll.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/video/matrox/g450_pll.c b/drivers/video/matrox/g450_pll.c index 440272a..7c76e07 100644 --- a/drivers/video/matrox/g450_pll.c +++ b/drivers/video/matrox/g450_pll.c @@ -331,7 +331,15 @@ static int __g450_setclk(WPMINFO unsigned int fout, unsigned int pll, tmp |= M1064_XPIXCLKCTRL_PLL_UP; } matroxfb_DAC_out(PMINFO M1064_XPIXCLKCTRL, tmp); +#ifdef __powerpc__ + /* This is necessary to avoid jitter on PowerPC + * (OpenFirmware) systems, but apparently + * introduces jitter, at least on a x86-64 + * using DVI. + * A simple workaround is disable for non-PPC. + */ matroxfb_DAC_out(PMINFO M1064_XDVICLKCTRL, 0); +#endif /* __powerpc__ */ matroxfb_DAC_out(PMINFO M1064_XPWRCTRL, xpwrctrl); matroxfb_DAC_unlock_irqrestore(flags); -- cgit v1.1 From 533475d3d48eb839be2b57f6b020150abae91063 Mon Sep 17 00:00:00 2001 From: Samuel Thibault Date: Sun, 27 Aug 2006 01:23:39 -0700 Subject: [PATCH] vcsa attribute bits -> ioctl(VT_GETHIFONTMASK) When reading /dev/vcsa while a font with more than 256 characters is loaded, one of the attribute bits records the 9th bit of the character. But depending on the console driver (vgacon or fbcon for instance), that's bit 3 or bit 0. And there is no way for userland to know that, thus no way for userland to safely grab the screen content. So here is a (tested) patch: Add a VT_GETHIFONTMASK ioctl for knowing which bit is the 9th bit for VC text (vc_hi_font_mask field of the vc_data structure). Signed-off-by: Samuel Thibault Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/vt_ioctl.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c index eccffaf..a5628a8 100644 --- a/drivers/char/vt_ioctl.c +++ b/drivers/char/vt_ioctl.c @@ -1011,6 +1011,8 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, return -EPERM; vt_dont_switch = 0; return 0; + case VT_GETHIFONTMASK: + return put_user(vc->vc_hi_font_mask, (unsigned short __user *)arg); default: return -ENOIOCTLCMD; } -- cgit v1.1 From fb8d81e47783f9198f3d6248bd4c0d16a1d5424e Mon Sep 17 00:00:00 2001 From: Jonathan McDowell Date: Sun, 27 Aug 2006 01:23:41 -0700 Subject: [PATCH] MTD NAND: Fix ams-delta after core conversion The recent hwctrl core conversion for MTD NAND devices broke the Amstrad Delta driver. This fixes it up and uses the existing control line defines rather than unclear magic numbers. Signed-off-by: Jonathan McDowell Acked-by: David Woodhouse Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/mtd/nand/ams-delta.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/ams-delta.c b/drivers/mtd/nand/ams-delta.c index d7897dc..a0ba07c 100644 --- a/drivers/mtd/nand/ams-delta.c +++ b/drivers/mtd/nand/ams-delta.c @@ -130,11 +130,13 @@ static void ams_delta_hwcontrol(struct mtd_info *mtd, int cmd, if (ctrl & NAND_CTRL_CHANGE) { unsigned long bits; - bits = (~ctrl & NAND_NCE) << 2; - bits |= (ctrl & NAND_CLE) << 7; - bits |= (ctrl & NAND_ALE) << 6; + bits = (~ctrl & NAND_NCE) ? AMS_DELTA_LATCH2_NAND_NCE : 0; + bits |= (ctrl & NAND_CLE) ? AMS_DELTA_LATCH2_NAND_CLE : 0; + bits |= (ctrl & NAND_ALE) ? AMS_DELTA_LATCH2_NAND_ALE : 0; - ams_delta_latch2_write(0xC2, bits); + ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_CLE | + AMS_DELTA_LATCH2_NAND_ALE | + AMS_DELTA_LATCH2_NAND_NCE, bits); } if (cmd != NAND_CMD_NONE) -- cgit v1.1 From 84692195969b83f0ba57dc33ecf73e6c124dd186 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Sun, 27 Aug 2006 01:23:49 -0700 Subject: [PATCH] md: avoid backward event updates in md superblock when degraded. If we - shut down a clean array, - restart with one (or more) drive(s) missing - make some changes - pause, so that they array gets marked 'clean', the event count on the superblock of included drives will be the same as that of the removed drives. So adding the removed drive back in will cause it to be included with no resync. To avoid this, we only update the eventcount backwards when the array is not degraded. In this case there can (should) be no non-connected drives that we can get confused with, and this is the particular case where updating-backwards is valuable. Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/md/md.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers') diff --git a/drivers/md/md.c b/drivers/md/md.c index b6d1602..8dbab2e 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -1597,6 +1597,19 @@ void md_update_sb(mddev_t * mddev) repeat: spin_lock_irq(&mddev->write_lock); + + if (mddev->degraded && mddev->sb_dirty == 3) + /* If the array is degraded, then skipping spares is both + * dangerous and fairly pointless. + * Dangerous because a device that was removed from the array + * might have a event_count that still looks up-to-date, + * so it can be re-added without a resync. + * Pointless because if there are any spares to skip, + * then a recovery will happen and soon that array won't + * be degraded any more and the spare can go back to sleep then. + */ + mddev->sb_dirty = 1; + sync_req = mddev->in_sync; mddev->utime = get_seconds(); if (mddev->sb_dirty == 3) -- cgit v1.1 From 6394cca54894f6a9bcf927ab78d28985944298ff Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Sun, 27 Aug 2006 01:23:50 -0700 Subject: [PATCH] md: fix recent breakage of md/raid1 array checking A recent patch broke the ability to do a user-request check of a raid1. This patch fixes the breakage and also moves a comment that was dislocated by the same patch. Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/md/raid1.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 1efe22a..87bfe9e 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -1625,15 +1625,16 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i return 0; } - /* before building a request, check if we can skip these blocks.. - * This call the bitmap_start_sync doesn't actually record anything - */ if (mddev->bitmap == NULL && mddev->recovery_cp == MaxSector && + !test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery) && conf->fullsync == 0) { *skipped = 1; return max_sector - sector_nr; } + /* before building a request, check if we can skip these blocks.. + * This call the bitmap_start_sync doesn't actually record anything + */ if (!bitmap_start_sync(mddev->bitmap, sector_nr, &sync_blocks, 1) && !conf->fullsync && !test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) { /* We can skip this block, and probably several more */ -- cgit v1.1 From 36e8e5783297fbb83bdebe7e245ef659958f23cb Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Sun, 27 Aug 2006 01:23:56 -0700 Subject: [PATCH] lockdep: annotate idescsi_pc_intr() idescsi_pc_intr() uses local_irq_enable() in IRQ context: annotate it. (this has no effect on kernels with lockdep disabled. On kernels with lockdep enabled this means that we wont actually disable interrupts, and the warning message will go away as well.) Signed-off-by: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/scsi/ide-scsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c index f7b5d73..94d1de5 100644 --- a/drivers/scsi/ide-scsi.c +++ b/drivers/scsi/ide-scsi.c @@ -517,7 +517,7 @@ static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive) /* No more interrupts */ if (test_bit(IDESCSI_LOG_CMD, &scsi->log)) printk (KERN_INFO "Packet command completed, %d bytes transferred\n", pc->actually_transferred); - local_irq_enable(); + local_irq_enable_in_hardirq(); if (status.b.check) rq->errors++; idescsi_end_request (drive, 1, 0); -- cgit v1.1 From f5ef68da5fda5e095b585ea5ecdd42af3c8695f7 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Sun, 27 Aug 2006 01:23:58 -0700 Subject: [PATCH] /proc/meminfo: don't put spaces in names None of the other /proc/meminfo lines have a space in the identifier. This post-2.6.17 addition has the potential to break existing parsers, so use an underscore instead (like Committed_AS). Cc: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/base/node.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/base/node.c b/drivers/base/node.c index d7de1753..e9b0957 100644 --- a/drivers/base/node.c +++ b/drivers/base/node.c @@ -64,7 +64,7 @@ static ssize_t node_read_meminfo(struct sys_device * dev, char * buf) "Node %d Mapped: %8lu kB\n" "Node %d AnonPages: %8lu kB\n" "Node %d PageTables: %8lu kB\n" - "Node %d NFS Unstable: %8lu kB\n" + "Node %d NFS_Unstable: %8lu kB\n" "Node %d Bounce: %8lu kB\n" "Node %d Slab: %8lu kB\n", nid, K(i.totalram), -- cgit v1.1 From 9c275a8391d96b49fa135d1e4073d4798b7c6445 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 27 Aug 2006 01:24:00 -0700 Subject: [PATCH] cdrom/gdsc: fix printk format warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix printk format warning: drivers/cdrom/gscd.c:269: warning: format ‘%lu’ expects type ‘long unsigned int’, but argument 2 has type ‘unsigned int’ Signed-off-by: Randy Dunlap Cc: Jens Axboe Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/cdrom/gscd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/cdrom/gscd.c b/drivers/cdrom/gscd.c index b6ee50a..fa70824 100644 --- a/drivers/cdrom/gscd.c +++ b/drivers/cdrom/gscd.c @@ -266,7 +266,7 @@ repeat: goto out; if (req->cmd != READ) { - printk("GSCD: bad cmd %lu\n", rq_data_dir(req)); + printk("GSCD: bad cmd %u\n", rq_data_dir(req)); end_request(req, 0); goto repeat; } -- cgit v1.1 From af9b897ee639d96b2bd29b65b50cd0a1f2b6d6c9 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Sun, 27 Aug 2006 01:24:01 -0700 Subject: [PATCH] tty layer comment the locking assumptions and functions somewhat Doesn't fix them but does show up some interesting areas that need review and fixing. Signed-off-by: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tty_io.c | 718 +++++++++++++++++++++++++++++++++++++++++++---- drivers/char/tty_ioctl.c | 59 +++- 2 files changed, 715 insertions(+), 62 deletions(-) (limited to 'drivers') diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index d6e4eaa..2cef982 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -153,6 +153,15 @@ int tty_ioctl(struct inode * inode, struct file * file, static int tty_fasync(int fd, struct file * filp, int on); static void release_mem(struct tty_struct *tty, int idx); +/** + * alloc_tty_struct - allocate a tty object + * + * Return a new empty tty structure. The data fields have not + * been initialized in any way but has been zeroed + * + * Locking: none + * FIXME: use kzalloc + */ static struct tty_struct *alloc_tty_struct(void) { @@ -166,6 +175,15 @@ static struct tty_struct *alloc_tty_struct(void) static void tty_buffer_free_all(struct tty_struct *); +/** + * free_tty_struct - free a disused tty + * @tty: tty struct to free + * + * Free the write buffers, tty queue and tty memory itself. + * + * Locking: none. Must be called after tty is definitely unused + */ + static inline void free_tty_struct(struct tty_struct *tty) { kfree(tty->write_buf); @@ -175,6 +193,17 @@ static inline void free_tty_struct(struct tty_struct *tty) #define TTY_NUMBER(tty) ((tty)->index + (tty)->driver->name_base) +/** + * tty_name - return tty naming + * @tty: tty structure + * @buf: buffer for output + * + * Convert a tty structure into a name. The name reflects the kernel + * naming policy and if udev is in use may not reflect user space + * + * Locking: none + */ + char *tty_name(struct tty_struct *tty, char *buf) { if (!tty) /* Hmm. NULL pointer. That's fun. */ @@ -235,6 +264,17 @@ static int check_tty_count(struct tty_struct *tty, const char *routine) * Tty buffer allocation management */ + +/** + * tty_buffer_free_all - free buffers used by a tty + * @tty: tty to free from + * + * Remove all the buffers pending on a tty whether queued with data + * or in the free ring. Must be called when the tty is no longer in use + * + * Locking: none + */ + static void tty_buffer_free_all(struct tty_struct *tty) { struct tty_buffer *thead; @@ -347,6 +387,18 @@ int tty_buffer_request_room(struct tty_struct *tty, size_t size) } EXPORT_SYMBOL_GPL(tty_buffer_request_room); +/** + * tty_insert_flip_string - Add characters to the tty buffer + * @tty: tty structure + * @chars: characters + * @size: size + * + * Queue a series of bytes to the tty buffering. All the characters + * passed are marked as without error. Returns the number added. + * + * Locking: Called functions may take tty->buf.lock + */ + int tty_insert_flip_string(struct tty_struct *tty, const unsigned char *chars, size_t size) { @@ -370,6 +422,20 @@ int tty_insert_flip_string(struct tty_struct *tty, const unsigned char *chars, } EXPORT_SYMBOL(tty_insert_flip_string); +/** + * tty_insert_flip_string_flags - Add characters to the tty buffer + * @tty: tty structure + * @chars: characters + * @flags: flag bytes + * @size: size + * + * Queue a series of bytes to the tty buffering. For each character + * the flags array indicates the status of the character. Returns the + * number added. + * + * Locking: Called functions may take tty->buf.lock + */ + int tty_insert_flip_string_flags(struct tty_struct *tty, const unsigned char *chars, const char *flags, size_t size) { @@ -394,6 +460,17 @@ int tty_insert_flip_string_flags(struct tty_struct *tty, } EXPORT_SYMBOL(tty_insert_flip_string_flags); +/** + * tty_schedule_flip - push characters to ldisc + * @tty: tty to push from + * + * Takes any pending buffers and transfers their ownership to the + * ldisc side of the queue. It then schedules those characters for + * processing by the line discipline. + * + * Locking: Takes tty->buf.lock + */ + void tty_schedule_flip(struct tty_struct *tty) { unsigned long flags; @@ -405,12 +482,19 @@ void tty_schedule_flip(struct tty_struct *tty) } EXPORT_SYMBOL(tty_schedule_flip); -/* +/** + * tty_prepare_flip_string - make room for characters + * @tty: tty + * @chars: return pointer for character write area + * @size: desired size + * * Prepare a block of space in the buffer for data. Returns the length * available and buffer pointer to the space which is now allocated and * accounted for as ready for normal characters. This is used for drivers * that need their own block copy routines into the buffer. There is no * guarantee the buffer is a DMA target! + * + * Locking: May call functions taking tty->buf.lock */ int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars, size_t size) @@ -427,12 +511,20 @@ int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars, size_ EXPORT_SYMBOL_GPL(tty_prepare_flip_string); -/* +/** + * tty_prepare_flip_string_flags - make room for characters + * @tty: tty + * @chars: return pointer for character write area + * @flags: return pointer for status flag write area + * @size: desired size + * * Prepare a block of space in the buffer for data. Returns the length * available and buffer pointer to the space which is now allocated and * accounted for as ready for characters. This is used for drivers * that need their own block copy routines into the buffer. There is no * guarantee the buffer is a DMA target! + * + * Locking: May call functions taking tty->buf.lock */ int tty_prepare_flip_string_flags(struct tty_struct *tty, unsigned char **chars, char **flags, size_t size) @@ -451,10 +543,16 @@ EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags); -/* +/** + * tty_set_termios_ldisc - set ldisc field + * @tty: tty structure + * @num: line discipline number + * * This is probably overkill for real world processors but * they are not on hot paths so a little discipline won't do * any harm. + * + * Locking: takes termios_sem */ static void tty_set_termios_ldisc(struct tty_struct *tty, int num) @@ -474,6 +572,19 @@ static DEFINE_SPINLOCK(tty_ldisc_lock); static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_wait); static struct tty_ldisc tty_ldiscs[NR_LDISCS]; /* line disc dispatch table */ +/** + * tty_register_ldisc - install a line discipline + * @disc: ldisc number + * @new_ldisc: pointer to the ldisc object + * + * Installs a new line discipline into the kernel. The discipline + * is set up as unreferenced and then made available to the kernel + * from this point onwards. + * + * Locking: + * takes tty_ldisc_lock to guard against ldisc races + */ + int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc) { unsigned long flags; @@ -493,6 +604,18 @@ int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc) } EXPORT_SYMBOL(tty_register_ldisc); +/** + * tty_unregister_ldisc - unload a line discipline + * @disc: ldisc number + * @new_ldisc: pointer to the ldisc object + * + * Remove a line discipline from the kernel providing it is not + * currently in use. + * + * Locking: + * takes tty_ldisc_lock to guard against ldisc races + */ + int tty_unregister_ldisc(int disc) { unsigned long flags; @@ -512,6 +635,19 @@ int tty_unregister_ldisc(int disc) } EXPORT_SYMBOL(tty_unregister_ldisc); +/** + * tty_ldisc_get - take a reference to an ldisc + * @disc: ldisc number + * + * Takes a reference to a line discipline. Deals with refcounts and + * module locking counts. Returns NULL if the discipline is not available. + * Returns a pointer to the discipline and bumps the ref count if it is + * available + * + * Locking: + * takes tty_ldisc_lock to guard against ldisc races + */ + struct tty_ldisc *tty_ldisc_get(int disc) { unsigned long flags; @@ -540,6 +676,17 @@ struct tty_ldisc *tty_ldisc_get(int disc) EXPORT_SYMBOL_GPL(tty_ldisc_get); +/** + * tty_ldisc_put - drop ldisc reference + * @disc: ldisc number + * + * Drop a reference to a line discipline. Manage refcounts and + * module usage counts + * + * Locking: + * takes tty_ldisc_lock to guard against ldisc races + */ + void tty_ldisc_put(int disc) { struct tty_ldisc *ld; @@ -557,6 +704,19 @@ void tty_ldisc_put(int disc) EXPORT_SYMBOL_GPL(tty_ldisc_put); +/** + * tty_ldisc_assign - set ldisc on a tty + * @tty: tty to assign + * @ld: line discipline + * + * Install an instance of a line discipline into a tty structure. The + * ldisc must have a reference count above zero to ensure it remains/ + * The tty instance refcount starts at zero. + * + * Locking: + * Caller must hold references + */ + static void tty_ldisc_assign(struct tty_struct *tty, struct tty_ldisc *ld) { tty->ldisc = *ld; @@ -571,6 +731,8 @@ static void tty_ldisc_assign(struct tty_struct *tty, struct tty_ldisc *ld) * the tty ldisc. Return 0 on failure or 1 on success. This is * used to implement both the waiting and non waiting versions * of tty_ldisc_ref + * + * Locking: takes tty_ldisc_lock */ static int tty_ldisc_try(struct tty_struct *tty) @@ -602,6 +764,8 @@ static int tty_ldisc_try(struct tty_struct *tty) * must also be careful not to hold other locks that will deadlock * against a discipline change, such as an existing ldisc reference * (which we check for) + * + * Locking: call functions take tty_ldisc_lock */ struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty) @@ -622,6 +786,8 @@ EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait); * Dereference the line discipline for the terminal and take a * reference to it. If the line discipline is in flux then * return NULL. Can be called from IRQ and timer functions. + * + * Locking: called functions take tty_ldisc_lock */ struct tty_ldisc *tty_ldisc_ref(struct tty_struct *tty) @@ -639,6 +805,8 @@ EXPORT_SYMBOL_GPL(tty_ldisc_ref); * * Undoes the effect of tty_ldisc_ref or tty_ldisc_ref_wait. May * be called in IRQ context. + * + * Locking: takes tty_ldisc_lock */ void tty_ldisc_deref(struct tty_ldisc *ld) @@ -683,6 +851,9 @@ static void tty_ldisc_enable(struct tty_struct *tty) * * Set the discipline of a tty line. Must be called from a process * context. + * + * Locking: takes tty_ldisc_lock. + * called functions take termios_sem */ static int tty_set_ldisc(struct tty_struct *tty, int ldisc) @@ -846,9 +1017,17 @@ restart: return retval; } -/* - * This routine returns a tty driver structure, given a device number +/** + * get_tty_driver - find device of a tty + * @dev_t: device identifier + * @index: returns the index of the tty + * + * This routine returns a tty driver structure, given a device number + * and also passes back the index number. + * + * Locking: caller must hold tty_mutex */ + static struct tty_driver *get_tty_driver(dev_t device, int *index) { struct tty_driver *p; @@ -863,11 +1042,17 @@ static struct tty_driver *get_tty_driver(dev_t device, int *index) return NULL; } -/* - * If we try to write to, or set the state of, a terminal and we're - * not in the foreground, send a SIGTTOU. If the signal is blocked or - * ignored, go ahead and perform the operation. (POSIX 7.2) +/** + * tty_check_change - check for POSIX terminal changes + * @tty: tty to check + * + * If we try to write to, or set the state of, a terminal and we're + * not in the foreground, send a SIGTTOU. If the signal is blocked or + * ignored, go ahead and perform the operation. (POSIX 7.2) + * + * Locking: none */ + int tty_check_change(struct tty_struct * tty) { if (current->signal->tty != tty) @@ -1005,10 +1190,27 @@ void tty_ldisc_flush(struct tty_struct *tty) EXPORT_SYMBOL_GPL(tty_ldisc_flush); -/* - * This can be called by the "eventd" kernel thread. That is process synchronous, - * but doesn't hold any locks, so we need to make sure we have the appropriate - * locks for what we're doing.. +/** + * do_tty_hangup - actual handler for hangup events + * @data: tty device + * + * This can be called by the "eventd" kernel thread. That is process + * synchronous but doesn't hold any locks, so we need to make sure we + * have the appropriate locks for what we're doing. + * + * The hangup event clears any pending redirections onto the hung up + * device. It ensures future writes will error and it does the needed + * line discipline hangup and signal delivery. The tty object itself + * remains intact. + * + * Locking: + * BKL + * redirect lock for undoing redirection + * file list lock for manipulating list of ttys + * tty_ldisc_lock from called functions + * termios_sem resetting termios data + * tasklist_lock to walk task list for hangup event + * */ static void do_tty_hangup(void *data) { @@ -1133,6 +1335,14 @@ static void do_tty_hangup(void *data) fput(f); } +/** + * tty_hangup - trigger a hangup event + * @tty: tty to hangup + * + * A carrier loss (virtual or otherwise) has occurred on this like + * schedule a hangup sequence to run after this event. + */ + void tty_hangup(struct tty_struct * tty) { #ifdef TTY_DEBUG_HANGUP @@ -1145,6 +1355,15 @@ void tty_hangup(struct tty_struct * tty) EXPORT_SYMBOL(tty_hangup); +/** + * tty_vhangup - process vhangup + * @tty: tty to hangup + * + * The user has asked via system call for the terminal to be hung up. + * We do this synchronously so that when the syscall returns the process + * is complete. That guarantee is neccessary for security reasons. + */ + void tty_vhangup(struct tty_struct * tty) { #ifdef TTY_DEBUG_HANGUP @@ -1156,6 +1375,14 @@ void tty_vhangup(struct tty_struct * tty) } EXPORT_SYMBOL(tty_vhangup); +/** + * tty_hung_up_p - was tty hung up + * @filp: file pointer of tty + * + * Return true if the tty has been subject to a vhangup or a carrier + * loss + */ + int tty_hung_up_p(struct file * filp) { return (filp->f_op == &hung_up_tty_fops); @@ -1163,19 +1390,28 @@ int tty_hung_up_p(struct file * filp) EXPORT_SYMBOL(tty_hung_up_p); -/* - * This function is typically called only by the session leader, when - * it wants to disassociate itself from its controlling tty. +/** + * disassociate_ctty - disconnect controlling tty + * @on_exit: true if exiting so need to "hang up" the session * - * It performs the following functions: + * This function is typically called only by the session leader, when + * it wants to disassociate itself from its controlling tty. + * + * It performs the following functions: * (1) Sends a SIGHUP and SIGCONT to the foreground process group * (2) Clears the tty from being controlling the session * (3) Clears the controlling tty for all processes in the * session group. * - * The argument on_exit is set to 1 if called when a process is - * exiting; it is 0 if called by the ioctl TIOCNOTTY. + * The argument on_exit is set to 1 if called when a process is + * exiting; it is 0 if called by the ioctl TIOCNOTTY. + * + * Locking: tty_mutex is taken to protect current->signal->tty + * BKL is taken for hysterical raisins + * Tasklist lock is taken (under tty_mutex) to walk process + * lists for the session. */ + void disassociate_ctty(int on_exit) { struct tty_struct *tty; @@ -1222,6 +1458,25 @@ void disassociate_ctty(int on_exit) unlock_kernel(); } + +/** + * stop_tty - propogate flow control + * @tty: tty to stop + * + * Perform flow control to the driver. For PTY/TTY pairs we + * must also propogate the TIOCKPKT status. May be called + * on an already stopped device and will not re-call the driver + * method. + * + * This functionality is used by both the line disciplines for + * halting incoming flow and by the driver. It may therefore be + * called from any context, may be under the tty atomic_write_lock + * but not always. + * + * Locking: + * Broken. Relies on BKL which is unsafe here. + */ + void stop_tty(struct tty_struct *tty) { if (tty->stopped) @@ -1238,6 +1493,19 @@ void stop_tty(struct tty_struct *tty) EXPORT_SYMBOL(stop_tty); +/** + * start_tty - propogate flow control + * @tty: tty to start + * + * Start a tty that has been stopped if at all possible. Perform + * any neccessary wakeups and propogate the TIOCPKT status. If this + * is the tty was previous stopped and is being started then the + * driver start method is invoked and the line discipline woken. + * + * Locking: + * Broken. Relies on BKL which is unsafe here. + */ + void start_tty(struct tty_struct *tty) { if (!tty->stopped || tty->flow_stopped) @@ -1258,6 +1526,23 @@ void start_tty(struct tty_struct *tty) EXPORT_SYMBOL(start_tty); +/** + * tty_read - read method for tty device files + * @file: pointer to tty file + * @buf: user buffer + * @count: size of user buffer + * @ppos: unused + * + * Perform the read system call function on this terminal device. Checks + * for hung up devices before calling the line discipline method. + * + * Locking: + * Locks the line discipline internally while needed + * For historical reasons the line discipline read method is + * invoked under the BKL. This will go away in time so do not rely on it + * in new code. Multiple read calls may be outstanding in parallel. + */ + static ssize_t tty_read(struct file * file, char __user * buf, size_t count, loff_t *ppos) { @@ -1302,6 +1587,7 @@ static inline ssize_t do_tty_write( ssize_t ret = 0, written = 0; unsigned int chunk; + /* FIXME: O_NDELAY ... */ if (mutex_lock_interruptible(&tty->atomic_write_lock)) { return -ERESTARTSYS; } @@ -1318,6 +1604,9 @@ static inline ssize_t do_tty_write( * layer has problems with bigger chunks. It will * claim to be able to handle more characters than * it actually does. + * + * FIXME: This can probably go away now except that 64K chunks + * are too likely to fail unless switched to vmalloc... */ chunk = 2048; if (test_bit(TTY_NO_WRITE_SPLIT, &tty->flags)) @@ -1375,6 +1664,24 @@ static inline ssize_t do_tty_write( } +/** + * tty_write - write method for tty device file + * @file: tty file pointer + * @buf: user data to write + * @count: bytes to write + * @ppos: unused + * + * Write data to a tty device via the line discipline. + * + * Locking: + * Locks the line discipline as required + * Writes to the tty driver are serialized by the atomic_write_lock + * and are then processed in chunks to the device. The line discipline + * write method will not be involked in parallel for each device + * The line discipline write method is called under the big + * kernel lock for historical reasons. New code should not rely on this. + */ + static ssize_t tty_write(struct file * file, const char __user * buf, size_t count, loff_t *ppos) { @@ -1422,7 +1729,18 @@ ssize_t redirected_tty_write(struct file * file, const char __user * buf, size_t static char ptychar[] = "pqrstuvwxyzabcde"; -static inline void pty_line_name(struct tty_driver *driver, int index, char *p) +/** + * pty_line_name - generate name for a pty + * @driver: the tty driver in use + * @index: the minor number + * @p: output buffer of at least 6 bytes + * + * Generate a name from a driver reference and write it to the output + * buffer. + * + * Locking: None + */ +static void pty_line_name(struct tty_driver *driver, int index, char *p) { int i = index + driver->name_base; /* ->name is initialized to "ttyp", but "tty" is expected */ @@ -1431,24 +1749,53 @@ static inline void pty_line_name(struct tty_driver *driver, int index, char *p) ptychar[i >> 4 & 0xf], i & 0xf); } -static inline void tty_line_name(struct tty_driver *driver, int index, char *p) +/** + * pty_line_name - generate name for a tty + * @driver: the tty driver in use + * @index: the minor number + * @p: output buffer of at least 7 bytes + * + * Generate a name from a driver reference and write it to the output + * buffer. + * + * Locking: None + */ +static void tty_line_name(struct tty_driver *driver, int index, char *p) { sprintf(p, "%s%d", driver->name, index + driver->name_base); } -/* +/** + * init_dev - initialise a tty device + * @driver: tty driver we are opening a device on + * @idx: device index + * @tty: returned tty structure + * + * Prepare a tty device. This may not be a "new" clean device but + * could also be an active device. The pty drivers require special + * handling because of this. + * + * Locking: + * The function is called under the tty_mutex, which + * protects us from the tty struct or driver itself going away. + * + * On exit the tty device has the line discipline attached and + * a reference count of 1. If a pair was created for pty/tty use + * and the other was a pty master then it too has a reference count of 1. + * * WSH 06/09/97: Rewritten to remove races and properly clean up after a * failed open. The new code protects the open with a mutex, so it's * really quite straightforward. The mutex locking can probably be * relaxed for the (most common) case of reopening a tty. */ + static int init_dev(struct tty_driver *driver, int idx, struct tty_struct **ret_tty) { struct tty_struct *tty, *o_tty; struct termios *tp, **tp_loc, *o_tp, **o_tp_loc; struct termios *ltp, **ltp_loc, *o_ltp, **o_ltp_loc; - int retval=0; + int retval = 0; /* check whether we're reopening an existing tty */ if (driver->flags & TTY_DRIVER_DEVPTS_MEM) { @@ -1662,10 +2009,20 @@ release_mem_out: goto end_init; } -/* - * Releases memory associated with a tty structure, and clears out the - * driver table slots. +/** + * release_mem - release tty structure memory + * + * Releases memory associated with a tty structure, and clears out the + * driver table slots. This function is called when a device is no longer + * in use. It also gets called when setup of a device fails. + * + * Locking: + * tty_mutex - sometimes only + * takes the file list lock internally when working on the list + * of ttys that the driver keeps. + * FIXME: should we require tty_mutex is held here ?? */ + static void release_mem(struct tty_struct *tty, int idx) { struct tty_struct *o_tty; @@ -2006,18 +2363,27 @@ static void release_dev(struct file * filp) } -/* - * tty_open and tty_release keep up the tty count that contains the - * number of opens done on a tty. We cannot use the inode-count, as - * different inodes might point to the same tty. +/** + * tty_open - open a tty device + * @inode: inode of device file + * @filp: file pointer to tty * - * Open-counting is needed for pty masters, as well as for keeping - * track of serial lines: DTR is dropped when the last close happens. - * (This is not done solely through tty->count, now. - Ted 1/27/92) + * tty_open and tty_release keep up the tty count that contains the + * number of opens done on a tty. We cannot use the inode-count, as + * different inodes might point to the same tty. * - * The termios state of a pty is reset on first open so that - * settings don't persist across reuse. + * Open-counting is needed for pty masters, as well as for keeping + * track of serial lines: DTR is dropped when the last close happens. + * (This is not done solely through tty->count, now. - Ted 1/27/92) + * + * The termios state of a pty is reset on first open so that + * settings don't persist across reuse. + * + * Locking: tty_mutex protects current->signal->tty, get_tty_driver and + * init_dev work. tty->count should protect the rest. + * task_lock is held to update task details for sessions */ + static int tty_open(struct inode * inode, struct file * filp) { struct tty_struct *tty; @@ -2132,6 +2498,18 @@ got_driver: } #ifdef CONFIG_UNIX98_PTYS +/** + * ptmx_open - open a unix 98 pty master + * @inode: inode of device file + * @filp: file pointer to tty + * + * Allocate a unix98 pty master device from the ptmx driver. + * + * Locking: tty_mutex protects theinit_dev work. tty->count should + protect the rest. + * allocated_ptys_lock handles the list of free pty numbers + */ + static int ptmx_open(struct inode * inode, struct file * filp) { struct tty_struct *tty; @@ -2191,6 +2569,18 @@ out: } #endif +/** + * tty_release - vfs callback for close + * @inode: inode of tty + * @filp: file pointer for handle to tty + * + * Called the last time each file handle is closed that references + * this tty. There may however be several such references. + * + * Locking: + * Takes bkl. See release_dev + */ + static int tty_release(struct inode * inode, struct file * filp) { lock_kernel(); @@ -2199,7 +2589,18 @@ static int tty_release(struct inode * inode, struct file * filp) return 0; } -/* No kernel lock held - fine */ +/** + * tty_poll - check tty status + * @filp: file being polled + * @wait: poll wait structures to update + * + * Call the line discipline polling method to obtain the poll + * status of the device. + * + * Locking: locks called line discipline but ldisc poll method + * may be re-entered freely by other callers. + */ + static unsigned int tty_poll(struct file * filp, poll_table * wait) { struct tty_struct * tty; @@ -2243,6 +2644,21 @@ static int tty_fasync(int fd, struct file * filp, int on) return 0; } +/** + * tiocsti - fake input character + * @tty: tty to fake input into + * @p: pointer to character + * + * Fake input to a tty device. Does the neccessary locking and + * input management. + * + * FIXME: does not honour flow control ?? + * + * Locking: + * Called functions take tty_ldisc_lock + * current->signal->tty check is safe without locks + */ + static int tiocsti(struct tty_struct *tty, char __user *p) { char ch, mbz = 0; @@ -2258,6 +2674,18 @@ static int tiocsti(struct tty_struct *tty, char __user *p) return 0; } +/** + * tiocgwinsz - implement window query ioctl + * @tty; tty + * @arg: user buffer for result + * + * Copies the kernel idea of the window size into the user buffer. No + * locking is done. + * + * FIXME: Returning random values racing a window size set is wrong + * should lock here against that + */ + static int tiocgwinsz(struct tty_struct *tty, struct winsize __user * arg) { if (copy_to_user(arg, &tty->winsize, sizeof(*arg))) @@ -2265,6 +2693,24 @@ static int tiocgwinsz(struct tty_struct *tty, struct winsize __user * arg) return 0; } +/** + * tiocswinsz - implement window size set ioctl + * @tty; tty + * @arg: user buffer for result + * + * Copies the user idea of the window size to the kernel. Traditionally + * this is just advisory information but for the Linux console it + * actually has driver level meaning and triggers a VC resize. + * + * Locking: + * The console_sem is used to ensure we do not try and resize + * the console twice at once. + * FIXME: Two racing size sets may leave the console and kernel + * parameters disagreeing. Is this exploitable ? + * FIXME: Random values racing a window size get is wrong + * should lock here against that + */ + static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty, struct winsize __user * arg) { @@ -2294,6 +2740,15 @@ static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty, return 0; } +/** + * tioccons - allow admin to move logical console + * @file: the file to become console + * + * Allow the adminstrator to move the redirected console device + * + * Locking: uses redirect_lock to guard the redirect information + */ + static int tioccons(struct file *file) { if (!capable(CAP_SYS_ADMIN)) @@ -2319,6 +2774,17 @@ static int tioccons(struct file *file) return 0; } +/** + * fionbio - non blocking ioctl + * @file: file to set blocking value + * @p: user parameter + * + * Historical tty interfaces had a blocking control ioctl before + * the generic functionality existed. This piece of history is preserved + * in the expected tty API of posix OS's. + * + * Locking: none, the open fle handle ensures it won't go away. + */ static int fionbio(struct file *file, int __user *p) { @@ -2334,6 +2800,23 @@ static int fionbio(struct file *file, int __user *p) return 0; } +/** + * tiocsctty - set controlling tty + * @tty: tty structure + * @arg: user argument + * + * This ioctl is used to manage job control. It permits a session + * leader to set this tty as the controlling tty for the session. + * + * Locking: + * Takes tasklist lock internally to walk sessions + * Takes task_lock() when updating signal->tty + * + * FIXME: tty_mutex is needed to protect signal->tty references. + * FIXME: why task_lock on the signal->tty reference ?? + * + */ + static int tiocsctty(struct tty_struct *tty, int arg) { struct task_struct *p; @@ -2374,6 +2857,18 @@ static int tiocsctty(struct tty_struct *tty, int arg) return 0; } +/** + * tiocgpgrp - get process group + * @tty: tty passed by user + * @real_tty: tty side of the tty pased by the user if a pty else the tty + * @p: returned pid + * + * Obtain the process group of the tty. If there is no process group + * return an error. + * + * Locking: none. Reference to ->signal->tty is safe. + */ + static int tiocgpgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p) { /* @@ -2385,6 +2880,20 @@ static int tiocgpgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t return put_user(real_tty->pgrp, p); } +/** + * tiocspgrp - attempt to set process group + * @tty: tty passed by user + * @real_tty: tty side device matching tty passed by user + * @p: pid pointer + * + * Set the process group of the tty to the session passed. Only + * permitted where the tty session is our session. + * + * Locking: None + * + * FIXME: current->signal->tty referencing is unsafe. + */ + static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p) { pid_t pgrp; @@ -2408,6 +2917,18 @@ static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t return 0; } +/** + * tiocgsid - get session id + * @tty: tty passed by user + * @real_tty: tty side of the tty pased by the user if a pty else the tty + * @p: pointer to returned session id + * + * Obtain the session id of the tty. If there is no session + * return an error. + * + * Locking: none. Reference to ->signal->tty is safe. + */ + static int tiocgsid(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p) { /* @@ -2421,6 +2942,16 @@ static int tiocgsid(struct tty_struct *tty, struct tty_struct *real_tty, pid_t _ return put_user(real_tty->session, p); } +/** + * tiocsetd - set line discipline + * @tty: tty device + * @p: pointer to user data + * + * Set the line discipline according to user request. + * + * Locking: see tty_set_ldisc, this function is just a helper + */ + static int tiocsetd(struct tty_struct *tty, int __user *p) { int ldisc; @@ -2430,6 +2961,21 @@ static int tiocsetd(struct tty_struct *tty, int __user *p) return tty_set_ldisc(tty, ldisc); } +/** + * send_break - performed time break + * @tty: device to break on + * @duration: timeout in mS + * + * Perform a timed break on hardware that lacks its own driver level + * timed break functionality. + * + * Locking: + * None + * + * FIXME: + * What if two overlap + */ + static int send_break(struct tty_struct *tty, unsigned int duration) { tty->driver->break_ctl(tty, -1); @@ -2442,8 +2988,19 @@ static int send_break(struct tty_struct *tty, unsigned int duration) return 0; } -static int -tty_tiocmget(struct tty_struct *tty, struct file *file, int __user *p) +/** + * tiocmget - get modem status + * @tty: tty device + * @file: user file pointer + * @p: pointer to result + * + * Obtain the modem status bits from the tty driver if the feature + * is supported. Return -EINVAL if it is not available. + * + * Locking: none (up to the driver) + */ + +static int tty_tiocmget(struct tty_struct *tty, struct file *file, int __user *p) { int retval = -EINVAL; @@ -2456,8 +3013,20 @@ tty_tiocmget(struct tty_struct *tty, struct file *file, int __user *p) return retval; } -static int -tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int cmd, +/** + * tiocmset - set modem status + * @tty: tty device + * @file: user file pointer + * @cmd: command - clear bits, set bits or set all + * @p: pointer to desired bits + * + * Set the modem status bits from the tty driver if the feature + * is supported. Return -EINVAL if it is not available. + * + * Locking: none (up to the driver) + */ + +static int tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned __user *p) { int retval = -EINVAL; @@ -2573,6 +3142,7 @@ int tty_ioctl(struct inode * inode, struct file * file, clear_bit(TTY_EXCLUSIVE, &tty->flags); return 0; case TIOCNOTTY: + /* FIXME: taks lock or tty_mutex ? */ if (current->signal->tty != tty) return -ENOTTY; if (current->signal->leader) @@ -2753,9 +3323,16 @@ void do_SAK(struct tty_struct *tty) EXPORT_SYMBOL(do_SAK); -/* - * This routine is called out of the software interrupt to flush data - * from the buffer chain to the line discipline. +/** + * flush_to_ldisc + * @private_: tty structure passed from work queue. + * + * This routine is called out of the software interrupt to flush data + * from the buffer chain to the line discipline. + * + * Locking: holds tty->buf.lock to guard buffer list. Drops the lock + * while invoking the line discipline receive_buf method. The + * receive_buf method is single threaded for each tty instance. */ static void flush_to_ldisc(void *private_) @@ -2831,6 +3408,8 @@ static int n_baud_table = ARRAY_SIZE(baud_table); * Convert termios baud rate data into a speed. This should be called * with the termios lock held if this termios is a terminal termios * structure. May change the termios data. + * + * Locking: none */ int tty_termios_baud_rate(struct termios *termios) @@ -2859,6 +3438,8 @@ EXPORT_SYMBOL(tty_termios_baud_rate); * Returns the baud rate as an integer for this terminal. The * termios lock must be held by the caller and the terminal bit * flags may be updated. + * + * Locking: none */ int tty_get_baud_rate(struct tty_struct *tty) @@ -2888,6 +3469,8 @@ EXPORT_SYMBOL(tty_get_baud_rate); * * In the event of the queue being busy for flipping the work will be * held off and retried later. + * + * Locking: tty buffer lock. Driver locks in low latency mode. */ void tty_flip_buffer_push(struct tty_struct *tty) @@ -2907,9 +3490,16 @@ void tty_flip_buffer_push(struct tty_struct *tty) EXPORT_SYMBOL(tty_flip_buffer_push); -/* - * This subroutine initializes a tty structure. +/** + * initialize_tty_struct + * @tty: tty to initialize + * + * This subroutine initializes a tty structure that has been newly + * allocated. + * + * Locking: none - tty in question must not be exposed at this point */ + static void initialize_tty_struct(struct tty_struct *tty) { memset(tty, 0, sizeof(struct tty_struct)); @@ -2935,6 +3525,7 @@ static void initialize_tty_struct(struct tty_struct *tty) /* * The default put_char routine if the driver did not define one. */ + static void tty_default_put_char(struct tty_struct *tty, unsigned char ch) { tty->driver->write(tty, &ch, 1); @@ -2943,19 +3534,23 @@ static void tty_default_put_char(struct tty_struct *tty, unsigned char ch) static struct class *tty_class; /** - * tty_register_device - register a tty device - * @driver: the tty driver that describes the tty device - * @index: the index in the tty driver for this tty device - * @device: a struct device that is associated with this tty device. - * This field is optional, if there is no known struct device for this - * tty device it can be set to NULL safely. + * tty_register_device - register a tty device + * @driver: the tty driver that describes the tty device + * @index: the index in the tty driver for this tty device + * @device: a struct device that is associated with this tty device. + * This field is optional, if there is no known struct device + * for this tty device it can be set to NULL safely. * - * Returns a pointer to the class device (or ERR_PTR(-EFOO) on error). + * Returns a pointer to the class device (or ERR_PTR(-EFOO) on error). * - * This call is required to be made to register an individual tty device if - * the tty driver's flags have the TTY_DRIVER_DYNAMIC_DEV bit set. If that - * bit is not set, this function should not be called by a tty driver. + * This call is required to be made to register an individual tty device + * if the tty driver's flags have the TTY_DRIVER_DYNAMIC_DEV bit set. If + * that bit is not set, this function should not be called by a tty + * driver. + * + * Locking: ?? */ + struct class_device *tty_register_device(struct tty_driver *driver, unsigned index, struct device *device) { @@ -2977,13 +3572,16 @@ struct class_device *tty_register_device(struct tty_driver *driver, } /** - * tty_unregister_device - unregister a tty device - * @driver: the tty driver that describes the tty device - * @index: the index in the tty driver for this tty device + * tty_unregister_device - unregister a tty device + * @driver: the tty driver that describes the tty device + * @index: the index in the tty driver for this tty device * - * If a tty device is registered with a call to tty_register_device() then - * this function must be made when the tty device is gone. + * If a tty device is registered with a call to tty_register_device() then + * this function must be called when the tty device is gone. + * + * Locking: ?? */ + void tty_unregister_device(struct tty_driver *driver, unsigned index) { class_device_destroy(tty_class, MKDEV(driver->major, driver->minor_start) + index); diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c index f19cf9d..4ad47d3 100644 --- a/drivers/char/tty_ioctl.c +++ b/drivers/char/tty_ioctl.c @@ -36,6 +36,18 @@ #define TERMIOS_WAIT 2 #define TERMIOS_TERMIO 4 + +/** + * tty_wait_until_sent - wait for I/O to finish + * @tty: tty we are waiting for + * @timeout: how long we will wait + * + * Wait for characters pending in a tty driver to hit the wire, or + * for a timeout to occur (eg due to flow control) + * + * Locking: none + */ + void tty_wait_until_sent(struct tty_struct * tty, long timeout) { DECLARE_WAITQUEUE(wait, current); @@ -94,6 +106,18 @@ static void unset_locked_termios(struct termios *termios, old->c_cc[i] : termios->c_cc[i]; } +/** + * change_termios - update termios values + * @tty: tty to update + * @new_termios: desired new value + * + * Perform updates to the termios values set on this terminal. There + * is a bit of layering violation here with n_tty in terms of the + * internal knowledge of this function. + * + * Locking: termios_sem + */ + static void change_termios(struct tty_struct * tty, struct termios * new_termios) { int canon_change; @@ -155,6 +179,19 @@ static void change_termios(struct tty_struct * tty, struct termios * new_termios up(&tty->termios_sem); } +/** + * set_termios - set termios values for a tty + * @tty: terminal device + * @arg: user data + * @opt: option information + * + * Helper function to prepare termios data and run neccessary other + * functions before using change_termios to do the actual changes. + * + * Locking: + * Called functions take ldisc and termios_sem locks + */ + static int set_termios(struct tty_struct * tty, void __user *arg, int opt) { struct termios tmp_termios; @@ -284,6 +321,17 @@ static void set_sgflags(struct termios * termios, int flags) } } +/** + * set_sgttyb - set legacy terminal values + * @tty: tty structure + * @sgttyb: pointer to old style terminal structure + * + * Updates a terminal from the legacy BSD style terminal information + * structure. + * + * Locking: termios_sem + */ + static int set_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb) { int retval; @@ -369,9 +417,16 @@ static int set_ltchars(struct tty_struct * tty, struct ltchars __user * ltchars) } #endif -/* - * Send a high priority character to the tty. +/** + * send_prio_char - send priority character + * + * Send a high priority character to the tty even if stopped + * + * Locking: none + * + * FIXME: overlapping calls with start/stop tty lose state of tty */ + static void send_prio_char(struct tty_struct *tty, char ch) { int was_stopped = tty->stopped; -- cgit v1.1 From 01da5fd83d6b2c5e36b77539f6cbdd8f49849225 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Sun, 27 Aug 2006 01:24:02 -0700 Subject: [PATCH] Fix tty layer DoS and comment relevant code Unlike the other tty comment patch this one has code changes. Specifically it limits the queue size for a tty to 64K characters (128Kbytes) worst case even if the tty is ignoring tty->throttle. This is because certain drivers don't honour the throttle value correctly, although it is a useful safeguard anyway. Signed-off-by: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tty_io.c | 89 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 79 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 2cef982..bb0d919 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -275,6 +275,17 @@ static int check_tty_count(struct tty_struct *tty, const char *routine) * Locking: none */ + +/** + * tty_buffer_free_all - free buffers used by a tty + * @tty: tty to free from + * + * Remove all the buffers pending on a tty whether queued with data + * or in the free ring. Must be called when the tty is no longer in use + * + * Locking: none + */ + static void tty_buffer_free_all(struct tty_struct *tty) { struct tty_buffer *thead; @@ -287,19 +298,47 @@ static void tty_buffer_free_all(struct tty_struct *tty) kfree(thead); } tty->buf.tail = NULL; + tty->buf.memory_used = 0; } +/** + * tty_buffer_init - prepare a tty buffer structure + * @tty: tty to initialise + * + * Set up the initial state of the buffer management for a tty device. + * Must be called before the other tty buffer functions are used. + * + * Locking: none + */ + static void tty_buffer_init(struct tty_struct *tty) { spin_lock_init(&tty->buf.lock); tty->buf.head = NULL; tty->buf.tail = NULL; tty->buf.free = NULL; + tty->buf.memory_used = 0; } -static struct tty_buffer *tty_buffer_alloc(size_t size) +/** + * tty_buffer_alloc - allocate a tty buffer + * @tty: tty device + * @size: desired size (characters) + * + * Allocate a new tty buffer to hold the desired number of characters. + * Return NULL if out of memory or the allocation would exceed the + * per device queue + * + * Locking: Caller must hold tty->buf.lock + */ + +static struct tty_buffer *tty_buffer_alloc(struct tty_struct *tty, size_t size) { - struct tty_buffer *p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC); + struct tty_buffer *p; + + if (tty->buf.memory_used + size > 65536) + return NULL; + p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC); if(p == NULL) return NULL; p->used = 0; @@ -309,17 +348,27 @@ static struct tty_buffer *tty_buffer_alloc(size_t size) p->read = 0; p->char_buf_ptr = (char *)(p->data); p->flag_buf_ptr = (unsigned char *)p->char_buf_ptr + size; -/* printk("Flip create %p\n", p); */ + tty->buf.memory_used += size; return p; } -/* Must be called with the tty_read lock held. This needs to acquire strategy - code to decide if we should kfree or relink a given expired buffer */ +/** + * tty_buffer_free - free a tty buffer + * @tty: tty owning the buffer + * @b: the buffer to free + * + * Free a tty buffer, or add it to the free list according to our + * internal strategy + * + * Locking: Caller must hold tty->buf.lock + */ static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b) { /* Dumb strategy for now - should keep some stats */ -/* printk("Flip dispose %p\n", b); */ + tty->buf.memory_used -= b->size; + WARN_ON(tty->buf.memory_used < 0); + if(b->size >= 512) kfree(b); else { @@ -328,6 +377,18 @@ static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b) } } +/** + * tty_buffer_find - find a free tty buffer + * @tty: tty owning the buffer + * @size: characters wanted + * + * Locate an existing suitable tty buffer or if we are lacking one then + * allocate a new one. We round our buffers off in 256 character chunks + * to get better allocation behaviour. + * + * Locking: Caller must hold tty->buf.lock + */ + static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size) { struct tty_buffer **tbh = &tty->buf.free; @@ -339,20 +400,28 @@ static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size) t->used = 0; t->commit = 0; t->read = 0; - /* DEBUG ONLY */ -/* memset(t->data, '*', size); */ -/* printk("Flip recycle %p\n", t); */ + tty->buf.memory_used += t->size; return t; } tbh = &((*tbh)->next); } /* Round the buffer size out */ size = (size + 0xFF) & ~ 0xFF; - return tty_buffer_alloc(size); + return tty_buffer_alloc(tty, size); /* Should possibly check if this fails for the largest buffer we have queued and recycle that ? */ } +/** + * tty_buffer_request_room - grow tty buffer if needed + * @tty: tty structure + * @size: size desired + * + * Make at least size bytes of linear space available for the tty + * buffer. If we fail return the size we managed to find. + * + * Locking: Takes tty->buf.lock + */ int tty_buffer_request_room(struct tty_struct *tty, size_t size) { struct tty_buffer *b, *n; -- cgit v1.1